--- /dev/null
+/*
+ * Copyright (c) 2012 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef LIBVPX_TEST_MD5_HELPER_H_
+#define LIBVPX_TEST_MD5_HELPER_H_
+
+extern "C" {
+#include "./md5_utils.h"
+#include "vpx/vpx_decoder.h"
+}
+
+namespace libvpx_test {
+class MD5 {
+ public:
+ MD5() {
+ MD5Init(&md5_);
+ }
+
+ void Add(const vpx_image_t *img) {
+ for (int plane = 0; plane < 3; ++plane) {
+ uint8_t *buf = img->planes[plane];
+ const int h = plane ? (img->d_h + 1) >> 1 : img->d_h;
+ const int w = plane ? (img->d_w + 1) >> 1 : img->d_w;
+
+ for (int y = 0; y < h; ++y) {
+ MD5Update(&md5_, buf, w);
+ buf += img->stride[plane];
+ }
+ }
+ }
+
+ const char *Get(void) {
+ static const char hex[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
+ };
+ uint8_t tmp[16];
+ MD5Context ctx_tmp = md5_;
+
+ MD5Final(tmp, &ctx_tmp);
+ for (int i = 0; i < 16; i++) {
+ res_[i * 2 + 0] = hex[tmp[i] >> 4];
+ res_[i * 2 + 1] = hex[tmp[i] & 0xf];
+ }
+ res_[32] = 0;
+
+ return res_;
+ }
+
+ protected:
+ char res_[33];
+ MD5Context md5_;
+};
+
+} // namespace libvpx_test
+
+#endif // LIBVPX_TEST_MD5_HELPER_H_
LIBVPX_TEST_SRCS-yes += register_state_check.h
LIBVPX_TEST_SRCS-yes += test.mk
LIBVPX_TEST_SRCS-yes += acm_random.h
+LIBVPX_TEST_SRCS-yes += md5_helper.h
LIBVPX_TEST_SRCS-yes += codec_factory.h
LIBVPX_TEST_SRCS-yes += test_libvpx.cc
LIBVPX_TEST_SRCS-yes += util.h
# IDCT test currently depends on FDCT function
LIBVPX_TEST_SRCS-yes += idct8x8_test.cc
+LIBVPX_TEST_SRCS-yes += tile_independence_test.cc
endif
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += fdct4x4_test.cc
#include "test/decode_test_driver.h"
#include "test/ivf_video_source.h"
#include "test/util.h"
+#include "test/md5_helper.h"
extern "C" {
-#include "./md5_utils.h"
#include "vpx_mem/vpx_mem.h"
}
-#if defined(_MSC_VER)
-#define snprintf sprintf_s
-#endif
-
namespace {
// There are 61 test vectors in total.
const char *kTestVectors[] = {
ASSERT_NE(res, EOF) << "Read md5 data failed";
expected_md5[32] = '\0';
- MD5Context md5;
- MD5Init(&md5);
-
- // Compute and update md5 for each raw in decompressed data.
- for (int plane = 0; plane < 3; ++plane) {
- uint8_t *buf = img.planes[plane];
-
- for (unsigned int y = 0; y < (plane ? (img.d_h + 1) >> 1 : img.d_h);
- ++y) {
- MD5Update(&md5, buf, (plane ? (img.d_w + 1) >> 1 : img.d_w));
- buf += img.stride[plane];
- }
- }
-
- uint8_t md5_sum[16];
- MD5Final(md5_sum, &md5);
-
- char actual_md5[33];
- // Convert to get the actual md5.
- for (int i = 0; i < 16; i++) {
- snprintf(&actual_md5[i * 2], sizeof(actual_md5) - i * 2, "%02x",
- md5_sum[i]);
- }
- actual_md5[32] = '\0';
+ ::libvpx_test::MD5 md5_res;
+ md5_res.Add(&img);
+ const char *actual_md5 = md5_res.Get();
// Check md5 match.
ASSERT_STREQ(expected_md5, actual_md5)
--- /dev/null
+/*
+ Copyright (c) 2012 The WebM project authors. All Rights Reserved.
+
+ Use of this source code is governed by a BSD-style license
+ that can be found in the LICENSE file in the root of the source
+ tree. An additional intellectual property rights grant can be found
+ in the file PATENTS. All contributing project authors may
+ be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <string>
+#include "third_party/googletest/src/include/gtest/gtest.h"
+#include "test/codec_factory.h"
+#include "test/encode_test_driver.h"
+#include "test/i420_video_source.h"
+#include "test/util.h"
+#include "test/md5_helper.h"
+extern "C" {
+#include "vpx_mem/vpx_mem.h"
+}
+
+namespace {
+class TileIndependenceTest : public ::libvpx_test::EncoderTest,
+ public ::libvpx_test::CodecTestWithParam<int> {
+ protected:
+ TileIndependenceTest() : EncoderTest(GET_PARAM(0)), n_tiles_(GET_PARAM(1)),
+ md5_fw_order_(), md5_inv_order_() {
+ init_flags_ = VPX_CODEC_USE_PSNR;
+ vpx_codec_dec_cfg_t cfg;
+ cfg.w = 352;
+ cfg.h = 288;
+ cfg.threads = 1;
+ cfg.inv_tile_order = 0;
+ fw_dec_ = codec_->CreateDecoder(cfg, 0);
+ cfg.inv_tile_order = 1;
+ inv_dec_ = codec_->CreateDecoder(cfg, 0);
+ }
+
+ virtual ~TileIndependenceTest() {
+ delete fw_dec_;
+ delete inv_dec_;
+ }
+
+ virtual void SetUp() {
+ InitializeConfig();
+ }
+
+ virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
+ libvpx_test::Encoder *encoder) {
+ if (video->frame() == 1) {
+ encoder->Control(VP9E_SET_TILE_COLUMNS, n_tiles_);
+ }
+ }
+
+ void UpdateMD5(::libvpx_test::Decoder *dec, const vpx_codec_cx_pkt_t *pkt,
+ ::libvpx_test::MD5 *md5) {
+ dec->DecodeFrame((uint8_t *) pkt->data.frame.buf, pkt->data.frame.sz);
+ const vpx_image_t *img = dec->GetDxData().Next();
+ md5->Add(img);
+ }
+
+ virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
+ UpdateMD5(fw_dec_, pkt, &md5_fw_order_);
+ UpdateMD5(inv_dec_, pkt, &md5_inv_order_);
+ }
+
+ private:
+ int n_tiles_;
+ protected:
+ ::libvpx_test::MD5 md5_fw_order_, md5_inv_order_;
+ ::libvpx_test::Decoder *fw_dec_, *inv_dec_;
+};
+
+// run an encode with 2 or 4 tiles, and do the decode both in normal and
+// inverted tile ordering. Ensure that the MD5 of the output in both cases
+// is identical. If so, tiles are considered independent and the test passes.
+TEST_P(TileIndependenceTest, MD5Match) {
+ const vpx_rational timebase = { 33333333, 1000000000 };
+ cfg_.g_timebase = timebase;
+ cfg_.rc_target_bitrate = 500;
+ cfg_.g_lag_in_frames = 25;
+ cfg_.rc_end_usage = VPX_VBR;
+
+ libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
+ timebase.den, timebase.num, 0, 30);
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+
+ const char *md5_fw_str = md5_fw_order_.Get();
+ const char *md5_inv_str = md5_inv_order_.Get();
+
+ // could use ASSERT_EQ(!memcmp(.., .., 16) here, but this gives nicer
+ // output if it fails. Not sure if it's helpful since it's really just
+ // a MD5...
+ ASSERT_STREQ(md5_fw_str, md5_inv_str);
+}
+
+VP9_INSTANTIATE_TEST_CASE(TileIndependenceTest,
+ ::testing::Values(VP8_TWO_TILE_COLUMNS,
+ VP8_FOUR_TILE_COLUMNS));
+
+} // namespace
int up_available;
int left_available;
+ int right_available;
/* Y,U,V,Y2 */
ENTROPY_CONTEXT_PLANES *above_context;
extern const uint8_t vp9_mbsplit_offset[4][16];
-static int left_block_mv(const MODE_INFO *cur_mb, int b) {
+static int left_block_mv(const MACROBLOCKD *xd,
+ const MODE_INFO *cur_mb, int b) {
if (!(b & 3)) {
+ if (!xd->left_available)
+ return 0;
+
/* On L edge, get from MB to left of us */
--cur_mb;
return (cur_mb->bmi + b - 1)->as_mv.first.as_int;
}
-static int left_block_second_mv(const MODE_INFO *cur_mb, int b) {
+static int left_block_second_mv(const MACROBLOCKD *xd,
+ const MODE_INFO *cur_mb, int b) {
if (!(b & 3)) {
+ if (!xd->left_available)
+ return 0;
+
/* On L edge, get from MB to left of us */
--cur_mb;
// list of candidate reference vectors.
//
void vp9_find_mv_refs(
+ VP9_COMMON *cm,
MACROBLOCKD *xd,
MODE_INFO *here,
MODE_INFO *lf_here,
int (*mv_ref_search)[2];
int *ref_distance_weight;
int zero_seen = FALSE;
+ const int mb_col = (-xd->mb_to_left_edge) >> 7;
// Blank the reference vector lists and other local structures.
vpx_memset(mv_ref_list, 0, sizeof(int_mv) * MAX_MV_REF_CANDIDATES);
// We first scan for candidate vectors that match the current reference frame
// Look at nearest neigbours
for (i = 0; i < 2; ++i) {
- if (((mv_ref_search[i][0] << 7) >= xd->mb_to_left_edge) &&
+ const int mb_search_col = mb_col + mv_ref_search[i][0];
+
+ if ((mb_search_col >= cm->cur_tile_mb_col_start) &&
+ (mb_search_col < cm->cur_tile_mb_col_end) &&
((mv_ref_search[i][1] << 7) >= xd->mb_to_top_edge)) {
candidate_mi = here + mv_ref_search[i][0] +
// More distant neigbours
for (i = 2; (i < MVREF_NEIGHBOURS) &&
(refmv_count < (MAX_MV_REF_CANDIDATES - 1)); ++i) {
- if (((mv_ref_search[i][0] << 7) >= xd->mb_to_left_edge) &&
+ const int mb_search_col = mb_col + mv_ref_search[i][0];
+
+ if ((mb_search_col >= cm->cur_tile_mb_col_start) &&
+ (mb_search_col < cm->cur_tile_mb_col_end) &&
((mv_ref_search[i][1] << 7) >= xd->mb_to_top_edge)) {
candidate_mi = here + mv_ref_search[i][0] +
(mv_ref_search[i][1] * xd->mode_info_stride);
// Look first at spatial neighbours
if (refmv_count < (MAX_MV_REF_CANDIDATES - 1)) {
for (i = 0; i < MVREF_NEIGHBOURS; ++i) {
- if (((mv_ref_search[i][0] << 7) >= xd->mb_to_left_edge) &&
+ const int mb_search_col = mb_col + mv_ref_search[i][0];
+
+ if ((mb_search_col >= cm->cur_tile_mb_col_start) &&
+ (mb_search_col < cm->cur_tile_mb_col_end) &&
((mv_ref_search[i][1] << 7) >= xd->mb_to_top_edge)) {
candidate_mi = here + mv_ref_search[i][0] +
#ifndef VP9_COMMON_VP9_MVREF_COMMON_H_
#define VP9_COMMON_VP9_MVREF_COMMON_H_
-void vp9_find_mv_refs(MACROBLOCKD *xd,
+void vp9_find_mv_refs(VP9_COMMON *cm,
+ MACROBLOCKD *xd,
MODE_INFO *here,
MODE_INFO *lf_here,
MV_REFERENCE_FRAME ref_frame,
int arnr_strength;
int arnr_type;
+ int tile_columns;
+
struct vpx_fixed_buf two_pass_stats_in;
struct vpx_codec_pkt_list *output_pkt_list;
int error_resilient_mode;
int frame_parallel_decoding_mode;
+
+ int tile_columns;
+ int cur_tile_mb_col_start, cur_tile_mb_col_end, cur_tile_idx;
} VP9_COMMON;
static int get_free_fb(VP9_COMMON *cm) {
// The prediction flags in these dummy entries are initialised to 0.
switch (pred_id) {
case PRED_SEG_ID:
- pred_context = (m - 1)->mbmi.seg_id_predicted +
- (m - cm->mode_info_stride)->mbmi.seg_id_predicted;
+ pred_context = (m - cm->mode_info_stride)->mbmi.seg_id_predicted;
+ if (xd->left_available)
+ pred_context += (m - 1)->mbmi.seg_id_predicted;
break;
case PRED_REF:
- pred_context = (m - 1)->mbmi.ref_predicted +
- (m - cm->mode_info_stride)->mbmi.ref_predicted;
+ pred_context = (m - cm->mode_info_stride)->mbmi.ref_predicted;
+ if (xd->left_available)
+ pred_context += (m - 1)->mbmi.ref_predicted;
break;
case PRED_COMP:
break;
case PRED_MBSKIP:
- pred_context = (m - 1)->mbmi.mb_skip_coeff +
- (m - cm->mode_info_stride)->mbmi.mb_skip_coeff;
+ pred_context = (m - cm->mode_info_stride)->mbmi.mb_skip_coeff;
+ if (xd->left_available)
+ pred_context += (m - 1)->mbmi.mb_skip_coeff;
break;
case PRED_SWITCHABLE_INTERP:
{
- int left_in_image = (m - 1)->mbmi.mb_in_image;
+ int left_in_image = xd->left_available && (m - 1)->mbmi.mb_in_image;
int above_in_image = (m - cm->mode_info_stride)->mbmi.mb_in_image;
int left_mode = (m - 1)->mbmi.mode;
int above_mode = (m - cm->mode_info_stride)->mbmi.mode;
above_left = (m - 1 - cm->mode_info_stride)->mbmi.ref_frame;
// Are neighbours in image
- left_in_image = (m - 1)->mbmi.mb_in_image;
+ left_in_image = (m - 1)->mbmi.mb_in_image && xd->left_available;
above_in_image = (m - cm->mode_info_stride)->mbmi.mb_in_image;
- above_left_in_image = (m - 1 - cm->mode_info_stride)->mbmi.mb_in_image;
+ above_left_in_image = (m - 1 - cm->mode_info_stride)->mbmi.mb_in_image &&
+ xd->left_available;
// Adjust scores for candidate reference frames based on neigbours
if (frame_allowed[left] && left_in_image) {
void vp9_build_intra_predictors_internal(uint8_t *src, int src_stride,
uint8_t *ypred_ptr,
int y_stride, int mode, int bsize,
- int up_available, int left_available) {
-
- uint8_t *yabove_row = src - src_stride;
- uint8_t yleft_col[64];
- uint8_t ytop_left = yabove_row[-1];
+ int up_available, int left_available,
+ int right_available) {
int r, c, i;
+ uint8_t yleft_col[64], yabove_data[65], ytop_left;
+ uint8_t *yabove_row = yabove_data + 1;
+ /*
+ * 127 127 127 .. 127 127 127 127 127 127
+ * 129 A B .. Y Z
+ * 129 C D .. W X
+ * 129 E F .. U V
+ * 129 G H .. S T T T T T
+ * ..
+ */
- for (i = 0; i < bsize; i++) {
- yleft_col[i] = src[i * src_stride - 1];
+ if (left_available) {
+ for (i = 0; i < bsize; i++)
+ yleft_col[i] = src[i * src_stride - 1];
+ } else {
+ vpx_memset(yleft_col, 129, bsize);
+ }
+
+ if (up_available) {
+ uint8_t *yabove_ptr = src - src_stride;
+ vpx_memcpy(yabove_row, yabove_ptr, bsize);
+ if (left_available) {
+ ytop_left = yabove_ptr[-1];
+ } else {
+ ytop_left = 127;
+ }
+ } else {
+ vpx_memset(yabove_row, 127, bsize);
+ ytop_left = 127;
}
+ yabove_row[-1] = ytop_left;
/* for Y */
switch (mode) {
xd->dst.y_buffer, xd->dst.y_stride,
intrapredictor, 16,
xd->mode_info_context->mbmi.interintra_mode, 16,
- xd->up_available, xd->left_available);
+ xd->up_available, xd->left_available, xd->right_available);
combine_interintra(xd->mode_info_context->mbmi.interintra_mode,
ypred, ystride, intrapredictor, 16, 16);
}
xd->dst.u_buffer, xd->dst.uv_stride,
uintrapredictor, 8,
xd->mode_info_context->mbmi.interintra_uv_mode, 8,
- xd->up_available, xd->left_available);
+ xd->up_available, xd->left_available, xd->right_available);
vp9_build_intra_predictors_internal(
xd->dst.v_buffer, xd->dst.uv_stride,
vintrapredictor, 8,
xd->mode_info_context->mbmi.interintra_uv_mode, 8,
- xd->up_available, xd->left_available);
+ xd->up_available, xd->left_available, xd->right_available);
combine_interintra(xd->mode_info_context->mbmi.interintra_uv_mode,
upred, uvstride, uintrapredictor, 8, 8);
combine_interintra(xd->mode_info_context->mbmi.interintra_uv_mode,
xd->dst.y_buffer, xd->dst.y_stride,
intrapredictor, 32,
xd->mode_info_context->mbmi.interintra_mode, 32,
- xd->up_available, xd->left_available);
+ xd->up_available, xd->left_available, xd->right_available);
combine_interintra(xd->mode_info_context->mbmi.interintra_mode,
ypred, ystride, intrapredictor, 32, 32);
}
xd->dst.u_buffer, xd->dst.uv_stride,
uintrapredictor, 16,
xd->mode_info_context->mbmi.interintra_uv_mode, 16,
- xd->up_available, xd->left_available);
+ xd->up_available, xd->left_available, xd->right_available);
vp9_build_intra_predictors_internal(
xd->dst.v_buffer, xd->dst.uv_stride,
vintrapredictor, 16,
xd->mode_info_context->mbmi.interintra_uv_mode, 16,
- xd->up_available, xd->left_available);
+ xd->up_available, xd->left_available, xd->right_available);
combine_interintra(xd->mode_info_context->mbmi.interintra_uv_mode,
upred, uvstride, uintrapredictor, 16, 16);
combine_interintra(xd->mode_info_context->mbmi.interintra_uv_mode,
const int mode = xd->mode_info_context->mbmi.interintra_mode;
vp9_build_intra_predictors_internal(xd->dst.y_buffer, xd->dst.y_stride,
intrapredictor, 64, mode, 64,
- xd->up_available, xd->left_available);
+ xd->up_available, xd->left_available,
+ xd->right_available);
combine_interintra(xd->mode_info_context->mbmi.interintra_mode,
ypred, ystride, intrapredictor, 64, 64);
}
const int mode = xd->mode_info_context->mbmi.interintra_uv_mode;
vp9_build_intra_predictors_internal(xd->dst.u_buffer, xd->dst.uv_stride,
uintrapredictor, 32, mode, 32,
- xd->up_available, xd->left_available);
+ xd->up_available, xd->left_available,
+ xd->right_available);
vp9_build_intra_predictors_internal(xd->dst.v_buffer, xd->dst.uv_stride,
vintrapredictor, 32, mode, 32,
- xd->up_available, xd->left_available);
+ xd->up_available, xd->left_available,
+ xd->right_available);
combine_interintra(xd->mode_info_context->mbmi.interintra_uv_mode,
upred, uvstride, uintrapredictor, 32, 32);
combine_interintra(xd->mode_info_context->mbmi.interintra_uv_mode,
vp9_build_intra_predictors_internal(xd->dst.y_buffer, xd->dst.y_stride,
xd->predictor, 16,
xd->mode_info_context->mbmi.mode, 16,
- xd->up_available, xd->left_available);
+ xd->up_available, xd->left_available,
+ xd->right_available);
}
void vp9_build_intra_predictors_mby_s(MACROBLOCKD *xd) {
vp9_build_intra_predictors_internal(xd->dst.y_buffer, xd->dst.y_stride,
xd->dst.y_buffer, xd->dst.y_stride,
xd->mode_info_context->mbmi.mode, 16,
- xd->up_available, xd->left_available);
+ xd->up_available, xd->left_available,
+ xd->right_available);
}
void vp9_build_intra_predictors_sby_s(MACROBLOCKD *xd) {
vp9_build_intra_predictors_internal(xd->dst.y_buffer, xd->dst.y_stride,
xd->dst.y_buffer, xd->dst.y_stride,
xd->mode_info_context->mbmi.mode, 32,
- xd->up_available, xd->left_available);
+ xd->up_available, xd->left_available,
+ xd->right_available);
}
void vp9_build_intra_predictors_sb64y_s(MACROBLOCKD *xd) {
vp9_build_intra_predictors_internal(xd->dst.y_buffer, xd->dst.y_stride,
xd->dst.y_buffer, xd->dst.y_stride,
xd->mode_info_context->mbmi.mode, 64,
- xd->up_available, xd->left_available);
+ xd->up_available, xd->left_available,
+ xd->right_available);
}
void vp9_build_intra_predictors_mbuv_internal(MACROBLOCKD *xd,
int mode, int bsize) {
vp9_build_intra_predictors_internal(xd->dst.u_buffer, xd->dst.uv_stride,
upred_ptr, uv_stride, mode, bsize,
- xd->up_available, xd->left_available);
+ xd->up_available, xd->left_available,
+ xd->right_available);
vp9_build_intra_predictors_internal(xd->dst.v_buffer, xd->dst.uv_stride,
vpred_ptr, uv_stride, mode, bsize,
- xd->up_available, xd->left_available);
+ xd->up_available, xd->left_available,
+ xd->right_available);
}
void vp9_build_intra_predictors_mbuv(MACROBLOCKD *xd) {
32);
}
-void vp9_intra8x8_predict(BLOCKD *xd,
+void vp9_intra8x8_predict(MACROBLOCKD *xd,
+ BLOCKD *b,
int mode,
uint8_t *predictor) {
- vp9_build_intra_predictors_internal(*(xd->base_dst) + xd->dst,
- xd->dst_stride, predictor, 16,
- mode, 8, 1, 1);
+ const int block4x4_idx = (b - xd->block);
+ const int block_idx = (block4x4_idx >> 2) | !!(block4x4_idx & 2);
+ const int have_top = (block_idx >> 1) || xd->up_available;
+ const int have_left = (block_idx & 1) || xd->left_available;
+ const int have_right = !(block_idx & 1) || xd->right_available;
+
+ vp9_build_intra_predictors_internal(*(b->base_dst) + b->dst,
+ b->dst_stride, predictor, 16,
+ mode, 8, have_top, have_left,
+ have_right);
}
-void vp9_intra_uv4x4_predict(BLOCKD *xd,
+void vp9_intra_uv4x4_predict(MACROBLOCKD *xd,
+ BLOCKD *b,
int mode,
uint8_t *predictor) {
- vp9_build_intra_predictors_internal(*(xd->base_dst) + xd->dst,
- xd->dst_stride, predictor, 8,
- mode, 4, 1, 1);
+ const int block_idx = (b - xd->block) & 3;
+ const int have_top = (block_idx >> 1) || xd->up_available;
+ const int have_left = (block_idx & 1) || xd->left_available;
+ const int have_right = !(block_idx & 1) || xd->right_available;
+
+ vp9_build_intra_predictors_internal(*(b->base_dst) + b->dst,
+ b->dst_stride, predictor, 8,
+ mode, 4, have_top, have_left,
+ have_right);
}
/* TODO: try different ways of use Y-UV mode correlation
}
#endif
-void vp9_intra4x4_predict(BLOCKD *x,
+void vp9_intra4x4_predict(MACROBLOCKD *xd,
+ BLOCKD *x,
int b_mode,
uint8_t *predictor) {
int i, r, c;
+ const int block_idx = x - xd->block;
+ const int have_top = (block_idx >> 2) || xd->up_available;
+ const int have_left = (block_idx & 3) || xd->left_available;
+ const int have_right = (block_idx & 3) != 3 || xd->right_available;
+ uint8_t left[4], above[8], top_left;
+ /*
+ * 127 127 127 .. 127 127 127 127 127 127
+ * 129 A B .. Y Z
+ * 129 C D .. W X
+ * 129 E F .. U V
+ * 129 G H .. S T T T T T
+ * ..
+ */
+
+ if (have_left) {
+ uint8_t *left_ptr = *(x->base_dst) + x->dst - 1;
+ const int stride = x->dst_stride;
+
+ left[0] = left_ptr[0 * stride];
+ left[1] = left_ptr[1 * stride];
+ left[2] = left_ptr[2 * stride];
+ left[3] = left_ptr[3 * stride];
+ } else {
+ left[0] = left[1] = left[2] = left[3] = 129;
+ }
+
+ if (have_top) {
+ uint8_t *above_ptr = *(x->base_dst) + x->dst - x->dst_stride;
- uint8_t *above = *(x->base_dst) + x->dst - x->dst_stride;
- uint8_t left[4];
- uint8_t top_left = above[-1];
+ if (have_left) {
+ top_left = above_ptr[-1];
+ } else {
+ top_left = 127;
+ }
- left[0] = (*(x->base_dst))[x->dst - 1];
- left[1] = (*(x->base_dst))[x->dst - 1 + x->dst_stride];
- left[2] = (*(x->base_dst))[x->dst - 1 + 2 * x->dst_stride];
- left[3] = (*(x->base_dst))[x->dst - 1 + 3 * x->dst_stride];
+ above[0] = above_ptr[0];
+ above[1] = above_ptr[1];
+ above[2] = above_ptr[2];
+ above[3] = above_ptr[3];
+ if (((block_idx & 3) != 3) ||
+ (have_right && block_idx == 3 &&
+ ((xd->mb_index != 3 && xd->sb_index != 3) ||
+ ((xd->mb_index & 1) == 0 && xd->sb_index == 3)))) {
+ above[4] = above_ptr[4];
+ above[5] = above_ptr[5];
+ above[6] = above_ptr[6];
+ above[7] = above_ptr[7];
+ } else if (have_right) {
+ uint8_t *above_right = above_ptr + 4;
+
+ if (xd->sb_index == 3 && (xd->mb_index & 1))
+ above_right -= 32 * x->dst_stride;
+ if (xd->mb_index == 3)
+ above_right -= 16 * x->dst_stride;
+ above_right -= (block_idx & ~3) * x->dst_stride;
+
+ /* use a more distant above-right (from closest available top-right
+ * corner), but with a "localized DC" (similar'ish to TM-pred):
+ *
+ * A B C D E F G H
+ * I J K L
+ * M N O P
+ * Q R S T
+ * U V W X x1 x2 x3 x4
+ *
+ * Where:
+ * x1 = clip_pixel(E + X - D)
+ * x2 = clip_pixel(F + X - D)
+ * x3 = clip_pixel(G + X - D)
+ * x4 = clip_pixel(H + X - D)
+ *
+ * This is applied anytime when we use a "distant" above-right edge
+ * that is not immediately top-right to the block that we're going
+ * to do intra prediction for.
+ */
+ above[4] = clip_pixel(above_right[0] + above_ptr[3] - above_right[-1]);
+ above[5] = clip_pixel(above_right[1] + above_ptr[3] - above_right[-1]);
+ above[6] = clip_pixel(above_right[2] + above_ptr[3] - above_right[-1]);
+ above[7] = clip_pixel(above_right[3] + above_ptr[3] - above_right[-1]);
+ } else {
+ // extend edge
+ above[4] = above[5] = above[6] = above[7] = above[3];
+ }
+ } else {
+ above[0] = above[1] = above[2] = above[3] = 127;
+ above[4] = above[5] = above[6] = above[7] = 127;
+ top_left = 127;
+ }
#if CONFIG_NEWBINTRAMODES
if (b_mode == B_CONTEXT_PRED)
#endif
}
}
-
-/* copy 4 bytes from the above right down so that the 4x4 prediction modes using pixels above and
- * to the right prediction have filled in pixels to use.
- */
-void vp9_intra_prediction_down_copy(MACROBLOCKD *xd) {
- int extend_edge = xd->mb_to_right_edge == 0 && xd->mb_index < 2;
- uint8_t *above_right = *(xd->block[0].base_dst) + xd->block[0].dst -
- xd->block[0].dst_stride + 16;
- uint32_t *dst_ptr0 = (uint32_t *)above_right;
- uint32_t *dst_ptr1 =
- (uint32_t *)(above_right + 4 * xd->block[0].dst_stride);
- uint32_t *dst_ptr2 =
- (uint32_t *)(above_right + 8 * xd->block[0].dst_stride);
- uint32_t *dst_ptr3 =
- (uint32_t *)(above_right + 12 * xd->block[0].dst_stride);
-
- uint32_t *src_ptr = (uint32_t *) above_right;
-
- if ((xd->sb_index >= 2 && xd->mb_to_right_edge == 0) ||
- (xd->sb_index == 3 && xd->mb_index & 1))
- src_ptr = (uint32_t *) (((uint8_t *) src_ptr) - 32 *
- xd->block[0].dst_stride);
- if (xd->mb_index == 3 ||
- (xd->mb_to_right_edge == 0 && xd->mb_index == 2))
- src_ptr = (uint32_t *) (((uint8_t *) src_ptr) - 16 *
- xd->block[0].dst_stride);
-
- if (extend_edge) {
- *src_ptr = ((uint8_t *) src_ptr)[-1] * 0x01010101U;
- }
-
- *dst_ptr0 = *src_ptr;
- *dst_ptr1 = *src_ptr;
- *dst_ptr2 = *src_ptr;
- *dst_ptr3 = *src_ptr;
-}
+++ /dev/null
-/*
- * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-
-#ifndef VP9_COMMON_VP9_RECONINTRA4X4_H_
-#define VP9_COMMON_VP9_RECONINTRA4X4_H_
-
-extern void vp9_intra_prediction_down_copy(MACROBLOCKD *xd);
-
-#endif // VP9_COMMON_VP9_RECONINTRA4X4_H_
prototype void vp9_build_intra_predictors_sb64uv_s "struct macroblockd *x"
specialize vp9_build_intra_predictors_sb64uv_s;
-prototype void vp9_intra4x4_predict "struct blockd *x, int b_mode, uint8_t *predictor"
+prototype void vp9_intra4x4_predict "struct macroblockd *xd, struct blockd *x, int b_mode, uint8_t *predictor"
specialize vp9_intra4x4_predict;
-prototype void vp9_intra8x8_predict "struct blockd *x, int b_mode, uint8_t *predictor"
+prototype void vp9_intra8x8_predict "struct macroblockd *xd, struct blockd *x, int b_mode, uint8_t *predictor"
specialize vp9_intra8x8_predict;
-prototype void vp9_intra_uv4x4_predict "struct blockd *x, int b_mode, uint8_t *predictor"
+prototype void vp9_intra_uv4x4_predict "struct macroblockd *xd, struct blockd *x, int b_mode, uint8_t *predictor"
specialize vp9_intra_uv4x4_predict;
#
int mb_col,
BOOL_DECODER* const bc) {
VP9_COMMON *const cm = &pbi->common;
+ MACROBLOCKD *const xd = &pbi->mb;
const int mis = pbi->common.mode_info_stride;
int map_index = mb_row * pbi->common.mb_cols + mb_col;
MB_PREDICTION_MODE y_mode;
int i = 0;
do {
const B_PREDICTION_MODE A = above_block_mode(m, i, mis);
- const B_PREDICTION_MODE L = left_block_mode(m, i);
+ const B_PREDICTION_MODE L = (xd->left_available || (i & 3)) ?
+ left_block_mode(m, i) : B_DC_PRED;
m->bmi[i].as_mode.first =
(B_PREDICTION_MODE) read_kf_bmode(
#endif
// if (cm->current_video_frame == 1 && mb_row == 4 && mb_col == 5)
// printf("Dello\n");
- vp9_find_mv_refs(xd, mi, cm->error_resilient_mode ? 0 : prev_mi,
+ vp9_find_mv_refs(cm, xd, mi, cm->error_resilient_mode ? 0 : prev_mi,
ref_frame, mbmi->ref_mvs[ref_frame],
cm->ref_frame_sign_bias);
xd->second_pre.v_buffer =
cm->yv12_fb[second_ref_fb_idx].v_buffer + recon_uvoffset;
- vp9_find_mv_refs(xd, mi, cm->error_resilient_mode ? 0 : prev_mi,
+ vp9_find_mv_refs(cm, xd, mi, cm->error_resilient_mode ? 0 : prev_mi,
mbmi->second_ref_frame,
mbmi->ref_mvs[mbmi->second_ref_frame],
cm->ref_frame_sign_bias);
k = vp9_mbsplit_offset[s][j];
- leftmv.as_int = left_block_mv(mi, k);
+ leftmv.as_int = left_block_mv(xd, mi, k);
abovemv.as_int = above_block_mv(mi, k, mis);
second_leftmv.as_int = 0;
second_abovemv.as_int = 0;
if (mbmi->second_ref_frame > 0) {
- second_leftmv.as_int = left_block_second_mv(mi, k);
+ second_leftmv.as_int = left_block_second_mv(xd, mi, k);
second_abovemv.as_int = above_block_second_mv(mi, k, mis);
}
mv_contz = vp9_mv_cont(&leftmv, &abovemv);
#include "vp9/common/vp9_common.h"
#include "vp9/common/vp9_header.h"
#include "vp9/common/vp9_reconintra.h"
-#include "vp9/common/vp9_reconintra4x4.h"
#include "vp9/common/vp9_reconinter.h"
#include "vp9/common/vp9_entropy.h"
#include "vp9/decoder/vp9_decodframe.h"
BLOCKD *b = &xd->block[ib];
if (xd->mode_info_context->mbmi.mode == I8X8_PRED) {
int i8x8mode = b->bmi.as_mode.first;
- vp9_intra8x8_predict(b, i8x8mode, b->predictor);
+ vp9_intra8x8_predict(xd, b, i8x8mode, b->predictor);
}
tx_type = get_tx_type_8x8(xd, &xd->block[ib]);
if (tx_type != DCT_DCT) {
BLOCKD *b = &xd->block[ib];
int i8x8mode = b->bmi.as_mode.first;
b = &xd->block[16 + i];
- vp9_intra_uv4x4_predict(&xd->block[16 + i], i8x8mode, b->predictor);
+ vp9_intra_uv4x4_predict(xd, &xd->block[16 + i], i8x8mode, b->predictor);
pbi->idct_add(b->qcoeff, b->dequant, b->predictor,
*(b->base_dst) + b->dst, 8, b->dst_stride);
b = &xd->block[20 + i];
- vp9_intra_uv4x4_predict(&xd->block[20 + i], i8x8mode, b->predictor);
+ vp9_intra_uv4x4_predict(xd, &xd->block[20 + i], i8x8mode, b->predictor);
pbi->idct_add(b->qcoeff, b->dequant, b->predictor,
*(b->base_dst) + b->dst, 8, b->dst_stride);
}
BLOCKD *b;
b = &xd->block[ib];
i8x8mode = b->bmi.as_mode.first;
- vp9_intra8x8_predict(b, i8x8mode, b->predictor);
+ vp9_intra8x8_predict(xd, b, i8x8mode, b->predictor);
for (j = 0; j < 4; j++) {
b = &xd->block[ib + iblock[j]];
tx_type = get_tx_type_4x4(xd, b);
}
}
b = &xd->block[16 + i];
- vp9_intra_uv4x4_predict(b, i8x8mode, b->predictor);
+ vp9_intra_uv4x4_predict(xd, b, i8x8mode, b->predictor);
pbi->idct_add(b->qcoeff, b->dequant, b->predictor,
*(b->base_dst) + b->dst, 8, b->dst_stride);
b = &xd->block[20 + i];
- vp9_intra_uv4x4_predict(b, i8x8mode, b->predictor);
+ vp9_intra_uv4x4_predict(xd, b, i8x8mode, b->predictor);
pbi->idct_add(b->qcoeff, b->dequant, b->predictor,
*(b->base_dst) + b->dst, 8, b->dst_stride);
}
if (!xd->mode_info_context->mbmi.mb_skip_coeff)
eobtotal += vp9_decode_coefs_4x4(pbi, xd, bc, PLANE_TYPE_Y_WITH_DC, i);
- vp9_intra4x4_predict(b, b_mode, b->predictor);
+ vp9_intra4x4_predict(xd, b, b_mode, b->predictor);
tx_type = get_tx_type_4x4(xd, b);
if (tx_type != DCT_DCT) {
vp9_ht_dequant_idct_add_c(tx_type, b->qcoeff,
xd->mb_to_bottom_edge = ((cm->mb_rows - block_size - mb_row) * 16) << 3;
xd->mb_to_right_edge = ((cm->mb_cols - block_size - mb_col) * 16) << 3;
- xd->up_available = (mb_row != 0);
- xd->left_available = (mb_col != 0);
+ xd->up_available = (mb_row != 0);
+ xd->left_available = (mb_col > cm->cur_tile_mb_col_start);
+ xd->right_available = (mb_col + block_size < cm->cur_tile_mb_col_end);
xd->dst.y_buffer = cm->yv12_fb[dst_fb_idx].y_buffer + recon_yoffset;
xd->dst.u_buffer = cm->yv12_fb[dst_fb_idx].u_buffer + recon_uvoffset;
// For a SB there are 2 left contexts, each pertaining to a MB row within
vpx_memset(pc->left_context, 0, sizeof(pc->left_context));
- for (mb_col = 0; mb_col < pc->mb_cols; mb_col += 4) {
+ for (mb_col = pc->cur_tile_mb_col_start;
+ mb_col < pc->cur_tile_mb_col_end; mb_col += 4) {
if (vp9_read(bc, pc->sb64_coded)) {
set_offsets(pbi, 64, mb_row, mb_col);
vp9_decode_mb_mode_mv(pbi, xd, mb_row, mb_col, bc);
vp9_decode_mb_mode_mv(pbi, xd, mb_row + y_idx, mb_col + x_idx, bc);
update_blockd_bmi(xd);
set_refs(pbi, 16, mb_row + y_idx, mb_col + x_idx);
- vp9_intra_prediction_down_copy(xd);
- decode_macroblock(pbi, xd, mb_row, mb_col, bc);
+ decode_macroblock(pbi, xd, mb_row + y_idx, mb_col + x_idx, bc);
/* check if the boolean decoder has suffered an error */
xd->corrupted |= bool_error(bc);
// Dummy read for now
vp9_read_literal(&header_bc, 2);
- setup_token_decoder(pbi, data + first_partition_length_in_bytes,
- &residual_bc);
-
/* Read the default quantizers. */
{
int Q, q_update;
vp9_decode_mode_mvs_init(pbi, &header_bc);
- vpx_memset(pc->above_context, 0, sizeof(ENTROPY_CONTEXT_PLANES) * pc->mb_cols);
+ /* tile info */
+ {
+ int log2_tile_cols;
+ const unsigned char *data_ptr = data + first_partition_length_in_bytes;
+ int tile, mb_start, mb_end;
+
+ log2_tile_cols = vp9_read_bit(&header_bc);
+ if (log2_tile_cols) {
+ log2_tile_cols += vp9_read_bit(&header_bc);
+ }
+ pc->tile_columns = 1 << log2_tile_cols;
- /* Decode a row of superblocks */
- for (mb_row = 0; mb_row < pc->mb_rows; mb_row += 4) {
- decode_sb_row(pbi, pc, mb_row, xd, &residual_bc);
+ vpx_memset(pc->above_context, 0,
+ sizeof(ENTROPY_CONTEXT_PLANES) * pc->mb_cols);
+
+ if (pbi->oxcf.inv_tile_order) {
+ const unsigned char *data_ptr2[4];
+ BOOL_DECODER UNINITIALIZED_IS_SAFE(bc_bak);
+
+ data_ptr2[0] = data_ptr;
+ for (tile = 1; tile < pc->tile_columns; tile++) {
+ int size = data_ptr2[tile - 1][0] + (data_ptr2[tile - 1][1] << 8) +
+ (data_ptr2[tile - 1][2] << 16) + (data_ptr2[tile - 1][3] << 24);
+ data_ptr2[tile - 1] += 4;
+ data_ptr2[tile] = data_ptr2[tile - 1] + size;
+ }
+ for (mb_end = pc->mb_cols, tile = pc->tile_columns - 1;
+ tile >= 0; tile--) {
+ // calculate end of tile column
+ const int sb_cols = (pc->mb_cols + 3) >> 2;
+ const int sb_start = (sb_cols * tile) >> log2_tile_cols;
+ mb_start = ((sb_start << 2) > pc->mb_cols) ?
+ pc->mb_cols : (sb_start << 2);
+
+ pc->cur_tile_idx = tile;
+ pc->cur_tile_mb_col_start = mb_start;
+ pc->cur_tile_mb_col_end = mb_end;
+
+ setup_token_decoder(pbi, data_ptr2[tile], &residual_bc);
+
+ /* Decode a row of superblocks */
+ for (mb_row = 0; mb_row < pc->mb_rows; mb_row += 4) {
+ decode_sb_row(pbi, pc, mb_row, xd, &residual_bc);
+ }
+ mb_end = mb_start;
+ if (tile == pc->tile_columns - 1)
+ bc_bak = residual_bc;
+ }
+ residual_bc = bc_bak;
+ } else {
+ for (mb_start = 0, tile = 0; tile < pc->tile_columns; tile++) {
+ // calculate end of tile column
+ const int sb_cols = (pc->mb_cols + 3) >> 2;
+ const int sb_end = (sb_cols * (tile + 1)) >> log2_tile_cols;
+ mb_end = ((sb_end << 2) > pc->mb_cols) ? pc->mb_cols : (sb_end << 2);
+
+ pc->cur_tile_idx = tile;
+ pc->cur_tile_mb_col_start = mb_start;
+ pc->cur_tile_mb_col_end = mb_end;
+
+ if (tile < pc->tile_columns - 1)
+ setup_token_decoder(pbi, data_ptr + 4, &residual_bc);
+ else
+ setup_token_decoder(pbi, data_ptr, &residual_bc);
+
+ /* Decode a row of superblocks */
+ for (mb_row = 0; mb_row < pc->mb_rows; mb_row += 4) {
+ decode_sb_row(pbi, pc, mb_row, xd, &residual_bc);
+ }
+ mb_start = mb_end;
+ if (tile < pc->tile_columns - 1) {
+ int size = data_ptr[0] + (data_ptr[1] << 8) + (data_ptr[2] << 16) +
+ (data_ptr[3] << 24);
+ data_ptr += 4 + size;
+ }
+ }
+ }
}
corrupt_tokens |= xd->corrupted;
int Version;
int postprocess;
int max_threads;
+ int inv_tile_order;
int input_partition;
} VP9D_CONFIG;
typedef enum {
vp9_initialize_dec();
vp9_create_common(&pbi->common);
+ pbi->oxcf = *oxcf;
pbi->common.current_video_frame = 0;
pbi->ready_for_new_data = 1;
* at this point, but if it becomes so, [0] may not always be the correct
* thing to do here.
*/
- cm->yv12_fb[cm->active_ref_idx[0]].corrupted = 1;
+ if (cm->active_ref_idx[0] != INT_MAX)
+ cm->yv12_fb[cm->active_ref_idx[0]].corrupted = 1;
}
cm->new_fb_idx = get_free_fb(cm);
* at this point, but if it becomes so, [0] may not always be the correct
* thing to do here.
*/
- cm->yv12_fb[cm->active_ref_idx[0]].corrupted = 1;
+ if (cm->active_ref_idx[0] != INT_MAX)
+ cm->yv12_fb[cm->active_ref_idx[0]].corrupted = 1;
if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0)
cm->fb_idx_ref_cnt[cm->new_fb_idx]--;
#else
while (j != L[++k]);
#endif
- leftmv.as_int = left_block_mv(m, k);
+ leftmv.as_int = left_block_mv(xd, m, k);
abovemv.as_int = above_block_mv(m, k, mis);
mv_contz = vp9_mv_cont(&leftmv, &abovemv);
int i = 0;
do {
const B_PREDICTION_MODE A = above_block_mode(m, i, mis);
- const B_PREDICTION_MODE L = left_block_mode(m, i);
+ const B_PREDICTION_MODE L = (xd->left_available || (i & 3)) ?
+ left_block_mode(m, i) : B_DC_PRED;
const int bm = m->bmi[i].as_mode.first;
#ifdef ENTROPY_STATS
MACROBLOCKD *const xd = &cpi->mb.e_mbd;
xd->mode_info_context = m;
+ xd->left_available = mb_col > c->cur_tile_mb_col_start;
+ xd->right_available =
+ (mb_col + (1 << m->mbmi.sb_type)) < c->cur_tile_mb_col_end;
+ xd->up_available = mb_row > 0;
if (c->frame_type == KEY_FRAME) {
write_mb_modes_kf(cpi, m, bc,
c->mb_rows - mb_row, c->mb_cols - mb_col);
pack_mb_tokens(bc, tok, tok_end);
}
-static void write_modes(VP9_COMP *cpi, vp9_writer* const bc) {
+static void write_modes(VP9_COMP *cpi, vp9_writer* const bc,
+ TOKENEXTRA **tok) {
VP9_COMMON *const c = &cpi->common;
const int mis = c->mode_info_stride;
- MODE_INFO *m, *m_ptr = c->mi;
+ MODE_INFO *m, *m_ptr = c->mi + c->cur_tile_mb_col_start;
int i, mb_row, mb_col;
- TOKENEXTRA *tok = cpi->tok;
- TOKENEXTRA *tok_end = tok + cpi->tok_count;
+ TOKENEXTRA *tok_end = *tok + cpi->tok_count;
for (mb_row = 0; mb_row < c->mb_rows; mb_row += 4, m_ptr += 4 * mis) {
m = m_ptr;
- for (mb_col = 0; mb_col < c->mb_cols; mb_col += 4, m += 4) {
+ for (mb_col = c->cur_tile_mb_col_start;
+ mb_col < c->cur_tile_mb_col_end; mb_col += 4, m += 4) {
vp9_write(bc, m->mbmi.sb_type == BLOCK_SIZE_SB64X64, c->sb64_coded);
if (m->mbmi.sb_type == BLOCK_SIZE_SB64X64) {
- write_modes_b(cpi, m, bc, &tok, tok_end, mb_row, mb_col);
+ write_modes_b(cpi, m, bc, tok, tok_end, mb_row, mb_col);
} else {
int j;
vp9_write(bc, sb_m->mbmi.sb_type, c->sb32_coded);
if (sb_m->mbmi.sb_type) {
assert(sb_m->mbmi.sb_type == BLOCK_SIZE_SB32X32);
- write_modes_b(cpi, sb_m, bc, &tok, tok_end,
+ write_modes_b(cpi, sb_m, bc, tok, tok_end,
mb_row + y_idx_sb, mb_col + x_idx_sb);
} else {
// Process the 4 MBs in the order:
}
assert(mb_m->mbmi.sb_type == BLOCK_SIZE_MB16X16);
- write_modes_b(cpi, mb_m, bc, &tok, tok_end,
+ write_modes_b(cpi, mb_m, bc, tok, tok_end,
mb_row + y_idx, mb_col + x_idx);
}
}
vp9_write_nmv_probs(cpi, xd->allow_high_precision_mv, &header_bc);
}
+ /* tiling */
+ vp9_write(&header_bc, pc->tile_columns > 1, 128);
+ if (pc->tile_columns > 1) {
+ vp9_write(&header_bc, pc->tile_columns > 2, 128);
+ }
+
vp9_stop_encode(&header_bc);
oh.first_partition_length_in_bytes = header_bc.pos;
}
*size = VP9_HEADER_SIZE + extra_bytes_packed + header_bc.pos;
- vp9_start_encode(&residual_bc, cx_data + header_bc.pos);
if (pc->frame_type == KEY_FRAME) {
decide_kf_ymode_entropy(cpi);
- write_modes(cpi, &residual_bc);
} else {
/* This is not required if the counts in cpi are consistent with the
* final packing pass */
// if (!cpi->dummy_packing) vp9_zero(cpi->NMVcount);
- write_modes(cpi, &residual_bc);
}
- vp9_stop_encode(&residual_bc);
+ {
+ int mb_start = 0, tile;
+ int total_size = 0;
+ unsigned char *data_ptr = cx_data + header_bc.pos;
+ TOKENEXTRA *tok = cpi->tok;
+
+ for (tile = 0; tile < pc->tile_columns; tile++) {
+ // calculate end of tile column
+ const int sb_cols = (pc->mb_cols + 3) >> 2;
+ const int sb_end = (sb_cols * (tile + 1)) >> cpi->oxcf.tile_columns;
+ const int mb_end = ((sb_end << 2) > pc->mb_cols) ?
+ pc->mb_cols : (sb_end << 2);
+
+ pc->cur_tile_idx = tile;
+ pc->cur_tile_mb_col_start = mb_start;
+ pc->cur_tile_mb_col_end = mb_end;
+
+ if (tile < pc->tile_columns - 1)
+ vp9_start_encode(&residual_bc, data_ptr + total_size + 4);
+ else
+ vp9_start_encode(&residual_bc, data_ptr + total_size);
+ write_modes(cpi, &residual_bc, &tok);
+ vp9_stop_encode(&residual_bc);
+ if (tile < pc->tile_columns - 1) {
+ /* size of this tile */
+ data_ptr[total_size + 0] = residual_bc.pos;
+ data_ptr[total_size + 1] = residual_bc.pos >> 8;
+ data_ptr[total_size + 2] = residual_bc.pos >> 16;
+ data_ptr[total_size + 3] = residual_bc.pos >> 24;
+ total_size += 4;
+ }
- *size += residual_bc.pos;
+ mb_start = mb_end;
+ total_size += residual_bc.pos;
+ }
+
+ *size += total_size;
+ }
+
+ if (pc->frame_type != KEY_FRAME && !cpi->common.error_resilient_mode) {
+ vp9_adapt_mode_context(&cpi->common);
+ }
}
#ifdef ENTROPY_STATS
#include "vp9/common/vp9_quant_common.h"
#include "vp9/encoder/vp9_segmentation.h"
#include "vp9/common/vp9_setupintrarecon.h"
-#include "vp9/common/vp9_reconintra4x4.h"
#include "vp9/encoder/vp9_encodeintra.h"
#include "vp9/common/vp9_reconinter.h"
#include "vp9/common/vp9_invtrans.h"
xd->mb_to_right_edge = ((cm->mb_cols - block_size - mb_col) * 16) << 3;
// Are edges available for intra prediction?
- xd->up_available = (mb_row != 0);
- xd->left_available = (mb_col != 0);
+ xd->up_available = (mb_row != 0);
+ xd->left_available = (mb_col > cm->cur_tile_mb_col_start);
+ xd->right_available = (mb_col + block_size < cm->cur_tile_mb_col_end);
/* Reference buffer offsets */
*ref_yoffset = (mb_row * ref_y_stride * 16) + (mb_col * 16);
const int x = mb_col & ~3;
const int p16 = ((mb_row & 1) << 1) + (mb_col & 1);
const int p32 = ((mb_row & 2) << 2) + ((mb_col & 2) << 1);
+ const int tile_progress = cm->cur_tile_mb_col_start * cm->mb_rows;
+ const int mb_cols = cm->cur_tile_mb_col_end - cm->cur_tile_mb_col_start;
cpi->seg0_progress =
- ((y * cm->mb_cols + x * 4 + p32 + p16) << 16) / cm->MBs;
+ ((y * mb_cols + x * 4 + p32 + p16 + tile_progress) << 16) / cm->MBs;
}
} else {
mbmi->segment_id = 0;
mbmi = &xd->mode_info_context->mbmi;
mbmi->sb_type = BLOCK_SIZE_MB16X16;
- vp9_intra_prediction_down_copy(xd);
-
// Find best coding mode & reconstruct the MB so it is available
// as a predictor for MBs that follow in the SB
if (cm->frame_type == KEY_FRAME) {
if (cpi->oxcf.tuning == VP8_TUNE_SSIM)
vp9_activity_masking(cpi, x);
- vp9_intra_prediction_down_copy(xd);
-
encode_macroblock(cpi, tp, recon_yoffset, recon_uvoffset,
output_enabled, mb_row + y_idx, mb_col + x_idx);
if (output_enabled)
MACROBLOCK *const x = &cpi->mb;
MACROBLOCKD *const xd = &x->e_mbd;
int mb_col;
- int mb_cols = cm->mb_cols;
// Initialize the left context for the new SB row
vpx_memset(cm->left_context, 0, sizeof(cm->left_context));
// Code each SB in the row
- for (mb_col = 0; mb_col < mb_cols; mb_col += 4) {
+ for (mb_col = cm->cur_tile_mb_col_start;
+ mb_col < cm->cur_tile_mb_col_end; mb_col += 4) {
int i;
int sb32_rate = 0, sb32_dist = 0;
int is_sb[4];
tp, &mb_rate, &mb_dist);
mb_rate += vp9_cost_bit(cm->sb32_coded, 0);
- if (!((( mb_cols & 1) && mb_col + x_idx == mb_cols - 1) ||
+ if (!(((cm->mb_cols & 1) && mb_col + x_idx == cm->mb_cols - 1) ||
((cm->mb_rows & 1) && mb_row + y_idx == cm->mb_rows - 1))) {
/* Pick a mode assuming that it applies to all 4 of the MBs in the SB */
pick_sb_modes(cpi, mb_row + y_idx, mb_col + x_idx,
memcpy(cm->left_context, &l, sizeof(l));
sb32_rate += vp9_cost_bit(cm->sb64_coded, 0);
- if (!((( mb_cols & 3) && mb_col + 3 >= mb_cols) ||
+ if (!(((cm->mb_cols & 3) && mb_col + 3 >= cm->mb_cols) ||
((cm->mb_rows & 3) && mb_row + 3 >= cm->mb_rows))) {
pick_sb64_modes(cpi, mb_row, mb_col, tp, &sb64_rate, &sb64_dist);
sb64_rate += vp9_cost_bit(cm->sb64_coded, 1);
vpx_usec_timer_start(&emr_timer);
{
- // For each row of SBs in the frame
- for (mb_row = 0; mb_row < cm->mb_rows; mb_row += 4) {
- encode_sb_row(cpi, mb_row, &tp, &totalrate);
+ // Take tiles into account and give start/end MB
+ int tile, mb_start = 0;
+
+ for (tile = 0; tile < cm->tile_columns; tile++) {
+ // calculate end of tile column
+ const int sb_cols = (cm->mb_cols + 3) >> 2;
+ const int sb_end = (sb_cols * (tile + 1)) >> cpi->oxcf.tile_columns;
+ const int mb_end = ((sb_end << 2) > cm->mb_cols) ?
+ cm->mb_cols : (sb_end << 2);
+
+ // For each row of SBs in the frame
+ cm->cur_tile_idx = tile;
+ cm->cur_tile_mb_col_start = mb_start;
+ cm->cur_tile_mb_col_end = mb_end;
+ for (mb_row = 0; mb_row < cm->mb_rows; mb_row += 4) {
+ encode_sb_row(cpi, mb_row, &tp, &totalrate);
+ }
+ mb_start = mb_end;
}
cpi->tok_count = (unsigned int)(tp - cpi->tok);
#include "vp9_rtcd.h"
#include "vp9/encoder/vp9_quantize.h"
#include "vp9/common/vp9_reconintra.h"
-#include "vp9/common/vp9_reconintra4x4.h"
#include "vp9/encoder/vp9_encodemb.h"
#include "vp9/common/vp9_invtrans.h"
#include "vp9/encoder/vp9_encodeintra.h"
b->bmi.as_mode.context = vp9_find_bpred_context(b);
#endif
- vp9_intra4x4_predict(b, b->bmi.as_mode.first, b->predictor);
+ vp9_intra4x4_predict(&x->e_mbd, b, b->bmi.as_mode.first, b->predictor);
vp9_subtract_b(be, b, 16);
tx_type = get_tx_type_4x4(&x->e_mbd, b);
int i;
TX_TYPE tx_type;
- vp9_intra8x8_predict(b, b->bmi.as_mode.first, b->predictor);
+ vp9_intra8x8_predict(xd, b, b->bmi.as_mode.first, b->predictor);
// generate residual blocks
vp9_subtract_4b_c(be, b, 16);
BLOCKD *b = &x->e_mbd.block[ib];
BLOCK *be = &x->block[ib];
- vp9_intra_uv4x4_predict(b, mode, b->predictor);
+ vp9_intra_uv4x4_predict(&x->e_mbd, b, mode, b->predictor);
vp9_subtract_b(be, b, 8);
static void init_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
VP9_COMP *cpi = (VP9_COMP *)(ptr);
- VP9_COMMON *cm = &cpi->common;
+ VP9_COMMON *const cm = &cpi->common;
cpi->oxcf = *oxcf;
cpi->gld_fb_idx = 1;
cpi->alt_fb_idx = 2;
+ cm->tile_columns = 1 << cpi->oxcf.tile_columns;
+
#if VP9_TEMPORAL_ALT_REF
{
int i;
void vp9_change_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
VP9_COMP *cpi = (VP9_COMP *)(ptr);
- VP9_COMMON *cm = &cpi->common;
+ VP9_COMMON *const cm = &cpi->common;
if (!cpi)
return;
cpi->last_frame_distortion = 0;
#endif
+ cm->tile_columns = 1 << cpi->oxcf.tile_columns;
}
#define M_LOG2_E 0.693147180559945309417
fwrite(src, s->uv_width, 1, yuv_rec_file);
src += s->uv_stride;
} while (--h);
+ fflush(yuv_rec_file);
}
#endif
#include "vp9/common/vp9_entropymode.h"
#include "vp9/common/vp9_reconinter.h"
#include "vp9/common/vp9_reconintra.h"
-#include "vp9/common/vp9_reconintra4x4.h"
#include "vp9/common/vp9_findnearmv.h"
#include "vp9/common/vp9_quant_common.h"
#include "vp9/encoder/vp9_encodemb.h"
rate = bmode_costs[mode];
#endif
- vp9_intra4x4_predict(b, mode, b->predictor);
+ vp9_intra4x4_predict(xd, b, mode, b->predictor);
vp9_subtract_b(be, b, 16);
b->bmi.as_mode.first = mode;
rate = mode_costs[mode];
b->bmi.as_mode.first = mode;
- vp9_intra8x8_predict(b, mode, b->predictor);
+ vp9_intra8x8_predict(xd, b, mode, b->predictor);
vp9_subtract_4b_c(be, b, 16);
}
break;
case LEFT4X4:
- this_mv->as_int = col ? d[-1].bmi.as_mv.first.as_int : left_block_mv(mic, i);
+ this_mv->as_int = col ? d[-1].bmi.as_mv.first.as_int :
+ left_block_mv(xd, mic, i);
if (mbmi->second_ref_frame > 0)
- this_second_mv->as_int = col ? d[-1].bmi.as_mv.second.as_int : left_block_second_mv(mic, i);
+ this_second_mv->as_int = col ? d[-1].bmi.as_mv.second.as_int :
+ left_block_second_mv(xd, mic, i);
break;
case ABOVE4X4:
- this_mv->as_int = row ? d[-4].bmi.as_mv.first.as_int : above_block_mv(mic, i, mis);
+ this_mv->as_int = row ? d[-4].bmi.as_mv.first.as_int :
+ above_block_mv(mic, i, mis);
if (mbmi->second_ref_frame > 0)
- this_second_mv->as_int = row ? d[-4].bmi.as_mv.second.as_int : above_block_second_mv(mic, i, mis);
+ this_second_mv->as_int = row ? d[-4].bmi.as_mv.second.as_int :
+ above_block_second_mv(mic, i, mis);
break;
case ZERO4X4:
this_mv->as_int = 0;
left_second_mv.as_int = 0;
left_mv.as_int = col ? d[-1].bmi.as_mv.first.as_int :
- left_block_mv(mic, i);
+ left_block_mv(xd, mic, i);
if (mbmi->second_ref_frame > 0)
left_second_mv.as_int = col ? d[-1].bmi.as_mv.second.as_int :
- left_block_second_mv(mic, i);
+ left_block_second_mv(xd, mic, i);
if (left_mv.as_int == this_mv->as_int &&
(mbmi->second_ref_frame <= 0 ||
v_buffer[frame_type] = yv12->v_buffer + recon_uvoffset;
// Gets an initial list of candidate vectors from neighbours and orders them
- vp9_find_mv_refs(xd, xd->mode_info_context,
+ vp9_find_mv_refs(&cpi->common, xd, xd->mode_info_context,
cpi->common.error_resilient_mode ?
0 : xd->prev_mode_info_context,
frame_type,
int t_pred_cost = INT_MAX;
int i;
- int mb_row, mb_col;
+ int tile, mb_row, mb_col, mb_start = 0;
int temporal_predictor_count[PREDICTION_PROBS][2];
int no_pred_segcounts[MAX_MB_SEGMENTS];
vp9_prob t_nopred_prob[PREDICTION_PROBS];
const int mis = cm->mode_info_stride;
- MODE_INFO *mi_ptr = cm->mi, *mi;
+ MODE_INFO *mi_ptr, *mi;
// Set default state for the segment tree probabilities and the
// temporal coding probabilities
// First of all generate stats regarding how well the last segment map
// predicts this one
+ for (tile = 0; tile < cm->tile_columns; tile++) {
+ // calculate end of tile column
+ const int sb_cols = (cm->mb_cols + 3) >> 2;
+ const int sb_end = (sb_cols * (tile + 1)) >> cpi->oxcf.tile_columns;
+ const int mb_end = ((sb_end << 2) > cm->mb_cols) ?
+ cm->mb_cols : (sb_end << 2);
+
+ cm->cur_tile_idx = tile;
+ cm->cur_tile_mb_col_start = mb_start;
+ cm->cur_tile_mb_col_end = mb_end;
+
+ mi_ptr = cm->mi + mb_start;
for (mb_row = 0; mb_row < cm->mb_rows; mb_row += 4, mi_ptr += 4 * mis) {
mi = mi_ptr;
- for (mb_col = 0; mb_col < cm->mb_cols; mb_col += 4, mi += 4) {
+ for (mb_col = mb_start; mb_col < mb_end; mb_col += 4, mi += 4) {
if (mi->mbmi.sb_type == BLOCK_SIZE_SB64X64) {
count_segs(cpi, mi, no_pred_segcounts, temporal_predictor_count,
t_unpred_seg_counts, 4, mb_row, mb_col);
}
}
+ mb_start = mb_end;
+ }
+
// Work out probability tree for coding segments without prediction
// and the cost.
calc_segtree_probs(xd, no_pred_segcounts, no_pred_tree);
VP9_COMMON_SRCS-yes += common/vp9_quant_common.h
VP9_COMMON_SRCS-yes += common/vp9_reconinter.h
VP9_COMMON_SRCS-yes += common/vp9_reconintra.h
-VP9_COMMON_SRCS-yes += common/vp9_reconintra4x4.h
VP9_COMMON_SRCS-yes += common/vp9_rtcd.c
VP9_COMMON_SRCS-yes += common/vp9_rtcd_defs.sh
VP9_COMMON_SRCS-yes += common/vp9_sadmxn.h
unsigned int noise_sensitivity;
unsigned int Sharpness;
unsigned int static_thresh;
- unsigned int token_partitions;
+ unsigned int tile_columns;
unsigned int arnr_max_frames; /* alt_ref Noise Reduction Max Frame Count */
unsigned int arnr_strength; /* alt_ref Noise Reduction Strength */
unsigned int arnr_type; /* alt_ref filter type */
0, /* noise_sensitivity */
0, /* Sharpness */
0, /* static_thresh */
- VP8_ONE_TOKENPARTITION, /* token_partitions */
+ VP8_ONE_TILE_COLUMN, /* tile_columns */
0, /* arnr_max_frames */
3, /* arnr_strength */
3, /* arnr_type*/
RANGE_CHECK_HI(vp8_cfg, noise_sensitivity, 6);
- RANGE_CHECK(vp8_cfg, token_partitions, VP8_ONE_TOKENPARTITION, VP8_EIGHT_TOKENPARTITION);
+ RANGE_CHECK(vp8_cfg, tile_columns,
+ VP8_ONE_TILE_COLUMN, VP8_FOUR_TILE_COLUMNS);
RANGE_CHECK_HI(vp8_cfg, Sharpness, 7);
RANGE_CHECK(vp8_cfg, arnr_max_frames, 0, 15);
RANGE_CHECK_HI(vp8_cfg, arnr_strength, 6);
oxcf->tuning = vp8_cfg.tuning;
+ oxcf->tile_columns = vp8_cfg.tile_columns;
+
#if CONFIG_LOSSLESS
oxcf->lossless = vp8_cfg.lossless;
#endif
MAP(VP8E_SET_NOISE_SENSITIVITY, xcfg.noise_sensitivity);
MAP(VP8E_SET_SHARPNESS, xcfg.Sharpness);
MAP(VP8E_SET_STATIC_THRESHOLD, xcfg.static_thresh);
- MAP(VP8E_SET_TOKEN_PARTITIONS, xcfg.token_partitions);
+ MAP(VP9E_SET_TILE_COLUMNS, xcfg.tile_columns);
MAP(VP8E_SET_ARNR_MAXFRAMES, xcfg.arnr_max_frames);
MAP(VP8E_SET_ARNR_STRENGTH, xcfg.arnr_strength);
{VP8E_SET_ENABLEAUTOALTREF, set_param},
{VP8E_SET_SHARPNESS, set_param},
{VP8E_SET_STATIC_THRESHOLD, set_param},
- {VP8E_SET_TOKEN_PARTITIONS, set_param},
+ {VP9E_SET_TILE_COLUMNS, set_param},
{VP8E_GET_LAST_QUANTIZER, get_param},
{VP8E_GET_LAST_QUANTIZER_64, get_param},
{VP8E_SET_ARNR_MAXFRAMES, set_param},
oxcf.Version = 9;
oxcf.postprocess = 0;
oxcf.max_threads = ctx->cfg.threads;
+ oxcf.inv_tile_order = ctx->cfg.inv_tile_order;
optr = vp9_create_decompressor(&oxcf);
/* If postprocessing was enabled by the application and a
/* TODO(jkoleszar): Move to vp9cx.h */
- VP9E_SET_LOSSLESS
+ VP9E_SET_LOSSLESS,
+ VP9E_SET_TILE_COLUMNS
};
/*!\brief vpx 1-D scaling mode
} vp8e_token_partitions;
+/*!\brief VP8 tile column mode
+ *
+ * This defines VP9 tiling mode for compressed data, i.e., the number of
+ * sub-streams in the bitstream. Used for parallelized encoding/decoding.
+ *
+ */
+
+typedef enum {
+ VP8_ONE_TILE_COLUMN = 0,
+ VP8_TWO_TILE_COLUMNS = 1,
+ VP8_FOUR_TILE_COLUMNS = 2
+} vp8e_tile_column_mode;
+
/*!\brief VP8 model tuning parameters
*
* Changes the encoder to tune for certain types of input material.
VPX_CTRL_USE_TYPE(VP8E_SET_TUNING, int) /* vp8e_tuning */
VPX_CTRL_USE_TYPE(VP8E_SET_CQ_LEVEL, unsigned int)
+VPX_CTRL_USE_TYPE(VP9E_SET_TILE_COLUMNS, int)
+
VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER, int *)
VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER_64, int *)
unsigned int threads; /**< Maximum number of threads to use, default 1 */
unsigned int w; /**< Width */
unsigned int h; /**< Height */
+ int inv_tile_order; /**< Invert tile decoding order, default 0 */
} vpx_codec_dec_cfg_t; /**< alias for struct vpx_codec_dec_cfg */
static const arg_def_t cpu_used = ARG_DEF(NULL, "cpu-used", 1,
"CPU Used (-16..16)");
static const arg_def_t token_parts = ARG_DEF(NULL, "token-parts", 1,
- "Number of token partitions to use, log2");
+ "Number of token partitions to use, log2");
+static const arg_def_t tile_cols = ARG_DEF(NULL, "tile-columns", 1,
+ "Number of tile columns to use, log2");
static const arg_def_t auto_altref = ARG_DEF(NULL, "auto-alt-ref", 1,
"Enable automatic alt reference frames");
static const arg_def_t arnr_maxframes = ARG_DEF(NULL, "arnr-maxframes", 1,
#if CONFIG_VP9_ENCODER
static const arg_def_t *vp9_args[] = {
&cpu_used, &auto_altref, &noise_sens, &sharpness, &static_thresh,
- &token_parts, &arnr_maxframes, &arnr_strength, &arnr_type,
+ &tile_cols, &arnr_maxframes, &arnr_strength, &arnr_type,
&tune_ssim, &cq_level, &max_intra_rate_pct,
#if CONFIG_LOSSLESS
&lossless,
static const int vp9_arg_ctrl_map[] = {
VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF,
VP8E_SET_NOISE_SENSITIVITY, VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD,
- VP8E_SET_TOKEN_PARTITIONS,
+ VP9E_SET_TILE_COLUMNS,
VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH, VP8E_SET_ARNR_TYPE,
VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT,
#if CONFIG_LOSSLESS