diff options
author | Kieran Kunhya <kieran@kunhya.com> | 2018-08-19 02:31:42 +0100 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2018-08-25 22:08:19 +0200 |
commit | 844ff494696e75221e718278139a0db5766ae797 (patch) | |
tree | ed4f0bf7102b2bf7e4a73a1d5b5dad68879ddcca | |
parent | 323095a6db670041f3c98724c0e9c4a494c55bb9 (diff) | |
download | ffmpeg-844ff494696e75221e718278139a0db5766ae797.tar.gz |
mpeg4video: Add Studio DPCM support
-rw-r--r-- | libavcodec/mpeg4videodec.c | 91 | ||||
-rw-r--r-- | libavcodec/mpegvideo.c | 73 | ||||
-rw-r--r-- | libavcodec/mpegvideo.h | 2 |
3 files changed, 146 insertions, 20 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) { diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index f75c0fd9b3..d4d3bea649 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -390,6 +390,8 @@ static int init_duplicate_context(MpegEncContext *s) } FF_ALLOCZ_OR_GOTO(s->avctx, s->block32, sizeof(*s->block32), fail) + s->dpcm_direction = 0; + FF_ALLOCZ_OR_GOTO(s->avctx, s->dpcm_macroblock, sizeof(*s->dpcm_macroblock), fail) if (s->avctx->codec_tag == AV_RL32("VCR2")) { // exchange uv @@ -427,6 +429,7 @@ static void free_duplicate_context(MpegEncContext *s) av_freep(&s->me.score_map); av_freep(&s->blocks); av_freep(&s->block32); + av_freep(&s->dpcm_macroblock); av_freep(&s->ac_val_base); s->block = NULL; } @@ -445,6 +448,8 @@ static void backup_duplicate_context(MpegEncContext *bak, MpegEncContext *src) COPY(blocks); COPY(block); COPY(block32); + COPY(dpcm_macroblock); + COPY(dpcm_direction); COPY(start_mb_y); COPY(end_mb_y); COPY(me.map_generation); @@ -820,6 +825,8 @@ static void clear_context(MpegEncContext *s) s->blocks = NULL; s->block32 = NULL; memset(s->pblocks, 0, sizeof(s->pblocks)); + s->dpcm_direction = 0; + s->dpcm_macroblock = NULL; s->ac_val_base = NULL; s->ac_val[0] = s->ac_val[1] = @@ -2132,23 +2139,55 @@ void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], TODO: Integrate 10-bit properly into mpegvideo.c so that ER works properly */ if (s->avctx->bits_per_raw_sample > 8){ const int act_block_size = block_size * 2; - s->idsp.idct_put(dest_y, dct_linesize, (int16_t*)(*s->block32)[0]); - s->idsp.idct_put(dest_y + act_block_size, dct_linesize, (int16_t*)(*s->block32)[1]); - s->idsp.idct_put(dest_y + dct_offset, dct_linesize, (int16_t*)(*s->block32)[2]); - s->idsp.idct_put(dest_y + dct_offset + act_block_size, dct_linesize, (int16_t*)(*s->block32)[3]); - - dct_linesize = uvlinesize << s->interlaced_dct; - dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size; - - s->idsp.idct_put(dest_cb, dct_linesize, (int16_t*)(*s->block32)[4]); - s->idsp.idct_put(dest_cr, dct_linesize, (int16_t*)(*s->block32)[5]); - s->idsp.idct_put(dest_cb + dct_offset, dct_linesize, (int16_t*)(*s->block32)[6]); - s->idsp.idct_put(dest_cr + dct_offset, dct_linesize, (int16_t*)(*s->block32)[7]); - if(!s->chroma_x_shift){//Chroma444 - s->idsp.idct_put(dest_cb + act_block_size, dct_linesize, (int16_t*)(*s->block32)[8]); - s->idsp.idct_put(dest_cr + act_block_size, dct_linesize, (int16_t*)(*s->block32)[9]); - s->idsp.idct_put(dest_cb + act_block_size + dct_offset, dct_linesize, (int16_t*)(*s->block32)[10]); - s->idsp.idct_put(dest_cr + act_block_size + dct_offset, dct_linesize, (int16_t*)(*s->block32)[11]); + + if(s->dpcm_direction == 0) { + s->idsp.idct_put(dest_y, dct_linesize, (int16_t*)(*s->block32)[0]); + s->idsp.idct_put(dest_y + act_block_size, dct_linesize, (int16_t*)(*s->block32)[1]); + s->idsp.idct_put(dest_y + dct_offset, dct_linesize, (int16_t*)(*s->block32)[2]); + s->idsp.idct_put(dest_y + dct_offset + act_block_size, dct_linesize, (int16_t*)(*s->block32)[3]); + + dct_linesize = uvlinesize << s->interlaced_dct; + dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size; + + s->idsp.idct_put(dest_cb, dct_linesize, (int16_t*)(*s->block32)[4]); + s->idsp.idct_put(dest_cr, dct_linesize, (int16_t*)(*s->block32)[5]); + s->idsp.idct_put(dest_cb + dct_offset, dct_linesize, (int16_t*)(*s->block32)[6]); + s->idsp.idct_put(dest_cr + dct_offset, dct_linesize, (int16_t*)(*s->block32)[7]); + if(!s->chroma_x_shift){//Chroma444 + s->idsp.idct_put(dest_cb + act_block_size, dct_linesize, (int16_t*)(*s->block32)[8]); + s->idsp.idct_put(dest_cr + act_block_size, dct_linesize, (int16_t*)(*s->block32)[9]); + s->idsp.idct_put(dest_cb + act_block_size + dct_offset, dct_linesize, (int16_t*)(*s->block32)[10]); + s->idsp.idct_put(dest_cr + act_block_size + dct_offset, dct_linesize, (int16_t*)(*s->block32)[11]); + } + } else if(s->dpcm_direction == 1) { + int i, w, h; + uint16_t *dest_pcm[3] = {(uint16_t*)dest_y, (uint16_t*)dest_cb, (uint16_t*)dest_cr}; + int linesize[3] = {dct_linesize, uvlinesize, uvlinesize}; + for(i = 0; i < 3; i++) { + int idx = 0; + int vsub = i ? s->chroma_y_shift : 0; + int hsub = i ? s->chroma_x_shift : 0; + for(h = 0; h < (16 >> vsub); h++){ + for(w = 0; w < (16 >> hsub); w++) + dest_pcm[i][w] = (*s->dpcm_macroblock)[i][idx++]; + dest_pcm[i] += linesize[i] / 2; + } + } + } else if(s->dpcm_direction == -1) { + int i, w, h; + uint16_t *dest_pcm[3] = {(uint16_t*)dest_y, (uint16_t*)dest_cb, (uint16_t*)dest_cr}; + int linesize[3] = {dct_linesize, uvlinesize, uvlinesize}; + for(i = 0; i < 3; i++) { + int idx = 0; + int vsub = i ? s->chroma_y_shift : 0; + int hsub = i ? s->chroma_x_shift : 0; + dest_pcm[i] += (linesize[i] / 2) * ((16 >> vsub) - 1); + for(h = (16 >> vsub)-1; h >= 1; h--){ + for(w = (16 >> hsub)-1; w >= 1; w--) + dest_pcm[i][w] = (*s->dpcm_macroblock)[i][idx++]; + dest_pcm[i] -= linesize[i] / 2; + } + } } } /* dct only in intra block */ diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index e16deb64e7..bbc6b5646a 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -509,6 +509,8 @@ typedef struct MpegEncContext { int (*decode_mb)(struct MpegEncContext *s, int16_t block[12][64]); // used by some codecs to avoid a switch() int32_t (*block32)[12][64]; + int dpcm_direction; // 0 = DCT, 1 = DPCM top to bottom scan, -1 = DPCM bottom to top scan + int16_t (*dpcm_macroblock)[3][256]; #define SLICE_OK 0 #define SLICE_ERROR -1 |