From patchwork Tue Mar 28 12:41:58 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 3146 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.44.195 with SMTP id s186csp609132vss; Tue, 28 Mar 2017 05:42:11 -0700 (PDT) X-Received: by 10.28.35.151 with SMTP id j145mr14369390wmj.50.1490704931155; Tue, 28 Mar 2017 05:42:11 -0700 (PDT) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id h190si3319289wmd.5.2017.03.28.05.42.10; Tue, 28 Mar 2017 05:42:11 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 520D068826A; Tue, 28 Mar 2017 15:41:44 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wr0-f174.google.com (mail-wr0-f174.google.com [209.85.128.174]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 98D13680AA5 for ; Tue, 28 Mar 2017 15:41:38 +0300 (EEST) Received: by mail-wr0-f174.google.com with SMTP id l43so102972341wre.1 for ; Tue, 28 Mar 2017 05:42:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:in-reply-to:references:from:date:message-id:subject:to; bh=drrpkJPWNis5tm5N8lggmPy8hJNFbbgbORpgORvKJ4A=; b=LFOL/ihnm7MovHwAJKt2Rb1O+2hhF11Mng9Cebq2baRa2Gvd0SWKr7XbUI7nYv6WgA qrzcAD/b5tI9QvZEpeJWGb8AKMAuAtJzpwVOpDmygTC6esfUW/KMyx+RaxfIvm6+gtAd Cb04UQMxDO+llbSd40E2+qs+GPsxpJRk8yQYXBBNNKkwpbGw8Zq9ljhw7L52e89iCjLZ 9OWc+fNYvVH4Jw42dm7PKzoLlK7iwRQJljasjV90RWiywtuOhaktMKhd4uDo/pmhj4Lv izmiC5nnynWfZUEPB1Bk2iPWNGQxQVepbZoiWPCLP+kza5RmvY73JoQxz0hCivX5Dwsr JsSQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to; bh=drrpkJPWNis5tm5N8lggmPy8hJNFbbgbORpgORvKJ4A=; b=gye9EVEdZzk8EXFpB4U9lasmYcYxciV0qe20bY8R47YsCKwXX/+bAQqRh8POGfWL1B hfYl2kN5Kwr0zLTwSbtwoJAAgaxx8OLhoUrtFLAi06B4Fj3SnlD7Hrhm4W3PPsuoxVz9 VB/kw8kHD2jonRCM9AVJz5KS94lY0yed+CF1Uq9sDGFtkWT3SG1ztpYX7qEiyiBwoX2q yFi9OGh7TNf8qEULSQX8vNMINUdtYAulUHJcTiaSmFn59uYKiAr6zBOAoaKQ80kT29gv OcLswmnuGoRcVIBa5gQ24uT/EgJR5a46RkF43FfAXrvvzjMi0yoQDvx50rsdNSXLC83G 504A== X-Gm-Message-State: AFeK/H3LHhw39b9s+tH11ZH2BXNLpTdb9/4jE2oc1y6iALGuclnbNAmiQDAa7dIfjF4tYNHwd3ZDgAdajWSRaQ== X-Received: by 10.223.134.18 with SMTP id 18mr6452242wrv.190.1490704920058; Tue, 28 Mar 2017 05:42:00 -0700 (PDT) MIME-Version: 1.0 Received: by 10.28.93.13 with HTTP; Tue, 28 Mar 2017 05:41:58 -0700 (PDT) In-Reply-To: References: <20170327180835.25486-1-onemda@gmail.com> From: Paul B Mahol Date: Tue, 28 Mar 2017 14:41:58 +0200 Message-ID: To: FFmpeg development discussions and patches Subject: Re: [FFmpeg-devel] [PATCH] avcodec/dnxhdenc: DNxHR 444 and HQX support X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" On 3/28/17, Mark Reid wrote: > On Mon, Mar 27, 2017 at 3:14 PM, Paul B Mahol wrote: > >> On 3/27/17, Paul B Mahol wrote: >> > On 3/27/17, Mark Reid wrote: >> >> On Mon, Mar 27, 2017 at 11:08 AM, Paul B Mahol >> wrote: >> >> >> >>> Signed-off-by: Paul B Mahol >> >>> --- >> >>> libavcodec/dnxhdenc.c | 227 ++++++++++++++++++++++++++++++ >> >>> +++++--------------- >> >>> libavcodec/dnxhdenc.h | 6 +- >> >>> 2 files changed, 163 insertions(+), 70 deletions(-) >> >>> >> > >> > [...] >> > >> >>> + case AV_PIX_FMT_YUV444P10: >> >>> + case AV_PIX_FMT_GBRP10: >> >>> + ctx->bit_depth = 10; >> >>> >> >> >> >> Am I missing something, I thought the dnxhr HQX and 444 profiles were >> >> 12bit? >> >> http://avid.force.com/pkb/articles/en_US/White_Paper/ >> DNxHR-Codec-Bandwidth-Specifications >> >> >> > >> > They are both 10 and 12 bit. >> > >> >> I get a failed Assertion here, >> >> >> >> Assertion nbits < ctx->bit_depth + 4 failed at >> >> libavcodec/dnxhdenc.c:837 >> >> when I try the following command >> >> ./ffmpeg_g -y -f rawvideo -video_size 2048x1556 -pixel_format yuv444p10 >> >> -i >> >> /dev/urandom \ >> >> -loglevel debug \ >> >> -vframes 5 \ >> >> -profile:v "dnxhr_444" \ >> >> -vcodec dnxhd \ >> >> -pix_fmt yuv444p10 \ >> >> test.mov >> >> >> > >> > What could be cause of that? If I try to avoid that I get ratecontrol >> > error. >> >> Actually that command is invalid as it passes > (2^10 - 1) values to >> video frame. >> Use geq="lum=random(x)*1023:cb=random(y):cr=random(z)*1023" instead. >> > > okay, well I tried instead > ./ffmpeg_g -y -f lavfi -i > nullsrc=s=2048x1556,geq="lum=random(1)*1023:cb=random(1):cr=random(1)*1023" > \ > -vframes 5 \ > -profile:v "dnxhr_444" \ > -vcodec dnxhd \ > -pix_fmt yuv444p10 \ > test.mov > > and now I get a different failed assertion: > > Assertion block_w * sizeof(uint16_t) <= ((buf_linesize) >= 0 ? > (buf_linesize) : (-(buf_linesize))) failed at > libavcodec/videodsp_template.c:35 > > same thing happens if I use a testsrc > ./ffmpeg_g -y -f lavfi -i "testsrc=size=2048x1556" \ > -vframes 5 \ > -profile:v "dnxhr_444" \ > -vcodec dnxhd \ > -pix_fmt yuv444p10 \ > test.mov > > also get the same assertion for the hqx profile Try attached patch: hqx have some issues with ratecontrol. From e99d2e7c866b395f161d2212fc073fe824b6228e Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Sat, 25 Mar 2017 20:19:26 +0100 Subject: [PATCH] avcodec/dnxhdenc: DNxHR 444 and HQX support Signed-off-by: Paul B Mahol --- libavcodec/dnxhdenc.c | 251 ++++++++++++++++++++++++++++++++++++-------------- libavcodec/dnxhdenc.h | 6 +- 2 files changed, 187 insertions(+), 70 deletions(-) diff --git a/libavcodec/dnxhdenc.c b/libavcodec/dnxhdenc.c index 33f25fb..602dd4f 100644 --- a/libavcodec/dnxhdenc.c +++ b/libavcodec/dnxhdenc.c @@ -23,6 +23,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define ASSERT_LEVEL 10 + #include "libavutil/attributes.h" #include "libavutil/internal.h" #include "libavutil/opt.h" @@ -112,6 +114,34 @@ void dnxhd_10bit_get_pixels_8x4_sym(int16_t *av_restrict block, memcpy(block + 4 * 8, pixels + 3 * line_size, 8 * sizeof(*block)); } +static int dnxhd_10bit_dct_quantize_444(MpegEncContext *ctx, int16_t *block, + int n, int qscale, int *overflow) +{ + const uint8_t *scantable= ctx->intra_scantable.scantable; + const int *qmat = n<4 ? ctx->q_intra_matrix[qscale] : ctx->q_chroma_intra_matrix[qscale]; + int last_non_zero = 0; + int i; + + ctx->fdsp.fdct(block); + + // Divide by 4 with rounding, to compensate scaling of DCT coefficients + block[0] = (block[0] + 2) >> 2; + + for (i = 1; i < 64; ++i) { + int j = scantable[i]; + block[j] = block[j] * qmat[j] >> 16; + if (block[j]) + last_non_zero = i; + } + + /* we need this permutation so that we correct the IDCT, we only permute the !=0 elements */ + if (ctx->idsp.perm_type != FF_IDCT_PERM_NONE) + ff_block_permute(block, ctx->idsp.idct_permutation, + scantable, last_non_zero); + + return last_non_zero; +} + static int dnxhd_10bit_dct_quantize(MpegEncContext *ctx, int16_t *block, int n, int qscale, int *overflow) { @@ -146,7 +176,7 @@ static int dnxhd_10bit_dct_quantize(MpegEncContext *ctx, int16_t *block, static av_cold int dnxhd_init_vlc(DNXHDEncContext *ctx) { int i, j, level, run; - int max_level = 1 << (ctx->cid_table->bit_depth + 2); + int max_level = 1 << (ctx->bit_depth + 2); FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->vlc_codes, max_level, 4 * sizeof(*ctx->vlc_codes), fail); @@ -223,7 +253,7 @@ static av_cold int dnxhd_init_qmat(DNXHDEncContext *ctx, int lbias, int cbias) (ctx->m.avctx->qmax + 1), 64 * 2 * sizeof(uint16_t), fail); - if (ctx->cid_table->bit_depth == 8) { + if (ctx->bit_depth == 8) { for (i = 1; i < 64; i++) { int j = ctx->m.idsp.idct_permutation[ff_zigzag_direct[i]]; weight_matrix[j] = ctx->cid_table->luma_weight[i]; @@ -309,17 +339,20 @@ static int dnxhd_get_hr_frame_size(const CIDEntry* profile, int mb_num) result = (result + 2048) / 4096 * 4096; return FFMAX(result, 8192); } + static av_cold int dnxhd_encode_init(AVCodecContext *avctx) { DNXHDEncContext *ctx = avctx->priv_data; - int i, index, bit_depth, ret; + int i, index, ret; switch (avctx->pix_fmt) { case AV_PIX_FMT_YUV422P: - bit_depth = 8; + ctx->bit_depth = 8; break; case AV_PIX_FMT_YUV422P10: - bit_depth = 10; + case AV_PIX_FMT_YUV444P10: + case AV_PIX_FMT_GBRP10: + ctx->bit_depth = 10; break; default: av_log(avctx, AV_LOG_ERROR, @@ -327,15 +360,32 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - if (ctx->profile == FF_PROFILE_DNXHR_444 || - ctx->profile == FF_PROFILE_DNXHR_HQX) { - avpriv_report_missing_feature(avctx, - "dnxhr_444 or dnxhr_hqx profile"); - return AVERROR_PATCHWELCOME; + if ((ctx->profile == FF_PROFILE_DNXHR_444 && (avctx->pix_fmt != AV_PIX_FMT_YUV444P10 && + avctx->pix_fmt != AV_PIX_FMT_GBRP10)) || + (ctx->profile != FF_PROFILE_DNXHR_444 && (avctx->pix_fmt == AV_PIX_FMT_YUV444P10 || + avctx->pix_fmt == AV_PIX_FMT_GBRP10))) { + av_log(avctx, AV_LOG_ERROR, + "pixel format is incompatible with DNxHD profile\n"); + return AVERROR(EINVAL); + } + + if (ctx->profile == FF_PROFILE_DNXHR_HQX && avctx->pix_fmt != AV_PIX_FMT_YUV422P10) { + av_log(avctx, AV_LOG_ERROR, + "pixel format is incompatible with DNxHR HQX profile\n"); + return AVERROR(EINVAL); } + if ((ctx->profile == FF_PROFILE_DNXHR_LB || + ctx->profile == FF_PROFILE_DNXHR_SQ || + ctx->profile == FF_PROFILE_DNXHR_HQ) && avctx->pix_fmt != AV_PIX_FMT_YUV422P) { + av_log(avctx, AV_LOG_ERROR, + "pixel format is incompatible with DNxHR LB/SQ/HQ profile\n"); + return AVERROR(EINVAL); + } + + ctx->is_444 = ctx->profile == FF_PROFILE_DNXHR_444; avctx->profile = ctx->profile; - ctx->cid = ff_dnxhd_find_cid(avctx, bit_depth); + ctx->cid = ff_dnxhd_find_cid(avctx, ctx->bit_depth); if (!ctx->cid) { av_log(avctx, AV_LOG_ERROR, "video parameters incompatible with DNxHD. Valid DNxHD profiles:\n"); @@ -362,7 +412,7 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) ctx->m.mb_intra = 1; ctx->m.h263_aic = 1; - avctx->bits_per_raw_sample = ctx->cid_table->bit_depth; + avctx->bits_per_raw_sample = ctx->bit_depth; ff_blockdsp_init(&ctx->bdsp, avctx); ff_fdctdsp_init(&ctx->m.fdsp, avctx); @@ -372,12 +422,16 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) ff_dct_encode_init(&ctx->m); if (ctx->profile != FF_PROFILE_DNXHD) - ff_videodsp_init(&ctx->m.vdsp, bit_depth); + ff_videodsp_init(&ctx->m.vdsp, ctx->bit_depth); if (!ctx->m.dct_quantize) ctx->m.dct_quantize = ff_dct_quantize_c; - if (ctx->cid_table->bit_depth == 10) { + if (ctx->is_444 || ctx->profile == FF_PROFILE_DNXHR_HQX) { + ctx->m.dct_quantize = dnxhd_10bit_dct_quantize_444; + ctx->get_pixels_8x4_sym = dnxhd_10bit_get_pixels_8x4_sym; + ctx->block_width_l2 = 4; + } else if (ctx->bit_depth == 10) { ctx->m.dct_quantize = dnxhd_10bit_dct_quantize; ctx->get_pixels_8x4_sym = dnxhd_10bit_get_pixels_8x4_sym; ctx->block_width_l2 = 4; @@ -490,10 +544,10 @@ static int dnxhd_write_header(AVCodecContext *avctx, uint8_t *buf) AV_WB16(buf + 0x1a, avctx->width); // SPL AV_WB16(buf + 0x1d, avctx->height >> ctx->interlaced); // NAL - buf[0x21] = ctx->cid_table->bit_depth == 10 ? 0x58 : 0x38; + buf[0x21] = ctx->bit_depth == 10 ? 0x58 : 0x38; buf[0x22] = 0x88 + (ctx->interlaced << 2); AV_WB32(buf + 0x28, ctx->cid); // CID - buf[0x2c] = ctx->interlaced ? 0 : 0x80; + buf[0x2c] = (!ctx->interlaced << 7) | (ctx->is_444 << 6) | (avctx->pix_fmt == AV_PIX_FMT_YUV444P10); buf[0x5f] = 0x01; // UDL @@ -554,8 +608,13 @@ void dnxhd_unquantize_c(DNXHDEncContext *ctx, int16_t *block, int n, int level; int i; - weight_matrix = (n & 2) ? ctx->cid_table->chroma_weight - : ctx->cid_table->luma_weight; + if (ctx->is_444) { + weight_matrix = ((n % 6) < 2) ? ctx->cid_table->luma_weight + : ctx->cid_table->chroma_weight; + } else { + weight_matrix = (n & 2) ? ctx->cid_table->chroma_weight + : ctx->cid_table->luma_weight; + } for (i = 1; i <= last_index; i++) { int j = ctx->m.intra_scantable.permutated[i]; @@ -563,7 +622,7 @@ void dnxhd_unquantize_c(DNXHDEncContext *ctx, int16_t *block, int n, if (level) { if (level < 0) { level = (1 - 2 * level) * qscale * weight_matrix[i]; - if (ctx->cid_table->bit_depth == 10) { + if (ctx->bit_depth == 10) { if (weight_matrix[i] != 8) level += 8; level >>= 4; @@ -575,7 +634,7 @@ void dnxhd_unquantize_c(DNXHDEncContext *ctx, int16_t *block, int n, level = -level; } else { level = (2 * level + 1) * qscale * weight_matrix[i]; - if (ctx->cid_table->bit_depth == 10) { + if (ctx->bit_depth == 10) { if (weight_matrix[i] != 8) level += 8; level >>= 4; @@ -630,14 +689,14 @@ void dnxhd_get_blocks(DNXHDEncContext *ctx, int mb_x, int mb_y) const uint8_t *ptr_y = ctx->thread[0]->src[0] + ((mb_y << 4) * ctx->m.linesize) + (mb_x << bs + 1); const uint8_t *ptr_u = ctx->thread[0]->src[1] + - ((mb_y << 4) * ctx->m.uvlinesize) + (mb_x << bs); + ((mb_y << 4) * ctx->m.uvlinesize) + (mb_x << bs + ctx->is_444); const uint8_t *ptr_v = ctx->thread[0]->src[2] + - ((mb_y << 4) * ctx->m.uvlinesize) + (mb_x << bs); + ((mb_y << 4) * ctx->m.uvlinesize) + (mb_x << bs + ctx->is_444); PixblockDSPContext *pdsp = &ctx->m.pdsp; VideoDSPContext *vdsp = &ctx->m.vdsp; - if (vdsp->emulated_edge_mc && ((mb_x << 4) + 16 > ctx->m.avctx->width || - (mb_y << 4) + 16 > ctx->m.avctx->height)) { + if (ctx->bit_depth != 10 && vdsp->emulated_edge_mc && ((mb_x << 4) + 16 > ctx->m.avctx->width || + (mb_y << 4) + 16 > ctx->m.avctx->height)) { int y_w = ctx->m.avctx->width - (mb_x << 4); int y_h = ctx->m.avctx->height - (mb_y << 4); int uv_w = (y_w + 1) / 2; @@ -663,50 +722,101 @@ void dnxhd_get_blocks(DNXHDEncContext *ctx, int mb_x, int mb_y) ptr_y = &ctx->edge_buf_y[0]; ptr_u = &ctx->edge_buf_uv[0][0]; ptr_v = &ctx->edge_buf_uv[1][0]; + } else if (ctx->bit_depth == 10 && vdsp->emulated_edge_mc && ((mb_x << 3) + 8 > ctx->m.avctx->width || + (mb_y << 3) + 8 > ctx->m.avctx->height)) { + int y_w = ctx->m.avctx->width - (mb_x << 3); + int y_h = ctx->m.avctx->height - (mb_y << 3); + int uv_w = ctx->is_444 ? y_w : (y_w + 1) / 2; + int uv_h = y_h; + linesize = 16; + uvlinesize = 8 + 8 * ctx->is_444; + + vdsp->emulated_edge_mc(&ctx->edge_buf_y[0], ptr_y, + linesize, ctx->m.linesize, + linesize / 2, 16, + 0, 0, y_w, y_h); + vdsp->emulated_edge_mc(&ctx->edge_buf_uv[0][0], ptr_u, + uvlinesize, ctx->m.uvlinesize, + uvlinesize / 2, 16, + 0, 0, uv_w, uv_h); + vdsp->emulated_edge_mc(&ctx->edge_buf_uv[1][0], ptr_v, + uvlinesize, ctx->m.uvlinesize, + uvlinesize / 2, 16, + 0, 0, uv_w, uv_h); + + dct_y_offset = bw * linesize; + dct_uv_offset = bw * uvlinesize; + ptr_y = &ctx->edge_buf_y[0]; + ptr_u = &ctx->edge_buf_uv[0][0]; + ptr_v = &ctx->edge_buf_uv[1][0]; } - pdsp->get_pixels(ctx->blocks[0], ptr_y, linesize); - pdsp->get_pixels(ctx->blocks[1], ptr_y + bw, linesize); - pdsp->get_pixels(ctx->blocks[2], ptr_u, uvlinesize); - pdsp->get_pixels(ctx->blocks[3], ptr_v, uvlinesize); - - if (mb_y + 1 == ctx->m.mb_height && ctx->m.avctx->height == 1080) { - if (ctx->interlaced) { - ctx->get_pixels_8x4_sym(ctx->blocks[4], - ptr_y + dct_y_offset, - linesize); - ctx->get_pixels_8x4_sym(ctx->blocks[5], - ptr_y + dct_y_offset + bw, - linesize); - ctx->get_pixels_8x4_sym(ctx->blocks[6], - ptr_u + dct_uv_offset, - uvlinesize); - ctx->get_pixels_8x4_sym(ctx->blocks[7], - ptr_v + dct_uv_offset, - uvlinesize); + if (!ctx->is_444) { + pdsp->get_pixels(ctx->blocks[0], ptr_y, linesize); + pdsp->get_pixels(ctx->blocks[1], ptr_y + bw, linesize); + pdsp->get_pixels(ctx->blocks[2], ptr_u, uvlinesize); + pdsp->get_pixels(ctx->blocks[3], ptr_v, uvlinesize); + + if (mb_y + 1 == ctx->m.mb_height && ctx->m.avctx->height == 1080) { + if (ctx->interlaced) { + ctx->get_pixels_8x4_sym(ctx->blocks[4], + ptr_y + dct_y_offset, + linesize); + ctx->get_pixels_8x4_sym(ctx->blocks[5], + ptr_y + dct_y_offset + bw, + linesize); + ctx->get_pixels_8x4_sym(ctx->blocks[6], + ptr_u + dct_uv_offset, + uvlinesize); + ctx->get_pixels_8x4_sym(ctx->blocks[7], + ptr_v + dct_uv_offset, + uvlinesize); + } else { + ctx->bdsp.clear_block(ctx->blocks[4]); + ctx->bdsp.clear_block(ctx->blocks[5]); + ctx->bdsp.clear_block(ctx->blocks[6]); + ctx->bdsp.clear_block(ctx->blocks[7]); + } } else { - ctx->bdsp.clear_block(ctx->blocks[4]); - ctx->bdsp.clear_block(ctx->blocks[5]); - ctx->bdsp.clear_block(ctx->blocks[6]); - ctx->bdsp.clear_block(ctx->blocks[7]); + pdsp->get_pixels(ctx->blocks[4], + ptr_y + dct_y_offset, linesize); + pdsp->get_pixels(ctx->blocks[5], + ptr_y + dct_y_offset + bw, linesize); + pdsp->get_pixels(ctx->blocks[6], + ptr_u + dct_uv_offset, uvlinesize); + pdsp->get_pixels(ctx->blocks[7], + ptr_v + dct_uv_offset, uvlinesize); } } else { - pdsp->get_pixels(ctx->blocks[4], - ptr_y + dct_y_offset, linesize); - pdsp->get_pixels(ctx->blocks[5], - ptr_y + dct_y_offset + bw, linesize); - pdsp->get_pixels(ctx->blocks[6], - ptr_u + dct_uv_offset, uvlinesize); - pdsp->get_pixels(ctx->blocks[7], - ptr_v + dct_uv_offset, uvlinesize); + pdsp->get_pixels(ctx->blocks[0], ptr_y, linesize); + pdsp->get_pixels(ctx->blocks[1], ptr_y + bw, linesize); + pdsp->get_pixels(ctx->blocks[6], ptr_y + dct_y_offset, linesize); + pdsp->get_pixels(ctx->blocks[7], ptr_y + dct_y_offset + bw, linesize); + + pdsp->get_pixels(ctx->blocks[2], ptr_u, uvlinesize); + pdsp->get_pixels(ctx->blocks[3], ptr_u + bw, uvlinesize); + pdsp->get_pixels(ctx->blocks[8], ptr_u + dct_uv_offset, uvlinesize); + pdsp->get_pixels(ctx->blocks[9], ptr_u + dct_uv_offset + bw, uvlinesize); + + pdsp->get_pixels(ctx->blocks[4], ptr_v, uvlinesize); + pdsp->get_pixels(ctx->blocks[5], ptr_v + bw, uvlinesize); + pdsp->get_pixels(ctx->blocks[10], ptr_v + dct_uv_offset, uvlinesize); + pdsp->get_pixels(ctx->blocks[11], ptr_v + dct_uv_offset + bw, uvlinesize); } } static av_always_inline int dnxhd_switch_matrix(DNXHDEncContext *ctx, int i) { - const static uint8_t component[8]={0,0,1,2,0,0,1,2}; - return component[i]; + int x; + + if (ctx->is_444) { + x = (i >> 1) % 3; + } else { + const static uint8_t component[8]={0,0,1,2,0,0,1,2}; + x = component[i]; + } + return x; } static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg, @@ -720,7 +830,7 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg, ctx->m.last_dc[0] = ctx->m.last_dc[1] = - ctx->m.last_dc[2] = 1 << (ctx->cid_table->bit_depth + 2); + ctx->m.last_dc[2] = 1 << (ctx->bit_depth + 2); for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) { unsigned mb = mb_y * ctx->m.mb_width + mb_x; @@ -731,13 +841,14 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg, dnxhd_get_blocks(ctx, mb_x, mb_y); - for (i = 0; i < 8; i++) { + for (i = 0; i < 8 + 4 * ctx->is_444; i++) { int16_t *src_block = ctx->blocks[i]; int overflow, nbits, diff, last_index; int n = dnxhd_switch_matrix(ctx, i); memcpy(block, src_block, 64 * sizeof(*block)); - last_index = ctx->m.dct_quantize(&ctx->m, block, 4 & (2*i), + last_index = ctx->m.dct_quantize(&ctx->m, block, + ctx->is_444 ? 4 * (n > 0): 4 & (2*i), qscale, &overflow); ac_bits += dnxhd_calc_ac_bits(ctx, block, last_index); @@ -747,7 +858,7 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg, else nbits = av_log2_16bit(2 * diff); - av_assert1(nbits < ctx->cid_table->bit_depth + 4); + av_assert1(nbits < ctx->bit_depth + 4); dc_bits += ctx->cid_table->dc_bits[nbits] + nbits; ctx->m.last_dc[n] = block[0]; @@ -760,7 +871,7 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg, } ctx->mb_rc[(qscale * ctx->m.mb_num) + mb].ssd = ssd; ctx->mb_rc[(qscale * ctx->m.mb_num) + mb].bits = ac_bits + dc_bits + 12 + - 8 * ctx->vlc_bits[0]; + (1 + ctx->is_444) * 8 * ctx->vlc_bits[0]; } return 0; } @@ -776,20 +887,22 @@ static int dnxhd_encode_thread(AVCodecContext *avctx, void *arg, ctx->m.last_dc[0] = ctx->m.last_dc[1] = - ctx->m.last_dc[2] = 1 << (ctx->cid_table->bit_depth + 2); + ctx->m.last_dc[2] = 1 << (ctx->bit_depth + 2); for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) { unsigned mb = mb_y * ctx->m.mb_width + mb_x; int qscale = ctx->mb_qscale[mb]; int i; - put_bits(&ctx->m.pb, 12, qscale << 1); + put_bits(&ctx->m.pb, 11, qscale); + put_bits(&ctx->m.pb, 1, avctx->pix_fmt == AV_PIX_FMT_YUV444P10); dnxhd_get_blocks(ctx, mb_x, mb_y); - for (i = 0; i < 8; i++) { + for (i = 0; i < 8 + 4 * ctx->is_444; i++) { int16_t *block = ctx->blocks[i]; int overflow, n = dnxhd_switch_matrix(ctx, i); - int last_index = ctx->m.dct_quantize(&ctx->m, block, 4 & (2*i), + int last_index = ctx->m.dct_quantize(&ctx->m, block, + ctx->is_444 ? (((i >> 1) % 3) < 1 ? 0 : 4): 4 & (2*i), qscale, &overflow); // START_TIMER; dnxhd_encode_block(ctx, block, last_index, n); @@ -830,7 +943,7 @@ static int dnxhd_mb_var_thread(AVCodecContext *avctx, void *arg, ((avctx->height >> ctx->interlaced) & 0xF); ctx = ctx->thread[threadnr]; - if (ctx->cid_table->bit_depth == 8) { + if (ctx->bit_depth == 8) { uint8_t *pix = ctx->thread[0]->src[0] + ((mb_y << 4) * ctx->m.linesize); for (mb_x = 0; mb_x < ctx->m.mb_width; ++mb_x, pix += 16) { unsigned mb = mb_y * ctx->m.mb_width + mb_x; @@ -1214,7 +1327,7 @@ FF_ENABLE_DEPRECATION_WARNINGS static av_cold int dnxhd_encode_end(AVCodecContext *avctx) { DNXHDEncContext *ctx = avctx->priv_data; - int max_level = 1 << (ctx->cid_table->bit_depth + 2); + int max_level = 1 << (ctx->bit_depth + 2); int i; av_free(ctx->vlc_codes - max_level * 2); @@ -1259,6 +1372,8 @@ AVCodec ff_dnxhd_encoder = { .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P10, + AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_GBRP10, AV_PIX_FMT_NONE }, .priv_class = &dnxhd_class, diff --git a/libavcodec/dnxhdenc.h b/libavcodec/dnxhdenc.h index eb9da12..3005a00 100644 --- a/libavcodec/dnxhdenc.h +++ b/libavcodec/dnxhdenc.h @@ -46,6 +46,8 @@ typedef struct DNXHDEncContext { int cid; int profile; + int bit_depth; + int is_444; const CIDEntry *cid_table; uint8_t *msip; ///< Macroblock Scan Indexes Payload uint32_t *slice_size; @@ -70,9 +72,9 @@ typedef struct DNXHDEncContext { unsigned min_padding; int intra_quant_bias; - DECLARE_ALIGNED(16, int16_t, blocks)[8][64]; + DECLARE_ALIGNED(16, int16_t, blocks)[12][64]; DECLARE_ALIGNED(16, uint8_t, edge_buf_y)[256]; - DECLARE_ALIGNED(16, uint8_t, edge_buf_uv)[2][128]; + DECLARE_ALIGNED(16, uint8_t, edge_buf_uv)[2][256]; int (*qmatrix_c) [64]; int (*qmatrix_l) [64]; -- 2.9.3