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