mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
avconv: buffer the packets written while the muxer is not initialized
This commit is contained in:
parent
1c169782ca
commit
398f015f07
76
avconv.c
76
avconv.c
@ -192,6 +192,13 @@ static void avconv_cleanup(int ret)
|
||||
|
||||
avcodec_free_context(&ost->enc_ctx);
|
||||
|
||||
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]);
|
||||
}
|
||||
for (i = 0; i < nb_input_files; i++) {
|
||||
@ -255,11 +262,33 @@ static void abort_codec_experimental(AVCodec *c, int encoder)
|
||||
exit_program(1);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Audio encoders may split the packets -- #frames in != #packets out.
|
||||
* But there is no reordering, so we can limit the number of output packets
|
||||
@ -315,7 +344,7 @@ static void write_packet(AVFormatContext *s, AVPacket *pkt, 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;
|
||||
|
||||
@ -345,10 +374,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) {
|
||||
@ -371,7 +400,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;
|
||||
@ -401,7 +430,7 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost,
|
||||
goto error;
|
||||
|
||||
av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
|
||||
output_packet(s, &pkt, ost);
|
||||
output_packet(of, &pkt, ost);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -410,7 +439,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,
|
||||
@ -475,11 +504,11 @@ static void do_subtitle_out(AVFormatContext *s,
|
||||
else
|
||||
pkt.pts += 90 * sub->end_display_time;
|
||||
}
|
||||
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 *in_picture,
|
||||
int *frame_size)
|
||||
@ -492,8 +521,8 @@ static void do_video_out(AVFormatContext *s,
|
||||
|
||||
format_video_sync = video_sync_method;
|
||||
if (format_video_sync == VSYNC_AUTO)
|
||||
format_video_sync = (s->oformat->flags & AVFMT_NOTIMESTAMPS) ? VSYNC_PASSTHROUGH :
|
||||
(s->oformat->flags & AVFMT_VARIABLE_FPS) ? VSYNC_VFR : VSYNC_CFR;
|
||||
format_video_sync = (of->ctx->oformat->flags & AVFMT_NOTIMESTAMPS) ? VSYNC_PASSTHROUGH :
|
||||
(of->ctx->oformat->flags & AVFMT_VARIABLE_FPS) ? VSYNC_VFR : VSYNC_CFR;
|
||||
if (format_video_sync != VSYNC_PASSTHROUGH &&
|
||||
ost->frame_number &&
|
||||
in_picture->pts != AV_NOPTS_VALUE &&
|
||||
@ -552,7 +581,7 @@ static void do_video_out(AVFormatContext *s,
|
||||
goto error;
|
||||
|
||||
av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
|
||||
output_packet(s, &pkt, ost);
|
||||
output_packet(of, &pkt, ost);
|
||||
*frame_size = pkt.size;
|
||||
|
||||
/* if two pass, output log */
|
||||
@ -662,12 +691,12 @@ static int poll_filter(OutputStream *ost)
|
||||
if (!ost->frame_aspect_ratio)
|
||||
ost->enc_ctx->sample_aspect_ratio = filtered_frame->sample_aspect_ratio;
|
||||
|
||||
do_video_out(of->ctx, ost, filtered_frame, &frame_size);
|
||||
do_video_out(of, ost, filtered_frame, &frame_size);
|
||||
if (vstats_filename && frame_size)
|
||||
do_video_stats(ost, frame_size);
|
||||
break;
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
do_audio_out(of->ctx, ost, filtered_frame);
|
||||
do_audio_out(of, ost, filtered_frame);
|
||||
break;
|
||||
default:
|
||||
// TODO support subtitle filters
|
||||
@ -975,7 +1004,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)
|
||||
@ -1022,7 +1051,7 @@ static void flush_encoders(void)
|
||||
break;
|
||||
}
|
||||
av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
|
||||
output_packet(os, &pkt, ost);
|
||||
output_packet(of, &pkt, ost);
|
||||
}
|
||||
|
||||
if (stop_encoding)
|
||||
@ -1115,7 +1144,7 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
|
||||
opkt.size = pkt->size;
|
||||
}
|
||||
|
||||
output_packet(of->ctx, &opkt, ost);
|
||||
output_packet(of, &opkt, ost);
|
||||
}
|
||||
|
||||
// This does not quite work like avcodec_decode_audio4/avcodec_decode_video2.
|
||||
@ -1353,7 +1382,7 @@ static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output)
|
||||
if (!check_output_constraints(ist, ost) || !ost->encoding_needed)
|
||||
continue;
|
||||
|
||||
do_subtitle_out(output_files[ost->file_index]->ctx, ost, ist, &subtitle, pkt->pts);
|
||||
do_subtitle_out(output_files[ost->file_index], ost, ist, &subtitle, pkt->pts);
|
||||
}
|
||||
|
||||
avsubtitle_free(&subtitle);
|
||||
@ -1657,6 +1686,17 @@ static int check_init_output_file(OutputFile *of, int file_index)
|
||||
if (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;
|
||||
}
|
||||
|
||||
|
7
avconv.h
7
avconv.h
@ -190,6 +190,8 @@ typedef struct OptionsContext {
|
||||
int nb_pass;
|
||||
SpecifierOpt *passlogfiles;
|
||||
int nb_passlogfiles;
|
||||
SpecifierOpt *max_muxing_queue_size;
|
||||
int nb_max_muxing_queue_size;
|
||||
} OptionsContext;
|
||||
|
||||
typedef struct InputFilter {
|
||||
@ -391,6 +393,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;
|
||||
} OutputStream;
|
||||
|
||||
typedef struct OutputFile {
|
||||
|
11
avconv_opt.c
11
avconv_opt.c
@ -1073,6 +1073,10 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e
|
||||
ost->enc_ctx->global_quality = FF_QP2LAMBDA * qscale;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -1083,6 +1087,10 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e
|
||||
ost->pix_fmts[0] = ost->pix_fmts[1] = AV_PIX_FMT_NONE;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2648,6 +2656,9 @@ const OptionDef options[] = {
|
||||
{ "bsf", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(bitstream_filters) },
|
||||
"A comma-separated list of bitstream filters", "bitstream_filters" },
|
||||
|
||||
{ "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" },
|
||||
|
@ -956,6 +956,15 @@ This option enables or disables accurate seeking in input files with the
|
||||
transcoding. Use @option{-noaccurate_seek} to disable it, which may be useful
|
||||
e.g. when copying some streams and transcoding the others.
|
||||
|
||||
@item -max_muxing_queue_size @var{packets} (@emph{output,per-stream})
|
||||
When transcoding audio and/or video streams, avconv 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
|
||||
@c man end OPTIONS
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user