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