Removed the 'stsd' variable from ff_get_qtpalette() in qtpalette.c.
Updated the doxy documentation for ff_get_qtpalette() accordingly.

Description of 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
use the correct palette. And why is that, 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.

Video samples for testing are available at
https://drive.google.com/open?id=0B3_pEBoLs0faWElmM2FnLTZYNlk.

--
Mats Peterson
http://matsp888.no-ip.org/~mats/
>From a15ec091ba494a5e5a8f710bdb97e869c9f702e7 Mon Sep 17 00:00:00 2001
From: Mats Peterson <matsp...@yahoo.com>
Date: Sun, 27 Dec 2015 21:28:09 +0100
Subject: [PATCH v9] lavf: palettized QuickTime video in Matroska

Removed the 'stsd' variable from ff_get_qtpalette() in qtpalette.c.
Updated the doxy documentation for ff_get_qtpalette() accordingly.

Original description of 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
use the correct palette. And why is that, 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.

Video samples for testing are available at
https://drive.google.com/open?id=0B3_pEBoLs0faWElmM2FnLTZYNlk.

---
 libavformat/Makefile      |    1 +
 libavformat/matroskadec.c |   32 +++++++++++-
 libavformat/mov.c         |   78 ++++-------------------------
 libavformat/qtpalette.c   |  121 +++++++++++++++++++++++++++++++++++++++++++++
 libavformat/qtpalette.h   |    5 +-
 5 files changed, 166 insertions(+), 71 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..9837a67 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,22 @@ 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);
+                ffio_init_context(&b, track->codec_priv.data,
+                                  track->codec_priv.size,
+                                  0, NULL, NULL, NULL, NULL);
+                if (ff_get_qtpalette(codec_id, &b, 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 +2347,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..eaabd41 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -1755,9 +1755,12 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb,
                                  AVStream *st, MOVStreamContext *sc)
 {
     uint8_t codec_name[32];
-    unsigned int color_depth, len, j;
-    int color_greyscale;
-    int color_table_id;
+    int64_t stsd_start;
+    unsigned int len;
+
+    /* The first 16 bytes of the video sample description are already
+     * read in ff_mov_read_stsd_entries() */
+    stsd_start = avio_tell(pb) - 16;
 
     avio_rb16(pb); /* version */
     avio_rb16(pb); /* revision level */
@@ -1795,74 +1798,11 @@ 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;
 
-    /* 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;
+    avio_seek(pb, stsd_start, SEEK_SET);
 
-            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, pb, sc->palette)) {
+        st->codec->bits_per_coded_sample &= 0x1F;
         sc->has_palette = 1;
     }
 }
diff --git a/libavformat/qtpalette.c b/libavformat/qtpalette.c
new file mode 100644
index 0000000..2901122
--- /dev/null
+++ b/libavformat/qtpalette.c
@@ -0,0 +1,121 @@
+/*
+ * 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"
+
+/**
+ * Retrieve the palette (or "color table" in QuickTime terms), either
+ * from the video sample description, or from the default Macintosh
+ * palette.
+ *
+ * The file offset of the AVIOContext pointed to by the 'pb' variable
+ * should be the start of the video sample description (the sample
+ * description size and the data format).
+ */
+int ff_get_qtpalette(int codec_id, AVIOContext *pb, uint32_t *palette)
+{
+    int tmp, bit_depth, color_table_id, greyscale, i;
+
+    avio_seek(pb, 82, SEEK_CUR);
+
+    /* Get the bit depth and greyscale state */
+    tmp = avio_rb16(pb);
+    bit_depth = tmp & 0x1F;
+    greyscale = tmp & 0x20;
+
+    /* Get the color table ID */
+    color_table_id = avio_rb16(pb);
+
+    /* 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_count, color_start, color_end;
+        uint32_t a, r, g, b;
+
+        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 */
+            color_start = avio_rb32(pb);
+            avio_rb16(pb); /* color table flags */
+            color_end = avio_rb16(pb);
+            if ((color_start <= 255) && (color_end <= 255)) {
+                for (i = color_start; i <= color_end; i++) {
+                    /* 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);
+                    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..54da2a1 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,6 @@ static const uint8_t ff_qt_default_palette_256[256 * 3] = {
   /* 255, 0xFF */  0x00, 0x00, 0x00
 };
 
+int ff_get_qtpalette(int codec_id, 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