From 18d1e18e3c72f70c2d9aaf2e8d9270a28b4895a2 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.

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

diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 4e20f15792..cac3b16f44 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -2473,25 +2473,50 @@ static int matroska_parse_tracks(AVFormatContext *s)
         } else if (!strcmp(track->codec_id, "V_QUICKTIME") &&
                    (track->codec_priv.size >= 21)          &&
                    (track->codec_priv.data)) {
-            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);
+            MOVStreamContext *msc;
+            MOVContext *mc = NULL;
+            void *priv_data;
+            int nb_streams;
+            priv_data = st->priv_data;
+            nb_streams = s->nb_streams;
+            mc = av_mallocz(sizeof(*mc));
+            if (!mc)
+                return AVERROR(ENOMEM);
+            mc->fc = s;
+            st->priv_data = msc = av_mallocz(sizeof(MOVStreamContext));
+            if (!msc) {
+                av_free(mc);
+                st->priv_data = priv_data;
+                return AVERROR(ENOMEM);
             }
-            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;
-                }
+            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;
+
+            av_log(matroska->ctx, AV_LOG_TRACE,
+                   "FourCC found %s in V_QUICKTIME.\n", av_fourcc2str(fourcc));
+
+            // dvh1 in mkv is likely HEVC
+            if (st->codecpar->codec_tag == 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

