]> git.sesse.net Git - ffmpeg/blob - libavformat/img2dec.c
Merge commit 'cb45553f577f8e0ebfe05d3287e1b6fa5859b967'
[ffmpeg] / libavformat / img2dec.c
1 /*
2  * Image format
3  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4  * Copyright (c) 2004 Michael Niedermayer
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22
23 #include "libavutil/avstring.h"
24 #include "libavutil/log.h"
25 #include "libavutil/opt.h"
26 #include "libavutil/pixdesc.h"
27 #include "libavutil/parseutils.h"
28 #include "avformat.h"
29 #include "internal.h"
30 #if HAVE_GLOB
31 #include <glob.h>
32
33 /* Locally define as 0 (bitwise-OR no-op) any missing glob options that
34    are non-posix glibc/bsd extensions. */
35 #ifndef GLOB_NOMAGIC
36 #define GLOB_NOMAGIC 0
37 #endif
38 #ifndef GLOB_BRACE
39 #define GLOB_BRACE 0
40 #endif
41
42 #endif /* HAVE_GLOB */
43
44 typedef struct {
45     const AVClass *class;  /**< Class for private options. */
46     int img_first;
47     int img_last;
48     int img_number;
49     int img_count;
50     int is_pipe;
51     int split_planes;       /**< use independent file for each Y, U, V plane */
52     char path[1024];
53     char *pixel_format;     /**< Set by a private option. */
54     char *video_size;       /**< Set by a private option. */
55     char *framerate;        /**< Set by a private option. */
56     int loop;
57     enum { PT_GLOB_SEQUENCE, PT_GLOB, PT_SEQUENCE } pattern_type;
58     int use_glob;
59 #if HAVE_GLOB
60     glob_t globstate;
61 #endif
62     int start_number;
63     int start_number_range;
64     int frame_size;
65 } VideoDemuxData;
66
67 static const int sizes[][2] = {
68     { 640, 480 },
69     { 720, 480 },
70     { 720, 576 },
71     { 352, 288 },
72     { 352, 240 },
73     { 160, 128 },
74     { 512, 384 },
75     { 640, 352 },
76     { 640, 240 },
77 };
78
79 static int infer_size(int *width_ptr, int *height_ptr, int size)
80 {
81     int i;
82
83     for (i = 0; i < FF_ARRAY_ELEMS(sizes); i++) {
84         if ((sizes[i][0] * sizes[i][1]) == size) {
85             *width_ptr  = sizes[i][0];
86             *height_ptr = sizes[i][1];
87             return 0;
88         }
89     }
90
91     return -1;
92 }
93
94 static int is_glob(const char *path)
95 {
96 #if HAVE_GLOB
97     size_t span = 0;
98     const char *p = path;
99
100     while (p = strchr(p, '%')) {
101         if (*(++p) == '%') {
102             ++p;
103             continue;
104         }
105         if (span = strspn(p, "*?[]{}"))
106             break;
107     }
108     /* Did we hit a glob char or get to the end? */
109     return span != 0;
110 #else
111     return 0;
112 #endif
113 }
114
115 /**
116  * Get index range of image files matched by path.
117  *
118  * @param pfirst_index pointer to index updated with the first number in the range
119  * @param plast_index  pointer to index updated with the last number in the range
120  * @param path         path which has to be matched by the image files in the range
121  * @param start_index  minimum accepted value for the first index in the range
122  * @return -1 if no image file could be found
123  */
124 static int find_image_range(int *pfirst_index, int *plast_index,
125                             const char *path, int start_index, int start_index_range)
126 {
127     char buf[1024];
128     int range, last_index, range1, first_index;
129
130     /* find the first image */
131     for (first_index = start_index; first_index < start_index + start_index_range; first_index++) {
132         if (av_get_frame_filename(buf, sizeof(buf), path, first_index) < 0) {
133             *pfirst_index =
134             *plast_index  = 1;
135             if (avio_check(buf, AVIO_FLAG_READ) > 0)
136                 return 0;
137             return -1;
138         }
139         if (avio_check(buf, AVIO_FLAG_READ) > 0)
140             break;
141     }
142     if (first_index == start_index + start_index_range)
143         goto fail;
144
145     /* find the last image */
146     last_index = first_index;
147     for (;;) {
148         range = 0;
149         for (;;) {
150             if (!range)
151                 range1 = 1;
152             else
153                 range1 = 2 * range;
154             if (av_get_frame_filename(buf, sizeof(buf), path,
155                                       last_index + range1) < 0)
156                 goto fail;
157             if (avio_check(buf, AVIO_FLAG_READ) <= 0)
158                 break;
159             range = range1;
160             /* just in case... */
161             if (range >= (1 << 30))
162                 goto fail;
163         }
164         /* we are sure than image last_index + range exists */
165         if (!range)
166             break;
167         last_index += range;
168     }
169     *pfirst_index = first_index;
170     *plast_index  = last_index;
171     return 0;
172
173 fail:
174     return -1;
175 }
176
177 static int img_read_probe(AVProbeData *p)
178 {
179     if (p->filename && ff_guess_image2_codec(p->filename)) {
180         if (av_filename_number_test(p->filename))
181             return AVPROBE_SCORE_MAX;
182         else if (is_glob(p->filename))
183             return AVPROBE_SCORE_MAX;
184         else if (av_match_ext(p->filename, "raw") || av_match_ext(p->filename, "gif"))
185             return 5;
186         else
187             return AVPROBE_SCORE_MAX / 2;
188     }
189     return 0;
190 }
191
192 static int img_read_header(AVFormatContext *s1)
193 {
194     VideoDemuxData *s = s1->priv_data;
195     int first_index, last_index, ret = 0;
196     int width = 0, height = 0;
197     AVStream *st;
198     enum AVPixelFormat pix_fmt = AV_PIX_FMT_NONE;
199     AVRational framerate;
200
201     s1->ctx_flags |= AVFMTCTX_NOHEADER;
202
203     st = avformat_new_stream(s1, NULL);
204     if (!st) {
205         return AVERROR(ENOMEM);
206     }
207
208     if (s->pixel_format &&
209         (pix_fmt = av_get_pix_fmt(s->pixel_format)) == AV_PIX_FMT_NONE) {
210         av_log(s1, AV_LOG_ERROR, "No such pixel format: %s.\n",
211                s->pixel_format);
212         return AVERROR(EINVAL);
213     }
214     if (s->video_size &&
215         (ret = av_parse_video_size(&width, &height, s->video_size)) < 0) {
216         av_log(s, AV_LOG_ERROR,
217                "Could not parse video size: %s.\n", s->video_size);
218         return ret;
219     }
220     if ((ret = av_parse_video_rate(&framerate, s->framerate)) < 0) {
221         av_log(s, AV_LOG_ERROR,
222                "Could not parse framerate: %s.\n", s->framerate);
223         return ret;
224     }
225
226     av_strlcpy(s->path, s1->filename, sizeof(s->path));
227     s->img_number = 0;
228     s->img_count  = 0;
229
230     /* find format */
231     if (s1->iformat->flags & AVFMT_NOFILE)
232         s->is_pipe = 0;
233     else {
234         s->is_pipe       = 1;
235         st->need_parsing = AVSTREAM_PARSE_FULL;
236     }
237
238     avpriv_set_pts_info(st, 60, framerate.den, framerate.num);
239
240     if (width && height) {
241         st->codec->width  = width;
242         st->codec->height = height;
243     }
244
245     if (!s->is_pipe) {
246         if (s->pattern_type == PT_GLOB_SEQUENCE) {
247         s->use_glob = is_glob(s->path);
248         if (s->use_glob) {
249             char *p = s->path, *q, *dup;
250             int gerr;
251
252             av_log(s1, AV_LOG_WARNING, "Pattern type 'glob_sequence' is deprecated: "
253                    "use pattern_type 'glob' instead\n");
254 #if HAVE_GLOB
255             dup = q = av_strdup(p);
256             while (*q) {
257                 /* Do we have room for the next char and a \ insertion? */
258                 if ((p - s->path) >= (sizeof(s->path) - 2))
259                   break;
260                 if (*q == '%' && strspn(q + 1, "%*?[]{}"))
261                     ++q;
262                 else if (strspn(q, "\\*?[]{}"))
263                     *p++ = '\\';
264                 *p++ = *q++;
265             }
266             *p = 0;
267             av_free(dup);
268
269             gerr = glob(s->path, GLOB_NOCHECK|GLOB_BRACE|GLOB_NOMAGIC, NULL, &s->globstate);
270             if (gerr != 0) {
271                 return AVERROR(ENOENT);
272             }
273             first_index = 0;
274             last_index = s->globstate.gl_pathc - 1;
275 #endif
276         }
277         }
278         if ((s->pattern_type == PT_GLOB_SEQUENCE && !s->use_glob) || s->pattern_type == PT_SEQUENCE) {
279             if (find_image_range(&first_index, &last_index, s->path,
280                                  s->start_number, s->start_number_range) < 0) {
281                 av_log(s1, AV_LOG_ERROR,
282                        "Could find no file with with path '%s' and index in the range %d-%d\n",
283                        s->path, s->start_number, s->start_number + s->start_number_range - 1);
284                 return AVERROR(ENOENT);
285             }
286         } else if (s->pattern_type == PT_GLOB) {
287 #if HAVE_GLOB
288             int gerr;
289             gerr = glob(s->path, GLOB_NOCHECK|GLOB_BRACE|GLOB_NOMAGIC, NULL, &s->globstate);
290             if (gerr != 0) {
291                 return AVERROR(ENOENT);
292             }
293             first_index = 0;
294             last_index = s->globstate.gl_pathc - 1;
295             s->use_glob = 1;
296 #else
297             av_log(s1, AV_LOG_ERROR,
298                    "Pattern type 'glob' was selected but globbing "
299                    "is not supported by this libavformat build\n");
300             return AVERROR(ENOSYS);
301 #endif
302         } else if (s->pattern_type != PT_GLOB_SEQUENCE) {
303             av_log(s1, AV_LOG_ERROR,
304                    "Unknown value '%d' for pattern_type option\n", s->pattern_type);
305             return AVERROR(EINVAL);
306         }
307         s->img_first  = first_index;
308         s->img_last   = last_index;
309         s->img_number = first_index;
310         /* compute duration */
311         st->start_time = 0;
312         st->duration   = last_index - first_index + 1;
313     }
314
315     if (s1->video_codec_id) {
316         st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
317         st->codec->codec_id   = s1->video_codec_id;
318     } else if (s1->audio_codec_id) {
319         st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
320         st->codec->codec_id   = s1->audio_codec_id;
321     } else {
322         const char *str = strrchr(s->path, '.');
323         s->split_planes       = str && !av_strcasecmp(str + 1, "y");
324         st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
325         st->codec->codec_id   = ff_guess_image2_codec(s->path);
326         if (st->codec->codec_id == AV_CODEC_ID_LJPEG)
327             st->codec->codec_id = AV_CODEC_ID_MJPEG;
328     }
329     if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
330         pix_fmt != AV_PIX_FMT_NONE)
331         st->codec->pix_fmt = pix_fmt;
332
333     return 0;
334 }
335
336 static int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
337 {
338     VideoDemuxData *s = s1->priv_data;
339     char filename_bytes[1024];
340     char *filename = filename_bytes;
341     int i;
342     int size[3]           = { 0 }, ret[3] = { 0 };
343     AVIOContext *f[3]     = { NULL };
344     AVCodecContext *codec = s1->streams[0]->codec;
345
346     if (!s->is_pipe) {
347         /* loop over input */
348         if (s->loop && s->img_number > s->img_last) {
349             s->img_number = s->img_first;
350         }
351         if (s->img_number > s->img_last)
352             return AVERROR_EOF;
353         if (s->use_glob) {
354 #if HAVE_GLOB
355             filename = s->globstate.gl_pathv[s->img_number];
356 #endif
357         } else {
358         if (av_get_frame_filename(filename_bytes, sizeof(filename_bytes),
359                                   s->path,
360                                   s->img_number) < 0 && s->img_number > 1)
361             return AVERROR(EIO);
362         }
363         for (i = 0; i < 3; i++) {
364             if (avio_open2(&f[i], filename, AVIO_FLAG_READ,
365                            &s1->interrupt_callback, NULL) < 0) {
366                 if (i >= 1)
367                     break;
368                 av_log(s1, AV_LOG_ERROR, "Could not open file : %s\n",
369                        filename);
370                 return AVERROR(EIO);
371             }
372             size[i] = avio_size(f[i]);
373
374             if (!s->split_planes)
375                 break;
376             filename[strlen(filename) - 1] = 'U' + i;
377         }
378
379         if (codec->codec_id == AV_CODEC_ID_RAWVIDEO && !codec->width)
380             infer_size(&codec->width, &codec->height, size[0]);
381     } else {
382         f[0] = s1->pb;
383         if (url_feof(f[0]))
384             return AVERROR(EIO);
385         if (s->frame_size > 0) {
386             size[0] = s->frame_size;
387         } else {
388             size[0] = 4096;
389         }
390     }
391
392     if (av_new_packet(pkt, size[0] + size[1] + size[2]) < 0)
393         return AVERROR(ENOMEM);
394     pkt->stream_index = 0;
395     pkt->flags       |= AV_PKT_FLAG_KEY;
396
397     pkt->size = 0;
398     for (i = 0; i < 3; i++) {
399         if (f[i]) {
400             ret[i] = avio_read(f[i], pkt->data + pkt->size, size[i]);
401             if (!s->is_pipe)
402                 avio_close(f[i]);
403             if (ret[i] > 0)
404                 pkt->size += ret[i];
405         }
406     }
407
408     if (ret[0] <= 0 || ret[1] < 0 || ret[2] < 0) {
409         av_free_packet(pkt);
410         return AVERROR(EIO); /* signal EOF */
411     } else {
412         s->img_count++;
413         s->img_number++;
414         return 0;
415     }
416 }
417
418 static int img_read_close(struct AVFormatContext* s1)
419 {
420     VideoDemuxData *s = s1->priv_data;
421 #if HAVE_GLOB
422     if (s->use_glob) {
423         globfree(&s->globstate);
424     }
425 #endif
426     return 0;
427 }
428
429 #define OFFSET(x) offsetof(VideoDemuxData, x)
430 #define DEC AV_OPT_FLAG_DECODING_PARAM
431 static const AVOption options[] = {
432     { "framerate",    "set the video framerate",             OFFSET(framerate),    AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0,       DEC },
433     { "loop",         "force loop over input file sequence", OFFSET(loop),         AV_OPT_TYPE_INT,    {.i64 = 0   }, 0, 1,       DEC },
434
435     { "pattern_type", "set pattern type",                    OFFSET(pattern_type), AV_OPT_TYPE_INT,    {.i64=PT_GLOB_SEQUENCE}, 0,       INT_MAX, DEC, "pattern_type"},
436     { "glob_sequence","glob/sequence pattern type",          0,                    AV_OPT_TYPE_CONST,  {.i64=PT_GLOB_SEQUENCE}, INT_MIN, INT_MAX, DEC, "pattern_type" },
437     { "glob",         "glob pattern type",                   0,                    AV_OPT_TYPE_CONST,  {.i64=PT_GLOB         }, INT_MIN, INT_MAX, DEC, "pattern_type" },
438     { "sequence",     "glob pattern type",                   0,                    AV_OPT_TYPE_CONST,  {.i64=PT_SEQUENCE     }, INT_MIN, INT_MAX, DEC, "pattern_type" },
439
440     { "pixel_format", "set video pixel format",              OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0,       DEC },
441     { "start_number", "set first number in the sequence",    OFFSET(start_number), AV_OPT_TYPE_INT,    {.i64 = 0   }, 0, INT_MAX, DEC },
442     { "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 },
443     { "video_size",   "set video size",                      OFFSET(video_size),   AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0,       DEC },
444     { "frame_size",   "force frame size in bytes",           OFFSET(frame_size),   AV_OPT_TYPE_INT,    {.i64 = 0   }, 0, INT_MAX, DEC },
445     { NULL },
446 };
447
448 #if CONFIG_IMAGE2_DEMUXER
449 static const AVClass img2_class = {
450     .class_name = "image2 demuxer",
451     .item_name  = av_default_item_name,
452     .option     = options,
453     .version    = LIBAVUTIL_VERSION_INT,
454 };
455 AVInputFormat ff_image2_demuxer = {
456     .name           = "image2",
457     .long_name      = NULL_IF_CONFIG_SMALL("image2 sequence"),
458     .priv_data_size = sizeof(VideoDemuxData),
459     .read_probe     = img_read_probe,
460     .read_header    = img_read_header,
461     .read_packet    = img_read_packet,
462     .read_close     = img_read_close,
463     .flags          = AVFMT_NOFILE,
464     .priv_class     = &img2_class,
465 };
466 #endif
467 #if CONFIG_IMAGE2PIPE_DEMUXER
468 static const AVClass img2pipe_class = {
469     .class_name = "image2pipe demuxer",
470     .item_name  = av_default_item_name,
471     .option     = options,
472     .version    = LIBAVUTIL_VERSION_INT,
473 };
474 AVInputFormat ff_image2pipe_demuxer = {
475     .name           = "image2pipe",
476     .long_name      = NULL_IF_CONFIG_SMALL("piped image2 sequence"),
477     .priv_data_size = sizeof(VideoDemuxData),
478     .read_header    = img_read_header,
479     .read_packet    = img_read_packet,
480     .priv_class     = &img2pipe_class,
481 };
482 #endif