diff --git a/libavcodec/notchlc.c b/libavcodec/notchlc.c index 9e6534339f..f9e03fdded 100644 --- a/libavcodec/notchlc.c +++ b/libavcodec/notchlc.c @@ -51,7 +51,7 @@ typedef struct NotchLCContext { unsigned y_data_offset; unsigned uv_data_offset; unsigned y_data_size; - unsigned uv_count_size; + unsigned a_data_offset; unsigned uv_count_offset; unsigned a_count_size; unsigned data_end; @@ -62,7 +62,7 @@ typedef struct NotchLCContext { static av_cold int decode_init(AVCodecContext *avctx) { - avctx->pix_fmt = AV_PIX_FMT_YUV444P12; + avctx->pix_fmt = AV_PIX_FMT_YUVA444P12; avctx->color_range = AVCOL_RANGE_JPEG; avctx->colorspace = AVCOL_SPC_RGB; avctx->color_primaries = AVCOL_PRI_BT709; @@ -196,11 +196,11 @@ static int decode_blocks(AVCodecContext *avctx, AVFrame *p, ThreadFrame *frame, if (s->y_data_size >= UINT_MAX / 4) return AVERROR_INVALIDDATA; - s->uv_count_size = bytestream2_get_le32(gb); - if (s->uv_count_size >= UINT_MAX / 4) + s->a_data_offset = bytestream2_get_le32(gb); + if (s->a_data_offset >= UINT_MAX / 4) return AVERROR_INVALIDDATA; - s->uv_count_size *= 4; - if (s->uv_count_size >= uncompressed_size) + s->a_data_offset *= 4; + if (s->a_data_offset >= uncompressed_size) return AVERROR_INVALIDDATA; s->a_count_size = bytestream2_get_le32(gb); @@ -218,9 +218,9 @@ static int decode_blocks(AVCodecContext *avctx, AVFrame *p, ThreadFrame *frame, if (s->data_end <= s->y_data_size) return AVERROR_INVALIDDATA; s->y_data_offset = s->data_end - s->y_data_size; - if (s->y_data_offset <= s->uv_count_size) + if (s->y_data_offset <= s->a_data_offset) return AVERROR_INVALIDDATA; - s->uv_count_offset = s->y_data_offset - s->uv_count_size; + s->uv_count_offset = s->y_data_offset - s->a_data_offset; if ((ret = ff_thread_get_buffer(avctx, frame, 0)) < 0) return ret; @@ -266,13 +266,76 @@ static int decode_blocks(AVCodecContext *avctx, AVFrame *p, ThreadFrame *frame, } dsty += 4 * ylinesize; - dsta += 4 * alinesize; } rgb = *gb; dgb = *gb; - bytestream2_seek(&rgb, s->uv_offset_data_offset, SEEK_SET); bytestream2_seek(gb, s->a_control_word_offset, SEEK_SET); + if (s->uv_count_offset == s->a_control_word_offset) { + for (int y = 0; y < avctx->height; y++) { + for (int x = 0; x < avctx->width; x++) + dsta[x] = 4095; + dsta += alinesize; + } + } else { + for (int y = 0; y < avctx->height; y += 16) { + for (int x = 0; x < avctx->width; x += 16) { + unsigned m = bytestream2_get_le32(gb); + unsigned offset = bytestream2_get_le32(gb); + unsigned alpha0, alpha1; + uint64_t control; + + if (offset >= UINT_MAX / 4) + return AVERROR_INVALIDDATA; + offset = offset * 4 + s->uv_data_offset + s->a_data_offset; + if (offset >= s->data_end) + return AVERROR_INVALIDDATA; + + bytestream2_seek(&dgb, offset, SEEK_SET); + control = bytestream2_get_le64(&dgb); + alpha0 = control & 0xFF; + alpha1 = (control >> 8) & 0xFF; + control = control >> 16; + + for (int by = 0; by < 4; by++) { + for (int bx = 0; bx < 4; bx++) { + switch (m & 3) { + case 0: + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + dsta[x + (i + by * 4) * alinesize + bx * 4 + j] = 0; + } + } + break; + case 1: + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + dsta[x + (i + by * 4) * alinesize + bx * 4 + j] = 4095; + } + } + break; + case 2: + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + dsta[x + (i + by * 4) * alinesize + bx * 4 + j] = (alpha0 + (alpha1 - alpha0) * (control & 7)) << 4; + } + } + break; + default: + return AVERROR_INVALIDDATA; + } + + control >>= 3; + m >>= 2; + } + } + } + + dsta += 16 * alinesize; + } + } + + bytestream2_seek(&rgb, s->uv_offset_data_offset, SEEK_SET); dstu = (uint16_t *)p->data[1]; dstv = (uint16_t *)p->data[2];