diff options
author | Hendrik Leppkes <h.leppkes@gmail.com> | 2016-10-08 11:38:47 +0200 |
---|---|---|
committer | Hendrik Leppkes <h.leppkes@gmail.com> | 2016-10-08 11:38:47 +0200 |
commit | 3e5e5bdfef07526aa5c6b15e0484bdc51289cad9 (patch) | |
tree | f5c3754aa42bf8ca8d541fb771ca7644c89da3ad | |
parent | c45ba265fcbb57fcacf82f66cb2a2643210308e1 (diff) | |
parent | 398f015f077c6a2406deffd9e37ff34b9c7bb3bc (diff) | |
download | ffmpeg-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.texi | 9 | ||||
-rw-r--r-- | ffmpeg.c | 84 | ||||
-rw-r--r-- | ffmpeg.h | 7 | ||||
-rw-r--r-- | ffmpeg_opt.c | 12 |
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 @@ -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; } @@ -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" }, |