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
);
293 return AVERROR(ENOMEM
);
294 pad
.config_props
= movie_config_output_props
;
295 pad
.request_frame
= movie_request_frame
;
296 ff_insert_outpad(ctx
, i
, &pad
);
297 ret
= open_stream(ctx
, &movie
->st
[i
]);
300 if ( movie
->st
[i
].st
->codec
->codec
->type
== AVMEDIA_TYPE_AUDIO
&&
301 !movie
->st
[i
].st
->codec
->channel_layout
) {
302 ret
= guess_channel_layout(&movie
->st
[i
], i
, ctx
);
308 av_log(ctx
, AV_LOG_VERBOSE
, "seek_point:%"PRIi64
" format_name:%s file_name:%s stream_index:%d\n",
309 movie
->seek_point
, movie
->format_name
, movie
->file_name
,
310 movie
->stream_index
);
315 static av_cold
void movie_uninit(AVFilterContext
*ctx
)
317 MovieContext
*movie
= ctx
->priv
;
320 for (i
= 0; i
< ctx
->nb_outputs
; i
++) {
321 av_freep(&ctx
->output_pads
[i
].name
);
323 avcodec_close(movie
->st
[i
].st
->codec
);
325 av_freep(&movie
->st
);
326 av_freep(&movie
->out_index
);
327 if (movie
->format_ctx
)
328 avformat_close_input(&movie
->format_ctx
);
331 static int movie_query_formats(AVFilterContext
*ctx
)
333 MovieContext
*movie
= ctx
->priv
;
334 int list
[] = { 0, -1 };
335 int64_t list64
[] = { 0, -1 };
338 for (i
= 0; i
< ctx
->nb_outputs
; i
++) {
339 MovieStream
*st
= &movie
->st
[i
];
340 AVCodecContext
*c
= st
->st
->codec
;
341 AVFilterLink
*outlink
= ctx
->outputs
[i
];
343 switch (c
->codec_type
) {
344 case AVMEDIA_TYPE_VIDEO
:
345 list
[0] = c
->pix_fmt
;
346 ff_formats_ref(ff_make_format_list(list
), &outlink
->in_formats
);
348 case AVMEDIA_TYPE_AUDIO
:
349 list
[0] = c
->sample_fmt
;
350 ff_formats_ref(ff_make_format_list(list
), &outlink
->in_formats
);
351 list
[0] = c
->sample_rate
;
352 ff_formats_ref(ff_make_format_list(list
), &outlink
->in_samplerates
);
353 list64
[0] = c
->channel_layout
;
354 ff_channel_layouts_ref(avfilter_make_format64_list(list64
),
355 &outlink
->in_channel_layouts
);
363 static int movie_config_output_props(AVFilterLink
*outlink
)
365 AVFilterContext
*ctx
= outlink
->src
;
366 MovieContext
*movie
= ctx
->priv
;
367 unsigned out_id
= FF_OUTLINK_IDX(outlink
);
368 MovieStream
*st
= &movie
->st
[out_id
];
369 AVCodecContext
*c
= st
->st
->codec
;
371 outlink
->time_base
= st
->st
->time_base
;
373 switch (c
->codec_type
) {
374 case AVMEDIA_TYPE_VIDEO
:
375 outlink
->w
= c
->width
;
376 outlink
->h
= c
->height
;
377 outlink
->frame_rate
= st
->st
->r_frame_rate
;
379 case AVMEDIA_TYPE_AUDIO
:
386 static char *describe_frame_to_str(char *dst
, size_t dst_size
,
387 AVFrame
*frame
, enum AVMediaType frame_type
,
390 switch (frame_type
) {
391 case AVMEDIA_TYPE_VIDEO
:
392 snprintf(dst
, dst_size
,
393 "video pts:%s time:%s size:%dx%d aspect:%d/%d",
394 av_ts2str(frame
->pts
), av_ts2timestr(frame
->pts
, &link
->time_base
),
395 frame
->width
, frame
->height
,
396 frame
->sample_aspect_ratio
.num
,
397 frame
->sample_aspect_ratio
.den
);
399 case AVMEDIA_TYPE_AUDIO
:
400 snprintf(dst
, dst_size
,
401 "audio pts:%s time:%s samples:%d",
402 av_ts2str(frame
->pts
), av_ts2timestr(frame
->pts
, &link
->time_base
),
406 snprintf(dst
, dst_size
, "%s BUG", av_get_media_type_string(frame_type
));
412 static int rewind_file(AVFilterContext
*ctx
)
414 MovieContext
*movie
= ctx
->priv
;
415 int64_t timestamp
= movie
->seek_point
;
418 if (movie
->format_ctx
->start_time
!= AV_NOPTS_VALUE
)
419 timestamp
+= movie
->format_ctx
->start_time
;
420 ret
= av_seek_frame(movie
->format_ctx
, -1, timestamp
, AVSEEK_FLAG_BACKWARD
);
422 av_log(ctx
, AV_LOG_ERROR
, "Unable to loop: %s\n", av_err2str(ret
));
423 movie
->loop_count
= 1; /* do not try again */
427 for (i
= 0; i
< ctx
->nb_outputs
; i
++) {
428 avcodec_flush_buffers(movie
->st
[i
].st
->codec
);
429 movie
->st
[i
].done
= 0;
436 * Try to push a frame to the requested output.
438 * @param ctx filter context
439 * @param out_id number of output where a frame is wanted;
440 * if the frame is read from file, used to set the return value;
441 * if the codec is being flushed, flush the corresponding stream
442 * @return 1 if a frame was pushed on the requested output,
443 * 0 if another attempt is possible,
446 static int movie_push_frame(AVFilterContext
*ctx
, unsigned out_id
)
448 MovieContext
*movie
= ctx
->priv
;
449 AVPacket
*pkt
= &movie
->pkt
;
450 enum AVMediaType frame_type
;
452 int ret
, got_frame
= 0, pkt_out_id
;
453 AVFilterLink
*outlink
;
458 if (movie
->st
[out_id
].done
) {
459 if (movie
->loop_count
!= 1) {
460 ret
= rewind_file(ctx
);
463 movie
->loop_count
-= movie
->loop_count
> 1;
464 av_log(ctx
, AV_LOG_VERBOSE
, "Stream finished, looping.\n");
465 return 0; /* retry */
469 pkt
->stream_index
= movie
->st
[out_id
].st
->index
;
470 /* packet is already ready for flushing */
472 ret
= av_read_frame(movie
->format_ctx
, &movie
->pkt0
);
474 av_init_packet(&movie
->pkt0
); /* ready for flushing */
476 if (ret
== AVERROR_EOF
) {
478 return 0; /* start flushing */
486 pkt_out_id
= pkt
->stream_index
> movie
->max_stream_index
? -1 :
487 movie
->out_index
[pkt
->stream_index
];
488 if (pkt_out_id
< 0) {
489 av_free_packet(&movie
->pkt0
);
490 pkt
->size
= 0; /* ready for next run */
494 st
= &movie
->st
[pkt_out_id
];
495 outlink
= ctx
->outputs
[pkt_out_id
];
497 frame
= av_frame_alloc();
499 return AVERROR(ENOMEM
);
501 frame_type
= st
->st
->codec
->codec_type
;
502 switch (frame_type
) {
503 case AVMEDIA_TYPE_VIDEO
:
504 ret
= avcodec_decode_video2(st
->st
->codec
, frame
, &got_frame
, pkt
);
506 case AVMEDIA_TYPE_AUDIO
:
507 ret
= avcodec_decode_audio4(st
->st
->codec
, frame
, &got_frame
, pkt
);
510 ret
= AVERROR(ENOSYS
);
514 av_log(ctx
, AV_LOG_WARNING
, "Decode error: %s\n", av_err2str(ret
));
515 av_frame_free(&frame
);
516 av_free_packet(&movie
->pkt0
);
518 movie
->pkt
.data
= NULL
;
521 if (!ret
|| st
->st
->codec
->codec_type
== AVMEDIA_TYPE_VIDEO
)
526 if (pkt
->size
<= 0) {
527 av_free_packet(&movie
->pkt0
);
528 pkt
->size
= 0; /* ready for next run */
534 av_frame_free(&frame
);
538 frame
->pts
= av_frame_get_best_effort_timestamp(frame
);
539 av_dlog(ctx
, "movie_push_frame(): file:'%s' %s\n", movie
->file_name
,
540 describe_frame_to_str((char[1024]){0}, 1024, frame
, frame_type
, outlink
));
542 if (st
->st
->codec
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
543 if (frame
->format
!= outlink
->format
) {
544 av_log(ctx
, AV_LOG_ERROR
, "Format changed %s -> %s, discarding frame\n",
545 av_get_pix_fmt_name(outlink
->format
),
546 av_get_pix_fmt_name(frame
->format
)
548 av_frame_free(&frame
);
552 ret
= ff_filter_frame(outlink
, frame
);
556 return pkt_out_id
== out_id
;
559 static int movie_request_frame(AVFilterLink
*outlink
)
561 AVFilterContext
*ctx
= outlink
->src
;
562 unsigned out_id
= FF_OUTLINK_IDX(outlink
);
566 ret
= movie_push_frame(ctx
, out_id
);
568 return FFMIN(ret
, 0);
572 #if CONFIG_MOVIE_FILTER
574 AVFILTER_DEFINE_CLASS(movie
);
576 AVFilter ff_avsrc_movie
= {
578 .description
= NULL_IF_CONFIG_SMALL("Read from a movie source."),
579 .priv_size
= sizeof(MovieContext
),
580 .priv_class
= &movie_class
,
581 .init
= movie_common_init
,
582 .uninit
= movie_uninit
,
583 .query_formats
= movie_query_formats
,
587 .flags
= AVFILTER_FLAG_DYNAMIC_OUTPUTS
,
590 #endif /* CONFIG_MOVIE_FILTER */
592 #if CONFIG_AMOVIE_FILTER
594 #define amovie_options movie_options
595 AVFILTER_DEFINE_CLASS(amovie
);
597 AVFilter ff_avsrc_amovie
= {
599 .description
= NULL_IF_CONFIG_SMALL("Read audio from a movie source."),
600 .priv_size
= sizeof(MovieContext
),
601 .init
= movie_common_init
,
602 .uninit
= movie_uninit
,
603 .query_formats
= movie_query_formats
,
607 .priv_class
= &amovie_class
,
608 .flags
= AVFILTER_FLAG_DYNAMIC_OUTPUTS
,
611 #endif /* CONFIG_AMOVIE_FILTER */