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/avstring.h"
00024 #include "libavutil/log.h"
00025 #include "libavutil/opt.h"
00026 #include "libavutil/pixdesc.h"
00027 #include "libavutil/parseutils.h"
00028 #include "avformat.h"
00029 #include "internal.h"
00030 #if HAVE_GLOB
00031 #include <glob.h>
00032
00033
00034
00035 #ifndef GLOB_NOMAGIC
00036 #define GLOB_NOMAGIC 0
00037 #endif
00038 #ifndef GLOB_BRACE
00039 #define GLOB_BRACE 0
00040 #endif
00041
00042 #endif
00043
00044 typedef struct {
00045 const AVClass *class;
00046 int img_first;
00047 int img_last;
00048 int img_number;
00049 int img_count;
00050 int is_pipe;
00051 int split_planes;
00052 char path[1024];
00053 char *pixel_format;
00054 char *video_size;
00055 char *framerate;
00056 int loop;
00057 enum { PT_GLOB_SEQUENCE, PT_GLOB, PT_SEQUENCE } pattern_type;
00058 int use_glob;
00059 #if HAVE_GLOB
00060 glob_t globstate;
00061 #endif
00062 int start_number;
00063 int start_number_range;
00064 } VideoDemuxData;
00065
00066 static const int sizes[][2] = {
00067 { 640, 480 },
00068 { 720, 480 },
00069 { 720, 576 },
00070 { 352, 288 },
00071 { 352, 240 },
00072 { 160, 128 },
00073 { 512, 384 },
00074 { 640, 352 },
00075 { 640, 240 },
00076 };
00077
00078 static int infer_size(int *width_ptr, int *height_ptr, int size)
00079 {
00080 int i;
00081
00082 for(i=0;i<FF_ARRAY_ELEMS(sizes);i++) {
00083 if ((sizes[i][0] * sizes[i][1]) == size) {
00084 *width_ptr = sizes[i][0];
00085 *height_ptr = sizes[i][1];
00086 return 0;
00087 }
00088 }
00089 return -1;
00090 }
00091
00092 static int is_glob(const char *path)
00093 {
00094 #if HAVE_GLOB
00095 size_t span = 0;
00096 const char *p = path;
00097
00098 while (p = strchr(p, '%')) {
00099 if (*(++p) == '%') {
00100 ++p;
00101 continue;
00102 }
00103 if (span = strspn(p, "*?[]{}"))
00104 break;
00105 }
00106
00107 return span != 0;
00108 #else
00109 return 0;
00110 #endif
00111 }
00112
00122 static int find_image_range(int *pfirst_index, int *plast_index,
00123 const char *path, int start_index, int start_index_range)
00124 {
00125 char buf[1024];
00126 int range, last_index, range1, first_index;
00127
00128
00129 for (first_index = start_index; first_index < start_index + start_index_range; first_index++) {
00130 if (av_get_frame_filename(buf, sizeof(buf), path, first_index) < 0){
00131 *pfirst_index =
00132 *plast_index = 1;
00133 if (avio_check(buf, AVIO_FLAG_READ) > 0)
00134 return 0;
00135 return -1;
00136 }
00137 if (avio_check(buf, AVIO_FLAG_READ) > 0)
00138 break;
00139 }
00140 if (first_index == start_index + start_index_range)
00141 goto fail;
00142
00143
00144 last_index = first_index;
00145 for(;;) {
00146 range = 0;
00147 for(;;) {
00148 if (!range)
00149 range1 = 1;
00150 else
00151 range1 = 2 * range;
00152 if (av_get_frame_filename(buf, sizeof(buf), path,
00153 last_index + range1) < 0)
00154 goto fail;
00155 if (avio_check(buf, AVIO_FLAG_READ) <= 0)
00156 break;
00157 range = range1;
00158
00159 if (range >= (1 << 30))
00160 goto fail;
00161 }
00162
00163 if (!range)
00164 break;
00165 last_index += range;
00166 }
00167 *pfirst_index = first_index;
00168 *plast_index = last_index;
00169 return 0;
00170 fail:
00171 return -1;
00172 }
00173
00174
00175 static int read_probe(AVProbeData *p)
00176 {
00177 if (p->filename && ff_guess_image2_codec(p->filename)) {
00178 if (av_filename_number_test(p->filename))
00179 return AVPROBE_SCORE_MAX;
00180 else if (is_glob(p->filename))
00181 return AVPROBE_SCORE_MAX;
00182 else
00183 return AVPROBE_SCORE_MAX/2;
00184 }
00185 return 0;
00186 }
00187
00188 static int read_header(AVFormatContext *s1)
00189 {
00190 VideoDemuxData *s = s1->priv_data;
00191 int first_index, last_index, ret = 0;
00192 int width = 0, height = 0;
00193 AVStream *st;
00194 enum PixelFormat pix_fmt = PIX_FMT_NONE;
00195 AVRational framerate;
00196
00197 s1->ctx_flags |= AVFMTCTX_NOHEADER;
00198
00199 st = avformat_new_stream(s1, NULL);
00200 if (!st) {
00201 return AVERROR(ENOMEM);
00202 }
00203
00204 if (s->pixel_format && (pix_fmt = av_get_pix_fmt(s->pixel_format)) == PIX_FMT_NONE) {
00205 av_log(s1, AV_LOG_ERROR, "No such pixel format: %s.\n", s->pixel_format);
00206 return AVERROR(EINVAL);
00207 }
00208 if (s->video_size && (ret = av_parse_video_size(&width, &height, s->video_size)) < 0) {
00209 av_log(s, AV_LOG_ERROR, "Could not parse video size: %s.\n", s->video_size);
00210 return ret;
00211 }
00212 if ((ret = av_parse_video_rate(&framerate, s->framerate)) < 0) {
00213 av_log(s, AV_LOG_ERROR, "Could not parse framerate: %s.\n", s->framerate);
00214 return ret;
00215 }
00216
00217 av_strlcpy(s->path, s1->filename, sizeof(s->path));
00218 s->img_number = 0;
00219 s->img_count = 0;
00220
00221
00222 if (s1->iformat->flags & AVFMT_NOFILE)
00223 s->is_pipe = 0;
00224 else{
00225 s->is_pipe = 1;
00226 st->need_parsing = AVSTREAM_PARSE_FULL;
00227 }
00228
00229 avpriv_set_pts_info(st, 60, framerate.den, framerate.num);
00230
00231 if (width && height) {
00232 st->codec->width = width;
00233 st->codec->height = height;
00234 }
00235
00236 if (!s->is_pipe) {
00237 if (s->pattern_type == PT_GLOB_SEQUENCE) {
00238 s->use_glob = is_glob(s->path);
00239 if (s->use_glob) {
00240 char *p = s->path, *q, *dup;
00241 int gerr;
00242
00243 av_log(s1, AV_LOG_WARNING, "Pattern type 'glob_sequence' is deprecated: "
00244 "use pattern_type 'glob' instead\n");
00245 #if HAVE_GLOB
00246 dup = q = av_strdup(p);
00247 while (*q) {
00248
00249 if ((p - s->path) >= (sizeof(s->path) - 2))
00250 break;
00251 if (*q == '%' && strspn(q + 1, "%*?[]{}"))
00252 ++q;
00253 else if (strspn(q, "\\*?[]{}"))
00254 *p++ = '\\';
00255 *p++ = *q++;
00256 }
00257 *p = 0;
00258 av_free(dup);
00259
00260 gerr = glob(s->path, GLOB_NOCHECK|GLOB_BRACE|GLOB_NOMAGIC, NULL, &s->globstate);
00261 if (gerr != 0) {
00262 return AVERROR(ENOENT);
00263 }
00264 first_index = 0;
00265 last_index = s->globstate.gl_pathc - 1;
00266 #endif
00267 }
00268 }
00269 if ((s->pattern_type == PT_GLOB_SEQUENCE && !s->use_glob) || s->pattern_type == PT_SEQUENCE) {
00270 if (find_image_range(&first_index, &last_index, s->path,
00271 s->start_number, s->start_number_range) < 0) {
00272 av_log(s1, AV_LOG_ERROR,
00273 "Could find no file with with path '%s' and index in the range %d-%d\n",
00274 s->path, s->start_number, s->start_number + s->start_number_range - 1);
00275 return AVERROR(ENOENT);
00276 }
00277 } else if (s->pattern_type == PT_GLOB) {
00278 #if HAVE_GLOB
00279 int gerr;
00280 gerr = glob(s->path, GLOB_NOCHECK|GLOB_BRACE|GLOB_NOMAGIC, NULL, &s->globstate);
00281 if (gerr != 0) {
00282 return AVERROR(ENOENT);
00283 }
00284 first_index = 0;
00285 last_index = s->globstate.gl_pathc - 1;
00286 s->use_glob = 1;
00287 #else
00288 av_log(s1, AV_LOG_ERROR,
00289 "Pattern type 'glob' was selected but globbing "
00290 "is not supported by this libavformat build\n");
00291 return AVERROR(ENOSYS);
00292 #endif
00293 } else if (s->pattern_type != PT_GLOB_SEQUENCE) {
00294 av_log(s1, AV_LOG_ERROR,
00295 "Unknown value '%d' for pattern_type option\n", s->pattern_type);
00296 return AVERROR(EINVAL);
00297 }
00298 s->img_first = first_index;
00299 s->img_last = last_index;
00300 s->img_number = first_index;
00301
00302 st->start_time = 0;
00303 st->duration = last_index - first_index + 1;
00304 }
00305
00306 if(s1->video_codec_id){
00307 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00308 st->codec->codec_id = s1->video_codec_id;
00309 }else if(s1->audio_codec_id){
00310 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00311 st->codec->codec_id = s1->audio_codec_id;
00312 }else{
00313 const char *str= strrchr(s->path, '.');
00314 s->split_planes = str && !av_strcasecmp(str + 1, "y");
00315 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00316 st->codec->codec_id = ff_guess_image2_codec(s->path);
00317 if (st->codec->codec_id == AV_CODEC_ID_LJPEG)
00318 st->codec->codec_id = AV_CODEC_ID_MJPEG;
00319 }
00320 if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO && pix_fmt != PIX_FMT_NONE)
00321 st->codec->pix_fmt = pix_fmt;
00322
00323 return 0;
00324 }
00325
00326 static int read_packet(AVFormatContext *s1, AVPacket *pkt)
00327 {
00328 VideoDemuxData *s = s1->priv_data;
00329 char filename_bytes[1024];
00330 char *filename = filename_bytes;
00331 int i;
00332 int size[3]={0}, ret[3]={0};
00333 AVIOContext *f[3] = {NULL};
00334 AVCodecContext *codec= s1->streams[0]->codec;
00335
00336 if (!s->is_pipe) {
00337
00338 if (s->loop && s->img_number > s->img_last) {
00339 s->img_number = s->img_first;
00340 }
00341 if (s->img_number > s->img_last)
00342 return AVERROR_EOF;
00343 if (s->use_glob) {
00344 #if HAVE_GLOB
00345 filename = s->globstate.gl_pathv[s->img_number];
00346 #endif
00347 } else {
00348 if (av_get_frame_filename(filename_bytes, sizeof(filename_bytes),
00349 s->path, s->img_number)<0 && s->img_number > 1)
00350 return AVERROR(EIO);
00351 }
00352 for(i=0; i<3; i++){
00353 if (avio_open2(&f[i], filename, AVIO_FLAG_READ,
00354 &s1->interrupt_callback, NULL) < 0) {
00355 if(i>=1)
00356 break;
00357 av_log(s1, AV_LOG_ERROR, "Could not open file : %s\n",filename);
00358 return AVERROR(EIO);
00359 }
00360 size[i]= avio_size(f[i]);
00361
00362 if(!s->split_planes)
00363 break;
00364 filename[ strlen(filename) - 1 ]= 'U' + i;
00365 }
00366
00367 if(codec->codec_id == AV_CODEC_ID_RAWVIDEO && !codec->width)
00368 infer_size(&codec->width, &codec->height, size[0]);
00369 } else {
00370 f[0] = s1->pb;
00371 if (url_feof(f[0]))
00372 return AVERROR(EIO);
00373 size[0]= 4096;
00374 }
00375
00376 av_new_packet(pkt, size[0] + size[1] + size[2]);
00377 pkt->stream_index = 0;
00378 pkt->flags |= AV_PKT_FLAG_KEY;
00379
00380 pkt->size= 0;
00381 for(i=0; i<3; i++){
00382 if(f[i]){
00383 ret[i]= avio_read(f[i], pkt->data + pkt->size, size[i]);
00384 if (!s->is_pipe)
00385 avio_close(f[i]);
00386 if(ret[i]>0)
00387 pkt->size += ret[i];
00388 }
00389 }
00390
00391 if (ret[0] <= 0 || ret[1]<0 || ret[2]<0) {
00392 av_free_packet(pkt);
00393 return AVERROR(EIO);
00394 } else {
00395 s->img_count++;
00396 s->img_number++;
00397 return 0;
00398 }
00399 }
00400
00401 static int read_close(struct AVFormatContext* s1)
00402 {
00403 VideoDemuxData *s = s1->priv_data;
00404 #if HAVE_GLOB
00405 if (s->use_glob) {
00406 globfree(&s->globstate);
00407 }
00408 #endif
00409 return 0;
00410 }
00411
00412 #define OFFSET(x) offsetof(VideoDemuxData, x)
00413 #define DEC AV_OPT_FLAG_DECODING_PARAM
00414 static const AVOption options[] = {
00415 { "framerate", "set the video framerate", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC },
00416 { "loop", "force loop over input file sequence", OFFSET(loop), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC },
00417
00418 { "pattern_type", "set pattern type", OFFSET(pattern_type), AV_OPT_TYPE_INT, {.i64=PT_GLOB_SEQUENCE}, 0, INT_MAX, DEC, "pattern_type"},
00419 { "glob_sequence","glob/sequence pattern type", 0, AV_OPT_TYPE_CONST, {.i64=PT_GLOB_SEQUENCE}, INT_MIN, INT_MAX, DEC, "pattern_type" },
00420 { "glob", "glob pattern type", 0, AV_OPT_TYPE_CONST, {.i64=PT_GLOB}, INT_MIN, INT_MAX, DEC, "pattern_type" },
00421 { "sequence", "glob pattern type", 0, AV_OPT_TYPE_CONST, {.i64=PT_SEQUENCE}, INT_MIN, INT_MAX, DEC, "pattern_type" },
00422
00423 { "pixel_format", "set video pixel format", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
00424 { "start_number", "set first number in the sequence", OFFSET(start_number), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
00425 { "start_number_range", "set range for looking at the first sequence number", OFFSET(start_number_range), AV_OPT_TYPE_INT, {.i64 = 5}, 1, INT_MAX, DEC },
00426 { "video_size", "set video size", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
00427 { NULL },
00428 };
00429
00430 #if CONFIG_IMAGE2_DEMUXER
00431 static const AVClass img2_class = {
00432 .class_name = "image2 demuxer",
00433 .item_name = av_default_item_name,
00434 .option = options,
00435 .version = LIBAVUTIL_VERSION_INT,
00436 };
00437 AVInputFormat ff_image2_demuxer = {
00438 .name = "image2",
00439 .long_name = NULL_IF_CONFIG_SMALL("image2 sequence"),
00440 .priv_data_size = sizeof(VideoDemuxData),
00441 .read_probe = read_probe,
00442 .read_header = read_header,
00443 .read_packet = read_packet,
00444 .read_close = read_close,
00445 .flags = AVFMT_NOFILE,
00446 .priv_class = &img2_class,
00447 };
00448 #endif
00449 #if CONFIG_IMAGE2PIPE_DEMUXER
00450 static const AVClass img2pipe_class = {
00451 .class_name = "image2pipe demuxer",
00452 .item_name = av_default_item_name,
00453 .option = options,
00454 .version = LIBAVUTIL_VERSION_INT,
00455 };
00456 AVInputFormat ff_image2pipe_demuxer = {
00457 .name = "image2pipe",
00458 .long_name = NULL_IF_CONFIG_SMALL("piped image2 sequence"),
00459 .priv_data_size = sizeof(VideoDemuxData),
00460 .read_header = read_header,
00461 .read_packet = read_packet,
00462 .priv_class = &img2pipe_class,
00463 };
00464 #endif