[Ffmpeg-devel] [Patch] DV in AVI fixes

Jeff Downs heydowns
Tue Dec 19 05:28:12 CET 2006


This patch fixes two issues with AVI files that contain "Type 1" DV.
Searching the mailing list indicates a number of people have seen at
least the first problem below.  The others become more apparent after
the first problem is fixed.

1. Seeking with DV-AVI files would cause a null pointer dereference in
avi_read_seek because the "logical" streams (all streams but the primary
video stream) have no backing AVIStream structure stored in AVStream
priv_data. This patch fixes this by limiting seek index lookups to the
first stream (with DV there is only one possible stream that could have
indexes anyway).

2. The DV demux was only partially informed of the seek having occurred.
Thus, while a seek would give you data starting at the right place in
the file, the synthesized timestamps would continue as though the seek
never happened. This is fixed by restructuring the way that DV is
informed about, and handles, the seek.  Briefly, it brings the DV
demux's seek handling for DV-AVI more in line that of raw DV.

3. The duration for DV-in-AVI ended up being computed at a high level
(utils.c), estimated based on bit rate. This turned out an incorrect
duration, probably because the computation used the file size (which, of
course, includes more than just the DV data). This was significantly off
for some samples we tested. This patch fixes this by setting the 
AVFormatContext's duration parameter to the correct duration
during header parsing, based on values in the AVI header.
-------------- next part --------------
Index: libavformat/dv.c
===================================================================
--- libavformat/dv.c	(revision 7331)
+++ libavformat/dv.c	(working copy)
@@ -358,8 +358,13 @@
     return offset;
 }
 
-void dv_flush_audio_packets(DVDemuxContext *c)
+void dv_offset_reset(DVDemuxContext *c, int64_t frame_offset)
 {
+    c->frames= frame_offset;
+    if (c->ach)
+        c->abytes= av_rescale(c->frames,
+                          c->ast[0]->codec->bit_rate * (int64_t)c->sys->frame_rate_base,
+                          8*c->sys->frame_rate);
     c->audio_pkt[0].size = c->audio_pkt[1].size = 0;
 }
 
@@ -419,13 +424,8 @@
     DVDemuxContext *c = r->dv_demux;
     int64_t offset= dv_frame_offset(s, c, timestamp, flags);
 
-    c->frames= offset / c->sys->frame_size;
-    if (c->ach)
-        c->abytes= av_rescale(c->frames,
-                          c->ast[0]->codec->bit_rate * (int64_t)c->sys->frame_rate_base,
-                          8*c->sys->frame_rate);
+    dv_offset_reset(c, offset / c->sys->frame_size);
 
-    dv_flush_audio_packets(c);
     return url_fseek(&s->pb, offset, SEEK_SET);
 }
 
Index: libavformat/dv.h
===================================================================
--- libavformat/dv.h	(revision 7331)
+++ libavformat/dv.h	(working copy)
@@ -29,7 +29,7 @@
 DVDemuxContext* dv_init_demux(AVFormatContext* s);
 int dv_get_packet(DVDemuxContext*, AVPacket *);
 int dv_produce_packet(DVDemuxContext*, AVPacket*, uint8_t*, int);
-void dv_flush_audio_packets(DVDemuxContext*);
+void dv_offset_reset(DVDemuxContext *c, int64_t frame_offset);
 
 typedef struct DVMuxContext DVMuxContext;
 DVMuxContext* dv_init_mux(AVFormatContext* s);
Index: libavformat/avidec.c
===================================================================
--- libavformat/avidec.c	(revision 7331)
+++ libavformat/avidec.c	(working copy)
@@ -289,6 +289,8 @@
             print_tag("strh", tag1, -1);
 #endif
             if(tag1 == MKTAG('i', 'a', 'v', 's') || tag1 == MKTAG('i', 'v', 'a', 's')){
+                int64_t dv_dur;
+
                 /*
                  * After some consideration -- I don't think we
                  * have to support anything but DV in a type1 AVIs.
@@ -314,8 +316,20 @@
                 url_fskip(pb, 3 * 4);
                 ast->scale = get_le32(pb);
                 ast->rate = get_le32(pb);
+                url_fskip(pb, 4);  /* start time */
+
+                dv_dur = get_le32(pb);
+                if (ast->scale > 0 && ast->rate > 0 && dv_dur > 0) {
+                    dv_dur *= AV_TIME_BASE;
+                    s->duration = av_rescale(dv_dur, ast->scale, ast->rate);
+                } 
+                /* 
+                 * else, leave duration alone; timing estimation in utils.c
+                 *      will make a guess based on bit rate.
+                 */
+
                 stream_index = s->nb_streams - 1;
-                url_fskip(pb, size - 7*4);
+                url_fskip(pb, size - 9*4);
                 break;
             }
 
@@ -903,6 +917,21 @@
 
 //    av_log(NULL, AV_LOG_DEBUG, "XX %"PRId64" %d %"PRId64"\n", timestamp, index, st->index_entries[index].timestamp);
 
+    if (ENABLE_DV_DEMUXER && avi->dv_demux) {
+        /* One and only one real stream for DV in AVI, and it has video  */
+        /* offsets. Calling with other stream indices should have failed */
+        /* the av_index_search_timestamp call above.                     */
+        assert(stream_index == 0);
+
+        /* Feed the DV video stream version of the timestamp to the */
+        /* DV demux so it can synth correct timestamps              */
+        dv_offset_reset(avi->dv_demux, timestamp);
+
+        url_fseek(&s->pb, pos, SEEK_SET);
+        avi->stream_index= -1;
+        return 0;
+    }
+
     for(i = 0; i < s->nb_streams; i++) {
         AVStream *st2 = s->streams[i];
         AVIStream *ast2 = st2->priv_data;
@@ -937,8 +966,6 @@
             ast2->frame_offset *=ast2->sample_size;
     }
 
-    if (ENABLE_DV_DEMUXER && avi->dv_demux)
-        dv_flush_audio_packets(avi->dv_demux);
     /* do the seek */
     url_fseek(&s->pb, pos, SEEK_SET);
     avi->stream_index= -1;



More information about the ffmpeg-devel mailing list