diff --git a/libavcodec/cdxl.c b/libavcodec/cdxl.c index 96ae14c418..056c3577ab 100644 --- a/libavcodec/cdxl.c +++ b/libavcodec/cdxl.c @@ -43,6 +43,7 @@ typedef struct CDXLVideoContext { AVCodecContext *avctx; int bpp; + int type; int format; int padded_bits; const uint8_t *palette; @@ -65,14 +66,19 @@ static av_cold int cdxl_decode_init(AVCodecContext *avctx) static void import_palette(CDXLVideoContext *c, uint32_t *new_palette) { - int i; - - for (i = 0; i < c->palette_size / 2; i++) { - unsigned rgb = AV_RB16(&c->palette[i * 2]); - unsigned r = ((rgb >> 8) & 0xF) * 0x11; - unsigned g = ((rgb >> 4) & 0xF) * 0x11; - unsigned b = (rgb & 0xF) * 0x11; - AV_WN32(&new_palette[i], (0xFFU << 24) | (r << 16) | (g << 8) | b); + if (c->type == 1) { + for (int i = 0; i < c->palette_size / 2; i++) { + unsigned rgb = AV_RB16(&c->palette[i * 2]); + unsigned r = ((rgb >> 8) & 0xF) * 0x11; + unsigned g = ((rgb >> 4) & 0xF) * 0x11; + unsigned b = (rgb & 0xF) * 0x11; + AV_WN32(&new_palette[i], (0xFFU << 24) | (r << 16) | (g << 8) | b); + } + } else { + for (int i = 0; i < c->palette_size / 3; i++) { + unsigned rgb = AV_RB24(&c->palette[i * 3]); + AV_WN32(&new_palette[i], (0xFFU << 24) | rgb); + } } } @@ -246,6 +252,7 @@ static int cdxl_decode_frame(AVCodecContext *avctx, void *data, if (buf_size < 32) return AVERROR_INVALIDDATA; + c->type = buf[0]; encoding = buf[1] & 7; c->format = buf[1] & 0xE0; w = AV_RB16(&buf[14]); @@ -256,7 +263,11 @@ static int cdxl_decode_frame(AVCodecContext *avctx, void *data, c->video = c->palette + c->palette_size; c->video_size = buf_size - c->palette_size - 32; - if (c->palette_size > 512) + if (c->type > 1) + return AVERROR_INVALIDDATA; + if (c->type == 1 && c->palette_size > 512) + return AVERROR_INVALIDDATA; + if (c->type == 0 && c->palette_size > 768) return AVERROR_INVALIDDATA; if (buf_size < c->palette_size + 32) return AVERROR_INVALIDDATA; diff --git a/libavformat/cdxl.c b/libavformat/cdxl.c index 5718fc3e21..0c7d021b8f 100644 --- a/libavformat/cdxl.c +++ b/libavformat/cdxl.c @@ -47,16 +47,18 @@ static int cdxl_read_probe(const AVProbeData *p) if (p->buf_size < CDXL_HEADER_SIZE) return 0; - /* reserved bytes should always be set to 0 */ - if (AV_RN64(&p->buf[24]) || AV_RN16(&p->buf[10])) + /* check type */ + if (p->buf[0] > 1) return 0; - /* check type */ - if (p->buf[0] != 1) + /* reserved bytes should always be set to 0 */ + if (p->buf[0] == 1 && (AV_RN64(&p->buf[24]) || AV_RN16(&p->buf[10]))) return 0; /* check palette size */ - if (AV_RB16(&p->buf[20]) > 512) + if (p->buf[0] == 1 && AV_RB16(&p->buf[20]) > 512) + return 0; + if (p->buf[0] == 0 && AV_RB16(&p->buf[20]) > 768) return 0; /* check number of planes */ @@ -111,7 +113,7 @@ static int cdxl_read_packet(AVFormatContext *s, AVPacket *pkt) uint32_t current_size, video_size, image_size; uint16_t audio_size, palette_size, width, height; int64_t pos; - int format, frames, ret; + int type, format, frames, ret; if (avio_feof(pb)) return AVERROR_EOF; @@ -120,17 +122,18 @@ static int cdxl_read_packet(AVFormatContext *s, AVPacket *pkt) if (!cdxl->read_chunk && avio_read(pb, cdxl->header, CDXL_HEADER_SIZE) != CDXL_HEADER_SIZE) return AVERROR_EOF; - if (cdxl->header[0] != 1) { - av_log(s, AV_LOG_ERROR, "non-standard cdxl file\n"); + if (cdxl->header[0] > 1) { + av_log(s, AV_LOG_ERROR, "unsupported cdxl file\n"); return AVERROR_INVALIDDATA; } + type = cdxl->header[0]; format = cdxl->header[1] & 0xE0; current_size = AV_RB32(&cdxl->header[2]); width = AV_RB16(&cdxl->header[14]); height = AV_RB16(&cdxl->header[16]); palette_size = AV_RB16(&cdxl->header[20]); - audio_size = AV_RB16(&cdxl->header[22]); + audio_size = AV_RB16(&cdxl->header[22]) * (1 + !!(cdxl->header[1] & 0x10)); if (cdxl->header[19] == 0 || FFALIGN(width, 16) * (uint64_t)height * cdxl->header[19] > INT_MAX) return AVERROR_INVALIDDATA; @@ -140,7 +143,8 @@ static int cdxl_read_packet(AVFormatContext *s, AVPacket *pkt) image_size = FFALIGN(width, 16) * height * cdxl->header[19] / 8; video_size = palette_size + image_size; - if (palette_size > 512) + if ((type == 1 && palette_size > 512) || + (type == 0 && palette_size > 768)) return AVERROR_INVALIDDATA; if (current_size < (uint64_t)audio_size + video_size + CDXL_HEADER_SIZE) return AVERROR_INVALIDDATA; @@ -153,7 +157,7 @@ static int cdxl_read_packet(AVFormatContext *s, AVPacket *pkt) st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; st->codecpar->codec_tag = 0; - st->codecpar->codec_id = AV_CODEC_ID_PCM_S8; + st->codecpar->codec_id = AV_CODEC_ID_PCM_S8_PLANAR; if (cdxl->header[1] & 0x10) { st->codecpar->channels = 2; st->codecpar->channel_layout = AV_CH_LAYOUT_STEREO; @@ -189,7 +193,7 @@ static int cdxl_read_packet(AVFormatContext *s, AVPacket *pkt) if (audio_size + video_size && cdxl->filesize > 0) { frames = cdxl->filesize / (audio_size + video_size); - if(cdxl->framerate) + if (cdxl->framerate) st->duration = frames; else st->duration = frames * (int64_t)audio_size; diff --git a/tests/ref/fate/cdxl-demux b/tests/ref/fate/cdxl-demux index f1334755aa..f919b67881 100644 --- a/tests/ref/fate/cdxl-demux +++ b/tests/ref/fate/cdxl-demux @@ -5,7 +5,7 @@ #sar 0: 0/1 #tb 1: 1/11025 #media_type 1: audio -#codec_id 1: pcm_s8 +#codec_id 1: pcm_s8_planar #sample_rate 1: 11025 #channel_layout 1: 4 #channel_layout_name 1: mono