Import aom library

This is the reference implementation for the Alliance for Open Media's av1 video code.

The commit used was 4d668d7feb1f8abd809d1bca0418570a7f142a36.
This commit is contained in:
trav90 2018-10-15 21:45:30 -05:00 • committed by Roy Tam
commit edc8d83307
989 changed files with 470949 additions and 0 deletions

138
third_party/aom/av1/decoder/accounting.c vendored Normal file
View file

@ -0,0 +1,138 @@
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "aom/aom_integer.h"
#include "./accounting.h"
static int aom_accounting_hash(const char *str) {
uint32_t val;
const unsigned char *ustr;
val = 0;
ustr = (const unsigned char *)str;
/* This is about the worst hash one can design, but it should be good enough
here. */
while (*ustr) val += *ustr++;
return val % AOM_ACCOUNTING_HASH_SIZE;
}
/* Dictionary lookup based on an open-addressing hash table. */
int aom_accounting_dictionary_lookup(Accounting *accounting, const char *str) {
int hash;
int len;
AccountingDictionary *dictionary;
dictionary = &accounting->syms.dictionary;
hash = aom_accounting_hash(str);
while (accounting->hash_dictionary[hash] != -1) {
if (strcmp(dictionary->strs[accounting->hash_dictionary[hash]], str) == 0) {
return accounting->hash_dictionary[hash];
}
hash++;
if (hash == AOM_ACCOUNTING_HASH_SIZE) hash = 0;
}
/* No match found. */
assert(dictionary->num_strs + 1 < MAX_SYMBOL_TYPES);
accounting->hash_dictionary[hash] = dictionary->num_strs;
len = strlen(str);
dictionary->strs[dictionary->num_strs] = malloc(len + 1);
snprintf(dictionary->strs[dictionary->num_strs], len + 1, "%s", str);
dictionary->num_strs++;
return dictionary->num_strs - 1;
}
void aom_accounting_init(Accounting *accounting) {
int i;
accounting->num_syms_allocated = 1000;
accounting->syms.syms =
malloc(sizeof(AccountingSymbol) * accounting->num_syms_allocated);
accounting->syms.dictionary.num_strs = 0;
assert(AOM_ACCOUNTING_HASH_SIZE > 2 * MAX_SYMBOL_TYPES);
for (i = 0; i < AOM_ACCOUNTING_HASH_SIZE; i++)
accounting->hash_dictionary[i] = -1;
aom_accounting_reset(accounting);
}
void aom_accounting_reset(Accounting *accounting) {
accounting->syms.num_syms = 0;
accounting->syms.num_binary_syms = 0;
accounting->syms.num_multi_syms = 0;
accounting->context.x = -1;
accounting->context.y = -1;
accounting->last_tell_frac = 0;
}
void aom_accounting_clear(Accounting *accounting) {
int i;
AccountingDictionary *dictionary;
free(accounting->syms.syms);
dictionary = &accounting->syms.dictionary;
for (i = 0; i < dictionary->num_strs; i++) {
free(dictionary->strs[i]);
}
}
void aom_accounting_set_context(Accounting *accounting, int16_t x, int16_t y) {
accounting->context.x = x;
accounting->context.y = y;
}
void aom_accounting_record(Accounting *accounting, const char *str,
uint32_t bits) {
AccountingSymbol sym;
// Reuse previous symbol if it has the same context and symbol id.
if (accounting->syms.num_syms) {
AccountingSymbol *last_sym;
last_sym = &accounting->syms.syms[accounting->syms.num_syms - 1];
if (memcmp(&last_sym->context, &accounting->context,
sizeof(AccountingSymbolContext)) == 0) {
uint32_t id;
id = aom_accounting_dictionary_lookup(accounting, str);
if (id == last_sym->id) {
last_sym->bits += bits;
last_sym->samples++;
return;
}
}
}
sym.context = accounting->context;
sym.samples = 1;
sym.bits = bits;
sym.id = aom_accounting_dictionary_lookup(accounting, str);
assert(sym.id <= 255);
if (accounting->syms.num_syms == accounting->num_syms_allocated) {
accounting->num_syms_allocated *= 2;
accounting->syms.syms =
realloc(accounting->syms.syms,
sizeof(AccountingSymbol) * accounting->num_syms_allocated);
assert(accounting->syms.syms != NULL);
}
accounting->syms.syms[accounting->syms.num_syms++] = sym;
}
void aom_accounting_dump(Accounting *accounting) {
int i;
AccountingSymbol *sym;
printf("\n----- Number of recorded syntax elements = %d -----\n",
accounting->syms.num_syms);
printf("----- Total number of symbol calls = %d (%d binary) -----\n",
accounting->syms.num_multi_syms + accounting->syms.num_binary_syms,
accounting->syms.num_binary_syms);
for (i = 0; i < accounting->syms.num_syms; i++) {
sym = &accounting->syms.syms[i];
printf("%s x: %d, y: %d bits: %f samples: %d\n",
accounting->syms.dictionary.strs[sym->id], sym->context.x,
sym->context.y, (float)sym->bits / 8.0, sym->samples);
}
}

View file

@ -0,0 +1,83 @@
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#ifndef AOM_ACCOUNTING_H_
#define AOM_ACCOUNTING_H_
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#define AOM_ACCOUNTING_HASH_SIZE (1021)
/* Max number of entries for symbol types in the dictionary (increase as
necessary). */
#define MAX_SYMBOL_TYPES (256)
/*The resolution of fractional-precision bit usage measurements, i.e.,
3 => 1/8th bits.*/
#define AOM_ACCT_BITRES (3)
typedef struct {
int16_t x;
int16_t y;
} AccountingSymbolContext;
typedef struct {
AccountingSymbolContext context;
uint32_t id;
/** Number of bits in units of 1/8 bit. */
uint32_t bits;
uint32_t samples;
} AccountingSymbol;
/** Dictionary for translating strings into id. */
typedef struct {
char *(strs[MAX_SYMBOL_TYPES]);
int num_strs;
} AccountingDictionary;
typedef struct {
/** All recorded symbols decoded. */
AccountingSymbol *syms;
/** Number of syntax actually recorded. */
int num_syms;
/** Raw symbol decoding calls for non-binary values. */
int num_multi_syms;
/** Raw binary symbol decoding calls. */
int num_binary_syms;
/** Dictionary for translating strings into id. */
AccountingDictionary dictionary;
} AccountingSymbols;
typedef struct Accounting Accounting;
struct Accounting {
AccountingSymbols syms;
/** Size allocated for symbols (not all may be used). */
int num_syms_allocated;
int16_t hash_dictionary[AOM_ACCOUNTING_HASH_SIZE];
AccountingSymbolContext context;
uint32_t last_tell_frac;
};
void aom_accounting_init(Accounting *accounting);
void aom_accounting_reset(Accounting *accounting);
void aom_accounting_clear(Accounting *accounting);
void aom_accounting_set_context(Accounting *accounting, int16_t x, int16_t y);
int aom_accounting_dictionary_lookup(Accounting *accounting, const char *str);
void aom_accounting_record(Accounting *accounting, const char *str,
uint32_t bits);
void aom_accounting_dump(Accounting *accounting);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // AOM_ACCOUNTING_H_

35
third_party/aom/av1/decoder/decint.h vendored Normal file
View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2001-2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
/* clang-format off */
#if !defined(_decint_H)
# define _decint_H (1)
# include "av1/common/pvq_state.h"
# include "aom_dsp/bitreader.h"
# include "aom_dsp/entdec.h"
typedef struct daala_dec_ctx daala_dec_ctx;
typedef struct daala_dec_ctx od_dec_ctx;
struct daala_dec_ctx {
/* Stores context-adaptive CDFs for PVQ. */
od_state state;
/* AOM entropy decoder. */
aom_reader *r;
int use_activity_masking;
/* Mode of quantization matrice : FLAT (0) or HVS (1) */
int qm;
};
#endif

5159
third_party/aom/av1/decoder/decodeframe.c vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#ifndef AV1_DECODER_DECODEFRAME_H_
#define AV1_DECODER_DECODEFRAME_H_
#ifdef __cplusplus
extern "C" {
#endif
struct AV1Decoder;
struct aom_read_bit_buffer;
#if CONFIG_REFERENCE_BUFFER
/* Placeholder for now */
void read_sequence_header(SequenceHeader *seq_params);
#endif
int av1_read_sync_code(struct aom_read_bit_buffer *const rb);
void av1_read_frame_size(struct aom_read_bit_buffer *rb, int *width,
int *height);
BITSTREAM_PROFILE av1_read_profile(struct aom_read_bit_buffer *rb);
void av1_decode_frame(struct AV1Decoder *pbi, const uint8_t *data,
const uint8_t *data_end, const uint8_t **p_data_end);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // AV1_DECODER_DECODEFRAME_H_

2405
third_party/aom/av1/decoder/decodemv.c vendored Normal file

File diff suppressed because it is too large Load diff

44
third_party/aom/av1/decoder/decodemv.h vendored Normal file
View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#ifndef AV1_DECODER_DECODEMV_H_
#define AV1_DECODER_DECODEMV_H_
#include "aom_dsp/bitreader.h"
#include "av1/decoder/decoder.h"
#ifdef __cplusplus
extern "C" {
#endif
void av1_read_mode_info(AV1Decoder *const pbi, MACROBLOCKD *xd,
#if CONFIG_SUPERTX
int supertx_enabled,
#endif
int mi_row, int mi_col, aom_reader *r, int x_mis,
int y_mis);
#ifdef __cplusplus
} // extern "C"
#endif
void av1_read_tx_type(const AV1_COMMON *const cm, MACROBLOCKD *xd,
#if CONFIG_SUPERTX
int supertx_enabled,
#endif
#if CONFIG_TXK_SEL
int block, int plane,
#endif
aom_reader *r);
#endif // AV1_DECODER_DECODEMV_H_

583
third_party/aom/av1/decoder/decoder.c vendored Normal file
View file

@ -0,0 +1,583 @@
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include "./av1_rtcd.h"
#include "./aom_dsp_rtcd.h"
#include "./aom_scale_rtcd.h"
#include "aom_mem/aom_mem.h"
#include "aom_ports/system_state.h"
#include "aom_ports/aom_once.h"
#include "aom_ports/aom_timer.h"
#include "aom_scale/aom_scale.h"
#include "aom_util/aom_thread.h"
#include "av1/common/alloccommon.h"
#include "av1/common/av1_loopfilter.h"
#include "av1/common/onyxc_int.h"
#include "av1/common/quant_common.h"
#include "av1/common/reconinter.h"
#include "av1/common/reconintra.h"
#include "av1/decoder/decodeframe.h"
#include "av1/decoder/decoder.h"
#if !CONFIG_PVQ
#include "av1/decoder/detokenize.h"
#endif
static void initialize_dec(void) {
static volatile int init_done = 0;
if (!init_done) {
av1_rtcd();
aom_dsp_rtcd();
aom_scale_rtcd();
av1_init_intra_predictors();
#if CONFIG_EXT_INTER
av1_init_wedge_masks();
#endif // CONFIG_EXT_INTER
init_done = 1;
#if CONFIG_EC_MULTISYMBOL
av1_indices_from_tree(av1_intra_mode_ind, av1_intra_mode_inv,
av1_intra_mode_tree);
av1_indices_from_tree(av1_switchable_interp_ind, av1_switchable_interp_inv,
av1_switchable_interp_tree);
#if CONFIG_EXT_TX
int s;
for (s = 1; s < EXT_TX_SETS_INTRA; ++s)
av1_indices_from_tree(av1_ext_tx_intra_ind[s], av1_ext_tx_intra_inv[s],
av1_ext_tx_intra_tree[s]);
for (s = 1; s < EXT_TX_SETS_INTER; ++s)
av1_indices_from_tree(av1_ext_tx_inter_ind[s], av1_ext_tx_inter_inv[s],
av1_ext_tx_inter_tree[s]);
#else
av1_indices_from_tree(av1_ext_tx_ind, av1_ext_tx_inv, av1_ext_tx_tree);
#endif
av1_indices_from_tree(av1_inter_mode_ind, av1_inter_mode_inv,
av1_inter_mode_tree);
#endif
}
}
static void av1_dec_setup_mi(AV1_COMMON *cm) {
cm->mi = cm->mip + cm->mi_stride + 1;
cm->mi_grid_visible = cm->mi_grid_base + cm->mi_stride + 1;
memset(cm->mi_grid_base, 0,
cm->mi_stride * (cm->mi_rows + 1) * sizeof(*cm->mi_grid_base));
}
static int av1_dec_alloc_mi(AV1_COMMON *cm, int mi_size) {
cm->mip = aom_calloc(mi_size, sizeof(*cm->mip));
if (!cm->mip) return 1;
cm->mi_alloc_size = mi_size;
cm->mi_grid_base = (MODE_INFO **)aom_calloc(mi_size, sizeof(MODE_INFO *));
if (!cm->mi_grid_base) return 1;
return 0;
}
static void av1_dec_free_mi(AV1_COMMON *cm) {
aom_free(cm->mip);
cm->mip = NULL;
aom_free(cm->mi_grid_base);
cm->mi_grid_base = NULL;
}
AV1Decoder *av1_decoder_create(BufferPool *const pool) {
AV1Decoder *volatile const pbi = aom_memalign(32, sizeof(*pbi));
AV1_COMMON *volatile const cm = pbi ? &pbi->common : NULL;
if (!cm) return NULL;
av1_zero(*pbi);
if (setjmp(cm->error.jmp)) {
cm->error.setjmp = 0;
av1_decoder_remove(pbi);
return NULL;
}
cm->error.setjmp = 1;
CHECK_MEM_ERROR(cm, cm->fc,
(FRAME_CONTEXT *)aom_memalign(32, sizeof(*cm->fc)));
CHECK_MEM_ERROR(cm, cm->frame_contexts,
(FRAME_CONTEXT *)aom_memalign(
32, FRAME_CONTEXTS * sizeof(*cm->frame_contexts)));
memset(cm->fc, 0, sizeof(*cm->fc));
memset(cm->frame_contexts, 0, FRAME_CONTEXTS * sizeof(*cm->frame_contexts));
pbi->need_resync = 1;
once(initialize_dec);
// Initialize the references to not point to any frame buffers.
memset(&cm->ref_frame_map, -1, sizeof(cm->ref_frame_map));
memset(&cm->next_ref_frame_map, -1, sizeof(cm->next_ref_frame_map));
cm->current_video_frame = 0;
pbi->ready_for_new_data = 1;
pbi->common.buffer_pool = pool;
cm->bit_depth = AOM_BITS_8;
cm->dequant_bit_depth = AOM_BITS_8;
cm->alloc_mi = av1_dec_alloc_mi;
cm->free_mi = av1_dec_free_mi;
cm->setup_mi = av1_dec_setup_mi;
av1_loop_filter_init(cm);
#if CONFIG_AOM_QM
aom_qm_init(cm);
#endif
#if CONFIG_LOOP_RESTORATION
av1_loop_restoration_precal();
#endif // CONFIG_LOOP_RESTORATION
#if CONFIG_ACCOUNTING
pbi->acct_enabled = 1;
aom_accounting_init(&pbi->accounting);
#endif
cm->error.setjmp = 0;
aom_get_worker_interface()->init(&pbi->lf_worker);
return pbi;
}
void av1_decoder_remove(AV1Decoder *pbi) {
int i;
if (!pbi) return;
aom_get_worker_interface()->end(&pbi->lf_worker);
aom_free(pbi->lf_worker.data1);
aom_free(pbi->tile_data);
for (i = 0; i < pbi->num_tile_workers; ++i) {
AVxWorker *const worker = &pbi->tile_workers[i];
aom_get_worker_interface()->end(worker);
}
aom_free(pbi->tile_worker_data);
aom_free(pbi->tile_worker_info);
aom_free(pbi->tile_workers);
if (pbi->num_tile_workers > 0) {
av1_loop_filter_dealloc(&pbi->lf_row_sync);
}
#if CONFIG_ACCOUNTING
aom_accounting_clear(&pbi->accounting);
#endif
aom_free(pbi);
}
static int equal_dimensions(const YV12_BUFFER_CONFIG *a,
const YV12_BUFFER_CONFIG *b) {
return a->y_height == b->y_height && a->y_width == b->y_width &&
a->uv_height == b->uv_height && a->uv_width == b->uv_width;
}
aom_codec_err_t av1_copy_reference_dec(AV1Decoder *pbi,
AOM_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd) {
AV1_COMMON *cm = &pbi->common;
/* TODO(jkoleszar): The decoder doesn't have any real knowledge of what the
* encoder is using the frame buffers for. This is just a stub to keep the
* aomenc --test-decode functionality working, and will be replaced in a
* later commit that adds AV1-specific controls for this functionality.
*/
if (ref_frame_flag == AOM_LAST_FLAG) {
const YV12_BUFFER_CONFIG *const cfg = get_ref_frame(cm, 0);
if (cfg == NULL) {
aom_internal_error(&cm->error, AOM_CODEC_ERROR,
"No 'last' reference frame");
return AOM_CODEC_ERROR;
}
if (!equal_dimensions(cfg, sd))
aom_internal_error(&cm->error, AOM_CODEC_ERROR,
"Incorrect buffer dimensions");
else
aom_yv12_copy_frame(cfg, sd);
} else {
aom_internal_error(&cm->error, AOM_CODEC_ERROR, "Invalid reference frame");
}
return cm->error.error_code;
}
aom_codec_err_t av1_set_reference_dec(AV1_COMMON *cm,
AOM_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd) {
int idx;
YV12_BUFFER_CONFIG *ref_buf = NULL;
// TODO(jkoleszar): The decoder doesn't have any real knowledge of what the
// encoder is using the frame buffers for. This is just a stub to keep the
// aomenc --test-decode functionality working, and will be replaced in a
// later commit that adds AV1-specific controls for this functionality.
// (Yunqing) The set_reference control depends on the following setting in
// encoder.
// cpi->lst_fb_idx = 0;
// #if CONFIG_EXT_REFS
// cpi->lst2_fb_idx = 1;
// cpi->lst3_fb_idx = 2;
// cpi->gld_fb_idx = 3;
// cpi->bwd_fb_idx = 4;
// cpi->alt_fb_idx = 5;
// #else // CONFIG_EXT_REFS
// cpi->gld_fb_idx = 1;
// cpi->alt_fb_idx = 2;
// #endif // CONFIG_EXT_REFS
// TODO(zoeliu): To revisit following code and reconsider what assumption we
// may take on the reference frame buffer virtual indexes
if (ref_frame_flag == AOM_LAST_FLAG) {
idx = cm->ref_frame_map[0];
#if CONFIG_EXT_REFS
} else if (ref_frame_flag == AOM_LAST2_FLAG) {
idx = cm->ref_frame_map[1];
} else if (ref_frame_flag == AOM_LAST3_FLAG) {
idx = cm->ref_frame_map[2];
} else if (ref_frame_flag == AOM_GOLD_FLAG) {
idx = cm->ref_frame_map[3];
} else if (ref_frame_flag == AOM_BWD_FLAG) {
idx = cm->ref_frame_map[4];
} else if (ref_frame_flag == AOM_ALT_FLAG) {
idx = cm->ref_frame_map[5];
#else
} else if (ref_frame_flag == AOM_GOLD_FLAG) {
idx = cm->ref_frame_map[1];
} else if (ref_frame_flag == AOM_ALT_FLAG) {
idx = cm->ref_frame_map[2];
#endif // CONFIG_EXT_REFS
} else {
aom_internal_error(&cm->error, AOM_CODEC_ERROR, "Invalid reference frame");
return cm->error.error_code;
}
if (idx < 0 || idx >= FRAME_BUFFERS) {
aom_internal_error(&cm->error, AOM_CODEC_ERROR,
"Invalid reference frame map");
return cm->error.error_code;
}
// Get the destination reference buffer.
ref_buf = &cm->buffer_pool->frame_bufs[idx].buf;
if (!equal_dimensions(ref_buf, sd)) {
aom_internal_error(&cm->error, AOM_CODEC_ERROR,
"Incorrect buffer dimensions");
} else {
// Overwrite the reference frame buffer.
aom_yv12_copy_frame(sd, ref_buf);
}
return cm->error.error_code;
}
/* If any buffer updating is signaled it should be done here. */
static void swap_frame_buffers(AV1Decoder *pbi) {
int ref_index = 0, mask;
AV1_COMMON *const cm = &pbi->common;
BufferPool *const pool = cm->buffer_pool;
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
lock_buffer_pool(pool);
for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
const int old_idx = cm->ref_frame_map[ref_index];
// Current thread releases the holding of reference frame.
decrease_ref_count(old_idx, frame_bufs, pool);
// Release the reference frame holding in the reference map for the decoding
// of the next frame.
if (mask & 1) decrease_ref_count(old_idx, frame_bufs, pool);
cm->ref_frame_map[ref_index] = cm->next_ref_frame_map[ref_index];
++ref_index;
}
// Current thread releases the holding of reference frame.
for (; ref_index < REF_FRAMES && !cm->show_existing_frame; ++ref_index) {
const int old_idx = cm->ref_frame_map[ref_index];
decrease_ref_count(old_idx, frame_bufs, pool);
cm->ref_frame_map[ref_index] = cm->next_ref_frame_map[ref_index];
}
unlock_buffer_pool(pool);
pbi->hold_ref_buf = 0;
cm->frame_to_show = get_frame_new_buffer(cm);
// TODO(zoeliu): To fix the ref frame buffer update for the scenario of
// cm->frame_parellel_decode == 1
if (!cm->frame_parallel_decode || !cm->show_frame) {
lock_buffer_pool(pool);
--frame_bufs[cm->new_fb_idx].ref_count;
unlock_buffer_pool(pool);
}
// Invalidate these references until the next frame starts.
for (ref_index = 0; ref_index < INTER_REFS_PER_FRAME; ref_index++) {
cm->frame_refs[ref_index].idx = INVALID_IDX;
cm->frame_refs[ref_index].buf = NULL;
}
}
int av1_receive_compressed_data(AV1Decoder *pbi, size_t size,
const uint8_t **psource) {
AV1_COMMON *volatile const cm = &pbi->common;
BufferPool *volatile const pool = cm->buffer_pool;
RefCntBuffer *volatile const frame_bufs = cm->buffer_pool->frame_bufs;
const uint8_t *source = *psource;
int retcode = 0;
cm->error.error_code = AOM_CODEC_OK;
if (size == 0) {
// This is used to signal that we are missing frames.
// We do not know if the missing frame(s) was supposed to update
// any of the reference buffers, but we act conservative and
// mark only the last buffer as corrupted.
//
// TODO(jkoleszar): Error concealment is undefined and non-normative
// at this point, but if it becomes so, [0] may not always be the correct
// thing to do here.
if (cm->frame_refs[0].idx > 0) {
assert(cm->frame_refs[0].buf != NULL);
cm->frame_refs[0].buf->corrupted = 1;
}
}
pbi->ready_for_new_data = 0;
// Find a free buffer for the new frame, releasing the reference previously
// held.
// Check if the previous frame was a frame without any references to it.
// Release frame buffer if not decoding in frame parallel mode.
if (!cm->frame_parallel_decode && cm->new_fb_idx >= 0 &&
frame_bufs[cm->new_fb_idx].ref_count == 0)
pool->release_fb_cb(pool->cb_priv,
&frame_bufs[cm->new_fb_idx].raw_frame_buffer);
// Find a free frame buffer. Return error if can not find any.
cm->new_fb_idx = get_free_fb(cm);
if (cm->new_fb_idx == INVALID_IDX) return AOM_CODEC_MEM_ERROR;
// Assign a MV array to the frame buffer.
cm->cur_frame = &pool->frame_bufs[cm->new_fb_idx];
pbi->hold_ref_buf = 0;
if (cm->frame_parallel_decode) {
AVxWorker *const worker = pbi->frame_worker_owner;
av1_frameworker_lock_stats(worker);
frame_bufs[cm->new_fb_idx].frame_worker_owner = worker;
// Reset decoding progress.
pbi->cur_buf = &frame_bufs[cm->new_fb_idx];
pbi->cur_buf->row = -1;
pbi->cur_buf->col = -1;
av1_frameworker_unlock_stats(worker);
} else {
pbi->cur_buf = &frame_bufs[cm->new_fb_idx];
}
if (setjmp(cm->error.jmp)) {
const AVxWorkerInterface *const winterface = aom_get_worker_interface();
int i;
cm->error.setjmp = 0;
pbi->ready_for_new_data = 1;
// Synchronize all threads immediately as a subsequent decode call may
// cause a resize invalidating some allocations.
winterface->sync(&pbi->lf_worker);
for (i = 0; i < pbi->num_tile_workers; ++i) {
winterface->sync(&pbi->tile_workers[i]);
}
lock_buffer_pool(pool);
// Release all the reference buffers if worker thread is holding them.
if (pbi->hold_ref_buf == 1) {
int ref_index = 0, mask;
for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
const int old_idx = cm->ref_frame_map[ref_index];
// Current thread releases the holding of reference frame.
decrease_ref_count(old_idx, frame_bufs, pool);
// Release the reference frame holding in the reference map for the
// decoding of the next frame.
if (mask & 1) decrease_ref_count(old_idx, frame_bufs, pool);
++ref_index;
}
// Current thread releases the holding of reference frame.
for (; ref_index < REF_FRAMES && !cm->show_existing_frame; ++ref_index) {
const int old_idx = cm->ref_frame_map[ref_index];
decrease_ref_count(old_idx, frame_bufs, pool);
}
pbi->hold_ref_buf = 0;
}
// Release current frame.
decrease_ref_count(cm->new_fb_idx, frame_bufs, pool);
unlock_buffer_pool(pool);
aom_clear_system_state();
return -1;
}
cm->error.setjmp = 1;
av1_decode_frame(pbi, source, source + size, psource);
swap_frame_buffers(pbi);
#if CONFIG_EXT_TILE
// For now, we only extend the frame borders when the whole frame is decoded.
// Later, if needed, extend the border for the decoded tile on the frame
// border.
if (pbi->dec_tile_row == -1 && pbi->dec_tile_col == -1)
#endif // CONFIG_EXT_TILE
aom_extend_frame_inner_borders(cm->frame_to_show);
aom_clear_system_state();
if (!cm->show_existing_frame) {
cm->last_show_frame = cm->show_frame;
#if CONFIG_EXT_REFS
// NOTE: It is not supposed to ref to any frame not used as reference
if (cm->is_reference_frame)
#endif // CONFIG_EXT_REFS
cm->prev_frame = cm->cur_frame;
if (cm->seg.enabled && !cm->frame_parallel_decode)
av1_swap_current_and_last_seg_map(cm);
}
// Update progress in frame parallel decode.
if (cm->frame_parallel_decode) {
// Need to lock the mutex here as another thread may
// be accessing this buffer.
AVxWorker *const worker = pbi->frame_worker_owner;
FrameWorkerData *const frame_worker_data = worker->data1;
av1_frameworker_lock_stats(worker);
if (cm->show_frame) {
cm->current_video_frame++;
}
frame_worker_data->frame_decoded = 1;
frame_worker_data->frame_context_ready = 1;
av1_frameworker_signal_stats(worker);
av1_frameworker_unlock_stats(worker);
} else {
cm->last_width = cm->width;
cm->last_height = cm->height;
if (cm->show_frame) {
cm->current_video_frame++;
}
}
cm->error.setjmp = 0;
return retcode;
}
int av1_get_raw_frame(AV1Decoder *pbi, YV12_BUFFER_CONFIG *sd) {
AV1_COMMON *const cm = &pbi->common;
int ret = -1;
if (pbi->ready_for_new_data == 1) return ret;
pbi->ready_for_new_data = 1;
/* no raw frame to show!!! */
if (!cm->show_frame) return ret;
pbi->ready_for_new_data = 1;
*sd = *cm->frame_to_show;
ret = 0;
aom_clear_system_state();
return ret;
}
int av1_get_frame_to_show(AV1Decoder *pbi, YV12_BUFFER_CONFIG *frame) {
AV1_COMMON *const cm = &pbi->common;
if (!cm->show_frame || !cm->frame_to_show) return -1;
*frame = *cm->frame_to_show;
return 0;
}
aom_codec_err_t av1_parse_superframe_index(const uint8_t *data, size_t data_sz,
uint32_t sizes[8], int *count,
aom_decrypt_cb decrypt_cb,
void *decrypt_state) {
// A chunk ending with a byte matching 0xc0 is an invalid chunk unless
// it is a super frame index. If the last byte of real video compression
// data is 0xc0 the encoder must add a 0 byte. If we have the marker but
// not the associated matching marker byte at the front of the index we have
// an invalid bitstream and need to return an error.
uint8_t marker;
size_t frame_sz_sum = 0;
assert(data_sz);
marker = read_marker(decrypt_cb, decrypt_state, data + data_sz - 1);
*count = 0;
if ((marker & 0xe0) == 0xc0) {
const uint32_t frames = (marker & 0x7) + 1;
const uint32_t mag = ((marker >> 3) & 0x3) + 1;
const size_t index_sz = 2 + mag * (frames - 1);
// This chunk is marked as having a superframe index but doesn't have
// enough data for it, thus it's an invalid superframe index.
if (data_sz < index_sz) return AOM_CODEC_CORRUPT_FRAME;
{
const uint8_t marker2 =
read_marker(decrypt_cb, decrypt_state, data + data_sz - index_sz);
// This chunk is marked as having a superframe index but doesn't have
// the matching marker byte at the front of the index therefore it's an
// invalid chunk.
if (marker != marker2) return AOM_CODEC_CORRUPT_FRAME;
}
{
// Found a valid superframe index.
uint32_t i, j;
const uint8_t *x = &data[data_sz - index_sz + 1];
// Frames has a maximum of 8 and mag has a maximum of 4.
uint8_t clear_buffer[28];
assert(sizeof(clear_buffer) >= (frames - 1) * mag);
if (decrypt_cb) {
decrypt_cb(decrypt_state, x, clear_buffer, (frames - 1) * mag);
x = clear_buffer;
}
for (i = 0; i < frames - 1; ++i) {
uint32_t this_sz = 0;
for (j = 0; j < mag; ++j) this_sz |= (*x++) << (j * 8);
this_sz += 1;
sizes[i] = this_sz;
frame_sz_sum += this_sz;
}
sizes[i] = (uint32_t)(data_sz - index_sz - frame_sz_sum);
*count = frames;
}
}
return AOM_CODEC_OK;
}

224
third_party/aom/av1/decoder/decoder.h vendored Normal file
View file

@ -0,0 +1,224 @@
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#ifndef AV1_DECODER_DECODER_H_
#define AV1_DECODER_DECODER_H_
#include "./aom_config.h"
#include "aom/aom_codec.h"
#include "aom_dsp/bitreader.h"
#include "aom_scale/yv12config.h"
#include "aom_util/aom_thread.h"
#include "av1/common/thread_common.h"
#include "av1/common/onyxc_int.h"
#include "av1/decoder/dthread.h"
#if CONFIG_ACCOUNTING
#include "av1/decoder/accounting.h"
#endif
#if CONFIG_INSPECTION
#include "av1/decoder/inspection.h"
#endif
#if CONFIG_PVQ
#include "aom_dsp/entdec.h"
#include "av1/decoder/decint.h"
#include "av1/encoder/encodemb.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
// TODO(hkuang): combine this with TileWorkerData.
typedef struct TileData {
AV1_COMMON *cm;
aom_reader bit_reader;
DECLARE_ALIGNED(16, MACROBLOCKD, xd);
/* dqcoeff are shared by all the planes. So planes must be decoded serially */
DECLARE_ALIGNED(16, tran_low_t, dqcoeff[MAX_TX_SQUARE]);
#if CONFIG_PVQ
/* forward transformed predicted image, a reference for PVQ */
DECLARE_ALIGNED(16, tran_low_t, pvq_ref_coeff[OD_TXSIZE_MAX * OD_TXSIZE_MAX]);
#endif
#if CONFIG_CFL
CFL_CTX cfl;
#endif
#if CONFIG_EC_ADAPT
DECLARE_ALIGNED(16, FRAME_CONTEXT, tctx);
#endif
#if CONFIG_PALETTE
DECLARE_ALIGNED(16, uint8_t, color_index_map[2][MAX_SB_SQUARE]);
#endif // CONFIG_PALETTE
} TileData;
typedef struct TileWorkerData {
struct AV1Decoder *pbi;
aom_reader bit_reader;
FRAME_COUNTS counts;
DECLARE_ALIGNED(16, MACROBLOCKD, xd);
/* dqcoeff are shared by all the planes. So planes must be decoded serially */
DECLARE_ALIGNED(16, tran_low_t, dqcoeff[MAX_TX_SQUARE]);
#if CONFIG_PVQ
/* forward transformed predicted image, a reference for PVQ */
DECLARE_ALIGNED(16, tran_low_t, pvq_ref_coeff[OD_TXSIZE_MAX * OD_TXSIZE_MAX]);
#endif
#if CONFIG_CFL
CFL_CTX cfl;
#endif
#if CONFIG_EC_ADAPT
FRAME_CONTEXT tctx;
#endif
#if CONFIG_PALETTE
DECLARE_ALIGNED(16, uint8_t, color_index_map[2][MAX_SB_SQUARE]);
#endif // CONFIG_PALETTE
struct aom_internal_error_info error_info;
} TileWorkerData;
typedef struct TileBufferDec {
const uint8_t *data;
size_t size;
const uint8_t *raw_data_end; // The end of the raw tile buffer in the
// bit stream.
int col; // only used with multi-threaded decoding
} TileBufferDec;
typedef struct AV1Decoder {
DECLARE_ALIGNED(16, MACROBLOCKD, mb);
DECLARE_ALIGNED(16, AV1_COMMON, common);
int ready_for_new_data;
int refresh_frame_flags;
// TODO(hkuang): Combine this with cur_buf in macroblockd as they are
// the same.
RefCntBuffer *cur_buf; // Current decoding frame buffer.
AVxWorker *frame_worker_owner; // frame_worker that owns this pbi.
AVxWorker lf_worker;
AVxWorker *tile_workers;
TileWorkerData *tile_worker_data;
TileInfo *tile_worker_info;
int num_tile_workers;
TileData *tile_data;
int allocated_tiles;
TileBufferDec tile_buffers[MAX_TILE_ROWS][MAX_TILE_COLS];
AV1LfSync lf_row_sync;
aom_decrypt_cb decrypt_cb;
void *decrypt_state;
int max_threads;
int inv_tile_order;
int need_resync; // wait for key/intra-only frame.
int hold_ref_buf; // hold the reference buffer.
int tile_size_bytes;
#if CONFIG_EXT_TILE
int tile_col_size_bytes;
int dec_tile_row, dec_tile_col;
#endif // CONFIG_EXT_TILE
#if CONFIG_ACCOUNTING
int acct_enabled;
Accounting accounting;
#endif
size_t uncomp_hdr_size; // Size of the uncompressed header
size_t first_partition_size; // Size of the compressed header
#if CONFIG_TILE_GROUPS
int tg_size; // Number of tiles in the current tilegroup
int tg_start; // First tile in the current tilegroup
int tg_size_bit_offset;
#endif
#if CONFIG_REFERENCE_BUFFER
SequenceHeader seq_params;
#endif
#if CONFIG_INSPECTION
aom_inspect_cb inspect_cb;
void *inspect_ctx;
#endif
} AV1Decoder;
int av1_receive_compressed_data(struct AV1Decoder *pbi, size_t size,
const uint8_t **dest);
int av1_get_raw_frame(struct AV1Decoder *pbi, YV12_BUFFER_CONFIG *sd);
int av1_get_frame_to_show(struct AV1Decoder *pbi, YV12_BUFFER_CONFIG *frame);
aom_codec_err_t av1_copy_reference_dec(struct AV1Decoder *pbi,
AOM_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd);
aom_codec_err_t av1_set_reference_dec(AV1_COMMON *cm,
AOM_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd);
static INLINE uint8_t read_marker(aom_decrypt_cb decrypt_cb,
void *decrypt_state, const uint8_t *data) {
if (decrypt_cb) {
uint8_t marker;
decrypt_cb(decrypt_state, data, &marker, 1);
return marker;
}
return *data;
}
// This function is exposed for use in tests, as well as the inlined function
// "read_marker".
aom_codec_err_t av1_parse_superframe_index(const uint8_t *data, size_t data_sz,
uint32_t sizes[8], int *count,
aom_decrypt_cb decrypt_cb,
void *decrypt_state);
struct AV1Decoder *av1_decoder_create(BufferPool *const pool);
void av1_decoder_remove(struct AV1Decoder *pbi);
static INLINE void decrease_ref_count(int idx, RefCntBuffer *const frame_bufs,
BufferPool *const pool) {
if (idx >= 0) {
--frame_bufs[idx].ref_count;
// A worker may only get a free framebuffer index when calling get_free_fb.
// But the private buffer is not set up until finish decoding header.
// So any error happens during decoding header, the frame_bufs will not
// have valid priv buffer.
if (frame_bufs[idx].ref_count == 0 &&
frame_bufs[idx].raw_frame_buffer.priv) {
pool->release_fb_cb(pool->cb_priv, &frame_bufs[idx].raw_frame_buffer);
}
}
}
#if CONFIG_EXT_REFS
static INLINE int dec_is_ref_frame_buf(AV1Decoder *const pbi,
RefCntBuffer *frame_buf) {
AV1_COMMON *const cm = &pbi->common;
int i;
for (i = 0; i < INTER_REFS_PER_FRAME; ++i) {
RefBuffer *const ref_frame = &cm->frame_refs[i];
if (ref_frame->idx == INVALID_IDX) continue;
if (frame_buf == &cm->buffer_pool->frame_bufs[ref_frame->idx]) break;
}
return (i < INTER_REFS_PER_FRAME);
}
#endif // CONFIG_EXT_REFS
#ifdef __cplusplus
} // extern "C"
#endif
#endif // AV1_DECODER_DECODER_H_

286
third_party/aom/av1/decoder/decodetxb.c vendored Normal file
View file

@ -0,0 +1,286 @@
/*
* Copyright (c) 2017, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#include "av1/common/scan.h"
#include "av1/common/idct.h"
#include "av1/common/txb_common.h"
#include "av1/decoder/decodemv.h"
#include "av1/decoder/decodetxb.h"
#include "av1/decoder/dsubexp.h"
#define ACCT_STR __func__
static int read_golomb(MACROBLOCKD *xd, aom_reader *r) {
int x = 1;
int length = 0;
int i = 0;
while (!i) {
i = aom_read_bit(r, ACCT_STR);
++length;
if (length >= 32) {
aom_internal_error(xd->error_info, AOM_CODEC_CORRUPT_FRAME,
"Invalid length in read_golomb");
break;
}
}
for (i = 0; i < length - 1; ++i) {
x <<= 1;
x += aom_read_bit(r, ACCT_STR);
}
return x - 1;
}
uint8_t av1_read_coeffs_txb(const AV1_COMMON *const cm, MACROBLOCKD *xd,
aom_reader *r, int block, int plane,
tran_low_t *tcoeffs, TXB_CTX *txb_ctx,
int16_t *max_scan_line, int *eob) {
FRAME_COUNTS *counts = xd->counts;
TX_SIZE tx_size = get_tx_size(plane, xd);
PLANE_TYPE plane_type = get_plane_type(plane);
aom_prob *nz_map = cm->fc->nz_map[tx_size][plane_type];
aom_prob *eob_flag = cm->fc->eob_flag[tx_size][plane_type];
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
const int seg_eob = tx_size_2d[tx_size];
int c = 0;
int update_eob = -1;
const int16_t *const dequant = xd->plane[plane].seg_dequant[mbmi->segment_id];
const int shift = av1_get_tx_scale(tx_size);
const int bwl = b_width_log2_lookup[txsize_to_bsize[tx_size]] + 2;
int cul_level = 0;
unsigned int(*nz_map_count)[SIG_COEF_CONTEXTS][2];
uint8_t txb_mask[32 * 32] = { 0 };
nz_map_count = (counts) ? &counts->nz_map[tx_size][plane_type] : NULL;
memset(tcoeffs, 0, sizeof(*tcoeffs) * seg_eob);
int all_zero =
aom_read(r, cm->fc->txb_skip[tx_size][txb_ctx->txb_skip_ctx], ACCT_STR);
if (xd->counts)
++xd->counts->txb_skip[tx_size][txb_ctx->txb_skip_ctx][all_zero];
*eob = 0;
if (all_zero) {
*max_scan_line = 0;
return 0;
}
#if CONFIG_TXK_SEL
av1_read_tx_type(cm, xd, block, plane, r);
#endif
TX_TYPE tx_type = get_tx_type(plane_type, xd, block, tx_size);
const SCAN_ORDER *const scan_order =
get_scan(cm, tx_size, tx_type, is_inter_block(mbmi));
const int16_t *scan = scan_order->scan;
for (c = 0; c < seg_eob; ++c) {
int is_nz;
int coeff_ctx = get_nz_map_ctx(tcoeffs, txb_mask, scan[c], bwl);
int eob_ctx = get_eob_ctx(tcoeffs, scan[c], bwl);
if (c < seg_eob - 1)
is_nz = aom_read(r, nz_map[coeff_ctx], tx_size);
else
is_nz = 1;
// set non-zero coefficient map.
tcoeffs[scan[c]] = is_nz;
if (c == seg_eob - 1) {
++c;
break;
}
if (counts) ++(*nz_map_count)[coeff_ctx][is_nz];
if (is_nz) {
int is_eob = aom_read(r, eob_flag[eob_ctx], tx_size);
if (counts) ++counts->eob_flag[tx_size][plane_type][eob_ctx][is_eob];
if (is_eob) break;
}
txb_mask[scan[c]] = 1;
}
*eob = AOMMIN(seg_eob, c + 1);
*max_scan_line = *eob;
int i;
for (i = 0; i < NUM_BASE_LEVELS; ++i) {
aom_prob *coeff_base = cm->fc->coeff_base[tx_size][plane_type][i];
update_eob = 0;
for (c = *eob - 1; c >= 0; --c) {
tran_low_t *v = &tcoeffs[scan[c]];
int sign;
int ctx;
if (*v <= i) continue;
ctx = get_base_ctx(tcoeffs, scan[c], bwl, i + 1);
if (aom_read(r, coeff_base[ctx], tx_size)) {
*v = i + 1;
cul_level += i + 1;
if (counts) ++counts->coeff_base[tx_size][plane_type][i][ctx][1];
if (c == 0) {
int dc_sign_ctx = txb_ctx->dc_sign_ctx;
sign = aom_read(r, cm->fc->dc_sign[plane_type][dc_sign_ctx], tx_size);
if (counts) ++counts->dc_sign[plane_type][dc_sign_ctx][sign];
} else {
sign = aom_read_bit(r, ACCT_STR);
}
if (sign) *v = -(*v);
continue;
}
*v = i + 2;
if (counts) ++counts->coeff_base[tx_size][plane_type][i][ctx][0];
// update the eob flag for coefficients with magnitude above 1.
update_eob = AOMMAX(update_eob, c);
}
}
for (c = update_eob; c >= 0; --c) {
tran_low_t *v = &tcoeffs[scan[c]];
int sign;
int idx;
int ctx;
if (*v <= NUM_BASE_LEVELS) continue;
if (c == 0) {
int dc_sign_ctx = txb_ctx->dc_sign_ctx;
sign = aom_read(r, cm->fc->dc_sign[plane_type][dc_sign_ctx], tx_size);
if (counts) ++counts->dc_sign[plane_type][dc_sign_ctx][sign];
} else {
sign = aom_read_bit(r, ACCT_STR);
}
ctx = get_level_ctx(tcoeffs, scan[c], bwl);
if (cm->fc->coeff_lps[tx_size][plane_type][ctx] == 0) exit(0);
for (idx = 0; idx < COEFF_BASE_RANGE; ++idx) {
if (aom_read(r, cm->fc->coeff_lps[tx_size][plane_type][ctx], tx_size)) {
*v = (idx + 1 + NUM_BASE_LEVELS);
if (sign) *v = -(*v);
cul_level += abs(*v);
if (counts) ++counts->coeff_lps[tx_size][plane_type][ctx][1];
break;
}
if (counts) ++counts->coeff_lps[tx_size][plane_type][ctx][0];
}
if (idx < COEFF_BASE_RANGE) continue;
// decode 0-th order Golomb code
*v = read_golomb(xd, r) + COEFF_BASE_RANGE + 1 + NUM_BASE_LEVELS;
if (sign) *v = -(*v);
cul_level += abs(*v);
}
for (c = 0; c < *eob; ++c) {
int16_t dqv = (c == 0) ? dequant[0] : dequant[1];
tran_low_t *v = &tcoeffs[scan[c]];
int sign = (*v) < 0;
*v = (abs(*v) * dqv) >> shift;
if (sign) *v = -(*v);
}
cul_level = AOMMIN(63, cul_level);
// DC value
set_dc_sign(&cul_level, tcoeffs[0]);
return cul_level;
}
uint8_t av1_read_coeffs_txb_facade(AV1_COMMON *cm, MACROBLOCKD *xd,
aom_reader *r, int row, int col, int block,
int plane, tran_low_t *tcoeffs,
int16_t *max_scan_line, int *eob) {
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
struct macroblockd_plane *pd = &xd->plane[plane];
const BLOCK_SIZE bsize = mbmi->sb_type;
#if CONFIG_CB4X4
#if CONFIG_CHROMA_2X2
const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, pd);
#else
const BLOCK_SIZE plane_bsize =
AOMMAX(BLOCK_4X4, get_plane_block_size(bsize, pd));
#endif // CONFIG_CHROMA_2X2
#else // CONFIG_CB4X4
const BLOCK_SIZE plane_bsize =
get_plane_block_size(AOMMAX(BLOCK_8X8, bsize), pd);
#endif // CONFIG_CB4X4
TX_SIZE tx_size = get_tx_size(plane, xd);
TXB_CTX txb_ctx;
get_txb_ctx(plane_bsize, tx_size, plane, pd->above_context + col,
pd->left_context + row, &txb_ctx);
uint8_t cul_level = av1_read_coeffs_txb(cm, xd, r, block, plane, tcoeffs,
&txb_ctx, max_scan_line, eob);
#if CONFIG_ADAPT_SCAN
PLANE_TYPE plane_type = get_plane_type(plane);
TX_TYPE tx_type = get_tx_type(plane_type, xd, block, tx_size);
if (xd->counts && *eob > 0)
av1_update_scan_count_facade(cm, xd->counts, tx_size, tx_type, pd->dqcoeff,
*eob);
#endif
av1_set_contexts(xd, pd, plane, tx_size, cul_level, col, row);
return cul_level;
}
static void read_txb_probs(FRAME_CONTEXT *fc, const TX_SIZE tx_size,
aom_reader *r) {
int plane, ctx, level;
if (aom_read_bit(r, ACCT_STR) == 0) return;
for (ctx = 0; ctx < TXB_SKIP_CONTEXTS; ++ctx)
av1_diff_update_prob(r, &fc->txb_skip[tx_size][ctx], ACCT_STR);
for (plane = 0; plane < PLANE_TYPES; ++plane)
for (ctx = 0; ctx < SIG_COEF_CONTEXTS; ++ctx)
av1_diff_update_prob(r, &fc->nz_map[tx_size][plane][ctx], ACCT_STR);
for (plane = 0; plane < PLANE_TYPES; ++plane)
for (ctx = 0; ctx < EOB_COEF_CONTEXTS; ++ctx)
av1_diff_update_prob(r, &fc->eob_flag[tx_size][plane][ctx], ACCT_STR);
for (level = 0; level < NUM_BASE_LEVELS; ++level)
for (plane = 0; plane < PLANE_TYPES; ++plane)
for (ctx = 0; ctx < COEFF_BASE_CONTEXTS; ++ctx)
av1_diff_update_prob(r, &fc->coeff_base[tx_size][plane][level][ctx],
ACCT_STR);
for (plane = 0; plane < PLANE_TYPES; ++plane)
for (ctx = 0; ctx < LEVEL_CONTEXTS; ++ctx)
av1_diff_update_prob(r, &fc->coeff_lps[tx_size][plane][ctx], ACCT_STR);
}
void av1_read_txb_probs(FRAME_CONTEXT *fc, TX_MODE tx_mode, aom_reader *r) {
const TX_SIZE max_tx_size = tx_mode_to_biggest_tx_size[tx_mode];
TX_SIZE tx_size;
int ctx, plane;
for (plane = 0; plane < PLANE_TYPES; ++plane)
for (ctx = 0; ctx < DC_SIGN_CONTEXTS; ++ctx)
av1_diff_update_prob(r, &fc->dc_sign[plane][ctx], ACCT_STR);
for (tx_size = TX_4X4; tx_size <= max_tx_size; ++tx_size)
read_txb_probs(fc, tx_size, r);
}

31
third_party/aom/av1/decoder/decodetxb.h vendored Normal file
View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2017, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#ifndef DECODETXB_H_
#define DECODETXB_H_
#include "./aom_config.h"
#include "av1/common/blockd.h"
#include "av1/common/onyxc_int.h"
#include "av1/common/txb_common.h"
#include "aom_dsp/bitreader.h"
uint8_t av1_read_coeffs_txb(const AV1_COMMON *const cm, MACROBLOCKD *xd,
aom_reader *r, int block, int plane,
tran_low_t *tcoeffs, TXB_CTX *txb_ctx,
int16_t *max_scan_line, int *eob);
uint8_t av1_read_coeffs_txb_facade(AV1_COMMON *cm, MACROBLOCKD *xd,
aom_reader *r, int row, int col, int block,
int plane, tran_low_t *tcoeffs,
int16_t *max_scan_line, int *eob);
void av1_read_txb_probs(FRAME_CONTEXT *fc, TX_MODE tx_mode, aom_reader *r);
#endif // DECODETXB_H_

467
third_party/aom/av1/decoder/detokenize.c vendored Normal file
View file

@ -0,0 +1,467 @@
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#include "./aom_config.h"
#if !CONFIG_PVQ
#include "aom_mem/aom_mem.h"
#include "aom_ports/mem.h"
#endif // !CONFIG_PVQ
#include "av1/common/blockd.h"
#define ACCT_STR __func__
#if !CONFIG_PVQ || CONFIG_VAR_TX
#include "av1/common/common.h"
#include "av1/common/entropy.h"
#include "av1/common/idct.h"
#include "av1/decoder/detokenize.h"
#define EOB_CONTEXT_NODE 0
#define ZERO_CONTEXT_NODE 1
#define ONE_CONTEXT_NODE 2
#define LOW_VAL_CONTEXT_NODE 0
#define TWO_CONTEXT_NODE 1
#define THREE_CONTEXT_NODE 2
#define HIGH_LOW_CONTEXT_NODE 3
#define CAT_ONE_CONTEXT_NODE 4
#define CAT_THREEFOUR_CONTEXT_NODE 5
#define CAT_THREE_CONTEXT_NODE 6
#define CAT_FIVE_CONTEXT_NODE 7
#define INCREMENT_COUNT(token) \
do { \
if (counts) ++coef_counts[band][ctx][token]; \
} while (0)
#if CONFIG_NEW_MULTISYMBOL
#define READ_COEFF(prob_name, cdf_name, num, r) read_coeff(cdf_name, num, r);
static INLINE int read_coeff(const aom_cdf_prob *const *cdf, int n,
aom_reader *r) {
int val = 0;
int i = 0;
int count = 0;
while (count < n) {
const int size = AOMMIN(n - count, 4);
val |= aom_read_cdf(r, cdf[i++], 1 << size, ACCT_STR) << count;
count += size;
}
return val;
}
#else
#define READ_COEFF(prob_name, cdf_name, num, r) read_coeff(prob_name, num, r);
static INLINE int read_coeff(const aom_prob *probs, int n, aom_reader *r) {
int i, val = 0;
for (i = 0; i < n; ++i) val = (val << 1) | aom_read(r, probs[i], ACCT_STR);
return val;
}
#endif
static int token_to_value(aom_reader *const r, int token, TX_SIZE tx_size,
int bit_depth) {
#if !CONFIG_HIGHBITDEPTH
assert(bit_depth == 8);
#endif // !CONFIG_HIGHBITDEPTH
switch (token) {
case ZERO_TOKEN:
case ONE_TOKEN:
case TWO_TOKEN:
case THREE_TOKEN:
case FOUR_TOKEN: return token;
case CATEGORY1_TOKEN:
return CAT1_MIN_VAL + READ_COEFF(av1_cat1_prob, av1_cat1_cdf, 1, r);
case CATEGORY2_TOKEN:
return CAT2_MIN_VAL + READ_COEFF(av1_cat2_prob, av1_cat2_cdf, 2, r);
case CATEGORY3_TOKEN:
return CAT3_MIN_VAL + READ_COEFF(av1_cat3_prob, av1_cat3_cdf, 3, r);
case CATEGORY4_TOKEN:
return CAT4_MIN_VAL + READ_COEFF(av1_cat4_prob, av1_cat4_cdf, 4, r);
case CATEGORY5_TOKEN:
return CAT5_MIN_VAL + READ_COEFF(av1_cat5_prob, av1_cat5_cdf, 5, r);
case CATEGORY6_TOKEN: {
const int skip_bits = (int)sizeof(av1_cat6_prob) -
av1_get_cat6_extrabits_size(tx_size, bit_depth);
return CAT6_MIN_VAL + READ_COEFF(av1_cat6_prob + skip_bits, av1_cat6_cdf,
18 - skip_bits, r);
}
default:
assert(0); // Invalid token.
return -1;
}
}
static int decode_coefs(MACROBLOCKD *xd, PLANE_TYPE type, tran_low_t *dqcoeff,
TX_SIZE tx_size, TX_TYPE tx_type, const int16_t *dq,
#if CONFIG_NEW_QUANT
dequant_val_type_nuq *dq_val,
#endif // CONFIG_NEW_QUANT
#if CONFIG_AOM_QM
const qm_val_t *iqm[2][TX_SIZES],
#endif // CONFIG_AOM_QM
int ctx, const int16_t *scan, const int16_t *nb,
int16_t *max_scan_line, aom_reader *r) {
FRAME_COUNTS *counts = xd->counts;
#if CONFIG_EC_ADAPT
FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
#else
FRAME_CONTEXT *const ec_ctx = xd->fc;
#endif
const int max_eob = tx_size_2d[tx_size];
const int ref = is_inter_block(&xd->mi[0]->mbmi);
#if CONFIG_AOM_QM
const qm_val_t *iqmatrix = iqm[!ref][tx_size];
#endif // CONFIG_AOM_QM
int band, c = 0;
const int tx_size_ctx = txsize_sqr_map[tx_size];
#if CONFIG_NEW_TOKENSET
aom_cdf_prob(*coef_head_cdfs)[COEFF_CONTEXTS][CDF_SIZE(ENTROPY_TOKENS)] =
ec_ctx->coef_head_cdfs[tx_size_ctx][type][ref];
aom_cdf_prob(*coef_tail_cdfs)[COEFF_CONTEXTS][CDF_SIZE(ENTROPY_TOKENS)] =
ec_ctx->coef_tail_cdfs[tx_size_ctx][type][ref];
int val = 0;
#if !CONFIG_EC_ADAPT
unsigned int *blockz_count;
unsigned int(*coef_counts)[COEFF_CONTEXTS][UNCONSTRAINED_NODES + 1] = NULL;
unsigned int(*eob_branch_count)[COEFF_CONTEXTS] = NULL;
#endif
#else
aom_prob(*coef_probs)[COEFF_CONTEXTS][UNCONSTRAINED_NODES] =
ec_ctx->coef_probs[tx_size_ctx][type][ref];
const aom_prob *prob;
#if CONFIG_EC_MULTISYMBOL
aom_cdf_prob(*coef_cdfs)[COEFF_CONTEXTS][CDF_SIZE(ENTROPY_TOKENS)] =
ec_ctx->coef_cdfs[tx_size_ctx][type][ref];
aom_cdf_prob(*cdf)[CDF_SIZE(ENTROPY_TOKENS)];
#endif // CONFIG_EC_MULTISYMBOL
unsigned int(*coef_counts)[COEFF_CONTEXTS][UNCONSTRAINED_NODES + 1] = NULL;
unsigned int(*eob_branch_count)[COEFF_CONTEXTS] = NULL;
#endif // CONFIG_NEW_TOKENSET
uint8_t token_cache[MAX_TX_SQUARE];
const uint8_t *band_translate = get_band_translate(tx_size);
int dq_shift;
int v, token;
int16_t dqv = dq[0];
#if CONFIG_NEW_QUANT
const tran_low_t *dqv_val = &dq_val[0][0];
#endif // CONFIG_NEW_QUANT
(void)tx_type;
#if CONFIG_AOM_QM
(void)iqmatrix;
#endif // CONFIG_AOM_QM
if (counts) {
#if !CONFIG_NEW_TOKENSET || !CONFIG_EC_ADAPT
coef_counts = counts->coef[tx_size_ctx][type][ref];
eob_branch_count = counts->eob_branch[tx_size_ctx][type][ref];
#endif
#if CONFIG_NEW_TOKENSET && !CONFIG_EC_ADAPT
blockz_count = counts->blockz_count[tx_size_ctx][type][ref][ctx];
#endif
}
dq_shift = av1_get_tx_scale(tx_size);
#if CONFIG_NEW_TOKENSET
band = *band_translate++;
int more_data = 1;
while (more_data) {
int comb_token;
int last_pos = (c + 1 == max_eob);
int first_pos = (c == 0);
#if CONFIG_NEW_QUANT
dqv_val = &dq_val[band][0];
#endif // CONFIG_NEW_QUANT
comb_token = last_pos ? 2 * aom_read_bit(r, ACCT_STR) + 2
: aom_read_symbol(r, coef_head_cdfs[band][ctx],
HEAD_TOKENS + first_pos, ACCT_STR) +
!first_pos;
if (first_pos) {
#if !CONFIG_EC_ADAPT
if (counts) ++blockz_count[comb_token != 0];
#endif
if (comb_token == 0) return 0;
}
token = comb_token >> 1;
while (!token) {
*max_scan_line = AOMMAX(*max_scan_line, scan[c]);
token_cache[scan[c]] = 0;
#if !CONFIG_EC_ADAPT
if (counts && !last_pos) {
++coef_counts[band][ctx][ZERO_TOKEN];
}
#endif
++c;
dqv = dq[1];
ctx = get_coef_context(nb, token_cache, c);
band = *band_translate++;
last_pos = (c + 1 == max_eob);
comb_token = last_pos ? 2 * aom_read_bit(r, ACCT_STR) + 2
: aom_read_symbol(r, coef_head_cdfs[band][ctx],
HEAD_TOKENS, ACCT_STR) +
1;
token = comb_token >> 1;
}
more_data = comb_token & 1;
#if !CONFIG_EC_ADAPT
if (counts && !last_pos) {
++coef_counts[band][ctx][token];
++eob_branch_count[band][ctx];
if (!more_data) ++coef_counts[band][ctx][EOB_MODEL_TOKEN];
}
#endif
if (token > ONE_TOKEN)
token +=
aom_read_symbol(r, coef_tail_cdfs[band][ctx], TAIL_TOKENS, ACCT_STR);
#if CONFIG_NEW_QUANT
dqv_val = &dq_val[band][0];
#endif // CONFIG_NEW_QUANT
*max_scan_line = AOMMAX(*max_scan_line, scan[c]);
token_cache[scan[c]] = av1_pt_energy_class[token];
val = token_to_value(r, token, tx_size,
#if CONFIG_HIGHBITDEPTH
xd->bd);
#else
8);
#endif // CONFIG_HIGHBITDEPTH
#if CONFIG_NEW_QUANT
v = av1_dequant_abscoeff_nuq(val, dqv, dqv_val);
v = dq_shift ? ROUND_POWER_OF_TWO(v, dq_shift) : v;
#else
#if CONFIG_AOM_QM
dqv = ((iqmatrix[scan[c]] * (int)dqv) + (1 << (AOM_QM_BITS - 1))) >>
AOM_QM_BITS;
#endif
v = (val * dqv) >> dq_shift;
#endif
v = aom_read_bit(r, ACCT_STR) ? -v : v;
#if CONFIG_COEFFICIENT_RANGE_CHECKING
#if CONFIG_HIGHBITDEPTH
check_range(v, xd->bd);
#else
check_range(v, 8);
#endif // CONFIG_HIGHBITDEPTH
#endif // CONFIG_COEFFICIENT_RANGE_CHECKING
dqcoeff[scan[c]] = v;
++c;
more_data &= (c < max_eob);
if (!more_data) break;
dqv = dq[1];
ctx = get_coef_context(nb, token_cache, c);
band = *band_translate++;
#else // CONFIG_NEW_TOKENSET
while (c < max_eob) {
int val = -1;
band = *band_translate++;
prob = coef_probs[band][ctx];
if (counts) ++eob_branch_count[band][ctx];
if (!aom_read(r, prob[EOB_CONTEXT_NODE], ACCT_STR)) {
INCREMENT_COUNT(EOB_MODEL_TOKEN);
break;
}
#if CONFIG_NEW_QUANT
dqv_val = &dq_val[band][0];
#endif // CONFIG_NEW_QUANT
while (!aom_read(r, prob[ZERO_CONTEXT_NODE], ACCT_STR)) {
INCREMENT_COUNT(ZERO_TOKEN);
dqv = dq[1];
token_cache[scan[c]] = 0;
++c;
if (c >= max_eob) return c; // zero tokens at the end (no eob token)
ctx = get_coef_context(nb, token_cache, c);
band = *band_translate++;
prob = coef_probs[band][ctx];
#if CONFIG_NEW_QUANT
dqv_val = &dq_val[band][0];
#endif // CONFIG_NEW_QUANT
}
*max_scan_line = AOMMAX(*max_scan_line, scan[c]);
#if CONFIG_EC_MULTISYMBOL
cdf = &coef_cdfs[band][ctx];
token = ONE_TOKEN +
aom_read_symbol(r, *cdf, CATEGORY6_TOKEN - ONE_TOKEN + 1, ACCT_STR);
INCREMENT_COUNT(ONE_TOKEN + (token > ONE_TOKEN));
assert(token != ZERO_TOKEN);
val = token_to_value(r, token, tx_size,
#if CONFIG_HIGHBITDEPTH
xd->bd);
#else
8);
#endif // CONFIG_HIGHBITDEPTH
#else // CONFIG_EC_MULTISYMBOL
if (!aom_read(r, prob[ONE_CONTEXT_NODE], ACCT_STR)) {
INCREMENT_COUNT(ONE_TOKEN);
token = ONE_TOKEN;
val = 1;
} else {
INCREMENT_COUNT(TWO_TOKEN);
token = aom_read_tree(r, av1_coef_con_tree,
av1_pareto8_full[prob[PIVOT_NODE] - 1], ACCT_STR);
assert(token != ZERO_TOKEN && token != ONE_TOKEN);
val = token_to_value(r, token, tx_size,
#if CONFIG_HIGHBITDEPTH
xd->bd);
#else
8);
#endif // CONFIG_HIGHBITDEPTH
}
#endif // CONFIG_EC_MULTISYMBOL
#if CONFIG_NEW_QUANT
v = av1_dequant_abscoeff_nuq(val, dqv, dqv_val);
v = dq_shift ? ROUND_POWER_OF_TWO(v, dq_shift) : v;
#else
#if CONFIG_AOM_QM
dqv = ((iqmatrix[scan[c]] * (int)dqv) + (1 << (AOM_QM_BITS - 1))) >>
AOM_QM_BITS;
#endif
v = (val * dqv) >> dq_shift;
#endif // CONFIG_NEW_QUANT
#if CONFIG_COEFFICIENT_RANGE_CHECKING
#if CONFIG_HIGHBITDEPTH
dqcoeff[scan[c]] =
highbd_check_range((aom_read_bit(r, ACCT_STR) ? -v : v), xd->bd);
#else
dqcoeff[scan[c]] = check_range(aom_read_bit(r, ACCT_STR) ? -v : v, 8);
#endif // CONFIG_HIGHBITDEPTH
#else
dqcoeff[scan[c]] = aom_read_bit(r, ACCT_STR) ? -v : v;
#endif // CONFIG_COEFFICIENT_RANGE_CHECKING
token_cache[scan[c]] = av1_pt_energy_class[token];
++c;
ctx = get_coef_context(nb, token_cache, c);
dqv = dq[1];
#endif // CONFIG_NEW_TOKENSET
}
return c;
}
#endif // !CONFIG_PVQ
#if CONFIG_PALETTE
void av1_decode_palette_tokens(MACROBLOCKD *const xd, int plane,
aom_reader *r) {
const MODE_INFO *const mi = xd->mi[0];
const MB_MODE_INFO *const mbmi = &mi->mbmi;
uint8_t color_order[PALETTE_MAX_SIZE];
const int n = mbmi->palette_mode_info.palette_size[plane];
int i, j;
uint8_t *const color_map = xd->plane[plane].color_index_map;
const aom_prob(
*const prob)[PALETTE_COLOR_INDEX_CONTEXTS][PALETTE_COLORS - 1] =
plane ? av1_default_palette_uv_color_index_prob
: av1_default_palette_y_color_index_prob;
int plane_block_width, plane_block_height, rows, cols;
av1_get_block_dimensions(mbmi->sb_type, plane, xd, &plane_block_width,
&plane_block_height, &rows, &cols);
assert(plane == 0 || plane == 1);
#if CONFIG_PALETTE_THROUGHPUT
// Run wavefront on the palette map index decoding.
for (i = 1; i < rows + cols - 1; ++i) {
for (j = AOMMIN(i, cols - 1); j >= AOMMAX(0, i - rows + 1); --j) {
const int color_ctx = av1_get_palette_color_index_context(
color_map, plane_block_width, (i - j), j, n, color_order, NULL);
const int color_idx =
aom_read_tree(r, av1_palette_color_index_tree[n - 2],
prob[n - 2][color_ctx], ACCT_STR);
assert(color_idx >= 0 && color_idx < n);
color_map[(i - j) * plane_block_width + j] = color_order[color_idx];
}
}
// Copy last column to extra columns.
if (cols < plane_block_width) {
for (i = 0; i < plane_block_height; ++i) {
memset(color_map + i * plane_block_width + cols,
color_map[i * plane_block_width + cols - 1],
(plane_block_width - cols));
}
}
#else
for (i = 0; i < rows; ++i) {
for (j = (i == 0 ? 1 : 0); j < cols; ++j) {
const int color_ctx = av1_get_palette_color_index_context(
color_map, plane_block_width, i, j, n, color_order, NULL);
const int color_idx =
aom_read_tree(r, av1_palette_color_index_tree[n - PALETTE_MIN_SIZE],
prob[n - PALETTE_MIN_SIZE][color_ctx], ACCT_STR);
assert(color_idx >= 0 && color_idx < n);
color_map[i * plane_block_width + j] = color_order[color_idx];
}
memset(color_map + i * plane_block_width + cols,
color_map[i * plane_block_width + cols - 1],
(plane_block_width - cols)); // Copy last column to extra columns.
}
#endif // CONFIG_PALETTE_THROUGHPUT
// Copy last row to extra rows.
for (i = rows; i < plane_block_height; ++i) {
memcpy(color_map + i * plane_block_width,
color_map + (rows - 1) * plane_block_width, plane_block_width);
}
}
#endif // CONFIG_PALETTE
#if !CONFIG_PVQ || CONFIG_VAR_TX
int av1_decode_block_tokens(AV1_COMMON *cm, MACROBLOCKD *const xd, int plane,
const SCAN_ORDER *sc, int x, int y, TX_SIZE tx_size,
TX_TYPE tx_type, int16_t *max_scan_line,
aom_reader *r, int seg_id) {
struct macroblockd_plane *const pd = &xd->plane[plane];
const int16_t *const dequant = pd->seg_dequant[seg_id];
const int ctx =
get_entropy_context(tx_size, pd->above_context + x, pd->left_context + y);
#if CONFIG_NEW_QUANT
const int ref = is_inter_block(&xd->mi[0]->mbmi);
int dq =
get_dq_profile_from_ctx(xd->qindex[seg_id], ctx, ref, pd->plane_type);
#endif // CONFIG_NEW_QUANT
const int eob =
decode_coefs(xd, pd->plane_type, pd->dqcoeff, tx_size, tx_type, dequant,
#if CONFIG_NEW_QUANT
pd->seg_dequant_nuq[seg_id][dq],
#endif // CONFIG_NEW_QUANT
#if CONFIG_AOM_QM
pd->seg_iqmatrix[seg_id],
#endif // CONFIG_AOM_QM
ctx, sc->scan, sc->neighbors, max_scan_line, r);
av1_set_contexts(xd, pd, plane, tx_size, eob > 0, x, y);
#if CONFIG_ADAPT_SCAN
if (xd->counts)
av1_update_scan_count_facade(cm, xd->counts, tx_size, tx_type, pd->dqcoeff,
eob);
#else
(void)cm;
#endif
return eob;
}
#endif // !CONFIG_PVQ

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#ifndef AV1_DECODER_DETOKENIZE_H_
#define AV1_DECODER_DETOKENIZE_H_
#include "./aom_config.h"
#if !CONFIG_PVQ || CONFIG_VAR_TX
#include "av1/decoder/decoder.h"
#include "av1/common/scan.h"
#endif // !CONFIG_PVQ
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_PALETTE
void av1_decode_palette_tokens(MACROBLOCKD *const xd, int plane, aom_reader *r);
#endif // CONFIG_PALETTE
#if !CONFIG_PVQ || CONFIG_VAR_TX
int av1_decode_block_tokens(AV1_COMMON *cm, MACROBLOCKD *const xd, int plane,
const SCAN_ORDER *sc, int x, int y, TX_SIZE tx_size,
TX_TYPE tx_type, int16_t *max_scan_line,
aom_reader *r, int seg_id);
#endif // !CONFIG_PVQ
#ifdef __cplusplus
} // extern "C"
#endif
#endif // AV1_DECODER_DETOKENIZE_H_

82
third_party/aom/av1/decoder/dsubexp.c vendored Normal file
View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#include <assert.h>
#include "av1/common/entropy.h"
#include "av1/decoder/dsubexp.h"
static int inv_recenter_nonneg(int v, int m) {
if (v > 2 * m) return v;
return (v & 1) ? m - ((v + 1) >> 1) : m + (v >> 1);
}
#define decode_uniform(r, ACCT_STR_NAME) \
decode_uniform_(r ACCT_STR_ARG(ACCT_STR_NAME))
#define decode_term_subexp(r, ACCT_STR_NAME) \
decode_term_subexp_(r ACCT_STR_ARG(ACCT_STR_NAME))
static int decode_uniform_(aom_reader *r ACCT_STR_PARAM) {
const int l = 8;
const int m = (1 << l) - 190;
const int v = aom_read_literal(r, l - 1, ACCT_STR_NAME);
return v < m ? v : (v << 1) - m + aom_read_bit(r, ACCT_STR_NAME);
}
static int inv_remap_prob(int v, int m) {
/* clang-format off */
static uint8_t inv_map_table[MAX_PROB - 1] = {
7, 20, 33, 46, 59, 72, 85, 98, 111, 124, 137, 150, 163, 176, 189,
202, 215, 228, 241, 254, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60,
61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76,
77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 92,
93, 94, 95, 96, 97, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
109, 110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 125,
126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 140, 141,
142, 143, 144, 145, 146, 147, 148, 149, 151, 152, 153, 154, 155, 156, 157,
158, 159, 160, 161, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173,
174, 175, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 190,
191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 203, 204, 205, 206,
207, 208, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219, 220, 221, 222,
223, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238,
239, 240, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253
}; /* clang-format on */
assert(v < (int)(sizeof(inv_map_table) / sizeof(inv_map_table[0])));
v = inv_map_table[v];
m--;
if ((m << 1) <= MAX_PROB) {
return 1 + inv_recenter_nonneg(v, m);
} else {
return MAX_PROB - inv_recenter_nonneg(v, MAX_PROB - 1 - m);
}
}
static int decode_term_subexp_(aom_reader *r ACCT_STR_PARAM) {
if (!aom_read_bit(r, ACCT_STR_NAME))
return aom_read_literal(r, 4, ACCT_STR_NAME);
if (!aom_read_bit(r, ACCT_STR_NAME))
return aom_read_literal(r, 4, ACCT_STR_NAME) + 16;
if (!aom_read_bit(r, ACCT_STR_NAME))
return aom_read_literal(r, 5, ACCT_STR_NAME) + 32;
return decode_uniform(r, ACCT_STR_NAME) + 64;
}
void av1_diff_update_prob_(aom_reader *r, aom_prob *p ACCT_STR_PARAM) {
if (aom_read(r, DIFF_UPDATE_PROB, ACCT_STR_NAME)) {
const int delp = decode_term_subexp(r, ACCT_STR_NAME);
*p = (aom_prob)inv_remap_prob(delp, *p);
}
}

32
third_party/aom/av1/decoder/dsubexp.h vendored Normal file
View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#ifndef AV1_DECODER_DSUBEXP_H_
#define AV1_DECODER_DSUBEXP_H_
#include "aom_dsp/bitreader.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_ACCOUNTING
#define av1_diff_update_prob(r, p, str) av1_diff_update_prob_(r, p, str)
#else
#define av1_diff_update_prob(r, p, str) av1_diff_update_prob_(r, p)
#endif
void av1_diff_update_prob_(aom_reader *r, aom_prob *p ACCT_STR_PARAM);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // AV1_DECODER_DSUBEXP_H_

194
third_party/aom/av1/decoder/dthread.c vendored Normal file
View file

@ -0,0 +1,194 @@
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#include "./aom_config.h"
#include "aom_mem/aom_mem.h"
#include "av1/common/reconinter.h"
#include "av1/decoder/dthread.h"
#include "av1/decoder/decoder.h"
// #define DEBUG_THREAD
// TODO(hkuang): Clean up all the #ifdef in this file.
void av1_frameworker_lock_stats(AVxWorker *const worker) {
#if CONFIG_MULTITHREAD
FrameWorkerData *const worker_data = worker->data1;
pthread_mutex_lock(&worker_data->stats_mutex);
#else
(void)worker;
#endif
}
void av1_frameworker_unlock_stats(AVxWorker *const worker) {
#if CONFIG_MULTITHREAD
FrameWorkerData *const worker_data = worker->data1;
pthread_mutex_unlock(&worker_data->stats_mutex);
#else
(void)worker;
#endif
}
void av1_frameworker_signal_stats(AVxWorker *const worker) {
#if CONFIG_MULTITHREAD
FrameWorkerData *const worker_data = worker->data1;
// TODO(hkuang): Fix the pthread_cond_broadcast in windows wrapper.
#if defined(_WIN32) && !HAVE_PTHREAD_H
pthread_cond_signal(&worker_data->stats_cond);
#else
pthread_cond_broadcast(&worker_data->stats_cond);
#endif
#else
(void)worker;
#endif
}
// This macro prevents thread_sanitizer from reporting known concurrent writes.
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
#define BUILDING_WITH_TSAN
#endif
#endif
// TODO(hkuang): Remove worker parameter as it is only used in debug code.
void av1_frameworker_wait(AVxWorker *const worker, RefCntBuffer *const ref_buf,
int row) {
#if CONFIG_MULTITHREAD
if (!ref_buf) return;
#ifndef BUILDING_WITH_TSAN
// The following line of code will get harmless tsan error but it is the key
// to get best performance.
if (ref_buf->row >= row && ref_buf->buf.corrupted != 1) return;
#endif
{
// Find the worker thread that owns the reference frame. If the reference
// frame has been fully decoded, it may not have owner.
AVxWorker *const ref_worker = ref_buf->frame_worker_owner;
FrameWorkerData *const ref_worker_data =
(FrameWorkerData *)ref_worker->data1;
const AV1Decoder *const pbi = ref_worker_data->pbi;
#ifdef DEBUG_THREAD
{
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
printf("%d %p worker is waiting for %d %p worker (%d) ref %d \r\n",
worker_data->worker_id, worker, ref_worker_data->worker_id,
ref_buf->frame_worker_owner, row, ref_buf->row);
}
#endif
av1_frameworker_lock_stats(ref_worker);
while (ref_buf->row < row && pbi->cur_buf == ref_buf &&
ref_buf->buf.corrupted != 1) {
pthread_cond_wait(&ref_worker_data->stats_cond,
&ref_worker_data->stats_mutex);
}
if (ref_buf->buf.corrupted == 1) {
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
av1_frameworker_unlock_stats(ref_worker);
aom_internal_error(&worker_data->pbi->common.error,
AOM_CODEC_CORRUPT_FRAME,
"Worker %p failed to decode frame", worker);
}
av1_frameworker_unlock_stats(ref_worker);
}
#else
(void)worker;
(void)ref_buf;
(void)row;
(void)ref_buf;
#endif // CONFIG_MULTITHREAD
}
void av1_frameworker_broadcast(RefCntBuffer *const buf, int row) {
#if CONFIG_MULTITHREAD
AVxWorker *worker = buf->frame_worker_owner;
#ifdef DEBUG_THREAD
{
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
printf("%d %p worker decode to (%d) \r\n", worker_data->worker_id,
buf->frame_worker_owner, row);
}
#endif
av1_frameworker_lock_stats(worker);
buf->row = row;
av1_frameworker_signal_stats(worker);
av1_frameworker_unlock_stats(worker);
#else
(void)buf;
(void)row;
#endif // CONFIG_MULTITHREAD
}
void av1_frameworker_copy_context(AVxWorker *const dst_worker,
AVxWorker *const src_worker) {
#if CONFIG_MULTITHREAD
FrameWorkerData *const src_worker_data = (FrameWorkerData *)src_worker->data1;
FrameWorkerData *const dst_worker_data = (FrameWorkerData *)dst_worker->data1;
AV1_COMMON *const src_cm = &src_worker_data->pbi->common;
AV1_COMMON *const dst_cm = &dst_worker_data->pbi->common;
int i;
// Wait until source frame's context is ready.
av1_frameworker_lock_stats(src_worker);
while (!src_worker_data->frame_context_ready) {
pthread_cond_wait(&src_worker_data->stats_cond,
&src_worker_data->stats_mutex);
}
dst_cm->last_frame_seg_map = src_cm->seg.enabled
? src_cm->current_frame_seg_map
: src_cm->last_frame_seg_map;
dst_worker_data->pbi->need_resync = src_worker_data->pbi->need_resync;
av1_frameworker_unlock_stats(src_worker);
dst_cm->bit_depth = src_cm->bit_depth;
#if CONFIG_HIGHBITDEPTH
dst_cm->use_highbitdepth = src_cm->use_highbitdepth;
#endif
#if CONFIG_EXT_REFS
// TODO(zoeliu): To handle parallel decoding
#endif // CONFIG_EXT_REFS
dst_cm->prev_frame =
src_cm->show_existing_frame ? src_cm->prev_frame : src_cm->cur_frame;
dst_cm->last_width =
!src_cm->show_existing_frame ? src_cm->width : src_cm->last_width;
dst_cm->last_height =
!src_cm->show_existing_frame ? src_cm->height : src_cm->last_height;
dst_cm->subsampling_x = src_cm->subsampling_x;
dst_cm->subsampling_y = src_cm->subsampling_y;
dst_cm->frame_type = src_cm->frame_type;
dst_cm->last_show_frame = !src_cm->show_existing_frame
? src_cm->show_frame
: src_cm->last_show_frame;
for (i = 0; i < REF_FRAMES; ++i)
dst_cm->ref_frame_map[i] = src_cm->next_ref_frame_map[i];
memcpy(dst_cm->lf_info.lfthr, src_cm->lf_info.lfthr,
(MAX_LOOP_FILTER + 1) * sizeof(loop_filter_thresh));
dst_cm->lf.last_sharpness_level = src_cm->lf.sharpness_level;
dst_cm->lf.filter_level = src_cm->lf.filter_level;
memcpy(dst_cm->lf.ref_deltas, src_cm->lf.ref_deltas, TOTAL_REFS_PER_FRAME);
memcpy(dst_cm->lf.mode_deltas, src_cm->lf.mode_deltas, MAX_MODE_LF_DELTAS);
dst_cm->seg = src_cm->seg;
memcpy(dst_cm->frame_contexts, src_cm->frame_contexts,
FRAME_CONTEXTS * sizeof(dst_cm->frame_contexts[0]));
#else
(void)dst_worker;
(void)src_worker;
#endif // CONFIG_MULTITHREAD
}

75
third_party/aom/av1/decoder/dthread.h vendored Normal file
View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#ifndef AV1_DECODER_DTHREAD_H_
#define AV1_DECODER_DTHREAD_H_
#include "./aom_config.h"
#include "aom_util/aom_thread.h"
#include "aom/internal/aom_codec_internal.h"
#ifdef __cplusplus
extern "C" {
#endif
struct AV1Common;
struct AV1Decoder;
// WorkerData for the FrameWorker thread. It contains all the information of
// the worker and decode structures for decoding a frame.
typedef struct FrameWorkerData {
struct AV1Decoder *pbi;
const uint8_t *data;
const uint8_t *data_end;
size_t data_size;
void *user_priv;
int result;
int worker_id;
int received_frame;
// scratch_buffer is used in frame parallel mode only.
// It is used to make a copy of the compressed data.
uint8_t *scratch_buffer;
size_t scratch_buffer_size;
#if CONFIG_MULTITHREAD
pthread_mutex_t stats_mutex;
pthread_cond_t stats_cond;
#endif
int frame_context_ready; // Current frame's context is ready to read.
int frame_decoded; // Finished decoding current frame.
} FrameWorkerData;
void av1_frameworker_lock_stats(AVxWorker *const worker);
void av1_frameworker_unlock_stats(AVxWorker *const worker);
void av1_frameworker_signal_stats(AVxWorker *const worker);
// Wait until ref_buf has been decoded to row in real pixel unit.
// Note: worker may already finish decoding ref_buf and release it in order to
// start decoding next frame. So need to check whether worker is still decoding
// ref_buf.
void av1_frameworker_wait(AVxWorker *const worker, RefCntBuffer *const ref_buf,
int row);
// FrameWorker broadcasts its decoding progress so other workers that are
// waiting on it can resume decoding.
void av1_frameworker_broadcast(RefCntBuffer *const buf, int row);
// Copy necessary decoding context from src worker to dst worker.
void av1_frameworker_copy_context(AVxWorker *const dst_worker,
AVxWorker *const src_worker);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // AV1_DECODER_DTHREAD_H_

View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2001-2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
/* clang-format off */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include "aom_dsp/bitreader.h"
#include "av1/common/generic_code.h"
#include "av1/common/odintrin.h"
#include "pvq_decoder.h"
/** Decodes a value from 0 to N-1 (with N up to 16) based on a cdf and adapts
* the cdf accordingly.
*
* @param [in,out] r multi-symbol entropy decoder
* @param [in,out] cdf CDF of the variable (Q15)
* @param [in] n number of values possible
* @param [in,out] count number of symbols encoded with that cdf so far
* @param [in] rate adaptation rate shift (smaller is faster)
* @return decoded variable
*/
int aom_decode_cdf_adapt_q15_(aom_reader *r, uint16_t *cdf, int n,
int *count, int rate ACCT_STR_PARAM) {
int val;
int i;
if (*count == 0) {
int ft;
ft = cdf[n - 1];
for (i = 0; i < n; i++) {
cdf[i] = AOM_ICDF(cdf[i]*32768/ft);
}
}
val = aom_read_cdf(r, cdf, n, ACCT_STR_NAME);
aom_cdf_adapt_q15(val, cdf, n, count, rate);
return val;
}
/** Encodes a random variable using a "generic" model, assuming that the
* distribution is one-sided (zero and up), has a single mode, and decays
* exponentially past the model.
*
* @param [in,out] r multi-symbol entropy decoder
* @param [in,out] model generic probability model
* @param [in] x variable being encoded
* @param [in,out] ExQ16 expectation of x (adapted)
* @param [in] integration integration period of ExQ16 (leaky average over
* 1<<integration samples)
*
* @retval decoded variable x
*/
int generic_decode_(aom_reader *r, generic_encoder *model,
int *ex_q16, int integration ACCT_STR_PARAM) {
int lg_q1;
int shift;
int id;
uint16_t *cdf;
int xs;
int lsb;
int x;
lsb = 0;
lg_q1 = log_ex(*ex_q16);
/* If expectation is too large, shift x to ensure that
all we have past xs=15 is the exponentially decaying tail
of the distribution. */
shift = OD_MAXI(0, (lg_q1 - 5) >> 1);
/* Choose the cdf to use: we have two per "octave" of ExQ16. */
id = OD_MINI(GENERIC_TABLES - 1, lg_q1);
cdf = model->cdf[id];
xs = aom_read_symbol_pvq(r, cdf, 16, ACCT_STR_NAME);
if (xs == 15) {
int e;
unsigned decay;
/* Estimate decay based on the assumption that the distribution is close
to Laplacian for large values. We should probably have an adaptive
estimate instead. Note: The 2* is a kludge that's not fully understood
yet. */
OD_ASSERT(*ex_q16 < INT_MAX >> 1);
e = ((2**ex_q16 >> 8) + (1 << shift >> 1)) >> shift;
decay = OD_MAXI(2, OD_MINI(254, 256*e/(e + 256)));
xs += aom_laplace_decode_special(r, decay, ACCT_STR_NAME);
}
if (shift != 0) {
int special;
/* Because of the rounding, there's only half the number of possibilities
for xs=0 */
special = xs == 0;
if (shift - special > 0) {
lsb = aom_read_literal(r, shift - special, ACCT_STR_NAME);
}
lsb -= !special << (shift - 1);
}
x = (xs << shift) + lsb;
generic_model_update(ex_q16, x, integration);
OD_LOG((OD_LOG_ENTROPY_CODER, OD_LOG_DEBUG,
"dec: %d %d %d %d %d %x", *ex_q16, x, shift, id, xs, dec->rng));
return x;
}

103
third_party/aom/av1/decoder/inspection.c vendored Normal file
View file

@ -0,0 +1,103 @@
/*
* Copyright (c) 2017, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#include "av1/decoder/decoder.h"
#include "av1/decoder/inspection.h"
#include "av1/common/enums.h"
#if CONFIG_CDEF
#include "av1/common/cdef.h"
#endif
void ifd_init(insp_frame_data *fd, int frame_width, int frame_height) {
fd->mi_cols = ALIGN_POWER_OF_TWO(frame_width, 3) >> MI_SIZE_LOG2;
fd->mi_rows = ALIGN_POWER_OF_TWO(frame_height, 3) >> MI_SIZE_LOG2;
fd->mi_grid = (insp_mi_data *)aom_malloc(sizeof(insp_mi_data) * fd->mi_rows *
fd->mi_cols);
}
void ifd_clear(insp_frame_data *fd) {
aom_free(fd->mi_grid);
fd->mi_grid = NULL;
}
/* TODO(negge) This function may be called by more than one thread when using
a multi-threaded decoder and this may cause a data race. */
int ifd_inspect(insp_frame_data *fd, void *decoder) {
struct AV1Decoder *pbi = (struct AV1Decoder *)decoder;
AV1_COMMON *const cm = &pbi->common;
// TODO(negge): Should this function just call ifd_clear() and ifd_init()?
if (fd->mi_rows != cm->mi_rows || fd->mi_cols != cm->mi_cols) {
return 0;
}
fd->show_frame = cm->show_frame;
fd->frame_type = cm->frame_type;
fd->base_qindex = cm->base_qindex;
fd->tile_mi_cols = cm->tile_width;
fd->tile_mi_rows = cm->tile_height;
#if CONFIG_ACCOUNTING
fd->accounting = &pbi->accounting;
#endif
#if CONFIG_CDEF
// TODO(negge): copy per frame CDEF data
#endif
int i, j;
for (i = 0; i < MAX_SEGMENTS; i++) {
for (j = 0; j < 2; j++) {
fd->y_dequant[i][j] = cm->y_dequant[i][j];
fd->uv_dequant[i][j] = cm->uv_dequant[i][j];
}
}
for (j = 0; j < cm->mi_rows; j++) {
for (i = 0; i < cm->mi_cols; i++) {
const MB_MODE_INFO *mbmi =
&cm->mi_grid_visible[j * cm->mi_stride + i]->mbmi;
insp_mi_data *mi = &fd->mi_grid[j * cm->mi_cols + i];
// Segment
mi->segment_id = mbmi->segment_id;
// Motion Vectors
mi->mv[0].row = mbmi->mv[0].as_mv.row;
mi->mv[0].col = mbmi->mv[0].as_mv.col;
mi->mv[1].row = mbmi->mv[1].as_mv.row;
mi->mv[1].col = mbmi->mv[1].as_mv.col;
// Reference Frames
mi->ref_frame[0] = mbmi->ref_frame[0];
mi->ref_frame[1] = mbmi->ref_frame[1];
// Prediction Mode
mi->mode = mbmi->mode;
// Prediction Mode for Chromatic planes
if (mi->mode < INTRA_MODES) {
mi->uv_mode = mbmi->uv_mode;
} else {
mi->uv_mode = INTRA_INVALID;
}
// Block Size
mi->sb_type = mbmi->sb_type;
// Skip Flag
mi->skip = mbmi->skip;
#if CONFIG_DUAL_FILTER
mi->filter[0] = mbmi->interp_filter[0];
mi->filter[1] = mbmi->interp_filter[1];
#else
mi->filter = mbmi->interp_filter;
#endif
// Transform
mi->tx_type = mbmi->tx_type;
mi->tx_size = mbmi->tx_size;
#if CONFIG_CDEF
mi->cdef_level = cm->cdef_strengths[mbmi->cdef_strength] / CLPF_STRENGTHS;
mi->cdef_strength =
cm->cdef_strengths[mbmi->cdef_strength] % CLPF_STRENGTHS;
mi->cdef_strength += mi->cdef_strength == 3;
#endif
}
}
return 1;
}

View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 2017, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#ifndef AOM_INSPECTION_H_
#define AOM_INSPECTION_H_
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#if CONFIG_ACCOUNTING
#include "av1/decoder/accounting.h"
#endif
typedef void (*aom_inspect_cb)(void *decoder, void *data);
typedef struct insp_mv insp_mv;
struct insp_mv {
int16_t row;
int16_t col;
};
typedef struct insp_mi_data insp_mi_data;
struct insp_mi_data {
insp_mv mv[2];
int8_t ref_frame[2];
int8_t mode;
int8_t uv_mode;
int8_t sb_type;
int8_t skip;
int8_t segment_id;
#if CONFIG_DUAL_FILTER
int8_t filter[2];
#else
int8_t filter;
#endif
int8_t tx_type;
int8_t tx_size;
#if CONFIG_CDEF
int8_t cdef_level;
int8_t cdef_strength;
#endif
};
typedef struct insp_frame_data insp_frame_data;
struct insp_frame_data {
#if CONFIG_ACCOUNTING
Accounting *accounting;
#endif
insp_mi_data *mi_grid;
int show_frame;
int frame_type;
int base_qindex;
int mi_rows;
int mi_cols;
int tile_mi_rows;
int tile_mi_cols;
int16_t y_dequant[MAX_SEGMENTS][2];
int16_t uv_dequant[MAX_SEGMENTS][2];
#if CONFIG_CDEF
// TODO(negge): add per frame CDEF data
#endif
};
void ifd_init(insp_frame_data *fd, int frame_width, int frame_height);
void ifd_clear(insp_frame_data *fd);
int ifd_inspect(insp_frame_data *fd, void *decoder);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // AOM_INSPECTION_H_

View file

@ -0,0 +1,121 @@
/*
* Copyright (c) 2001-2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
/* clang-format off */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include "aom_dsp/bitreader.h"
#include "av1/common/pvq.h"
#include "pvq_decoder.h"
#define aom_decode_pvq_split(r, adapt, sum, ctx, ACCT_STR_NAME) \
aom_decode_pvq_split_(r, adapt, sum, ctx ACCT_STR_ARG(ACCT_STR_NAME))
static int aom_decode_pvq_split_(aom_reader *r, od_pvq_codeword_ctx *adapt,
int sum, int ctx ACCT_STR_PARAM) {
int shift;
int count;
int msbs;
int fctx;
count = 0;
if (sum == 0) return 0;
shift = OD_MAXI(0, OD_ILOG(sum) - 3);
fctx = 7*ctx + (sum >> shift) - 1;
msbs = aom_read_symbol_pvq(r, adapt->pvq_split_cdf[fctx], (sum >> shift) + 1,
ACCT_STR_NAME);
if (shift) count = aom_read_literal(r, shift, ACCT_STR_NAME);
count += msbs << shift;
if (count > sum) {
count = sum;
#if CONFIG_DAALA_EC
r->ec.error = 1;
#else
# error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
#endif
}
return count;
}
void aom_decode_band_pvq_splits(aom_reader *r, od_pvq_codeword_ctx *adapt,
od_coeff *y, int n, int k, int level) {
int mid;
int count_right;
if (n == 1) {
y[0] = k;
}
else if (k == 0) {
OD_CLEAR(y, n);
}
else if (k == 1 && n <= 16) {
int cdf_id;
int pos;
cdf_id = od_pvq_k1_ctx(n, level == 0);
OD_CLEAR(y, n);
pos = aom_read_symbol_pvq(r, adapt->pvq_k1_cdf[cdf_id], n, "pvq:k1");
y[pos] = 1;
}
else {
mid = n >> 1;
count_right = aom_decode_pvq_split(r, adapt, k, od_pvq_size_ctx(n),
"pvq:split");
aom_decode_band_pvq_splits(r, adapt, y, mid, k - count_right, level + 1);
aom_decode_band_pvq_splits(r, adapt, y + mid, n - mid, count_right,
level + 1);
}
}
/** Decodes the tail of a Laplace-distributed variable, i.e. it doesn't
* do anything special for the zero case.
*
* @param [dec] range decoder
* @param [decay] decay factor of the distribution, i.e. pdf ~= decay^x
*
* @retval decoded variable x
*/
int aom_laplace_decode_special_(aom_reader *r, unsigned decay ACCT_STR_PARAM) {
int pos;
int shift;
int xs;
int sym;
const uint16_t *cdf;
shift = 0;
/* We don't want a large decay value because that would require too many
symbols. */
while (decay > 235) {
decay = (decay*decay + 128) >> 8;
shift++;
}
decay = OD_MINI(decay, 254);
decay = OD_MAXI(decay, 2);
cdf = EXP_CDF_TABLE[(decay + 1) >> 1];
OD_LOG((OD_LOG_PVQ, OD_LOG_DEBUG, "decay = %d\n", decay));
xs = 0;
do {
sym = OD_MINI(xs, 15);
{
int i;
OD_LOG((OD_LOG_PVQ, OD_LOG_DEBUG, "%d %d %d", xs, shift, sym));
for (i = 0; i < 16; i++) {
OD_LOG_PARTIAL((OD_LOG_PVQ, OD_LOG_DEBUG, "%d ", cdf[i]));
}
OD_LOG_PARTIAL((OD_LOG_PVQ, OD_LOG_DEBUG, "\n"));
}
sym = aom_read_cdf(r, cdf, 16, ACCT_STR_NAME);
xs += sym;
} while (sym >= 15);
if (shift) pos = (xs << shift) + aom_read_literal(r, shift, ACCT_STR_NAME);
else pos = xs;
return pos;
}

View file

@ -0,0 +1,378 @@
/*
* Copyright (c) 2001-2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
/* clang-format off */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include "./aom_config.h"
#include "aom_dsp/bitreader.h"
#include "aom_dsp/entcode.h"
#include "aom_dsp/entdec.h"
#include "av1/common/odintrin.h"
#include "av1/common/partition.h"
#include "av1/common/pvq_state.h"
#include "av1/decoder/decint.h"
#include "av1/decoder/pvq_decoder.h"
#include "aom_ports/system_state.h"
int aom_read_symbol_pvq_(aom_reader *r, aom_cdf_prob *cdf, int nsymbs
ACCT_STR_PARAM) {
if (cdf[0] == 0)
aom_cdf_init_q15_1D(cdf, nsymbs, CDF_SIZE(nsymbs));
return aom_read_symbol(r, cdf, nsymbs, ACCT_STR_NAME);
}
static void aom_decode_pvq_codeword(aom_reader *r, od_pvq_codeword_ctx *ctx,
od_coeff *y, int n, int k) {
int i;
aom_decode_band_pvq_splits(r, ctx, y, n, k, 0);
for (i = 0; i < n; i++) {
if (y[i] && aom_read_bit(r, "pvq:sign")) y[i] = -y[i];
}
}
/** Inverse of neg_interleave; decodes the interleaved gain.
*
* @param [in] x quantized/interleaved gain to decode
* @param [in] ref quantized gain of the reference
* @return original quantized gain value
*/
static int neg_deinterleave(int x, int ref) {
if (x < 2*ref-1) {
if (x & 1) return ref - 1 - (x >> 1);
else return ref + (x >> 1);
}
else return x+1;
}
/** Synthesizes one parition of coefficient values from a PVQ-encoded
* vector.
*
* @param [out] xcoeff output coefficient partition (x in math doc)
* @param [in] ypulse PVQ-encoded values (y in math doc); in the noref
* case, this vector has n entries, in the
* reference case it contains n-1 entries
* (the m-th entry is not included)
* @param [in] ref reference vector (prediction)
* @param [in] n number of elements in this partition
* @param [in] gr gain of the reference vector (prediction)
* @param [in] noref indicates presence or lack of prediction
* @param [in] g decoded quantized vector gain
* @param [in] theta decoded theta (prediction error)
* @param [in] qm QM with magnitude compensation
* @param [in] qm_inv Inverse of QM with magnitude compensation
*/
static void pvq_synthesis(od_coeff *xcoeff, od_coeff *ypulse, od_val16 *r16,
int n, od_val32 gr, int noref, od_val32 g, od_val32 theta, const int16_t *qm_inv,
int shift) {
int s;
int m;
/* Sign of the Householder reflection vector */
s = 0;
/* Direction of the Householder reflection vector */
m = noref ? 0 : od_compute_householder(r16, n, gr, &s, shift);
od_pvq_synthesis_partial(xcoeff, ypulse, r16, n, noref, g, theta, m, s,
qm_inv);
}
typedef struct {
od_coeff *ref;
int nb_coeffs;
int allow_flip;
} cfl_ctx;
/** Decodes a single vector of integers (eg, a partition within a
* coefficient block) encoded using PVQ
*
* @param [in,out] ec range encoder
* @param [in] q0 scale/quantizer
* @param [in] n number of coefficients in partition
* @param [in,out] model entropy decoder state
* @param [in,out] adapt adaptation context
* @param [in,out] exg ExQ16 expectation of decoded gain value
* @param [in,out] ext ExQ16 expectation of decoded theta value
* @param [in] ref 'reference' (prediction) vector
* @param [out] out decoded partition
* @param [out] noref boolean indicating absence of reference
* @param [in] beta per-band activity masking beta param
* @param [in] is_keyframe whether we're encoding a keyframe
* @param [in] pli plane index
* @param [in] cdf_ctx selects which cdf context to use
* @param [in,out] skip_rest whether to skip further bands in each direction
* @param [in] band index of the band being decoded
* @param [in] band index of the band being decoded
* @param [out] skip skip flag with range [0,1]
* @param [in] qm QM with magnitude compensation
* @param [in] qm_inv Inverse of QM with magnitude compensation
*/
static void pvq_decode_partition(aom_reader *r,
int q0,
int n,
generic_encoder model[3],
od_adapt_ctx *adapt,
int *exg,
int *ext,
od_coeff *ref,
od_coeff *out,
int *noref,
od_val16 beta,
int is_keyframe,
int pli,
int cdf_ctx,
cfl_ctx *cfl,
int has_skip,
int *skip_rest,
int band,
int *skip,
const int16_t *qm,
const int16_t *qm_inv) {
int k;
od_val32 qcg;
int itheta;
od_val32 theta;
od_val32 gr;
od_val32 gain_offset;
od_coeff y[MAXN];
int qg;
int id;
int i;
od_val16 ref16[MAXN];
int rshift;
theta = 0;
gr = 0;
gain_offset = 0;
/* Skip is per-direction. For band=0, we can use any of the flags. */
if (skip_rest[(band + 2) % 3]) {
qg = 0;
if (is_keyframe) {
itheta = -1;
*noref = 1;
}
else {
itheta = 0;
*noref = 0;
}
}
else {
/* Jointly decode gain, itheta and noref for small values. Then we handle
larger gain. */
id = aom_read_symbol_pvq(r, &adapt->pvq.pvq_gaintheta_cdf[cdf_ctx][0],
8 + 7*has_skip, "pvq:gaintheta");
if (!is_keyframe && id >= 10) id++;
if (is_keyframe && id >= 8) id++;
if (id >= 8) {
id -= 8;
skip_rest[0] = skip_rest[1] = skip_rest[2] = 1;
}
qg = id & 1;
itheta = (id >> 1) - 1;
*noref = (itheta == -1);
}
/* The CfL flip bit is only decoded on the first band that has noref=0. */
if (cfl->allow_flip && !*noref) {
int flip;
flip = aom_read_bit(r, "cfl:flip");
if (flip) {
for (i = 0; i < cfl->nb_coeffs; i++) cfl->ref[i] = -cfl->ref[i];
}
cfl->allow_flip = 0;
}
if (qg > 0) {
int tmp;
tmp = *exg;
qg = 1 + generic_decode(r, &model[!*noref], &tmp, 2, "pvq:gain");
OD_IIR_DIADIC(*exg, qg << 16, 2);
}
*skip = 0;
#if defined(OD_FLOAT_PVQ)
rshift = 0;
#else
/* Shift needed to make the reference fit in 15 bits, so that the Householder
vector can fit in 16 bits. */
rshift = OD_MAXI(0, od_vector_log_mag(ref, n) - 14);
#endif
for (i = 0; i < n; i++) {
#if defined(OD_FLOAT_PVQ)
ref16[i] = ref[i]*(double)qm[i]*OD_QM_SCALE_1;
#else
ref16[i] = OD_SHR_ROUND(ref[i]*qm[i], OD_QM_SHIFT + rshift);
#endif
}
if(!*noref){
/* we have a reference; compute its gain */
od_val32 cgr;
int icgr;
int cfl_enabled;
cfl_enabled = pli != 0 && is_keyframe && !OD_DISABLE_CFL;
cgr = od_pvq_compute_gain(ref16, n, q0, &gr, beta, rshift);
if (cfl_enabled) cgr = OD_CGAIN_SCALE;
#if defined(OD_FLOAT_PVQ)
icgr = (int)floor(.5 + cgr);
#else
icgr = OD_SHR_ROUND(cgr, OD_CGAIN_SHIFT);
#endif
/* quantized gain is interleave encoded when there's a reference;
deinterleave it now */
if (is_keyframe) qg = neg_deinterleave(qg, icgr);
else {
qg = neg_deinterleave(qg, icgr + 1) - 1;
if (qg == 0) *skip = (icgr ? OD_PVQ_SKIP_ZERO : OD_PVQ_SKIP_COPY);
}
if (qg == icgr && itheta == 0 && !cfl_enabled) *skip = OD_PVQ_SKIP_COPY;
gain_offset = cgr - OD_SHL(icgr, OD_CGAIN_SHIFT);
qcg = OD_SHL(qg, OD_CGAIN_SHIFT) + gain_offset;
/* read and decode first-stage PVQ error theta */
if (itheta > 1) {
int tmp;
tmp = *ext;
itheta = 2 + generic_decode(r, &model[2], &tmp, 2, "pvq:theta");
OD_IIR_DIADIC(*ext, itheta << 16, 2);
}
theta = od_pvq_compute_theta(itheta, od_pvq_compute_max_theta(qcg, beta));
}
else{
itheta = 0;
if (!is_keyframe) qg++;
qcg = OD_SHL(qg, OD_CGAIN_SHIFT);
if (qg == 0) *skip = OD_PVQ_SKIP_ZERO;
}
k = od_pvq_compute_k(qcg, itheta, *noref, n, beta);
if (k != 0) {
/* when noref==0, y is actually size n-1 */
aom_decode_pvq_codeword(r, &adapt->pvq.pvq_codeword_ctx, y,
n - !*noref, k);
}
else {
OD_CLEAR(y, n);
}
if (*skip) {
if (*skip == OD_PVQ_SKIP_COPY) OD_COPY(out, ref, n);
else OD_CLEAR(out, n);
}
else {
od_val32 g;
g = od_gain_expand(qcg, q0, beta);
pvq_synthesis(out, y, ref16, n, gr, *noref, g, theta, qm_inv, rshift);
}
/* If OD_PVQ_SKIP_ZERO or OD_PVQ_SKIP_COPY, set skip to 1 for visualization */
if (*skip) *skip = 1;
}
/** Decodes a coefficient block (except for DC) encoded using PVQ
*
* @param [in,out] dec daala decoder context
* @param [in] ref 'reference' (prediction) vector
* @param [out] out decoded partition
* @param [in] q0 quantizer
* @param [in] pli plane index
* @param [in] bs log of the block size minus two
* @param [in] beta per-band activity masking beta param
* @param [in] is_keyframe whether we're encoding a keyframe
* @param [out] flags bitmask of the per band skip and noref flags
* @param [in] ac_dc_coded skip flag for the block (range 0-3)
* @param [in] qm QM with magnitude compensation
* @param [in] qm_inv Inverse of QM with magnitude compensation
*/
void od_pvq_decode(daala_dec_ctx *dec,
od_coeff *ref,
od_coeff *out,
int q0,
int pli,
int bs,
const od_val16 *beta,
int is_keyframe,
unsigned int *flags,
PVQ_SKIP_TYPE ac_dc_coded,
const int16_t *qm,
const int16_t *qm_inv){
int noref[PVQ_MAX_PARTITIONS];
int skip[PVQ_MAX_PARTITIONS];
int *exg;
int *ext;
int nb_bands;
int i;
const int *off;
int size[PVQ_MAX_PARTITIONS];
generic_encoder *model;
int skip_rest[3] = {0};
cfl_ctx cfl;
const unsigned char *pvq_qm;
int use_masking;
aom_clear_system_state();
/*Default to skip=1 and noref=0 for all bands.*/
for (i = 0; i < PVQ_MAX_PARTITIONS; i++) {
noref[i] = 0;
skip[i] = 1;
}
use_masking = dec->use_activity_masking;
if (use_masking)
pvq_qm = &dec->state.pvq_qm_q4[pli][0];
else
pvq_qm = 0;
exg = &dec->state.adapt->pvq.pvq_exg[pli][bs][0];
ext = dec->state.adapt->pvq.pvq_ext + bs*PVQ_MAX_PARTITIONS;
model = dec->state.adapt->pvq.pvq_param_model;
nb_bands = OD_BAND_OFFSETS[bs][0];
off = &OD_BAND_OFFSETS[bs][1];
out[0] = ac_dc_coded & DC_CODED;
if (ac_dc_coded < AC_CODED) {
if (is_keyframe) for (i = 1; i < 1 << (2*bs + 4); i++) out[i] = 0;
else for (i = 1; i < 1 << (2*bs + 4); i++) out[i] = ref[i];
}
else {
for (i = 0; i < nb_bands; i++) size[i] = off[i+1] - off[i];
cfl.ref = ref;
cfl.nb_coeffs = off[nb_bands];
cfl.allow_flip = pli != 0 && is_keyframe;
for (i = 0; i < nb_bands; i++) {
int q;
if (use_masking)
q = OD_MAXI(1, q0 * pvq_qm[od_qm_get_index(bs, i + 1)] >> 4);
else
q = OD_MAXI(1, q0);
pvq_decode_partition(dec->r, q, size[i],
model, dec->state.adapt, exg + i, ext + i, ref + off[i], out + off[i],
&noref[i], beta[i], is_keyframe, pli,
(pli != 0)*OD_TXSIZES*PVQ_MAX_PARTITIONS + bs*PVQ_MAX_PARTITIONS + i,
&cfl, i == 0 && (i < nb_bands - 1), skip_rest, i, &skip[i],
qm + off[i], qm_inv + off[i]);
if (i == 0 && !skip_rest[0] && bs > 0) {
int skip_dir;
int j;
skip_dir = aom_read_symbol(dec->r,
&dec->state.adapt->pvq.pvq_skip_dir_cdf[(pli != 0) + 2*(bs - 1)][0], 7,
"pvq:skiprest");
for (j = 0; j < 3; j++) skip_rest[j] = !!(skip_dir & (1 << j));
}
}
}
*flags = 0;
for (i = nb_bands - 1; i >= 0; i--) {
*flags <<= 1;
*flags |= noref[i]&1;
*flags <<= 1;
*flags |= skip[i]&1;
}
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2001-2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
/* clang-format off */
#if !defined(_pvq_decoder_H)
# define _pvq_decoder_H (1)
# include "aom_dsp/bitreader.h"
# include "aom_dsp/entdec.h"
# include "av1/common/pvq.h"
# include "av1/decoder/decint.h"
#define aom_read_symbol_pvq(r, cdf, nsymbs, ACCT_STR_NAME) \
aom_read_symbol_pvq_(r, cdf, nsymbs ACCT_STR_ARG(ACCT_STR_NAME))
int aom_read_symbol_pvq_(aom_reader *r, aom_cdf_prob *cdf, int nsymbs
ACCT_STR_PARAM);
void aom_decode_band_pvq_splits(aom_reader *r, od_pvq_codeword_ctx *adapt,
od_coeff *y, int n, int k, int level);
#define aom_laplace_decode_special(r, decay, ACCT_STR_NAME) \
aom_laplace_decode_special_(r, decay ACCT_STR_ARG(ACCT_STR_NAME))
int aom_laplace_decode_special_(aom_reader *r, unsigned decay ACCT_STR_PARAM);
void od_pvq_decode(daala_dec_ctx *dec, od_coeff *ref, od_coeff *out, int q0,
int pli, int bs, const od_val16 *beta, int is_keyframe,
unsigned int *flags, PVQ_SKIP_TYPE ac_dc_coded, const int16_t *qm,
const int16_t *qm_inv);
#endif