Commit 490ba1ad authored by Geza Lore's avatar Geza Lore

Port large scale tile coding features from nextgen.

If configured with --enable-ext-tile, the codec uses an alternative
tile coding syntax in the bitstream. Changes include::
 - The maximum number of tile rows and columns is extended to 1024
   each.
 - The minimum tile width/height is 64 pixels (1 superblock).
 - A tile copy mode is added where a tile directly reuse the coded
   data of a previous tile
 - The meaning of the tile-columns and tile-rows codec parameters are
   overloaded to mean tile-width and tile-height in units of 64
   pixels.
 - All tiles should now be independent, including rows within the
   same columns, so large scale parallel, or independent decoding is
   possible.
 - vpxdec also gained the options to decode only a particular tile,
   tile row, or tile column.

Changes without --enable-ext-tile:
 - All tiles should now be independent, including rows within the
   same columns, so large scale parallel, or independent decoding is
   possible.
 - vpxenc default tile configuration changed to use 1 tile column.

Change-Id: I0cd08ad550967ac18622dae5e98ad23d581cb33e
parent b4334460
......@@ -131,28 +131,32 @@ int vp10_alloc_context_buffers(VP10_COMMON *cm, int width, int height) {
}
if (cm->above_context_alloc_cols < cm->mi_cols) {
// TODO(geza.lore): These are bigger than they need to be.
// cm->tile_width would be enough but it complicates indexing a
// little elsewhere.
const int aligned_mi_cols = mi_cols_aligned_to_sb(cm->mi_cols);
int i;
for (i = 0 ; i < MAX_MB_PLANE ; i++) {
vpx_free(cm->above_context[i]);
vpx_free(cm->above_context[i]);
cm->above_context[i] = (ENTROPY_CONTEXT *)vpx_calloc(
2 * mi_cols_aligned_to_sb(cm->mi_cols),
sizeof(*cm->above_context[0]));
2 * aligned_mi_cols, sizeof(*cm->above_context[0]));
if (!cm->above_context[i]) goto fail;
}
vpx_free(cm->above_seg_context);
cm->above_seg_context = (PARTITION_CONTEXT *)vpx_calloc(
mi_cols_aligned_to_sb(cm->mi_cols), sizeof(*cm->above_seg_context));
aligned_mi_cols, sizeof(*cm->above_seg_context));
if (!cm->above_seg_context) goto fail;
#if CONFIG_VAR_TX
vpx_free(cm->above_txfm_context);
cm->above_txfm_context = (TXFM_CONTEXT *)vpx_calloc(
mi_cols_aligned_to_sb(cm->mi_cols), sizeof(*cm->above_txfm_context));
aligned_mi_cols, sizeof(*cm->above_txfm_context));
if (!cm->above_txfm_context) goto fail;
#endif
cm->above_context_alloc_cols = cm->mi_cols;
cm->above_context_alloc_cols = aligned_mi_cols;
}
return 0;
......
......@@ -26,6 +26,14 @@ extern "C" {
#define MI_MASK (MI_BLOCK_SIZE - 1)
#if CONFIG_EXT_TILE
# define MAX_TILE_ROWS 1024
# define MAX_TILE_COLS 1024
#else
# define MAX_TILE_ROWS 4
# define MAX_TILE_COLS 64
#endif // CONFIG_EXT_TILE
// Bitstream profiles indicated by 2-3 bits in the uncompressed header.
// 00: Profile 0. 8-bit 4:2:0 only.
// 10: Profile 1. 8-bit 4:4:4, 4:2:2, and 4:4:0.
......
......@@ -211,10 +211,18 @@ static INLINE int_mv scale_mv(const MB_MODE_INFO *mbmi, int ref,
static INLINE int is_inside(const TileInfo *const tile,
int mi_col, int mi_row, int mi_rows,
const POSITION *mi_pos) {
#if CONFIG_EXT_TILE
(void) mi_rows;
return !(mi_row + mi_pos->row < tile->mi_row_start ||
mi_col + mi_pos->col < tile->mi_col_start ||
mi_row + mi_pos->row >= tile->mi_row_end ||
mi_col + mi_pos->col >= tile->mi_col_end);
#else
return !(mi_row + mi_pos->row < 0 ||
mi_col + mi_pos->col < tile->mi_col_start ||
mi_row + mi_pos->row >= mi_rows ||
mi_col + mi_pos->col >= tile->mi_col_end);
#endif // CONFIG_EXT_TILE
}
static INLINE void lower_mv_precision(MV *mv, int allow_hp) {
......
......@@ -308,8 +308,12 @@ typedef struct VP10Common {
int error_resilient_mode;
#if !CONFIG_EXT_TILE
int log2_tile_cols, log2_tile_rows;
int tile_sz_mag;
#endif // !CONFIG_EXT_TILE
int tile_cols, tile_rows;
int tile_width, tile_height;
int byte_alignment;
int skip_loop_filter;
......@@ -436,7 +440,7 @@ static INLINE void vp10_init_macroblockd(VP10_COMMON *cm, MACROBLOCKD *xd,
static INLINE void set_skip_context(MACROBLOCKD *xd, int mi_row, int mi_col) {
const int above_idx = mi_col * 2;
const int left_idx = (mi_row * 2) & 15;
const int left_idx = (mi_row * 2) & 15; // FIXME: Mask should be CU_SIZE*2-1
int i;
for (i = 0; i < MAX_MB_PLANE; ++i) {
struct macroblockd_plane *const pd = &xd->plane[i];
......@@ -460,7 +464,11 @@ static INLINE void set_mi_row_col(MACROBLOCKD *xd, const TileInfo *const tile,
xd->mb_to_right_edge = ((mi_cols - bw - mi_col) * MI_SIZE) * 8;
// Are edges available for intra prediction?
#if CONFIG_EXT_TILE
xd->up_available = (mi_row > tile->mi_row_start);
#else
xd->up_available = (mi_row != 0);
#endif // CONFIG_EXT_TILE
xd->left_available = (mi_col > tile->mi_col_start);
if (xd->up_available) {
xd->above_mi = xd->mi[-xd->mi_stride];
......@@ -586,11 +594,18 @@ static INLINE int partition_plane_context(const MACROBLOCKD *xd,
static INLINE void vp10_zero_above_context(VP10_COMMON *const cm,
int mi_col_start, int mi_col_end) {
const int width = mi_col_end - mi_col_start;
int i;
for (i = 0 ; i < MAX_MB_PLANE ; i++)
vp10_zero_array(cm->above_context[i] + 2 * mi_col_start, 2 * width);
const int offset_y = 2 * mi_col_start;
const int width_y = 2 * width;
const int offset_uv = offset_y >> cm->subsampling_x;
const int width_uv = width_y >> cm->subsampling_x;
vp10_zero_array(cm->above_context[0] + offset_y, width_y);
vp10_zero_array(cm->above_context[1] + offset_uv, width_uv);
vp10_zero_array(cm->above_context[2] + offset_uv, width_uv);
vp10_zero_array(cm->above_seg_context + mi_col_start, width);
#if CONFIG_VAR_TX
vp10_zero_array(cm->above_txfm_context + mi_col_start, width);
#endif // CONFIG_VAR_TX
......
......@@ -172,7 +172,7 @@ static void loop_filter_rows_mt(YV12_BUFFER_CONFIG *frame,
const int sb_rows = mi_cols_aligned_to_sb(cm->mi_rows) >> MI_BLOCK_SIZE_LOG2;
// Decoder may allocate more threads than number of tiles based on user's
// input.
const int tile_cols = 1 << cm->log2_tile_cols;
const int tile_cols = cm->tile_cols;
const int num_workers = VPXMIN(nworkers, tile_cols);
int i;
......
......@@ -15,20 +15,16 @@
#define MIN_TILE_WIDTH_B64 4
#define MAX_TILE_WIDTH_B64 64
static int get_tile_offset(int idx, int mis, int log2) {
const int sb_cols = mi_cols_aligned_to_sb(mis) >> MI_BLOCK_SIZE_LOG2;
const int offset = ((idx * sb_cols) >> log2) << MI_BLOCK_SIZE_LOG2;
return VPXMIN(offset, mis);
}
void vp10_tile_set_row(TileInfo *tile, const VP10_COMMON *cm, int row) {
tile->mi_row_start = get_tile_offset(row, cm->mi_rows, cm->log2_tile_rows);
tile->mi_row_end = get_tile_offset(row + 1, cm->mi_rows, cm->log2_tile_rows);
tile->mi_row_start = row * cm->tile_height;
tile->mi_row_end = VPXMIN(tile->mi_row_start + cm->tile_height,
cm->mi_rows);
}
void vp10_tile_set_col(TileInfo *tile, const VP10_COMMON *cm, int col) {
tile->mi_col_start = get_tile_offset(col, cm->mi_cols, cm->log2_tile_cols);
tile->mi_col_end = get_tile_offset(col + 1, cm->mi_cols, cm->log2_tile_cols);
tile->mi_col_start = col * cm->tile_width;
tile->mi_col_end = VPXMIN(tile->mi_col_start + cm->tile_width,
cm->mi_cols);
}
void vp10_tile_init(TileInfo *tile, const VP10_COMMON *cm, int row, int col) {
......@@ -36,6 +32,8 @@ void vp10_tile_init(TileInfo *tile, const VP10_COMMON *cm, int row, int col) {
vp10_tile_set_col(tile, cm, col);
}
#if !CONFIG_EXT_TILE
// TODO(geza.lore): CU_SIZE dependent.
static int get_min_log2_tile_cols(const int sb64_cols) {
int min_log2 = 0;
while ((MAX_TILE_WIDTH_B64 << min_log2) < sb64_cols)
......@@ -51,9 +49,10 @@ static int get_max_log2_tile_cols(const int sb64_cols) {
}
void vp10_get_tile_n_bits(int mi_cols,
int *min_log2_tile_cols, int *max_log2_tile_cols) {
int *min_log2_tile_cols, int *max_log2_tile_cols) {
const int sb64_cols = mi_cols_aligned_to_sb(mi_cols) >> MI_BLOCK_SIZE_LOG2;
*min_log2_tile_cols = get_min_log2_tile_cols(sb64_cols);
*max_log2_tile_cols = get_max_log2_tile_cols(sb64_cols);
assert(*min_log2_tile_cols <= *max_log2_tile_cols);
}
#endif // !CONFIG_EXT_TILE
......@@ -2898,7 +2898,35 @@ static void setup_frame_size_with_refs(VP10_COMMON *cm,
pool->frame_bufs[cm->new_fb_idx].buf.render_height = cm->render_height;
}
static void setup_tile_info(VP10_COMMON *cm, struct vpx_read_bit_buffer *rb) {
static void setup_tile_info(VP10Decoder *const pbi,
struct vpx_read_bit_buffer *const rb) {
VP10_COMMON *const cm = &pbi->common;
#if CONFIG_EXT_TILE
// Read the tile width/height
cm->tile_width = vpx_rb_read_literal(rb, 6) + 1; // in [1, 64]
cm->tile_height = vpx_rb_read_literal(rb, 6) + 1; // in [1, 64]
cm->tile_width = cm->tile_width << MI_BLOCK_SIZE_LOG2;
cm->tile_height = cm->tile_height << MI_BLOCK_SIZE_LOG2;
cm->tile_width = VPXMIN(cm->tile_width, cm->mi_cols);
cm->tile_height = VPXMIN(cm->tile_height, cm->mi_rows);
// Get the number of tiles
cm->tile_cols = 1;
while (cm->tile_cols * cm->tile_width < cm->mi_cols)
++cm->tile_cols;
cm->tile_rows = 1;
while (cm->tile_rows * cm->tile_height < cm->mi_rows)
++cm->tile_rows;
if (cm->tile_cols * cm->tile_rows > 1) {
// Read the number of bytes used to store tile size
pbi->tile_col_size_bytes = vpx_rb_read_literal(rb, 2) + 1;
pbi->tile_size_bytes = vpx_rb_read_literal(rb, 2) + 1;
}
#else
int min_log2_tile_cols, max_log2_tile_cols, max_ones;
vp10_get_tile_n_bits(cm->mi_cols, &min_log2_tile_cols, &max_log2_tile_cols);
......@@ -2917,43 +2945,170 @@ static void setup_tile_info(VP10_COMMON *cm, struct vpx_read_bit_buffer *rb) {
if (cm->log2_tile_rows)
cm->log2_tile_rows += vpx_rb_read_bit(rb);
cm->tile_cols = 1 << cm->log2_tile_cols;
cm->tile_rows = 1 << cm->log2_tile_rows;
cm->tile_width = (mi_cols_aligned_to_sb(cm->mi_cols) >> cm->log2_tile_cols);
cm->tile_height = (mi_cols_aligned_to_sb(cm->mi_rows) >> cm->log2_tile_rows);
// round to integer multiples of 8
cm->tile_width = mi_cols_aligned_to_sb(cm->tile_width);
cm->tile_height = mi_cols_aligned_to_sb(cm->tile_height);
// tile size magnitude
if (cm->log2_tile_rows > 0 || cm->log2_tile_cols > 0) {
cm->tile_sz_mag = vpx_rb_read_literal(rb, 2);
if (cm->tile_rows > 1 || cm->tile_cols > 1) {
pbi->tile_size_bytes = vpx_rb_read_literal(rb, 2) + 1;
}
#endif // CONFIG_EXT_TILE
}
typedef struct TileBuffer {
const uint8_t *data;
size_t size;
int col; // only used with multi-threaded decoding
} TileBuffer;
static int mem_get_varsize(const uint8_t *data, const int mag) {
switch (mag) {
case 0:
return data[0];
static int mem_get_varsize(const uint8_t *src, const int sz) {
switch (sz) {
case 1:
return mem_get_le16(data);
return src[0];
case 2:
return mem_get_le24(data);
return mem_get_le16(src);
case 3:
return mem_get_le32(data);
return mem_get_le24(src);
case 4:
return mem_get_le32(src);
default:
assert("Invalid size" && 0);
return -1;
}
}
#if CONFIG_EXT_TILE
// Reads the next tile returning its size and adjusting '*data' accordingly
// based on 'is_last'.
static void get_tile_buffer(const uint8_t *const data_end,
struct vpx_internal_error_info *error_info,
const uint8_t **data,
vpx_decrypt_cb decrypt_cb, void *decrypt_state,
TileBufferDec (*const tile_buffers)[MAX_TILE_COLS],
int tile_size_bytes, int col, int row) {
size_t size;
assert("Invalid tile size marker value" && 0);
size_t copy_size = 0;
const uint8_t *copy_data = NULL;
return -1;
if (!read_is_valid(*data, tile_size_bytes, data_end))
vpx_internal_error(error_info, VPX_CODEC_CORRUPT_FRAME,
"Truncated packet or corrupt tile length");
if (decrypt_cb) {
uint8_t be_data[4];
decrypt_cb(decrypt_state, *data, be_data, tile_size_bytes);
// Only read number of bytes in cm->tile_size_bytes.
size = mem_get_varsize(be_data, tile_size_bytes);
} else {
size = mem_get_varsize(*data, tile_size_bytes);
}
// The top bit indicates copy mode
if ((size >> (tile_size_bytes * 8 - 1)) == 1) {
// The remaining bits in the top byte signal the row offset
int offset = (size >> (tile_size_bytes - 1) * 8) & 0x7f;
// Currently, only use tiles in same column as reference tiles.
copy_data = tile_buffers[row - offset][col].data;
copy_size = tile_buffers[row - offset][col].size;
size = 0;
}
*data += tile_size_bytes;
if (size > (size_t)(data_end - *data))
vpx_internal_error(error_info, VPX_CODEC_CORRUPT_FRAME,
"Truncated packet or corrupt tile size");
if (size > 0) {
tile_buffers[row][col].data = *data;
tile_buffers[row][col].size = size;
} else {
tile_buffers[row][col].data = copy_data;
tile_buffers[row][col].size = copy_size;
}
*data += size;
}
static void get_tile_buffers(
VP10Decoder *pbi,
const uint8_t *data, const uint8_t *data_end,
TileBufferDec (*const tile_buffers)[MAX_TILE_COLS]) {
VP10_COMMON *const cm = &pbi->common;
const int tile_cols = cm->tile_cols;
const int tile_rows = cm->tile_rows;
const int have_tiles = tile_cols * tile_rows > 1;
if (!have_tiles) {
const uint32_t tile_size = data_end - data;
tile_buffers[0][0].data = data;
tile_buffers[0][0].size = tile_size;
} else {
const uint8_t *tile_col_data_end[MAX_TILE_COLS];
const uint8_t *const data_start = data;
const int dec_tile_row = VPXMIN(pbi->dec_tile_row, tile_rows);
const int single_row = pbi->dec_tile_row >= 0;
const int tile_rows_start = single_row ? dec_tile_row : 0;
const int tile_rows_end = single_row ? tile_rows_start + 1 : tile_rows;
const int dec_tile_col = VPXMIN(pbi->dec_tile_col, tile_cols);
const int single_col = pbi->dec_tile_col >= 0;
const int tile_cols_start = single_col ? dec_tile_col : 0;
const int tile_cols_end = single_col ? tile_cols_start + 1 : tile_cols;
const int tile_col_size_bytes = pbi->tile_col_size_bytes;
const int tile_size_bytes = pbi->tile_size_bytes;
size_t tile_col_size;
int r, c;
// Read tile column sizes
for (c = 0; c < tile_cols_end; ++c) {
const int is_last = c == tile_cols - 1;
if (!is_last) {
tile_col_size = mem_get_varsize(data, tile_col_size_bytes);
data += tile_col_size_bytes;
tile_col_data_end[c] = data + tile_col_size;
} else {
tile_col_size = data_end - data;
tile_col_data_end[c] = data_end;
}
data += tile_col_size;
}
data = data_start;
// Read tile sizes
for (c = tile_cols_start; c < tile_cols_end; ++c) {
if (c > 0)
data = tile_col_data_end[c - 1];
if (c < tile_cols - 1)
data += tile_col_size_bytes;
for (r = 0; r < tile_rows_end; ++r) {
tile_buffers[r][c].col = c;
get_tile_buffer(tile_col_data_end[c],
&pbi->common.error, &data,
pbi->decrypt_cb, pbi->decrypt_state,
tile_buffers, tile_size_bytes, c, r);
}
}
}
}
#else
// Reads the next tile returning its size and adjusting '*data' accordingly
// based on 'is_last'.
static void get_tile_buffer(const uint8_t *const data_end,
const int tile_sz_mag, int is_last,
const int tile_size_bytes, int is_last,
struct vpx_internal_error_info *error_info,
const uint8_t **data,
vpx_decrypt_cb decrypt_cb, void *decrypt_state,
TileBuffer *buf) {
TileBufferDec *const buf) {
size_t size;
if (!is_last) {
......@@ -2963,12 +3118,12 @@ static void get_tile_buffer(const uint8_t *const data_end,
if (decrypt_cb) {
uint8_t be_data[4];
decrypt_cb(decrypt_state, *data, be_data, tile_sz_mag + 1);
size = mem_get_varsize(be_data, tile_sz_mag) + 1;
decrypt_cb(decrypt_state, *data, be_data, tile_size_bytes);
size = mem_get_varsize(be_data, tile_size_bytes);
} else {
size = mem_get_varsize(*data, tile_sz_mag) + 1;
size = mem_get_varsize(*data, tile_size_bytes);
}
*data += tile_sz_mag + 1;
*data += tile_size_bytes;
if (size > (size_t)(data_end - *data))
vpx_internal_error(error_info, VPX_CODEC_CORRUPT_FRAME,
......@@ -2983,36 +3138,54 @@ static void get_tile_buffer(const uint8_t *const data_end,
*data += size;
}
static void get_tile_buffers(VP10Decoder *pbi,
const uint8_t *data, const uint8_t *data_end,
int tile_cols, int tile_rows,
TileBuffer (*tile_buffers)[1 << 6]) {
static void get_tile_buffers(
VP10Decoder *pbi,
const uint8_t *data, const uint8_t *data_end,
TileBufferDec (*const tile_buffers)[MAX_TILE_COLS]) {
VP10_COMMON *const cm = &pbi->common;
int r, c;
const int tile_cols = cm->tile_cols;
const int tile_rows = cm->tile_rows;
for (r = 0; r < tile_rows; ++r) {
for (c = 0; c < tile_cols; ++c) {
const int is_last = (r == tile_rows - 1) && (c == tile_cols - 1);
TileBuffer *const buf = &tile_buffers[r][c];
TileBufferDec *const buf = &tile_buffers[r][c];
buf->col = c;
get_tile_buffer(data_end, pbi->common.tile_sz_mag,
is_last, &pbi->common.error, &data,
get_tile_buffer(data_end, pbi->tile_size_bytes,
is_last, &cm->error, &data,
pbi->decrypt_cb, pbi->decrypt_state, buf);
}
}
}
#endif // CONFIG_EXT_TILE
static const uint8_t *decode_tiles(VP10Decoder *pbi,
const uint8_t *data,
const uint8_t *data_end) {
VP10_COMMON *const cm = &pbi->common;
const VPxWorkerInterface *const winterface = vpx_get_worker_interface();
const int aligned_cols = mi_cols_aligned_to_sb(cm->mi_cols);
const int tile_cols = 1 << cm->log2_tile_cols;
const int tile_rows = 1 << cm->log2_tile_rows;
TileBuffer tile_buffers[4][1 << 6];
const int tile_cols = cm->tile_cols;
const int tile_rows = cm->tile_rows;
TileBufferDec (*const tile_buffers)[MAX_TILE_COLS] = pbi->tile_buffers;
#if CONFIG_EXT_TILE
const int dec_tile_row = VPXMIN(pbi->dec_tile_row, tile_rows);
const int single_row = pbi->dec_tile_row >= 0;
const int tile_rows_start = single_row ? dec_tile_row : 0;
const int tile_rows_end = single_row ? dec_tile_row + 1 : tile_rows;
const int dec_tile_col = VPXMIN(pbi->dec_tile_col, tile_cols);
const int single_col = pbi->dec_tile_col >= 0;
const int tile_cols_start = single_col ? dec_tile_col : 0;
const int tile_cols_end = single_col ? tile_cols_start + 1 : tile_cols;
const int inv_col_order = pbi->inv_tile_order && !single_col;
#else
const int tile_rows_start = 0;
const int tile_rows_end = tile_rows;
const int tile_cols_start = 0;
const int tile_cols_end = tile_cols;
const int inv_col_order = pbi->inv_tile_order;
#endif // CONFIG_EXT_TILE
int tile_row, tile_col;
int mi_row, mi_col;
TileData *tile_data = NULL;
#if CONFIG_ENTROPY
cm->do_subframe_update =
......@@ -3038,82 +3211,82 @@ static const uint8_t *decode_tiles(VP10Decoder *pbi,
pbi->mb.plane);
}
assert(tile_rows <= 4);
assert(tile_cols <= (1 << 6));
vp10_zero_above_context(cm, 0, aligned_cols);
assert(tile_rows <= MAX_TILE_ROWS);
assert(tile_cols <= MAX_TILE_COLS);
get_tile_buffers(pbi, data, data_end, tile_cols, tile_rows, tile_buffers);
get_tile_buffers(pbi, data, data_end, tile_buffers);
if (pbi->tile_data == NULL ||
(tile_cols * tile_rows) != pbi->total_tiles) {
(tile_cols * tile_rows) != pbi->allocated_tiles) {
vpx_free(pbi->tile_data);
CHECK_MEM_ERROR(
cm,
pbi->tile_data,
vpx_memalign(32, tile_cols * tile_rows * (sizeof(*pbi->tile_data))));
pbi->total_tiles = tile_rows * tile_cols;
pbi->allocated_tiles = tile_rows * tile_cols;
}
// Load all tile information into tile_data.
for (tile_row = 0; tile_row < tile_rows; ++tile_row) {
for (tile_col = 0; tile_col < tile_cols; ++tile_col) {
const TileBuffer *const buf = &tile_buffers[tile_row][tile_col];
tile_data = pbi->tile_data + tile_cols * tile_row + tile_col;
tile_data->cm = cm;
tile_data->xd = pbi->mb;
tile_data->xd.corrupted = 0;
tile_data->xd.counts =
for (tile_row = tile_rows_start; tile_row < tile_rows_end; ++tile_row) {
for (tile_col = tile_cols_start; tile_col < tile_cols_end; ++tile_col) {
const TileBufferDec *const buf = &tile_buffers[tile_row][tile_col];
TileData *const td = pbi->tile_data + tile_cols * tile_row + tile_col;
td->cm = cm;
td->xd = pbi->mb;
td->xd.corrupted = 0;
td->xd.counts =
cm->refresh_frame_context == REFRESH_FRAME_CONTEXT_BACKWARD ?
&cm->counts : NULL;
vp10_zero(tile_data->dqcoeff);
vp10_tile_init(&tile_data->xd.tile, tile_data->cm, tile_row, tile_col);
#if !CONFIG_ANS
setup_bool_decoder(buf->data, data_end, buf->size, &cm->error,
&tile_data->bit_reader, pbi->decrypt_cb,
pbi->decrypt_state);
#else
if (buf->size < 3 || !read_is_valid(buf->data, buf->size, data_end))
vpx_internal_error(&cm->error, VPX_CODEC_CORRUPT_FRAME,
"Truncated packet or corrupt tile length");
vp10_zero(td->dqcoeff);
vp10_tile_init(&td->xd.tile, td->cm, tile_row, tile_col);
setup_bool_decoder(buf->data, data_end, buf->size, &cm->error,
&tile_data->bit_reader, pbi->decrypt_cb,
pbi->decrypt_state);
&td->bit_reader,
pbi->decrypt_cb, pbi->decrypt_state);
#if CONFIG_ANS
setup_token_decoder(buf->data, data_end, buf->size, &cm->error,
&tile_data->token_ans, pbi->decrypt_cb,
pbi->decrypt_state);
#endif
vp10_init_macroblockd(cm, &tile_data->xd, tile_data->dqcoeff);
tile_data->xd.plane[0].color_index_map = tile_data->color_index_map[0];
tile_data->xd.plane[1].color_index_map = tile_data->color_index_map[1];
&td->token_ans,
pbi->decrypt_cb, pbi->decrypt_state);
#endif // CONFIG_ANS
vp10_init_macroblockd(cm, &td->xd, td->dqcoeff);
td->xd.plane[0].color_index_map = td->color_index_map[0];
td->xd.plane[1].color_index_map = td->color_index_map[1];
}
}
for (tile_row = 0; tile_row < tile_rows; ++tile_row) {
TileInfo tile;
vp10_tile_set_row(&tile, cm, tile_row);
for (mi_row = tile.mi_row_start; mi_row < tile.mi_row_end;
mi_row += MI_BLOCK_SIZE) {
for (tile_col = 0; tile_col < tile_cols; ++tile_col) {
const int col = pbi->inv_tile_order ?
tile_cols - tile_col - 1 : tile_col;
tile_data = pbi->tile_data + tile_cols * tile_row + col;
vp10_tile_set_col(&tile, tile_data->cm, col);
vp10_zero_left_context(&tile_data->xd);
for (mi_col = tile.mi_col_start; mi_col < tile.mi_col_end;
for (tile_row = tile_rows_start; tile_row < tile_rows_end; ++tile_row) {
int mi_row = 0;
TileInfo tile_info;
vp10_tile_set_row(&tile_info, cm, tile_row);
for (tile_col = tile_cols_start; tile_col < tile_cols_end; ++tile_col) {
const int col = inv_col_order ? tile_cols - 1 - tile_col : tile_col;
TileData *const td = pbi->tile_data + tile_cols * tile_row + col;
vp10_tile_set_col(&tile_info, cm, col);
vp10_zero_above_context(cm, tile_info.mi_col_start, tile_info.mi_col_end);
for (mi_row = tile_info.mi_row_start; mi_row < tile_info.mi_row_end;
mi_row += MI_BLOCK_SIZE) {
int mi_col;
vp10_zero_left_context(&td->xd);
for (mi_col = tile_info.mi_col_start; mi_col < tile_info.mi_col_end;
mi_col += MI_BLOCK_SIZE) {
decode_partition(pbi, &tile_data->xd,
decode_partition(pbi, &td->xd,
#if CONFIG_SUPERTX
0,
#endif
mi_row, mi_col, &tile_data->bit_reader,
#endif // CONFIG_SUPERTX
mi_row, mi_col, &td->bit_reader,
#if CONFIG_ANS
&tile_data->token_ans,
&td->token_ans,
#endif // CONFIG_ANS
BLOCK_64X64, 4);
}
pbi->mb.corrupted |= tile_data->xd.corrupted;
pbi->mb.corrupted |= td->xd.corrupted;
if (pbi->mb.corrupted)
vpx_internal_error(&cm->error, VPX_CODEC_CORRUPT_FRAME,
"Failed to decode tile data");
......@@ -3130,42 +3303,49 @@ static const uint8_t *decode_tiles(VP10Decoder *pbi,
}
#endif // CONFIG_ENTROPY
}
}
assert(mi_row > 0);
#if !CONFIG_VAR_TX
// Loopfilter one row.
if (cm->lf.filter_level && !cm->skip_loop_filter) {
const int lf_start = mi_row - MI_BLOCK_SIZE;
LFWorkerData *const lf_data = (LFWorkerData*)pbi->lf_worker.data1;