I mistakenly used 'extradata' rather than 'st->codec->extradata', naturally leading to a segfault. Here's an updated patch.

An explanation of the patch follows:

Palettized QuickTime video in Matroska has hitherto not been recognized whatsoever, and the "palette" used has been completely random.

The patch for matroskadec.c fixes this issue by adding a palette side data packet in matroska_deliver_packet(), much in the same way as it's done in mov.c.

The change to mov.c consists mainly of moving the palette handling from the mov_parse_stsd_video() function to a new ff_get_qtpalette() function in the new file qtpalette.c, which is shared by both matroskadec.c and mov.c.

In matroskadec.c, I'm also putting the palette in 'extradata', like it's done for V_MS/VFW/FOURCC; this is a requirement in order for MPlayer to recognize the palette. And why is this, you may wonder. Well, it's because for some mysterious reason, MPlayer adds ANOTHER palette side data packet after the one added in matroskadec.c. It uses whatever is in extradata as the palette when adding this packet.

Mats

--
Mats Peterson
http://matsp888.no-ip.org/~mats/
>From 91376a9e4e0cb4a7522be565e248616c4803c0ad Mon Sep 17 00:00:00 2001
From: Mats Peterson <matsp...@yahoo.com>
Date: Wed, 23 Dec 2015 15:30:15 +0100
Subject: [PATCH v6] lavf: palettized QuickTime video in Matroska

---
 libavformat/Makefile      |    1 +
 libavformat/matroskadec.c |   30 ++++++++++-
 libavformat/mov.c         |   92 ++++++++-------------------------
 libavformat/qtpalette.c   |  123 +++++++++++++++++++++++++++++++++++++++++++++
 libavformat/qtpalette.h   |    6 ++-
 5 files changed, 178 insertions(+), 74 deletions(-)
 create mode 100644 libavformat/qtpalette.c

diff --git a/libavformat/Makefile b/libavformat/Makefile
index 110e9e3..e03c73e 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -18,6 +18,7 @@ OBJS = allformats.o         \
        mux.o                \
        options.o            \
        os_support.o         \
+       qtpalette.o          \
        riff.o               \
        sdp.o                \
        url.o                \
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index c574749..cc3cdd0 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -64,6 +64,8 @@
 #include <zlib.h>
 #endif
 
+#include "qtpalette.h"
+
 typedef enum {
     EBML_NONE,
     EBML_UINT,
@@ -312,6 +314,9 @@ typedef struct MatroskaDemuxContext {
 
     /* WebM DASH Manifest live flag/ */
     int is_live;
+
+    uint32_t palette[AVPALETTE_COUNT];
+    int has_palette;
 } MatroskaDemuxContext;
 
 typedef struct MatroskaBlock {
@@ -1856,7 +1861,7 @@ static int matroska_parse_tracks(AVFormatContext *s)
             fourcc           = st->codec->codec_tag;
             extradata_offset = FFMIN(track->codec_priv.size, 18);
         } else if (!strcmp(track->codec_id, "A_QUICKTIME")
-                   && (track->codec_priv.size >= 86)
+                   && (track->codec_priv.size >= 36)
                    && (track->codec_priv.data)) {
             fourcc = AV_RL32(track->codec_priv.data + 4);
             codec_id = ff_codec_get_id(ff_codec_movaudio_tags, fourcc);
@@ -1881,6 +1886,20 @@ static int matroska_parse_tracks(AVFormatContext *s)
                 av_log(matroska->ctx, AV_LOG_ERROR,
                        "mov FourCC not found %s.\n", buf);
             }
+            if (track->codec_priv.size >= 86) {
+                bit_depth = AV_RB16(track->codec_priv.data + 82);
+                if (ff_get_qtpalette(codec_id, track->codec_priv.data + 16,
+                        NULL, matroska->palette)) {
+                    bit_depth &= 0x1F;
+                    /* Behave like V_MS/VFW/FOURCC; copy the palette to
+                     * extradata */
+                    if (ff_alloc_extradata(st->codec, AVPALETTE_SIZE))
+                        return AVERROR(ENOMEM);
+                    memcpy(st->codec->extradata, matroska->palette,
+                            AVPALETTE_SIZE);
+                    matroska->has_palette = 1;
+                }
+            }
         } else if (codec_id == AV_CODEC_ID_PCM_S16BE) {
             switch (track->audio.bitdepth) {
             case  8:
@@ -2326,6 +2345,15 @@ static int matroska_deliver_packet(MatroskaDemuxContext *matroska,
     if (matroska->num_packets > 0) {
         memcpy(pkt, matroska->packets[0], sizeof(AVPacket));
         av_freep(&matroska->packets[0]);
+        if (matroska->has_palette) {
+            uint8_t *pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
+            if (!pal) {
+                av_log(matroska->ctx, AV_LOG_ERROR, "Cannot append palette to packet\n");
+            } else {
+                memcpy(pal, matroska->palette, AVPALETTE_SIZE);
+            }
+            matroska->has_palette = 0;
+        }
         if (matroska->num_packets > 1) {
             void *newpackets;
             memmove(&matroska->packets[0], &matroska->packets[1],
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 06e80c8..5b0c5af 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -1751,13 +1751,20 @@ static int mov_codec_id(AVStream *st, uint32_t format)
     return id;
 }
 
-static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb,
+static int mov_parse_stsd_video(MOVContext *c, AVIOContext *pb,
                                  AVStream *st, MOVStreamContext *sc)
 {
+    uint8_t *stsd;
     uint8_t codec_name[32];
-    unsigned int color_depth, len, j;
-    int color_greyscale;
-    int color_table_id;
+    int64_t pos;
+    unsigned int len;
+
+    if (!(stsd = av_malloc(70)))
+        return AVERROR(ENOMEM);
+
+    pos = avio_tell(pb);
+    avio_read(pb, stsd, 70);
+    avio_seek(pb, pos, SEEK_SET);
 
     avio_rb16(pb); /* version */
     avio_rb16(pb); /* revision level */
@@ -1795,76 +1802,15 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb,
         st->codec->codec_id = AV_CODEC_ID_FLV1;
 
     st->codec->bits_per_coded_sample = avio_rb16(pb); /* depth */
-    color_table_id = avio_rb16(pb); /* colortable id */
-    av_log(c->fc, AV_LOG_TRACE, "depth %d, ctab id %d\n",
-            st->codec->bits_per_coded_sample, color_table_id);
-    /* figure out the palette situation */
-    color_depth     = st->codec->bits_per_coded_sample & 0x1F;
-    color_greyscale = st->codec->bits_per_coded_sample & 0x20;
-    /* Do not create a greyscale palette for cinepak */
-    if (color_greyscale && st->codec->codec_id == AV_CODEC_ID_CINEPAK)
-        return;
+    avio_rb16(pb); /* colortable id */
 
-    /* if the depth is 2, 4, or 8 bpp, file is palettized */
-    if ((color_depth == 2) || (color_depth == 4) || (color_depth == 8)) {
-        /* for palette traversal */
-        unsigned int color_start, color_count, color_end;
-        unsigned int a, r, g, b;
-
-        if (color_greyscale) {
-            int color_index, color_dec;
-            /* compute the greyscale palette */
-            st->codec->bits_per_coded_sample = color_depth;
-            color_count = 1 << color_depth;
-            color_index = 255;
-            color_dec   = 256 / (color_count - 1);
-            for (j = 0; j < color_count; j++) {
-                r = g = b = color_index;
-                sc->palette[j] = (0xFFU << 24) | (r << 16) | (g << 8) | (b);
-                color_index -= color_dec;
-                if (color_index < 0)
-                    color_index = 0;
-            }
-        } else if (color_table_id) {
-            const uint8_t *color_table;
-            /* if flag bit 3 is set, use the default palette */
-            color_count = 1 << color_depth;
-            if (color_depth == 2)
-                color_table = ff_qt_default_palette_4;
-            else if (color_depth == 4)
-                color_table = ff_qt_default_palette_16;
-            else
-                color_table = ff_qt_default_palette_256;
-
-            for (j = 0; j < color_count; j++) {
-                r = color_table[j * 3 + 0];
-                g = color_table[j * 3 + 1];
-                b = color_table[j * 3 + 2];
-                sc->palette[j] = (0xFFU << 24) | (r << 16) | (g << 8) | (b);
-            }
-        } else {
-            /* load the palette from the file */
-            color_start = avio_rb32(pb);
-            color_count = avio_rb16(pb);
-            color_end   = avio_rb16(pb);
-            if ((color_start <= 255) && (color_end <= 255)) {
-                for (j = color_start; j <= color_end; j++) {
-                    /* each A, R, G, or B component is 16 bits;
-                        * only use the top 8 bits */
-                    a = avio_r8(pb);
-                    avio_r8(pb);
-                    r = avio_r8(pb);
-                    avio_r8(pb);
-                    g = avio_r8(pb);
-                    avio_r8(pb);
-                    b = avio_r8(pb);
-                    avio_r8(pb);
-                    sc->palette[j] = (a << 24 ) | (r << 16) | (g << 8) | (b);
-                }
-            }
-        }
+    if (ff_get_qtpalette(st->codec->codec_id, stsd, pb, sc->palette)) {
+        st->codec->bits_per_coded_sample &= 0x1F;
         sc->has_palette = 1;
     }
+
+    av_free(stsd);
+    return 0;
 }
 
 static void mov_parse_stsd_audio(MOVContext *c, AVIOContext *pb,
@@ -2242,7 +2188,9 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
 
         if (st->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
             st->codec->codec_id = id;
-            mov_parse_stsd_video(c, pb, st, sc);
+            ret = mov_parse_stsd_video(c, pb, st, sc);
+            if (ret < 0)
+                return ret;
         } else if (st->codec->codec_type==AVMEDIA_TYPE_AUDIO) {
             st->codec->codec_id = id;
             mov_parse_stsd_audio(c, pb, st, sc);
diff --git a/libavformat/qtpalette.c b/libavformat/qtpalette.c
new file mode 100644
index 0000000..3064ce0
--- /dev/null
+++ b/libavformat/qtpalette.c
@@ -0,0 +1,123 @@
+/*
+ * QuickTime palette handling
+ * Copyright (c) 2001 Fabrice Bellard
+ * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
+ * Copyright (c) 2015 Mats Peterson
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+
+#include "avformat.h"
+#include "libavutil/intreadwrite.h"
+#include "qtpalette.h"
+
+int ff_get_qtpalette(int codec_id, uint8_t *stsd, AVIOContext *pb,
+        uint32_t *palette)
+{
+    int tmp, bit_depth, greyscale, i;
+
+    /* Get the bit depth and greyscale state */
+    tmp = AV_RB16(stsd + 66);
+    bit_depth = tmp & 0x1F;
+    greyscale = tmp & 0x20;
+
+    /* Do not create a greyscale palette for Cinepak */
+    if (greyscale && codec_id == AV_CODEC_ID_CINEPAK)
+        return 0;
+
+    /* If the depth is 2, 4, or 8 bpp, file is palettized. */
+    if ((bit_depth == 2 || bit_depth == 4 || bit_depth == 8)) {
+        int color_table_id, color_count, color_start, color_end;
+        uint32_t a, r, g, b;
+
+        color_table_id = AV_RB16(stsd + 68);
+
+        if (greyscale) {
+            int color_index, color_dec;
+            /* compute the greyscale palette */
+            color_count = 1 << bit_depth;
+            color_index = 255;
+            color_dec   = 256 / (color_count - 1);
+            for (i = 0; i < color_count; i++) {
+                r = g = b = color_index;
+                palette[i] = (0xFFU << 24) | (r << 16) | (g << 8) | (b);
+                color_index -= color_dec;
+                if (color_index < 0)
+                    color_index = 0;
+            }
+        } else if (color_table_id) {
+            /* The color table ID is non-zero. Interpret this as
+             * being -1, which means use the default Macintosh
+             * color table */
+            const uint8_t *color_table;
+            color_count = 1 << bit_depth;
+            if (bit_depth == 2)
+                color_table = ff_qt_default_palette_4;
+            else if (bit_depth == 4)
+                color_table = ff_qt_default_palette_16;
+            else
+                color_table = ff_qt_default_palette_256;
+            for (i = 0; i < color_count; i++) {
+                r = color_table[i * 3 + 0];
+                g = color_table[i * 3 + 1];
+                b = color_table[i * 3 + 2];
+                palette[i] = (0xFFU << 24) | (r << 16) | (g << 8) | (b);
+            }
+        } else {
+            /* The color table ID is 0; the color table is in the sample
+             * description */
+            if (pb) {
+                color_start = avio_rb32(pb);
+                avio_rb16(pb); /* color table flags */
+                color_end = avio_rb16(pb);
+            } else {
+                color_start = AV_RB16(stsd + 70);
+                color_end = AV_RB16(stsd + 76);
+            }
+            if ((color_start <= 255) && (color_end <= 255)) {
+                uint8_t *p = stsd + 78;
+                for (i = color_start; i <= color_end; i++) {
+                    /* each A, R, G, or B component is 16 bits;
+                     * only use the top 8 bits */
+                    if (pb) {
+                        a = avio_r8(pb);
+                        avio_r8(pb);
+                        r = avio_r8(pb);
+                        avio_r8(pb);
+                        g = avio_r8(pb);
+                        avio_r8(pb);
+                        b = avio_r8(pb);
+                        avio_r8(pb);
+                    } else {
+                        a = *p++; p++;
+                        r = *p++; p++;
+                        g = *p++; p++;
+                        b = *p++; p++;
+                    }
+                    palette[i] = (a << 24 ) | (r << 16) | (g << 8) | (b);
+                }
+            }
+        }
+
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/libavformat/qtpalette.h b/libavformat/qtpalette.h
index 7d6802f..8d1a23b 100644
--- a/libavformat/qtpalette.h
+++ b/libavformat/qtpalette.h
@@ -23,7 +23,8 @@
 #ifndef AVFORMAT_QTPALETTE_H
 #define AVFORMAT_QTPALETTE_H
 
-#include <inttypes.h>
+#include <stdint.h>
+#include "avformat.h"
 
 static const uint8_t ff_qt_default_palette_4[4 * 3] = {
   0x93, 0x65, 0x5E,
@@ -310,4 +311,7 @@ static const uint8_t ff_qt_default_palette_256[256 * 3] = {
   /* 255, 0xFF */  0x00, 0x00, 0x00
 };
 
+int ff_get_qtpalette(int codec_id, uint8_t *stsd, AVIOContext *pb,
+        uint32_t *palette);
+
 #endif /* AVFORMAT_QTPALETTE_H */
-- 
1.7.10.4

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to