00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00031 #include "libavutil/avassert.h"
00032 #include "libavutil/avstring.h"
00033 #include "libavutil/file.h"
00034 #include "avformat.h"
00035 #include <fcntl.h>
00036 #if HAVE_IO_H
00037 #include <io.h>
00038 #endif
00039 #if HAVE_UNISTD_H
00040 #include <unistd.h>
00041 #endif
00042 #include <sys/stat.h>
00043 #include <stdlib.h>
00044 #include "os_support.h"
00045 #include "url.h"
00046 
00047 typedef struct Context {
00048     int fd;
00049     int64_t end;
00050     int64_t pos;
00051     URLContext *inner;
00052 } Context;
00053 
00054 static int cache_open(URLContext *h, const char *arg, int flags)
00055 {
00056     char *buffername;
00057     Context *c= h->priv_data;
00058 
00059     av_strstart(arg, "cache:", &arg);
00060 
00061     c->fd = av_tempfile("ffcache", &buffername, 0, h);
00062     if (c->fd < 0){
00063         av_log(h, AV_LOG_ERROR, "Failed to create tempfile\n");
00064         return c->fd;
00065     }
00066 
00067     unlink(buffername);
00068     av_freep(&buffername);
00069 
00070     return ffurl_open(&c->inner, arg, flags, &h->interrupt_callback, NULL);
00071 }
00072 
00073 static int cache_read(URLContext *h, unsigned char *buf, int size)
00074 {
00075     Context *c= h->priv_data;
00076     int r;
00077 
00078     if(c->pos<c->end){
00079         r = read(c->fd, buf, FFMIN(size, c->end - c->pos));
00080         if(r>0)
00081             c->pos += r;
00082         return (-1 == r)?AVERROR(errno):r;
00083     }else{
00084         r = ffurl_read(c->inner, buf, size);
00085         if(r > 0){
00086             int r2= write(c->fd, buf, r);
00087             av_assert0(r2==r); 
00088             c->pos += r;
00089             c->end += r;
00090         }
00091         return r;
00092     }
00093 }
00094 
00095 static int64_t cache_seek(URLContext *h, int64_t pos, int whence)
00096 {
00097     Context *c= h->priv_data;
00098 
00099     if (whence == AVSEEK_SIZE) {
00100         pos= ffurl_seek(c->inner, pos, whence);
00101         if(pos <= 0){
00102             pos= ffurl_seek(c->inner, -1, SEEK_END);
00103             ffurl_seek(c->inner, c->end, SEEK_SET);
00104             if(pos <= 0)
00105                 return c->end;
00106         }
00107         return pos;
00108     }
00109 
00110     pos= lseek(c->fd, pos, whence);
00111     if(pos<0){
00112         return pos;
00113     }else if(pos <= c->end){
00114         c->pos= pos;
00115         return pos;
00116     }else{
00117         lseek(c->fd, c->pos, SEEK_SET);
00118         return AVERROR(EPIPE);
00119     }
00120 }
00121 
00122 static int cache_close(URLContext *h)
00123 {
00124     Context *c= h->priv_data;
00125     close(c->fd);
00126     ffurl_close(c->inner);
00127 
00128     return 0;
00129 }
00130 
00131 URLProtocol ff_cache_protocol = {
00132     .name                = "cache",
00133     .url_open            = cache_open,
00134     .url_read            = cache_read,
00135     .url_seek            = cache_seek,
00136     .url_close           = cache_close,
00137     .priv_data_size      = sizeof(Context),
00138 };