X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmatroskadec.c;h=d78823215085ba43269494cdb688fbc4dac42449;hb=21f946840260da150affd9a20cc35b3d56194ba6;hp=b77e7e8265661735228f47ca104504641ecfae48;hpb=30833d121e24fc644c9c4e6ca07df3e9e4963180;p=ffmpeg diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index b77e7e82656..d7882321508 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -64,6 +64,8 @@ #include #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 { @@ -1703,6 +1708,33 @@ static void mkv_stereo_mode_display_mul(int stereo_mode, int *h_width, int *h_he } } +static int get_qt_codec(MatroskaTrack *track, uint32_t *fourcc, enum AVCodecID *codec_id) +{ + const AVCodecTag *codec_tags; + + codec_tags = track->type == MATROSKA_TRACK_TYPE_VIDEO ? + ff_codec_movvideo_tags : ff_codec_movaudio_tags; + + /* Normalize noncompliant private data that starts with the fourcc + * by expanding/shifting the data by 4 bytes and storing the data + * size at the start. */ + if (ff_codec_get_id(codec_tags, AV_RL32(track->codec_priv.data))) { + uint8_t *p = av_realloc(track->codec_priv.data, + track->codec_priv.size + 4); + if (!p) + return AVERROR(ENOMEM); + memmove(p + 4, p, track->codec_priv.size); + track->codec_priv.data = p; + track->codec_priv.size += 4; + AV_WB32(track->codec_priv.data, track->codec_priv.size); + } + + *fourcc = AV_RL32(track->codec_priv.data + 4); + *codec_id = ff_codec_get_id(codec_tags, *fourcc); + + return 0; +} + static int matroska_parse_tracks(AVFormatContext *s) { MatroskaDemuxContext *matroska = s->priv_data; @@ -1856,31 +1888,53 @@ 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) + /* Normally 36, but allow noncompliant private data */ + && (track->codec_priv.size >= 32) && (track->codec_priv.data)) { - fourcc = AV_RL32(track->codec_priv.data + 4); - codec_id = ff_codec_get_id(ff_codec_movaudio_tags, fourcc); - if (ff_codec_get_id(ff_codec_movaudio_tags, AV_RL32(track->codec_priv.data))) { - fourcc = AV_RL32(track->codec_priv.data); - codec_id = ff_codec_get_id(ff_codec_movaudio_tags, fourcc); + uint16_t sample_size; + int ret = get_qt_codec(track, &fourcc, &codec_id); + if (ret < 0) + return ret; + sample_size = AV_RB16(track->codec_priv.data + 26); + if (fourcc == 0) { + if (sample_size == 8) { + fourcc = MKTAG('r','a','w',' '); + codec_id = ff_codec_get_id(ff_codec_movaudio_tags, fourcc); + } else if (sample_size == 16) { + fourcc = MKTAG('t','w','o','s'); + codec_id = ff_codec_get_id(ff_codec_movaudio_tags, fourcc); + } } + if ((fourcc == MKTAG('t','w','o','s') || + fourcc == MKTAG('s','o','w','t')) && + sample_size == 8) + codec_id = AV_CODEC_ID_PCM_S8; } else if (!strcmp(track->codec_id, "V_QUICKTIME") && (track->codec_priv.size >= 21) && (track->codec_priv.data)) { - fourcc = AV_RL32(track->codec_priv.data + 4); - codec_id = ff_codec_get_id(ff_codec_movvideo_tags, fourcc); - if (ff_codec_get_id(ff_codec_movvideo_tags, AV_RL32(track->codec_priv.data))) { - fourcc = AV_RL32(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); } - if (codec_id == AV_CODEC_ID_NONE && AV_RL32(track->codec_priv.data+4) == AV_RL32("SMI ")) - codec_id = AV_CODEC_ID_SVQ3; if (codec_id == AV_CODEC_ID_NONE) { char buf[32]; av_get_codec_tag_string(buf, sizeof(buf), fourcc); 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; + matroska->has_palette = 1; + } + } } else if (codec_id == AV_CODEC_ID_PCM_S16BE) { switch (track->audio.bitdepth) { case 8: @@ -2063,7 +2117,7 @@ static int matroska_parse_tracks(AVFormatContext *s) if (track->type == MATROSKA_TRACK_TYPE_VIDEO) { MatroskaTrackPlane *planes = track->operation.combine_planes.elem; - int display_width_mul = 1; + int display_width_mul = 1; int display_height_mul = 1; st->codec->codec_type = AVMEDIA_TYPE_VIDEO; @@ -2078,7 +2132,7 @@ static int matroska_parse_tracks(AVFormatContext *s) av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den, - st->codec->height * track->video.display_width * display_width_mul, + st->codec->height * track->video.display_width * display_width_mul, st->codec->width * track->video.display_height * display_height_mul, 255); if (st->codec->codec_id != AV_CODEC_ID_HEVC) @@ -2326,6 +2380,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],