From f76de15ba175f8935556d46884b8840d4722ed10 Mon Sep 17 00:00:00 2001
From: Stanislav Ionascu <stanislav.ionascu@gmail.com>
Date: Sun, 11 Aug 2019 21:10:30 +0200
Subject: [PATCH] avformat/matroskadec: properly parse stsd in v_quicktime

Per matroska spec, v_quicktime contains the complete stsd atom, after
the mandatory size + fourcc. By properly parsing the hvcc sub-atoms of
the track, it becomes possible to demux/decode mp4/mov tracks stored as is
in matroska containers.

Also dvh1 in stsd in matroska is more likely hevc codec than dv.
QuickTime palette parsing is reused from the stsd parser results.
For non compliant input (when fourcc comes without the size), shift and
prepend the size to the private data.
Reading the SMI atom is reused from the stsd parser.

Signed-off-by: Stanislav Ionascu <stanislav.ionascu@gmail.com>
---
 libavformat/matroskadec.c | 59 ++++++++++++++++++++++++++++++---------
 1 file changed, 46 insertions(+), 13 deletions(-)

diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 1ea9b807e6..2a397c909a 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -2473,25 +2473,58 @@ static int matroska_parse_tracks(AVFormatContext *s)
         } else if (!strcmp(track->codec_id, "V_QUICKTIME") &&
                    (track->codec_priv.size >= 21)          &&
                    (track->codec_priv.data)) {
+            MOVStreamContext *msc;
+            MOVContext *mc = NULL;
+            void *priv_data;
+            int nb_streams;
             int ret = get_qt_codec(track, &fourcc, &codec_id);
             if (ret < 0)
                 return ret;
-            if (codec_id == AV_CODEC_ID_NONE && AV_RL32(track->codec_priv.data+4) == AV_RL32("SMI ")) {
-                fourcc = MKTAG('S','V','Q','3');
-                codec_id = ff_codec_get_id(ff_codec_movvideo_tags, fourcc);
+            mc = av_mallocz(sizeof(*mc));
+            if (!mc)
+                return AVERROR(ENOMEM);
+            priv_data = st->priv_data;
+            nb_streams = s->nb_streams;
+            mc->fc = s;
+            st->priv_data = msc = av_mallocz(sizeof(MOVStreamContext));
+            if (!msc) {
+                av_free(mc);
+                st->priv_data = priv_data;
+                return AVERROR(ENOMEM);
             }
+            ffio_init_context(&b, track->codec_priv.data,
+                              track->codec_priv.size,
+                              0, NULL, NULL, NULL, NULL);
+
+            /* ff_mov_read_stsd_entries updates stream s->nb_streams-1,
+             * so set it temporarily to indicate which stream to update. */
+            s->nb_streams = st->index + 1;
+            ff_mov_read_stsd_entries(mc, &b, 1);
+
+            /* copy palette from MOVStreamContext */
+            track->has_palette = msc->has_palette;
+            if (track->has_palette) {
+                /* leave bit_depth = -1, to reuse bits_per_coded_sample  */
+                memcpy(track->palette, msc->palette, AVPALETTE_COUNT);
+            }
+
+            av_free(msc);
+            av_free(mc);
+            st->priv_data = priv_data;
+            s->nb_streams = nb_streams;
+            fourcc = st->codecpar->codec_tag;
+            codec_id = st->codecpar->codec_id;
+
+            av_log(matroska->ctx, AV_LOG_TRACE,
+                   "mov FourCC found %s.\n", av_fourcc2str(fourcc));
+
             if (codec_id == AV_CODEC_ID_NONE)
                 av_log(matroska->ctx, AV_LOG_ERROR,
-                       "mov FourCC not found %s.\n", av_fourcc2str(fourcc));
-            if (track->codec_priv.size >= 86) {
-                bit_depth = AV_RB16(track->codec_priv.data + 82);
-                ffio_init_context(&b, track->codec_priv.data,
-                                  track->codec_priv.size,
-                                  0, NULL, NULL, NULL, NULL);
-                if (ff_get_qtpalette(codec_id, &b, track->palette)) {
-                    bit_depth &= 0x1F;
-                    track->has_palette = 1;
-                }
+                        "mov FourCC not found %s.\n", av_fourcc2str(fourcc));
+
+            // dvh1 in mkv is likely HEVC
+            if (fourcc == MKTAG('d','v','h','1')) {
+                codec_id = AV_CODEC_ID_HEVC;
             }
         } else if (codec_id == AV_CODEC_ID_PCM_S16BE) {
             switch (track->audio.bitdepth) {
-- 
2.20.1

