summaryrefslogtreecommitdiff
path: root/libavcodec/dnxhdenc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavcodec/dnxhdenc.c')
-rw-r--r--libavcodec/dnxhdenc.c370
1 files changed, 242 insertions, 128 deletions
diff --git a/libavcodec/dnxhdenc.c b/libavcodec/dnxhdenc.c
index 0c6c59cec8..33f25fb4ac 100644
--- a/libavcodec/dnxhdenc.c
+++ b/libavcodec/dnxhdenc.c
@@ -6,20 +6,20 @@
* VC-3 encoder funded by the British Broadcasting Corporation
* 10 bit support added by MirriAd Ltd, Joseph Artsimovich <joseph@mirriad.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,6 +34,7 @@
#include "internal.h"
#include "mpegvideo.h"
#include "pixblockdsp.h"
+#include "profiles.h"
#include "dnxhdenc.h"
// The largest value that will not lead to overflow for 10-bit samples.
@@ -44,21 +45,36 @@
#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
{ "nitris_compat", "encode with Avid Nitris compatibility",
- offsetof(DNXHDEncContext, nitris_compat), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
+ offsetof(DNXHDEncContext, nitris_compat), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
{ "ibias", "intra quant bias",
offsetof(DNXHDEncContext, intra_quant_bias), AV_OPT_TYPE_INT,
- { .i64 = FF_DEFAULT_QUANT_BIAS }, INT_MIN, INT_MAX, VE },
+ { .i64 = 0 }, INT_MIN, INT_MAX, VE },
+ { "profile", NULL, offsetof(DNXHDEncContext, profile), AV_OPT_TYPE_INT,
+ { .i64 = FF_PROFILE_DNXHD },
+ FF_PROFILE_DNXHD, FF_PROFILE_DNXHR_444, VE, "profile" },
+ { "dnxhd", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_DNXHD },
+ 0, 0, VE, "profile" },
+ { "dnxhr_444", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_DNXHR_444 },
+ 0, 0, VE, "profile" },
+ { "dnxhr_hqx", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_DNXHR_HQX },
+ 0, 0, VE, "profile" },
+ { "dnxhr_hq", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_DNXHR_HQ },
+ 0, 0, VE, "profile" },
+ { "dnxhr_sq", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_DNXHR_SQ },
+ 0, 0, VE, "profile" },
+ { "dnxhr_lb", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_DNXHR_LB },
+ 0, 0, VE, "profile" },
{ NULL }
};
-static const AVClass class = {
- "dnxhd",
- av_default_item_name,
- options,
- LIBAVUTIL_VERSION_INT
+static const AVClass dnxhd_class = {
+ .class_name = "dnxhd",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
};
-static void dnxhd_8bit_get_pixels_8x4_sym(int16_t *restrict block,
+static void dnxhd_8bit_get_pixels_8x4_sym(int16_t *av_restrict block,
const uint8_t *pixels,
ptrdiff_t line_size)
{
@@ -82,25 +98,25 @@ static void dnxhd_8bit_get_pixels_8x4_sym(int16_t *restrict block,
}
static av_always_inline
-void dnxhd_10bit_get_pixels_8x4_sym(int16_t *restrict block,
+void dnxhd_10bit_get_pixels_8x4_sym(int16_t *av_restrict block,
const uint8_t *pixels,
ptrdiff_t line_size)
{
- int i;
-
- block += 32;
-
- for (i = 0; i < 4; i++) {
- memcpy(block + i * 8, pixels + i * line_size, 8 * sizeof(*block));
- memcpy(block - (i + 1) * 8, pixels + i * line_size, 8 * sizeof(*block));
- }
+ memcpy(block + 0 * 8, pixels + 0 * line_size, 8 * sizeof(*block));
+ memcpy(block + 7 * 8, pixels + 0 * line_size, 8 * sizeof(*block));
+ memcpy(block + 1 * 8, pixels + 1 * line_size, 8 * sizeof(*block));
+ memcpy(block + 6 * 8, pixels + 1 * line_size, 8 * sizeof(*block));
+ memcpy(block + 2 * 8, pixels + 2 * line_size, 8 * sizeof(*block));
+ memcpy(block + 5 * 8, pixels + 2 * line_size, 8 * sizeof(*block));
+ memcpy(block + 3 * 8, pixels + 3 * line_size, 8 * sizeof(*block));
+ memcpy(block + 4 * 8, pixels + 3 * line_size, 8 * sizeof(*block));
}
static int dnxhd_10bit_dct_quantize(MpegEncContext *ctx, int16_t *block,
int n, int qscale, int *overflow)
{
const uint8_t *scantable= ctx->intra_scantable.scantable;
- const int *qmat = ctx->q_intra_matrix[qscale];
+ const int *qmat = n<4 ? ctx->q_intra_matrix[qscale] : ctx->q_chroma_intra_matrix[qscale];
int last_non_zero = 0;
int i;
@@ -119,6 +135,11 @@ static int dnxhd_10bit_dct_quantize(MpegEncContext *ctx, int16_t *block,
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;
}
@@ -127,10 +148,10 @@ static av_cold int dnxhd_init_vlc(DNXHDEncContext *ctx)
int i, j, level, run;
int max_level = 1 << (ctx->cid_table->bit_depth + 2);
- FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->vlc_codes,
- max_level * 4 * sizeof(*ctx->vlc_codes), fail);
- FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->vlc_bits,
- max_level * 4 * sizeof(*ctx->vlc_bits), fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->vlc_codes,
+ max_level, 4 * sizeof(*ctx->vlc_codes), fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->vlc_bits,
+ max_level, 4 * sizeof(*ctx->vlc_bits), fail);
FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->run_codes,
63 * 2, fail);
FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->run_bits,
@@ -149,10 +170,10 @@ static av_cold int dnxhd_init_vlc(DNXHDEncContext *ctx)
alevel -= offset << 6;
}
for (j = 0; j < 257; j++) {
- if (ctx->cid_table->ac_level[j] == alevel &&
- (!offset || (ctx->cid_table->ac_index_flag[j] && offset)) &&
- (!run || (ctx->cid_table->ac_run_flag [j] && run))) {
- assert(!ctx->vlc_codes[index]);
+ if (ctx->cid_table->ac_info[2*j+0] >> 1 == alevel &&
+ (!offset || (ctx->cid_table->ac_info[2*j+1] & 1) && offset) &&
+ (!run || (ctx->cid_table->ac_info[2*j+1] & 2) && run)) {
+ av_assert1(!ctx->vlc_codes[index]);
if (alevel) {
ctx->vlc_codes[index] =
(ctx->cid_table->ac_codes[j] << 1) | (sign & 1);
@@ -164,7 +185,7 @@ static av_cold int dnxhd_init_vlc(DNXHDEncContext *ctx)
break;
}
}
- assert(!alevel || j < 257);
+ av_assert0(!alevel || j < 257);
if (offset) {
ctx->vlc_codes[index] =
(ctx->vlc_codes[index] << ctx->cid_table->index_bits) | offset;
@@ -174,7 +195,7 @@ static av_cold int dnxhd_init_vlc(DNXHDEncContext *ctx)
}
for (i = 0; i < 62; i++) {
int run = ctx->cid_table->run[i];
- assert(run < 63);
+ av_assert0(run < 63);
ctx->run_codes[run] = ctx->cid_table->run_codes[i];
ctx->run_bits[run] = ctx->cid_table->run_bits[i];
}
@@ -191,15 +212,15 @@ static av_cold int dnxhd_init_qmat(DNXHDEncContext *ctx, int lbias, int cbias)
const uint8_t *luma_weight_table = ctx->cid_table->luma_weight;
const uint8_t *chroma_weight_table = ctx->cid_table->chroma_weight;
- FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->qmatrix_l,
- (ctx->m.avctx->qmax + 1) * 64 * sizeof(int), fail);
- FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->qmatrix_c,
- (ctx->m.avctx->qmax + 1) * 64 * sizeof(int), fail);
- FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->qmatrix_l16,
- (ctx->m.avctx->qmax + 1) * 64 * 2 * sizeof(uint16_t),
+ FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->qmatrix_l,
+ (ctx->m.avctx->qmax + 1), 64 * sizeof(int), fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->qmatrix_c,
+ (ctx->m.avctx->qmax + 1), 64 * sizeof(int), fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->qmatrix_l16,
+ (ctx->m.avctx->qmax + 1), 64 * 2 * sizeof(uint16_t),
fail);
- FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->qmatrix_c16,
- (ctx->m.avctx->qmax + 1) * 64 * 2 * sizeof(uint16_t),
+ FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->qmatrix_c16,
+ (ctx->m.avctx->qmax + 1), 64 * 2 * sizeof(uint16_t),
fail);
if (ctx->cid_table->bit_depth == 8) {
@@ -232,7 +253,7 @@ static av_cold int dnxhd_init_qmat(DNXHDEncContext *ctx, int lbias, int cbias)
// 10-bit
for (qscale = 1; qscale <= ctx->m.avctx->qmax; qscale++) {
for (i = 1; i < 64; i++) {
- int j = ctx->m.idsp.idct_permutation[ff_zigzag_direct[i]];
+ int j = ff_zigzag_direct[i];
/* The quantization formula from the VC-3 standard is:
* quantized = sign(block[i]) * floor(abs(block[i]/s) * p /
@@ -253,6 +274,11 @@ static av_cold int dnxhd_init_qmat(DNXHDEncContext *ctx, int lbias, int cbias)
}
}
+ ctx->m.q_chroma_intra_matrix16 = ctx->qmatrix_c16;
+ ctx->m.q_chroma_intra_matrix = ctx->qmatrix_c;
+ ctx->m.q_intra_matrix16 = ctx->qmatrix_l16;
+ ctx->m.q_intra_matrix = ctx->qmatrix_l;
+
return 0;
fail:
return AVERROR(ENOMEM);
@@ -260,14 +286,16 @@ fail:
static av_cold int dnxhd_init_rc(DNXHDEncContext *ctx)
{
- FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->mb_rc,
- 8160 * ctx->m.avctx->qmax * sizeof(RCEntry), fail);
- if (ctx->m.avctx->mb_decision != FF_MB_DECISION_RD)
- FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->mb_cmp,
- ctx->m.mb_num * sizeof(RCCMPEntry), fail);
-
- ctx->frame_bits = (ctx->cid_table->coding_unit_size -
- 640 - 4 - ctx->min_padding) * 8;
+ FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->mb_rc, (ctx->m.avctx->qmax + 1),
+ ctx->m.mb_num * sizeof(RCEntry), fail);
+ if (ctx->m.avctx->mb_decision != FF_MB_DECISION_RD) {
+ FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->mb_cmp,
+ ctx->m.mb_num, sizeof(RCCMPEntry), fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->mb_cmp_tmp,
+ ctx->m.mb_num, sizeof(RCCMPEntry), fail);
+ }
+ ctx->frame_bits = (ctx->coding_unit_size -
+ ctx->data_offset - 4 - ctx->min_padding) * 8;
ctx->qscale = 1;
ctx->lambda = 2 << LAMBDA_FRAC_BITS; // qscale 2
return 0;
@@ -275,6 +303,12 @@ fail:
return AVERROR(ENOMEM);
}
+static int dnxhd_get_hr_frame_size(const CIDEntry* profile, int mb_num)
+{
+ int result = mb_num * profile->packet_scale.num / profile->packet_scale.den;
+ result = (result + 2048) / 4096 * 4096;
+ return FFMAX(result, 8192);
+}
static av_cold int dnxhd_encode_init(AVCodecContext *avctx)
{
DNXHDEncContext *ctx = avctx->priv_data;
@@ -289,22 +323,39 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx)
break;
default:
av_log(avctx, AV_LOG_ERROR,
- "Pixel format is incompatible with DNxHD, use yuv422p or yuv422p10.\n");
+ "pixel format is incompatible with DNxHD\n");
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;
+ }
+
+ avctx->profile = ctx->profile;
ctx->cid = ff_dnxhd_find_cid(avctx, bit_depth);
if (!ctx->cid) {
av_log(avctx, AV_LOG_ERROR,
- "Video parameters incompatible with DNxHD, available CIDs:\n");
- ff_dnxhd_list_cid(avctx);
+ "video parameters incompatible with DNxHD. Valid DNxHD profiles:\n");
+ ff_dnxhd_print_profiles(avctx, AV_LOG_ERROR);
return AVERROR(EINVAL);
}
av_log(avctx, AV_LOG_DEBUG, "cid %d\n", ctx->cid);
+ if (ctx->cid >= 1270 && ctx->cid <= 1274)
+ avctx->codec_tag = MKTAG('A','V','d','h');
+
+ if (avctx->width < 256 || avctx->height < 120) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Input dimensions too small, input must be at least 256x120\n");
+ return AVERROR(EINVAL);
+ }
+
index = ff_dnxhd_get_cid_table(ctx->cid);
- if (index < 0)
- return index;
+ av_assert0(index >= 0);
+
ctx->cid_table = &ff_dnxhd_cid_table[index];
ctx->m.avctx = avctx;
@@ -318,6 +369,11 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx)
ff_mpv_idct_init(&ctx->m);
ff_mpegvideoencdsp_init(&ctx->m.mpvencdsp, avctx);
ff_pixblockdsp_init(&ctx->m.pdsp, avctx);
+ ff_dct_encode_init(&ctx->m);
+
+ if (ctx->profile != FF_PROFILE_DNXHD)
+ ff_videodsp_init(&ctx->m.vdsp, bit_depth);
+
if (!ctx->m.dct_quantize)
ctx->m.dct_quantize = ff_dct_quantize_c;
@@ -343,6 +399,20 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx)
ctx->m.mb_num = ctx->m.mb_height * ctx->m.mb_width;
+ if (ctx->cid_table->frame_size == DNXHD_VARIABLE) {
+ ctx->frame_size = dnxhd_get_hr_frame_size(ctx->cid_table,
+ ctx->m.mb_num);
+ ctx->coding_unit_size = ctx->frame_size;
+ } else {
+ ctx->frame_size = ctx->cid_table->frame_size;
+ ctx->coding_unit_size = ctx->cid_table->coding_unit_size;
+ }
+
+ if (ctx->m.mb_height > 68)
+ ctx->data_offset = 0x170 + (ctx->m.mb_height << 2);
+ else
+ ctx->data_offset = 0x280;
+
#if FF_API_QUANT_BIAS
FF_DISABLE_DEPRECATION_WARNINGS
if (avctx->intra_quant_bias != FF_DEFAULT_QUANT_BIAS)
@@ -384,6 +454,11 @@ FF_ENABLE_DEPRECATION_WARNINGS
return AVERROR(EINVAL);
}
+ if (avctx->qmax <= 1) {
+ av_log(avctx, AV_LOG_ERROR, "qmax must be at least 2\n");
+ return AVERROR(EINVAL);
+ }
+
ctx->thread[0] = ctx;
for (i = 1; i < avctx->thread_count; i++) {
ctx->thread[i] = av_malloc(sizeof(DNXHDEncContext));
@@ -398,11 +473,16 @@ fail: // for FF_ALLOCZ_OR_GOTO
static int dnxhd_write_header(AVCodecContext *avctx, uint8_t *buf)
{
DNXHDEncContext *ctx = avctx->priv_data;
- static const uint8_t header_prefix[5] = { 0x00, 0x00, 0x02, 0x80, 0x01 };
- memset(buf, 0, 640);
+ memset(buf, 0, ctx->data_offset);
+
+ // * write prefix */
+ AV_WB16(buf + 0x02, ctx->data_offset);
+ if (ctx->cid >= 1270 && ctx->cid <= 1274)
+ buf[4] = 0x03;
+ else
+ buf[4] = 0x01;
- memcpy(buf, header_prefix, 5);
buf[5] = ctx->interlaced ? ctx->cur_field + 2 : 0x01;
buf[6] = 0x80; // crc flag off
buf[7] = 0xa0; // reserved
@@ -437,7 +517,7 @@ static av_always_inline void dnxhd_encode_dc(DNXHDEncContext *ctx, int diff)
}
put_bits(&ctx->m.pb, ctx->cid_table->dc_bits[nbits] + nbits,
(ctx->cid_table->dc_codes[nbits] << nbits) +
- (diff & ((1 << nbits) - 1)));
+ av_mod_uintp2(diff, nbits));
}
static av_always_inline
@@ -543,6 +623,10 @@ void dnxhd_get_blocks(DNXHDEncContext *ctx, int mb_x, int mb_y)
{
const int bs = ctx->block_width_l2;
const int bw = 1 << bs;
+ int dct_y_offset = ctx->dct_y_offset;
+ int dct_uv_offset = ctx->dct_uv_offset;
+ int linesize = ctx->m.linesize;
+ int uvlinesize = ctx->m.uvlinesize;
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] +
@@ -550,26 +634,56 @@ void dnxhd_get_blocks(DNXHDEncContext *ctx, int mb_x, int mb_y)
const uint8_t *ptr_v = ctx->thread[0]->src[2] +
((mb_y << 4) * ctx->m.uvlinesize) + (mb_x << bs);
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)) {
+ 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;
+ int uv_h = y_h;
+ linesize = 16;
+ uvlinesize = 8;
+
+ vdsp->emulated_edge_mc(&ctx->edge_buf_y[0], ptr_y,
+ linesize, ctx->m.linesize,
+ linesize, 16,
+ 0, 0, y_w, y_h);
+ vdsp->emulated_edge_mc(&ctx->edge_buf_uv[0][0], ptr_u,
+ uvlinesize, ctx->m.uvlinesize,
+ uvlinesize, 16,
+ 0, 0, uv_w, uv_h);
+ vdsp->emulated_edge_mc(&ctx->edge_buf_uv[1][0], ptr_v,
+ uvlinesize, ctx->m.uvlinesize,
+ uvlinesize, 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, ctx->m.linesize);
- pdsp->get_pixels(ctx->blocks[1], ptr_y + bw, ctx->m.linesize);
- pdsp->get_pixels(ctx->blocks[2], ptr_u, ctx->m.uvlinesize);
- pdsp->get_pixels(ctx->blocks[3], ptr_v, ctx->m.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[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 + ctx->dct_y_offset,
- ctx->m.linesize);
+ ptr_y + dct_y_offset,
+ linesize);
ctx->get_pixels_8x4_sym(ctx->blocks[5],
- ptr_y + ctx->dct_y_offset + bw,
- ctx->m.linesize);
+ ptr_y + dct_y_offset + bw,
+ linesize);
ctx->get_pixels_8x4_sym(ctx->blocks[6],
- ptr_u + ctx->dct_uv_offset,
- ctx->m.uvlinesize);
+ ptr_u + dct_uv_offset,
+ uvlinesize);
ctx->get_pixels_8x4_sym(ctx->blocks[7],
- ptr_v + ctx->dct_uv_offset,
- ctx->m.uvlinesize);
+ ptr_v + dct_uv_offset,
+ uvlinesize);
} else {
ctx->bdsp.clear_block(ctx->blocks[4]);
ctx->bdsp.clear_block(ctx->blocks[5]);
@@ -578,28 +692,21 @@ void dnxhd_get_blocks(DNXHDEncContext *ctx, int mb_x, int mb_y)
}
} else {
pdsp->get_pixels(ctx->blocks[4],
- ptr_y + ctx->dct_y_offset, ctx->m.linesize);
+ ptr_y + dct_y_offset, linesize);
pdsp->get_pixels(ctx->blocks[5],
- ptr_y + ctx->dct_y_offset + bw, ctx->m.linesize);
+ ptr_y + dct_y_offset + bw, linesize);
pdsp->get_pixels(ctx->blocks[6],
- ptr_u + ctx->dct_uv_offset, ctx->m.uvlinesize);
+ ptr_u + dct_uv_offset, uvlinesize);
pdsp->get_pixels(ctx->blocks[7],
- ptr_v + ctx->dct_uv_offset, ctx->m.uvlinesize);
+ ptr_v + dct_uv_offset, uvlinesize);
}
}
static av_always_inline
int dnxhd_switch_matrix(DNXHDEncContext *ctx, int i)
{
- if (i & 2) {
- ctx->m.q_intra_matrix16 = ctx->qmatrix_c16;
- ctx->m.q_intra_matrix = ctx->qmatrix_c;
- return 1 + (i & 1);
- } else {
- ctx->m.q_intra_matrix16 = ctx->qmatrix_l16;
- ctx->m.q_intra_matrix = ctx->qmatrix_l;
- return 0;
- }
+ const static uint8_t component[8]={0,0,1,2,0,0,1,2};
+ return component[i];
}
static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg,
@@ -630,7 +737,7 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg,
int n = dnxhd_switch_matrix(ctx, i);
memcpy(block, src_block, 64 * sizeof(*block));
- last_index = ctx->m.dct_quantize(&ctx->m, block, i,
+ last_index = ctx->m.dct_quantize(&ctx->m, block, 4 & (2*i),
qscale, &overflow);
ac_bits += dnxhd_calc_ac_bits(ctx, block, last_index);
@@ -640,7 +747,7 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg,
else
nbits = av_log2_16bit(2 * diff);
- assert(nbits < ctx->cid_table->bit_depth + 4);
+ av_assert1(nbits < ctx->cid_table->bit_depth + 4);
dc_bits += ctx->cid_table->dc_bits[nbits] + nbits;
ctx->m.last_dc[n] = block[0];
@@ -651,8 +758,8 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg,
ssd += dnxhd_ssd_block(block, src_block);
}
}
- ctx->mb_rc[qscale][mb].ssd = ssd;
- ctx->mb_rc[qscale][mb].bits = ac_bits + dc_bits + 12 +
+ 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];
}
return 0;
@@ -664,7 +771,7 @@ static int dnxhd_encode_thread(AVCodecContext *avctx, void *arg,
DNXHDEncContext *ctx = avctx->priv_data;
int mb_y = jobnr, mb_x;
ctx = ctx->thread[threadnr];
- init_put_bits(&ctx->m.pb, (uint8_t *)arg + 640 + ctx->slice_offs[jobnr],
+ init_put_bits(&ctx->m.pb, (uint8_t *)arg + ctx->data_offset + ctx->slice_offs[jobnr],
ctx->slice_size[jobnr]);
ctx->m.last_dc[0] =
@@ -682,7 +789,7 @@ static int dnxhd_encode_thread(AVCodecContext *avctx, void *arg,
for (i = 0; i < 8; 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, i,
+ int last_index = ctx->m.dct_quantize(&ctx->m, block, 4 & (2*i),
qscale, &overflow);
// START_TIMER;
dnxhd_encode_block(ctx, block, last_index, n);
@@ -730,7 +837,7 @@ static int dnxhd_mb_var_thread(AVCodecContext *avctx, void *arg,
int sum;
int varc;
- if (!partial_last_row && mb_x * 16 <= avctx->width - 16) {
+ if (!partial_last_row && mb_x * 16 <= avctx->width - 16 && (avctx->width % 16) == 0) {
sum = ctx->m.mpvencdsp.pix_sum(pix, ctx->m.linesize);
varc = ctx->m.mpvencdsp.pix_norm1(pix, ctx->m.linesize);
} else {
@@ -758,11 +865,13 @@ static int dnxhd_mb_var_thread(AVCodecContext *avctx, void *arg,
unsigned mb = mb_y * ctx->m.mb_width + mb_x;
int sum = 0;
int sqsum = 0;
+ int bw = FFMIN(avctx->width - 16 * mb_x, 16);
+ int bh = FFMIN((avctx->height >> ctx->interlaced) - 16 * mb_y, 16);
int mean, sqmean;
int i, j;
// Macroblocks are 16x16 pixels, unlike DCT blocks which are 8x8.
- for (i = 0; i < 16; ++i) {
- for (j = 0; j < 16; ++j) {
+ for (i = 0; i < bh; ++i) {
+ for (j = 0; j < bw; ++j) {
// Turn 16-bit pixels into 10-bit ones.
const int sample = (unsigned) pix[j] >> 6;
sum += sample;
@@ -806,17 +915,20 @@ static int dnxhd_encode_rdo(AVCodecContext *avctx, DNXHDEncContext *ctx)
unsigned min = UINT_MAX;
int qscale = 1;
int mb = y * ctx->m.mb_width + x;
+ int rc = 0;
for (q = 1; q < avctx->qmax; q++) {
- unsigned score = ctx->mb_rc[q][mb].bits * lambda +
- ((unsigned) ctx->mb_rc[q][mb].ssd << LAMBDA_FRAC_BITS);
+ int i = (q*ctx->m.mb_num) + mb;
+ unsigned score = ctx->mb_rc[i].bits * lambda +
+ ((unsigned) ctx->mb_rc[i].ssd << LAMBDA_FRAC_BITS);
if (score < min) {
min = score;
qscale = q;
+ rc = i;
}
}
- bits += ctx->mb_rc[qscale][mb].bits;
+ bits += ctx->mb_rc[rc].bits;
ctx->mb_qscale[mb] = qscale;
- ctx->mb_bits[mb] = ctx->mb_rc[qscale][mb].bits;
+ ctx->mb_bits[mb] = ctx->mb_rc[rc].bits;
}
bits = (bits + 31) & ~31; // padding
if (bits > ctx->frame_bits)
@@ -873,7 +985,7 @@ static int dnxhd_find_qscale(DNXHDEncContext *ctx)
NULL, NULL, ctx->m.mb_height);
for (y = 0; y < ctx->m.mb_height; y++) {
for (x = 0; x < ctx->m.mb_width; x++)
- bits += ctx->mb_rc[qscale][y*ctx->m.mb_width+x].bits;
+ bits += ctx->mb_rc[(qscale*ctx->m.mb_num) + (y*ctx->m.mb_width+x)].bits;
bits = (bits+31)&~31; // padding
if (bits > ctx->frame_bits)
break;
@@ -932,13 +1044,13 @@ static void radix_count(const RCCMPEntry *data, int size,
buckets[j][get_bucket(v, 0)]++;
v >>= BUCKET_BITS;
}
- assert(!v);
+ av_assert1(!v);
}
for (j = 0; j < RADIX_PASSES; j++) {
int offset = size;
for (i = NBUCKETS - 1; i >= 0; i--)
buckets[j][i] = offset -= buckets[j][i];
- assert(!buckets[j][0]);
+ av_assert1(!buckets[j][0]);
}
}
@@ -954,10 +1066,9 @@ static void radix_sort_pass(RCCMPEntry *dst, const RCCMPEntry *data,
}
}
-static void radix_sort(RCCMPEntry *data, int size)
+static void radix_sort(RCCMPEntry *data, RCCMPEntry *tmp, int size)
{
int buckets[RADIX_PASSES][NBUCKETS];
- RCCMPEntry *tmp = av_malloc(sizeof(*tmp) * size);
radix_count(data, size, buckets);
radix_sort_pass(tmp, data, size, buckets[0], 0);
radix_sort_pass(data, tmp, size, buckets[1], 1);
@@ -965,7 +1076,6 @@ static void radix_sort(RCCMPEntry *data, int size)
radix_sort_pass(tmp, data, size, buckets[2], 2);
radix_sort_pass(data, tmp, size, buckets[3], 3);
}
- av_free(tmp);
}
static int dnxhd_encode_fast(AVCodecContext *avctx, DNXHDEncContext *ctx)
@@ -977,17 +1087,18 @@ static int dnxhd_encode_fast(AVCodecContext *avctx, DNXHDEncContext *ctx)
for (y = 0; y < ctx->m.mb_height; y++) {
for (x = 0; x < ctx->m.mb_width; x++) {
int mb = y * ctx->m.mb_width + x;
+ int rc = (ctx->qscale * ctx->m.mb_num ) + mb;
int delta_bits;
ctx->mb_qscale[mb] = ctx->qscale;
- ctx->mb_bits[mb] = ctx->mb_rc[ctx->qscale][mb].bits;
- max_bits += ctx->mb_rc[ctx->qscale][mb].bits;
+ ctx->mb_bits[mb] = ctx->mb_rc[rc].bits;
+ max_bits += ctx->mb_rc[rc].bits;
if (!RC_VARIANCE) {
- delta_bits = ctx->mb_rc[ctx->qscale][mb].bits -
- ctx->mb_rc[ctx->qscale + 1][mb].bits;
+ delta_bits = ctx->mb_rc[rc].bits -
+ ctx->mb_rc[rc + ctx->m.mb_num].bits;
ctx->mb_cmp[mb].mb = mb;
ctx->mb_cmp[mb].value =
- delta_bits ? ((ctx->mb_rc[ctx->qscale][mb].ssd -
- ctx->mb_rc[ctx->qscale + 1][mb].ssd) * 100) /
+ delta_bits ? ((ctx->mb_rc[rc].ssd -
+ ctx->mb_rc[rc + ctx->m.mb_num].ssd) * 100) /
delta_bits
: INT_MIN; // avoid increasing qscale
}
@@ -998,13 +1109,14 @@ static int dnxhd_encode_fast(AVCodecContext *avctx, DNXHDEncContext *ctx)
if (RC_VARIANCE)
avctx->execute2(avctx, dnxhd_mb_var_thread,
NULL, NULL, ctx->m.mb_height);
- radix_sort(ctx->mb_cmp, ctx->m.mb_num);
+ radix_sort(ctx->mb_cmp, ctx->mb_cmp_tmp, ctx->m.mb_num);
for (x = 0; x < ctx->m.mb_num && max_bits > ctx->frame_bits; x++) {
int mb = ctx->mb_cmp[x].mb;
- max_bits -= ctx->mb_rc[ctx->qscale][mb].bits -
- ctx->mb_rc[ctx->qscale + 1][mb].bits;
+ int rc = (ctx->qscale * ctx->m.mb_num ) + mb;
+ max_bits -= ctx->mb_rc[rc].bits -
+ ctx->mb_rc[rc + ctx->m.mb_num].bits;
ctx->mb_qscale[mb] = ctx->qscale + 1;
- ctx->mb_bits[mb] = ctx->mb_rc[ctx->qscale + 1][mb].bits;
+ ctx->mb_bits[mb] = ctx->mb_rc[rc + ctx->m.mb_num].bits;
}
}
return 0;
@@ -1035,13 +1147,10 @@ static int dnxhd_encode_picture(AVCodecContext *avctx, AVPacket *pkt,
DNXHDEncContext *ctx = avctx->priv_data;
int first_field = 1;
int offset, i, ret;
- uint8_t *buf, *sd;
+ uint8_t *buf;
- if ((ret = ff_alloc_packet(pkt, ctx->cid_table->frame_size)) < 0) {
- av_log(avctx, AV_LOG_ERROR,
- "output buffer is too small to compress picture\n");
+ if ((ret = ff_alloc_packet2(avctx, pkt, ctx->frame_size, 0)) < 0)
return ret;
- }
buf = pkt->data;
dnxhd_load_picture(ctx, frame);
@@ -1071,21 +1180,21 @@ encode_coding_unit:
for (i = 0; i < ctx->m.mb_height; i++) {
AV_WB32(ctx->msip + i * 4, offset);
offset += ctx->slice_size[i];
- assert(!(ctx->slice_size[i] & 3));
+ av_assert1(!(ctx->slice_size[i] & 3));
}
avctx->execute2(avctx, dnxhd_encode_thread, buf, NULL, ctx->m.mb_height);
- assert(640 + offset + 4 <= ctx->cid_table->coding_unit_size);
- memset(buf + 640 + offset, 0,
- ctx->cid_table->coding_unit_size - 4 - offset - 640);
+ av_assert1(ctx->data_offset + offset + 4 <= ctx->coding_unit_size);
+ memset(buf + ctx->data_offset + offset, 0,
+ ctx->coding_unit_size - 4 - offset - ctx->data_offset);
- AV_WB32(buf + ctx->cid_table->coding_unit_size - 4, 0x600DC0DE); // EOF
+ AV_WB32(buf + ctx->coding_unit_size - 4, 0x600DC0DE); // EOF
if (ctx->interlaced && first_field) {
first_field = 0;
ctx->cur_field ^= 1;
- buf += ctx->cid_table->coding_unit_size;
+ buf += ctx->coding_unit_size;
goto encode_coding_unit;
}
@@ -1095,10 +1204,7 @@ FF_DISABLE_DEPRECATION_WARNINGS
FF_ENABLE_DEPRECATION_WARNINGS
#endif
- sd = av_packet_new_side_data(pkt, AV_PKT_DATA_QUALITY_FACTOR, sizeof(int));
- if (!sd)
- return AVERROR(ENOMEM);
- *(int *)sd = ctx->qscale * FF_QP2LAMBDA;
+ ff_side_data_set_encoder_stats(pkt, ctx->qscale * FF_QP2LAMBDA, NULL, 0, AV_PICTURE_TYPE_I);
pkt->flags |= AV_PKT_FLAG_KEY;
*got_packet = 1;
@@ -1120,6 +1226,7 @@ static av_cold int dnxhd_encode_end(AVCodecContext *avctx)
av_freep(&ctx->mb_qscale);
av_freep(&ctx->mb_rc);
av_freep(&ctx->mb_cmp);
+ av_freep(&ctx->mb_cmp_tmp);
av_freep(&ctx->slice_size);
av_freep(&ctx->slice_offs);
@@ -1134,6 +1241,11 @@ static av_cold int dnxhd_encode_end(AVCodecContext *avctx)
return 0;
}
+static const AVCodecDefault dnxhd_defaults[] = {
+ { "qmax", "1024" }, /* Maximum quantization scale factor allowed for VC-3 */
+ { NULL },
+};
+
AVCodec ff_dnxhd_encoder = {
.name = "dnxhd",
.long_name = NULL_IF_CONFIG_SMALL("VC3/DNxHD"),
@@ -1149,5 +1261,7 @@ AVCodec ff_dnxhd_encoder = {
AV_PIX_FMT_YUV422P10,
AV_PIX_FMT_NONE
},
- .priv_class = &class,
+ .priv_class = &dnxhd_class,
+ .defaults = dnxhd_defaults,
+ .profiles = NULL_IF_CONFIG_SMALL(ff_dnxhd_profiles),
};