📄 vp3.c
字号:
{ 0, 0, 0, 0},
{ 0, 0, 0,128}, // PL
{ 0, 0,128, 0}, // PUR
{ 0, 0, 53, 75}, // PUR|PL
{ 0,128, 0, 0}, // PU
{ 0, 64, 0, 64}, // PU|PL
{ 0,128, 0, 0}, // PU|PUR
{ 0, 0, 53, 75}, // PU|PUR|PL
{128, 0, 0, 0}, // PUL
{ 0, 0, 0,128}, // PUL|PL
{ 64, 0, 64, 0}, // PUL|PUR
{ 0, 0, 53, 75}, // PUL|PUR|PL
{ 0,128, 0, 0}, // PUL|PU
{-104,116, 0,116}, // PUL|PU|PL
{ 24, 80, 24, 0}, // PUL|PU|PUR
{-104,116, 0,116} // PUL|PU|PUR|PL
};
/* This table shows which types of blocks can use other blocks for
* prediction. For example, INTRA is the only mode in this table to
* have a frame number of 0. That means INTRA blocks can only predict
* from other INTRA blocks. There are 2 golden frame coding types;
* blocks encoding in these modes can only predict from other blocks
* that were encoded with these 1 of these 2 modes. */
unsigned char compatible_frame[8] = {
1, /* MODE_INTER_NO_MV */
0, /* MODE_INTRA */
1, /* MODE_INTER_PLUS_MV */
1, /* MODE_INTER_LAST_MV */
1, /* MODE_INTER_PRIOR_MV */
2, /* MODE_USING_GOLDEN */
2, /* MODE_GOLDEN_MV */
1 /* MODE_INTER_FOUR_MV */
};
int current_frame_type;
/* there is a last DC predictor for each of the 3 frame types */
short last_dc[3];
int transform = 0;
debug_vp3(" vp3: reversing DC prediction\n");
vul = vu = vur = vl = 0;
last_dc[0] = last_dc[1] = last_dc[2] = 0;
/* for each fragment row... */
for (y = 0; y < fragment_height; y++) {
/* for each fragment in a row... */
for (x = 0; x < fragment_width; x++, i++) {
/* reverse prediction if this block was coded */
if (s->all_fragments[i].coding_method != MODE_COPY) {
current_frame_type =
compatible_frame[s->all_fragments[i].coding_method];
debug_dc_pred(" frag %d: orig DC = %d, ",
i, DC_COEFF(i));
transform= 0;
if(x){
l= i-1;
vl = DC_COEFF(l);
if(FRAME_CODED(l) && COMPATIBLE_FRAME(l))
transform |= PL;
}
if(y){
u= i-fragment_width;
vu = DC_COEFF(u);
if(FRAME_CODED(u) && COMPATIBLE_FRAME(u))
transform |= PU;
if(x){
ul= i-fragment_width-1;
vul = DC_COEFF(ul);
if(FRAME_CODED(ul) && COMPATIBLE_FRAME(ul))
transform |= PUL;
}
if(x + 1 < fragment_width){
ur= i-fragment_width+1;
vur = DC_COEFF(ur);
if(FRAME_CODED(ur) && COMPATIBLE_FRAME(ur))
transform |= PUR;
}
}
debug_dc_pred("transform = %d, ", transform);
if (transform == 0) {
/* if there were no fragments to predict from, use last
* DC saved */
predicted_dc = last_dc[current_frame_type];
debug_dc_pred("from last DC (%d) = %d\n",
current_frame_type, DC_COEFF(i));
} else {
/* apply the appropriate predictor transform */
predicted_dc =
(predictor_transform[transform][0] * vul) +
(predictor_transform[transform][1] * vu) +
(predictor_transform[transform][2] * vur) +
(predictor_transform[transform][3] * vl);
predicted_dc /= 128;
/* check for outranging on the [ul u l] and
* [ul u ur l] predictors */
if ((transform == 13) || (transform == 15)) {
if (FFABS(predicted_dc - vu) > 128)
predicted_dc = vu;
else if (FFABS(predicted_dc - vl) > 128)
predicted_dc = vl;
else if (FFABS(predicted_dc - vul) > 128)
predicted_dc = vul;
}
debug_dc_pred("from pred DC = %d\n",
DC_COEFF(i));
}
/* at long last, apply the predictor */
if(s->coeffs[i].index){
*s->next_coeff= s->coeffs[i];
s->coeffs[i].index=0;
s->coeffs[i].coeff=0;
s->coeffs[i].next= s->next_coeff++;
}
s->coeffs[i].coeff += predicted_dc;
/* save the DC */
last_dc[current_frame_type] = DC_COEFF(i);
if(DC_COEFF(i) && !(s->all_fragments[i].coeff_count&127)){
s->all_fragments[i].coeff_count= 129;
// s->all_fragments[i].next_coeff= s->next_coeff;
s->coeffs[i].next= s->next_coeff;
(s->next_coeff++)->next=NULL;
}
}
}
}
}
static void horizontal_filter(unsigned char *first_pixel, int stride,
int *bounding_values);
static void vertical_filter(unsigned char *first_pixel, int stride,
int *bounding_values);
/*
* Perform the final rendering for a particular slice of data.
* The slice number ranges from 0..(macroblock_height - 1).
*/
static void render_slice(Vp3DecodeContext *s, int slice)
{
int x;
int m, n;
int16_t *dequantizer;
DECLARE_ALIGNED_16(DCTELEM, block[64]);
int motion_x = 0xdeadbeef, motion_y = 0xdeadbeef;
int motion_halfpel_index;
uint8_t *motion_source;
int plane;
int current_macroblock_entry = slice * s->macroblock_width * 6;
if (slice >= s->macroblock_height)
return;
for (plane = 0; plane < 3; plane++) {
uint8_t *output_plane = s->current_frame.data [plane];
uint8_t * last_plane = s-> last_frame.data [plane];
uint8_t *golden_plane = s-> golden_frame.data [plane];
int stride = s->current_frame.linesize[plane];
int plane_width = s->width >> !!plane;
int plane_height = s->height >> !!plane;
int y = slice * FRAGMENT_PIXELS << !plane ;
int slice_height = y + (FRAGMENT_PIXELS << !plane);
int i = s->macroblock_fragments[current_macroblock_entry + plane + 3*!!plane];
if (!s->flipped_image) stride = -stride;
if(FFABS(stride) > 2048)
return; //various tables are fixed size
/* for each fragment row in the slice (both of them)... */
for (; y < slice_height; y += 8) {
/* for each fragment in a row... */
for (x = 0; x < plane_width; x += 8, i++) {
if ((i < 0) || (i >= s->fragment_count)) {
av_log(s->avctx, AV_LOG_ERROR, " vp3:render_slice(): bad fragment number (%d)\n", i);
return;
}
/* transform if this block was coded */
if ((s->all_fragments[i].coding_method != MODE_COPY) &&
!((s->avctx->flags & CODEC_FLAG_GRAY) && plane)) {
if ((s->all_fragments[i].coding_method == MODE_USING_GOLDEN) ||
(s->all_fragments[i].coding_method == MODE_GOLDEN_MV))
motion_source= golden_plane;
else
motion_source= last_plane;
motion_source += s->all_fragments[i].first_pixel;
motion_halfpel_index = 0;
/* sort out the motion vector if this fragment is coded
* using a motion vector method */
if ((s->all_fragments[i].coding_method > MODE_INTRA) &&
(s->all_fragments[i].coding_method != MODE_USING_GOLDEN)) {
int src_x, src_y;
motion_x = s->all_fragments[i].motion_x;
motion_y = s->all_fragments[i].motion_y;
if(plane){
motion_x= (motion_x>>1) | (motion_x&1);
motion_y= (motion_y>>1) | (motion_y&1);
}
src_x= (motion_x>>1) + x;
src_y= (motion_y>>1) + y;
if ((motion_x == 127) || (motion_y == 127))
av_log(s->avctx, AV_LOG_ERROR, " help! got invalid motion vector! (%X, %X)\n", motion_x, motion_y);
motion_halfpel_index = motion_x & 0x01;
motion_source += (motion_x >> 1);
motion_halfpel_index |= (motion_y & 0x01) << 1;
motion_source += ((motion_y >> 1) * stride);
if(src_x<0 || src_y<0 || src_x + 9 >= plane_width || src_y + 9 >= plane_height){
uint8_t *temp= s->edge_emu_buffer;
if(stride<0) temp -= 9*stride;
else temp += 9*stride;
ff_emulated_edge_mc(temp, motion_source, stride, 9, 9, src_x, src_y, plane_width, plane_height);
motion_source= temp;
}
}
/* first, take care of copying a block from either the
* previous or the golden frame */
if (s->all_fragments[i].coding_method != MODE_INTRA) {
/* Note, it is possible to implement all MC cases with
put_no_rnd_pixels_l2 which would look more like the
VP3 source but this would be slower as
put_no_rnd_pixels_tab is better optimzed */
if(motion_halfpel_index != 3){
s->dsp.put_no_rnd_pixels_tab[1][motion_halfpel_index](
output_plane + s->all_fragments[i].first_pixel,
motion_source, stride, 8);
}else{
int d= (motion_x ^ motion_y)>>31; // d is 0 if motion_x and _y have the same sign, else -1
s->dsp.put_no_rnd_pixels_l2[1](
output_plane + s->all_fragments[i].first_pixel,
motion_source - d,
motion_source + stride + 1 + d,
stride, 8);
}
dequantizer = s->qmat[1][plane];
}else{
dequantizer = s->qmat[0][plane];
}
/* dequantize the DCT coefficients */
debug_idct("fragment %d, coding mode %d, DC = %d, dequant = %d:\n",
i, s->all_fragments[i].coding_method,
DC_COEFF(i), dequantizer[0]);
if(s->avctx->idct_algo==FF_IDCT_VP3){
Coeff *coeff= s->coeffs + i;
memset(block, 0, sizeof(block));
while(coeff->next){
block[coeff->index]= coeff->coeff * dequantizer[coeff->index];
coeff= coeff->next;
}
}else{
Coeff *coeff= s->coeffs + i;
memset(block, 0, sizeof(block));
while(coeff->next){
block[coeff->index]= (coeff->coeff * dequantizer[coeff->index] + 2)>>2;
coeff= coeff->next;
}
}
/* invert DCT and place (or add) in final output */
if (s->all_fragments[i].coding_method == MODE_INTRA) {
if(s->avctx->idct_algo!=FF_IDCT_VP3)
block[0] += 128<<3;
s->dsp.idct_put(
output_plane + s->all_fragments[i].first_pixel,
stride,
block);
} else {
s->dsp.idct_add(
output_plane + s->all_fragments[i].first_pixel,
stride,
block);
}
debug_idct("block after idct_%s():\n",
(s->all_fragments[i].coding_method == MODE_INTRA)?
"put" : "add");
for (m = 0; m < 8; m++) {
for (n = 0; n < 8; n++) {
debug_idct(" %3d", *(output_plane +
s->all_fragments[i].first_pixel + (m * stride + n)));
}
debug_idct("\n");
}
debug_idct("\n");
} else {
/* copy directly from the previous frame */
s->dsp.put_pixels_tab[1][0](
output_plane + s->all_fragments[i].first_pixel,
last_plane + s->all_fragments[i].first_pixel,
stride, 8);
}
#if 0
/* perform the left edge filter if:
* - the fragment is not on the left column
* - the fragment is coded in this frame
* - the fragment is not coded in this frame but the left
* fragment is coded in this frame (this is done instead
* of a right edge filter when rendering the left fragment
* since this fragment is not available yet) */
if ((x > 0) &&
((s->all_fragments[i].coding_method != MODE_COPY) ||
((s->all_fra
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -