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 };