]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/matroskadec.c
avformat/matroskadec: Avoid allocating array for lace sizes
[ffmpeg] / libavformat / matroskadec.c
index 439ee462a535b61d2e33f0c667aad94c08dcbefc..2f289a90b33c88abae50c7d4c6fe87ba995889af 100644 (file)
@@ -110,6 +110,7 @@ typedef const struct EbmlSyntax {
 
 typedef struct EbmlList {
     int nb_elem;
+    unsigned int alloc_elem_size;
     void *elem;
 } EbmlList;
 
@@ -706,7 +707,7 @@ static EbmlSyntax matroska_segments[] = {
 };
 
 static EbmlSyntax matroska_blockmore[] = {
-    { MATROSKA_ID_BLOCKADDID,      EBML_UINT, 0, offsetof(MatroskaBlock,additional_id) },
+    { MATROSKA_ID_BLOCKADDID,      EBML_UINT, 0, offsetof(MatroskaBlock,additional_id), { .u = 1 } },
     { MATROSKA_ID_BLOCKADDITIONAL, EBML_BIN,  0, offsetof(MatroskaBlock,additional) },
     CHILD_OF(matroska_blockadditions)
 };
@@ -797,7 +798,7 @@ static int matroska_resync(MatroskaDemuxContext *matroska, int64_t last_pos)
             id == MATROSKA_ID_CLUSTER  || id == MATROSKA_ID_CHAPTERS) {
             /* Prepare the context for parsing of a level 1 element. */
             matroska_reset_status(matroska, id, -1);
-            /* Given that we are here means that an error has occured,
+            /* Given that we are here means that an error has occurred,
              * so treat the segment as unknown length in order not to
              * discard valid data that happens to be beyond the designated
              * end of the segment. */
@@ -1236,8 +1237,13 @@ static int ebml_parse(MatroskaDemuxContext *matroska,
         data = (char *) data + syntax->data_offset;
         if (syntax->list_elem_size) {
             EbmlList *list = data;
-            void *newelem = av_realloc_array(list->elem, list->nb_elem + 1,
-                                                   syntax->list_elem_size);
+            void *newelem;
+
+            if ((unsigned)list->nb_elem + 1 >= UINT_MAX / syntax->list_elem_size)
+                return AVERROR(ENOMEM);
+            newelem = av_fast_realloc(list->elem,
+                                      &list->alloc_elem_size,
+                                      (list->nb_elem + 1) * syntax->list_elem_size);
             if (!newelem)
                 return AVERROR(ENOMEM);
             list->elem = newelem;
@@ -1325,7 +1331,7 @@ static int ebml_parse(MatroskaDemuxContext *matroska,
             // current element (i.e. how much would be skipped); if there were
             // more than a few skipped elements in a row and skipping the current
             // element would lead us more than SKIP_THRESHOLD away from the last
-            // known good position, then it is inferred that an error occured.
+            // known good position, then it is inferred that an error occurred.
             // The dependency on the number of unknown elements in a row exists
             // because the distance to the last known good position is
             // automatically big if the last parsed element was big.
@@ -1490,6 +1496,7 @@ static void ebml_free(EbmlSyntax *syntax, void *data)
                     ebml_free(syntax[i].def.n, ptr);
                 av_freep(&list->elem);
                 list->nb_elem = 0;
+                list->alloc_elem_size = 0;
             } else
                 ebml_free(syntax[i].def.n, data_off);
         default:
@@ -2109,9 +2116,6 @@ static int mkv_parse_video_color(AVStream *st, const MatroskaTrack *track) {
     }
 
     if (has_mastering_primaries || has_mastering_luminance) {
-        // Use similar rationals as other standards.
-        const int chroma_den = 50000;
-        const int luma_den = 10000;
         AVMasteringDisplayMetadata *metadata =
             (AVMasteringDisplayMetadata*) av_stream_new_side_data(
                 st, AV_PKT_DATA_MASTERING_DISPLAY_METADATA,
@@ -2121,29 +2125,19 @@ static int mkv_parse_video_color(AVStream *st, const MatroskaTrack *track) {
         }
         memset(metadata, 0, sizeof(AVMasteringDisplayMetadata));
         if (has_mastering_primaries) {
-            metadata->display_primaries[0][0] = av_make_q(
-                round(mastering_meta->r_x * chroma_den), chroma_den);
-            metadata->display_primaries[0][1] = av_make_q(
-                round(mastering_meta->r_y * chroma_den), chroma_den);
-            metadata->display_primaries[1][0] = av_make_q(
-                round(mastering_meta->g_x * chroma_den), chroma_den);
-            metadata->display_primaries[1][1] = av_make_q(
-                round(mastering_meta->g_y * chroma_den), chroma_den);
-            metadata->display_primaries[2][0] = av_make_q(
-                round(mastering_meta->b_x * chroma_den), chroma_den);
-            metadata->display_primaries[2][1] = av_make_q(
-                round(mastering_meta->b_y * chroma_den), chroma_den);
-            metadata->white_point[0] = av_make_q(
-                round(mastering_meta->white_x * chroma_den), chroma_den);
-            metadata->white_point[1] = av_make_q(
-                round(mastering_meta->white_y * chroma_den), chroma_den);
+            metadata->display_primaries[0][0] = av_d2q(mastering_meta->r_x, INT_MAX);
+            metadata->display_primaries[0][1] = av_d2q(mastering_meta->r_y, INT_MAX);
+            metadata->display_primaries[1][0] = av_d2q(mastering_meta->g_x, INT_MAX);
+            metadata->display_primaries[1][1] = av_d2q(mastering_meta->g_y, INT_MAX);
+            metadata->display_primaries[2][0] = av_d2q(mastering_meta->b_x, INT_MAX);
+            metadata->display_primaries[2][1] = av_d2q(mastering_meta->b_y, INT_MAX);
+            metadata->white_point[0] = av_d2q(mastering_meta->white_x, INT_MAX);
+            metadata->white_point[1] = av_d2q(mastering_meta->white_y, INT_MAX);
             metadata->has_primaries = 1;
         }
         if (has_mastering_luminance) {
-            metadata->max_luminance = av_make_q(
-                round(mastering_meta->max_luminance * luma_den), luma_den);
-            metadata->min_luminance = av_make_q(
-                round(mastering_meta->min_luminance * luma_den), luma_den);
+            metadata->max_luminance = av_d2q(mastering_meta->max_luminance, INT_MAX);
+            metadata->min_luminance = av_d2q(mastering_meta->min_luminance, INT_MAX);
             metadata->has_luminance = 1;
         }
     }
@@ -2551,34 +2545,33 @@ static int matroska_parse_tracks(AVFormatContext *s)
             memcpy(&extradata[12], track->codec_priv.data,
                    track->codec_priv.size);
         } else if (codec_id == AV_CODEC_ID_TTA) {
-            extradata_size = 30;
-            extradata      = av_mallocz(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
-            if (!extradata)
-                return AVERROR(ENOMEM);
-            ffio_init_context(&b, extradata, extradata_size, 1,
-                              NULL, NULL, NULL, NULL);
-            avio_write(&b, "TTA1", 4);
-            avio_wl16(&b, 1);
+            uint8_t *ptr;
             if (track->audio.channels > UINT16_MAX ||
                 track->audio.bitdepth > UINT16_MAX) {
                 av_log(matroska->ctx, AV_LOG_WARNING,
                        "Too large audio channel number %"PRIu64
                        " or bitdepth %"PRIu64". Skipping track.\n",
                        track->audio.channels, track->audio.bitdepth);
-                av_freep(&extradata);
                 if (matroska->ctx->error_recognition & AV_EF_EXPLODE)
                     return AVERROR_INVALIDDATA;
                 else
                     continue;
             }
-            avio_wl16(&b, track->audio.channels);
-            avio_wl16(&b, track->audio.bitdepth);
             if (track->audio.out_samplerate < 0 || track->audio.out_samplerate > INT_MAX)
                 return AVERROR_INVALIDDATA;
-            avio_wl32(&b, track->audio.out_samplerate);
-            avio_wl32(&b, av_rescale((matroska->duration * matroska->time_scale),
-                                     track->audio.out_samplerate,
-                                     AV_TIME_BASE * 1000));
+            extradata_size = 22;
+            extradata      = av_mallocz(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
+            if (!extradata)
+                return AVERROR(ENOMEM);
+            ptr = extradata;
+            bytestream_put_be32(&ptr, AV_RB32("TTA1"));
+            bytestream_put_le16(&ptr, 1);
+            bytestream_put_le16(&ptr, track->audio.channels);
+            bytestream_put_le16(&ptr, track->audio.bitdepth);
+            bytestream_put_le32(&ptr, track->audio.out_samplerate);
+            bytestream_put_le32(&ptr, av_rescale(matroska->duration * matroska->time_scale,
+                                                 track->audio.out_samplerate,
+                                                 AV_TIME_BASE * 1000));
         } else if (codec_id == AV_CODEC_ID_RV10 ||
                    codec_id == AV_CODEC_ID_RV20 ||
                    codec_id == AV_CODEC_ID_RV30 ||
@@ -2997,19 +2990,14 @@ static void matroska_clear_queue(MatroskaDemuxContext *matroska)
 
 static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
                                 int *buf_size, int type,
-                                uint32_t **lace_buf, int *laces)
+                                uint32_t lace_size[256], int *laces)
 {
     int res = 0, n, size = *buf_size;
     uint8_t *data = *buf;
-    uint32_t *lace_size;
 
     if (!type) {
         *laces    = 1;
-        *lace_buf = av_malloc(sizeof(**lace_buf));
-        if (!*lace_buf)
-            return AVERROR(ENOMEM);
-
-        *lace_buf[0] = size;
+        lace_size[0] = size;
         return 0;
     }
 
@@ -3017,9 +3005,6 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
     *laces    = *data + 1;
     data     += 1;
     size     -= 1;
-    lace_size = av_malloc_array(*laces, sizeof(*lace_size));
-    if (!lace_size)
-        return AVERROR(ENOMEM);
 
     switch (type) {
     case 0x1: /* Xiph lacing */
@@ -3100,7 +3085,6 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
     }
 
     *buf      = data;
-    *lace_buf = lace_size;
     *buf_size = size;
 
     return res;
@@ -3273,15 +3257,16 @@ static int matroska_parse_prores(MatroskaTrack *track, uint8_t *src,
     int dstlen = *size;
 
     if (AV_RB32(&src[4]) != MKBETAG('i', 'c', 'p', 'f')) {
-        dst = av_malloc(dstlen + 8 + AV_INPUT_BUFFER_PADDING_SIZE);
+        dstlen += 8;
+
+        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);
-        memset(dst + 8 + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE);
-        dstlen += 8;
+        memcpy(dst + 8, src, dstlen - 8);
+        memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE);
     }
 
     *pdst = dst;
@@ -3537,7 +3522,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf
     int res = 0;
     AVStream *st;
     int16_t block_time;
-    uint32_t *lace_size = NULL;
+    uint32_t lace_size[256];
     int n, flags, laces = 0;
     uint64_t num;
     int trust_default_duration = 1;
@@ -3596,10 +3581,9 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf
     }
 
     res = matroska_parse_laces(matroska, &data, &size, (flags & 0x06) >> 1,
-                               &lace_size, &laces);
-
-    if (res)
-        goto end;
+                               lace_size, &laces);
+    if (res < 0)
+        return res;
 
     if (track->audio.samplerate == 8000) {
         // If this is needed for more codecs, then add them here
@@ -3633,7 +3617,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf
                                           lace_size[n],
                                           timecode, pos);
             if (res)
-                goto end;
+                return res;
 
         } else if (st->codecpar->codec_id == AV_CODEC_ID_WEBVTT) {
             res = matroska_parse_webvtt(matroska, track, st,
@@ -3641,7 +3625,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf
                                         timecode, lace_duration,
                                         pos);
             if (res)
-                goto end;
+                return res;
         } else {
             res = matroska_parse_frame(matroska, track, st, buf, data, lace_size[n],
                                        timecode, lace_duration, pos,
@@ -3649,7 +3633,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf
                                        additional, additional_id, additional_size,
                                        discard_padding);
             if (res)
-                goto end;
+                return res;
         }
 
         if (timecode != AV_NOPTS_VALUE)
@@ -3658,9 +3642,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf
         size -= lace_size[n];
     }
 
-end:
-    av_free(lace_size);
-    return res;
+    return 0;
 }
 
 static int matroska_parse_cluster(MatroskaDemuxContext *matroska)