[FFmpeg-devel] [PATCH 2/2] ffmpeg: Made execution of reap_filters() more deterministic with respect to when headers are written
Aaron Levinson
alevinsn at aracnet.com
Fri May 12 23:28:14 EEST 2017
Purpose: Made execution of reap_filters() more deterministic with
respect to when headers are written in relationship with the
initialization of output streams and the processing of input audio
and/or video frames. This change fixes a bug in ffmpeg encountered
when decoding interlaced video. In some cases, ffmpeg would treat it
as progressive.
Detailed description of problem: Run the following command: "ffmpeg -i
test8_1080i.h264 -c:v mpeg2video test8_1080i_mp2.ts". In this case,
test8_1080i.h264 is an H.264-encoded file with 1080i59.94
(interlaced). Prior to the patch, the following output is generated:
Input #0, h264, from 'test8_1080i.h264':
Duration: N/A, bitrate: N/A
Stream #0:0: Video: h264 (High), yuv420p(top first), 1920x1080 [SAR 1:1 DAR 16:9], 29.97 fps, 29.97 tbr, 1200k tbn, 59.94 tbc
Stream mapping:
Stream #0:0 -> #0:0 (h264 (native) -> mpeg2video (native))
Press [q] to stop, [?] for help
Output #0, mpegts, to 'test8_1080i_mp2_2.ts':
Metadata:
encoder : Lavf57.72.100
Stream #0:0: Video: mpeg2video (Main), yuv420p, 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 200 kb/s, 29.97 fps, 90k tbn, 29.97 tbc
Metadata:
encoder : Lavc57.92.100 mpeg2video
which demonstrates the bug. The output stream should instead look like:
Stream #0:0: Video: mpeg2video (Main), yuv420p(top coded first (swapped)), 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 200 kb/s, 29.97 fps, 90k tbn, 29.97 tbc
The bug is caused by the fact that reap_filters() calls
init_output_stream(), which is then immediately followed by a call to
check_init_output_file(), and this is all done prior to the first call
to do_video_out(). An initial call to do_video_out() is necessary to
populate the interlaced video information to the output stream's
codecpar (mux_par->field_order in do_video_out()). However,
check_init_output_file() calls avformat_write_header() prior to the
initial call to do_video_out(), so field_order is populated too late,
and the header is written with the default field_order value,
progressive.
Signed-off-by: Aaron Levinson <alevinsn at aracnet.com>
---
ffmpeg.c | 43 ++++++++++++++++++++++++++++++++++++++++---
1 file changed, 40 insertions(+), 3 deletions(-)
diff --git a/ffmpeg.c b/ffmpeg.c
index 3cd45ba665..7b044b068c 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -1434,6 +1434,7 @@ static int reap_filters(int flush)
AVFilterContext *filter;
AVCodecContext *enc = ost->enc_ctx;
int ret = 0;
+ int do_check_init_output_file = 0;
if (!ost->filter || !ost->filter->graph->graph)
continue;
@@ -1448,9 +1449,7 @@ static int reap_filters(int flush)
exit_program(1);
}
- ret = check_init_output_file(of, ost->file_index);
- if (ret < 0)
- exit_program(1);
+ do_check_init_output_file = 1;
}
if (!ost->filtered_frame && !(ost->filtered_frame = av_frame_alloc())) {
@@ -1526,6 +1525,44 @@ static int reap_filters(int flush)
}
av_frame_unref(filtered_frame);
+
+ /*
+ * It is important to call check_init_output_file() here, after
+ * do_video_out() was called, instead of in init_output_stream(),
+ * as was done previously.
+ * If called from init_output_stream(), it is possible that not
+ * everything will have been fully initialized by the time that
+ * check_init_output_file() is called, and if
+ * check_init_output_file() determines that all output streams
+ * have been initialized, it will write the header. An example
+ * of initialization that depends on do_video_out() being called
+ * at least once is the specification of interlaced video, which
+ * happens in do_video_out(). This is particularly relevant when
+ * decoding--without processing a video frame, the interlaced
+ * video setting is not propagated before the header is written,
+ * and that causes problems.
+ * TODO: should probably handle interlaced video differently
+ * and not depend on it being setup in do_video_out(). Another
+ * solution would be to set it up once by examining the input
+ * header.
+ */
+ if (do_check_init_output_file) {
+ ret = check_init_output_file(of, ost->file_index);
+ if (ret < 0)
+ exit_program(1);
+ do_check_init_output_file = 0;
+ }
+ }
+
+ /*
+ * Can't wait too long to call check_init_output_file().
+ * Otherwise, bad things start to occur.
+ * If didn't do it earlier, do it by the time it gets here.
+ */
+ if (do_check_init_output_file) {
+ ret = check_init_output_file(of, ost->file_index);
+ if (ret < 0)
+ exit_program(1);
}
}
--
2.12.2.windows.2
More information about the ffmpeg-devel
mailing list