1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-23 12:43:46 +02:00
FFmpeg/libavcodec/proresdec2.c
Andreas Rheinhardt 20f9727018 avcodec/codec_internal: Add FFCodec, hide internal part of AVCodec
Up until now, codec.h contains both public and private parts
of AVCodec. This exposes the internals of AVCodec to users
and leads them into the temptation of actually using them
and forces us to forward-declare structures and types that
users can't use at all.

This commit changes this by adding a new structure FFCodec to
codec_internal.h that extends AVCodec, i.e. contains the public
AVCodec as first member; the private fields of AVCodec are moved
to this structure, leaving codec.h clean.

Reviewed-by: Anton Khirnov <anton@khirnov.net>
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2022-03-21 01:33:09 +01:00

894 lines
29 KiB
C

/*
* Copyright (c) 2010-2011 Maxim Poliakovski
* Copyright (c) 2010-2011 Elvis Presley
*
* 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
*/
/**
* @file
* Known FOURCCs: 'apch' (HQ), 'apcn' (SD), 'apcs' (LT), 'acpo' (Proxy), 'ap4h' (4444)
*/
//#define DEBUG
#define LONG_BITSTREAM_READER
#include "config_components.h"
#include "libavutil/internal.h"
#include "libavutil/mem_internal.h"
#include "avcodec.h"
#include "codec_internal.h"
#include "get_bits.h"
#include "hwconfig.h"
#include "idctdsp.h"
#include "internal.h"
#include "profiles.h"
#include "simple_idct.h"
#include "proresdec.h"
#include "proresdata.h"
#include "thread.h"
static void permute(uint8_t *dst, const uint8_t *src, const uint8_t permutation[64])
{
int i;
for (i = 0; i < 64; i++)
dst[i] = permutation[src[i]];
}
#define ALPHA_SHIFT_16_TO_10(alpha_val) (alpha_val >> 6)
#define ALPHA_SHIFT_8_TO_10(alpha_val) ((alpha_val << 2) | (alpha_val >> 6))
#define ALPHA_SHIFT_16_TO_12(alpha_val) (alpha_val >> 4)
#define ALPHA_SHIFT_8_TO_12(alpha_val) ((alpha_val << 4) | (alpha_val >> 4))
static void inline unpack_alpha(GetBitContext *gb, uint16_t *dst, int num_coeffs,
const int num_bits, const int decode_precision) {
const int mask = (1 << num_bits) - 1;
int i, idx, val, alpha_val;
idx = 0;
alpha_val = mask;
do {
do {
if (get_bits1(gb)) {
val = get_bits(gb, num_bits);
} else {
int sign;
val = get_bits(gb, num_bits == 16 ? 7 : 4);
sign = val & 1;
val = (val + 2) >> 1;
if (sign)
val = -val;
}
alpha_val = (alpha_val + val) & mask;
if (num_bits == 16) {
if (decode_precision == 10) {
dst[idx++] = ALPHA_SHIFT_16_TO_10(alpha_val);
} else { /* 12b */
dst[idx++] = ALPHA_SHIFT_16_TO_12(alpha_val);
}
} else {
if (decode_precision == 10) {
dst[idx++] = ALPHA_SHIFT_8_TO_10(alpha_val);
} else { /* 12b */
dst[idx++] = ALPHA_SHIFT_8_TO_12(alpha_val);
}
}
if (idx >= num_coeffs)
break;
} while (get_bits_left(gb)>0 && get_bits1(gb));
val = get_bits(gb, 4);
if (!val)
val = get_bits(gb, 11);
if (idx + val > num_coeffs)
val = num_coeffs - idx;
if (num_bits == 16) {
for (i = 0; i < val; i++) {
if (decode_precision == 10) {
dst[idx++] = ALPHA_SHIFT_16_TO_10(alpha_val);
} else { /* 12b */
dst[idx++] = ALPHA_SHIFT_16_TO_12(alpha_val);
}
}
} else {
for (i = 0; i < val; i++) {
if (decode_precision == 10) {
dst[idx++] = ALPHA_SHIFT_8_TO_10(alpha_val);
} else { /* 12b */
dst[idx++] = ALPHA_SHIFT_8_TO_12(alpha_val);
}
}
}
} while (idx < num_coeffs);
}
static void unpack_alpha_10(GetBitContext *gb, uint16_t *dst, int num_coeffs,
const int num_bits)
{
if (num_bits == 16) {
unpack_alpha(gb, dst, num_coeffs, 16, 10);
} else { /* 8 bits alpha */
unpack_alpha(gb, dst, num_coeffs, 8, 10);
}
}
static void unpack_alpha_12(GetBitContext *gb, uint16_t *dst, int num_coeffs,
const int num_bits)
{
if (num_bits == 16) {
unpack_alpha(gb, dst, num_coeffs, 16, 12);
} else { /* 8 bits alpha */
unpack_alpha(gb, dst, num_coeffs, 8, 12);
}
}
static av_cold int decode_init(AVCodecContext *avctx)
{
int ret = 0;
ProresContext *ctx = avctx->priv_data;
uint8_t idct_permutation[64];
avctx->bits_per_raw_sample = 10;
switch (avctx->codec_tag) {
case MKTAG('a','p','c','o'):
avctx->profile = FF_PROFILE_PRORES_PROXY;
break;
case MKTAG('a','p','c','s'):
avctx->profile = FF_PROFILE_PRORES_LT;
break;
case MKTAG('a','p','c','n'):
avctx->profile = FF_PROFILE_PRORES_STANDARD;
break;
case MKTAG('a','p','c','h'):
avctx->profile = FF_PROFILE_PRORES_HQ;
break;
case MKTAG('a','p','4','h'):
avctx->profile = FF_PROFILE_PRORES_4444;
avctx->bits_per_raw_sample = 12;
break;
case MKTAG('a','p','4','x'):
avctx->profile = FF_PROFILE_PRORES_XQ;
avctx->bits_per_raw_sample = 12;
break;
default:
avctx->profile = FF_PROFILE_UNKNOWN;
av_log(avctx, AV_LOG_WARNING, "Unknown prores profile %d\n", avctx->codec_tag);
}
if (avctx->bits_per_raw_sample == 10) {
av_log(avctx, AV_LOG_DEBUG, "Auto bitdepth precision. Use 10b decoding based on codec tag.\n");
} else { /* 12b */
av_log(avctx, AV_LOG_DEBUG, "Auto bitdepth precision. Use 12b decoding based on codec tag.\n");
}
ff_blockdsp_init(&ctx->bdsp, avctx);
ret = ff_proresdsp_init(&ctx->prodsp, avctx);
if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "Fail to init proresdsp for bits per raw sample %d\n", avctx->bits_per_raw_sample);
return ret;
}
ff_init_scantable_permutation(idct_permutation,
ctx->prodsp.idct_permutation_type);
permute(ctx->progressive_scan, ff_prores_progressive_scan, idct_permutation);
permute(ctx->interlaced_scan, ff_prores_interlaced_scan, idct_permutation);
ctx->pix_fmt = AV_PIX_FMT_NONE;
if (avctx->bits_per_raw_sample == 10){
ctx->unpack_alpha = unpack_alpha_10;
} else if (avctx->bits_per_raw_sample == 12){
ctx->unpack_alpha = unpack_alpha_12;
} else {
av_log(avctx, AV_LOG_ERROR, "Fail to set unpack_alpha for bits per raw sample %d\n", avctx->bits_per_raw_sample);
return AVERROR_BUG;
}
return ret;
}
static int decode_frame_header(ProresContext *ctx, const uint8_t *buf,
const int data_size, AVCodecContext *avctx)
{
int hdr_size, width, height, flags;
int version;
const uint8_t *ptr;
enum AVPixelFormat pix_fmt;
hdr_size = AV_RB16(buf);
ff_dlog(avctx, "header size %d\n", hdr_size);
if (hdr_size > data_size) {
av_log(avctx, AV_LOG_ERROR, "error, wrong header size\n");
return AVERROR_INVALIDDATA;
}
version = AV_RB16(buf + 2);
ff_dlog(avctx, "%.4s version %d\n", buf+4, version);
if (version > 1) {
av_log(avctx, AV_LOG_ERROR, "unsupported version: %d\n", version);
return AVERROR_PATCHWELCOME;
}
width = AV_RB16(buf + 8);
height = AV_RB16(buf + 10);
if (width != avctx->width || height != avctx->height) {
int ret;
av_log(avctx, AV_LOG_WARNING, "picture resolution change: %dx%d -> %dx%d\n",
avctx->width, avctx->height, width, height);
if ((ret = ff_set_dimensions(avctx, width, height)) < 0)
return ret;
}
ctx->frame_type = (buf[12] >> 2) & 3;
ctx->alpha_info = buf[17] & 0xf;
if (ctx->alpha_info > 2) {
av_log(avctx, AV_LOG_ERROR, "Invalid alpha mode %d\n", ctx->alpha_info);
return AVERROR_INVALIDDATA;
}
if (avctx->skip_alpha) ctx->alpha_info = 0;
ff_dlog(avctx, "frame type %d\n", ctx->frame_type);
if (ctx->frame_type == 0) {
ctx->scan = ctx->progressive_scan; // permuted
} else {
ctx->scan = ctx->interlaced_scan; // permuted
ctx->frame->interlaced_frame = 1;
ctx->frame->top_field_first = ctx->frame_type == 1;
}
if (ctx->alpha_info) {
if (avctx->bits_per_raw_sample == 10) {
pix_fmt = (buf[12] & 0xC0) == 0xC0 ? AV_PIX_FMT_YUVA444P10 : AV_PIX_FMT_YUVA422P10;
} else { /* 12b */
pix_fmt = (buf[12] & 0xC0) == 0xC0 ? AV_PIX_FMT_YUVA444P12 : AV_PIX_FMT_YUVA422P12;
}
} else {
if (avctx->bits_per_raw_sample == 10) {
pix_fmt = (buf[12] & 0xC0) == 0xC0 ? AV_PIX_FMT_YUV444P10 : AV_PIX_FMT_YUV422P10;
} else { /* 12b */
pix_fmt = (buf[12] & 0xC0) == 0xC0 ? AV_PIX_FMT_YUV444P12 : AV_PIX_FMT_YUV422P12;
}
}
if (pix_fmt != ctx->pix_fmt) {
#define HWACCEL_MAX (CONFIG_PRORES_VIDEOTOOLBOX_HWACCEL)
enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmtp = pix_fmts;
int ret;
ctx->pix_fmt = pix_fmt;
#if CONFIG_PRORES_VIDEOTOOLBOX_HWACCEL
*fmtp++ = AV_PIX_FMT_VIDEOTOOLBOX;
#endif
*fmtp++ = ctx->pix_fmt;
*fmtp = AV_PIX_FMT_NONE;
if ((ret = ff_thread_get_format(avctx, pix_fmts)) < 0)
return ret;
avctx->pix_fmt = ret;
}
avctx->color_primaries = buf[14];
avctx->color_trc = buf[15];
avctx->colorspace = buf[16];
avctx->color_range = AVCOL_RANGE_MPEG;
ptr = buf + 20;
flags = buf[19];
ff_dlog(avctx, "flags %x\n", flags);
if (flags & 2) {
if(buf + data_size - ptr < 64) {
av_log(avctx, AV_LOG_ERROR, "Header truncated\n");
return AVERROR_INVALIDDATA;
}
permute(ctx->qmat_luma, ctx->prodsp.idct_permutation, ptr);
ptr += 64;
} else {
memset(ctx->qmat_luma, 4, 64);
}
if (flags & 1) {
if(buf + data_size - ptr < 64) {
av_log(avctx, AV_LOG_ERROR, "Header truncated\n");
return AVERROR_INVALIDDATA;
}
permute(ctx->qmat_chroma, ctx->prodsp.idct_permutation, ptr);
} else {
memcpy(ctx->qmat_chroma, ctx->qmat_luma, 64);
}
return hdr_size;
}
static int decode_picture_header(AVCodecContext *avctx, const uint8_t *buf, const int buf_size)
{
ProresContext *ctx = avctx->priv_data;
int i, hdr_size, slice_count;
unsigned pic_data_size;
int log2_slice_mb_width, log2_slice_mb_height;
int slice_mb_count, mb_x, mb_y;
const uint8_t *data_ptr, *index_ptr;
hdr_size = buf[0] >> 3;
if (hdr_size < 8 || hdr_size > buf_size) {
av_log(avctx, AV_LOG_ERROR, "error, wrong picture header size\n");
return AVERROR_INVALIDDATA;
}
pic_data_size = AV_RB32(buf + 1);
if (pic_data_size > buf_size) {
av_log(avctx, AV_LOG_ERROR, "error, wrong picture data size\n");
return AVERROR_INVALIDDATA;
}
log2_slice_mb_width = buf[7] >> 4;
log2_slice_mb_height = buf[7] & 0xF;
if (log2_slice_mb_width > 3 || log2_slice_mb_height) {
av_log(avctx, AV_LOG_ERROR, "unsupported slice resolution: %dx%d\n",
1 << log2_slice_mb_width, 1 << log2_slice_mb_height);
return AVERROR_INVALIDDATA;
}
ctx->mb_width = (avctx->width + 15) >> 4;
if (ctx->frame_type)
ctx->mb_height = (avctx->height + 31) >> 5;
else
ctx->mb_height = (avctx->height + 15) >> 4;
// QT ignores the written value
// slice_count = AV_RB16(buf + 5);
slice_count = ctx->mb_height * ((ctx->mb_width >> log2_slice_mb_width) +
av_popcount(ctx->mb_width & (1 << log2_slice_mb_width) - 1));
if (ctx->slice_count != slice_count || !ctx->slices) {
av_freep(&ctx->slices);
ctx->slice_count = 0;
ctx->slices = av_calloc(slice_count, sizeof(*ctx->slices));
if (!ctx->slices)
return AVERROR(ENOMEM);
ctx->slice_count = slice_count;
}
if (!slice_count)
return AVERROR(EINVAL);
if (hdr_size + slice_count*2 > buf_size) {
av_log(avctx, AV_LOG_ERROR, "error, wrong slice count\n");
return AVERROR_INVALIDDATA;
}
// parse slice information
index_ptr = buf + hdr_size;
data_ptr = index_ptr + slice_count*2;
slice_mb_count = 1 << log2_slice_mb_width;
mb_x = 0;
mb_y = 0;
for (i = 0; i < slice_count; i++) {
SliceContext *slice = &ctx->slices[i];
slice->data = data_ptr;
data_ptr += AV_RB16(index_ptr + i*2);
while (ctx->mb_width - mb_x < slice_mb_count)
slice_mb_count >>= 1;
slice->mb_x = mb_x;
slice->mb_y = mb_y;
slice->mb_count = slice_mb_count;
slice->data_size = data_ptr - slice->data;
if (slice->data_size < 6) {
av_log(avctx, AV_LOG_ERROR, "error, wrong slice data size\n");
return AVERROR_INVALIDDATA;
}
mb_x += slice_mb_count;
if (mb_x == ctx->mb_width) {
slice_mb_count = 1 << log2_slice_mb_width;
mb_x = 0;
mb_y++;
}
if (data_ptr > buf + buf_size) {
av_log(avctx, AV_LOG_ERROR, "error, slice out of bounds\n");
return AVERROR_INVALIDDATA;
}
}
if (mb_x || mb_y != ctx->mb_height) {
av_log(avctx, AV_LOG_ERROR, "error wrong mb count y %d h %d\n",
mb_y, ctx->mb_height);
return AVERROR_INVALIDDATA;
}
return pic_data_size;
}
#define DECODE_CODEWORD(val, codebook, SKIP) \
do { \
unsigned int rice_order, exp_order, switch_bits; \
unsigned int q, buf, bits; \
\
UPDATE_CACHE(re, gb); \
buf = GET_CACHE(re, gb); \
\
/* number of bits to switch between rice and exp golomb */ \
switch_bits = codebook & 3; \
rice_order = codebook >> 5; \
exp_order = (codebook >> 2) & 7; \
\
q = 31 - av_log2(buf); \
\
if (q > switch_bits) { /* exp golomb */ \
bits = exp_order - switch_bits + (q<<1); \
if (bits > FFMIN(MIN_CACHE_BITS, 31)) \
return AVERROR_INVALIDDATA; \
val = SHOW_UBITS(re, gb, bits) - (1 << exp_order) + \
((switch_bits + 1) << rice_order); \
SKIP(re, gb, bits); \
} else if (rice_order) { \
SKIP_BITS(re, gb, q+1); \
val = (q << rice_order) + SHOW_UBITS(re, gb, rice_order); \
SKIP(re, gb, rice_order); \
} else { \
val = q; \
SKIP(re, gb, q+1); \
} \
} while (0)
#define TOSIGNED(x) (((x) >> 1) ^ (-((x) & 1)))
#define FIRST_DC_CB 0xB8
static const uint8_t dc_codebook[7] = { 0x04, 0x28, 0x28, 0x4D, 0x4D, 0x70, 0x70};
static av_always_inline int decode_dc_coeffs(GetBitContext *gb, int16_t *out,
int blocks_per_slice)
{
int16_t prev_dc;
int code, i, sign;
OPEN_READER(re, gb);
DECODE_CODEWORD(code, FIRST_DC_CB, LAST_SKIP_BITS);
prev_dc = TOSIGNED(code);
out[0] = prev_dc;
out += 64; // dc coeff for the next block
code = 5;
sign = 0;
for (i = 1; i < blocks_per_slice; i++, out += 64) {
DECODE_CODEWORD(code, dc_codebook[FFMIN(code, 6U)], LAST_SKIP_BITS);
if(code) sign ^= -(code & 1);
else sign = 0;
prev_dc += (((code + 1) >> 1) ^ sign) - sign;
out[0] = prev_dc;
}
CLOSE_READER(re, gb);
return 0;
}
// adaptive codebook switching lut according to previous run/level values
static const uint8_t run_to_cb[16] = { 0x06, 0x06, 0x05, 0x05, 0x04, 0x29, 0x29, 0x29, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x4C };
static const uint8_t lev_to_cb[10] = { 0x04, 0x0A, 0x05, 0x06, 0x04, 0x28, 0x28, 0x28, 0x28, 0x4C };
static av_always_inline int decode_ac_coeffs(AVCodecContext *avctx, GetBitContext *gb,
int16_t *out, int blocks_per_slice)
{
ProresContext *ctx = avctx->priv_data;
int block_mask, sign;
unsigned pos, run, level;
int max_coeffs, i, bits_left;
int log2_block_count = av_log2(blocks_per_slice);
OPEN_READER(re, gb);
UPDATE_CACHE(re, gb); \
run = 4;
level = 2;
max_coeffs = 64 << log2_block_count;
block_mask = blocks_per_slice - 1;
for (pos = block_mask;;) {
bits_left = gb->size_in_bits - re_index;
if (!bits_left || (bits_left < 32 && !SHOW_UBITS(re, gb, bits_left)))
break;
DECODE_CODEWORD(run, run_to_cb[FFMIN(run, 15)], LAST_SKIP_BITS);
pos += run + 1;
if (pos >= max_coeffs) {
av_log(avctx, AV_LOG_ERROR, "ac tex damaged %d, %d\n", pos, max_coeffs);
return AVERROR_INVALIDDATA;
}
DECODE_CODEWORD(level, lev_to_cb[FFMIN(level, 9)], SKIP_BITS);
level += 1;
i = pos >> log2_block_count;
sign = SHOW_SBITS(re, gb, 1);
SKIP_BITS(re, gb, 1);
out[((pos & block_mask) << 6) + ctx->scan[i]] = ((level ^ sign) - sign);
}
CLOSE_READER(re, gb);
return 0;
}
static int decode_slice_luma(AVCodecContext *avctx, SliceContext *slice,
uint16_t *dst, int dst_stride,
const uint8_t *buf, unsigned buf_size,
const int16_t *qmat)
{
ProresContext *ctx = avctx->priv_data;
LOCAL_ALIGNED_32(int16_t, blocks, [8*4*64]);
int16_t *block;
GetBitContext gb;
int i, blocks_per_slice = slice->mb_count<<2;
int ret;
for (i = 0; i < blocks_per_slice; i++)
ctx->bdsp.clear_block(blocks+(i<<6));
init_get_bits(&gb, buf, buf_size << 3);
if ((ret = decode_dc_coeffs(&gb, blocks, blocks_per_slice)) < 0)
return ret;
if ((ret = decode_ac_coeffs(avctx, &gb, blocks, blocks_per_slice)) < 0)
return ret;
block = blocks;
for (i = 0; i < slice->mb_count; i++) {
ctx->prodsp.idct_put(dst, dst_stride, block+(0<<6), qmat);
ctx->prodsp.idct_put(dst +8, dst_stride, block+(1<<6), qmat);
ctx->prodsp.idct_put(dst+4*dst_stride , dst_stride, block+(2<<6), qmat);
ctx->prodsp.idct_put(dst+4*dst_stride+8, dst_stride, block+(3<<6), qmat);
block += 4*64;
dst += 16;
}
return 0;
}
static int decode_slice_chroma(AVCodecContext *avctx, SliceContext *slice,
uint16_t *dst, int dst_stride,
const uint8_t *buf, unsigned buf_size,
const int16_t *qmat, int log2_blocks_per_mb)
{
ProresContext *ctx = avctx->priv_data;
LOCAL_ALIGNED_32(int16_t, blocks, [8*4*64]);
int16_t *block;
GetBitContext gb;
int i, j, blocks_per_slice = slice->mb_count << log2_blocks_per_mb;
int ret;
for (i = 0; i < blocks_per_slice; i++)
ctx->bdsp.clear_block(blocks+(i<<6));
init_get_bits(&gb, buf, buf_size << 3);
if ((ret = decode_dc_coeffs(&gb, blocks, blocks_per_slice)) < 0)
return ret;
if ((ret = decode_ac_coeffs(avctx, &gb, blocks, blocks_per_slice)) < 0)
return ret;
block = blocks;
for (i = 0; i < slice->mb_count; i++) {
for (j = 0; j < log2_blocks_per_mb; j++) {
ctx->prodsp.idct_put(dst, dst_stride, block+(0<<6), qmat);
ctx->prodsp.idct_put(dst+4*dst_stride, dst_stride, block+(1<<6), qmat);
block += 2*64;
dst += 8;
}
}
return 0;
}
/**
* Decode alpha slice plane.
*/
static void decode_slice_alpha(ProresContext *ctx,
uint16_t *dst, int dst_stride,
const uint8_t *buf, int buf_size,
int blocks_per_slice)
{
GetBitContext gb;
int i;
LOCAL_ALIGNED_32(int16_t, blocks, [8*4*64]);
int16_t *block;
for (i = 0; i < blocks_per_slice<<2; i++)
ctx->bdsp.clear_block(blocks+(i<<6));
init_get_bits(&gb, buf, buf_size << 3);
if (ctx->alpha_info == 2) {
ctx->unpack_alpha(&gb, blocks, blocks_per_slice * 4 * 64, 16);
} else {
ctx->unpack_alpha(&gb, blocks, blocks_per_slice * 4 * 64, 8);
}
block = blocks;
for (i = 0; i < 16; i++) {
memcpy(dst, block, 16 * blocks_per_slice * sizeof(*dst));
dst += dst_stride >> 1;
block += 16 * blocks_per_slice;
}
}
static int decode_slice_thread(AVCodecContext *avctx, void *arg, int jobnr, int threadnr)
{
ProresContext *ctx = avctx->priv_data;
SliceContext *slice = &ctx->slices[jobnr];
const uint8_t *buf = slice->data;
AVFrame *pic = ctx->frame;
int i, hdr_size, qscale, log2_chroma_blocks_per_mb;
int luma_stride, chroma_stride;
int y_data_size, u_data_size, v_data_size, a_data_size, offset;
uint8_t *dest_y, *dest_u, *dest_v;
LOCAL_ALIGNED_16(int16_t, qmat_luma_scaled, [64]);
LOCAL_ALIGNED_16(int16_t, qmat_chroma_scaled,[64]);
int mb_x_shift;
int ret;
uint16_t val_no_chroma;
slice->ret = -1;
//av_log(avctx, AV_LOG_INFO, "slice %d mb width %d mb x %d y %d\n",
// jobnr, slice->mb_count, slice->mb_x, slice->mb_y);
// slice header
hdr_size = buf[0] >> 3;
qscale = av_clip(buf[1], 1, 224);
qscale = qscale > 128 ? qscale - 96 << 2: qscale;
y_data_size = AV_RB16(buf + 2);
u_data_size = AV_RB16(buf + 4);
v_data_size = slice->data_size - y_data_size - u_data_size - hdr_size;
if (hdr_size > 7) v_data_size = AV_RB16(buf + 6);
a_data_size = slice->data_size - y_data_size - u_data_size -
v_data_size - hdr_size;
if (y_data_size < 0 || u_data_size < 0 || v_data_size < 0
|| hdr_size+y_data_size+u_data_size+v_data_size > slice->data_size){
av_log(avctx, AV_LOG_ERROR, "invalid plane data size\n");
return AVERROR_INVALIDDATA;
}
buf += hdr_size;
for (i = 0; i < 64; i++) {
qmat_luma_scaled [i] = ctx->qmat_luma [i] * qscale;
qmat_chroma_scaled[i] = ctx->qmat_chroma[i] * qscale;
}
if (ctx->frame_type == 0) {
luma_stride = pic->linesize[0];
chroma_stride = pic->linesize[1];
} else {
luma_stride = pic->linesize[0] << 1;
chroma_stride = pic->linesize[1] << 1;
}
if (avctx->pix_fmt == AV_PIX_FMT_YUV444P10 || avctx->pix_fmt == AV_PIX_FMT_YUVA444P10 ||
avctx->pix_fmt == AV_PIX_FMT_YUV444P12 || avctx->pix_fmt == AV_PIX_FMT_YUVA444P12) {
mb_x_shift = 5;
log2_chroma_blocks_per_mb = 2;
} else {
mb_x_shift = 4;
log2_chroma_blocks_per_mb = 1;
}
offset = (slice->mb_y << 4) * luma_stride + (slice->mb_x << 5);
dest_y = pic->data[0] + offset;
dest_u = pic->data[1] + (slice->mb_y << 4) * chroma_stride + (slice->mb_x << mb_x_shift);
dest_v = pic->data[2] + (slice->mb_y << 4) * chroma_stride + (slice->mb_x << mb_x_shift);
if (ctx->frame_type && ctx->first_field ^ ctx->frame->top_field_first) {
dest_y += pic->linesize[0];
dest_u += pic->linesize[1];
dest_v += pic->linesize[2];
offset += pic->linesize[3];
}
ret = decode_slice_luma(avctx, slice, (uint16_t*)dest_y, luma_stride,
buf, y_data_size, qmat_luma_scaled);
if (ret < 0)
return ret;
if (!(avctx->flags & AV_CODEC_FLAG_GRAY) && (u_data_size + v_data_size) > 0) {
ret = decode_slice_chroma(avctx, slice, (uint16_t*)dest_u, chroma_stride,
buf + y_data_size, u_data_size,
qmat_chroma_scaled, log2_chroma_blocks_per_mb);
if (ret < 0)
return ret;
ret = decode_slice_chroma(avctx, slice, (uint16_t*)dest_v, chroma_stride,
buf + y_data_size + u_data_size, v_data_size,
qmat_chroma_scaled, log2_chroma_blocks_per_mb);
if (ret < 0)
return ret;
}
else {
size_t mb_max_x = slice->mb_count << (mb_x_shift - 1);
size_t i, j;
if (avctx->bits_per_raw_sample == 10) {
val_no_chroma = 511;
} else { /* 12b */
val_no_chroma = 511 * 4;
}
for (i = 0; i < 16; ++i)
for (j = 0; j < mb_max_x; ++j) {
*(uint16_t*)(dest_u + (i * chroma_stride) + (j << 1)) = val_no_chroma;
*(uint16_t*)(dest_v + (i * chroma_stride) + (j << 1)) = val_no_chroma;
}
}
/* decode alpha plane if available */
if (ctx->alpha_info && pic->data[3] && a_data_size) {
uint8_t *dest_a = pic->data[3] + offset;
decode_slice_alpha(ctx, (uint16_t*)dest_a, luma_stride,
buf + y_data_size + u_data_size + v_data_size,
a_data_size, slice->mb_count);
}
slice->ret = 0;
return 0;
}
static int decode_picture(AVCodecContext *avctx)
{
ProresContext *ctx = avctx->priv_data;
int i;
int error = 0;
avctx->execute2(avctx, decode_slice_thread, NULL, NULL, ctx->slice_count);
for (i = 0; i < ctx->slice_count; i++)
error += ctx->slices[i].ret < 0;
if (error)
ctx->frame->decode_error_flags = FF_DECODE_ERROR_INVALID_BITSTREAM;
if (error < ctx->slice_count)
return 0;
return ctx->slices[0].ret;
}
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVPacket *avpkt)
{
ProresContext *ctx = avctx->priv_data;
AVFrame *frame = data;
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
int frame_hdr_size, pic_size, ret;
if (buf_size < 28 || AV_RL32(buf + 4) != AV_RL32("icpf")) {
av_log(avctx, AV_LOG_ERROR, "invalid frame header\n");
return AVERROR_INVALIDDATA;
}
ctx->frame = frame;
ctx->frame->pict_type = AV_PICTURE_TYPE_I;
ctx->frame->key_frame = 1;
ctx->first_field = 1;
buf += 8;
buf_size -= 8;
frame_hdr_size = decode_frame_header(ctx, buf, buf_size, avctx);
if (frame_hdr_size < 0)
return frame_hdr_size;
buf += frame_hdr_size;
buf_size -= frame_hdr_size;
if ((ret = ff_thread_get_buffer(avctx, frame, 0)) < 0)
return ret;
ff_thread_finish_setup(avctx);
if (avctx->hwaccel) {
ret = avctx->hwaccel->start_frame(avctx, NULL, 0);
if (ret < 0)
return ret;
ret = avctx->hwaccel->decode_slice(avctx, avpkt->data, avpkt->size);
if (ret < 0)
return ret;
ret = avctx->hwaccel->end_frame(avctx);
if (ret < 0)
return ret;
goto finish;
}
decode_picture:
pic_size = decode_picture_header(avctx, buf, buf_size);
if (pic_size < 0) {
av_log(avctx, AV_LOG_ERROR, "error decoding picture header\n");
return pic_size;
}
if ((ret = decode_picture(avctx)) < 0) {
av_log(avctx, AV_LOG_ERROR, "error decoding picture\n");
return ret;
}
buf += pic_size;
buf_size -= pic_size;
if (ctx->frame_type && buf_size > 0 && ctx->first_field) {
ctx->first_field = 0;
goto decode_picture;
}
finish:
*got_frame = 1;
return avpkt->size;
}
static av_cold int decode_close(AVCodecContext *avctx)
{
ProresContext *ctx = avctx->priv_data;
av_freep(&ctx->slices);
return 0;
}
#if HAVE_THREADS
static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
{
ProresContext *csrc = src->priv_data;
ProresContext *cdst = dst->priv_data;
cdst->pix_fmt = csrc->pix_fmt;
return 0;
}
#endif
const FFCodec ff_prores_decoder = {
.p.name = "prores",
.p.long_name = NULL_IF_CONFIG_SMALL("Apple ProRes (iCodec Pro)"),
.p.type = AVMEDIA_TYPE_VIDEO,
.p.id = AV_CODEC_ID_PRORES,
.priv_data_size = sizeof(ProresContext),
.init = decode_init,
.close = decode_close,
.decode = decode_frame,
.update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS,
.p.profiles = NULL_IF_CONFIG_SMALL(ff_prores_profiles),
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
.hw_configs = (const AVCodecHWConfigInternal *const []) {
#if CONFIG_PRORES_VIDEOTOOLBOX_HWACCEL
HWACCEL_VIDEOTOOLBOX(prores),
#endif
NULL
},
};