From 89747d09cc0573d8c631c504e8354cbb80c60a53 Mon Sep 17 00:00:00 2001 From: Jingning Han Date: Wed, 27 May 2015 10:48:26 -0700 Subject: [PATCH] Enable selective key frame tile decoding This commit allows the decoder to decode selective tiles according to decoder configuration settings. To decode a single tile out of the provided key frame bit-stream (test_kf.webm), set compiler configuration: --enable-experimental --enable-row-tile --enable-key-frame-tile use the command: vpxdec -o test_dec.y4m test_kf.webm --tile-row=1 --tile-column=2 where the tile's row and column indexes are 1 and 2, respectively. To decode all row tiles inside a provided column index, use: --tile-row=-1 --tile-column=2 To decode all column tiles inside a provided row index, use: --tile-row=2 --tile-column=-1 Change-Id: Ib73c266414dcee7eaab5d741b90d0058970dae56 --- vp9/common/vp9_onyxc_int.h | 4 +- vp9/decoder/vp9_decodeframe.c | 201 ++++++++++++++++++++++++---------- vp9/decoder/vp9_decodemv.c | 3 +- vp9/encoder/vp9_bitstream.c | 10 +- vp9/encoder/vp9_encodeframe.c | 9 ++ vp9/encoder/vp9_rdopt.c | 6 +- vpxdec.c | 4 +- 7 files changed, 170 insertions(+), 67 deletions(-) diff --git a/vp9/common/vp9_onyxc_int.h b/vp9/common/vp9_onyxc_int.h index 442957c5f..c02696c96 100644 --- a/vp9/common/vp9_onyxc_int.h +++ b/vp9/common/vp9_onyxc_int.h @@ -320,7 +320,7 @@ static INLINE int calc_mi_size(int len) { return len + MI_BLOCK_SIZE; } -static INLINE void set_mi_row_col(MACROBLOCKD *xd, const TileInfo *const tile, +static void set_mi_row_col(MACROBLOCKD *xd, const TileInfo *const tile, int mi_row, int bh, int mi_col, int bw, int mi_rows, int mi_cols) { @@ -330,7 +330,7 @@ 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 VP9_ROW_TILE +#if CONFIG_ROW_TILE xd->up_available = (mi_row > tile->mi_row_start); #else xd->up_available = (mi_row != 0); diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c index 2fafc34ae..52690ac16 100644 --- a/vp9/decoder/vp9_decodeframe.c +++ b/vp9/decoder/vp9_decodeframe.c @@ -1961,8 +1961,12 @@ static void get_tile_buffers(VP9Decoder *pbi, const uint8_t *orig_data = data; const uint8_t *tile_end_col[1024]; size_t tile_col_size; + int tile_col_limit = (pbi->dec_tile_col == -1) ? INT_MAX : + MIN(pbi->dec_tile_col, tile_cols); + int tile_row_limit = (pbi->dec_tile_row == -1) ? INT_MAX : + MIN(pbi->dec_tile_row, tile_rows); - for (c = 0; c < tile_cols; ++c) { + for (c = 0; c < tile_cols && c <= tile_col_limit; ++c) { if (c < tile_cols - 1) { tile_col_size = mem_get_be32(data); data += 4; @@ -1975,14 +1979,33 @@ static void get_tile_buffers(VP9Decoder *pbi, } data = orig_data; - for (c = 0; c < tile_cols; ++c) { + + if (tile_row_limit != INT_MAX && tile_col_limit != INT_MAX) { + // Decode a single tile + if (tile_col_limit > 0) + data = tile_end_col[tile_col_limit - 1]; + if (tile_col_limit < tile_cols - 1) + data += 4; + + for (r = 0; r <= tile_row_limit; ++r) { + const int is_last = (r == tile_rows - 1); + TileBuffer *const buf = &tile_buffers[r][tile_col_limit]; + buf->col = tile_col_limit; + get_tile_buffer(tile_end_col[tile_col_limit], is_last, + &pbi->common.error, &data, + pbi->decrypt_cb, pbi->decrypt_state, buf); + } + return; + } + + for (c = 0; c < tile_cols && c <= tile_col_limit; ++c) { if (c > 0) data = tile_end_col[c - 1]; if (c < tile_cols - 1) data += 4; - for (r = 0; r < tile_rows; ++r) { + for (r = 0; r < tile_rows && r <= tile_row_limit; ++r) { const int is_last = (r == tile_rows - 1); TileBuffer *const buf = &tile_buffers[r][c]; buf->col = c; @@ -2021,8 +2044,14 @@ static const uint8_t *decode_tiles(VP9Decoder *pbi, const int tile_rows = cm->tile_rows; #if CONFIG_ROW_TILE TileBuffer (*tile_buffers)[1024] = pbi->tile_buffers; + const int tile_col_limit = (pbi->dec_tile_col == -1) ? INT_MAX : + MIN(pbi->dec_tile_col, tile_cols); + const int tile_row_limit = (pbi->dec_tile_row == -1) ? INT_MAX : + MIN(pbi->dec_tile_row, tile_rows); #else TileBuffer tile_buffers[4][1024]; + const int tile_col_limit = INT_MAX; + const int tile_row_limit = INT_MAX; #endif int tile_row, tile_col; int mi_row, mi_col; @@ -2078,79 +2107,131 @@ static const uint8_t *decode_tiles(VP9Decoder *pbi, pbi->total_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) { - TileInfo tile; - 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; - vp9_tile_init(&tile, tile_data->cm, tile_row, tile_col); + if (tile_row_limit != INT_MAX && tile_col_limit != INT_MAX) { + TileInfo tile; + const TileBuffer *const buf = &tile_buffers[tile_row_limit][tile_col_limit]; + tile_data = pbi->tile_data + tile_cols * tile_row_limit + tile_col_limit; + tile_data->cm = cm; + tile_data->xd = pbi->mb; + tile_data->xd.corrupted = 0; + vp9_tile_init(&tile, tile_data->cm, tile_row_limit, tile_col_limit); + setup_token_decoder(buf->data, data_end, buf->size, &cm->error, + &tile_data->bit_reader, pbi->decrypt_cb, + pbi->decrypt_state); + init_macroblockd(cm, &tile_data->xd); + vp9_zero(tile_data->xd.dqcoeff); + } else { + // 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) { + TileInfo tile; + const TileBuffer *const buf = &tile_buffers[tile_row][tile_col]; - setup_token_decoder(buf->data, data_end, buf->size, &cm->error, - &tile_data->bit_reader, pbi->decrypt_cb, - pbi->decrypt_state); + if (tile_row > tile_row_limit || tile_col > tile_col_limit) + continue; - init_macroblockd(cm, &tile_data->xd); + 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; + vp9_tile_init(&tile, tile_data->cm, tile_row, tile_col); - vp9_zero(tile_data->xd.dqcoeff); + setup_token_decoder(buf->data, data_end, buf->size, &cm->error, + &tile_data->bit_reader, pbi->decrypt_cb, + pbi->decrypt_state); + + init_macroblockd(cm, &tile_data->xd); + + vp9_zero(tile_data->xd.dqcoeff); + } } } - for (tile_row = 0; tile_row < tile_rows; ++tile_row) { + if (tile_row_limit != INT_MAX && tile_col_limit != INT_MAX) { TileInfo tile; -#if !CONFIG_ROW_TILE - vp9_tile_set_row(&tile, cm, tile_row); + vp9_tile_init(&tile, cm, tile_row_limit, tile_col_limit); + + for (mi_row = tile.mi_row_start; mi_row < tile.mi_row_end; + mi_row += MI_BLOCK_SIZE) { + tile_data = pbi->tile_data + tile_cols * tile_row_limit + tile_col_limit; + vp9_zero(tile_data->xd.left_context); + vp9_zero(tile_data->xd.left_seg_context); + for (mi_col = tile.mi_col_start; mi_col < tile.mi_col_end; + mi_col += MI_BLOCK_SIZE) { + decode_partition(tile_data->cm, &tile_data->xd, &tile, +#if CONFIG_SUPERTX + 0, +#endif + mi_row, mi_col, + &tile_data->bit_reader, BLOCK_64X64); + } + pbi->mb.corrupted |= tile_data->xd.corrupted; + } + return data_end; + } else { + for (tile_row = 0; tile_row < tile_rows; ++tile_row) { + TileInfo tile; +#if CONFIG_ROW_TILE + if (tile_row_limit != INT_MAX && tile_row != tile_row_limit) + continue; +#else + vp9_tile_set_row(&tile, cm, tile_row); #endif - for (tile_col = 0; tile_col < tile_cols; ++tile_col) { + for (tile_col = 0; tile_col < tile_cols; ++tile_col) { #if CONFIG_ROW_TILE - vp9_tile_init(&tile, cm, tile_row, tile_col); + if (tile_col_limit != INT_MAX && tile_col != tile_col_limit) + continue; + vp9_tile_init(&tile, cm, tile_row, tile_col); + vpx_memset(cm->above_context, 0, sizeof(*cm->above_context) * + MAX_MB_PLANE * 2 * aligned_cols); + vpx_memset(&cm->above_seg_context[tile.mi_col_start], 0, + sizeof(*cm->above_seg_context) * + mi_cols_aligned_to_sb(tile.mi_col_end - tile.mi_col_start)); #else - vp9_tile_set_col(&tile, cm, tile_col); + vp9_tile_set_col(&tile, cm, tile_col); #endif - for (mi_row = tile.mi_row_start; mi_row < tile.mi_row_end; - mi_row += MI_BLOCK_SIZE) { - const int col = pbi->inv_tile_order ? - tile_cols - tile_col - 1 : tile_col; - tile_data = pbi->tile_data + tile_cols * tile_row + col; - vp9_zero(tile_data->xd.left_context); - vp9_zero(tile_data->xd.left_seg_context); - for (mi_col = tile.mi_col_start; mi_col < tile.mi_col_end; - mi_col += MI_BLOCK_SIZE) { - decode_partition(tile_data->cm, &tile_data->xd, &tile, + for (mi_row = tile.mi_row_start; mi_row < tile.mi_row_end; + mi_row += MI_BLOCK_SIZE) { + const int col = pbi->inv_tile_order ? + tile_cols - tile_col - 1 : tile_col; + tile_data = pbi->tile_data + tile_cols * tile_row + col; + vp9_zero(tile_data->xd.left_context); + vp9_zero(tile_data->xd.left_seg_context); + for (mi_col = tile.mi_col_start; mi_col < tile.mi_col_end; + mi_col += MI_BLOCK_SIZE) { + decode_partition(tile_data->cm, &tile_data->xd, &tile, #if CONFIG_SUPERTX - 0, + 0, #endif - mi_row, mi_col, - &tile_data->bit_reader, BLOCK_64X64); + mi_row, mi_col, + &tile_data->bit_reader, BLOCK_64X64); + } + pbi->mb.corrupted |= tile_data->xd.corrupted; } - pbi->mb.corrupted |= tile_data->xd.corrupted; } - } #if !CONFIG_INTRABC - // Loopfilter one row. - if (!pbi->mb.corrupted && cm->lf.filter_level) { - const int lf_start = tile.mi_row_start - MI_BLOCK_SIZE; - LFWorkerData *const lf_data = (LFWorkerData*)pbi->lf_worker.data1; - - // delay the loopfilter by 1 macroblock row. - if (lf_start < 0) continue; - - // decoding has completed: finish up the loop filter in this thread. - if (tile.mi_row_end >= cm->mi_rows) continue; - - winterface->sync(&pbi->lf_worker); - lf_data->start = lf_start; - lf_data->stop = tile.mi_row_end - MI_BLOCK_SIZE;; - if (pbi->max_threads > 1) { - winterface->launch(&pbi->lf_worker); - } else { - winterface->execute(&pbi->lf_worker); + // Loopfilter one row. + if (!pbi->mb.corrupted && cm->lf.filter_level) { + const int lf_start = tile.mi_row_start - MI_BLOCK_SIZE; + LFWorkerData *const lf_data = (LFWorkerData*)pbi->lf_worker.data1; + + // delay the loopfilter by 1 macroblock row. + if (lf_start < 0) continue; + + // decoding has completed: finish up the loop filter in this thread. + if (tile.mi_row_end >= cm->mi_rows) continue; + + winterface->sync(&pbi->lf_worker); + lf_data->start = lf_start; + lf_data->stop = tile.mi_row_end - MI_BLOCK_SIZE;; + if (pbi->max_threads > 1) { + winterface->launch(&pbi->lf_worker); + } else { + winterface->execute(&pbi->lf_worker); + } } - } #endif // !CONFIG_INTRABC + } } // Loopfilter remaining rows in the frame. @@ -2162,6 +2243,10 @@ static const uint8_t *decode_tiles(VP9Decoder *pbi, winterface->execute(&pbi->lf_worker); } +#if CONFIG_ROW_TILE && CONFIG_KEY_FRAME_TILE + return data_end; +#endif + // Get last tile data. tile_data = pbi->tile_data + tile_cols * tile_rows - 1; diff --git a/vp9/decoder/vp9_decodemv.c b/vp9/decoder/vp9_decodemv.c index 62a12fb95..7394d86b8 100644 --- a/vp9/decoder/vp9_decodemv.c +++ b/vp9/decoder/vp9_decodemv.c @@ -249,7 +249,8 @@ static void read_intra_frame_mode_info(VP9_COMMON *const cm, int mi_row, int mi_col, vp9_reader *r) { MODE_INFO *const mi = xd->mi[0].src_mi; MB_MODE_INFO *const mbmi = &mi->mbmi; - const MODE_INFO *above_mi = xd->mi[-cm->mi_stride].src_mi; + const MODE_INFO *above_mi = xd->up_available ? + xd->mi[-cm->mi_stride].src_mi : NULL; const MODE_INFO *left_mi = xd->left_available ? xd->mi[-1].src_mi : NULL; const BLOCK_SIZE bsize = mbmi->sb_type; int i; diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c index d06c6d629..47199cdb6 100644 --- a/vp9/encoder/vp9_bitstream.c +++ b/vp9/encoder/vp9_bitstream.c @@ -848,7 +848,8 @@ static void write_mb_modes_kf(const VP9_COMMON *cm, MODE_INFO *mi_8x8, vp9_writer *w) { const struct segmentation *const seg = &cm->seg; const MODE_INFO *const mi = mi_8x8; - const MODE_INFO *const above_mi = mi_8x8[-xd->mi_stride].src_mi; + const MODE_INFO *const above_mi = xd->up_available ? + mi_8x8[-xd->mi_stride].src_mi : NULL; const MODE_INFO *const left_mi = xd->left_available ? mi_8x8[-1].src_mi : NULL; const MB_MODE_INFO *const mbmi = &mi->mbmi; @@ -1261,7 +1262,12 @@ static void write_modes(VP9_COMP *cpi, const TileInfo *const tile, vp9_writer *w, TOKENEXTRA **tok, const TOKENEXTRA *const tok_end) { int mi_row, mi_col; - +#if CONFIG_ROW_TILE + VP9_COMMON *cm = &cpi->common; + vpx_memset(&cm->above_seg_context[tile->mi_col_start], 0, + sizeof(*cm->above_seg_context) * + mi_cols_aligned_to_sb(tile->mi_col_end - tile->mi_col_start)); +#endif for (mi_row = tile->mi_row_start; mi_row < tile->mi_row_end; mi_row += MI_BLOCK_SIZE) { vp9_zero(cpi->mb.e_mbd.left_seg_context); diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 7dfc31058..ad5f45b9f 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -4561,6 +4561,15 @@ static void encode_tiles(VP9_COMP *cpi) { TOKENEXTRA * const old_tok = tok[tile_row][tile_col]; int mi_row; +#if CONFIG_ROW_TILE + int col_width = + mi_cols_aligned_to_sb(ptile->mi_col_end - ptile->mi_col_start); + vpx_memset(cm->above_context, 0, sizeof(*cm->above_context) * + MAX_MB_PLANE * 2 * mi_cols_aligned_to_sb(cm->mi_cols)); + vpx_memset(&cm->above_seg_context[ptile->mi_col_start], 0, + sizeof(*cm->above_seg_context) * col_width); +#endif + for (mi_row = ptile->mi_row_start; mi_row < ptile->mi_row_end; mi_row += MI_BLOCK_SIZE) { if (cpi->sf.use_nonrd_pick_mode && !frame_is_intra_only(cm)) diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c index afb370fe6..218806993 100644 --- a/vp9/encoder/vp9_rdopt.c +++ b/vp9/encoder/vp9_rdopt.c @@ -1360,7 +1360,8 @@ static int64_t rd_pick_intra_sub_8x8_y_mode(VP9_COMP *cpi, MACROBLOCK *mb, int i, j; const MACROBLOCKD *const xd = &mb->e_mbd; MODE_INFO *const mic = xd->mi[0].src_mi; - const MODE_INFO *above_mi = xd->mi[-xd->mi_stride].src_mi; + const MODE_INFO *above_mi = xd->up_available ? + xd->mi[-xd->mi_stride].src_mi : NULL; const MODE_INFO *left_mi = xd->left_available ? xd->mi[-1].src_mi : NULL; const BLOCK_SIZE bsize = xd->mi[0].src_mi->mbmi.sb_type; const int num_4x4_blocks_wide = num_4x4_blocks_wide_lookup[bsize]; @@ -1762,7 +1763,8 @@ static int64_t rd_pick_intra_sby_mode(VP9_COMP *cpi, MACROBLOCK *x, #if CONFIG_FILTERINTRA int mode_ext, fbit, fbit_selected = 0; #endif // CONFIG_FILTERINTRA - const MODE_INFO *above_mi = xd->mi[-xd->mi_stride].src_mi; + const MODE_INFO *above_mi = xd->up_available ? + xd->mi[-xd->mi_stride].src_mi : NULL; const MODE_INFO *left_mi = xd->left_available ? xd->mi[-1].src_mi : NULL; const PREDICTION_MODE A = vp9_above_block_mode(mic, above_mi, 0); const PREDICTION_MODE L = vp9_left_block_mode(mic, left_mi, 0); diff --git a/vpxdec.c b/vpxdec.c index 3c8a1c561..361a10e92 100644 --- a/vpxdec.c +++ b/vpxdec.c @@ -670,9 +670,9 @@ int main_loop(int argc, const char **argv_) { #endif #if CONFIG_ROW_TILE && CONFIG_KEY_FRAME_TILE else if (arg_match(&arg, &tiler, argi)) - tile_row = arg_parse_uint(&arg); + tile_row = arg_parse_int(&arg); else if (arg_match(&arg, &tilec, argi)) - tile_col = arg_parse_uint(&arg); + tile_col = arg_parse_int(&arg); #endif #if CONFIG_VP8_DECODER else if (arg_match(&arg, &addnoise_level, argi)) { -- 2.49.0