You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	avformat/mux: implement AVFMT_FLAG_SHORTEST
This will allow fixing several bugs with the -shortest option Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This commit is contained in:
		| @@ -61,6 +61,10 @@ Reduce the latency introduced by optional buffering | ||||
| Only write platform-, build- and time-independent data. | ||||
| This ensures that file and data checksums are reproducible and match between | ||||
| platforms. Its primary use is for regression testing. | ||||
| @item shortest | ||||
| Stop muxing at the end of the shortest stream. | ||||
| It may be needed to increase max_interleave_delta to avoid flusing the longer | ||||
| streams before EOF. | ||||
| @end table | ||||
|  | ||||
| @item seek2any @var{integer} (@emph{input}) | ||||
|   | ||||
| @@ -1448,6 +1448,7 @@ typedef struct AVFormatContext { | ||||
| #define AVFMT_FLAG_PRIV_OPT    0x20000 ///< Enable use of private options by delaying codec open (this could be made default once all code is converted) | ||||
| #define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Don't merge side data but keep it separate. | ||||
| #define AVFMT_FLAG_FAST_SEEK   0x80000 ///< Enable fast, but inaccurate seeks for some formats | ||||
| #define AVFMT_FLAG_SHORTEST   0x100000 ///< Stop muxing when the shortest stream stops. | ||||
|  | ||||
|     /** | ||||
|      * Maximum size of the data read from input for determining | ||||
|   | ||||
| @@ -125,6 +125,11 @@ struct AVFormatInternal { | ||||
|      */ | ||||
|     int header_written; | ||||
|     int write_header_ret; | ||||
|  | ||||
|     /** | ||||
|      * Timestamp of the end of the shortest stream. | ||||
|      */ | ||||
|     int64_t shortest_end; | ||||
| }; | ||||
|  | ||||
| struct AVStreamInternal { | ||||
|   | ||||
| @@ -1032,6 +1032,7 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, | ||||
|     int stream_count = 0; | ||||
|     int noninterleaved_count = 0; | ||||
|     int i, ret; | ||||
|     int eof = flush; | ||||
|  | ||||
|     if (pkt) { | ||||
|         if ((ret = ff_interleave_add_packet(s, pkt, interleave_compare_dts)) < 0) | ||||
| @@ -1084,6 +1085,44 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (s->internal->packet_buffer && | ||||
|         eof && | ||||
|         (s->flags & AVFMT_FLAG_SHORTEST) && | ||||
|         s->internal->shortest_end == AV_NOPTS_VALUE) { | ||||
|         AVPacket *top_pkt = &s->internal->packet_buffer->pkt; | ||||
|  | ||||
|         s->internal->shortest_end = av_rescale_q(top_pkt->dts, | ||||
|                                        s->streams[top_pkt->stream_index]->time_base, | ||||
|                                        AV_TIME_BASE_Q); | ||||
|     } | ||||
|  | ||||
|     if (s->internal->shortest_end != AV_NOPTS_VALUE) { | ||||
|         while (s->internal->packet_buffer) { | ||||
|             AVPacket *top_pkt = &s->internal->packet_buffer->pkt; | ||||
|             AVStream *st; | ||||
|             int64_t top_dts = av_rescale_q(top_pkt->dts, | ||||
|                                         s->streams[top_pkt->stream_index]->time_base, | ||||
|                                         AV_TIME_BASE_Q); | ||||
|  | ||||
|             if (s->internal->shortest_end + 1 >= top_dts) | ||||
|                 break; | ||||
|  | ||||
|             pktl = s->internal->packet_buffer; | ||||
|             st   = s->streams[pktl->pkt.stream_index]; | ||||
|  | ||||
|             s->internal->packet_buffer = pktl->next; | ||||
|             if (!s->internal->packet_buffer) | ||||
|                 s->internal->packet_buffer_end = NULL; | ||||
|  | ||||
|             if (st->last_in_packet_buffer == pktl) | ||||
|                 st->last_in_packet_buffer = NULL; | ||||
|  | ||||
|             av_packet_unref(&pktl->pkt); | ||||
|             av_freep(&pktl); | ||||
|             flush = 0; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (stream_count && flush) { | ||||
|         AVStream *st; | ||||
|         pktl = s->internal->packet_buffer; | ||||
|   | ||||
| @@ -143,6 +143,7 @@ AVFormatContext *avformat_alloc_context(void) | ||||
|     } | ||||
|     ic->internal->offset = AV_NOPTS_VALUE; | ||||
|     ic->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE; | ||||
|     ic->internal->shortest_end = AV_NOPTS_VALUE; | ||||
|  | ||||
|     return ic; | ||||
| } | ||||
|   | ||||
| @@ -54,6 +54,7 @@ static const AVOption avformat_options[] = { | ||||
| {"nobuffer", "reduce the latency introduced by optional buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOBUFFER }, 0, INT_MAX, D, "fflags"}, | ||||
| {"seek2any", "allow seeking to non-keyframes on demuxer level when supported", OFFSET(seek2any), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, D}, | ||||
| {"bitexact", "do not write random/volatile data", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_BITEXACT }, 0, 0, E, "fflags" }, | ||||
| {"shortest", "stop muxing with the shortest stream", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_SHORTEST }, 0, 0, E, "fflags" }, | ||||
| {"analyzeduration", "specify how many microseconds are analyzed to probe the input", OFFSET(max_analyze_duration), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, D}, | ||||
| {"cryptokey", "decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, {.dbl = 0}, 0, 0, D}, | ||||
| {"indexmem", "max memory used for timestamp index (per stream)", OFFSET(max_index_size), AV_OPT_TYPE_INT, {.i64 = 1<<20 }, 0, INT_MAX, D}, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user