Here is another update of my patch for palettized QuickTime video in
Matroska.
Only read the first 86 - 16 (16 bytes are already read in
ff_mov_read_stsd_entries()) bytes into the 'stsd' variable in
mov_parse_stsd_video() in mov.c, since we are going to read the palette
from the file in ff_get_qtpalette() anyway. Remove the unnecessary
'size' parameter from mov_parse_stsd_video().
Original 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.
--
Mats Peterson
http://matsp888.no-ip.org/~mats/
>From f0b604a685547a038daac8f75450e6dc84c5787e Mon Sep 17 00:00:00 2001
From: Mats Peterson <matsp...@yahoo.com>
Date: Wed, 23 Dec 2015 11:19:06 +0100
Subject: [PATCH] libavformat: palettized QuickTime video in Matroska, round 4
---
libavformat/Makefile | 1 +
libavformat/matroskadec.c | 30 ++++++++++-
libavformat/mov.c | 92 ++++++++-------------------------
libavformat/qtpalette.c | 124 +++++++++++++++++++++++++++++++++++++++++++++
libavformat/qtpalette.h | 4 ++
5 files changed, 178 insertions(+), 73 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..28bc44f 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[256];
+ 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 (! (extradata = av_malloc(AVPALETTE_SIZE)))
+ return AVERROR(ENOMEM);
+ memcpy(extradata, matroska->palette, AVPALETTE_SIZE);
+ extradata_size = 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..d8b9ce8 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..90268e1
--- /dev/null
+++ b/libavformat/qtpalette.c
@@ -0,0 +1,124 @@
+/*
+ * 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 <inttypes.h>
+
+#include "libavcodec/avcodec.h"
+#include "libavformat/avio.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..8f875ae 100644
--- a/libavformat/qtpalette.h
+++ b/libavformat/qtpalette.h
@@ -24,6 +24,7 @@
#define AVFORMAT_QTPALETTE_H
#include <inttypes.h>
+#include "libavformat/avio.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