summaryrefslogtreecommitdiff
path: root/libavcodec/mpeg4videodec.c
diff options
context:
space:
mode:
authorKieran Kunhya <kieran@kunhya.com>2018-08-19 02:31:42 +0100
committerPaul B Mahol <onemda@gmail.com>2018-08-25 22:08:19 +0200
commit844ff494696e75221e718278139a0db5766ae797 (patch)
treeed4f0bf7102b2bf7e4a73a1d5b5dad68879ddcca /libavcodec/mpeg4videodec.c
parent323095a6db670041f3c98724c0e9c4a494c55bb9 (diff)
mpeg4video: Add Studio DPCM support
Diffstat (limited to 'libavcodec/mpeg4videodec.c')
-rw-r--r--libavcodec/mpeg4videodec.c91
1 files changed, 88 insertions, 3 deletions
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) {