]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/avienc.c
Merge commit '2b4c38d3c647f409080606ef02b3363ada00be2c'
[ffmpeg] / libavformat / avienc.c
index 3b5e5c44135d679203a67ac59be3109980d6881c..fb2cdd2077e3371f0d3d31fbcdbc536d1c172c2d 100644 (file)
@@ -52,6 +52,7 @@ typedef struct AVIIndex {
     int64_t     audio_strm_offset;
     int         entry;
     int         ents_allocated;
+    int         master_odml_riff_id_base;
     AVIIentry** cluster;
 } AVIIndex;
 
@@ -156,6 +157,33 @@ static int avi_write_counters(AVFormatContext *s, int riff_id)
     return 0;
 }
 
+static void write_odml_master(AVFormatContext *s, int stream_index)
+{
+    AVIOContext *pb = s->pb;
+    AVStream *st = s->streams[stream_index];
+    AVCodecContext *enc = st->codec;
+    AVIStream *avist = st->priv_data;
+    unsigned char tag[5];
+    int j;
+
+    /* Starting to lay out AVI OpenDML master index.
+        * We want to make it JUNK entry for now, since we'd
+        * like to get away without making AVI an OpenDML one
+        * for compatibility reasons. */
+    avist->indexes.indx_start = ff_start_tag(pb, "JUNK");
+    avio_wl16(pb, 4);   /* wLongsPerEntry */
+    avio_w8(pb, 0);     /* bIndexSubType (0 == frame index) */
+    avio_w8(pb, 0);     /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */
+    avio_wl32(pb, 0);   /* nEntriesInUse (will fill out later on) */
+    ffio_wfourcc(pb, avi_stream2fourcc(tag, stream_index, enc->codec_type));
+                        /* dwChunkId */
+    avio_wl64(pb, 0);   /* dwReserved[3] */
+    avio_wl32(pb, 0);   /* Must be 0.    */
+    for (j = 0; j < AVI_MASTER_INDEX_SIZE * 2; j++)
+        avio_wl64(pb, 0);
+    ff_end_tag(pb, avist->indexes.indx_start);
+}
+
 static int avi_write_header(AVFormatContext *s)
 {
     AVIContext *avi = s->priv_data;
@@ -365,26 +393,7 @@ static int avi_write_header(AVFormatContext *s)
         }
 
         if (pb->seekable) {
-            unsigned char tag[5];
-            int j;
-
-            /* Starting to lay out AVI OpenDML master index.
-             * We want to make it JUNK entry for now, since we'd
-             * like to get away without making AVI an OpenDML one
-             * for compatibility reasons. */
-            avist->indexes.entry      = avist->indexes.ents_allocated = 0;
-            avist->indexes.indx_start = ff_start_tag(pb, "JUNK");
-            avio_wl16(pb, 4);   /* wLongsPerEntry */
-            avio_w8(pb, 0);     /* bIndexSubType (0 == frame index) */
-            avio_w8(pb, 0);     /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */
-            avio_wl32(pb, 0);   /* nEntriesInUse (will fill out later on) */
-            ffio_wfourcc(pb, avi_stream2fourcc(tag, i, enc->codec_type));
-                                /* dwChunkId */
-            avio_wl64(pb, 0);   /* dwReserved[3] */
-            // avio_wl32(pb, 0);   /* Must be 0.    */
-            for (j = 0; j < AVI_MASTER_INDEX_SIZE * 2; j++)
-                avio_wl64(pb, 0);
-            ff_end_tag(pb, avist->indexes.indx_start);
+            write_odml_master(s, i);
         }
 
         if (enc->codec_type == AVMEDIA_TYPE_VIDEO   &&
@@ -460,6 +469,39 @@ static int avi_write_header(AVFormatContext *s)
     return 0;
 }
 
+static void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix, int size)
+{
+    AVIOContext *pb = s->pb;
+    AVIContext *avi = s->priv_data;
+    AVIStream *avist = s->streams[stream_index]->priv_data;
+    int64_t pos;
+    int au_byterate, au_ssize, au_scale;
+
+    avio_flush(pb);
+    pos = avio_tell(pb);
+
+    /* Updating one entry in the AVI OpenDML master index */
+    avio_seek(pb, avist->indexes.indx_start - 8, SEEK_SET);
+    ffio_wfourcc(pb, "indx");             /* enabling this entry */
+    avio_skip(pb, 8);
+    avio_wl32(pb, avi->riff_id - avist->indexes.master_odml_riff_id_base);          /* nEntriesInUse */
+    avio_skip(pb, 16 * (avi->riff_id - avist->indexes.master_odml_riff_id_base));
+    avio_wl64(pb, ix);                    /* qwOffset */
+    avio_wl32(pb, size);                  /* dwSize */
+    ff_parse_specific_params(s->streams[stream_index], &au_byterate, &au_ssize, &au_scale);
+    if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_AUDIO && au_ssize > 0) {
+        uint32_t audio_segm_size = (avist->audio_strm_length - avist->indexes.audio_strm_offset);
+        if ((audio_segm_size % au_ssize > 0) && !avist->sample_requested) {
+            avpriv_request_sample(s, "OpenDML index duration for audio packets with partial frames");
+            avist->sample_requested = 1;
+        }
+        avio_wl32(pb, audio_segm_size / au_ssize);  /* dwDuration (sample count) */
+    } else
+        avio_wl32(pb, avist->indexes.entry);  /* dwDuration (packet count) */
+
+    avio_seek(pb, pos, SEEK_SET);
+}
+
 static int avi_write_ix(AVFormatContext *s)
 {
     AVIOContext *pb = s->pb;
@@ -470,16 +512,24 @@ static int avi_write_ix(AVFormatContext *s)
 
     av_assert0(pb->seekable);
 
-    if (avi->riff_id > AVI_MASTER_INDEX_SIZE) {
-        av_log(s, AV_LOG_ERROR, "Invalid riff index %d > %d\n",
-               avi->riff_id, AVI_MASTER_INDEX_SIZE);
-        return AVERROR(EINVAL);
+    for (i = 0; i < s->nb_streams; i++) {
+        AVIStream *avist = s->streams[i]->priv_data;
+        if (avi->riff_id - avist->indexes.master_odml_riff_id_base == AVI_MASTER_INDEX_SIZE) {
+            int64_t pos;
+            int size = 8+2+1+1+4+8+4+4+16*AVI_MASTER_INDEX_SIZE;
+
+            pos = avio_tell(pb);
+            update_odml_entry(s, i, pos, size);
+            write_odml_master(s, i);
+            av_assert1(avio_tell(pb) - pos == size);
+            avist->indexes.master_odml_riff_id_base = avi->riff_id - 1;
+        }
+        av_assert0(avi->riff_id - avist->indexes.master_odml_riff_id_base < AVI_MASTER_INDEX_SIZE);
     }
 
     for (i = 0; i < s->nb_streams; i++) {
         AVIStream *avist = s->streams[i]->priv_data;
-        int64_t ix, pos;
-        int au_byterate, au_ssize, au_scale;
+        int64_t ix;
 
         avi_stream2fourcc(tag, i, s->streams[i]->codec->codec_type);
         ix_tag[3] = '0' + i;
@@ -504,29 +554,8 @@ static int avi_write_ix(AVFormatContext *s)
             avio_wl32(pb, ((uint32_t) ie->len & ~0x80000000) |
                           (ie->flags & 0x10 ? 0 : 0x80000000));
         }
-        avio_flush(pb);
-        pos = avio_tell(pb);
-
-        /* Updating one entry in the AVI OpenDML master index */
-        avio_seek(pb, avist->indexes.indx_start - 8, SEEK_SET);
-        ffio_wfourcc(pb, "indx");             /* enabling this entry */
-        avio_skip(pb, 8);
-        avio_wl32(pb, avi->riff_id);          /* nEntriesInUse */
-        avio_skip(pb, 16 * avi->riff_id);
-        avio_wl64(pb, ix);                    /* qwOffset */
-        avio_wl32(pb, pos - ix);              /* dwSize */
-        ff_parse_specific_params(s->streams[i], &au_byterate, &au_ssize, &au_scale);
-        if (s->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && au_ssize > 0) {
-            uint32_t audio_segm_size = (avist->audio_strm_length - avist->indexes.audio_strm_offset);
-            if ((audio_segm_size % au_ssize > 0) && !avist->sample_requested) {
-                avpriv_request_sample(s, "OpenDML index duration for audio packets with partial frames");
-                avist->sample_requested = 1;
-            }
-            avio_wl32(pb, audio_segm_size / au_ssize);  /* dwDuration (sample count) */
-        } else
-            avio_wl32(pb, avist->indexes.entry);  /* dwDuration (packet count) */
 
-        avio_seek(pb, pos, SEEK_SET);
+        update_odml_entry(s, i, ix, avio_tell(pb) - ix);
     }
     return 0;
 }