[FFmpeg-devel] [PATCH] 10-bit DNxHD decoding and encoding
Baptiste Coudurier
baptiste.coudurier at gmail.com
Wed Mar 23 18:08:46 CET 2011
Hi,
On 03/23/2011 08:28 AM, Joseph Artsimovich wrote:
> Hi,
>
> This patch addresses concerns raised over my previosly submitted patch and also adds support for encoding in addition to decoding. Please review. To test encoding, do:
> ffmpeg -i source.mov -b 185M -pix_fmt yuv422p16 -vcodec dnxhd -y target.mov
> I uploaded a sample file called 10bit_dnxhd_interlaced_normal.mov to upload.ffmpeg.org
>
> [...]
>
> -static const uint16_t dnxhd_1238_run_codes[62] = {
> +static const uint16_t dnxhd_1235_1238_1241_run_codes[62] = {
> 0, 4, 10, 11, 24, 25, 26, 27, 56, 57, 58, 59, 120, 242, 486, 487, 488, 489, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023,
Please rename in a separate patch.
> [...]
>
> @@ -40,6 +43,7 @@ typedef struct {
> VLC ac_vlc, dc_vlc, run_vlc;
> int last_dc[3];
> DSPContext dsp;
> + int dsp_bits; // 8, 10 or 0 if not initialized.
bit_depth is a better name IMHO.
> [...]
>
> @@ -59,6 +62,33 @@ static av_always_inline void dnxhd_get_pixels_8x4(DCTELEM *restrict block, const
> memcpy(block+24, block-32, sizeof(*block)*8);
> }
>
> +static av_always_inline void dnxhd_10bit_get_pixels_8x8(DCTELEM *restrict block, const uint16_t *pixels, int line_size)
> +{
> + for (int i = 0; i < 8; ++i) {
> + for (int j = 0; j < 8; ++j) {
> + block[j] = (DCTELEM)floor((float)pixels[j] * (1023.0f / 65535.0f) + 0.5f);
Btw, why are you using floats here ?
> [...]
> unsigned mb = mb_y * ctx->m.mb_width + mb_x;
> @@ -425,7 +531,11 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg, int jobnr, i
> int dc_bits = 0;
> int i;
>
> - dnxhd_get_blocks(ctx, mb_x, mb_y);
> + if (ctx->cid_table->bit_depth == 10) {
> + dnxhd_10bit_get_blocks(ctx, mb_x, mb_y);
> + } else {
> + dnxhd_get_blocks(ctx, mb_x, mb_y);
> + }
I think a function pointer in context would be better.
> for (i = 0; i < 8; i++) {
> DCTELEM *src_block = ctx->blocks[i];
> @@ -439,6 +549,8 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg, int jobnr, i
> diff = block[0] - ctx->m.last_dc[n];
> if (diff < 0) nbits = av_log2_16bit(-2*diff);
> else nbits = av_log2_16bit( 2*diff);
> +
> + assert(nbits < ctx->cid_table->bit_depth + 4);
assert would kill the program.
> [...]
>
> };
>
> +// To get DCT coefficients multiplied by 4.
Shouldn't we avoid returning scaled output, could be usefull for 11,12
bits, etc..
> [...]
>
> diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h
> index 3e447ab..eb2352f 100644
> --- a/libavcodec/mpegvideo.h
> +++ b/libavcodec/mpegvideo.h
> @@ -49,7 +49,19 @@ enum OutputFormat {
> #define MPEG_BUF_SIZE (16 * 1024)
>
> #define QMAT_SHIFT_MMX 16
> -#define QMAT_SHIFT 22
> +
> +/*
> + * QMAT_SHIFT should be as high as possible, but not so high to cause
> + * overflow in the following expression:
> + * scaled_dct[i] * ((p / s) * ((1 << QMAT_SHIFT) / (qscale * weight_table[i]))))
> + * where s is a scale factor applied to DCT coefficients while
> + * p and weight_table are codec-specific.
> + * For example, the worst case for 10-bit DNxHD would be:
> + * p == 32, s == 4, qscale == 1, weight_table[i] == 32, scaled_dct[i] == (1 << 13) * 4
> + * which gives (1 << 15) * (((1 << QMAT_SHIFT) >> 5) << 3)
> + * which gives 18 as the largest safe QMAT_SHIFT.
> + */
> +#define QMAT_SHIFT 18
>
> #define MAX_FCODE 7
> #define MAX_MV 2048
> diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c
> index 9255fa8..3f46033 100644
> --- a/libavcodec/mpegvideo_enc.c
> +++ b/libavcodec/mpegvideo_enc.c
> @@ -3725,9 +3725,14 @@ int dct_quantize_c(MpegEncContext *s,
> else
> q = s->c_dc_scale;
> q = q << 3;
> - } else
> + } else {
> /* For AIC we skip quant/dequant of INTRADC */
> - q = 1 << 3;
> + if (s->dsp.fdct == ff_faandct_10bit_safe) {
> + q = 1 << 2;
> + } else {
> + q = 1 << 3; // The post-scale applied to a DCT output.
> + }
> + }
>
> /* note: block[0] is assumed to be positive */
> block[0] = (block[0] + (q >> 1)) / q;
dct_quantize_mmx/sse2/etc .. is used if present, see QMAX_SHIFT_MMX.
I think it's time to separate the dnxhd quantization fonction from the
mpeg one and change QMAT_SHIFT only there.
Remove MpegEncContext from DNxHDEncContext, add dnxhd_template_mmx.c in
x86 and clean it up (intra only, out format, aic only etc..)
--
Baptiste COUDURIER
Key fingerprint 8D77134D20CC9220201FC5DB0AC9325C5C1ABAAA
FFmpeg maintainer http://www.ffmpeg.org
More information about the ffmpeg-devel
mailing list