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 "libavutil/log.h"
00026 #include "libavutil/opt.h"
00027 #include "libavutil/pixdesc.h"
00028 #include "libavutil/parseutils.h"
00029 #include "avformat.h"
00030 #include "avio_internal.h"
00031 #include "internal.h"
00032
00033 typedef struct {
00034 const AVClass *class;
00035 int img_first;
00036 int img_last;
00037 int img_number;
00038 int img_count;
00039 int is_pipe;
00040 char path[1024];
00041 char *pixel_format;
00042 char *video_size;
00043 char *framerate;
00044 int loop;
00045 } VideoData;
00046
00047 typedef struct {
00048 enum CodecID id;
00049 const char *str;
00050 } IdStrMap;
00051
00052 static const IdStrMap img_tags[] = {
00053 { CODEC_ID_MJPEG , "jpeg"},
00054 { CODEC_ID_MJPEG , "jpg"},
00055 { CODEC_ID_LJPEG , "ljpg"},
00056 { CODEC_ID_PNG , "png"},
00057 { CODEC_ID_PNG , "mng"},
00058 { CODEC_ID_PPM , "ppm"},
00059 { CODEC_ID_PPM , "pnm"},
00060 { CODEC_ID_PGM , "pgm"},
00061 { CODEC_ID_PGMYUV , "pgmyuv"},
00062 { CODEC_ID_PBM , "pbm"},
00063 { CODEC_ID_PAM , "pam"},
00064 { CODEC_ID_MPEG1VIDEO, "mpg1-img"},
00065 { CODEC_ID_MPEG2VIDEO, "mpg2-img"},
00066 { CODEC_ID_MPEG4 , "mpg4-img"},
00067 { CODEC_ID_FFV1 , "ffv1-img"},
00068 { CODEC_ID_RAWVIDEO , "y"},
00069 { CODEC_ID_BMP , "bmp"},
00070 { CODEC_ID_GIF , "gif"},
00071 { CODEC_ID_TARGA , "tga"},
00072 { CODEC_ID_TIFF , "tiff"},
00073 { CODEC_ID_TIFF , "tif"},
00074 { CODEC_ID_SGI , "sgi"},
00075 { CODEC_ID_PTX , "ptx"},
00076 { CODEC_ID_PCX , "pcx"},
00077 { CODEC_ID_SUNRAST , "sun"},
00078 { CODEC_ID_SUNRAST , "ras"},
00079 { CODEC_ID_SUNRAST , "rs"},
00080 { CODEC_ID_SUNRAST , "im1"},
00081 { CODEC_ID_SUNRAST , "im8"},
00082 { CODEC_ID_SUNRAST , "im24"},
00083 { CODEC_ID_SUNRAST , "sunras"},
00084 { CODEC_ID_JPEG2000 , "jp2"},
00085 { CODEC_ID_JPEG2000 , "jpc"},
00086 { CODEC_ID_DPX , "dpx"},
00087 { CODEC_ID_PICTOR , "pic"},
00088 { CODEC_ID_NONE , NULL}
00089 };
00090
00091 static const int sizes[][2] = {
00092 { 640, 480 },
00093 { 720, 480 },
00094 { 720, 576 },
00095 { 352, 288 },
00096 { 352, 240 },
00097 { 160, 128 },
00098 { 512, 384 },
00099 { 640, 352 },
00100 { 640, 240 },
00101 };
00102
00103 static int infer_size(int *width_ptr, int *height_ptr, int size)
00104 {
00105 int i;
00106
00107 for(i=0;i<FF_ARRAY_ELEMS(sizes);i++) {
00108 if ((sizes[i][0] * sizes[i][1]) == size) {
00109 *width_ptr = sizes[i][0];
00110 *height_ptr = sizes[i][1];
00111 return 0;
00112 }
00113 }
00114 return -1;
00115 }
00116 static enum CodecID av_str2id(const IdStrMap *tags, const char *str)
00117 {
00118 str= strrchr(str, '.');
00119 if(!str) return CODEC_ID_NONE;
00120 str++;
00121
00122 while (tags->id) {
00123 if (!av_strcasecmp(str, tags->str))
00124 return tags->id;
00125
00126 tags++;
00127 }
00128 return CODEC_ID_NONE;
00129 }
00130
00131
00132 static int find_image_range(int *pfirst_index, int *plast_index,
00133 const char *path)
00134 {
00135 char buf[1024];
00136 int range, last_index, range1, first_index;
00137
00138
00139 for(first_index = 0; first_index < 5; first_index++) {
00140 if (av_get_frame_filename(buf, sizeof(buf), path, first_index) < 0){
00141 *pfirst_index =
00142 *plast_index = 1;
00143 if (avio_check(buf, AVIO_FLAG_READ) > 0)
00144 return 0;
00145 return -1;
00146 }
00147 if (avio_check(buf, AVIO_FLAG_READ) > 0)
00148 break;
00149 }
00150 if (first_index == 5)
00151 goto fail;
00152
00153
00154 last_index = first_index;
00155 for(;;) {
00156 range = 0;
00157 for(;;) {
00158 if (!range)
00159 range1 = 1;
00160 else
00161 range1 = 2 * range;
00162 if (av_get_frame_filename(buf, sizeof(buf), path,
00163 last_index + range1) < 0)
00164 goto fail;
00165 if (avio_check(buf, AVIO_FLAG_READ) <= 0)
00166 break;
00167 range = range1;
00168
00169 if (range >= (1 << 30))
00170 goto fail;
00171 }
00172
00173 if (!range)
00174 break;
00175 last_index += range;
00176 }
00177 *pfirst_index = first_index;
00178 *plast_index = last_index;
00179 return 0;
00180 fail:
00181 return -1;
00182 }
00183
00184
00185 static int read_probe(AVProbeData *p)
00186 {
00187 if (p->filename && av_str2id(img_tags, p->filename)) {
00188 if (av_filename_number_test(p->filename))
00189 return AVPROBE_SCORE_MAX;
00190 else
00191 return AVPROBE_SCORE_MAX/2;
00192 }
00193 return 0;
00194 }
00195
00196 enum CodecID ff_guess_image2_codec(const char *filename)
00197 {
00198 return av_str2id(img_tags, filename);
00199 }
00200
00201 #if FF_API_GUESS_IMG2_CODEC
00202 enum CodecID av_guess_image2_codec(const char *filename){
00203 return av_str2id(img_tags, filename);
00204 }
00205 #endif
00206
00207 static int read_header(AVFormatContext *s1, AVFormatParameters *ap)
00208 {
00209 VideoData *s = s1->priv_data;
00210 int first_index, last_index, ret = 0;
00211 int width = 0, height = 0;
00212 AVStream *st;
00213 enum PixelFormat pix_fmt = PIX_FMT_NONE;
00214 AVRational framerate;
00215
00216 s1->ctx_flags |= AVFMTCTX_NOHEADER;
00217
00218 st = avformat_new_stream(s1, NULL);
00219 if (!st) {
00220 return AVERROR(ENOMEM);
00221 }
00222
00223 if (s->pixel_format && (pix_fmt = av_get_pix_fmt(s->pixel_format)) == PIX_FMT_NONE) {
00224 av_log(s1, AV_LOG_ERROR, "No such pixel format: %s.\n", s->pixel_format);
00225 return AVERROR(EINVAL);
00226 }
00227 if (s->video_size && (ret = av_parse_video_size(&width, &height, s->video_size)) < 0) {
00228 av_log(s, AV_LOG_ERROR, "Could not parse video size: %s.\n", s->video_size);
00229 return ret;
00230 }
00231 if ((ret = av_parse_video_rate(&framerate, s->framerate)) < 0) {
00232 av_log(s, AV_LOG_ERROR, "Could not parse framerate: %s.\n", s->framerate);
00233 return ret;
00234 }
00235
00236 #if FF_API_LOOP_INPUT
00237 if (s1->loop_input)
00238 s->loop = s1->loop_input;
00239 #endif
00240
00241 av_strlcpy(s->path, s1->filename, sizeof(s->path));
00242 s->img_number = 0;
00243 s->img_count = 0;
00244
00245
00246 if (s1->iformat->flags & AVFMT_NOFILE)
00247 s->is_pipe = 0;
00248 else{
00249 s->is_pipe = 1;
00250 st->need_parsing = AVSTREAM_PARSE_FULL;
00251 }
00252
00253 avpriv_set_pts_info(st, 60, framerate.den, framerate.num);
00254
00255 if (width && height) {
00256 st->codec->width = width;
00257 st->codec->height = height;
00258 }
00259
00260 if (!s->is_pipe) {
00261 if (find_image_range(&first_index, &last_index, s->path) < 0)
00262 return AVERROR(ENOENT);
00263 s->img_first = first_index;
00264 s->img_last = last_index;
00265 s->img_number = first_index;
00266
00267 st->start_time = 0;
00268 st->duration = last_index - first_index + 1;
00269 }
00270
00271 if(s1->video_codec_id){
00272 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00273 st->codec->codec_id = s1->video_codec_id;
00274 }else if(s1->audio_codec_id){
00275 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00276 st->codec->codec_id = s1->audio_codec_id;
00277 }else{
00278 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00279 st->codec->codec_id = av_str2id(img_tags, s->path);
00280 }
00281 if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO && pix_fmt != PIX_FMT_NONE)
00282 st->codec->pix_fmt = pix_fmt;
00283
00284 return 0;
00285 }
00286
00287 static int read_packet(AVFormatContext *s1, AVPacket *pkt)
00288 {
00289 VideoData *s = s1->priv_data;
00290 char filename[1024];
00291 int i;
00292 int size[3]={0}, ret[3]={0};
00293 AVIOContext *f[3];
00294 AVCodecContext *codec= s1->streams[0]->codec;
00295
00296 if (!s->is_pipe) {
00297
00298 if (s->loop && s->img_number > s->img_last) {
00299 s->img_number = s->img_first;
00300 }
00301 if (s->img_number > s->img_last)
00302 return AVERROR_EOF;
00303 if (av_get_frame_filename(filename, sizeof(filename),
00304 s->path, s->img_number)<0 && s->img_number > 1)
00305 return AVERROR(EIO);
00306 for(i=0; i<3; i++){
00307 if (avio_open2(&f[i], filename, AVIO_FLAG_READ,
00308 &s1->interrupt_callback, NULL) < 0) {
00309 if(i==1)
00310 break;
00311 av_log(s1, AV_LOG_ERROR, "Could not open file : %s\n",filename);
00312 return AVERROR(EIO);
00313 }
00314 size[i]= avio_size(f[i]);
00315
00316 if(codec->codec_id != CODEC_ID_RAWVIDEO)
00317 break;
00318 filename[ strlen(filename) - 1 ]= 'U' + i;
00319 }
00320
00321 if(codec->codec_id == CODEC_ID_RAWVIDEO && !codec->width)
00322 infer_size(&codec->width, &codec->height, size[0]);
00323 } else {
00324 f[0] = s1->pb;
00325 if (f[0]->eof_reached)
00326 return AVERROR(EIO);
00327 size[0]= 4096;
00328 }
00329
00330 av_new_packet(pkt, size[0] + size[1] + size[2]);
00331 pkt->stream_index = 0;
00332 pkt->flags |= AV_PKT_FLAG_KEY;
00333
00334 pkt->size= 0;
00335 for(i=0; i<3; i++){
00336 if(size[i]){
00337 ret[i]= avio_read(f[i], pkt->data + pkt->size, size[i]);
00338 if (!s->is_pipe)
00339 avio_close(f[i]);
00340 if(ret[i]>0)
00341 pkt->size += ret[i];
00342 }
00343 }
00344
00345 if (ret[0] <= 0 || ret[1]<0 || ret[2]<0) {
00346 av_free_packet(pkt);
00347 return AVERROR(EIO);
00348 } else {
00349 s->img_count++;
00350 s->img_number++;
00351 return 0;
00352 }
00353 }
00354
00355 #if CONFIG_IMAGE2_MUXER || CONFIG_IMAGE2PIPE_MUXER
00356
00357
00358
00359 static int write_header(AVFormatContext *s)
00360 {
00361 VideoData *img = s->priv_data;
00362
00363 img->img_number = 1;
00364 av_strlcpy(img->path, s->filename, sizeof(img->path));
00365
00366
00367 if (s->oformat->flags & AVFMT_NOFILE)
00368 img->is_pipe = 0;
00369 else
00370 img->is_pipe = 1;
00371
00372 return 0;
00373 }
00374
00375 static int write_packet(AVFormatContext *s, AVPacket *pkt)
00376 {
00377 VideoData *img = s->priv_data;
00378 AVIOContext *pb[3];
00379 char filename[1024];
00380 AVCodecContext *codec= s->streams[ pkt->stream_index ]->codec;
00381 int i;
00382
00383 if (!img->is_pipe) {
00384 if (av_get_frame_filename(filename, sizeof(filename),
00385 img->path, img->img_number) < 0 && img->img_number>1) {
00386 av_log(s, AV_LOG_ERROR,
00387 "Could not get frame filename number %d from pattern '%s'\n",
00388 img->img_number, img->path);
00389 return AVERROR(EIO);
00390 }
00391 for(i=0; i<3; i++){
00392 if (avio_open2(&pb[i], filename, AVIO_FLAG_WRITE,
00393 &s->interrupt_callback, NULL) < 0) {
00394 av_log(s, AV_LOG_ERROR, "Could not open file : %s\n",filename);
00395 return AVERROR(EIO);
00396 }
00397
00398 if(codec->codec_id != CODEC_ID_RAWVIDEO)
00399 break;
00400 filename[ strlen(filename) - 1 ]= 'U' + i;
00401 }
00402 } else {
00403 pb[0] = s->pb;
00404 }
00405
00406 if(codec->codec_id == CODEC_ID_RAWVIDEO){
00407 int ysize = codec->width * codec->height;
00408 avio_write(pb[0], pkt->data , ysize);
00409 avio_write(pb[1], pkt->data + ysize, (pkt->size - ysize)/2);
00410 avio_write(pb[2], pkt->data + ysize +(pkt->size - ysize)/2, (pkt->size - ysize)/2);
00411 avio_flush(pb[1]);
00412 avio_flush(pb[2]);
00413 avio_close(pb[1]);
00414 avio_close(pb[2]);
00415 }else{
00416 if(av_str2id(img_tags, s->filename) == CODEC_ID_JPEG2000){
00417 AVStream *st = s->streams[0];
00418 if(st->codec->extradata_size > 8 &&
00419 AV_RL32(st->codec->extradata+4) == MKTAG('j','p','2','h')){
00420 if(pkt->size < 8 || AV_RL32(pkt->data+4) != MKTAG('j','p','2','c'))
00421 goto error;
00422 avio_wb32(pb[0], 12);
00423 ffio_wfourcc(pb[0], "jP ");
00424 avio_wb32(pb[0], 0x0D0A870A);
00425 avio_wb32(pb[0], 20);
00426 ffio_wfourcc(pb[0], "ftyp");
00427 ffio_wfourcc(pb[0], "jp2 ");
00428 avio_wb32(pb[0], 0);
00429 ffio_wfourcc(pb[0], "jp2 ");
00430 avio_write(pb[0], st->codec->extradata, st->codec->extradata_size);
00431 }else if(pkt->size < 8 ||
00432 (!st->codec->extradata_size &&
00433 AV_RL32(pkt->data+4) != MKTAG('j','P',' ',' '))){
00434 error:
00435 av_log(s, AV_LOG_ERROR, "malformed JPEG 2000 codestream\n");
00436 return -1;
00437 }
00438 }
00439 avio_write(pb[0], pkt->data, pkt->size);
00440 }
00441 avio_flush(pb[0]);
00442 if (!img->is_pipe) {
00443 avio_close(pb[0]);
00444 }
00445
00446 img->img_number++;
00447 return 0;
00448 }
00449
00450 #endif
00451
00452 #define OFFSET(x) offsetof(VideoData, x)
00453 #define DEC AV_OPT_FLAG_DECODING_PARAM
00454 static const AVOption options[] = {
00455 { "pixel_format", "", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
00456 { "video_size", "", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
00457 { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC },
00458 { "loop", "", OFFSET(loop), AV_OPT_TYPE_INT, {.dbl = 0}, 0, 1, DEC },
00459 { NULL },
00460 };
00461
00462
00463 #if CONFIG_IMAGE2_DEMUXER
00464 static const AVClass img2_class = {
00465 .class_name = "image2 demuxer",
00466 .item_name = av_default_item_name,
00467 .option = options,
00468 .version = LIBAVUTIL_VERSION_INT,
00469 };
00470 AVInputFormat ff_image2_demuxer = {
00471 .name = "image2",
00472 .long_name = NULL_IF_CONFIG_SMALL("image2 sequence"),
00473 .priv_data_size = sizeof(VideoData),
00474 .read_probe = read_probe,
00475 .read_header = read_header,
00476 .read_packet = read_packet,
00477 .flags = AVFMT_NOFILE,
00478 .priv_class = &img2_class,
00479 };
00480 #endif
00481 #if CONFIG_IMAGE2PIPE_DEMUXER
00482 static const AVClass img2pipe_class = {
00483 .class_name = "image2pipe demuxer",
00484 .item_name = av_default_item_name,
00485 .option = options,
00486 .version = LIBAVUTIL_VERSION_INT,
00487 };
00488 AVInputFormat ff_image2pipe_demuxer = {
00489 .name = "image2pipe",
00490 .long_name = NULL_IF_CONFIG_SMALL("piped image2 sequence"),
00491 .priv_data_size = sizeof(VideoData),
00492 .read_header = read_header,
00493 .read_packet = read_packet,
00494 .priv_class = &img2pipe_class,
00495 };
00496 #endif
00497
00498
00499 #if CONFIG_IMAGE2_MUXER
00500 AVOutputFormat ff_image2_muxer = {
00501 .name = "image2",
00502 .long_name = NULL_IF_CONFIG_SMALL("image2 sequence"),
00503 .extensions = "bmp,dpx,jpeg,jpg,ljpg,pam,pbm,pcx,pgm,pgmyuv,png,"
00504 "ppm,sgi,tga,tif,tiff,jp2",
00505 .priv_data_size = sizeof(VideoData),
00506 .video_codec = CODEC_ID_MJPEG,
00507 .write_header = write_header,
00508 .write_packet = write_packet,
00509 .flags = AVFMT_NOTIMESTAMPS | AVFMT_NODIMENSIONS | AVFMT_NOFILE
00510 };
00511 #endif
00512 #if CONFIG_IMAGE2PIPE_MUXER
00513 AVOutputFormat ff_image2pipe_muxer = {
00514 .name = "image2pipe",
00515 .long_name = NULL_IF_CONFIG_SMALL("piped image2 sequence"),
00516 .priv_data_size = sizeof(VideoData),
00517 .video_codec = CODEC_ID_MJPEG,
00518 .write_header = write_header,
00519 .write_packet = write_packet,
00520 .flags = AVFMT_NOTIMESTAMPS | AVFMT_NODIMENSIONS
00521 };
00522 #endif