mirror of
https://github.com/xenia-project/FFmpeg.git
synced 2024-11-24 03:59:43 +00:00
mpeg4video: Add Studio DPCM support
This commit is contained in:
parent
323095a6db
commit
844ff49469
@ -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) {
|
||||
|
@ -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;
|
||||
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]);
|
||||
|
||||
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]);
|
||||
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 */
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user