00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "avformat.h"
00023 #include "avstring.h"
00024
00025 typedef struct {
00026 int img_first;
00027 int img_last;
00028 int img_number;
00029 int img_count;
00030 int is_pipe;
00031 char path[1024];
00032 } VideoData;
00033
00034 typedef struct {
00035 enum CodecID id;
00036 const char *str;
00037 } IdStrMap;
00038
00039 static const IdStrMap img_tags[] = {
00040 { CODEC_ID_MJPEG , "jpeg"},
00041 { CODEC_ID_MJPEG , "jpg"},
00042 { CODEC_ID_LJPEG , "ljpg"},
00043 { CODEC_ID_PNG , "png"},
00044 { CODEC_ID_PPM , "ppm"},
00045 { CODEC_ID_PGM , "pgm"},
00046 { CODEC_ID_PGMYUV , "pgmyuv"},
00047 { CODEC_ID_PBM , "pbm"},
00048 { CODEC_ID_PAM , "pam"},
00049 { CODEC_ID_MPEG1VIDEO, "mpg1-img"},
00050 { CODEC_ID_MPEG2VIDEO, "mpg2-img"},
00051 { CODEC_ID_MPEG4 , "mpg4-img"},
00052 { CODEC_ID_FFV1 , "ffv1-img"},
00053 { CODEC_ID_RAWVIDEO , "y"},
00054 { CODEC_ID_BMP , "bmp"},
00055 { CODEC_ID_GIF , "gif"},
00056 { CODEC_ID_TARGA , "tga"},
00057 { CODEC_ID_TIFF , "tiff"},
00058 { CODEC_ID_SGI , "sgi"},
00059 { CODEC_ID_PTX , "ptx"},
00060 {0, NULL}
00061 };
00062
00063 static int sizes[][2] = {
00064 { 640, 480 },
00065 { 720, 480 },
00066 { 720, 576 },
00067 { 352, 288 },
00068 { 352, 240 },
00069 { 160, 128 },
00070 { 512, 384 },
00071 { 640, 352 },
00072 { 640, 240 },
00073 };
00074
00075 static int infer_size(int *width_ptr, int *height_ptr, int size)
00076 {
00077 int i;
00078
00079 for(i=0;i<sizeof(sizes)/sizeof(sizes[0]);i++) {
00080 if ((sizes[i][0] * sizes[i][1]) == size) {
00081 *width_ptr = sizes[i][0];
00082 *height_ptr = sizes[i][1];
00083 return 0;
00084 }
00085 }
00086 return -1;
00087 }
00088 static enum CodecID av_str2id(const IdStrMap *tags, const char *str)
00089 {
00090 str= strrchr(str, '.');
00091 if(!str) return CODEC_ID_NONE;
00092 str++;
00093
00094 while (tags->id) {
00095 int i;
00096 for(i=0; toupper(tags->str[i]) == toupper(str[i]); i++){
00097 if(tags->str[i]==0 && str[i]==0)
00098 return tags->id;
00099 }
00100
00101 tags++;
00102 }
00103 return CODEC_ID_NONE;
00104 }
00105
00106
00107 static int find_image_range(int *pfirst_index, int *plast_index,
00108 const char *path)
00109 {
00110 char buf[1024];
00111 int range, last_index, range1, first_index;
00112
00113
00114 for(first_index = 0; first_index < 5; first_index++) {
00115 if (av_get_frame_filename(buf, sizeof(buf), path, first_index) < 0){
00116 *pfirst_index =
00117 *plast_index = 1;
00118 return 0;
00119 }
00120 if (url_exist(buf))
00121 break;
00122 }
00123 if (first_index == 5)
00124 goto fail;
00125
00126
00127 last_index = first_index;
00128 for(;;) {
00129 range = 0;
00130 for(;;) {
00131 if (!range)
00132 range1 = 1;
00133 else
00134 range1 = 2 * range;
00135 if (av_get_frame_filename(buf, sizeof(buf), path,
00136 last_index + range1) < 0)
00137 goto fail;
00138 if (!url_exist(buf))
00139 break;
00140 range = range1;
00141
00142 if (range >= (1 << 30))
00143 goto fail;
00144 }
00145
00146 if (!range)
00147 break;
00148 last_index += range;
00149 }
00150 *pfirst_index = first_index;
00151 *plast_index = last_index;
00152 return 0;
00153 fail:
00154 return -1;
00155 }
00156
00157
00158 static int image_probe(AVProbeData *p)
00159 {
00160 if (p->filename && av_str2id(img_tags, p->filename)) {
00161 if (av_filename_number_test(p->filename))
00162 return AVPROBE_SCORE_MAX;
00163 else
00164 return AVPROBE_SCORE_MAX/2;
00165 }
00166 return 0;
00167 }
00168
00169 enum CodecID av_guess_image2_codec(const char *filename){
00170 return av_str2id(img_tags, filename);
00171 }
00172
00173 static int img_read_header(AVFormatContext *s1, AVFormatParameters *ap)
00174 {
00175 VideoData *s = s1->priv_data;
00176 int first_index, last_index;
00177 AVStream *st;
00178
00179 s1->ctx_flags |= AVFMTCTX_NOHEADER;
00180
00181 st = av_new_stream(s1, 0);
00182 if (!st) {
00183 return AVERROR(ENOMEM);
00184 }
00185
00186 av_strlcpy(s->path, s1->filename, sizeof(s->path));
00187 s->img_number = 0;
00188 s->img_count = 0;
00189
00190
00191 if (s1->iformat->flags & AVFMT_NOFILE)
00192 s->is_pipe = 0;
00193 else{
00194 s->is_pipe = 1;
00195 st->need_parsing = AVSTREAM_PARSE_FULL;
00196 }
00197
00198 if (!ap->time_base.num) {
00199 av_set_pts_info(st, 60, 1, 25);
00200 } else {
00201 av_set_pts_info(st, 60, ap->time_base.num, ap->time_base.den);
00202 }
00203
00204 if(ap->width && ap->height){
00205 st->codec->width = ap->width;
00206 st->codec->height= ap->height;
00207 }
00208
00209 if (!s->is_pipe) {
00210 if (find_image_range(&first_index, &last_index, s->path) < 0)
00211 return AVERROR(EIO);
00212 s->img_first = first_index;
00213 s->img_last = last_index;
00214 s->img_number = first_index;
00215
00216 st->start_time = 0;
00217 st->duration = last_index - first_index + 1;
00218 }
00219
00220 if(ap->video_codec_id){
00221 st->codec->codec_type = CODEC_TYPE_VIDEO;
00222 st->codec->codec_id = ap->video_codec_id;
00223 }else if(ap->audio_codec_id){
00224 st->codec->codec_type = CODEC_TYPE_AUDIO;
00225 st->codec->codec_id = ap->audio_codec_id;
00226 }else{
00227 st->codec->codec_type = CODEC_TYPE_VIDEO;
00228 st->codec->codec_id = av_str2id(img_tags, s->path);
00229 }
00230 if(st->codec->codec_type == CODEC_TYPE_VIDEO && ap->pix_fmt != PIX_FMT_NONE)
00231 st->codec->pix_fmt = ap->pix_fmt;
00232
00233 return 0;
00234 }
00235
00236 static int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
00237 {
00238 VideoData *s = s1->priv_data;
00239 char filename[1024];
00240 int i;
00241 int size[3]={0}, ret[3]={0};
00242 ByteIOContext f1[3], *f[3]= {&f1[0], &f1[1], &f1[2]};
00243 AVCodecContext *codec= s1->streams[0]->codec;
00244
00245 if (!s->is_pipe) {
00246
00247 if (s1->loop_input && s->img_number > s->img_last) {
00248 s->img_number = s->img_first;
00249 }
00250 if (av_get_frame_filename(filename, sizeof(filename),
00251 s->path, s->img_number)<0 && s->img_number > 1)
00252 return AVERROR(EIO);
00253 for(i=0; i<3; i++){
00254 if (url_fopen(f[i], filename, URL_RDONLY) < 0)
00255 return AVERROR(EIO);
00256 size[i]= url_fsize(f[i]);
00257
00258 if(codec->codec_id != CODEC_ID_RAWVIDEO)
00259 break;
00260 filename[ strlen(filename) - 1 ]= 'U' + i;
00261 }
00262
00263 if(codec->codec_id == CODEC_ID_RAWVIDEO && !codec->width)
00264 infer_size(&codec->width, &codec->height, size[0]);
00265 } else {
00266 f[0] = &s1->pb;
00267 if (url_feof(f[0]))
00268 return AVERROR(EIO);
00269 size[0]= 4096;
00270 }
00271
00272 av_new_packet(pkt, size[0] + size[1] + size[2]);
00273 pkt->stream_index = 0;
00274 pkt->flags |= PKT_FLAG_KEY;
00275
00276 pkt->size= 0;
00277 for(i=0; i<3; i++){
00278 if(size[i]){
00279 ret[i]= get_buffer(f[i], pkt->data + pkt->size, size[i]);
00280 if (!s->is_pipe)
00281 url_fclose(f[i]);
00282 if(ret[i]>0)
00283 pkt->size += ret[i];
00284 }
00285 }
00286
00287 if (ret[0] <= 0 || ret[1]<0 || ret[2]<0) {
00288 av_free_packet(pkt);
00289 return AVERROR(EIO);
00290 } else {
00291 s->img_count++;
00292 s->img_number++;
00293 return 0;
00294 }
00295 }
00296
00297 static int img_read_close(AVFormatContext *s1)
00298 {
00299 return 0;
00300 }
00301
00302 #ifdef CONFIG_MUXERS
00303
00304
00305
00306 static int img_write_header(AVFormatContext *s)
00307 {
00308 VideoData *img = s->priv_data;
00309
00310 img->img_number = 1;
00311 av_strlcpy(img->path, s->filename, sizeof(img->path));
00312
00313
00314 if (s->oformat->flags & AVFMT_NOFILE)
00315 img->is_pipe = 0;
00316 else
00317 img->is_pipe = 1;
00318
00319 return 0;
00320 }
00321
00322 static int img_write_packet(AVFormatContext *s, AVPacket *pkt)
00323 {
00324 VideoData *img = s->priv_data;
00325 ByteIOContext pb1[3], *pb[3]= {&pb1[0], &pb1[1], &pb1[2]};
00326 char filename[1024];
00327 AVCodecContext *codec= s->streams[ pkt->stream_index ]->codec;
00328 int i;
00329
00330 if (!img->is_pipe) {
00331 if (av_get_frame_filename(filename, sizeof(filename),
00332 img->path, img->img_number) < 0 && img->img_number>1)
00333 return AVERROR(EIO);
00334 for(i=0; i<3; i++){
00335 if (url_fopen(pb[i], filename, URL_WRONLY) < 0)
00336 return AVERROR(EIO);
00337
00338 if(codec->codec_id != CODEC_ID_RAWVIDEO)
00339 break;
00340 filename[ strlen(filename) - 1 ]= 'U' + i;
00341 }
00342 } else {
00343 pb[0] = &s->pb;
00344 }
00345
00346 if(codec->codec_id == CODEC_ID_RAWVIDEO){
00347 int ysize = codec->width * codec->height;
00348 put_buffer(pb[0], pkt->data , ysize);
00349 put_buffer(pb[1], pkt->data + ysize, (pkt->size - ysize)/2);
00350 put_buffer(pb[2], pkt->data + ysize +(pkt->size - ysize)/2, (pkt->size - ysize)/2);
00351 put_flush_packet(pb[1]);
00352 put_flush_packet(pb[2]);
00353 url_fclose(pb[1]);
00354 url_fclose(pb[2]);
00355 }else{
00356 put_buffer(pb[0], pkt->data, pkt->size);
00357 }
00358 put_flush_packet(pb[0]);
00359 if (!img->is_pipe) {
00360 url_fclose(pb[0]);
00361 }
00362
00363 img->img_number++;
00364 return 0;
00365 }
00366
00367 static int img_write_trailer(AVFormatContext *s)
00368 {
00369 return 0;
00370 }
00371
00372 #endif
00373
00374
00375 #ifdef CONFIG_IMAGE2_DEMUXER
00376 AVInputFormat image2_demuxer = {
00377 "image2",
00378 "image2 sequence",
00379 sizeof(VideoData),
00380 image_probe,
00381 img_read_header,
00382 img_read_packet,
00383 img_read_close,
00384 NULL,
00385 NULL,
00386 AVFMT_NOFILE,
00387 };
00388 #endif
00389 #ifdef CONFIG_IMAGE2PIPE_DEMUXER
00390 AVInputFormat image2pipe_demuxer = {
00391 "image2pipe",
00392 "piped image2 sequence",
00393 sizeof(VideoData),
00394 NULL,
00395 img_read_header,
00396 img_read_packet,
00397 img_read_close,
00398 NULL,
00399 };
00400 #endif
00401
00402
00403 #ifdef CONFIG_IMAGE2_MUXER
00404 AVOutputFormat image2_muxer = {
00405 "image2",
00406 "image2 sequence",
00407 "",
00408 "",
00409 sizeof(VideoData),
00410 CODEC_ID_NONE,
00411 CODEC_ID_MJPEG,
00412 img_write_header,
00413 img_write_packet,
00414 img_write_trailer,
00415 AVFMT_NOFILE,
00416 };
00417 #endif
00418 #ifdef CONFIG_IMAGE2PIPE_MUXER
00419 AVOutputFormat image2pipe_muxer = {
00420 "image2pipe",
00421 "piped image2 sequence",
00422 "",
00423 "",
00424 sizeof(VideoData),
00425 CODEC_ID_NONE,
00426 CODEC_ID_MJPEG,
00427 img_write_header,
00428 img_write_packet,
00429 img_write_trailer,
00430 };
00431 #endif