diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 9b6bb3d759..8ab8aee711 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -3478,12 +3478,6 @@ static int need_output(void) if (ost->finished || of_finished(of)) continue; - if (ost->frame_number >= ost->max_frames) { - int j; - for (j = 0; j < of->ctx->nb_streams; j++) - close_output_stream(output_streams[of->ost_index + j]); - continue; - } return 1; } diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 641bdb98b0..56444770bf 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -237,19 +237,11 @@ void of_submit_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost) if (pkt) { /* - * Audio encoders may split the packets -- #frames in != #packets out. - * But there is no reordering, so we can limit the number of output packets - * by simply dropping them here. * Counting encoded video frames needs to be done separately because of * reordering, see do_video_out(). */ - if (!(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->encoding_needed)) { - if (ost->frame_number >= ost->max_frames) { - av_packet_unref(pkt); - return; - } + if (!(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->encoding_needed)) ost->frame_number++; - } } if (of->mux->header_written) { diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 4281644cfc..f7b5ce347b 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -2390,6 +2390,7 @@ static int init_complex_filters(void) static int setup_sync_queues(OutputFile *of, AVFormatContext *oc, int64_t buf_size_us) { int nb_av_enc = 0, nb_interleaved = 0; + int limit_frames = 0, limit_frames_av_enc = 0; #define IS_AV_ENC(ost, type) \ (ost->encoding_needed && (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) @@ -2404,14 +2405,19 @@ static int setup_sync_queues(OutputFile *of, AVFormatContext *oc, int64_t buf_si nb_interleaved += IS_INTERLEAVED(type); nb_av_enc += IS_AV_ENC(ost, type); + + limit_frames |= ost->max_frames < INT64_MAX; + limit_frames_av_enc |= (ost->max_frames < INT64_MAX) && IS_AV_ENC(ost, type); } - if (!(nb_interleaved > 1 && of->shortest)) + if (!((nb_interleaved > 1 && of->shortest) || + (nb_interleaved > 0 && limit_frames))) return 0; - /* if we have more than one encoded audio/video streams, then we + /* if we have more than one encoded audio/video streams, or at least + * one encoded audio/video stream is frame-limited, then we * synchronize them before encoding */ - if (nb_av_enc > 1) { + if ((of->shortest && nb_av_enc > 1) || limit_frames_av_enc) { of->sq_encode = sq_alloc(SYNC_QUEUE_FRAMES, buf_size_us); if (!of->sq_encode) return AVERROR(ENOMEM); @@ -2423,13 +2429,17 @@ static int setup_sync_queues(OutputFile *of, AVFormatContext *oc, int64_t buf_si if (!IS_AV_ENC(ost, type)) continue; - ost->sq_idx_encode = sq_add_stream(of->sq_encode); + ost->sq_idx_encode = sq_add_stream(of->sq_encode, + of->shortest || ost->max_frames < INT64_MAX); if (ost->sq_idx_encode < 0) return ost->sq_idx_encode; ost->sq_frame = av_frame_alloc(); if (!ost->sq_frame) return AVERROR(ENOMEM); + + if (ost->max_frames != INT64_MAX) + sq_limit_frames(of->sq_encode, ost->sq_idx_encode, ost->max_frames); } } @@ -2447,9 +2457,13 @@ static int setup_sync_queues(OutputFile *of, AVFormatContext *oc, int64_t buf_si if (!IS_INTERLEAVED(type)) continue; - ost->sq_idx_mux = sq_add_stream(of->sq_mux); + ost->sq_idx_mux = sq_add_stream(of->sq_mux, + of->shortest || ost->max_frames < INT64_MAX); if (ost->sq_idx_mux < 0) return ost->sq_idx_mux; + + if (ost->max_frames != INT64_MAX) + sq_limit_frames(of->sq_mux, ost->sq_idx_mux, ost->max_frames); } } diff --git a/fftools/sync_queue.c b/fftools/sync_queue.c index ab654ca790..3143d12cf1 100644 --- a/fftools/sync_queue.c +++ b/fftools/sync_queue.c @@ -34,8 +34,12 @@ typedef struct SyncQueueStream { /* stream head: largest timestamp seen */ int64_t head_ts; + int limiting; /* no more frames will be sent for this stream */ int finished; + + uint64_t frames_sent; + uint64_t frames_max; } SyncQueueStream; struct SyncQueue { @@ -86,7 +90,7 @@ static void finish_stream(SyncQueue *sq, unsigned int stream_idx) st->finished = 1; - if (st->head_ts != AV_NOPTS_VALUE) { + if (st->limiting && st->head_ts != AV_NOPTS_VALUE) { /* check if this stream is the new finished head */ if (sq->head_finished_stream < 0 || av_compare_ts(st->head_ts, st->tb, @@ -121,7 +125,7 @@ static void queue_head_update(SyncQueue *sq) * the queue head */ for (unsigned int i = 0; i < sq->nb_streams; i++) { SyncQueueStream *st = &sq->streams[i]; - if (st->head_ts == AV_NOPTS_VALUE) + if (st->limiting && st->head_ts == AV_NOPTS_VALUE) return; } @@ -132,7 +136,7 @@ static void queue_head_update(SyncQueue *sq) for (unsigned int i = 0; i < sq->nb_streams; i++) { SyncQueueStream *st_head = &sq->streams[sq->head_stream]; SyncQueueStream *st_other = &sq->streams[i]; - if (st_other->head_ts != AV_NOPTS_VALUE && + if (st_other->limiting && st_other->head_ts != AV_NOPTS_VALUE && av_compare_ts(st_other->head_ts, st_other->tb, st_head->head_ts, st_head->tb) < 0) sq->head_stream = i; @@ -159,7 +163,8 @@ static void stream_update_ts(SyncQueue *sq, unsigned int stream_idx, int64_t ts) finish_stream(sq, stream_idx); /* update the overall head timestamp if it could have changed */ - if (sq->head_stream < 0 || sq->head_stream == stream_idx) + if (st->limiting && + (sq->head_stream < 0 || sq->head_stream == stream_idx)) queue_head_update(sq); } @@ -262,6 +267,10 @@ int sq_send(SyncQueue *sq, unsigned int stream_idx, SyncQueueFrame frame) stream_update_ts(sq, stream_idx, ts); + st->frames_sent++; + if (st->frames_sent >= st->frames_max) + finish_stream(sq, stream_idx); + return 0; } @@ -339,7 +348,7 @@ int sq_receive(SyncQueue *sq, int stream_idx, SyncQueueFrame frame) return ret; } -int sq_add_stream(SyncQueue *sq) +int sq_add_stream(SyncQueue *sq, int limiting) { SyncQueueStream *tmp, *st; @@ -360,6 +369,8 @@ int sq_add_stream(SyncQueue *sq) * streams forever; cf. overflow_heartbeat() */ st->tb = (AVRational){ 1, 1 }; st->head_ts = AV_NOPTS_VALUE; + st->frames_max = UINT64_MAX; + st->limiting = limiting; return sq->nb_streams++; } @@ -379,6 +390,18 @@ void sq_set_tb(SyncQueue *sq, unsigned int stream_idx, AVRational tb) st->tb = tb; } +void sq_limit_frames(SyncQueue *sq, unsigned int stream_idx, uint64_t frames) +{ + SyncQueueStream *st; + + av_assert0(stream_idx < sq->nb_streams); + st = &sq->streams[stream_idx]; + + st->frames_max = frames; + if (st->frames_sent >= st->frames_max) + finish_stream(sq, stream_idx); +} + SyncQueue *sq_alloc(enum SyncQueueType type, int64_t buf_size_us) { SyncQueue *sq = av_mallocz(sizeof(*sq)); diff --git a/fftools/sync_queue.h b/fftools/sync_queue.h index e08780b7bf..3f823ff0d9 100644 --- a/fftools/sync_queue.h +++ b/fftools/sync_queue.h @@ -51,11 +51,13 @@ void sq_free(SyncQueue **sq); /** * Add a new stream to the sync queue. * + * @param limiting whether the stream is limiting, i.e. no other stream can be + * longer than this one * @return * - a non-negative stream index on success * - a negative error code on error */ -int sq_add_stream(SyncQueue *sq); +int sq_add_stream(SyncQueue *sq, int limiting); /** * Set the timebase for the stream with index stream_idx. Should be called @@ -63,6 +65,13 @@ int sq_add_stream(SyncQueue *sq); */ void sq_set_tb(SyncQueue *sq, unsigned int stream_idx, AVRational tb); +/** + * Limit the number of output frames for stream with index stream_idx + * to max_frames. + */ +void sq_limit_frames(SyncQueue *sq, unsigned int stream_idx, + uint64_t max_frames); + /** * Submit a frame for the stream with index stream_idx. * diff --git a/tests/ref/fate/matroska-flac-extradata-update b/tests/ref/fate/matroska-flac-extradata-update index e8812f51b5..d5814925f5 100644 --- a/tests/ref/fate/matroska-flac-extradata-update +++ b/tests/ref/fate/matroska-flac-extradata-update @@ -1,8 +1,8 @@ -732446e97bae29037ff0cd9963d4ac08 *tests/data/fate/matroska-flac-extradata-update.matroska -1987 tests/data/fate/matroska-flac-extradata-update.matroska -#extradata 0: 34, 0x7acb09e7 -#extradata 1: 34, 0x7acb09e7 -#extradata 2: 34, 0x443402dd +28bc0ded5dc520d955caf29db80d35da *tests/data/fate/matroska-flac-extradata-update.matroska +1795 tests/data/fate/matroska-flac-extradata-update.matroska +#extradata 0: 34, 0x93650c81 +#extradata 1: 34, 0x93650c81 +#extradata 2: 34, 0x93650c81 #tb 0: 1/1000 #media_type 0: audio #codec_id 0: flac @@ -42,9 +42,3 @@ 0, 672, 672, 96, 26, 0x50dd042e 1, 672, 672, 96, 26, 0x50dd042e 2, 672, 672, 96, 26, 0x50dd042e -0, 768, 768, 96, 26, 0x53de0499 -1, 768, 768, 96, 26, 0x53de0499 -0, 864, 864, 96, 26, 0x53df04b4 -1, 864, 864, 96, 26, 0x53df04b4 -0, 960, 960, 42, 26, 0x5740044b -1, 960, 960, 42, 26, 0x5740044b diff --git a/tests/ref/fate/mkv-1242 b/tests/ref/fate/mkv-1242 index e025701093..1d1a227832 100644 --- a/tests/ref/fate/mkv-1242 +++ b/tests/ref/fate/mkv-1242 @@ -42,6 +42,3 @@ 1, 383, 383, 21, 325, 0xcd7a9fd6 1, 404, 404, 22, 359, 0x6edeb91c 1, 426, 426, 21, 333, 0xb8999fb7 -1, 447, 447, 21, 317, 0xf2589e1a -1, 468, 468, 21, 319, 0x82ed9572 -1, 489, 489, 22, 473, 0xea54e696