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