[FFmpeg-devel] [PATCH 2/4] avformat/avienc: write chained master index only if std_compliance is normal or below

Tobias Rapp t.rapp at noa-archive.com
Tue Jan 17 15:39:19 EET 2017


OpenDML specification v1.02 states that entries of a master index chunk
shall point to standard or field index chunks.

Changed incorrect duration of last master index entry to -1 in case it
points to another master index.

Propagate error when index write fails.

Signed-off-by: Tobias Rapp <t.rapp at noa-archive.com>
---
 libavformat/avienc.c | 30 +++++++++++++++++++++++-------
 1 file changed, 23 insertions(+), 7 deletions(-)

diff --git a/libavformat/avienc.c b/libavformat/avienc.c
index fd16fff..5d5c02a 100644
--- a/libavformat/avienc.c
+++ b/libavformat/avienc.c
@@ -524,7 +524,13 @@ static int avi_write_header(AVFormatContext *s)
     return 0;
 }
 
-static void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix, int size)
+/* Index entry points to standard index */
+#define AVI_UPDATE_ODML_ENTRY_DEFAULT   0x00000000
+
+/* Index entry points to another master index */
+#define AVI_UPDATE_ODML_ENTRY_MASTER    0x00000001
+
+static void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix, int size, int flags)
 {
     AVIOContext *pb = s->pb;
     AVIContext *avi = s->priv_data;
@@ -544,7 +550,10 @@ static void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix,
     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]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && au_ssize > 0) {
+    if (flags & AVI_UPDATE_ODML_ENTRY_MASTER) {
+        av_assert0(s->strict_std_compliance <= FF_COMPLIANCE_NORMAL);
+        avio_wl32(pb, -1);  /* dwDuration (undefined) */
+    } else if (s->streams[stream_index]->codecpar->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");
@@ -567,6 +576,12 @@ static int avi_write_ix(AVFormatContext *s)
 
     av_assert0(pb->seekable);
 
+    if (avi->riff_id >= AVI_MASTER_INDEX_SIZE && s->strict_std_compliance > FF_COMPLIANCE_NORMAL) {
+        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) {
@@ -574,7 +589,7 @@ static int avi_write_ix(AVFormatContext *s)
             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);
+            update_odml_entry(s, i, pos, size, AVI_UPDATE_ODML_ENTRY_MASTER);
             write_odml_master(s, i);
             av_assert1(avio_tell(pb) - pos == size);
             avist->indexes.master_odml_riff_id_base = avi->riff_id - 1;
@@ -610,7 +625,7 @@ static int avi_write_ix(AVFormatContext *s)
                           (ie->flags & 0x10 ? 0 : 0x80000000));
         }
 
-        update_odml_entry(s, i, ix, avio_tell(pb) - ix);
+        update_odml_entry(s, i, ix, avio_tell(pb) - ix, AVI_UPDATE_ODML_ENTRY_DEFAULT);
     }
     return 0;
 }
@@ -801,6 +816,7 @@ static int avi_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
     AVIOContext *pb     = s->pb;
     AVIStream *avist    = s->streams[stream_index]->priv_data;
     AVCodecParameters *par = s->streams[stream_index]->codecpar;
+    int ret;
 
     if (pkt->dts != AV_NOPTS_VALUE)
         avist->last_dts = pkt->dts + pkt->duration;
@@ -810,7 +826,8 @@ static int avi_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
     // Make sure to put an OpenDML chunk when the file size exceeds the limits
     if (pb->seekable &&
         (avio_tell(pb) - avi->riff_start > AVI_MAX_RIFF_SIZE)) {
-        avi_write_ix(s);
+        if ((ret = avi_write_ix(s)) < 0)
+            return ret;
         ff_end_tag(pb, avi->movi_list);
 
         if (avi->riff_id == 1)
@@ -827,7 +844,6 @@ static int avi_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
         avist->audio_strm_length += size;
 
     if (s->pb->seekable) {
-        int ret;
         ret = avi_add_ientry(s, stream_index, NULL, flags, size);
         if (ret < 0)
             return ret;
@@ -861,7 +877,7 @@ static int avi_write_trailer(AVFormatContext *s)
             res = avi_write_idx1(s);
             ff_end_tag(pb, avi->riff_start);
         } else {
-            avi_write_ix(s);
+            res = avi_write_ix(s);
             ff_end_tag(pb, avi->movi_list);
             ff_end_tag(pb, avi->riff_start);
 
-- 
1.9.1




More information about the ffmpeg-devel mailing list