*
* VC-3 encoder funded by the British Broadcasting Corporation
*
- * This file is part of FFmpeg.
+ * This file is part of Libav.
*
- * FFmpeg is free software; you can redistribute it and/or
+ * Libav 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,
+ * Libav 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
+ * License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
//#define DEBUG
#define RC_VARIANCE 1 // use variance or ssd for fast rc
+#include "libavutil/opt.h"
#include "avcodec.h"
#include "dsputil.h"
#include "mpegvideo.h"
#include "dnxhdenc.h"
+#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), FF_OPT_TYPE_INT, 0, 0, 1, VE},
+{NULL}
+};
+static const AVClass class = { "dnxhd", av_default_item_name, options, LIBAVUTIL_VERSION_INT };
+
int dct_quantize_c(MpegEncContext *s, DCTELEM *block, int n, int qscale, int *overflow);
#define LAMBDA_FRAC_BITS 10
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) * 8;
+ ctx->frame_bits = (ctx->cid_table->coding_unit_size - 640 - 4 - ctx->min_padding) * 8;
ctx->qscale = 1;
ctx->lambda = 2<<LAMBDA_FRAC_BITS; // qscale 2
return 0;
if (dnxhd_init_qmat(ctx, ctx->m.intra_quant_bias, 0) < 0) // XXX tune lbias/cbias
return -1;
+ // Avid Nitris hardware decoder requires a minimum amount of padding in the coding unit payload
+ if (ctx->nitris_compat)
+ ctx->min_padding = 1600;
+
if (dnxhd_init_vlc(ctx) < 0)
return -1;
if (dnxhd_init_rc(ctx) < 0)
FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->mb_qscale, ctx->m.mb_num *sizeof(uint8_t) , fail);
ctx->frame.key_frame = 1;
- ctx->frame.pict_type = FF_I_TYPE;
+ ctx->frame.pict_type = AV_PICTURE_TYPE_I;
ctx->m.avctx->coded_frame = &ctx->frame;
if (avctx->thread_count > MAX_THREADS) {
buf[5] = ctx->interlaced ? ctx->cur_field+2 : 0x01;
buf[6] = 0x80; // crc flag off
buf[7] = 0xa0; // reserved
- AV_WB16(buf + 0x18, avctx->height); // ALPF
+ AV_WB16(buf + 0x18, avctx->height>>ctx->interlaced); // ALPF
AV_WB16(buf + 0x1a, avctx->width); // SPL
- AV_WB16(buf + 0x1d, avctx->height); // NAL
+ AV_WB16(buf + 0x1d, avctx->height>>ctx->interlaced); // NAL
buf[0x21] = 0x38; // FIXME 8 bit per comp
- buf[0x22] = 0x88 + (ctx->frame.interlaced_frame<<2);
+ buf[0x22] = 0x88 + (ctx->interlaced<<2);
AV_WB32(buf + 0x28, ctx->cid); // CID
buf[0x2c] = ctx->interlaced ? 0 : 0x80;
DNXHDEncContext *ctx = avctx->priv_data;
int mb_y = jobnr, mb_x;
int qscale = ctx->qscale;
+ LOCAL_ALIGNED_16(DCTELEM, block, [64]);
ctx = ctx->thread[threadnr];
- ctx->m.last_dc[0] =
- ctx->m.last_dc[1] =
- ctx->m.last_dc[2] = 1024;
+ ctx->m.last_dc[0] =
+ ctx->m.last_dc[1] =
+ ctx->m.last_dc[2] = 1024;
- for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) {
- unsigned mb = mb_y * ctx->m.mb_width + mb_x;
- int ssd = 0;
- int ac_bits = 0;
- int dc_bits = 0;
- int i;
+ for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) {
+ unsigned mb = mb_y * ctx->m.mb_width + mb_x;
+ int ssd = 0;
+ int ac_bits = 0;
+ int dc_bits = 0;
+ int i;
- dnxhd_get_blocks(ctx, mb_x, mb_y);
+ dnxhd_get_blocks(ctx, mb_x, mb_y);
- for (i = 0; i < 8; i++) {
- DECLARE_ALIGNED_16(DCTELEM, block[64]);
- DCTELEM *src_block = ctx->blocks[i];
- int overflow, nbits, diff, last_index;
- int n = dnxhd_switch_matrix(ctx, i);
+ for (i = 0; i < 8; i++) {
+ DCTELEM *src_block = ctx->blocks[i];
+ int overflow, nbits, diff, last_index;
+ int n = dnxhd_switch_matrix(ctx, i);
- memcpy(block, src_block, sizeof(block));
- last_index = ctx->m.dct_quantize((MpegEncContext*)ctx, block, i, qscale, &overflow);
- ac_bits += dnxhd_calc_ac_bits(ctx, block, last_index);
+ memcpy(block, src_block, 64*sizeof(*block));
+ last_index = ctx->m.dct_quantize((MpegEncContext*)ctx, block, i, qscale, &overflow);
+ ac_bits += dnxhd_calc_ac_bits(ctx, block, last_index);
- diff = block[0] - ctx->m.last_dc[n];
- if (diff < 0) nbits = av_log2_16bit(-2*diff);
- else nbits = av_log2_16bit( 2*diff);
- dc_bits += ctx->cid_table->dc_bits[nbits] + nbits;
+ diff = block[0] - ctx->m.last_dc[n];
+ if (diff < 0) nbits = av_log2_16bit(-2*diff);
+ else nbits = av_log2_16bit( 2*diff);
+ dc_bits += ctx->cid_table->dc_bits[nbits] + nbits;
- ctx->m.last_dc[n] = block[0];
+ ctx->m.last_dc[n] = block[0];
- if (avctx->mb_decision == FF_MB_DECISION_RD || !RC_VARIANCE) {
- dnxhd_unquantize_c(ctx, block, i, qscale, last_index);
- ctx->m.dsp.idct(block);
- ssd += dnxhd_ssd_block(block, src_block);
- }
+ if (avctx->mb_decision == FF_MB_DECISION_RD || !RC_VARIANCE) {
+ dnxhd_unquantize_c(ctx, block, i, qscale, last_index);
+ ctx->m.dsp.idct(block);
+ 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+8*ctx->vlc_bits[0];
}
+ ctx->mb_rc[qscale][mb].ssd = ssd;
+ ctx->mb_rc[qscale][mb].bits = ac_bits+dc_bits+12+8*ctx->vlc_bits[0];
+ }
return 0;
}
ctx = ctx->thread[threadnr];
init_put_bits(&ctx->m.pb, (uint8_t *)arg + 640 + ctx->slice_offs[jobnr], ctx->slice_size[jobnr]);
- ctx->m.last_dc[0] =
- ctx->m.last_dc[1] =
- ctx->m.last_dc[2] = 1024;
- 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);
-
- dnxhd_get_blocks(ctx, mb_x, mb_y);
-
- for (i = 0; i < 8; i++) {
- DCTELEM *block = ctx->blocks[i];
- int last_index, overflow;
- int n = dnxhd_switch_matrix(ctx, i);
- last_index = ctx->m.dct_quantize((MpegEncContext*)ctx, block, i, qscale, &overflow);
- //START_TIMER;
- dnxhd_encode_block(ctx, block, last_index, n);
- //STOP_TIMER("encode_block");
- }
+ ctx->m.last_dc[0] =
+ ctx->m.last_dc[1] =
+ ctx->m.last_dc[2] = 1024;
+ 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);
+
+ dnxhd_get_blocks(ctx, mb_x, mb_y);
+
+ for (i = 0; i < 8; i++) {
+ DCTELEM *block = ctx->blocks[i];
+ int last_index, overflow;
+ int n = dnxhd_switch_matrix(ctx, i);
+ last_index = ctx->m.dct_quantize((MpegEncContext*)ctx, block, i, qscale, &overflow);
+ //START_TIMER;
+ dnxhd_encode_block(ctx, block, last_index, n);
+ //STOP_TIMER("encode_block");
}
- if (put_bits_count(&ctx->m.pb)&31)
- put_bits(&ctx->m.pb, 32-(put_bits_count(&ctx->m.pb)&31), 0);
+ }
+ if (put_bits_count(&ctx->m.pb)&31)
+ put_bits(&ctx->m.pb, 32-(put_bits_count(&ctx->m.pb)&31), 0);
flush_put_bits(&ctx->m.pb);
return 0;
}
DNXHDEncContext *ctx = avctx->priv_data;
int mb_y = jobnr, mb_x;
ctx = ctx->thread[threadnr];
- for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) {
- unsigned mb = mb_y * ctx->m.mb_width + mb_x;
- uint8_t *pix = ctx->thread[0]->src[0] + ((mb_y<<4) * ctx->m.linesize) + (mb_x<<4);
- int sum = ctx->m.dsp.pix_sum(pix, ctx->m.linesize);
- int varc = (ctx->m.dsp.pix_norm1(pix, ctx->m.linesize) - (((unsigned)(sum*sum))>>8)+128)>>8;
- ctx->mb_cmp[mb].value = varc;
- ctx->mb_cmp[mb].mb = mb;
- }
+ for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) {
+ unsigned mb = mb_y * ctx->m.mb_width + mb_x;
+ uint8_t *pix = ctx->thread[0]->src[0] + ((mb_y<<4) * ctx->m.linesize) + (mb_x<<4);
+ int sum = ctx->m.dsp.pix_sum(pix, ctx->m.linesize);
+ int varc = (ctx->m.dsp.pix_norm1(pix, ctx->m.linesize) - (((unsigned)(sum*sum))>>8)+128)>>8;
+ ctx->mb_cmp[mb].value = varc;
+ ctx->mb_cmp[mb].mb = mb;
+ }
return 0;
}
if (bits > ctx->frame_bits)
break;
}
- //dprintf(ctx->m.avctx, "lambda %d, up %u, down %u, bits %d, frame %d\n",
+ //av_dlog(ctx->m.avctx, "lambda %d, up %u, down %u, bits %d, frame %d\n",
// lambda, last_higher, last_lower, bits, ctx->frame_bits);
if (end) {
if (bits > ctx->frame_bits)
last_higher = FFMAX(lambda, last_higher);
if (last_lower != INT_MAX)
lambda = (lambda+last_lower)>>1;
+ else if ((int64_t)lambda + up_step > INT_MAX)
+ return -1;
else
lambda += up_step;
- up_step *= 5;
+ up_step = FFMIN((int64_t)up_step*5, INT_MAX);
down_step = 1<<LAMBDA_FRAC_BITS;
}
}
- //dprintf(ctx->m.avctx, "out lambda %d\n", lambda);
+ //av_dlog(ctx->m.avctx, "out lambda %d\n", lambda);
ctx->lambda = lambda;
return 0;
}
if (bits > ctx->frame_bits)
break;
}
- //dprintf(ctx->m.avctx, "%d, qscale %d, bits %d, frame %d, higher %d, lower %d\n",
+ //av_dlog(ctx->m.avctx, "%d, qscale %d, bits %d, frame %d, higher %d, lower %d\n",
// ctx->m.avctx->frame_number, qscale, bits, ctx->frame_bits, last_higher, last_lower);
if (bits < ctx->frame_bits) {
if (qscale == 1)
return -1;
}
}
- //dprintf(ctx->m.avctx, "out qscale %d\n", qscale);
+ //av_dlog(ctx->m.avctx, "out qscale %d\n", qscale);
ctx->qscale = qscale;
return 0;
}
else
ret = dnxhd_encode_fast(avctx, ctx);
if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "picture could not fit ratecontrol constraints\n");
+ av_log(avctx, AV_LOG_ERROR,
+ "picture could not fit ratecontrol constraints, increase qmax\n");
return -1;
}
return 0;
}
-AVCodec dnxhd_encoder = {
+AVCodec ff_dnxhd_encoder = {
"dnxhd",
- CODEC_TYPE_VIDEO,
+ AVMEDIA_TYPE_VIDEO,
CODEC_ID_DNXHD,
sizeof(DNXHDEncContext),
dnxhd_encode_init,
dnxhd_encode_picture,
dnxhd_encode_end,
+ .capabilities = CODEC_CAP_SLICE_THREADS,
.pix_fmts = (const enum PixelFormat[]){PIX_FMT_YUV422P, PIX_FMT_NONE},
.long_name = NULL_IF_CONFIG_SMALL("VC3/DNxHD"),
+ .priv_class = &class,
};