You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	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:
		| @@ -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 | ||||
|   | ||||
							
								
								
									
										84
									
								
								ffmpeg.c
									
									
									
									
									
								
							
							
						
						
									
										84
									
								
								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; | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										7
									
								
								ffmpeg.h
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								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; | ||||
|  | ||||
|   | ||||
							
								
								
									
										12
									
								
								ffmpeg_opt.c
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								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" }, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user