move packet interleaving function into AVOutputFormat, so it can be overriden easily...
authorMichael Niedermayer <michaelni@gmx.at>
Wed, 29 Sep 2004 23:25:01 +0000 (23:25 +0000)
committerMichael Niedermayer <michaelni@gmx.at>
Wed, 29 Sep 2004 23:25:01 +0000 (23:25 +0000)
Originally committed as revision 3540 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavformat/avformat.h
libavformat/utils.c

index 7bfe4b1..f4d83d1 100644 (file)
@@ -5,7 +5,7 @@
 extern "C" {
 #endif
 
-#define LIBAVFORMAT_BUILD       4616
+#define LIBAVFORMAT_BUILD       4617
 
 #define LIBAVFORMAT_VERSION_INT FFMPEG_VERSION_INT
 #define LIBAVFORMAT_VERSION     FFMPEG_VERSION
@@ -140,6 +140,7 @@ typedef struct AVOutputFormat {
     int flags;
     /* currently only used to set pixel format if not YUV420P */
     int (*set_parameters)(struct AVFormatContext *, AVFormatParameters *);
+    int (*interleave_packet)(struct AVFormatContext *, AVPacket *out, AVPacket *in, int flush);
     /* private fields */
     struct AVOutputFormat *next;
 } AVOutputFormat;
index ed8f583..a6a823b 100644 (file)
@@ -1975,12 +1975,81 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt)
     return s->oformat->write_packet(s, pkt);
 }
 
+/**
+ * interleave_packet implementation which will interleave per DTS.
+ */
+static int av_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush){
+    AVPacketList *pktl, **next_point, *this_pktl;
+    int stream_count=0;
+    int streams[MAX_STREAMS];
+
+    if(pkt){
+        AVStream *st= s->streams[ pkt->stream_index];
+
+        assert(pkt->destruct != av_destruct_packet); //FIXME
+
+        this_pktl = av_mallocz(sizeof(AVPacketList));
+        this_pktl->pkt= *pkt;
+        av_dup_packet(&this_pktl->pkt);
+
+        next_point = &s->packet_buffer;
+        while(*next_point){
+            AVStream *st2= s->streams[ (*next_point)->pkt.stream_index];
+            int64_t left=  st2->time_base.num * (int64_t)st ->time_base.den;
+            int64_t right= st ->time_base.num * (int64_t)st2->time_base.den;
+            if((*next_point)->pkt.dts * left > pkt->dts * right) //FIXME this can overflow
+                break;
+            next_point= &(*next_point)->next;
+        }
+        this_pktl->next= *next_point;
+        *next_point= this_pktl;
+    }
+    
+    memset(streams, 0, sizeof(streams));
+    pktl= s->packet_buffer;
+    while(pktl){
+//av_log(s, AV_LOG_DEBUG, "show st:%d dts:%lld\n", pktl->pkt.stream_index, pktl->pkt.dts);
+        if(streams[ pktl->pkt.stream_index ] == 0)
+            stream_count++;
+        streams[ pktl->pkt.stream_index ]++;
+        pktl= pktl->next;
+    }
+    
+    if(s->nb_streams == stream_count || (flush && stream_count)){
+        pktl= s->packet_buffer;
+        *out= pktl->pkt;
+        
+        s->packet_buffer= pktl->next;        
+        av_freep(&pktl);
+        return 1;
+    }else{
+        av_init_packet(out);
+        return 0;
+    }
+}
+
+/**
+ * Interleaves a AVPacket correctly so it can be muxed.
+ * @param out the interleaved packet will be output here
+ * @param in the input packet
+ * @param flush 1 if no further packets are available as input and all
+ *              remaining packets should be output
+ * @return 1 if a packet was output, 0 if no packet could be output, 
+ *         < 0 if an error occured
+ */
+static int av_interleave_packet(AVFormatContext *s, AVPacket *out, AVPacket *in, int flush){
+    if(s->oformat->interleave_packet)
+        return s->oformat->interleave_packet(s, out, in, flush);
+    else
+        return av_interleave_packet_per_dts(s, out, in, flush);
+}
+
 /**
  * Writes a packet to an output media file ensuring correct interleaving. 
  * The packet shall contain one audio or video frame.
  * If the packets are already correctly interleaved the application should
  * call av_write_frame() instead as its slightly faster, its also important
- * to keep in mind that non interlaved input will need huge amounts
+ * to keep in mind that completly non interleaved input will need huge amounts
  * of memory to interleave with this, so its prefereable to interleave at the
  * demuxer level
  *
@@ -1989,9 +2058,6 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt)
  * @return < 0 if error, = 0 if OK, 1 if end of stream wanted.
  */
 int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt){
-    AVPacketList *pktl, **next_point, *this_pktl;
-    int stream_count=0;
-    int streams[MAX_STREAMS];
     AVStream *st= s->streams[ pkt->stream_index];
 
     compute_pkt_fields2(st, pkt);
@@ -1999,57 +2065,25 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt){
     //FIXME/XXX/HACK drop zero sized packets
     if(st->codec.codec_type == CODEC_TYPE_AUDIO && pkt->size==0)
         return 0;
-
+    
     if(pkt->dts == AV_NOPTS_VALUE)
         return -1;
-        
-    assert(pkt->destruct != av_destruct_packet); //FIXME
-
-    this_pktl = av_mallocz(sizeof(AVPacketList));
-    this_pktl->pkt= *pkt;
-    av_dup_packet(&this_pktl->pkt);
-
-    next_point = &s->packet_buffer;
-    while(*next_point){
-        AVStream *st2= s->streams[ (*next_point)->pkt.stream_index];
-        int64_t left=  st2->time_base.num * (int64_t)st ->time_base.den;
-        int64_t right= st ->time_base.num * (int64_t)st2->time_base.den;
-        if((*next_point)->pkt.dts * left > pkt->dts * right) //FIXME this can overflow
-            break;
-        next_point= &(*next_point)->next;
-    }
-    this_pktl->next= *next_point;
-    *next_point= this_pktl;
-    
-    memset(streams, 0, sizeof(streams));
-    pktl= s->packet_buffer;
-    while(pktl){
-//av_log(s, AV_LOG_DEBUG, "show st:%d dts:%lld\n", pktl->pkt.stream_index, pktl->pkt.dts);
-        if(streams[ pktl->pkt.stream_index ] == 0)
-            stream_count++;
-        streams[ pktl->pkt.stream_index ]++;
-        pktl= pktl->next;
-    }
 
-    while(s->nb_streams == stream_count){
-        int ret;
-
-        pktl= s->packet_buffer;
-//av_log(s, AV_LOG_DEBUG, "write st:%d dts:%lld\n", pktl->pkt.stream_index, pktl->pkt.dts);
-        truncate_ts(s->streams[pktl->pkt.stream_index], &pktl->pkt);
-        ret= s->oformat->write_packet(s, &pktl->pkt);
+    for(;;){
+        AVPacket opkt;
+        int ret= av_interleave_packet(s, &opkt, pkt, 0);
+        if(ret<=0) //FIXME cleanup needed for ret<0 ?
+            return ret;
         
-        s->packet_buffer= pktl->next;        
-        if((--streams[ pktl->pkt.stream_index ]) == 0)
-            stream_count--;
-
-        av_free_packet(&pktl->pkt);
-        av_freep(&pktl);
+        truncate_ts(s->streams[opkt.stream_index], &opkt);
+        ret= s->oformat->write_packet(s, &opkt);
+        
+        av_free_packet(&opkt);
+        pkt= NULL;
         
         if(ret<0)
             return ret;
     }
-    return 0;
 }
 
 /**
@@ -2062,21 +2096,21 @@ int av_write_trailer(AVFormatContext *s)
 {
     int ret;
     
-    while(s->packet_buffer){
-        int ret;
-        AVPacketList *pktl= s->packet_buffer;
-
-//av_log(s, AV_LOG_DEBUG, "write_trailer st:%d dts:%lld\n", pktl->pkt.stream_index, pktl->pkt.dts);
-        truncate_ts(s->streams[pktl->pkt.stream_index], &pktl->pkt);
-        ret= s->oformat->write_packet(s, &pktl->pkt);
+    for(;;){
+        AVPacket pkt;
+        ret= av_interleave_packet(s, &pkt, NULL, 1);
+        if(ret<0) //FIXME cleanup needed for ret<0 ?
+            return ret;
+        if(!ret)
+            break;
         
-        s->packet_buffer= pktl->next;        
-
-        av_free_packet(&pktl->pkt);
-        av_freep(&pktl);
+        truncate_ts(s->streams[pkt.stream_index], &pkt);
+        ret= s->oformat->write_packet(s, &pkt);
+        
+        av_free_packet(&pkt);
         
         if(ret<0)
-            return ret;
+            return ret; 
     }
 
     ret = s->oformat->write_trailer(s);