]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/matroskadec.c
avformat/tls_schannel: always decrypt all received data
[ffmpeg] / libavformat / matroskadec.c
index 088eeabf2d7b529035804c43e6081c62df22e8d2..b277c05f9da668882465f387e1a1c1dd28c6a10a 100644 (file)
@@ -249,6 +249,7 @@ typedef struct MatroskaTrack {
     AVStream *stream;
     int64_t end_timecode;
     int ms_compat;
+    int needs_decoding;
     uint64_t max_block_additional_id;
 
     uint32_t palette[AVPALETTE_COUNT];
@@ -1134,7 +1135,7 @@ static int is_ebml_id_valid(uint32_t id)
  * an entry already exists, return the existing entry.
  */
 static MatroskaLevel1Element *matroska_find_level1_elem(MatroskaDemuxContext *matroska,
-                                                        uint32_t id)
+                                                        uint32_t id, int64_t pos)
 {
     int i;
     MatroskaLevel1Element *elem;
@@ -1146,19 +1147,18 @@ static MatroskaLevel1Element *matroska_find_level1_elem(MatroskaDemuxContext *ma
     if (id == MATROSKA_ID_CLUSTER)
         return NULL;
 
-    // There can be multiple seekheads.
-    if (id != MATROSKA_ID_SEEKHEAD) {
-        for (i = 0; i < matroska->num_level1_elems; i++) {
-            if (matroska->level1_elems[i].id == id)
+    // There can be multiple SeekHeads and Tags.
+    for (i = 0; i < matroska->num_level1_elems; i++) {
+        if (matroska->level1_elems[i].id == id) {
+            if (matroska->level1_elems[i].pos == pos ||
+                id != MATROSKA_ID_SEEKHEAD && id != MATROSKA_ID_TAGS)
                 return &matroska->level1_elems[i];
         }
     }
 
     // Only a completely broken file would have more elements.
-    // It also provides a low-effort way to escape from circular seekheads
-    // (every iteration will add a level1 entry).
     if (matroska->num_level1_elems >= FF_ARRAY_ELEMS(matroska->level1_elems)) {
-        av_log(matroska->ctx, AV_LOG_ERROR, "Too many level1 elements or circular seekheads.\n");
+        av_log(matroska->ctx, AV_LOG_ERROR, "Too many level1 elements.\n");
         return NULL;
     }
 
@@ -1407,7 +1407,7 @@ static int ebml_parse(MatroskaDemuxContext *matroska,
         if (id == MATROSKA_ID_CUES)
             matroska->cues_parsing_deferred = 0;
         if (syntax->type == EBML_LEVEL1 &&
-            (level1_elem = matroska_find_level1_elem(matroska, syntax->id))) {
+            (level1_elem = matroska_find_level1_elem(matroska, syntax->id, pos))) {
             if (!level1_elem->pos) {
                 // Zero is not a valid position for a level 1 element.
                 level1_elem->pos = pos;
@@ -1865,8 +1865,12 @@ static void matroska_execute_seekhead(MatroskaDemuxContext *matroska)
         MatroskaSeekhead *seekheads = seekhead_list->elem;
         uint32_t id = seekheads[i].id;
         int64_t pos = seekheads[i].pos + matroska->segment_start;
+        MatroskaLevel1Element *elem;
+
+        if (id != seekheads[i].id || pos < matroska->segment_start)
+            continue;
 
-        MatroskaLevel1Element *elem = matroska_find_level1_elem(matroska, id);
+        elem = matroska_find_level1_elem(matroska, id, pos);
         if (!elem || elem->parsed)
             continue;
 
@@ -2405,6 +2409,11 @@ static int matroska_parse_tracks(AVFormatContext *s)
                 }
             }
         }
+        track->needs_decoding = encodings && !encodings[0].type &&
+                                encodings[0].scope & 1          &&
+                                (encodings[0].compression.algo !=
+                                   MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP ||
+                                 encodings[0].compression.settings.size);
 
         for (j = 0; ff_mkv_codec_tags[j].id != AV_CODEC_ID_NONE; j++) {
             if (!strncmp(ff_mkv_codec_tags[j].str, track->codec_id,
@@ -3113,12 +3122,12 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska,
                                    uint8_t *data, int size, uint64_t timecode,
                                    int64_t pos)
 {
-    int a = st->codecpar->block_align;
-    int sps = track->audio.sub_packet_size;
-    int cfs = track->audio.coded_framesize;
-    int h   = track->audio.sub_packet_h;
+    const int a   = st->codecpar->block_align;
+    const int sps = track->audio.sub_packet_size;
+    const int cfs = track->audio.coded_framesize;
+    const int h   = track->audio.sub_packet_h;
+    const int w   = track->audio.frame_size;
     int y   = track->audio.sub_packet_cnt;
-    int w   = track->audio.frame_size;
     int x;
 
     if (!track->audio.pkt_cnt) {
@@ -3186,10 +3195,11 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska,
 }
 
 /* reconstruct full wavpack blocks from mangled matroska ones */
-static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src,
-                                  uint8_t **pdst, int *size)
+static int matroska_parse_wavpack(MatroskaTrack *track,
+                                  uint8_t **data, int *size)
 {
     uint8_t *dst = NULL;
+    uint8_t *src = *data;
     int dstlen   = 0;
     int srclen   = *size;
     uint32_t samples;
@@ -3259,7 +3269,7 @@ static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src,
 
     memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE);
 
-    *pdst = dst;
+    *data = dst;
     *size = dstlen;
 
     return 0;
@@ -3269,22 +3279,22 @@ fail:
     return ret;
 }
 
-static int matroska_parse_prores(MatroskaTrack *track, uint8_t *src,
-                                 uint8_t **pdst, int *size)
+static int matroska_parse_prores(MatroskaTrack *track,
+                                 uint8_t **data, int *size)
 {
     uint8_t *dst;
     int dstlen = *size + 8;
 
-        dst = av_malloc(dstlen + AV_INPUT_BUFFER_PADDING_SIZE);
-        if (!dst)
-            return AVERROR(ENOMEM);
+    dst = av_malloc(dstlen + AV_INPUT_BUFFER_PADDING_SIZE);
+    if (!dst)
+        return AVERROR(ENOMEM);
 
-        AV_WB32(dst, dstlen);
-        AV_WB32(dst + 4, MKBETAG('i', 'c', 'p', 'f'));
-        memcpy(dst + 8, src, dstlen - 8);
-        memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+    AV_WB32(dst, dstlen);
+    AV_WB32(dst + 4, MKBETAG('i', 'c', 'p', 'f'));
+    memcpy(dst + 8, *data, dstlen - 8);
+    memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE);
 
-    *pdst = dst;
+    *data = dst;
     *size = dstlen;
 
     return 0;
@@ -3413,49 +3423,40 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
                                 uint8_t *additional, uint64_t additional_id, int additional_size,
                                 int64_t discard_padding)
 {
-    MatroskaTrackEncoding *encodings = track->encodings.elem;
     uint8_t *pkt_data = data;
     int res = 0;
     AVPacket pktl, *pkt = &pktl;
 
-    if (encodings && !encodings->type && encodings->scope & 1) {
-        res = matroska_decode_buffer(&pkt_data, &pkt_size, track);
-        if (res < 0)
-            return res;
-    }
-
     if (st->codecpar->codec_id == AV_CODEC_ID_WAVPACK) {
-        uint8_t *wv_data;
-        res = matroska_parse_wavpack(track, pkt_data, &wv_data, &pkt_size);
+        res = matroska_parse_wavpack(track, &pkt_data, &pkt_size);
         if (res < 0) {
             av_log(matroska->ctx, AV_LOG_ERROR,
                    "Error parsing a wavpack block.\n");
             goto fail;
         }
-        if (pkt_data != data)
-            av_freep(&pkt_data);
-        pkt_data = wv_data;
+        if (!buf)
+            av_freep(&data);
+        buf = NULL;
     }
 
     if (st->codecpar->codec_id == AV_CODEC_ID_PRORES &&
         AV_RB32(pkt_data + 4)  != MKBETAG('i', 'c', 'p', 'f')) {
-        uint8_t *pr_data;
-        res = matroska_parse_prores(track, pkt_data, &pr_data, &pkt_size);
+        res = matroska_parse_prores(track, &pkt_data, &pkt_size);
         if (res < 0) {
             av_log(matroska->ctx, AV_LOG_ERROR,
                    "Error parsing a prores block.\n");
             goto fail;
         }
-        if (pkt_data != data)
-            av_freep(&pkt_data);
-        pkt_data = pr_data;
+        if (!buf)
+            av_freep(&data);
+        buf = NULL;
     }
 
     if (!pkt_size && !additional_size)
         goto no_output;
 
     av_init_packet(pkt);
-    if (pkt_data != data)
+    if (!buf)
         pkt->buf = av_buffer_create(pkt_data, pkt_size + AV_INPUT_BUFFER_PADDING_SIZE,
                                     NULL, NULL, 0);
     else
@@ -3526,8 +3527,8 @@ FF_ENABLE_DEPRECATION_WARNINGS
 
 no_output:
 fail:
-    if (pkt_data != data)
-        av_freep(&pkt_data);
+    if (!buf)
+        av_free(pkt_data);
     return res;
 }
 
@@ -3629,25 +3630,41 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf
 
     for (n = 0; n < laces; n++) {
         int64_t lace_duration = block_duration*(n+1) / laces - block_duration*n / laces;
+        uint8_t *out_data = data;
+        int      out_size = lace_size[n];
+
+        if (track->needs_decoding) {
+            res = matroska_decode_buffer(&out_data, &out_size, track);
+            if (res < 0)
+                return res;
+            /* Given that we are here means that out_data is no longer
+             * owned by buf, so set it to NULL. This depends upon
+             * zero-length header removal compression being ignored. */
+            av_assert1(out_data != data);
+            buf = NULL;
+        }
 
         if (track->audio.buf) {
-            res = matroska_parse_rm_audio(matroska, track, st, data,
-                                          lace_size[n],
+            res = matroska_parse_rm_audio(matroska, track, st,
+                                          out_data, out_size,
                                           timecode, pos);
+            if (!buf)
+                av_free(out_data);
             if (res)
                 return res;
-
         } else if (st->codecpar->codec_id == AV_CODEC_ID_WEBVTT) {
             res = matroska_parse_webvtt(matroska, track, st,
-                                        data, lace_size[n],
+                                        out_data, out_size,
                                         timecode, lace_duration,
                                         pos);
+            if (!buf)
+                av_free(out_data);
             if (res)
                 return res;
         } else {
-            res = matroska_parse_frame(matroska, track, st, buf, data, lace_size[n],
-                                       timecode, lace_duration, pos,
-                                       !n ? is_keyframe : 0,
+            res = matroska_parse_frame(matroska, track, st, buf, out_data,
+                                       out_size, timecode, lace_duration,
+                                       pos, !n ? is_keyframe : 0,
                                        additional, additional_id, additional_size,
                                        discard_padding);
             if (res)