yading@11: /* yading@11: * Input cache protocol. yading@11: * Copyright (c) 2011 Michael Niedermayer yading@11: * yading@11: * This file is part of FFmpeg. yading@11: * yading@11: * FFmpeg is free software; you can redistribute it and/or yading@11: * modify it under the terms of the GNU Lesser General Public yading@11: * License as published by the Free Software Foundation; either yading@11: * version 2.1 of the License, or (at your option) any later version. yading@11: * yading@11: * FFmpeg is distributed in the hope that it will be useful, yading@11: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@11: * Lesser General Public License for more details. yading@11: * yading@11: * You should have received a copy of the GNU Lesser General Public yading@11: * License along with FFmpeg; if not, write to the Free Software yading@11: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@11: * yading@11: * Based on file.c by Fabrice Bellard yading@11: */ yading@11: yading@11: /** yading@11: * @TODO yading@11: * support non continuous caching yading@11: * support keeping files yading@11: * support filling with a background thread yading@11: */ yading@11: yading@11: #include "libavutil/avassert.h" yading@11: #include "libavutil/avstring.h" yading@11: #include "libavutil/file.h" yading@11: #include "avformat.h" yading@11: #include yading@11: #if HAVE_IO_H yading@11: #include yading@11: #endif yading@11: #if HAVE_UNISTD_H yading@11: #include yading@11: #endif yading@11: #include yading@11: #include yading@11: #include "os_support.h" yading@11: #include "url.h" yading@11: yading@11: typedef struct Context { yading@11: int fd; yading@11: int64_t end; yading@11: int64_t pos; yading@11: URLContext *inner; yading@11: } Context; yading@11: yading@11: static int cache_open(URLContext *h, const char *arg, int flags) yading@11: { yading@11: char *buffername; yading@11: Context *c= h->priv_data; yading@11: yading@11: av_strstart(arg, "cache:", &arg); yading@11: yading@11: c->fd = av_tempfile("ffcache", &buffername, 0, h); yading@11: if (c->fd < 0){ yading@11: av_log(h, AV_LOG_ERROR, "Failed to create tempfile\n"); yading@11: return c->fd; yading@11: } yading@11: yading@11: unlink(buffername); yading@11: av_freep(&buffername); yading@11: yading@11: return ffurl_open(&c->inner, arg, flags, &h->interrupt_callback, NULL); yading@11: } yading@11: yading@11: static int cache_read(URLContext *h, unsigned char *buf, int size) yading@11: { yading@11: Context *c= h->priv_data; yading@11: int r; yading@11: yading@11: if(c->posend){ yading@11: r = read(c->fd, buf, FFMIN(size, c->end - c->pos)); yading@11: if(r>0) yading@11: c->pos += r; yading@11: return (-1 == r)?AVERROR(errno):r; yading@11: }else{ yading@11: r = ffurl_read(c->inner, buf, size); yading@11: if(r > 0){ yading@11: int r2= write(c->fd, buf, r); yading@11: av_assert0(r2==r); // FIXME handle cache failure yading@11: c->pos += r; yading@11: c->end += r; yading@11: } yading@11: return r; yading@11: } yading@11: } yading@11: yading@11: static int64_t cache_seek(URLContext *h, int64_t pos, int whence) yading@11: { yading@11: Context *c= h->priv_data; yading@11: yading@11: if (whence == AVSEEK_SIZE) { yading@11: pos= ffurl_seek(c->inner, pos, whence); yading@11: if(pos <= 0){ yading@11: pos= ffurl_seek(c->inner, -1, SEEK_END); yading@11: ffurl_seek(c->inner, c->end, SEEK_SET); yading@11: if(pos <= 0) yading@11: return c->end; yading@11: } yading@11: return pos; yading@11: } yading@11: yading@11: pos= lseek(c->fd, pos, whence); yading@11: if(pos<0){ yading@11: return pos; yading@11: }else if(pos <= c->end){ yading@11: c->pos= pos; yading@11: return pos; yading@11: }else{ yading@11: if(lseek(c->fd, c->pos, SEEK_SET) < 0) { yading@11: av_log(h, AV_LOG_ERROR, "Failure to seek in cache\n"); yading@11: } yading@11: return AVERROR(EPIPE); yading@11: } yading@11: } yading@11: yading@11: static int cache_close(URLContext *h) yading@11: { yading@11: Context *c= h->priv_data; yading@11: close(c->fd); yading@11: ffurl_close(c->inner); yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: URLProtocol ff_cache_protocol = { yading@11: .name = "cache", yading@11: .url_open = cache_open, yading@11: .url_read = cache_read, yading@11: .url_seek = cache_seek, yading@11: .url_close = cache_close, yading@11: .priv_data_size = sizeof(Context), yading@11: };