blob: 29829062e585a1083ccfa22607283ebbe1889a27 [file] [log] [blame]
/*
* Copyright (c) 2010, 2011, Google Inc. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be
* found in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "vpx_codec_internal.h"
#include "bit_ops.h"
#include "dixie.h"
#include "vp8_prob_data.h"
#include "dequant_data.h"
#include "modemv.h"
#include "tokens.h"
#include "predict.h"
#include "dixie_loopfilter.h"
#include <string.h>
#include <assert.h>
enum
{
FRAME_HEADER_SZ = 3,
KEYFRAME_HEADER_SZ = 7
};
#define ARRAY_COPY(a,b) {\
assert(sizeof(a)==sizeof(b));memcpy(a,b,sizeof(a));}
static void
decode_entropy_header(struct vp8_decoder_ctx *ctx,
struct bool_decoder *bool,
struct vp8_entropy_hdr *hdr)
{
int i, j, k, l;
/* Read coefficient probability updates */
for (i = 0; i < BLOCK_TYPES; i++)
for (j = 0; j < COEFF_BANDS; j++)
for (k = 0; k < PREV_COEFF_CONTEXTS; k++)
for (l = 0; l < ENTROPY_NODES; l++)
if (bool_get(bool,
k_coeff_entropy_update_probs
[i][j][k][l]))
hdr->coeff_probs[i][j][k][l] =
bool_get_uint(bool, 8);
/* Read coefficient skip mode probability */
hdr->coeff_skip_enabled = bool_get_bit(bool);
if (hdr->coeff_skip_enabled)
hdr->coeff_skip_prob = bool_get_uint(bool, 8);
/* Parse interframe probability updates */
if (!ctx->frame_hdr.is_keyframe)
{
hdr->prob_inter = bool_get_uint(bool, 8);
hdr->prob_last = bool_get_uint(bool, 8);
hdr->prob_gf = bool_get_uint(bool, 8);
if (bool_get_bit(bool))
for (i = 0; i < 4; i++)
hdr->y_mode_probs[i] = bool_get_uint(bool, 8);
if (bool_get_bit(bool))
for (i = 0; i < 3; i++)
hdr->uv_mode_probs[i] = bool_get_uint(bool, 8);
for (i = 0; i < 2; i++)
for (j = 0; j < MV_PROB_CNT; j++)
if (bool_get(bool, k_mv_entropy_update_probs[i][j]))
{
int x = bool_get_uint(bool, 7);
hdr->mv_probs[i][j] = x ? x << 1 : 1;
}
}
}
static void
decode_reference_header(struct vp8_decoder_ctx *ctx,
struct bool_decoder *bool,
struct vp8_reference_hdr *hdr)
{
unsigned int key = ctx->frame_hdr.is_keyframe;
hdr->refresh_gf = key ? 1 : bool_get_bit(bool);
hdr->refresh_arf = key ? 1 : bool_get_bit(bool);
hdr->copy_gf = key ? 0 : !hdr->refresh_gf
? bool_get_uint(bool, 2) : 0;
hdr->copy_arf = key ? 0 : !hdr->refresh_arf
? bool_get_uint(bool, 2) : 0;
hdr->sign_bias[GOLDEN_FRAME] = key ? 0 : bool_get_bit(bool);
hdr->sign_bias[ALTREF_FRAME] = key ? 0 : bool_get_bit(bool);
hdr->refresh_entropy = bool_get_bit(bool);
hdr->refresh_last = key ? 1 : bool_get_bit(bool);
}
static void
decode_quantizer_header(struct vp8_decoder_ctx *ctx,
struct bool_decoder *bool,
struct vp8_quant_hdr *hdr)
{
int update;
int last_q = hdr->q_index;
hdr->q_index = bool_get_uint(bool, 7);
update = last_q != hdr->q_index;
update |= (hdr->y1_dc_delta_q = bool_maybe_get_int(bool, 4));
update |= (hdr->y2_dc_delta_q = bool_maybe_get_int(bool, 4));
update |= (hdr->y2_ac_delta_q = bool_maybe_get_int(bool, 4));
update |= (hdr->uv_dc_delta_q = bool_maybe_get_int(bool, 4));
update |= (hdr->uv_ac_delta_q = bool_maybe_get_int(bool, 4));
hdr->delta_update = update;
}
static void
decode_and_init_token_partitions(struct vp8_decoder_ctx *ctx,
struct bool_decoder *bool,
const unsigned char *data,
unsigned int sz,
struct vp8_token_hdr *hdr)
{
int i;
hdr->partitions = 1 << bool_get_uint(bool, 2);
if (sz < 3 *(hdr->partitions - 1))
vpx_internal_error(&ctx->error, VPX_CODEC_CORRUPT_FRAME,
"Truncated packet found parsing partition"
" lengths.");
sz -= 3 * (hdr->partitions - 1);
for (i = 0; i < hdr->partitions; i++)
{
if (i < hdr->partitions - 1)
{
hdr->partition_sz[i] = (data[2] << 16)
| (data[1] << 8) | data[0];
data += 3;
}
else
hdr->partition_sz[i] = sz;
if (sz < hdr->partition_sz[i])
vpx_internal_error(&ctx->error, VPX_CODEC_CORRUPT_FRAME,
"Truncated partition %d", i);
sz -= hdr->partition_sz[i];
}
for (i = 0; i < ctx->token_hdr.partitions; i++)
{
init_bool_decoder(&ctx->tokens[i].bool, data,
ctx->token_hdr.partition_sz[i]);
data += ctx->token_hdr.partition_sz[i];
}
}
static void
decode_loopfilter_header(struct vp8_decoder_ctx *ctx,
struct bool_decoder *bool,
struct vp8_loopfilter_hdr *hdr)
{
if (ctx->frame_hdr.is_keyframe)
memset(hdr, 0, sizeof(*hdr));
hdr->use_simple = bool_get_bit(bool);
hdr->level = bool_get_uint(bool, 6);
hdr->sharpness = bool_get_uint(bool, 3);
hdr->delta_enabled = bool_get_bit(bool);
if (hdr->delta_enabled && bool_get_bit(bool))
{
int i;
for (i = 0; i < BLOCK_CONTEXTS; i++)
hdr->ref_delta[i] = bool_maybe_get_int(bool, 6);
for (i = 0; i < BLOCK_CONTEXTS; i++)
hdr->mode_delta[i] = bool_maybe_get_int(bool, 6);
}
}
static void
decode_segmentation_header(struct vp8_decoder_ctx *ctx,
struct bool_decoder *bool,
struct vp8_segment_hdr *hdr)
{
if (ctx->frame_hdr.is_keyframe)
memset(hdr, 0, sizeof(*hdr));
hdr->enabled = bool_get_bit(bool);
if (hdr->enabled)
{
int i;
hdr->update_map = bool_get_bit(bool);
hdr->update_data = bool_get_bit(bool);
if (hdr->update_data)
{
hdr->abs = bool_get_bit(bool);
for (i = 0; i < MAX_MB_SEGMENTS; i++)
hdr->quant_idx[i] = bool_maybe_get_int(bool, 7);
for (i = 0; i < MAX_MB_SEGMENTS; i++)
hdr->lf_level[i] = bool_maybe_get_int(bool, 6);
}
if (hdr->update_map)
{
for (i = 0; i < MB_FEATURE_TREE_PROBS; i++)
hdr->tree_probs[i] = bool_get_bit(bool)
? bool_get_uint(bool, 8)
: 255;
}
}
else
{
hdr->update_map = 0;
hdr->update_data = 0;
}
}
static void
dequant_global_init(struct dequant_factors dqf[MAX_MB_SEGMENTS])
{
int i;
for (i = 0; i < MAX_MB_SEGMENTS; i++)
dqf[i].quant_idx = -1;
}
static int
clamp_q(int q)
{
if (q < 0) return 0;
else if (q > 127) return 127;
return q;
}
static int
dc_q(int q)
{
return dc_q_lookup[clamp_q(q)];
}
static int
ac_q(int q)
{
return ac_q_lookup[clamp_q(q)];
}
static void
dequant_init(struct dequant_factors factors[MAX_MB_SEGMENTS],
const struct vp8_segment_hdr *seg,
const struct vp8_quant_hdr *quant_hdr)
{
int i, q;
struct dequant_factors *dqf = factors;
for (i = 0; i < (seg->enabled ? MAX_MB_SEGMENTS : 1); i++)
{
q = quant_hdr->q_index;
if (seg->enabled)
q = (!seg->abs) ? q + seg->quant_idx[i]
: seg->quant_idx[i];
if (dqf->quant_idx != q || quant_hdr->delta_update)
{
dqf->factor[TOKEN_BLOCK_Y1][0] =
dc_q(q + quant_hdr->y1_dc_delta_q);
dqf->factor[TOKEN_BLOCK_Y1][1] =
ac_q(q);
dqf->factor[TOKEN_BLOCK_UV][0] =
dc_q(q + quant_hdr->uv_dc_delta_q);
dqf->factor[TOKEN_BLOCK_UV][1] =
ac_q(q + quant_hdr->uv_ac_delta_q);
dqf->factor[TOKEN_BLOCK_Y2][0] =
dc_q(q + quant_hdr->y2_dc_delta_q) * 2;
dqf->factor[TOKEN_BLOCK_Y2][1] =
ac_q(q + quant_hdr->y2_ac_delta_q) * 155 / 100;
if (dqf->factor[TOKEN_BLOCK_Y2][1] < 8)
dqf->factor[TOKEN_BLOCK_Y2][1] = 8;
if (dqf->factor[TOKEN_BLOCK_UV][0] > 132)
dqf->factor[TOKEN_BLOCK_UV][0] = 132;
dqf->quant_idx = q;
}
dqf++;
}
}
static void
decode_frame(struct vp8_decoder_ctx *ctx,
const unsigned char *data,
unsigned int sz)
{
vpx_codec_err_t res;
struct bool_decoder bool;
int i, row, partition;
ctx->saved_entropy_valid = 0;
if ((res = vp8_parse_frame_header(data, sz, &ctx->frame_hdr)))
vpx_internal_error(&ctx->error, res,
"Failed to parse frame header");
if (ctx->frame_hdr.is_experimental)
vpx_internal_error(&ctx->error, VPX_CODEC_UNSUP_BITSTREAM,
"Experimental bitstreams not supported.");
data += FRAME_HEADER_SZ;
sz -= FRAME_HEADER_SZ;
if (ctx->frame_hdr.is_keyframe)
{
data += KEYFRAME_HEADER_SZ;
sz -= KEYFRAME_HEADER_SZ;
ctx->mb_cols = (ctx->frame_hdr.kf.w + 15) / 16;
ctx->mb_rows = (ctx->frame_hdr.kf.h + 15) / 16;
}
/* Start the bitreader for the header/entropy partition */
init_bool_decoder(&bool, data, ctx->frame_hdr.part0_sz);
/* Skip the colorspace and clamping bits */
if (ctx->frame_hdr.is_keyframe)
if (bool_get_uint(&bool, 2))
vpx_internal_error(
&ctx->error, VPX_CODEC_UNSUP_BITSTREAM,
"Reserved bits not supported.");
decode_segmentation_header(ctx, &bool, &ctx->segment_hdr);
decode_loopfilter_header(ctx, &bool, &ctx->loopfilter_hdr);
decode_and_init_token_partitions(ctx,
&bool,
data + ctx->frame_hdr.part0_sz,
sz - ctx->frame_hdr.part0_sz,
&ctx->token_hdr);
decode_quantizer_header(ctx, &bool, &ctx->quant_hdr);
decode_reference_header(ctx, &bool, &ctx->reference_hdr);
/* Set keyframe entropy defaults. These get updated on keyframes
* regardless of the refresh_entropy setting.
*/
if (ctx->frame_hdr.is_keyframe)
{
ARRAY_COPY(ctx->entropy_hdr.coeff_probs,
k_default_coeff_probs);
ARRAY_COPY(ctx->entropy_hdr.mv_probs,
k_default_mv_probs);
ARRAY_COPY(ctx->entropy_hdr.y_mode_probs,
k_default_y_mode_probs);
ARRAY_COPY(ctx->entropy_hdr.uv_mode_probs,
k_default_uv_mode_probs);
}
if (!ctx->reference_hdr.refresh_entropy)
{
ctx->saved_entropy = ctx->entropy_hdr;
ctx->saved_entropy_valid = 1;
}
decode_entropy_header(ctx, &bool, &ctx->entropy_hdr);
vp8_dixie_modemv_init(ctx);
vp8_dixie_tokens_init(ctx);
vp8_dixie_predict_init(ctx);
dequant_init(ctx->dequant_factors, &ctx->segment_hdr,
&ctx->quant_hdr);
for (row = 0, partition = 0; row < ctx->mb_rows; row++)
{
vp8_dixie_modemv_process_row(
ctx, &bool, row, 0, ctx->mb_cols);
vp8_dixie_tokens_process_row(ctx, partition, row, 0,
ctx->mb_cols);
vp8_dixie_predict_process_row(ctx, row, 0, ctx->mb_cols);
if (ctx->loopfilter_hdr.level && row)
vp8_dixie_loopfilter_process_row(ctx, row - 1, 0,
ctx->mb_cols);
if (++partition == ctx->token_hdr.partitions)
partition = 0;
}
if (ctx->loopfilter_hdr.level)
vp8_dixie_loopfilter_process_row(
ctx, row - 1, 0, ctx->mb_cols);
ctx->frame_cnt++;
if (!ctx->reference_hdr.refresh_entropy)
{
ctx->entropy_hdr = ctx->saved_entropy;
ctx->saved_entropy_valid = 0;
}
/* Handle reference frame updates */
if (ctx->reference_hdr.copy_arf == 1)
{
vp8_dixie_release_ref_frame(ctx->ref_frames[ALTREF_FRAME]);
ctx->ref_frames[ALTREF_FRAME] =
vp8_dixie_ref_frame(ctx->ref_frames[LAST_FRAME]);
}
else if (ctx->reference_hdr.copy_arf == 2)
{
vp8_dixie_release_ref_frame(ctx->ref_frames[ALTREF_FRAME]);
ctx->ref_frames[ALTREF_FRAME] =
vp8_dixie_ref_frame(ctx->ref_frames[GOLDEN_FRAME]);
}
if (ctx->reference_hdr.copy_gf == 1)
{
vp8_dixie_release_ref_frame(ctx->ref_frames[GOLDEN_FRAME]);
ctx->ref_frames[GOLDEN_FRAME] =
vp8_dixie_ref_frame(ctx->ref_frames[LAST_FRAME]);
}
else if (ctx->reference_hdr.copy_gf == 2)
{
vp8_dixie_release_ref_frame(ctx->ref_frames[GOLDEN_FRAME]);
ctx->ref_frames[GOLDEN_FRAME] =
vp8_dixie_ref_frame(ctx->ref_frames[ALTREF_FRAME]);
}
if (ctx->reference_hdr.refresh_gf)
{
vp8_dixie_release_ref_frame(ctx->ref_frames[GOLDEN_FRAME]);
ctx->ref_frames[GOLDEN_FRAME] =
vp8_dixie_ref_frame(ctx->ref_frames[CURRENT_FRAME]);
}
if (ctx->reference_hdr.refresh_arf)
{
vp8_dixie_release_ref_frame(ctx->ref_frames[ALTREF_FRAME]);
ctx->ref_frames[ALTREF_FRAME] =
vp8_dixie_ref_frame(ctx->ref_frames[CURRENT_FRAME]);
}
if (ctx->reference_hdr.refresh_last)
{
vp8_dixie_release_ref_frame(ctx->ref_frames[LAST_FRAME]);
ctx->ref_frames[LAST_FRAME] =
vp8_dixie_ref_frame(ctx->ref_frames[CURRENT_FRAME]);
}
}
void
vp8_dixie_decode_init(struct vp8_decoder_ctx *ctx)
{
dequant_global_init(ctx->dequant_factors);
}
#define CHECK_FOR_UPDATE(lval,rval,update_flag) do {\
unsigned int old = lval; \
update_flag |= (old != (lval = rval)); \
} while(0)
vpx_codec_err_t
vp8_parse_frame_header(const unsigned char *data,
unsigned int sz,
struct vp8_frame_hdr *hdr)
{
unsigned long raw;
if (sz < 10)
return VPX_CODEC_CORRUPT_FRAME;
/* The frame header is defined as a three-byte little endian
* value
*/
raw = data[0] | (data[1] << 8) | (data[2] << 16);
hdr->is_keyframe = !BITS_GET(raw, 0, 1);
hdr->version = BITS_GET(raw, 1, 2);
hdr->is_experimental = BITS_GET(raw, 3, 1);
hdr->is_shown = BITS_GET(raw, 4, 1);
hdr->part0_sz = BITS_GET(raw, 5, 19);
if (sz <= hdr->part0_sz + (hdr->is_keyframe ? 10 : 3))
return VPX_CODEC_CORRUPT_FRAME;
hdr->frame_size_updated = 0;
if (hdr->is_keyframe)
{
unsigned int update = 0;
/* Keyframe header consists of a three-byte sync code
* followed by the width and height and associated scaling
* factors.
*/
if (data[3] != 0x9d || data[4] != 0x01 || data[5] != 0x2a)
return VPX_CODEC_UNSUP_BITSTREAM;
raw = data[6] | (data[7] << 8)
| (data[8] << 16) | (data[9] << 24);
CHECK_FOR_UPDATE(hdr->kf.w, BITS_GET(raw, 0, 14),
update);
CHECK_FOR_UPDATE(hdr->kf.scale_w, BITS_GET(raw, 14, 2),
update);
CHECK_FOR_UPDATE(hdr->kf.h, BITS_GET(raw, 16, 14),
update);
CHECK_FOR_UPDATE(hdr->kf.scale_h, BITS_GET(raw, 30, 2),
update);
hdr->frame_size_updated = update;
if (!hdr->kf.w || !hdr->kf.h)
return VPX_CODEC_UNSUP_BITSTREAM;
}
return VPX_CODEC_OK;
}
vpx_codec_err_t
vp8_dixie_decode_frame(struct vp8_decoder_ctx *ctx,
const unsigned char *data,
unsigned int sz)
{
volatile struct vp8_decoder_ctx *ctx_ = ctx;
ctx->error.error_code = VPX_CODEC_OK;
ctx->error.has_detail = 0;
if (!setjmp(ctx->error.jmp))
decode_frame(ctx, data, sz);
return ctx_->error.error_code;
}
void
vp8_dixie_decode_destroy(struct vp8_decoder_ctx *ctx)
{
vp8_dixie_predict_destroy(ctx);
vp8_dixie_tokens_destroy(ctx);
vp8_dixie_modemv_destroy(ctx);
}