FFmpeg
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
img2dec.c
Go to the documentation of this file.
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;
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
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 
178 {
179  if (p->filename && ff_guess_image2_codec(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 
193 {
194  VideoDemuxData *s = s1->priv_data;
195  int first_index, last_index, ret = 0;
196  int width = 0, height = 0;
197  AVStream *st;
199  AVRational framerate;
200 
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;
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) {
317  st->codec->codec_id = s1->video_codec_id;
318  } else if (s1->audio_codec_id) {
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");
326  if (st->codec->codec_id == AV_CODEC_ID_LJPEG)
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 
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),
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),
480  .priv_class = &img2pipe_class,
481 };
482 #endif