Merge commit '398f015f077c6a2406deffd9e37ff34b9c7bb3bc'

* commit '398f015f077c6a2406deffd9e37ff34b9c7bb3bc':
  avconv: buffer the packets written while the muxer is not initialized

Merged-by: Hendrik Leppkes <h.leppkes@gmail.com>
This commit is contained in:
Hendrik Leppkes 2016-10-08 11:38:47 +02:00
commit 3e5e5bdfef
4 changed files with 90 additions and 22 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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" },