aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHendrik Leppkes <h.leppkes@gmail.com>2016-10-08 11:38:47 +0200
committerHendrik Leppkes <h.leppkes@gmail.com>2016-10-08 11:38:47 +0200
commit3e5e5bdfef07526aa5c6b15e0484bdc51289cad9 (patch)
treef5c3754aa42bf8ca8d541fb771ca7644c89da3ad
parentc45ba265fcbb57fcacf82f66cb2a2643210308e1 (diff)
parent398f015f077c6a2406deffd9e37ff34b9c7bb3bc (diff)
downloadffmpeg-3e5e5bdfef07526aa5c6b15e0484bdc51289cad9.tar.gz
Merge commit '398f015f077c6a2406deffd9e37ff34b9c7bb3bc'
* commit '398f015f077c6a2406deffd9e37ff34b9c7bb3bc': avconv: buffer the packets written while the muxer is not initialized Merged-by: Hendrik Leppkes <h.leppkes@gmail.com>
-rw-r--r--doc/ffmpeg.texi9
-rw-r--r--ffmpeg.c84
-rw-r--r--ffmpeg.h7
-rw-r--r--ffmpeg_opt.c12
4 files changed, 90 insertions, 22 deletions
diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
index 5255d2d376..b00de30a6d 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -1279,6 +1279,15 @@ No packets were passed to the muxer, the output is empty.
@item -xerror (@emph{global})
Stop and exit on error
+@item -max_muxing_queue_size @var{packets} (@emph{output,per-stream})
+When transcoding audio and/or video streams, ffmpeg will not begin writing into
+the output until it has one packet for each such stream. While waiting for that
+to happen, packets for other streams are buffered. This option sets the size of
+this buffer, in packets, for the matching output stream.
+
+The default value of this option should be high enough for most uses, so only
+touch this option if you are sure that you need it.
+
@end table
As a special exception, you can use a bitmap subtitle stream as input: it
diff --git a/ffmpeg.c b/ffmpeg.c
index 49d91bee79..693981f077 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -533,6 +533,13 @@ static void ffmpeg_cleanup(int ret)
avcodec_free_context(&ost->enc_ctx);
avcodec_parameters_free(&ost->ref_par);
+ while (av_fifo_size(ost->muxing_queue)) {
+ AVPacket pkt;
+ av_fifo_generic_read(ost->muxing_queue, &pkt, sizeof(pkt), NULL);
+ av_packet_unref(&pkt);
+ }
+ av_fifo_free(ost->muxing_queue);
+
av_freep(&output_streams[i]);
}
#if HAVE_PTHREADS
@@ -635,11 +642,33 @@ static void close_all_output_streams(OutputStream *ost, OSTFinished this_stream,
}
}
-static void write_packet(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
+static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost)
{
+ AVFormatContext *s = of->ctx;
AVStream *st = ost->st;
int ret;
+ if (!of->header_written) {
+ AVPacket tmp_pkt;
+ /* the muxer is not initialized yet, buffer the packet */
+ if (!av_fifo_space(ost->muxing_queue)) {
+ int new_size = FFMIN(2 * av_fifo_size(ost->muxing_queue),
+ ost->max_muxing_queue_size);
+ if (new_size <= av_fifo_size(ost->muxing_queue)) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Too many packets buffered for output stream %d:%d.\n",
+ ost->file_index, ost->st->index);
+ exit_program(1);
+ }
+ ret = av_fifo_realloc2(ost->muxing_queue, new_size);
+ if (ret < 0)
+ exit_program(1);
+ }
+ av_packet_move_ref(&tmp_pkt, pkt);
+ av_fifo_generic_write(ost->muxing_queue, &tmp_pkt, sizeof(tmp_pkt), NULL);
+ return;
+ }
+
if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && video_sync_method == VSYNC_DROP) ||
(st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && audio_sync_method < 0))
pkt->pts = pkt->dts = AV_NOPTS_VALUE;
@@ -752,7 +781,7 @@ static void close_output_stream(OutputStream *ost)
}
}
-static void output_packet(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
+static void output_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost)
{
int ret = 0;
@@ -800,10 +829,10 @@ static void output_packet(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
goto finish;
idx++;
} else
- write_packet(s, pkt, ost);
+ write_packet(of, pkt, ost);
}
} else
- write_packet(s, pkt, ost);
+ write_packet(of, pkt, ost);
finish:
if (ret < 0 && ret != AVERROR_EOF) {
@@ -827,7 +856,7 @@ static int check_recording_time(OutputStream *ost)
return 1;
}
-static void do_audio_out(AVFormatContext *s, OutputStream *ost,
+static void do_audio_out(OutputFile *of, OutputStream *ost,
AVFrame *frame)
{
AVCodecContext *enc = ost->enc_ctx;
@@ -878,7 +907,7 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost,
av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base));
}
- output_packet(s, &pkt, ost);
+ output_packet(of, &pkt, ost);
}
return;
@@ -887,7 +916,7 @@ error:
exit_program(1);
}
-static void do_subtitle_out(AVFormatContext *s,
+static void do_subtitle_out(OutputFile *of,
OutputStream *ost,
InputStream *ist,
AVSubtitle *sub)
@@ -967,11 +996,11 @@ static void do_subtitle_out(AVFormatContext *s,
pkt.pts += 90 * sub->end_display_time;
}
pkt.dts = pkt.pts;
- output_packet(s, &pkt, ost);
+ output_packet(of, &pkt, ost);
}
}
-static void do_video_out(AVFormatContext *s,
+static void do_video_out(OutputFile *of,
OutputStream *ost,
AVFrame *next_picture,
double sync_ipts)
@@ -1020,10 +1049,10 @@ static void do_video_out(AVFormatContext *s,
format_video_sync = video_sync_method;
if (format_video_sync == VSYNC_AUTO) {
- if(!strcmp(s->oformat->name, "avi")) {
+ if(!strcmp(of->ctx->oformat->name, "avi")) {
format_video_sync = VSYNC_VFR;
} else
- format_video_sync = (s->oformat->flags & AVFMT_VARIABLE_FPS) ? ((s->oformat->flags & AVFMT_NOTIMESTAMPS) ? VSYNC_PASSTHROUGH : VSYNC_VFR) : VSYNC_CFR;
+ format_video_sync = (of->ctx->oformat->flags & AVFMT_VARIABLE_FPS) ? ((of->ctx->oformat->flags & AVFMT_NOTIMESTAMPS) ? VSYNC_PASSTHROUGH : VSYNC_VFR) : VSYNC_CFR;
if ( ist
&& format_video_sync == VSYNC_CFR
&& input_files[ist->file_index]->ctx->nb_streams == 1
@@ -1134,7 +1163,7 @@ static void do_video_out(AVFormatContext *s,
return;
#if FF_API_LAVF_FMT_RAWPICTURE
- if (s->oformat->flags & AVFMT_RAWPICTURE &&
+ if (of->ctx->oformat->flags & AVFMT_RAWPICTURE &&
enc->codec->id == AV_CODEC_ID_RAWVIDEO) {
/* raw pictures are written as AVPicture structure to
avoid any copies. We support temporarily the older
@@ -1148,7 +1177,7 @@ static void do_video_out(AVFormatContext *s,
pkt.pts = av_rescale_q(in_picture->pts, enc->time_base, ost->st->time_base);
pkt.flags |= AV_PKT_FLAG_KEY;
- output_packet(s, &pkt, ost);
+ output_packet(of, &pkt, ost);
} else
#endif
{
@@ -1251,7 +1280,7 @@ static void do_video_out(AVFormatContext *s,
}
frame_size = pkt.size;
- output_packet(s, &pkt, ost);
+ output_packet(of, &pkt, ost);
/* if two pass, output log */
if (ost->logfile && enc->stats_out) {
@@ -1379,7 +1408,7 @@ static int reap_filters(int flush)
"Error in av_buffersink_get_frame_flags(): %s\n", av_err2str(ret));
} else if (flush && ret == AVERROR_EOF) {
if (filter->inputs[0]->type == AVMEDIA_TYPE_VIDEO)
- do_video_out(of->ctx, ost, NULL, AV_NOPTS_VALUE);
+ do_video_out(of, ost, NULL, AV_NOPTS_VALUE);
}
break;
}
@@ -1419,7 +1448,7 @@ static int reap_filters(int flush)
enc->time_base.num, enc->time_base.den);
}
- do_video_out(of->ctx, ost, filtered_frame, float_pts);
+ do_video_out(of, ost, filtered_frame, float_pts);
break;
case AVMEDIA_TYPE_AUDIO:
if (!(enc->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE) &&
@@ -1428,7 +1457,7 @@ static int reap_filters(int flush)
"Audio filter graph output is not normalized and encoder does not support parameter changes\n");
break;
}
- do_audio_out(of->ctx, ost, filtered_frame);
+ do_audio_out(of, ost, filtered_frame);
break;
default:
// TODO support subtitle filters
@@ -1758,7 +1787,7 @@ static void flush_encoders(void)
for (i = 0; i < nb_output_streams; i++) {
OutputStream *ost = output_streams[i];
AVCodecContext *enc = ost->enc_ctx;
- AVFormatContext *os = output_files[ost->file_index]->ctx;
+ OutputFile *of = output_files[ost->file_index];
int stop_encoding = 0;
if (!ost->encoding_needed)
@@ -1767,7 +1796,7 @@ static void flush_encoders(void)
if (enc->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <= 1)
continue;
#if FF_API_LAVF_FMT_RAWPICTURE
- if (enc->codec_type == AVMEDIA_TYPE_VIDEO && (os->oformat->flags & AVFMT_RAWPICTURE) && enc->codec->id == AV_CODEC_ID_RAWVIDEO)
+ if (enc->codec_type == AVMEDIA_TYPE_VIDEO && (of->ctx->oformat->flags & AVFMT_RAWPICTURE) && enc->codec->id == AV_CODEC_ID_RAWVIDEO)
continue;
#endif
@@ -1819,7 +1848,7 @@ static void flush_encoders(void)
}
av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
pkt_size = pkt.size;
- output_packet(os, &pkt, ost);
+ output_packet(of, &pkt, ost);
if (ost->enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO && vstats_filename) {
do_video_stats(ost, pkt_size);
}
@@ -1961,7 +1990,7 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
}
#endif
- output_packet(of->ctx, &opkt, ost);
+ output_packet(of, &opkt, ost);
}
int guess_input_channel_layout(InputStream *ist)
@@ -2367,7 +2396,7 @@ static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output)
|| ost->enc->type != AVMEDIA_TYPE_SUBTITLE)
continue;
- do_subtitle_out(output_files[ost->file_index]->ctx, ost, ist, &subtitle);
+ do_subtitle_out(output_files[ost->file_index], ost, ist, &subtitle);
}
out:
@@ -2756,6 +2785,17 @@ static int check_init_output_file(OutputFile *of, int file_index)
if (sdp_filename || want_sdp)
print_sdp();
+ /* flush the muxing queues */
+ for (i = 0; i < of->ctx->nb_streams; i++) {
+ OutputStream *ost = output_streams[of->ost_index + i];
+
+ while (av_fifo_size(ost->muxing_queue)) {
+ AVPacket pkt;
+ av_fifo_generic_read(ost->muxing_queue, &pkt, sizeof(pkt), NULL);
+ write_packet(of, &pkt, ost);
+ }
+ }
+
return 0;
}
diff --git a/ffmpeg.h b/ffmpeg.h
index 2a22f438fc..e1d4593b27 100644
--- a/ffmpeg.h
+++ b/ffmpeg.h
@@ -212,6 +212,8 @@ typedef struct OptionsContext {
int nb_pass;
SpecifierOpt *passlogfiles;
int nb_passlogfiles;
+ SpecifierOpt *max_muxing_queue_size;
+ int nb_max_muxing_queue_size;
SpecifierOpt *guess_layout_max;
int nb_guess_layout_max;
SpecifierOpt *apad;
@@ -499,6 +501,11 @@ typedef struct OutputStream {
/* packet quality factor */
int quality;
+ int max_muxing_queue_size;
+
+ /* the packets are buffered here until the muxer is ready to be initialized */
+ AVFifoBuffer *muxing_queue;
+
/* packet picture type */
int pict_type;
diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c
index bea2829e4a..4d25fff410 100644
--- a/ffmpeg_opt.c
+++ b/ffmpeg_opt.c
@@ -1395,6 +1395,10 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e
MATCH_PER_STREAM_OPT(disposition, str, ost->disposition, oc, st);
ost->disposition = av_strdup(ost->disposition);
+ ost->max_muxing_queue_size = 128;
+ MATCH_PER_STREAM_OPT(max_muxing_queue_size, i, ost->max_muxing_queue_size, oc, st);
+ ost->max_muxing_queue_size *= sizeof(AVPacket);
+
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
ost->enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
@@ -1414,6 +1418,10 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e
}
ost->last_mux_dts = AV_NOPTS_VALUE;
+ ost->muxing_queue = av_fifo_alloc(8 * sizeof(AVPacket));
+ if (!ost->muxing_queue)
+ exit_program(1);
+
return ost;
}
@@ -3565,6 +3573,10 @@ const OptionDef options[] = {
"set the subtitle options to the indicated preset", "preset" },
{ "fpre", HAS_ARG | OPT_EXPERT| OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_preset },
"set options from indicated preset file", "filename" },
+
+ { "max_muxing_queue_size", HAS_ARG | OPT_INT | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(max_muxing_queue_size) },
+ "maximum number of packets that can be buffered while waiting for all streams to initialize", "packets" },
+
/* data codec support */
{ "dcodec", HAS_ARG | OPT_DATA | OPT_PERFILE | OPT_EXPERT | OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_data_codec },
"force data codec ('copy' to copy stream)", "codec" },