@@ -3467,12 +3467,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;
}
@@ -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) {
@@ -2336,6 +2336,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))
@@ -2350,14 +2351,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);
@@ -2369,13 +2375,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);
}
}
@@ -2393,9 +2403,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);
}
}
@@ -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));
@@ -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.
*
@@ -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
@@ -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