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