From 9d639bea980bb7940bfeb527a60c847c14d13ee9 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 | 62 +++++++++++++++++++++++++++------------
 1 file changed, 44 insertions(+), 18 deletions(-)

diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 4e20f15792..9ca9efe6b1 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -2473,25 +2473,51 @@ 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;
+            codec_id = st->codecpar->codec_id;
+
+            av_log(matroska->ctx, AV_LOG_TRACE,
+                   "mov FourCC found %s.\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

