2010-05-18 17:58:33 +02:00
|
|
|
/*
|
2010-09-09 14:16:39 +02:00
|
|
|
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
2010-05-18 17:58:33 +02:00
|
|
|
*
|
2010-06-09 17:29:20 +02:00
|
|
|
* Use of this source code is governed by a BSD-style license
|
2010-06-04 22:19:40 +02:00
|
|
|
* that can be found in the LICENSE file in the root of the source
|
|
|
|
* tree. An additional intellectual property rights grant can be found
|
2010-06-09 17:29:20 +02:00
|
|
|
* in the file PATENTS. All contributing project authors may
|
2010-06-04 22:19:40 +02:00
|
|
|
* be found in the AUTHORS file in the root of the source tree.
|
2010-05-18 17:58:33 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
New RTCD implementation
This is a proof of concept RTCD implementation to replace the current
system of nested includes, prototypes, INVOKE macros, etc. Currently
only the decoder specific functions are implemented in the new system.
Additional functions will be added in subsequent commits.
Overview:
RTCD "functions" are implemented as either a global function pointer
or a macro (when only one eligible specialization available).
Functions which have RTCD specializations are listed using a simple
DSL identifying the function's base name, its prototype, and the
architecture extensions that specializations are available for.
Advantages over the old system:
- No INVOKE macros. A call to an RTCD function looks like an ordinary
function call.
- No need to pass vtables around.
- If there is only one eligible function to call, the function is
called directly, rather than indirecting through a function pointer.
- Supports the notion of "required" extensions, so in combination with
the above, on x86_64 if the best function available is sse2 or lower
it will be called directly, since all x86_64 platforms implement
sse2.
- Elides all references to functions which will never be called, which
could reduce binary size. For example if sse2 is required and there
are both mmx and sse2 implementations of a certain function, the
code will have no link time references to the mmx code.
- Significantly easier to add a new function, just one file to edit.
Disadvantages:
- Requires global writable data (though this is not a new requirement)
- 1 new generated source file.
Change-Id: Iae6edab65315f79c168485c96872641c5aa09d55
2011-08-19 20:06:00 +02:00
|
|
|
#include "vpx_config.h"
|
2012-11-09 02:09:30 +01:00
|
|
|
#include "vp8_rtcd.h"
|
|
|
|
#include "./vpx_scale_rtcd.h"
|
2010-05-18 17:58:33 +02:00
|
|
|
#include "onyxd_int.h"
|
2011-02-10 20:41:38 +01:00
|
|
|
#include "vp8/common/header.h"
|
|
|
|
#include "vp8/common/reconintra4x4.h"
|
|
|
|
#include "vp8/common/reconinter.h"
|
2010-05-18 17:58:33 +02:00
|
|
|
#include "detokenize.h"
|
2011-02-10 20:41:38 +01:00
|
|
|
#include "vp8/common/invtrans.h"
|
|
|
|
#include "vp8/common/alloccommon.h"
|
|
|
|
#include "vp8/common/entropymode.h"
|
|
|
|
#include "vp8/common/quant_common.h"
|
2012-12-03 23:19:49 +01:00
|
|
|
#include "vpx_scale/vpx_scale.h"
|
2011-02-10 20:41:38 +01:00
|
|
|
#include "vp8/common/setupintrarecon.h"
|
2010-09-09 20:42:48 +02:00
|
|
|
|
2010-05-18 17:58:33 +02:00
|
|
|
#include "decodemv.h"
|
2011-02-10 20:41:38 +01:00
|
|
|
#include "vp8/common/extend.h"
|
2011-05-02 15:30:51 +02:00
|
|
|
#if CONFIG_ERROR_CONCEALMENT
|
|
|
|
#include "error_concealment.h"
|
|
|
|
#endif
|
2010-05-18 17:58:33 +02:00
|
|
|
#include "vpx_mem/vpx_mem.h"
|
2011-02-10 20:41:38 +01:00
|
|
|
#include "vp8/common/threading.h"
|
2010-05-18 17:58:33 +02:00
|
|
|
#include "decoderthreading.h"
|
|
|
|
#include "dboolhuff.h"
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
void vp8cx_init_de_quantizer(VP8D_COMP *pbi)
|
|
|
|
{
|
|
|
|
int Q;
|
|
|
|
VP8_COMMON *const pc = & pbi->common;
|
|
|
|
|
|
|
|
for (Q = 0; Q < QINDEX_RANGE; Q++)
|
|
|
|
{
|
2010-10-22 02:04:30 +02:00
|
|
|
pc->Y1dequant[Q][0] = (short)vp8_dc_quant(Q, pc->y1dc_delta_q);
|
|
|
|
pc->Y2dequant[Q][0] = (short)vp8_dc2quant(Q, pc->y2dc_delta_q);
|
|
|
|
pc->UVdequant[Q][0] = (short)vp8_dc_uv_quant(Q, pc->uvdc_delta_q);
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-01-04 17:56:50 +01:00
|
|
|
pc->Y1dequant[Q][1] = (short)vp8_ac_yquant(Q);
|
|
|
|
pc->Y2dequant[Q][1] = (short)vp8_ac2quant(Q, pc->y2ac_delta_q);
|
|
|
|
pc->UVdequant[Q][1] = (short)vp8_ac_uv_quant(Q, pc->uvac_delta_q);
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-04 21:23:53 +02:00
|
|
|
void vp8_mb_init_dequantizer(VP8D_COMP *pbi, MACROBLOCKD *xd)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int QIndex;
|
|
|
|
MB_MODE_INFO *mbmi = &xd->mode_info_context->mbmi;
|
|
|
|
VP8_COMMON *const pc = & pbi->common;
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Decide whether to use the default or alternate baseline Q value. */
|
2010-05-18 17:58:33 +02:00
|
|
|
if (xd->segmentation_enabled)
|
|
|
|
{
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Abs Value */
|
2010-05-18 17:58:33 +02:00
|
|
|
if (xd->mb_segement_abs_delta == SEGMENT_ABSDATA)
|
|
|
|
QIndex = xd->segment_feature_data[MB_LVL_ALT_Q][mbmi->segment_id];
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Delta Value */
|
2010-05-18 17:58:33 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
QIndex = pc->base_qindex + xd->segment_feature_data[MB_LVL_ALT_Q][mbmi->segment_id];
|
2010-10-28 01:04:02 +02:00
|
|
|
QIndex = (QIndex >= 0) ? ((QIndex <= MAXQ) ? QIndex : MAXQ) : 0; /* Clamp to valid range */
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
QIndex = pc->base_qindex;
|
|
|
|
|
2012-01-04 17:56:50 +01:00
|
|
|
/* Set up the macroblock dequant constants */
|
|
|
|
xd->dequant_y1_dc[0] = 1;
|
|
|
|
xd->dequant_y1[0] = pc->Y1dequant[QIndex][0];
|
|
|
|
xd->dequant_y2[0] = pc->Y2dequant[QIndex][0];
|
|
|
|
xd->dequant_uv[0] = pc->UVdequant[QIndex][0];
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-01-04 17:56:50 +01:00
|
|
|
for (i = 1; i < 16; i++)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2012-01-04 17:56:50 +01:00
|
|
|
xd->dequant_y1_dc[i] =
|
|
|
|
xd->dequant_y1[i] = pc->Y1dequant[QIndex][1];
|
|
|
|
xd->dequant_y2[i] = pc->Y2dequant[QIndex][1];
|
|
|
|
xd->dequant_uv[i] = pc->UVdequant[QIndex][1];
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-02 15:30:51 +02:00
|
|
|
static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd,
|
|
|
|
unsigned int mb_idx)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2011-06-28 16:22:13 +02:00
|
|
|
MB_PREDICTION_MODE mode;
|
|
|
|
int i;
|
2012-02-29 16:38:14 +01:00
|
|
|
#if CONFIG_ERROR_CONCEALMENT
|
2011-12-16 19:48:01 +01:00
|
|
|
int corruption_detected = 0;
|
2012-02-29 16:38:14 +01:00
|
|
|
#endif
|
2010-05-28 20:28:12 +02:00
|
|
|
|
2010-08-12 22:25:43 +02:00
|
|
|
if (xd->mode_info_context->mbmi.mb_skip_coeff)
|
2010-05-28 20:28:12 +02:00
|
|
|
{
|
|
|
|
vp8_reset_mb_tokens_context(xd);
|
|
|
|
}
|
2011-09-06 14:34:36 +02:00
|
|
|
else if (!vp8dx_bool_error(xd->current_bc))
|
2010-05-28 20:28:12 +02:00
|
|
|
{
|
2011-12-16 19:48:01 +01:00
|
|
|
int eobtotal;
|
2010-05-28 20:28:12 +02:00
|
|
|
eobtotal = vp8_decode_mb_tokens(pbi, xd);
|
2011-12-16 19:48:01 +01:00
|
|
|
|
|
|
|
/* Special case: Force the loopfilter to skip when eobtotal is zero */
|
|
|
|
xd->mode_info_context->mbmi.mb_skip_coeff = (eobtotal==0);
|
2010-05-28 20:28:12 +02:00
|
|
|
}
|
|
|
|
|
2011-12-16 19:48:01 +01:00
|
|
|
mode = xd->mode_info_context->mbmi.mode;
|
|
|
|
|
|
|
|
if (xd->segmentation_enabled)
|
2012-05-04 21:23:53 +02:00
|
|
|
vp8_mb_init_dequantizer(pbi, xd);
|
2011-09-16 17:03:53 +02:00
|
|
|
|
2010-05-28 20:28:12 +02:00
|
|
|
|
2011-12-16 19:48:01 +01:00
|
|
|
#if CONFIG_ERROR_CONCEALMENT
|
2011-06-28 16:22:13 +02:00
|
|
|
|
2011-12-16 19:48:01 +01:00
|
|
|
if(pbi->ec_active)
|
2010-05-28 20:28:12 +02:00
|
|
|
{
|
2011-12-16 19:48:01 +01:00
|
|
|
int throw_residual;
|
|
|
|
/* When we have independent partitions we can apply residual even
|
|
|
|
* though other partitions within the frame are corrupt.
|
|
|
|
*/
|
|
|
|
throw_residual = (!pbi->independent_partitions &&
|
|
|
|
pbi->frame_corrupt_residual);
|
|
|
|
throw_residual = (throw_residual || vp8dx_bool_error(xd->current_bc));
|
2011-04-26 15:37:19 +02:00
|
|
|
|
2011-12-16 19:48:01 +01:00
|
|
|
if ((mb_idx >= pbi->mvs_corrupt_from_mb || throw_residual))
|
|
|
|
{
|
|
|
|
/* MB with corrupt residuals or corrupt mode/motion vectors.
|
|
|
|
* Better to use the predictor as reconstruction.
|
|
|
|
*/
|
|
|
|
pbi->frame_corrupt_residual = 1;
|
|
|
|
vpx_memset(xd->qcoeff, 0, sizeof(xd->qcoeff));
|
|
|
|
vp8_conceal_corrupt_mb(xd);
|
|
|
|
|
|
|
|
|
|
|
|
corruption_detected = 1;
|
|
|
|
|
|
|
|
/* force idct to be skipped for B_PRED and use the
|
|
|
|
* prediction only for reconstruction
|
|
|
|
* */
|
|
|
|
vpx_memset(xd->eobs, 0, 25);
|
|
|
|
}
|
2010-05-28 20:28:12 +02:00
|
|
|
}
|
2011-12-16 19:48:01 +01:00
|
|
|
#endif
|
2010-05-28 20:28:12 +02:00
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* do prediction */
|
2011-04-21 20:59:42 +02:00
|
|
|
if (xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2012-02-21 20:59:05 +01:00
|
|
|
vp8_build_intra_predictors_mbuv_s(xd,
|
2012-03-08 21:27:41 +01:00
|
|
|
xd->recon_above[1],
|
|
|
|
xd->recon_above[2],
|
|
|
|
xd->recon_left[1],
|
|
|
|
xd->recon_left[2],
|
|
|
|
xd->recon_left_stride[1],
|
2012-03-20 20:11:42 +01:00
|
|
|
xd->dst.u_buffer, xd->dst.v_buffer,
|
|
|
|
xd->dst.uv_stride);
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2011-06-28 16:22:13 +02:00
|
|
|
if (mode != B_PRED)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2012-02-28 20:12:30 +01:00
|
|
|
vp8_build_intra_predictors_mby_s(xd,
|
2012-03-08 21:27:41 +01:00
|
|
|
xd->recon_above[0],
|
|
|
|
xd->recon_left[0],
|
|
|
|
xd->recon_left_stride[0],
|
2012-03-20 20:11:42 +01:00
|
|
|
xd->dst.y_buffer,
|
|
|
|
xd->dst.y_stride);
|
2011-12-16 19:48:01 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-01-04 17:56:50 +01:00
|
|
|
short *DQC = xd->dequant_y1;
|
2012-01-20 19:52:16 +01:00
|
|
|
int dst_stride = xd->dst.y_stride;
|
2012-01-04 17:56:50 +01:00
|
|
|
|
2011-12-16 19:48:01 +01:00
|
|
|
/* clear out residual eob info */
|
|
|
|
if(xd->mode_info_context->mbmi.mb_skip_coeff)
|
|
|
|
vpx_memset(xd->eobs, 0, 25);
|
|
|
|
|
2012-03-08 21:27:41 +01:00
|
|
|
intra_prediction_down_copy(xd, xd->recon_above[0] + 16);
|
2011-12-16 19:48:01 +01:00
|
|
|
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
{
|
|
|
|
BLOCKD *b = &xd->block[i];
|
2012-08-01 20:01:46 +02:00
|
|
|
unsigned char *dst = xd->dst.y_buffer + b->offset;
|
2012-08-02 23:26:04 +02:00
|
|
|
B_PREDICTION_MODE b_mode =
|
|
|
|
xd->mode_info_context->bmi[i].as_mode;
|
2012-08-01 20:01:46 +02:00
|
|
|
unsigned char *Above = dst - dst_stride;
|
|
|
|
unsigned char *yleft = dst - 1;
|
|
|
|
int left_stride = dst_stride;
|
|
|
|
unsigned char top_left = Above[-1];
|
2012-02-28 20:12:30 +01:00
|
|
|
|
2012-08-01 20:17:57 +02:00
|
|
|
vp8_intra4x4_predict(Above, yleft, left_stride, b_mode,
|
|
|
|
dst, dst_stride, top_left);
|
2011-12-16 19:48:01 +01:00
|
|
|
|
|
|
|
if (xd->eobs[i])
|
|
|
|
{
|
|
|
|
if (xd->eobs[i] > 1)
|
|
|
|
{
|
2012-08-01 20:01:46 +02:00
|
|
|
vp8_dequant_idct_add(b->qcoeff, DQC, dst, dst_stride);
|
2011-12-16 19:48:01 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-01-13 01:55:44 +01:00
|
|
|
vp8_dc_only_idct_add
|
2012-01-04 17:56:50 +01:00
|
|
|
(b->qcoeff[0] * DQC[0],
|
2012-08-01 20:01:46 +02:00
|
|
|
dst, dst_stride,
|
|
|
|
dst, dst_stride);
|
2011-12-16 19:48:01 +01:00
|
|
|
((int *)b->qcoeff)[0] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vp8_build_inter_predictors_mb(xd);
|
|
|
|
}
|
2011-12-16 19:48:01 +01:00
|
|
|
|
2011-08-08 10:56:20 +02:00
|
|
|
|
2011-05-02 15:30:51 +02:00
|
|
|
#if CONFIG_ERROR_CONCEALMENT
|
2011-12-16 19:48:01 +01:00
|
|
|
if (corruption_detected)
|
2011-05-02 15:30:51 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-12-16 19:48:01 +01:00
|
|
|
if(!xd->mode_info_context->mbmi.mb_skip_coeff)
|
2010-05-28 20:28:12 +02:00
|
|
|
{
|
2011-12-16 19:48:01 +01:00
|
|
|
/* dequantization and idct */
|
|
|
|
if (mode != B_PRED)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2012-01-04 17:56:50 +01:00
|
|
|
short *DQC = xd->dequant_y1;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2011-12-16 19:48:01 +01:00
|
|
|
if (mode != SPLITMV)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2011-12-16 19:48:01 +01:00
|
|
|
BLOCKD *b = &xd->block[24];
|
|
|
|
|
|
|
|
/* do 2nd order transform on the dc block */
|
|
|
|
if (xd->eobs[24] > 1)
|
2011-10-18 18:06:50 +02:00
|
|
|
{
|
New RTCD implementation
This is a proof of concept RTCD implementation to replace the current
system of nested includes, prototypes, INVOKE macros, etc. Currently
only the decoder specific functions are implemented in the new system.
Additional functions will be added in subsequent commits.
Overview:
RTCD "functions" are implemented as either a global function pointer
or a macro (when only one eligible specialization available).
Functions which have RTCD specializations are listed using a simple
DSL identifying the function's base name, its prototype, and the
architecture extensions that specializations are available for.
Advantages over the old system:
- No INVOKE macros. A call to an RTCD function looks like an ordinary
function call.
- No need to pass vtables around.
- If there is only one eligible function to call, the function is
called directly, rather than indirecting through a function pointer.
- Supports the notion of "required" extensions, so in combination with
the above, on x86_64 if the best function available is sse2 or lower
it will be called directly, since all x86_64 platforms implement
sse2.
- Elides all references to functions which will never be called, which
could reduce binary size. For example if sse2 is required and there
are both mmx and sse2 implementations of a certain function, the
code will have no link time references to the mmx code.
- Significantly easier to add a new function, just one file to edit.
Disadvantages:
- Requires global writable data (though this is not a new requirement)
- 1 new generated source file.
Change-Id: Iae6edab65315f79c168485c96872641c5aa09d55
2011-08-19 20:06:00 +02:00
|
|
|
vp8_dequantize_b(b, xd->dequant_y2);
|
2011-12-16 19:48:01 +01:00
|
|
|
|
2012-01-13 01:55:44 +01:00
|
|
|
vp8_short_inv_walsh4x4(&b->dqcoeff[0],
|
2011-12-16 19:48:01 +01:00
|
|
|
xd->qcoeff);
|
|
|
|
((int *)b->qcoeff)[0] = 0;
|
|
|
|
((int *)b->qcoeff)[1] = 0;
|
|
|
|
((int *)b->qcoeff)[2] = 0;
|
|
|
|
((int *)b->qcoeff)[3] = 0;
|
|
|
|
((int *)b->qcoeff)[4] = 0;
|
|
|
|
((int *)b->qcoeff)[5] = 0;
|
|
|
|
((int *)b->qcoeff)[6] = 0;
|
|
|
|
((int *)b->qcoeff)[7] = 0;
|
2011-10-18 18:06:50 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-01-04 17:56:50 +01:00
|
|
|
b->dqcoeff[0] = b->qcoeff[0] * xd->dequant_y2[0];
|
2012-01-13 01:55:44 +01:00
|
|
|
vp8_short_inv_walsh4x4_1(&b->dqcoeff[0],
|
2011-12-16 19:48:01 +01:00
|
|
|
xd->qcoeff);
|
2011-10-18 18:06:50 +02:00
|
|
|
((int *)b->qcoeff)[0] = 0;
|
|
|
|
}
|
2011-11-17 18:54:42 +01:00
|
|
|
|
2011-12-16 19:48:01 +01:00
|
|
|
/* override the dc dequant constant in order to preserve the
|
|
|
|
* dc components
|
|
|
|
*/
|
2012-01-04 17:56:50 +01:00
|
|
|
DQC = xd->dequant_y1_dc;
|
2011-11-17 18:54:42 +01:00
|
|
|
}
|
|
|
|
|
New RTCD implementation
This is a proof of concept RTCD implementation to replace the current
system of nested includes, prototypes, INVOKE macros, etc. Currently
only the decoder specific functions are implemented in the new system.
Additional functions will be added in subsequent commits.
Overview:
RTCD "functions" are implemented as either a global function pointer
or a macro (when only one eligible specialization available).
Functions which have RTCD specializations are listed using a simple
DSL identifying the function's base name, its prototype, and the
architecture extensions that specializations are available for.
Advantages over the old system:
- No INVOKE macros. A call to an RTCD function looks like an ordinary
function call.
- No need to pass vtables around.
- If there is only one eligible function to call, the function is
called directly, rather than indirecting through a function pointer.
- Supports the notion of "required" extensions, so in combination with
the above, on x86_64 if the best function available is sse2 or lower
it will be called directly, since all x86_64 platforms implement
sse2.
- Elides all references to functions which will never be called, which
could reduce binary size. For example if sse2 is required and there
are both mmx and sse2 implementations of a certain function, the
code will have no link time references to the mmx code.
- Significantly easier to add a new function, just one file to edit.
Disadvantages:
- Requires global writable data (though this is not a new requirement)
- 1 new generated source file.
Change-Id: Iae6edab65315f79c168485c96872641c5aa09d55
2011-08-19 20:06:00 +02:00
|
|
|
vp8_dequant_idct_add_y_block
|
2012-01-04 17:56:50 +01:00
|
|
|
(xd->qcoeff, DQC,
|
2011-12-16 19:48:01 +01:00
|
|
|
xd->dst.y_buffer,
|
|
|
|
xd->dst.y_stride, xd->eobs);
|
|
|
|
}
|
2011-11-17 18:54:42 +01:00
|
|
|
|
New RTCD implementation
This is a proof of concept RTCD implementation to replace the current
system of nested includes, prototypes, INVOKE macros, etc. Currently
only the decoder specific functions are implemented in the new system.
Additional functions will be added in subsequent commits.
Overview:
RTCD "functions" are implemented as either a global function pointer
or a macro (when only one eligible specialization available).
Functions which have RTCD specializations are listed using a simple
DSL identifying the function's base name, its prototype, and the
architecture extensions that specializations are available for.
Advantages over the old system:
- No INVOKE macros. A call to an RTCD function looks like an ordinary
function call.
- No need to pass vtables around.
- If there is only one eligible function to call, the function is
called directly, rather than indirecting through a function pointer.
- Supports the notion of "required" extensions, so in combination with
the above, on x86_64 if the best function available is sse2 or lower
it will be called directly, since all x86_64 platforms implement
sse2.
- Elides all references to functions which will never be called, which
could reduce binary size. For example if sse2 is required and there
are both mmx and sse2 implementations of a certain function, the
code will have no link time references to the mmx code.
- Significantly easier to add a new function, just one file to edit.
Disadvantages:
- Requires global writable data (though this is not a new requirement)
- 1 new generated source file.
Change-Id: Iae6edab65315f79c168485c96872641c5aa09d55
2011-08-19 20:06:00 +02:00
|
|
|
vp8_dequant_idct_add_uv_block
|
2012-01-04 17:56:50 +01:00
|
|
|
(xd->qcoeff+16*16, xd->dequant_uv,
|
2011-12-16 19:48:01 +01:00
|
|
|
xd->dst.u_buffer, xd->dst.v_buffer,
|
|
|
|
xd->dst.uv_stride, xd->eobs+16);
|
2011-06-28 16:22:13 +02:00
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int get_delta_q(vp8_reader *bc, int prev, int *q_update)
|
|
|
|
{
|
|
|
|
int ret_val = 0;
|
|
|
|
|
|
|
|
if (vp8_read_bit(bc))
|
|
|
|
{
|
|
|
|
ret_val = vp8_read_literal(bc, 4);
|
|
|
|
|
|
|
|
if (vp8_read_bit(bc))
|
|
|
|
ret_val = -ret_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Trigger a quantizer update if the delta-q value has changed */
|
|
|
|
if (ret_val != prev)
|
|
|
|
*q_update = 1;
|
|
|
|
|
|
|
|
return ret_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef PACKET_TESTING
|
|
|
|
#include <stdio.h>
|
|
|
|
FILE *vpxlog = 0;
|
|
|
|
#endif
|
|
|
|
|
2012-08-21 21:42:49 +02:00
|
|
|
static void yv12_extend_frame_top_c(YV12_BUFFER_CONFIG *ybf)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
unsigned char *src_ptr1;
|
|
|
|
unsigned char *dest_ptr1;
|
|
|
|
|
|
|
|
unsigned int Border;
|
|
|
|
int plane_stride;
|
|
|
|
|
|
|
|
/***********/
|
|
|
|
/* Y Plane */
|
|
|
|
/***********/
|
|
|
|
Border = ybf->border;
|
|
|
|
plane_stride = ybf->y_stride;
|
|
|
|
src_ptr1 = ybf->y_buffer - Border;
|
|
|
|
dest_ptr1 = src_ptr1 - (Border * plane_stride);
|
|
|
|
|
|
|
|
for (i = 0; i < (int)Border; i++)
|
|
|
|
{
|
|
|
|
vpx_memcpy(dest_ptr1, src_ptr1, plane_stride);
|
|
|
|
dest_ptr1 += plane_stride;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***********/
|
|
|
|
/* U Plane */
|
|
|
|
/***********/
|
|
|
|
plane_stride = ybf->uv_stride;
|
|
|
|
Border /= 2;
|
|
|
|
src_ptr1 = ybf->u_buffer - Border;
|
|
|
|
dest_ptr1 = src_ptr1 - (Border * plane_stride);
|
|
|
|
|
|
|
|
for (i = 0; i < (int)(Border); i++)
|
|
|
|
{
|
|
|
|
vpx_memcpy(dest_ptr1, src_ptr1, plane_stride);
|
|
|
|
dest_ptr1 += plane_stride;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********/
|
|
|
|
/* V Plane */
|
|
|
|
/***********/
|
|
|
|
|
|
|
|
src_ptr1 = ybf->v_buffer - Border;
|
|
|
|
dest_ptr1 = src_ptr1 - (Border * plane_stride);
|
|
|
|
|
|
|
|
for (i = 0; i < (int)(Border); i++)
|
|
|
|
{
|
|
|
|
vpx_memcpy(dest_ptr1, src_ptr1, plane_stride);
|
|
|
|
dest_ptr1 += plane_stride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void yv12_extend_frame_bottom_c(YV12_BUFFER_CONFIG *ybf)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
unsigned char *src_ptr1, *src_ptr2;
|
|
|
|
unsigned char *dest_ptr2;
|
|
|
|
|
|
|
|
unsigned int Border;
|
|
|
|
int plane_stride;
|
|
|
|
int plane_height;
|
|
|
|
|
|
|
|
/***********/
|
|
|
|
/* Y Plane */
|
|
|
|
/***********/
|
|
|
|
Border = ybf->border;
|
|
|
|
plane_stride = ybf->y_stride;
|
|
|
|
plane_height = ybf->y_height;
|
|
|
|
|
|
|
|
src_ptr1 = ybf->y_buffer - Border;
|
|
|
|
src_ptr2 = src_ptr1 + (plane_height * plane_stride) - plane_stride;
|
|
|
|
dest_ptr2 = src_ptr2 + plane_stride;
|
|
|
|
|
|
|
|
for (i = 0; i < (int)Border; i++)
|
|
|
|
{
|
|
|
|
vpx_memcpy(dest_ptr2, src_ptr2, plane_stride);
|
|
|
|
dest_ptr2 += plane_stride;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***********/
|
|
|
|
/* U Plane */
|
|
|
|
/***********/
|
|
|
|
plane_stride = ybf->uv_stride;
|
|
|
|
plane_height = ybf->uv_height;
|
|
|
|
Border /= 2;
|
|
|
|
|
|
|
|
src_ptr1 = ybf->u_buffer - Border;
|
|
|
|
src_ptr2 = src_ptr1 + (plane_height * plane_stride) - plane_stride;
|
|
|
|
dest_ptr2 = src_ptr2 + plane_stride;
|
|
|
|
|
|
|
|
for (i = 0; i < (int)(Border); i++)
|
|
|
|
{
|
|
|
|
vpx_memcpy(dest_ptr2, src_ptr2, plane_stride);
|
|
|
|
dest_ptr2 += plane_stride;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********/
|
|
|
|
/* V Plane */
|
|
|
|
/***********/
|
|
|
|
|
|
|
|
src_ptr1 = ybf->v_buffer - Border;
|
|
|
|
src_ptr2 = src_ptr1 + (plane_height * plane_stride) - plane_stride;
|
|
|
|
dest_ptr2 = src_ptr2 + plane_stride;
|
|
|
|
|
|
|
|
for (i = 0; i < (int)(Border); i++)
|
|
|
|
{
|
|
|
|
vpx_memcpy(dest_ptr2, src_ptr2, plane_stride);
|
|
|
|
dest_ptr2 += plane_stride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void yv12_extend_frame_left_right_c(YV12_BUFFER_CONFIG *ybf,
|
|
|
|
unsigned char *y_src,
|
|
|
|
unsigned char *u_src,
|
|
|
|
unsigned char *v_src)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
unsigned char *src_ptr1, *src_ptr2;
|
|
|
|
unsigned char *dest_ptr1, *dest_ptr2;
|
|
|
|
|
|
|
|
unsigned int Border;
|
|
|
|
int plane_stride;
|
|
|
|
int plane_height;
|
|
|
|
int plane_width;
|
|
|
|
|
|
|
|
/***********/
|
|
|
|
/* Y Plane */
|
|
|
|
/***********/
|
|
|
|
Border = ybf->border;
|
|
|
|
plane_stride = ybf->y_stride;
|
|
|
|
plane_height = 16;
|
|
|
|
plane_width = ybf->y_width;
|
|
|
|
|
|
|
|
/* copy the left and right most columns out */
|
|
|
|
src_ptr1 = y_src;
|
|
|
|
src_ptr2 = src_ptr1 + plane_width - 1;
|
|
|
|
dest_ptr1 = src_ptr1 - Border;
|
|
|
|
dest_ptr2 = src_ptr2 + 1;
|
|
|
|
|
|
|
|
for (i = 0; i < plane_height; i++)
|
|
|
|
{
|
|
|
|
vpx_memset(dest_ptr1, src_ptr1[0], Border);
|
|
|
|
vpx_memset(dest_ptr2, src_ptr2[0], Border);
|
|
|
|
src_ptr1 += plane_stride;
|
|
|
|
src_ptr2 += plane_stride;
|
|
|
|
dest_ptr1 += plane_stride;
|
|
|
|
dest_ptr2 += plane_stride;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********/
|
|
|
|
/* U Plane */
|
|
|
|
/***********/
|
|
|
|
plane_stride = ybf->uv_stride;
|
|
|
|
plane_height = 8;
|
|
|
|
plane_width = ybf->uv_width;
|
|
|
|
Border /= 2;
|
|
|
|
|
|
|
|
/* copy the left and right most columns out */
|
|
|
|
src_ptr1 = u_src;
|
|
|
|
src_ptr2 = src_ptr1 + plane_width - 1;
|
|
|
|
dest_ptr1 = src_ptr1 - Border;
|
|
|
|
dest_ptr2 = src_ptr2 + 1;
|
|
|
|
|
|
|
|
for (i = 0; i < plane_height; i++)
|
|
|
|
{
|
|
|
|
vpx_memset(dest_ptr1, src_ptr1[0], Border);
|
|
|
|
vpx_memset(dest_ptr2, src_ptr2[0], Border);
|
|
|
|
src_ptr1 += plane_stride;
|
|
|
|
src_ptr2 += plane_stride;
|
|
|
|
dest_ptr1 += plane_stride;
|
|
|
|
dest_ptr2 += plane_stride;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********/
|
|
|
|
/* V Plane */
|
|
|
|
/***********/
|
|
|
|
|
|
|
|
/* copy the left and right most columns out */
|
|
|
|
src_ptr1 = v_src;
|
|
|
|
src_ptr2 = src_ptr1 + plane_width - 1;
|
|
|
|
dest_ptr1 = src_ptr1 - Border;
|
|
|
|
dest_ptr2 = src_ptr2 + 1;
|
|
|
|
|
|
|
|
for (i = 0; i < plane_height; i++)
|
|
|
|
{
|
|
|
|
vpx_memset(dest_ptr1, src_ptr1[0], Border);
|
|
|
|
vpx_memset(dest_ptr2, src_ptr2[0], Border);
|
|
|
|
src_ptr1 += plane_stride;
|
|
|
|
src_ptr2 += plane_stride;
|
|
|
|
dest_ptr1 += plane_stride;
|
|
|
|
dest_ptr2 += plane_stride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
static void decode_mb_rows(VP8D_COMP *pbi)
|
|
|
|
{
|
|
|
|
VP8_COMMON *const pc = & pbi->common;
|
|
|
|
MACROBLOCKD *const xd = & pbi->mb;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-08-02 20:58:09 +02:00
|
|
|
MODE_INFO *lf_mic = xd->mode_info_context;
|
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
int ibc = 0;
|
|
|
|
int num_part = 1 << pc->multi_token_partition;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
|
|
|
int recon_yoffset, recon_uvoffset;
|
2012-02-29 16:38:14 +01:00
|
|
|
int mb_row, mb_col;
|
|
|
|
int mb_idx = 0;
|
2012-09-24 21:44:45 +02:00
|
|
|
|
|
|
|
YV12_BUFFER_CONFIG *yv12_fb_new = pbi->dec_fb_ref[INTRA_FRAME];
|
|
|
|
|
|
|
|
int recon_y_stride = yv12_fb_new->y_stride;
|
|
|
|
int recon_uv_stride = yv12_fb_new->uv_stride;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
unsigned char *ref_buffer[MAX_REF_FRAMES][3];
|
|
|
|
unsigned char *dst_buffer[3];
|
2012-08-02 20:58:09 +02:00
|
|
|
unsigned char *lf_dst[3];
|
2012-08-21 21:42:49 +02:00
|
|
|
unsigned char *eb_dst[3];
|
2012-02-29 16:38:14 +01:00
|
|
|
int i;
|
|
|
|
int ref_fb_corrupted[MAX_REF_FRAMES];
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
ref_fb_corrupted[INTRA_FRAME] = 0;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
for(i = 1; i < MAX_REF_FRAMES; i++)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2012-09-24 21:44:45 +02:00
|
|
|
YV12_BUFFER_CONFIG *this_fb = pbi->dec_fb_ref[i];
|
2011-05-02 15:30:51 +02:00
|
|
|
|
2012-09-24 21:44:45 +02:00
|
|
|
ref_buffer[i][0] = this_fb->y_buffer;
|
|
|
|
ref_buffer[i][1] = this_fb->u_buffer;
|
|
|
|
ref_buffer[i][2] = this_fb->v_buffer;
|
|
|
|
|
|
|
|
ref_fb_corrupted[i] = this_fb->corrupted;
|
2012-02-29 16:38:14 +01:00
|
|
|
}
|
|
|
|
|
2012-08-02 20:58:09 +02:00
|
|
|
/* Set up the buffer pointers */
|
2012-09-24 21:44:45 +02:00
|
|
|
eb_dst[0] = lf_dst[0] = dst_buffer[0] = yv12_fb_new->y_buffer;
|
|
|
|
eb_dst[1] = lf_dst[1] = dst_buffer[1] = yv12_fb_new->u_buffer;
|
|
|
|
eb_dst[2] = lf_dst[2] = dst_buffer[2] = yv12_fb_new->v_buffer;
|
2012-02-29 16:38:14 +01:00
|
|
|
|
|
|
|
xd->up_available = 0;
|
|
|
|
|
2012-08-02 20:58:09 +02:00
|
|
|
/* Initialize the loop filter for this frame. */
|
|
|
|
if(pc->filter_level)
|
|
|
|
vp8_loop_filter_frame_init(pc, xd, pc->filter_level);
|
|
|
|
|
2012-09-24 21:44:45 +02:00
|
|
|
vp8_setup_intra_recon_top_line(yv12_fb_new);
|
2012-09-13 20:51:27 +02:00
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
/* Decode the individual macro block */
|
|
|
|
for (mb_row = 0; mb_row < pc->mb_rows; mb_row++)
|
|
|
|
{
|
|
|
|
if (num_part > 1)
|
2011-05-02 15:30:51 +02:00
|
|
|
{
|
2012-02-29 16:38:14 +01:00
|
|
|
xd->current_bc = & pbi->mbc[ibc];
|
|
|
|
ibc++;
|
|
|
|
|
|
|
|
if (ibc == num_part)
|
|
|
|
ibc = 0;
|
2011-05-02 15:30:51 +02:00
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
recon_yoffset = mb_row * recon_y_stride * 16;
|
|
|
|
recon_uvoffset = mb_row * recon_uv_stride * 8;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
/* reset contexts */
|
|
|
|
xd->above_context = pc->above_context;
|
|
|
|
vpx_memset(xd->left_context, 0, sizeof(ENTROPY_CONTEXT_PLANES));
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
xd->left_available = 0;
|
2010-07-22 14:07:32 +02:00
|
|
|
|
2013-09-20 22:29:59 +02:00
|
|
|
xd->mb_to_top_edge = -((mb_row * 16) << 3);
|
2012-02-29 16:38:14 +01:00
|
|
|
xd->mb_to_bottom_edge = ((pc->mb_rows - 1 - mb_row) * 16) << 3;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-03-08 21:27:41 +01:00
|
|
|
xd->recon_above[0] = dst_buffer[0] + recon_yoffset;
|
|
|
|
xd->recon_above[1] = dst_buffer[1] + recon_uvoffset;
|
|
|
|
xd->recon_above[2] = dst_buffer[2] + recon_uvoffset;
|
|
|
|
|
|
|
|
xd->recon_left[0] = xd->recon_above[0] - 1;
|
|
|
|
xd->recon_left[1] = xd->recon_above[1] - 1;
|
|
|
|
xd->recon_left[2] = xd->recon_above[2] - 1;
|
|
|
|
|
|
|
|
xd->recon_above[0] -= xd->dst.y_stride;
|
|
|
|
xd->recon_above[1] -= xd->dst.uv_stride;
|
|
|
|
xd->recon_above[2] -= xd->dst.uv_stride;
|
|
|
|
|
2012-05-21 23:30:56 +02:00
|
|
|
/* TODO: move to outside row loop */
|
2012-03-08 21:27:41 +01:00
|
|
|
xd->recon_left_stride[0] = xd->dst.y_stride;
|
|
|
|
xd->recon_left_stride[1] = xd->dst.uv_stride;
|
|
|
|
|
2012-09-13 20:51:27 +02:00
|
|
|
setup_intra_recon_left(xd->recon_left[0], xd->recon_left[1],
|
|
|
|
xd->recon_left[2], xd->dst.y_stride,
|
|
|
|
xd->dst.uv_stride);
|
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
for (mb_col = 0; mb_col < pc->mb_cols; mb_col++)
|
2010-12-16 16:46:31 +01:00
|
|
|
{
|
2012-02-29 16:38:14 +01:00
|
|
|
/* Distance of Mb to the various image edges.
|
|
|
|
* These are specified to 8th pel as they are always compared to values
|
|
|
|
* that are in 1/8th pel units
|
|
|
|
*/
|
|
|
|
xd->mb_to_left_edge = -((mb_col * 16) << 3);
|
|
|
|
xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3;
|
|
|
|
|
|
|
|
#if CONFIG_ERROR_CONCEALMENT
|
|
|
|
{
|
|
|
|
int corrupt_residual = (!pbi->independent_partitions &&
|
|
|
|
pbi->frame_corrupt_residual) ||
|
|
|
|
vp8dx_bool_error(xd->current_bc);
|
|
|
|
if (pbi->ec_active &&
|
|
|
|
xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME &&
|
|
|
|
corrupt_residual)
|
|
|
|
{
|
|
|
|
/* We have an intra block with corrupt coefficients, better to
|
|
|
|
* conceal with an inter block. Interpolate MVs from neighboring
|
|
|
|
* MBs.
|
|
|
|
*
|
|
|
|
* Note that for the first mb with corrupt residual in a frame,
|
|
|
|
* we might not discover that before decoding the residual. That
|
|
|
|
* happens after this check, and therefore no inter concealment
|
|
|
|
* will be done.
|
|
|
|
*/
|
|
|
|
vp8_interpolate_motion(xd,
|
|
|
|
mb_row, mb_col,
|
|
|
|
pc->mb_rows, pc->mb_cols,
|
|
|
|
pc->mode_info_stride);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
xd->dst.y_buffer = dst_buffer[0] + recon_yoffset;
|
|
|
|
xd->dst.u_buffer = dst_buffer[1] + recon_uvoffset;
|
|
|
|
xd->dst.v_buffer = dst_buffer[2] + recon_uvoffset;
|
|
|
|
|
|
|
|
xd->pre.y_buffer = ref_buffer[xd->mode_info_context->mbmi.ref_frame][0] + recon_yoffset;
|
|
|
|
xd->pre.u_buffer = ref_buffer[xd->mode_info_context->mbmi.ref_frame][1] + recon_uvoffset;
|
|
|
|
xd->pre.v_buffer = ref_buffer[xd->mode_info_context->mbmi.ref_frame][2] + recon_uvoffset;
|
|
|
|
|
2010-12-16 16:46:31 +01:00
|
|
|
/* propagate errors from reference frames */
|
2012-02-29 16:38:14 +01:00
|
|
|
xd->corrupted |= ref_fb_corrupted[xd->mode_info_context->mbmi.ref_frame];
|
2010-12-16 16:46:31 +01:00
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
decode_macroblock(pbi, xd, mb_idx);
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
mb_idx++;
|
|
|
|
xd->left_available = 1;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
/* check if the boolean decoder has suffered an error */
|
|
|
|
xd->corrupted |= vp8dx_bool_error(xd->current_bc);
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-03-08 21:27:41 +01:00
|
|
|
xd->recon_above[0] += 16;
|
|
|
|
xd->recon_above[1] += 8;
|
|
|
|
xd->recon_above[2] += 8;
|
|
|
|
xd->recon_left[0] += 16;
|
|
|
|
xd->recon_left[1] += 8;
|
|
|
|
xd->recon_left[2] += 8;
|
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
recon_yoffset += 16;
|
|
|
|
recon_uvoffset += 8;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
++xd->mode_info_context; /* next mb */
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
xd->above_context++;
|
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
/* adjust to the next row of mbs */
|
2012-09-24 21:44:45 +02:00
|
|
|
vp8_extend_mb_row(yv12_fb_new, xd->dst.y_buffer + 16,
|
2012-08-02 20:58:09 +02:00
|
|
|
xd->dst.u_buffer + 8, xd->dst.v_buffer + 8);
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
++xd->mode_info_context; /* skip prediction column */
|
|
|
|
xd->up_available = 1;
|
|
|
|
|
2012-08-02 20:58:09 +02:00
|
|
|
if(pc->filter_level)
|
|
|
|
{
|
|
|
|
if(mb_row > 0)
|
|
|
|
{
|
|
|
|
if (pc->filter_type == NORMAL_LOOPFILTER)
|
|
|
|
vp8_loop_filter_row_normal(pc, lf_mic, mb_row-1,
|
|
|
|
recon_y_stride, recon_uv_stride,
|
|
|
|
lf_dst[0], lf_dst[1], lf_dst[2]);
|
|
|
|
else
|
|
|
|
vp8_loop_filter_row_simple(pc, lf_mic, mb_row-1,
|
|
|
|
recon_y_stride, recon_uv_stride,
|
|
|
|
lf_dst[0], lf_dst[1], lf_dst[2]);
|
2012-08-21 21:42:49 +02:00
|
|
|
|
|
|
|
if(mb_row > 1)
|
|
|
|
{
|
2012-09-24 21:44:45 +02:00
|
|
|
yv12_extend_frame_left_right_c(yv12_fb_new,
|
2012-08-21 21:42:49 +02:00
|
|
|
eb_dst[0],
|
|
|
|
eb_dst[1],
|
|
|
|
eb_dst[2]);
|
|
|
|
|
|
|
|
eb_dst[0] += recon_y_stride * 16;
|
|
|
|
eb_dst[1] += recon_uv_stride * 8;
|
|
|
|
eb_dst[2] += recon_uv_stride * 8;
|
|
|
|
|
|
|
|
if(mb_row == 2)
|
2012-09-24 21:44:45 +02:00
|
|
|
yv12_extend_frame_top_c(yv12_fb_new);
|
2012-08-21 21:42:49 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-08-02 20:58:09 +02:00
|
|
|
lf_dst[0] += recon_y_stride * 16;
|
|
|
|
lf_dst[1] += recon_uv_stride * 8;
|
|
|
|
lf_dst[2] += recon_uv_stride * 8;
|
|
|
|
lf_mic += pc->mb_cols;
|
|
|
|
lf_mic++; /* Skip border mb */
|
|
|
|
}
|
|
|
|
}
|
2012-08-21 21:42:49 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if(mb_row > 0)
|
|
|
|
{
|
|
|
|
/**/
|
2012-09-24 21:44:45 +02:00
|
|
|
yv12_extend_frame_left_right_c(yv12_fb_new,
|
2012-08-21 21:42:49 +02:00
|
|
|
eb_dst[0],
|
|
|
|
eb_dst[1],
|
|
|
|
eb_dst[2]);
|
|
|
|
|
|
|
|
eb_dst[0] += recon_y_stride * 16;
|
|
|
|
eb_dst[1] += recon_uv_stride * 8;
|
|
|
|
eb_dst[2] += recon_uv_stride * 8;
|
|
|
|
|
|
|
|
if(mb_row == 1)
|
2012-09-24 21:44:45 +02:00
|
|
|
yv12_extend_frame_top_c(yv12_fb_new);
|
2012-08-21 21:42:49 +02:00
|
|
|
}
|
|
|
|
}
|
2012-08-02 20:58:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if(pc->filter_level)
|
|
|
|
{
|
|
|
|
if (pc->filter_type == NORMAL_LOOPFILTER)
|
|
|
|
vp8_loop_filter_row_normal(pc, lf_mic, mb_row-1, recon_y_stride,
|
|
|
|
recon_uv_stride, lf_dst[0], lf_dst[1],
|
|
|
|
lf_dst[2]);
|
|
|
|
else
|
|
|
|
vp8_loop_filter_row_simple(pc, lf_mic, mb_row-1, recon_y_stride,
|
|
|
|
recon_uv_stride, lf_dst[0], lf_dst[1],
|
|
|
|
lf_dst[2]);
|
2012-08-21 21:42:49 +02:00
|
|
|
|
2012-09-24 21:44:45 +02:00
|
|
|
yv12_extend_frame_left_right_c(yv12_fb_new,
|
2012-08-21 21:42:49 +02:00
|
|
|
eb_dst[0],
|
|
|
|
eb_dst[1],
|
|
|
|
eb_dst[2]);
|
|
|
|
eb_dst[0] += recon_y_stride * 16;
|
|
|
|
eb_dst[1] += recon_uv_stride * 8;
|
|
|
|
eb_dst[2] += recon_uv_stride * 8;
|
2012-02-29 16:38:14 +01:00
|
|
|
}
|
2012-09-24 21:44:45 +02:00
|
|
|
yv12_extend_frame_left_right_c(yv12_fb_new,
|
2012-08-21 21:42:49 +02:00
|
|
|
eb_dst[0],
|
|
|
|
eb_dst[1],
|
|
|
|
eb_dst[2]);
|
2012-08-02 20:58:09 +02:00
|
|
|
|
2012-09-24 21:44:45 +02:00
|
|
|
yv12_extend_frame_bottom_c(yv12_fb_new);
|
|
|
|
|
2012-02-29 16:38:14 +01:00
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2013-06-13 21:16:58 +02:00
|
|
|
static unsigned int read_partition_size(VP8D_COMP *pbi,
|
|
|
|
const unsigned char *cx_size)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2013-06-13 21:16:58 +02:00
|
|
|
unsigned char temp[3];
|
|
|
|
if (pbi->decrypt_cb)
|
|
|
|
{
|
|
|
|
pbi->decrypt_cb(pbi->decrypt_state, cx_size, temp, 3);
|
|
|
|
cx_size = temp;
|
|
|
|
}
|
|
|
|
return cx_size[0] + (cx_size[1] << 8) + (cx_size[2] << 16);
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
|
2011-09-29 09:17:09 +02:00
|
|
|
static int read_is_valid(const unsigned char *start,
|
|
|
|
size_t len,
|
|
|
|
const unsigned char *end)
|
2011-06-13 16:42:27 +02:00
|
|
|
{
|
2011-09-29 09:17:09 +02:00
|
|
|
return (start + len > start && start + len <= end);
|
|
|
|
}
|
2011-06-13 16:42:27 +02:00
|
|
|
|
2011-09-29 09:17:09 +02:00
|
|
|
static unsigned int read_available_partition_size(
|
|
|
|
VP8D_COMP *pbi,
|
|
|
|
const unsigned char *token_part_sizes,
|
|
|
|
const unsigned char *fragment_start,
|
|
|
|
const unsigned char *first_fragment_end,
|
|
|
|
const unsigned char *fragment_end,
|
|
|
|
int i,
|
|
|
|
int num_part)
|
|
|
|
{
|
|
|
|
VP8_COMMON* pc = &pbi->common;
|
|
|
|
const unsigned char *partition_size_ptr = token_part_sizes + i * 3;
|
2012-04-27 12:41:58 +02:00
|
|
|
unsigned int partition_size = 0;
|
2011-09-29 09:17:09 +02:00
|
|
|
ptrdiff_t bytes_left = fragment_end - fragment_start;
|
|
|
|
/* Calculate the length of this partition. The last partition
|
|
|
|
* size is implicit. If the partition size can't be read, then
|
|
|
|
* either use the remaining data in the buffer (for EC mode)
|
|
|
|
* or throw an error.
|
|
|
|
*/
|
|
|
|
if (i < num_part - 1)
|
2011-06-13 16:42:27 +02:00
|
|
|
{
|
2011-09-29 09:17:09 +02:00
|
|
|
if (read_is_valid(partition_size_ptr, 3, first_fragment_end))
|
2013-06-13 21:16:58 +02:00
|
|
|
partition_size = read_partition_size(pbi, partition_size_ptr);
|
2011-09-29 09:17:09 +02:00
|
|
|
else if (pbi->ec_active)
|
2012-08-17 19:05:35 +02:00
|
|
|
partition_size = (unsigned int)bytes_left;
|
2011-09-29 09:17:09 +02:00
|
|
|
else
|
|
|
|
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
|
|
|
|
"Truncated partition size data");
|
2011-06-13 16:42:27 +02:00
|
|
|
}
|
2011-09-29 09:17:09 +02:00
|
|
|
else
|
2012-08-17 19:05:35 +02:00
|
|
|
partition_size = (unsigned int)bytes_left;
|
2011-06-13 16:42:27 +02:00
|
|
|
|
2011-09-29 09:17:09 +02:00
|
|
|
/* Validate the calculated partition length. If the buffer
|
|
|
|
* described by the partition can't be fully read, then restrict
|
|
|
|
* it to the portion that can be (for EC mode) or throw an error.
|
|
|
|
*/
|
|
|
|
if (!read_is_valid(fragment_start, partition_size, fragment_end))
|
2011-06-13 16:42:27 +02:00
|
|
|
{
|
2011-09-29 09:17:09 +02:00
|
|
|
if (pbi->ec_active)
|
2012-08-17 19:05:35 +02:00
|
|
|
partition_size = (unsigned int)bytes_left;
|
2011-09-29 09:17:09 +02:00
|
|
|
else
|
|
|
|
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
|
|
|
|
"Truncated packet or corrupt partition "
|
|
|
|
"%d length", i + 1);
|
2011-06-13 16:42:27 +02:00
|
|
|
}
|
2011-09-29 09:17:09 +02:00
|
|
|
return partition_size;
|
2011-08-05 18:27:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-18 17:58:33 +02:00
|
|
|
static void setup_token_decoder(VP8D_COMP *pbi,
|
2011-09-29 09:17:09 +02:00
|
|
|
const unsigned char* token_part_sizes)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2012-09-21 20:00:29 +02:00
|
|
|
vp8_reader *bool_decoder = &pbi->mbc[0];
|
2011-12-21 22:37:22 +01:00
|
|
|
unsigned int partition_idx;
|
2012-05-08 20:45:35 +02:00
|
|
|
unsigned int fragment_idx;
|
|
|
|
unsigned int num_token_partitions;
|
2013-01-29 19:34:35 +01:00
|
|
|
const unsigned char *first_fragment_end = pbi->fragments.ptrs[0] +
|
|
|
|
pbi->fragments.sizes[0];
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2011-09-29 09:17:09 +02:00
|
|
|
TOKEN_PARTITION multi_token_partition =
|
2012-09-21 20:00:29 +02:00
|
|
|
(TOKEN_PARTITION)vp8_read_literal(&pbi->mbc[8], 2);
|
|
|
|
if (!vp8dx_bool_error(&pbi->mbc[8]))
|
2011-09-29 09:17:09 +02:00
|
|
|
pbi->common.multi_token_partition = multi_token_partition;
|
|
|
|
num_token_partitions = 1 << pbi->common.multi_token_partition;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2011-09-29 09:17:09 +02:00
|
|
|
/* Check for partitions within the fragments and unpack the fragments
|
|
|
|
* so that each fragment pointer points to its corresponding partition. */
|
2013-01-29 19:34:35 +01:00
|
|
|
for (fragment_idx = 0; fragment_idx < pbi->fragments.count; ++fragment_idx)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2013-01-29 19:34:35 +01:00
|
|
|
unsigned int fragment_size = pbi->fragments.sizes[fragment_idx];
|
|
|
|
const unsigned char *fragment_end = pbi->fragments.ptrs[fragment_idx] +
|
2011-09-29 09:17:09 +02:00
|
|
|
fragment_size;
|
|
|
|
/* Special case for handling the first partition since we have already
|
|
|
|
* read its size. */
|
|
|
|
if (fragment_idx == 0)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2011-09-29 09:17:09 +02:00
|
|
|
/* Size of first partition + token partition sizes element */
|
|
|
|
ptrdiff_t ext_first_part_size = token_part_sizes -
|
2013-01-29 19:34:35 +01:00
|
|
|
pbi->fragments.ptrs[0] + 3 * (num_token_partitions - 1);
|
2012-08-17 19:05:35 +02:00
|
|
|
fragment_size -= (unsigned int)ext_first_part_size;
|
2011-09-29 09:17:09 +02:00
|
|
|
if (fragment_size > 0)
|
|
|
|
{
|
2013-01-29 19:34:35 +01:00
|
|
|
pbi->fragments.sizes[0] = (unsigned int)ext_first_part_size;
|
2011-09-29 09:17:09 +02:00
|
|
|
/* The fragment contains an additional partition. Move to
|
|
|
|
* next. */
|
|
|
|
fragment_idx++;
|
2013-01-29 19:34:35 +01:00
|
|
|
pbi->fragments.ptrs[fragment_idx] = pbi->fragments.ptrs[0] +
|
|
|
|
pbi->fragments.sizes[0];
|
2011-09-29 09:17:09 +02:00
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
2011-09-29 09:17:09 +02:00
|
|
|
/* Split the chunk into partitions read from the bitstream */
|
|
|
|
while (fragment_size > 0)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2011-09-29 09:17:09 +02:00
|
|
|
ptrdiff_t partition_size = read_available_partition_size(
|
|
|
|
pbi,
|
|
|
|
token_part_sizes,
|
2013-01-29 19:34:35 +01:00
|
|
|
pbi->fragments.ptrs[fragment_idx],
|
2011-09-29 09:17:09 +02:00
|
|
|
first_fragment_end,
|
|
|
|
fragment_end,
|
|
|
|
fragment_idx - 1,
|
|
|
|
num_token_partitions);
|
2013-01-29 19:34:35 +01:00
|
|
|
pbi->fragments.sizes[fragment_idx] = (unsigned int)partition_size;
|
2012-08-17 19:05:35 +02:00
|
|
|
fragment_size -= (unsigned int)partition_size;
|
2011-09-29 09:17:09 +02:00
|
|
|
assert(fragment_idx <= num_token_partitions);
|
|
|
|
if (fragment_size > 0)
|
|
|
|
{
|
|
|
|
/* The fragment contains an additional partition.
|
|
|
|
* Move to next. */
|
|
|
|
fragment_idx++;
|
2013-01-29 19:34:35 +01:00
|
|
|
pbi->fragments.ptrs[fragment_idx] =
|
|
|
|
pbi->fragments.ptrs[fragment_idx - 1] + partition_size;
|
2011-09-29 09:17:09 +02:00
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
2011-09-29 09:17:09 +02:00
|
|
|
}
|
|
|
|
|
2013-01-29 19:34:35 +01:00
|
|
|
pbi->fragments.count = num_token_partitions + 1;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2013-01-29 19:34:35 +01:00
|
|
|
for (partition_idx = 1; partition_idx < pbi->fragments.count; ++partition_idx)
|
2011-09-29 09:17:09 +02:00
|
|
|
{
|
|
|
|
if (vp8dx_start_decode(bool_decoder,
|
2013-01-29 19:34:35 +01:00
|
|
|
pbi->fragments.ptrs[partition_idx],
|
2013-03-16 02:21:55 +01:00
|
|
|
pbi->fragments.sizes[partition_idx],
|
2013-06-13 21:16:58 +02:00
|
|
|
pbi->decrypt_cb, pbi->decrypt_state))
|
2011-09-29 09:17:09 +02:00
|
|
|
vpx_internal_error(&pbi->common.error, VPX_CODEC_MEM_ERROR,
|
|
|
|
"Failed to allocate bool decoder %d",
|
|
|
|
partition_idx);
|
2010-05-18 17:58:33 +02:00
|
|
|
|
|
|
|
bool_decoder++;
|
|
|
|
}
|
|
|
|
|
2011-02-05 06:29:25 +01:00
|
|
|
#if CONFIG_MULTITHREAD
|
2010-05-18 17:58:33 +02:00
|
|
|
/* Clamp number of decoder threads */
|
2011-09-29 09:17:09 +02:00
|
|
|
if (pbi->decoding_thread_count > num_token_partitions - 1)
|
|
|
|
pbi->decoding_thread_count = num_token_partitions - 1;
|
2011-02-05 06:29:25 +01:00
|
|
|
#endif
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void init_frame(VP8D_COMP *pbi)
|
|
|
|
{
|
|
|
|
VP8_COMMON *const pc = & pbi->common;
|
|
|
|
MACROBLOCKD *const xd = & pbi->mb;
|
|
|
|
|
|
|
|
if (pc->frame_type == KEY_FRAME)
|
|
|
|
{
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Various keyframe initializations */
|
2010-05-18 17:58:33 +02:00
|
|
|
vpx_memcpy(pc->fc.mvc, vp8_default_mv_context, sizeof(vp8_default_mv_context));
|
|
|
|
|
|
|
|
vp8_init_mbmode_probs(pc);
|
|
|
|
|
|
|
|
vp8_default_coef_probs(pc);
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* reset the segment feature data to 0 with delta coding (Default state). */
|
2010-05-18 17:58:33 +02:00
|
|
|
vpx_memset(xd->segment_feature_data, 0, sizeof(xd->segment_feature_data));
|
|
|
|
xd->mb_segement_abs_delta = SEGMENT_DELTADATA;
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* reset the mode ref deltasa for loop filter */
|
2010-05-18 17:58:33 +02:00
|
|
|
vpx_memset(xd->ref_lf_deltas, 0, sizeof(xd->ref_lf_deltas));
|
|
|
|
vpx_memset(xd->mode_lf_deltas, 0, sizeof(xd->mode_lf_deltas));
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* All buffers are implicitly updated on key frames. */
|
2010-05-18 17:58:33 +02:00
|
|
|
pc->refresh_golden_frame = 1;
|
|
|
|
pc->refresh_alt_ref_frame = 1;
|
|
|
|
pc->copy_buffer_to_gf = 0;
|
|
|
|
pc->copy_buffer_to_arf = 0;
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Note that Golden and Altref modes cannot be used on a key frame so
|
|
|
|
* ref_frame_sign_bias[] is undefined and meaningless
|
|
|
|
*/
|
2010-05-18 17:58:33 +02:00
|
|
|
pc->ref_frame_sign_bias[GOLDEN_FRAME] = 0;
|
|
|
|
pc->ref_frame_sign_bias[ALTREF_FRAME] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-10-28 01:04:02 +02:00
|
|
|
/* To enable choice of different interploation filters */
|
2012-04-23 19:23:21 +02:00
|
|
|
if (!pc->use_bilinear_mc_filter)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2012-01-13 01:55:44 +01:00
|
|
|
xd->subpixel_predict = vp8_sixtap_predict4x4;
|
|
|
|
xd->subpixel_predict8x4 = vp8_sixtap_predict8x4;
|
|
|
|
xd->subpixel_predict8x8 = vp8_sixtap_predict8x8;
|
|
|
|
xd->subpixel_predict16x16 = vp8_sixtap_predict16x16;
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-01-13 01:55:44 +01:00
|
|
|
xd->subpixel_predict = vp8_bilinear_predict4x4;
|
|
|
|
xd->subpixel_predict8x4 = vp8_bilinear_predict8x4;
|
|
|
|
xd->subpixel_predict8x8 = vp8_bilinear_predict8x8;
|
|
|
|
xd->subpixel_predict16x16 = vp8_bilinear_predict16x16;
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
2011-08-08 10:56:20 +02:00
|
|
|
|
|
|
|
if (pbi->decoded_key_frame && pbi->ec_enabled && !pbi->ec_active)
|
|
|
|
pbi->ec_active = 1;
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
|
2010-08-31 16:49:57 +02:00
|
|
|
xd->left_context = &pc->left_context;
|
2010-05-18 17:58:33 +02:00
|
|
|
xd->mode_info_context = pc->mi;
|
|
|
|
xd->frame_type = pc->frame_type;
|
2010-08-12 22:25:43 +02:00
|
|
|
xd->mode_info_context->mbmi.mode = DC_PRED;
|
2010-05-18 17:58:33 +02:00
|
|
|
xd->mode_info_stride = pc->mode_info_stride;
|
2010-12-16 16:46:31 +01:00
|
|
|
xd->corrupted = 0; /* init without corruption */
|
2011-08-24 20:42:26 +02:00
|
|
|
|
|
|
|
xd->fullpixel_mask = 0xffffffff;
|
|
|
|
if(pc->full_pixel)
|
|
|
|
xd->fullpixel_mask = 0xfffffff8;
|
|
|
|
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int vp8_decode_frame(VP8D_COMP *pbi)
|
|
|
|
{
|
2013-03-16 02:21:55 +01:00
|
|
|
vp8_reader *const bc = &pbi->mbc[8];
|
|
|
|
VP8_COMMON *const pc = &pbi->common;
|
|
|
|
MACROBLOCKD *const xd = &pbi->mb;
|
2013-01-29 19:34:35 +01:00
|
|
|
const unsigned char *data = pbi->fragments.ptrs[0];
|
|
|
|
const unsigned char *data_end = data + pbi->fragments.sizes[0];
|
2010-10-28 01:04:02 +02:00
|
|
|
ptrdiff_t first_partition_length_in_bytes;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
|
|
|
int i, j, k, l;
|
|
|
|
const int *const mb_feature_data_bits = vp8_mb_feature_data_bits;
|
2011-08-08 10:56:20 +02:00
|
|
|
int corrupt_tokens = 0;
|
|
|
|
int prev_independent_partitions = pbi->independent_partitions;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-09-24 21:44:45 +02:00
|
|
|
YV12_BUFFER_CONFIG *yv12_fb_new = pbi->dec_fb_ref[INTRA_FRAME];
|
|
|
|
|
2010-12-16 16:46:31 +01:00
|
|
|
/* start with no corruption of current frame */
|
|
|
|
xd->corrupted = 0;
|
2012-09-24 21:44:45 +02:00
|
|
|
yv12_fb_new->corrupted = 0;
|
2010-12-16 16:46:31 +01:00
|
|
|
|
2010-10-20 00:40:46 +02:00
|
|
|
if (data_end - data < 3)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2011-10-25 01:56:55 +02:00
|
|
|
if (!pbi->ec_active)
|
2011-05-02 15:30:51 +02:00
|
|
|
{
|
|
|
|
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
|
|
|
|
"Truncated packet");
|
|
|
|
}
|
2011-10-25 01:56:55 +02:00
|
|
|
|
|
|
|
/* Declare the missing frame as an inter frame since it will
|
|
|
|
be handled as an inter frame when we have estimated its
|
|
|
|
motion vectors. */
|
|
|
|
pc->frame_type = INTER_FRAME;
|
|
|
|
pc->version = 0;
|
|
|
|
pc->show_frame = 1;
|
|
|
|
first_partition_length_in_bytes = 0;
|
2011-05-02 15:30:51 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-06-13 21:16:58 +02:00
|
|
|
unsigned char clear_buffer[10];
|
|
|
|
const unsigned char *clear = data;
|
|
|
|
if (pbi->decrypt_cb)
|
|
|
|
{
|
2013-09-17 18:45:13 +02:00
|
|
|
int n = (int)(data_end - data);
|
2013-06-13 21:16:58 +02:00
|
|
|
if (n > 10) n = 10;
|
|
|
|
pbi->decrypt_cb(pbi->decrypt_state, data, clear_buffer, n);
|
|
|
|
clear = clear_buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
pc->frame_type = (FRAME_TYPE)(clear[0] & 1);
|
|
|
|
pc->version = (clear[0] >> 1) & 7;
|
|
|
|
pc->show_frame = (clear[0] >> 4) & 1;
|
2011-05-02 15:30:51 +02:00
|
|
|
first_partition_length_in_bytes =
|
2013-06-13 21:16:58 +02:00
|
|
|
(clear[0] | (clear[1] << 8) | (clear[2] << 16)) >> 5;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2013-03-16 02:21:55 +01:00
|
|
|
if (!pbi->ec_active &&
|
|
|
|
(data + first_partition_length_in_bytes > data_end
|
2011-05-02 15:30:51 +02:00
|
|
|
|| data + first_partition_length_in_bytes < data))
|
|
|
|
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
|
|
|
|
"Truncated packet or corrupt partition 0 length");
|
2011-09-06 14:34:36 +02:00
|
|
|
|
|
|
|
data += 3;
|
2013-06-13 21:16:58 +02:00
|
|
|
clear += 3;
|
2011-09-06 14:34:36 +02:00
|
|
|
|
2011-05-02 15:30:51 +02:00
|
|
|
vp8_setup_version(pc);
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-09-08 01:38:15 +02:00
|
|
|
|
2011-05-02 15:30:51 +02:00
|
|
|
if (pc->frame_type == KEY_FRAME)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2011-05-02 15:30:51 +02:00
|
|
|
/* vet via sync code */
|
|
|
|
/* When error concealment is enabled we should only check the sync
|
|
|
|
* code if we have enough bits available
|
|
|
|
*/
|
2011-08-08 10:56:20 +02:00
|
|
|
if (!pbi->ec_active || data + 3 < data_end)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2013-06-13 21:16:58 +02:00
|
|
|
if (clear[0] != 0x9d || clear[1] != 0x01 || clear[2] != 0x2a)
|
2011-05-02 15:30:51 +02:00
|
|
|
vpx_internal_error(&pc->error, VPX_CODEC_UNSUP_BITSTREAM,
|
|
|
|
"Invalid frame sync code");
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
|
2011-05-02 15:30:51 +02:00
|
|
|
/* If error concealment is enabled we should only parse the new size
|
|
|
|
* if we have enough data. Otherwise we will end up with the wrong
|
|
|
|
* size.
|
|
|
|
*/
|
2011-08-08 10:56:20 +02:00
|
|
|
if (!pbi->ec_active || data + 6 < data_end)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2013-06-13 21:16:58 +02:00
|
|
|
pc->Width = (clear[3] | (clear[4] << 8)) & 0x3fff;
|
|
|
|
pc->horiz_scale = clear[4] >> 6;
|
|
|
|
pc->Height = (clear[5] | (clear[6] << 8)) & 0x3fff;
|
|
|
|
pc->vert_scale = clear[6] >> 6;
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
2011-05-02 15:30:51 +02:00
|
|
|
data += 7;
|
2013-06-13 21:16:58 +02:00
|
|
|
clear += 7;
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
2012-09-08 01:38:15 +02:00
|
|
|
else
|
|
|
|
{
|
2012-09-24 21:44:45 +02:00
|
|
|
vpx_memcpy(&xd->pre, yv12_fb_new, sizeof(YV12_BUFFER_CONFIG));
|
|
|
|
vpx_memcpy(&xd->dst, yv12_fb_new, sizeof(YV12_BUFFER_CONFIG));
|
2012-09-08 01:38:15 +02:00
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
2012-09-24 21:44:45 +02:00
|
|
|
if ((!pbi->decoded_key_frame && pc->frame_type != KEY_FRAME))
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
init_frame(pbi);
|
|
|
|
|
2013-06-13 21:16:58 +02:00
|
|
|
if (vp8dx_start_decode(bc, data, (unsigned int)(data_end - data),
|
|
|
|
pbi->decrypt_cb, pbi->decrypt_state))
|
2010-05-18 17:58:33 +02:00
|
|
|
vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR,
|
|
|
|
"Failed to allocate bool decoder 0");
|
|
|
|
if (pc->frame_type == KEY_FRAME) {
|
2013-07-12 23:11:53 +02:00
|
|
|
(void)vp8_read_bit(bc); // colorspace
|
2010-05-18 17:58:33 +02:00
|
|
|
pc->clamp_type = (CLAMP_TYPE)vp8_read_bit(bc);
|
|
|
|
}
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Is segmentation enabled */
|
2010-05-18 17:58:33 +02:00
|
|
|
xd->segmentation_enabled = (unsigned char)vp8_read_bit(bc);
|
|
|
|
|
|
|
|
if (xd->segmentation_enabled)
|
|
|
|
{
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Signal whether or not the segmentation map is being explicitly updated this frame. */
|
2010-05-18 17:58:33 +02:00
|
|
|
xd->update_mb_segmentation_map = (unsigned char)vp8_read_bit(bc);
|
|
|
|
xd->update_mb_segmentation_data = (unsigned char)vp8_read_bit(bc);
|
|
|
|
|
|
|
|
if (xd->update_mb_segmentation_data)
|
|
|
|
{
|
|
|
|
xd->mb_segement_abs_delta = (unsigned char)vp8_read_bit(bc);
|
|
|
|
|
|
|
|
vpx_memset(xd->segment_feature_data, 0, sizeof(xd->segment_feature_data));
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* For each segmentation feature (Quant and loop filter level) */
|
2010-05-18 17:58:33 +02:00
|
|
|
for (i = 0; i < MB_LVL_MAX; i++)
|
|
|
|
{
|
|
|
|
for (j = 0; j < MAX_MB_SEGMENTS; j++)
|
|
|
|
{
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Frame level data */
|
2010-05-18 17:58:33 +02:00
|
|
|
if (vp8_read_bit(bc))
|
|
|
|
{
|
|
|
|
xd->segment_feature_data[i][j] = (signed char)vp8_read_literal(bc, mb_feature_data_bits[i]);
|
|
|
|
|
|
|
|
if (vp8_read_bit(bc))
|
|
|
|
xd->segment_feature_data[i][j] = -xd->segment_feature_data[i][j];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
xd->segment_feature_data[i][j] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xd->update_mb_segmentation_map)
|
|
|
|
{
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Which macro block level features are enabled */
|
2010-05-18 17:58:33 +02:00
|
|
|
vpx_memset(xd->mb_segment_tree_probs, 255, sizeof(xd->mb_segment_tree_probs));
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Read the probs used to decode the segment id for each macro block. */
|
2010-05-18 17:58:33 +02:00
|
|
|
for (i = 0; i < MB_FEATURE_TREE_PROBS; i++)
|
|
|
|
{
|
2010-10-28 01:04:02 +02:00
|
|
|
/* If not explicitly set value is defaulted to 255 by memset above */
|
2010-05-18 17:58:33 +02:00
|
|
|
if (vp8_read_bit(bc))
|
|
|
|
xd->mb_segment_tree_probs[i] = (vp8_prob)vp8_read_literal(bc, 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-02-16 20:15:11 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* No segmentation updates on this frame */
|
|
|
|
xd->update_mb_segmentation_map = 0;
|
|
|
|
xd->update_mb_segmentation_data = 0;
|
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Read the loop filter level and type */
|
2010-05-18 17:58:33 +02:00
|
|
|
pc->filter_type = (LOOPFILTERTYPE) vp8_read_bit(bc);
|
|
|
|
pc->filter_level = vp8_read_literal(bc, 6);
|
|
|
|
pc->sharpness_level = vp8_read_literal(bc, 3);
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Read in loop filter deltas applied at the MB level based on mode or ref frame. */
|
2010-05-18 17:58:33 +02:00
|
|
|
xd->mode_ref_lf_delta_update = 0;
|
|
|
|
xd->mode_ref_lf_delta_enabled = (unsigned char)vp8_read_bit(bc);
|
|
|
|
|
|
|
|
if (xd->mode_ref_lf_delta_enabled)
|
|
|
|
{
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Do the deltas need to be updated */
|
2010-05-18 17:58:33 +02:00
|
|
|
xd->mode_ref_lf_delta_update = (unsigned char)vp8_read_bit(bc);
|
|
|
|
|
|
|
|
if (xd->mode_ref_lf_delta_update)
|
|
|
|
{
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Send update */
|
2010-05-18 17:58:33 +02:00
|
|
|
for (i = 0; i < MAX_REF_LF_DELTAS; i++)
|
|
|
|
{
|
|
|
|
if (vp8_read_bit(bc))
|
|
|
|
{
|
2010-10-28 01:04:02 +02:00
|
|
|
/*sign = vp8_read_bit( bc );*/
|
2010-05-18 17:58:33 +02:00
|
|
|
xd->ref_lf_deltas[i] = (signed char)vp8_read_literal(bc, 6);
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
if (vp8_read_bit(bc)) /* Apply sign */
|
2010-05-18 17:58:33 +02:00
|
|
|
xd->ref_lf_deltas[i] = xd->ref_lf_deltas[i] * -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Send update */
|
2010-05-18 17:58:33 +02:00
|
|
|
for (i = 0; i < MAX_MODE_LF_DELTAS; i++)
|
|
|
|
{
|
|
|
|
if (vp8_read_bit(bc))
|
|
|
|
{
|
2010-10-28 01:04:02 +02:00
|
|
|
/*sign = vp8_read_bit( bc );*/
|
2010-05-18 17:58:33 +02:00
|
|
|
xd->mode_lf_deltas[i] = (signed char)vp8_read_literal(bc, 6);
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
if (vp8_read_bit(bc)) /* Apply sign */
|
2010-05-18 17:58:33 +02:00
|
|
|
xd->mode_lf_deltas[i] = xd->mode_lf_deltas[i] * -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 09:17:09 +02:00
|
|
|
setup_token_decoder(pbi, data + first_partition_length_in_bytes);
|
|
|
|
|
2012-09-21 20:00:29 +02:00
|
|
|
xd->current_bc = &pbi->mbc[0];
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Read the default quantizers. */
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
|
|
|
int Q, q_update;
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
Q = vp8_read_literal(bc, 7); /* AC 1st order Q = default */
|
2010-05-18 17:58:33 +02:00
|
|
|
pc->base_qindex = Q;
|
|
|
|
q_update = 0;
|
|
|
|
pc->y1dc_delta_q = get_delta_q(bc, pc->y1dc_delta_q, &q_update);
|
|
|
|
pc->y2dc_delta_q = get_delta_q(bc, pc->y2dc_delta_q, &q_update);
|
|
|
|
pc->y2ac_delta_q = get_delta_q(bc, pc->y2ac_delta_q, &q_update);
|
|
|
|
pc->uvdc_delta_q = get_delta_q(bc, pc->uvdc_delta_q, &q_update);
|
|
|
|
pc->uvac_delta_q = get_delta_q(bc, pc->uvac_delta_q, &q_update);
|
|
|
|
|
|
|
|
if (q_update)
|
|
|
|
vp8cx_init_de_quantizer(pbi);
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* MB level dequantizer setup */
|
2012-05-04 21:23:53 +02:00
|
|
|
vp8_mb_init_dequantizer(pbi, &pbi->mb);
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Determine if the golden frame or ARF buffer should be updated and how.
|
|
|
|
* For all non key frames the GF and ARF refresh flags and sign bias
|
|
|
|
* flags must be set explicitly.
|
|
|
|
*/
|
2010-05-18 17:58:33 +02:00
|
|
|
if (pc->frame_type != KEY_FRAME)
|
|
|
|
{
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Should the GF or ARF be updated from the current frame */
|
2010-05-18 17:58:33 +02:00
|
|
|
pc->refresh_golden_frame = vp8_read_bit(bc);
|
2011-05-02 15:30:51 +02:00
|
|
|
#if CONFIG_ERROR_CONCEALMENT
|
|
|
|
/* Assume we shouldn't refresh golden if the bit is missing */
|
|
|
|
xd->corrupted |= vp8dx_bool_error(bc);
|
2011-08-08 10:56:20 +02:00
|
|
|
if (pbi->ec_active && xd->corrupted)
|
2011-05-02 15:30:51 +02:00
|
|
|
pc->refresh_golden_frame = 0;
|
|
|
|
#endif
|
|
|
|
|
2010-05-18 17:58:33 +02:00
|
|
|
pc->refresh_alt_ref_frame = vp8_read_bit(bc);
|
2011-05-02 15:30:51 +02:00
|
|
|
#if CONFIG_ERROR_CONCEALMENT
|
|
|
|
/* Assume we shouldn't refresh altref if the bit is missing */
|
|
|
|
xd->corrupted |= vp8dx_bool_error(bc);
|
2011-08-08 10:56:20 +02:00
|
|
|
if (pbi->ec_active && xd->corrupted)
|
2011-05-02 15:30:51 +02:00
|
|
|
pc->refresh_alt_ref_frame = 0;
|
|
|
|
#endif
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* Buffer to buffer copy flags. */
|
2010-05-18 17:58:33 +02:00
|
|
|
pc->copy_buffer_to_gf = 0;
|
|
|
|
|
|
|
|
if (!pc->refresh_golden_frame)
|
|
|
|
pc->copy_buffer_to_gf = vp8_read_literal(bc, 2);
|
|
|
|
|
2011-11-18 15:44:17 +01:00
|
|
|
#if CONFIG_ERROR_CONCEALMENT
|
|
|
|
/* Assume we shouldn't copy to the golden if the bit is missing */
|
|
|
|
xd->corrupted |= vp8dx_bool_error(bc);
|
|
|
|
if (pbi->ec_active && xd->corrupted)
|
|
|
|
pc->copy_buffer_to_gf = 0;
|
|
|
|
#endif
|
|
|
|
|
2010-05-18 17:58:33 +02:00
|
|
|
pc->copy_buffer_to_arf = 0;
|
|
|
|
|
|
|
|
if (!pc->refresh_alt_ref_frame)
|
|
|
|
pc->copy_buffer_to_arf = vp8_read_literal(bc, 2);
|
|
|
|
|
2011-11-18 15:44:17 +01:00
|
|
|
#if CONFIG_ERROR_CONCEALMENT
|
|
|
|
/* Assume we shouldn't copy to the alt-ref if the bit is missing */
|
|
|
|
xd->corrupted |= vp8dx_bool_error(bc);
|
|
|
|
if (pbi->ec_active && xd->corrupted)
|
|
|
|
pc->copy_buffer_to_arf = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2010-05-18 17:58:33 +02:00
|
|
|
pc->ref_frame_sign_bias[GOLDEN_FRAME] = vp8_read_bit(bc);
|
|
|
|
pc->ref_frame_sign_bias[ALTREF_FRAME] = vp8_read_bit(bc);
|
|
|
|
}
|
|
|
|
|
|
|
|
pc->refresh_entropy_probs = vp8_read_bit(bc);
|
2011-11-18 15:44:17 +01:00
|
|
|
#if CONFIG_ERROR_CONCEALMENT
|
|
|
|
/* Assume we shouldn't refresh the probabilities if the bit is
|
|
|
|
* missing */
|
|
|
|
xd->corrupted |= vp8dx_bool_error(bc);
|
|
|
|
if (pbi->ec_active && xd->corrupted)
|
|
|
|
pc->refresh_entropy_probs = 0;
|
|
|
|
#endif
|
2010-05-18 17:58:33 +02:00
|
|
|
if (pc->refresh_entropy_probs == 0)
|
|
|
|
{
|
|
|
|
vpx_memcpy(&pc->lfc, &pc->fc, sizeof(pc->fc));
|
|
|
|
}
|
|
|
|
|
|
|
|
pc->refresh_last_frame = pc->frame_type == KEY_FRAME || vp8_read_bit(bc);
|
|
|
|
|
2011-05-02 15:30:51 +02:00
|
|
|
#if CONFIG_ERROR_CONCEALMENT
|
|
|
|
/* Assume we should refresh the last frame if the bit is missing */
|
|
|
|
xd->corrupted |= vp8dx_bool_error(bc);
|
2011-08-08 10:56:20 +02:00
|
|
|
if (pbi->ec_active && xd->corrupted)
|
2011-05-02 15:30:51 +02:00
|
|
|
pc->refresh_last_frame = 1;
|
|
|
|
#endif
|
|
|
|
|
2010-05-18 17:58:33 +02:00
|
|
|
if (0)
|
|
|
|
{
|
|
|
|
FILE *z = fopen("decodestats.stt", "a");
|
|
|
|
fprintf(z, "%6d F:%d,G:%d,A:%d,L:%d,Q:%d\n",
|
|
|
|
pc->current_video_frame,
|
|
|
|
pc->frame_type,
|
|
|
|
pc->refresh_golden_frame,
|
|
|
|
pc->refresh_alt_ref_frame,
|
|
|
|
pc->refresh_last_frame,
|
|
|
|
pc->base_qindex);
|
|
|
|
fclose(z);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2011-08-08 10:56:20 +02:00
|
|
|
pbi->independent_partitions = 1;
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* read coef probability tree */
|
2010-05-18 17:58:33 +02:00
|
|
|
for (i = 0; i < BLOCK_TYPES; i++)
|
|
|
|
for (j = 0; j < COEF_BANDS; j++)
|
|
|
|
for (k = 0; k < PREV_COEF_CONTEXTS; k++)
|
2011-06-28 23:03:47 +02:00
|
|
|
for (l = 0; l < ENTROPY_NODES; l++)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
vp8_prob *const p = pc->fc.coef_probs [i][j][k] + l;
|
|
|
|
|
|
|
|
if (vp8_read(bc, vp8_coef_update_probs [i][j][k][l]))
|
|
|
|
{
|
|
|
|
*p = (vp8_prob)vp8_read_literal(bc, 8);
|
|
|
|
|
|
|
|
}
|
2011-08-08 10:56:20 +02:00
|
|
|
if (k > 0 && *p != pc->fc.coef_probs[i][j][k-1][l])
|
|
|
|
pbi->independent_partitions = 0;
|
|
|
|
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* clear out the coeff buffer */
|
2010-05-18 17:58:33 +02:00
|
|
|
vpx_memset(xd->qcoeff, 0, sizeof(xd->qcoeff));
|
|
|
|
|
2010-09-09 20:42:48 +02:00
|
|
|
vp8_decode_mode_mvs(pbi);
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2011-05-02 15:30:51 +02:00
|
|
|
#if CONFIG_ERROR_CONCEALMENT
|
2011-08-08 10:56:20 +02:00
|
|
|
if (pbi->ec_active &&
|
2011-05-02 15:30:51 +02:00
|
|
|
pbi->mvs_corrupt_from_mb < (unsigned int)pc->mb_cols * pc->mb_rows)
|
|
|
|
{
|
|
|
|
/* Motion vectors are missing in this frame. We will try to estimate
|
|
|
|
* them and then continue decoding the frame as usual */
|
|
|
|
vp8_estimate_missing_mvs(pbi);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-08-31 16:49:57 +02:00
|
|
|
vpx_memset(pc->above_context, 0, sizeof(ENTROPY_CONTEXT_PLANES) * pc->mb_cols);
|
2012-02-29 16:38:14 +01:00
|
|
|
pbi->frame_corrupt_residual = 0;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2011-02-05 06:29:25 +01:00
|
|
|
#if CONFIG_MULTITHREAD
|
2010-06-11 16:17:57 +02:00
|
|
|
if (pbi->b_multithreaded_rd && pc->multi_token_partition != ONE_PARTITION)
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2013-03-14 22:45:23 +01:00
|
|
|
unsigned int thread;
|
2010-09-16 20:08:52 +02:00
|
|
|
vp8mt_decode_mb_rows(pbi, xd);
|
2012-09-24 21:44:45 +02:00
|
|
|
vp8_yv12_extend_frame_borders(yv12_fb_new);
|
2013-03-14 22:45:23 +01:00
|
|
|
for (thread = 0; thread < pbi->decoding_thread_count; ++thread)
|
|
|
|
corrupt_tokens |= pbi->mb_row_di[thread].mbd.corrupted;
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
else
|
2011-02-05 06:29:25 +01:00
|
|
|
#endif
|
2010-05-18 17:58:33 +02:00
|
|
|
{
|
2012-02-29 16:38:14 +01:00
|
|
|
decode_mb_rows(pbi);
|
2011-08-08 10:56:20 +02:00
|
|
|
corrupt_tokens |= xd->corrupted;
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
|
2010-12-16 16:46:31 +01:00
|
|
|
/* Collect information about decoder corruption. */
|
|
|
|
/* 1. Check first boolean decoder for errors. */
|
2012-09-24 21:44:45 +02:00
|
|
|
yv12_fb_new->corrupted = vp8dx_bool_error(bc);
|
2010-12-16 16:46:31 +01:00
|
|
|
/* 2. Check the macroblock information */
|
2012-09-24 21:44:45 +02:00
|
|
|
yv12_fb_new->corrupted |= corrupt_tokens;
|
2011-08-08 10:56:20 +02:00
|
|
|
|
|
|
|
if (!pbi->decoded_key_frame)
|
|
|
|
{
|
|
|
|
if (pc->frame_type == KEY_FRAME &&
|
2012-09-24 21:44:45 +02:00
|
|
|
!yv12_fb_new->corrupted)
|
2011-08-08 10:56:20 +02:00
|
|
|
pbi->decoded_key_frame = 1;
|
|
|
|
else
|
|
|
|
vpx_internal_error(&pbi->common.error, VPX_CODEC_CORRUPT_FRAME,
|
|
|
|
"A stream must start with a complete key frame");
|
|
|
|
}
|
2010-12-16 16:46:31 +01:00
|
|
|
|
2010-10-28 01:04:02 +02:00
|
|
|
/* vpx_log("Decoder: Frame Decoded, Size Roughly:%d bytes \n",bc->pos+pbi->bc2.pos); */
|
2010-05-18 17:58:33 +02:00
|
|
|
|
|
|
|
if (pc->refresh_entropy_probs == 0)
|
|
|
|
{
|
|
|
|
vpx_memcpy(&pc->fc, &pc->lfc, sizeof(pc->fc));
|
2011-08-08 10:56:20 +02:00
|
|
|
pbi->independent_partitions = prev_independent_partitions;
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef PACKET_TESTING
|
|
|
|
{
|
|
|
|
FILE *f = fopen("decompressor.VP8", "ab");
|
|
|
|
unsigned int size = pbi->bc2.pos + pbi->bc.pos + 8;
|
|
|
|
fwrite((void *) &size, 4, 1, f);
|
|
|
|
fwrite((void *) pbi->Source, size, 1, f);
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|