2 * Copyright (c) 2010 Stefano Sabatini
3 * Copyright (c) 2008 Victor Paesa
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 * @todo use direct rendering (no allocation of a new frame)
27 * @todo support a PTS correction mechanism
33 #include "libavutil/attributes.h"
34 #include "libavutil/avstring.h"
35 #include "libavutil/avassert.h"
36 #include "libavutil/opt.h"
37 #include "libavutil/imgutils.h"
38 #include "libavutil/timestamp.h"
39 #include "libavformat/avformat.h"
47 typedef struct MovieStream
{
52 typedef struct MovieContext
{
53 /* common A/V fields */
55 int64_t seek_point
; ///< seekpoint in microseconds
59 char *stream_specs
; /**< user-provided list of streams, separated by + */
60 int stream_index
; /**< for compatibility */
63 AVFormatContext
*format_ctx
;
67 int max_stream_index
; /**< max stream # actually used for output */
68 MovieStream
*st
; /**< array of all streams, one per output */
69 int *out_index
; /**< stream number -> output number map, or -1 */
72 #define OFFSET(x) offsetof(MovieContext, x)
73 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_VIDEO_PARAM
75 static const AVOption movie_options
[]= {
76 { "filename", NULL
, OFFSET(file_name
), AV_OPT_TYPE_STRING
, .flags
= FLAGS
},
77 { "format_name", "set format name", OFFSET(format_name
), AV_OPT_TYPE_STRING
, .flags
= FLAGS
},
78 { "f", "set format name", OFFSET(format_name
), AV_OPT_TYPE_STRING
, .flags
= FLAGS
},
79 { "stream_index", "set stream index", OFFSET(stream_index
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, INT_MAX
, FLAGS
},
80 { "si", "set stream index", OFFSET(stream_index
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, INT_MAX
, FLAGS
},
81 { "seek_point", "set seekpoint (seconds)", OFFSET(seek_point_d
), AV_OPT_TYPE_DOUBLE
, { .dbl
= 0 }, 0, (INT64_MAX
-1) / 1000000, FLAGS
},
82 { "sp", "set seekpoint (seconds)", OFFSET(seek_point_d
), AV_OPT_TYPE_DOUBLE
, { .dbl
= 0 }, 0, (INT64_MAX
-1) / 1000000, FLAGS
},
83 { "streams", "set streams", OFFSET(stream_specs
), AV_OPT_TYPE_STRING
, {.str
= 0}, CHAR_MAX
, CHAR_MAX
, FLAGS
},
84 { "s", "set streams", OFFSET(stream_specs
), AV_OPT_TYPE_STRING
, {.str
= 0}, CHAR_MAX
, CHAR_MAX
, FLAGS
},
85 { "loop", "set loop count", OFFSET(loop_count
), AV_OPT_TYPE_INT
, {.i64
= 1}, 0, INT_MAX
, FLAGS
},
89 static int movie_config_output_props(AVFilterLink
*outlink
);
90 static int movie_request_frame(AVFilterLink
*outlink
);
92 static AVStream
*find_stream(void *log
, AVFormatContext
*avf
, const char *spec
)
94 int i
, ret
, already
= 0, stream_id
= -1;
95 char type_char
[2], dummy
;
96 AVStream
*found
= NULL
;
97 enum AVMediaType type
;
99 ret
= sscanf(spec
, "d%1[av]%d%c", type_char
, &stream_id
, &dummy
);
100 if (ret
>= 1 && ret
<= 2) {
101 type
= type_char
[0] == 'v' ? AVMEDIA_TYPE_VIDEO
: AVMEDIA_TYPE_AUDIO
;
102 ret
= av_find_best_stream(avf
, type
, stream_id
, -1, NULL
, 0);
104 av_log(log
, AV_LOG_ERROR
, "No %s stream with index '%d' found\n",
105 av_get_media_type_string(type
), stream_id
);
108 return avf
->streams
[ret
];
110 for (i
= 0; i
< avf
->nb_streams
; i
++) {
111 ret
= avformat_match_stream_specifier(avf
, avf
->streams
[i
], spec
);
113 av_log(log
, AV_LOG_ERROR
,
114 "Invalid stream specifier \"%s\"\n", spec
);
119 if (avf
->streams
[i
]->discard
!= AVDISCARD_ALL
) {
124 av_log(log
, AV_LOG_WARNING
,
125 "Ambiguous stream specifier \"%s\", using #%d\n", spec
, i
);
128 found
= avf
->streams
[i
];
131 av_log(log
, AV_LOG_WARNING
, "Stream specifier \"%s\" %s\n", spec
,
132 already
? "matched only already used streams" :
133 "did not match any stream");
136 if (found
->codec
->codec_type
!= AVMEDIA_TYPE_VIDEO
&&
137 found
->codec
->codec_type
!= AVMEDIA_TYPE_AUDIO
) {
138 av_log(log
, AV_LOG_ERROR
, "Stream specifier \"%s\" matched a %s stream,"
139 "currently unsupported by libavfilter\n", spec
,
140 av_get_media_type_string(found
->codec
->codec_type
));
146 static int open_stream(void *log
, MovieStream
*st
)
151 codec
= avcodec_find_decoder(st
->st
->codec
->codec_id
);
153 av_log(log
, AV_LOG_ERROR
, "Failed to find any codec\n");
154 return AVERROR(EINVAL
);
157 st
->st
->codec
->refcounted_frames
= 1;
159 if ((ret
= avcodec_open2(st
->st
->codec
, codec
, NULL
)) < 0) {
160 av_log(log
, AV_LOG_ERROR
, "Failed to open codec\n");
167 static int guess_channel_layout(MovieStream
*st
, int st_index
, void *log_ctx
)
169 AVCodecContext
*dec_ctx
= st
->st
->codec
;
171 int64_t chl
= av_get_default_channel_layout(dec_ctx
->channels
);
174 av_log(log_ctx
, AV_LOG_ERROR
,
175 "Channel layout is not set in stream %d, and could not "
176 "be guessed from the number of channels (%d)\n",
177 st_index
, dec_ctx
->channels
);
178 return AVERROR(EINVAL
);
181 av_get_channel_layout_string(buf
, sizeof(buf
), dec_ctx
->channels
, chl
);
182 av_log(log_ctx
, AV_LOG_WARNING
,
183 "Channel layout is not set in output stream %d, "
184 "guessed channel layout is '%s'\n",
186 dec_ctx
->channel_layout
= chl
;
190 static av_cold
int movie_common_init(AVFilterContext
*ctx
)
192 MovieContext
*movie
= ctx
->priv
;
193 AVInputFormat
*iformat
= NULL
;
195 int nb_streams
= 1, ret
, i
;
196 char default_streams
[16], *stream_specs
, *spec
, *cursor
;
200 if (!movie
->file_name
) {
201 av_log(ctx
, AV_LOG_ERROR
, "No filename provided!\n");
202 return AVERROR(EINVAL
);
205 movie
->seek_point
= movie
->seek_point_d
* 1000000 + 0.5;
207 stream_specs
= movie
->stream_specs
;
209 snprintf(default_streams
, sizeof(default_streams
), "d%c%d",
210 !strcmp(ctx
->filter
->name
, "amovie") ? 'a' : 'v',
211 movie
->stream_index
);
212 stream_specs
= default_streams
;
214 for (cursor
= stream_specs
; *cursor
; cursor
++)
218 if (movie
->loop_count
!= 1 && nb_streams
!= 1) {
219 av_log(ctx
, AV_LOG_ERROR
,
220 "Loop with several streams is currently unsupported\n");
221 return AVERROR_PATCHWELCOME
;
226 // Try to find the movie format (container)
227 iformat
= movie
->format_name
? av_find_input_format(movie
->format_name
) : NULL
;
229 movie
->format_ctx
= NULL
;
230 if ((ret
= avformat_open_input(&movie
->format_ctx
, movie
->file_name
, iformat
, NULL
)) < 0) {
231 av_log(ctx
, AV_LOG_ERROR
,
232 "Failed to avformat_open_input '%s'\n", movie
->file_name
);
235 if ((ret
= avformat_find_stream_info(movie
->format_ctx
, NULL
)) < 0)
236 av_log(ctx
, AV_LOG_WARNING
, "Failed to find stream info\n");
238 // if seeking requested, we execute it
239 if (movie
->seek_point
> 0) {
240 timestamp
= movie
->seek_point
;
241 // add the stream start time, should it exist
242 if (movie
->format_ctx
->start_time
!= AV_NOPTS_VALUE
) {
243 if (timestamp
> INT64_MAX
- movie
->format_ctx
->start_time
) {
244 av_log(ctx
, AV_LOG_ERROR
,
245 "%s: seek value overflow with start_time:%"PRId64
" seek_point:%"PRId64
"\n",
246 movie
->file_name
, movie
->format_ctx
->start_time
, movie
->seek_point
);
247 return AVERROR(EINVAL
);
249 timestamp
+= movie
->format_ctx
->start_time
;
251 if ((ret
= av_seek_frame(movie
->format_ctx
, -1, timestamp
, AVSEEK_FLAG_BACKWARD
)) < 0) {
252 av_log(ctx
, AV_LOG_ERROR
, "%s: could not seek to position %"PRId64
"\n",
253 movie
->file_name
, timestamp
);
258 for (i
= 0; i
< movie
->format_ctx
->nb_streams
; i
++)
259 movie
->format_ctx
->streams
[i
]->discard
= AVDISCARD_ALL
;
261 movie
->st
= av_calloc(nb_streams
, sizeof(*movie
->st
));
263 return AVERROR(ENOMEM
);
265 for (i
= 0; i
< nb_streams
; i
++) {
266 spec
= av_strtok(stream_specs
, "+", &cursor
);
269 stream_specs
= NULL
; /* for next strtok */
270 st
= find_stream(ctx
, movie
->format_ctx
, spec
);
272 return AVERROR(EINVAL
);
273 st
->discard
= AVDISCARD_DEFAULT
;
274 movie
->st
[i
].st
= st
;
275 movie
->max_stream_index
= FFMAX(movie
->max_stream_index
, st
->index
);
277 if (av_strtok(NULL
, "+", &cursor
))
280 movie
->out_index
= av_calloc(movie
->max_stream_index
+ 1,
281 sizeof(*movie
->out_index
));
282 if (!movie
->out_index
)
283 return AVERROR(ENOMEM
);
284 for (i
= 0; i
<= movie
->max_stream_index
; i
++)
285 movie
->out_index
[i
] = -1;
286 for (i
= 0; i
< nb_streams
; i
++) {
287 AVFilterPad pad
= { 0 };
288 movie
->out_index
[movie
->st
[i
].st
->index
] = i
;
289 snprintf(name
, sizeof(name
), "out%d", i
);
290 pad
.type
= movie
->st
[i
].st
->codec
->codec_type
;
291 pad
.name
= av_strdup(name
);
292 pad
.config_props
= movie_config_output_props
;
293 pad
.request_frame
= movie_request_frame
;
294 ff_insert_outpad(ctx
, i
, &pad
);
295 ret
= open_stream(ctx
, &movie
->st
[i
]);
298 if ( movie
->st
[i
].st
->codec
->codec
->type
== AVMEDIA_TYPE_AUDIO
&&
299 !movie
->st
[i
].st
->codec
->channel_layout
) {
300 ret
= guess_channel_layout(&movie
->st
[i
], i
, ctx
);
306 av_log(ctx
, AV_LOG_VERBOSE
, "seek_point:%"PRIi64
" format_name:%s file_name:%s stream_index:%d\n",
307 movie
->seek_point
, movie
->format_name
, movie
->file_name
,
308 movie
->stream_index
);
313 static av_cold
void movie_uninit(AVFilterContext
*ctx
)
315 MovieContext
*movie
= ctx
->priv
;
318 for (i
= 0; i
< ctx
->nb_outputs
; i
++) {
319 av_freep(&ctx
->output_pads
[i
].name
);
321 avcodec_close(movie
->st
[i
].st
->codec
);
323 av_freep(&movie
->st
);
324 av_freep(&movie
->out_index
);
325 if (movie
->format_ctx
)
326 avformat_close_input(&movie
->format_ctx
);
329 static int movie_query_formats(AVFilterContext
*ctx
)
331 MovieContext
*movie
= ctx
->priv
;
332 int list
[] = { 0, -1 };
333 int64_t list64
[] = { 0, -1 };
336 for (i
= 0; i
< ctx
->nb_outputs
; i
++) {
337 MovieStream
*st
= &movie
->st
[i
];
338 AVCodecContext
*c
= st
->st
->codec
;
339 AVFilterLink
*outlink
= ctx
->outputs
[i
];
341 switch (c
->codec_type
) {
342 case AVMEDIA_TYPE_VIDEO
:
343 list
[0] = c
->pix_fmt
;
344 ff_formats_ref(ff_make_format_list(list
), &outlink
->in_formats
);
346 case AVMEDIA_TYPE_AUDIO
:
347 list
[0] = c
->sample_fmt
;
348 ff_formats_ref(ff_make_format_list(list
), &outlink
->in_formats
);
349 list
[0] = c
->sample_rate
;
350 ff_formats_ref(ff_make_format_list(list
), &outlink
->in_samplerates
);
351 list64
[0] = c
->channel_layout
;
352 ff_channel_layouts_ref(avfilter_make_format64_list(list64
),
353 &outlink
->in_channel_layouts
);
361 static int movie_config_output_props(AVFilterLink
*outlink
)
363 AVFilterContext
*ctx
= outlink
->src
;
364 MovieContext
*movie
= ctx
->priv
;
365 unsigned out_id
= FF_OUTLINK_IDX(outlink
);
366 MovieStream
*st
= &movie
->st
[out_id
];
367 AVCodecContext
*c
= st
->st
->codec
;
369 outlink
->time_base
= st
->st
->time_base
;
371 switch (c
->codec_type
) {
372 case AVMEDIA_TYPE_VIDEO
:
373 outlink
->w
= c
->width
;
374 outlink
->h
= c
->height
;
375 outlink
->frame_rate
= st
->st
->r_frame_rate
;
377 case AVMEDIA_TYPE_AUDIO
:
384 static char *describe_frame_to_str(char *dst
, size_t dst_size
,
385 AVFrame
*frame
, enum AVMediaType frame_type
,
388 switch (frame_type
) {
389 case AVMEDIA_TYPE_VIDEO
:
390 snprintf(dst
, dst_size
,
391 "video pts:%s time:%s size:%dx%d aspect:%d/%d",
392 av_ts2str(frame
->pts
), av_ts2timestr(frame
->pts
, &link
->time_base
),
393 frame
->width
, frame
->height
,
394 frame
->sample_aspect_ratio
.num
,
395 frame
->sample_aspect_ratio
.den
);
397 case AVMEDIA_TYPE_AUDIO
:
398 snprintf(dst
, dst_size
,
399 "audio pts:%s time:%s samples:%d",
400 av_ts2str(frame
->pts
), av_ts2timestr(frame
->pts
, &link
->time_base
),
404 snprintf(dst
, dst_size
, "%s BUG", av_get_media_type_string(frame_type
));
410 static int rewind_file(AVFilterContext
*ctx
)
412 MovieContext
*movie
= ctx
->priv
;
413 int64_t timestamp
= movie
->seek_point
;
416 if (movie
->format_ctx
->start_time
!= AV_NOPTS_VALUE
)
417 timestamp
+= movie
->format_ctx
->start_time
;
418 ret
= av_seek_frame(movie
->format_ctx
, -1, timestamp
, AVSEEK_FLAG_BACKWARD
);
420 av_log(ctx
, AV_LOG_ERROR
, "Unable to loop: %s\n", av_err2str(ret
));
421 movie
->loop_count
= 1; /* do not try again */
425 for (i
= 0; i
< ctx
->nb_outputs
; i
++) {
426 avcodec_flush_buffers(movie
->st
[i
].st
->codec
);
427 movie
->st
[i
].done
= 0;
434 * Try to push a frame to the requested output.
436 * @param ctx filter context
437 * @param out_id number of output where a frame is wanted;
438 * if the frame is read from file, used to set the return value;
439 * if the codec is being flushed, flush the corresponding stream
440 * @return 1 if a frame was pushed on the requested output,
441 * 0 if another attempt is possible,
444 static int movie_push_frame(AVFilterContext
*ctx
, unsigned out_id
)
446 MovieContext
*movie
= ctx
->priv
;
447 AVPacket
*pkt
= &movie
->pkt
;
448 enum AVMediaType frame_type
;
450 int ret
, got_frame
= 0, pkt_out_id
;
451 AVFilterLink
*outlink
;
456 if (movie
->st
[out_id
].done
) {
457 if (movie
->loop_count
!= 1) {
458 ret
= rewind_file(ctx
);
461 movie
->loop_count
-= movie
->loop_count
> 1;
462 av_log(ctx
, AV_LOG_VERBOSE
, "Stream finished, looping.\n");
463 return 0; /* retry */
467 pkt
->stream_index
= movie
->st
[out_id
].st
->index
;
468 /* packet is already ready for flushing */
470 ret
= av_read_frame(movie
->format_ctx
, &movie
->pkt0
);
472 av_init_packet(&movie
->pkt0
); /* ready for flushing */
474 if (ret
== AVERROR_EOF
) {
476 return 0; /* start flushing */
484 pkt_out_id
= pkt
->stream_index
> movie
->max_stream_index
? -1 :
485 movie
->out_index
[pkt
->stream_index
];
486 if (pkt_out_id
< 0) {
487 av_free_packet(&movie
->pkt0
);
488 pkt
->size
= 0; /* ready for next run */
492 st
= &movie
->st
[pkt_out_id
];
493 outlink
= ctx
->outputs
[pkt_out_id
];
495 frame
= av_frame_alloc();
497 return AVERROR(ENOMEM
);
499 frame_type
= st
->st
->codec
->codec_type
;
500 switch (frame_type
) {
501 case AVMEDIA_TYPE_VIDEO
:
502 ret
= avcodec_decode_video2(st
->st
->codec
, frame
, &got_frame
, pkt
);
504 case AVMEDIA_TYPE_AUDIO
:
505 ret
= avcodec_decode_audio4(st
->st
->codec
, frame
, &got_frame
, pkt
);
508 ret
= AVERROR(ENOSYS
);
512 av_log(ctx
, AV_LOG_WARNING
, "Decode error: %s\n", av_err2str(ret
));
513 av_frame_free(&frame
);
514 av_free_packet(&movie
->pkt0
);
516 movie
->pkt
.data
= NULL
;
519 if (!ret
|| st
->st
->codec
->codec_type
== AVMEDIA_TYPE_VIDEO
)
524 if (pkt
->size
<= 0) {
525 av_free_packet(&movie
->pkt0
);
526 pkt
->size
= 0; /* ready for next run */
532 av_frame_free(&frame
);
536 frame
->pts
= av_frame_get_best_effort_timestamp(frame
);
537 av_dlog(ctx
, "movie_push_frame(): file:'%s' %s\n", movie
->file_name
,
538 describe_frame_to_str((char[1024]){0}, 1024, frame
, frame_type
, outlink
));
540 if (st
->st
->codec
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
541 if (frame
->format
!= outlink
->format
) {
542 av_log(ctx
, AV_LOG_ERROR
, "Format changed %s -> %s, discarding frame\n",
543 av_get_pix_fmt_name(outlink
->format
),
544 av_get_pix_fmt_name(frame
->format
)
546 av_frame_free(&frame
);
550 ret
= ff_filter_frame(outlink
, frame
);
554 return pkt_out_id
== out_id
;
557 static int movie_request_frame(AVFilterLink
*outlink
)
559 AVFilterContext
*ctx
= outlink
->src
;
560 unsigned out_id
= FF_OUTLINK_IDX(outlink
);
564 ret
= movie_push_frame(ctx
, out_id
);
566 return FFMIN(ret
, 0);
570 #if CONFIG_MOVIE_FILTER
572 AVFILTER_DEFINE_CLASS(movie
);
574 AVFilter ff_avsrc_movie
= {
576 .description
= NULL_IF_CONFIG_SMALL("Read from a movie source."),
577 .priv_size
= sizeof(MovieContext
),
578 .priv_class
= &movie_class
,
579 .init
= movie_common_init
,
580 .uninit
= movie_uninit
,
581 .query_formats
= movie_query_formats
,
585 .flags
= AVFILTER_FLAG_DYNAMIC_OUTPUTS
,
588 #endif /* CONFIG_MOVIE_FILTER */
590 #if CONFIG_AMOVIE_FILTER
592 #define amovie_options movie_options
593 AVFILTER_DEFINE_CLASS(amovie
);
595 AVFilter ff_avsrc_amovie
= {
597 .description
= NULL_IF_CONFIG_SMALL("Read audio from a movie source."),
598 .priv_size
= sizeof(MovieContext
),
599 .init
= movie_common_init
,
600 .uninit
= movie_uninit
,
601 .query_formats
= movie_query_formats
,
605 .priv_class
= &amovie_class
,
606 .flags
= AVFILTER_FLAG_DYNAMIC_OUTPUTS
,
609 #endif /* CONFIG_AMOVIE_FILTER */