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