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