From 844ff494696e75221e718278139a0db5766ae797 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Sun, 19 Aug 2018 02:31:42 +0100 Subject: mpeg4video: Add Studio DPCM support --- libavcodec/mpeg4videodec.c | 91 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 3 deletions(-) (limited to 'libavcodec/mpeg4videodec.c') diff --git a/libavcodec/mpeg4videodec.c b/libavcodec/mpeg4videodec.c index 1686ed1001..4c77081237 100644 --- a/libavcodec/mpeg4videodec.c +++ b/libavcodec/mpeg4videodec.c @@ -24,6 +24,7 @@ #include "libavutil/internal.h" #include "libavutil/opt.h" +#include "libavutil/pixdesc.h" #include "error_resilience.h" #include "hwaccel.h" #include "idctdsp.h" @@ -36,6 +37,7 @@ #include "profiles.h" #include "thread.h" #include "xvididct.h" +#include "unary.h" /* The defines below define the number of bits that are read at once for * reading vlc values. Changing these may improve speed and data cache needs @@ -1923,10 +1925,91 @@ static int mpeg4_decode_studio_block(MpegEncContext *s, int32_t block[64], int n return 0; } +static int mpeg4_decode_dpcm_macroblock(MpegEncContext *s, int16_t macroblock[256], int n) +{ + int i, j, w, h, idx = 0; + int block_mean, rice_parameter, rice_prefix_code, rice_suffix_code, + dpcm_residual, left, top, topleft, min_left_top, max_left_top, p, p2, output; + h = 16 >> (n ? s->chroma_y_shift : 0); + w = 16 >> (n ? s->chroma_x_shift : 0); + + block_mean = get_bits(&s->gb, s->avctx->bits_per_raw_sample); + if (block_mean == 0){ + av_log(s->avctx, AV_LOG_ERROR, "Forbidden block_mean\n"); + return AVERROR_INVALIDDATA; + } + s->last_dc[n] = block_mean * (1 << (s->dct_precision + s->intra_dc_precision)); + + rice_parameter = get_bits(&s->gb, 4); + if (rice_parameter == 0) { + av_log(s->avctx, AV_LOG_ERROR, "Forbidden rice_parameter\n"); + return AVERROR_INVALIDDATA; + } + + if (rice_parameter == 15) + rice_parameter = 0; + + if (rice_parameter > 11) { + av_log(s->avctx, AV_LOG_ERROR, "Forbidden rice_parameter\n"); + return AVERROR_INVALIDDATA; + } + + for (i = 0; i < h; i++) { + output = 1 << (s->avctx->bits_per_raw_sample - 1); + top = 1 << (s->avctx->bits_per_raw_sample - 1); + + for (j = 0; j < w; j++) { + left = output; + topleft = top; + + rice_prefix_code = get_unary(&s->gb, 1, 12); + + /* Escape */ + if (rice_prefix_code == 11) + dpcm_residual = get_bits(&s->gb, s->avctx->bits_per_raw_sample); + else { + rice_suffix_code = get_bitsz(&s->gb, rice_parameter); + dpcm_residual = (rice_prefix_code << rice_parameter) + rice_suffix_code; + } + + /* Map to a signed residual */ + if (dpcm_residual & 1) + dpcm_residual = (-1 * dpcm_residual) >> 1; + else + dpcm_residual = (dpcm_residual >> 1); + + if (i != 0) + top = macroblock[idx-w]; + + p = left + top - topleft; + min_left_top = FFMIN(left, top); + if (p < min_left_top) + p = min_left_top; + + max_left_top = FFMAX(left, top); + if (p > max_left_top) + p = max_left_top; + + p2 = (FFMIN(min_left_top, topleft) + FFMAX(max_left_top, topleft)) >> 1; + if (p2 == p) + p2 = block_mean; + + if (p2 > p) + dpcm_residual *= -1; + + macroblock[idx++] = output = (dpcm_residual + p) & ((1 << s->avctx->bits_per_raw_sample) - 1); + } + } + + return 0; +} + static int mpeg4_decode_studio_mb(MpegEncContext *s, int16_t block_[12][64]) { int i; + s->dpcm_direction = 0; + /* StudioMacroblock */ /* Assumes I-VOP */ s->mb_intra = 1; @@ -1945,9 +2028,11 @@ static int mpeg4_decode_studio_mb(MpegEncContext *s, int16_t block_[12][64]) } else { /* DPCM */ check_marker(s->avctx, &s->gb, "DPCM block start"); - avpriv_request_sample(s->avctx, "DPCM encoded block"); - next_start_code_studio(&s->gb); - return SLICE_ERROR; + s->dpcm_direction = get_bits1(&s->gb) ? -1 : 1; + for (i = 0; i < 3; i++) { + if (mpeg4_decode_dpcm_macroblock(s, (*s->dpcm_macroblock)[i], i) < 0) + return AVERROR_INVALIDDATA; + } } if (get_bits_left(&s->gb) >= 24 && show_bits(&s->gb, 23) == 0) { -- cgit v1.2.3