Introduce max_streams_delay and flush the packet queue if the packets
in the queue have a delay larger than the max_streams_delay.

av_interleave_packet_per_dts waits untill it gets a frame for each
stream before outputting packets in interleaved order.

Sparse streams tend to add up latency and in specific cases end up
allocating a large amount of memory.

Original report of the issue and initial proposed solution by
[email protected] on bug 31.
---
 libavformat/avformat.h |    4 ++++
 libavformat/utils.c    |   34 +++++++++++++++++++++++++++-------
 2 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 33e820e..7845c84 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -1005,6 +1005,9 @@ typedef struct AVFormatContext {
      */
     AVIOInterruptCB interrupt_callback;
 
+    /* av_interleave_packet_per_dts() support */
+    int64_t max_streams_delay;
+
     /*****************************************************************
      * All fields below this line are not part of the public API. They
      * may not be used outside of libavformat and can be changed and
@@ -1040,6 +1043,7 @@ typedef struct AVFormatContext {
 
     /* av_seek_frame() support */
     int64_t data_offset; /**< offset of the first packet */
+
 #endif
 } AVFormatContext;
 
diff --git a/libavformat/utils.c b/libavformat/utils.c
index b8262ec..e8c17be 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -3140,19 +3140,39 @@ static int ff_interleave_compare_dts(AVFormatContext 
*s, AVPacket *next, AVPacke
     return comp > 0;
 }
 
-int av_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, AVPacket 
*pkt, int flush){
+int av_interleave_packet_per_dts(AVFormatContext *s,
+                                 AVPacket *out, AVPacket *pkt, int flush)
+{
+    AVPacket *last_pkt;
     AVPacketList *pktl;
-    int stream_count=0;
+    int stream_count = 0;
+    int64_t delta_dts = INT64_MIN;
+    int64_t last_dts;
     int i;
 
-    if(pkt){
+    if (pkt) {
         ff_interleave_add_packet(s, pkt, ff_interleave_compare_dts);
     }
 
-    for(i=0; i < s->nb_streams; i++)
-        stream_count+= !!s->streams[i]->last_in_packet_buffer;
+    last_pkt = &s->packet_buffer->pkt;
+    last_dts = av_rescale_q(last_pkt->dts,
+                           s->streams[last_pkt->stream_index]->time_base,
+                            AV_TIME_BASE_Q);
+
+    for (i=0; i < s->nb_streams; i++)
+        if (s->streams[i]->last_in_packet_buffer) {
+            delta_dts = FFMAX(delta_dts,
+                av_rescale_q(s->streams[i]->last_in_packet_buffer->pkt.dts,
+                            s->streams[i]->time_base,
+                            AV_TIME_BASE_Q) - last_dts);
+            stream_count++;
+        }
+    if (s->max_streams_delay && delta_dts > s->max_streams_delay) {
+        av_log(s, AV_LOG_DEBUG, "Sparse stream detected, forcing flush\n");
+        flush = 1;
+    }
 
-    if(stream_count && (s->nb_streams == stream_count || flush)){
+    if (stream_count && (s->nb_streams == stream_count || flush)) {
         pktl= s->packet_buffer;
         *out= pktl->pkt;
 
@@ -3164,7 +3184,7 @@ int av_interleave_packet_per_dts(AVFormatContext *s, 
AVPacket *out, AVPacket *pk
             s->streams[out->stream_index]->last_in_packet_buffer= NULL;
         av_freep(&pktl);
         return 1;
-    }else{
+    } else {
         av_init_packet(out);
         return 0;
     }
-- 
1.7.8.rc1

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to