Merge "Use an exponential growth approach for the ANS reversal buffer." into nextgenv2
diff --git a/build/make/configure.sh b/build/make/configure.sh
index d888268..b305d33 100644
--- a/build/make/configure.sh
+++ b/build/make/configure.sh
@@ -644,6 +644,9 @@
# detect tgt_isa
case "$gcctarget" in
+ aarch64*)
+ tgt_isa=arm64
+ ;;
armv6*)
tgt_isa=armv6
;;
@@ -1187,6 +1190,12 @@
soft_disable avx2
;;
esac
+ case $vc_version in
+ 7|8|9)
+ echo "${tgt_cc} omits stdint.h, disabling webm-io..."
+ soft_disable webm_io
+ ;;
+ esac
;;
esac
diff --git a/configure b/configure
index edb8a36..eedbf7f 100755
--- a/configure
+++ b/configure
@@ -103,6 +103,7 @@
all_platforms="${all_platforms} armv6-linux-gcc"
all_platforms="${all_platforms} armv6-none-rvct"
all_platforms="${all_platforms} arm64-darwin-gcc"
+all_platforms="${all_platforms} arm64-linux-gcc"
all_platforms="${all_platforms} armv7-android-gcc" #neon Cortex-A8
all_platforms="${all_platforms} armv7-darwin-gcc" #neon Cortex-A8
all_platforms="${all_platforms} armv7-linux-rvct" #neon Cortex-A8
diff --git a/examples.mk b/examples.mk
index 13af086..593c8dd 100644
--- a/examples.mk
+++ b/examples.mk
@@ -36,21 +36,30 @@
third_party/libyuv/source/scale_neon64.cc \
third_party/libyuv/source/scale_win.cc \
-LIBWEBM_COMMON_SRCS += third_party/libwebm/webmids.hpp
+LIBWEBM_COMMON_SRCS += third_party/libwebm/common/hdr_util.cc \
+ third_party/libwebm/common/hdr_util.h \
+ third_party/libwebm/common/webmids.h
-LIBWEBM_MUXER_SRCS += third_party/libwebm/mkvmuxer.cpp \
- third_party/libwebm/mkvmuxerutil.cpp \
- third_party/libwebm/mkvwriter.cpp \
- third_party/libwebm/mkvmuxer.hpp \
- third_party/libwebm/mkvmuxertypes.hpp \
- third_party/libwebm/mkvmuxerutil.hpp \
- third_party/libwebm/mkvparser.hpp \
- third_party/libwebm/mkvwriter.hpp
+LIBWEBM_MUXER_SRCS += third_party/libwebm/mkvmuxer/mkvmuxer.cc \
+ third_party/libwebm/mkvmuxer/mkvmuxerutil.cc \
+ third_party/libwebm/mkvmuxer/mkvwriter.cc \
+ third_party/libwebm/mkvmuxer/mkvmuxer.h \
+ third_party/libwebm/mkvmuxer/mkvmuxertypes.h \
+ third_party/libwebm/mkvmuxer/mkvmuxerutil.h \
+ third_party/libwebm/mkvparser/mkvparser.h \
+ third_party/libwebm/mkvmuxer/mkvwriter.h
-LIBWEBM_PARSER_SRCS = third_party/libwebm/mkvparser.cpp \
- third_party/libwebm/mkvreader.cpp \
- third_party/libwebm/mkvparser.hpp \
- third_party/libwebm/mkvreader.hpp
+LIBWEBM_PARSER_SRCS = third_party/libwebm/mkvparser/mkvparser.cc \
+ third_party/libwebm/mkvparser/mkvreader.cc \
+ third_party/libwebm/mkvparser/mkvparser.h \
+ third_party/libwebm/mkvparser/mkvreader.h
+
+# Add compile flags and include path for libwebm sources.
+ifeq ($(CONFIG_WEBM_IO),yes)
+ CXXFLAGS += -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
+ INC_PATH-yes += $(SRC_PATH_BARE)/third_party/libwebm
+endif
+
# List of examples to build. UTILS are tools meant for distribution
# while EXAMPLES demonstrate specific portions of the API.
@@ -70,6 +79,7 @@
endif
ifeq ($(CONFIG_WEBM_IO),yes)
vpxdec.SRCS += $(LIBWEBM_COMMON_SRCS)
+ vpxdec.SRCS += $(LIBWEBM_MUXER_SRCS)
vpxdec.SRCS += $(LIBWEBM_PARSER_SRCS)
vpxdec.SRCS += webmdec.cc webmdec.h
endif
@@ -93,6 +103,7 @@
ifeq ($(CONFIG_WEBM_IO),yes)
vpxenc.SRCS += $(LIBWEBM_COMMON_SRCS)
vpxenc.SRCS += $(LIBWEBM_MUXER_SRCS)
+ vpxenc.SRCS += $(LIBWEBM_PARSER_SRCS)
vpxenc.SRCS += webmenc.cc webmenc.h
endif
vpxenc.GUID = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1
diff --git a/libs.mk b/libs.mk
index e6fb068..c2a4725 100644
--- a/libs.mk
+++ b/libs.mk
@@ -394,6 +394,12 @@
$(shell $(SRC_PATH_BARE)/build/make/version.sh "$(SRC_PATH_BARE)" $(BUILD_PFX)vpx_version.h)
CLEAN-OBJS += $(BUILD_PFX)vpx_version.h
+#
+# Add include path for libwebm sources.
+#
+ifeq ($(CONFIG_WEBM_IO),yes)
+ CXXFLAGS += -I$(SRC_PATH_BARE)/third_party/libwebm
+endif
##
## libvpx test directives
@@ -469,6 +475,7 @@
$(if $(CONFIG_STATIC_MSVCRT),--static-crt) \
--out=$@ $(INTERNAL_CFLAGS) $(CFLAGS) \
-I. -I"$(SRC_PATH_BARE)/third_party/googletest/src/include" \
+ $(if $(CONFIG_WEBM_IO),-I"$(SRC_PATH_BARE)/third_party/libwebm") \
-L. -l$(CODEC_LIB) -l$(GTEST_LIB) $^
PROJECTS-$(CONFIG_MSVS) += test_libvpx.$(VCPROJ_SFX)
diff --git a/test/active_map_test.cc b/test/active_map_test.cc
index 0221995..dc3de72 100644
--- a/test/active_map_test.cc
+++ b/test/active_map_test.cc
@@ -85,5 +85,5 @@
VP9_INSTANTIATE_TEST_CASE(ActiveMapTest,
::testing::Values(::libvpx_test::kRealTime),
- ::testing::Range(0, 6));
+ ::testing::Range(0, 9));
} // namespace
diff --git a/test/dct16x16_test.cc b/test/dct16x16_test.cc
index d6cc5e4..c4dfaf3 100644
--- a/test/dct16x16_test.cc
+++ b/test/dct16x16_test.cc
@@ -792,6 +792,67 @@
CompareInvReference(ref_txfm_, thresh_);
}
+class PartialTrans16x16Test
+ : public ::testing::TestWithParam<
+ std::tr1::tuple<FdctFunc, vpx_bit_depth_t> > {
+ public:
+ virtual ~PartialTrans16x16Test() {}
+ virtual void SetUp() {
+ fwd_txfm_ = GET_PARAM(0);
+ bit_depth_ = GET_PARAM(1);
+ }
+
+ virtual void TearDown() { libvpx_test::ClearSystemState(); }
+
+ protected:
+ vpx_bit_depth_t bit_depth_;
+ FdctFunc fwd_txfm_;
+};
+
+TEST_P(PartialTrans16x16Test, Extremes) {
+#if CONFIG_VP9_HIGHBITDEPTH
+ const int16_t maxval =
+ static_cast<int16_t>(clip_pixel_highbd(1 << 30, bit_depth_));
+#else
+ const int16_t maxval = 255;
+#endif
+ const int minval = -maxval;
+ DECLARE_ALIGNED(16, int16_t, input[kNumCoeffs]);
+ DECLARE_ALIGNED(16, tran_low_t, output[kNumCoeffs]);
+
+ for (int i = 0; i < kNumCoeffs; ++i) input[i] = maxval;
+ output[0] = 0;
+ ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 16));
+ EXPECT_EQ((maxval * kNumCoeffs) >> 1, output[0]);
+
+ for (int i = 0; i < kNumCoeffs; ++i) input[i] = minval;
+ output[0] = 0;
+ ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 16));
+ EXPECT_EQ((minval * kNumCoeffs) >> 1, output[0]);
+}
+
+TEST_P(PartialTrans16x16Test, Random) {
+#if CONFIG_VP9_HIGHBITDEPTH
+ const int16_t maxval =
+ static_cast<int16_t>(clip_pixel_highbd(1 << 30, bit_depth_));
+#else
+ const int16_t maxval = 255;
+#endif
+ DECLARE_ALIGNED(16, int16_t, input[kNumCoeffs]);
+ DECLARE_ALIGNED(16, tran_low_t, output[kNumCoeffs]);
+ ACMRandom rnd(ACMRandom::DeterministicSeed());
+
+ int sum = 0;
+ for (int i = 0; i < kNumCoeffs; ++i) {
+ const int val = (i & 1) ? -rnd(maxval + 1) : rnd(maxval + 1);
+ input[i] = val;
+ sum += val;
+ }
+ output[0] = 0;
+ ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 16));
+ EXPECT_EQ(sum >> 1, output[0]);
+}
+
using std::tr1::make_tuple;
#if CONFIG_VP9_HIGHBITDEPTH
@@ -824,6 +885,11 @@
make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 1, VPX_BITS_8),
make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 2, VPX_BITS_8),
make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 3, VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(
+ C, PartialTrans16x16Test,
+ ::testing::Values(make_tuple(&vpx_highbd_fdct16x16_1_c, VPX_BITS_8),
+ make_tuple(&vpx_highbd_fdct16x16_1_c, VPX_BITS_10),
+ make_tuple(&vpx_highbd_fdct16x16_1_c, VPX_BITS_12)));
#else
INSTANTIATE_TEST_CASE_P(
C, Trans16x16HT,
@@ -832,6 +898,9 @@
make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 1, VPX_BITS_8),
make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 2, VPX_BITS_8),
make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 3, VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(C, PartialTrans16x16Test,
+ ::testing::Values(make_tuple(&vpx_fdct16x16_1_c,
+ VPX_BITS_8)));
#endif // CONFIG_VP9_HIGHBITDEPTH
#if HAVE_NEON_ASM && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
@@ -859,6 +928,9 @@
VPX_BITS_8),
make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 3,
VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(SSE2, PartialTrans16x16Test,
+ ::testing::Values(make_tuple(&vpx_fdct16x16_1_sse2,
+ VPX_BITS_8)));
#endif // HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
@@ -896,6 +968,9 @@
&idct16x16_10_add_12_sse2, 3167, VPX_BITS_12),
make_tuple(&idct16x16_12,
&idct16x16_256_add_12_sse2, 3167, VPX_BITS_12)));
+INSTANTIATE_TEST_CASE_P(SSE2, PartialTrans16x16Test,
+ ::testing::Values(make_tuple(&vpx_fdct16x16_1_sse2,
+ VPX_BITS_8)));
#endif // HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
@@ -912,5 +987,8 @@
make_tuple(&vp9_fht16x16_msa, &vp9_iht16x16_256_add_msa, 2, VPX_BITS_8),
make_tuple(&vp9_fht16x16_msa, &vp9_iht16x16_256_add_msa, 3,
VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(MSA, PartialTrans16x16Test,
+ ::testing::Values(make_tuple(&vpx_fdct16x16_1_msa,
+ VPX_BITS_8)));
#endif // HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
} // namespace
diff --git a/test/dct32x32_test.cc b/test/dct32x32_test.cc
index 2dac10b..1cbac5c 100644
--- a/test/dct32x32_test.cc
+++ b/test/dct32x32_test.cc
@@ -305,6 +305,67 @@
}
}
+class PartialTrans32x32Test
+ : public ::testing::TestWithParam<
+ std::tr1::tuple<FwdTxfmFunc, vpx_bit_depth_t> > {
+ public:
+ virtual ~PartialTrans32x32Test() {}
+ virtual void SetUp() {
+ fwd_txfm_ = GET_PARAM(0);
+ bit_depth_ = GET_PARAM(1);
+ }
+
+ virtual void TearDown() { libvpx_test::ClearSystemState(); }
+
+ protected:
+ vpx_bit_depth_t bit_depth_;
+ FwdTxfmFunc fwd_txfm_;
+};
+
+TEST_P(PartialTrans32x32Test, Extremes) {
+#if CONFIG_VP9_HIGHBITDEPTH
+ const int16_t maxval =
+ static_cast<int16_t>(clip_pixel_highbd(1 << 30, bit_depth_));
+#else
+ const int16_t maxval = 255;
+#endif
+ const int minval = -maxval;
+ DECLARE_ALIGNED(16, int16_t, input[kNumCoeffs]);
+ DECLARE_ALIGNED(16, tran_low_t, output[kNumCoeffs]);
+
+ for (int i = 0; i < kNumCoeffs; ++i) input[i] = maxval;
+ output[0] = 0;
+ ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 32));
+ EXPECT_EQ((maxval * kNumCoeffs) >> 3, output[0]);
+
+ for (int i = 0; i < kNumCoeffs; ++i) input[i] = minval;
+ output[0] = 0;
+ ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 32));
+ EXPECT_EQ((minval * kNumCoeffs) >> 3, output[0]);
+}
+
+TEST_P(PartialTrans32x32Test, Random) {
+#if CONFIG_VP9_HIGHBITDEPTH
+ const int16_t maxval =
+ static_cast<int16_t>(clip_pixel_highbd(1 << 30, bit_depth_));
+#else
+ const int16_t maxval = 255;
+#endif
+ DECLARE_ALIGNED(16, int16_t, input[kNumCoeffs]);
+ DECLARE_ALIGNED(16, tran_low_t, output[kNumCoeffs]);
+ ACMRandom rnd(ACMRandom::DeterministicSeed());
+
+ int sum = 0;
+ for (int i = 0; i < kNumCoeffs; ++i) {
+ const int val = (i & 1) ? -rnd(maxval + 1) : rnd(maxval + 1);
+ input[i] = val;
+ sum += val;
+ }
+ output[0] = 0;
+ ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 32));
+ EXPECT_EQ(sum >> 3, output[0]);
+}
+
using std::tr1::make_tuple;
#if CONFIG_VP9_HIGHBITDEPTH
@@ -323,6 +384,11 @@
&vpx_idct32x32_1024_add_c, 0, VPX_BITS_8),
make_tuple(&vpx_fdct32x32_rd_c,
&vpx_idct32x32_1024_add_c, 1, VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(
+ C, PartialTrans32x32Test,
+ ::testing::Values(make_tuple(&vpx_highbd_fdct32x32_1_c, VPX_BITS_8),
+ make_tuple(&vpx_highbd_fdct32x32_1_c, VPX_BITS_10),
+ make_tuple(&vpx_highbd_fdct32x32_1_c, VPX_BITS_12)));
#else
INSTANTIATE_TEST_CASE_P(
C, Trans32x32Test,
@@ -331,9 +397,12 @@
&vpx_idct32x32_1024_add_c, 0, VPX_BITS_8),
make_tuple(&vpx_fdct32x32_rd_c,
&vpx_idct32x32_1024_add_c, 1, VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(C, PartialTrans32x32Test,
+ ::testing::Values(make_tuple(&vpx_fdct32x32_1_c,
+ VPX_BITS_8)));
#endif // CONFIG_VP9_HIGHBITDEPTH
-#if HAVE_NEON_ASM && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
+#if HAVE_NEON && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
NEON, Trans32x32Test,
::testing::Values(
@@ -341,7 +410,7 @@
&vpx_idct32x32_1024_add_neon, 0, VPX_BITS_8),
make_tuple(&vpx_fdct32x32_rd_c,
&vpx_idct32x32_1024_add_neon, 1, VPX_BITS_8)));
-#endif // HAVE_NEON_ASM && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
+#endif // HAVE_NEON && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
@@ -351,6 +420,9 @@
&vpx_idct32x32_1024_add_sse2, 0, VPX_BITS_8),
make_tuple(&vpx_fdct32x32_rd_sse2,
&vpx_idct32x32_1024_add_sse2, 1, VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(SSE2, PartialTrans32x32Test,
+ ::testing::Values(make_tuple(&vpx_fdct32x32_1_sse2,
+ VPX_BITS_8)));
#endif // HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
@@ -367,6 +439,9 @@
VPX_BITS_8),
make_tuple(&vpx_fdct32x32_rd_sse2, &vpx_idct32x32_1024_add_c, 1,
VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(SSE2, PartialTrans32x32Test,
+ ::testing::Values(make_tuple(&vpx_fdct32x32_1_sse2,
+ VPX_BITS_8)));
#endif // HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_AVX2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
@@ -387,5 +462,8 @@
&vpx_idct32x32_1024_add_msa, 0, VPX_BITS_8),
make_tuple(&vpx_fdct32x32_rd_msa,
&vpx_idct32x32_1024_add_msa, 1, VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(MSA, PartialTrans32x32Test,
+ ::testing::Values(make_tuple(&vpx_fdct32x32_1_msa,
+ VPX_BITS_8)));
#endif // HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
} // namespace
diff --git a/test/superframe_test.cc b/test/superframe_test.cc
index 4fc9555..e6852e3 100644
--- a/test/superframe_test.cc
+++ b/test/superframe_test.cc
@@ -108,7 +108,11 @@
::testing::Values(::libvpx_test::kTwoPassGood),
::testing::Values(0)));
+// The superframe index is currently mandatory with ANS due to the decoder
+// starting at the end of the buffer.
+#if !CONFIG_ANS
VP10_INSTANTIATE_TEST_CASE(SuperframeTest, ::testing::Combine(
::testing::Values(::libvpx_test::kTwoPassGood),
::testing::Values(1)));
+#endif
} // namespace
diff --git a/test/test.mk b/test/test.mk
index 7c3f101..59f054c 100644
--- a/test/test.mk
+++ b/test/test.mk
@@ -60,10 +60,10 @@
## WebM Parsing
ifeq ($(CONFIG_WEBM_IO), yes)
-LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser.cpp
-LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvreader.cpp
-LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser.hpp
-LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvreader.hpp
+LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser/mkvparser.cc
+LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser/mkvreader.cc
+LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser/mkvparser.h
+LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser/mkvreader.h
LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += $(LIBWEBM_PARSER_SRCS)
LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += ../tools_common.h
LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += ../webmdec.cc
diff --git a/test/vp10_fht4x4_test.cc b/test/vp10_fht4x4_test.cc
index 2e9d2d4..63d9ec7 100644
--- a/test/vp10_fht4x4_test.cc
+++ b/test/vp10_fht4x4_test.cc
@@ -119,10 +119,12 @@
}
#endif // CONFIG_VP9_HIGHBITDEPTH
+#define SPEED_TEST (0)
+#if SPEED_TEST
#if CONFIG_EXT_TX
TEST(VP10Trans4x4HTSpeedTest, C_version) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
- const int count_test_block = 20000;
+ const int count_test_block = 200000;
int bit_depth = 8;
int mask = (1 << bit_depth) - 1;
const int num_coeffs = 16;
@@ -131,10 +133,10 @@
const int stride = 4;
int tx_type;
+ for (int j = 0; j < num_coeffs; ++j) {
+ input[j] = (rnd.Rand8() & mask) - (rnd.Rand8() & mask);
+ }
for (int i = 0; i < count_test_block; ++i) {
- for (int j = 0; j < num_coeffs; ++j) {
- input[j] = (rnd.Rand8() & mask) - (rnd.Rand8() & mask);
- }
for (tx_type = V_DCT; tx_type <= H_FLIPADST; ++tx_type) {
vp10_fht4x4_c(input, output, stride, tx_type);
}
@@ -148,28 +150,30 @@
#if HAVE_SSE2 && CONFIG_EXT_TX
TEST(VP10Trans4x4HTSpeedTest, SSE2_version) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
- const int count_test_block = 20000;
+ const int count_test_block = 200000;
int bit_depth = 8;
int mask = (1 << bit_depth) - 1;
const int num_coeffs = 16;
int16_t *input = new int16_t[num_coeffs];
- tran_low_t *output = new tran_low_t[num_coeffs];
+ tran_low_t *output = reinterpret_cast<tran_low_t *>(
+ vpx_memalign(16, num_coeffs * sizeof(tran_low_t)));
const int stride = 4;
int tx_type;
+ for (int j = 0; j < num_coeffs; ++j) {
+ input[j] = (rnd.Rand8() & mask) - (rnd.Rand8() & mask);
+ }
for (int i = 0; i < count_test_block; ++i) {
- for (int j = 0; j < num_coeffs; ++j) {
- input[j] = (rnd.Rand8() & mask) - (rnd.Rand8() & mask);
- }
for (tx_type = V_DCT; tx_type <= H_FLIPADST; ++tx_type) {
vp10_fht4x4_sse2(input, output, stride, tx_type);
}
}
delete[] input;
- delete[] output;
+ vpx_free(output);
}
#endif // HAVE_SSE2 && CONFIG_EXT_TX
+#endif // SPEED_TEST
using std::tr1::make_tuple;
@@ -225,16 +229,16 @@
SSE4_1, VP10HighbdTrans4x4HT,
::testing::Values(
#if !CONFIG_EXT_TX
- make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 0,
- VPX_BITS_10, 16),
+ // make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 0,
+ // VPX_BITS_10, 16),
make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 1,
VPX_BITS_10, 16),
make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 2,
VPX_BITS_10, 16),
make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 3,
VPX_BITS_10, 16),
- make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 0,
- VPX_BITS_12, 16),
+ // make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 0,
+ // VPX_BITS_12, 16),
make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 1,
VPX_BITS_12, 16),
make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 2,
@@ -242,8 +246,8 @@
make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 3,
VPX_BITS_12, 16)));
#else
- make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 0,
- VPX_BITS_10, 16),
+ // make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 0,
+ // VPX_BITS_10, 16),
make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 1,
VPX_BITS_10, 16),
make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 2,
@@ -272,8 +276,8 @@
VPX_BITS_10, 16),
make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 15,
VPX_BITS_10, 16),
- make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 0,
- VPX_BITS_12, 16),
+ // make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 0,
+ // VPX_BITS_12, 16),
make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 1,
VPX_BITS_12, 16),
make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 2,
diff --git a/third_party/libwebm/Android.mk b/third_party/libwebm/Android.mk
index be9d77d..8149a08 100644
--- a/third_party/libwebm/Android.mk
+++ b/third_party/libwebm/Android.mk
@@ -2,9 +2,16 @@
include $(CLEAR_VARS)
LOCAL_MODULE:= libwebm
-LOCAL_SRC_FILES:= mkvparser.cpp \
- mkvreader.cpp \
- mkvmuxer.cpp \
- mkvmuxerutil.cpp \
- mkvwriter.cpp
+LOCAL_CPPFLAGS:=-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS
+LOCAL_CPPFLAGS+=-D__STDC_LIMIT_MACROS -Wno-extern-c-compat
+LOCAL_C_INCLUDES:= $(LOCAL_PATH)
+LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)
+
+LOCAL_SRC_FILES:= common/file_util.cc \
+ common/hdr_util.cc \
+ mkvparser/mkvparser.cc \
+ mkvparser/mkvreader.cc \
+ mkvmuxer/mkvmuxer.cc \
+ mkvmuxer/mkvmuxerutil.cc \
+ mkvmuxer/mkvwriter.cc
include $(BUILD_STATIC_LIBRARY)
diff --git a/third_party/libwebm/README.libvpx b/third_party/libwebm/README.libvpx
index 2989d3d..73f8303 100644
--- a/third_party/libwebm/README.libvpx
+++ b/third_party/libwebm/README.libvpx
@@ -1,5 +1,5 @@
URL: https://chromium.googlesource.com/webm/libwebm
-Version: 476366249e1fda7710a389cd41c57db42305e0d4
+Version: 32d5ac49414a8914ec1e1f285f3f927c6e8ec29d
License: BSD
License File: LICENSE.txt
diff --git a/third_party/libwebm/RELEASE.TXT b/third_party/libwebm/RELEASE.TXT
deleted file mode 100644
index a7e9f03..0000000
--- a/third_party/libwebm/RELEASE.TXT
+++ /dev/null
@@ -1,34 +0,0 @@
-1.0.0.5
- * Handled case when no duration
- * Handled empty clusters
- * Handled empty clusters when seeking
- * Implemented check lacing bits
-
-1.0.0.4
- * Made Cues member variables mutables
- * Defined against badly-formatted cue points
- * Segment::GetCluster returns CuePoint too
- * Separated cue-based searches
-
-1.0.0.3
- * Added Block::GetOffset() to get a frame's offset in a block
- * Changed cluster count type from size_t to long
- * Parsed SeekHead to find cues
- * Allowed seeking beyond end of cluster cache
- * Added not to attempt to reparse cues element
- * Restructured Segment::LoadCluster
- * Marked position of cues without parsing cues element
- * Allowed cue points to be loaded incrementally
- * Implemented to load lazily cue points as they're searched
- * Merged Cues::LoadCuePoint into Cues::Find
- * Lazy init cues
- * Loaded cue point during find
-
-1.0.0.2
- * added support for Cues element
- * seeking was improved
-
-1.0.0.1
- * fixed item 141
- * added item 142
- * added this file, RELEASE.TXT, to repository
diff --git a/third_party/libwebm/common/file_util.cc b/third_party/libwebm/common/file_util.cc
new file mode 100644
index 0000000..4f91318
--- /dev/null
+++ b/third_party/libwebm/common/file_util.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2016 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 "common/file_util.h"
+
+#include <sys/stat.h>
+#ifndef _MSC_VER
+#include <unistd.h> // close()
+#endif
+
+#include <cstdio>
+#include <cstdlib>
+#include <fstream>
+#include <ios>
+
+namespace libwebm {
+
+std::string GetTempFileName() {
+#if !defined _MSC_VER && !defined __MINGW32__
+ char temp_file_name_template[] = "libwebm_temp.XXXXXX";
+ int fd = mkstemp(temp_file_name_template);
+ if (fd != -1) {
+ close(fd);
+ return std::string(temp_file_name_template);
+ }
+ return std::string();
+#else
+ char tmp_file_name[_MAX_PATH];
+ errno_t err = tmpnam_s(tmp_file_name);
+ if (err == 0) {
+ return std::string(tmp_file_name);
+ }
+ return std::string();
+#endif
+}
+
+uint64_t GetFileSize(const std::string& file_name) {
+ uint64_t file_size = 0;
+#ifndef _MSC_VER
+ struct stat st;
+ st.st_size = 0;
+ if (stat(file_name.c_str(), &st) == 0) {
+#else
+ struct _stat st;
+ st.st_size = 0;
+ if (_stat(file_name.c_str(), &st) == 0) {
+#endif
+ file_size = st.st_size;
+ }
+ return file_size;
+}
+
+TempFileDeleter::TempFileDeleter() { file_name_ = GetTempFileName(); }
+
+TempFileDeleter::~TempFileDeleter() {
+ std::ifstream file(file_name_.c_str());
+ if (file.good()) {
+ file.close();
+ std::remove(file_name_.c_str());
+ }
+}
+
+} // namespace libwebm
diff --git a/third_party/libwebm/common/file_util.h b/third_party/libwebm/common/file_util.h
new file mode 100644
index 0000000..0e71eac
--- /dev/null
+++ b/third_party/libwebm/common/file_util.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2016 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 LIBWEBM_COMMON_FILE_UTIL_H_
+#define LIBWEBM_COMMON_FILE_UTIL_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "mkvmuxer/mkvmuxertypes.h" // LIBWEBM_DISALLOW_COPY_AND_ASSIGN()
+
+namespace libwebm {
+
+// Returns a temporary file name.
+std::string GetTempFileName();
+
+// Returns size of file specified by |file_name|, or 0 upon failure.
+uint64_t GetFileSize(const std::string& file_name);
+
+// Manages life of temporary file specified at time of construction. Deletes
+// file upon destruction.
+class TempFileDeleter {
+ public:
+ TempFileDeleter();
+ explicit TempFileDeleter(std::string file_name) : file_name_(file_name) {}
+ ~TempFileDeleter();
+ const std::string& name() const { return file_name_; }
+
+ private:
+ std::string file_name_;
+ LIBWEBM_DISALLOW_COPY_AND_ASSIGN(TempFileDeleter);
+};
+
+} // namespace libwebm
+
+#endif // LIBWEBM_COMMON_FILE_UTIL_H_
\ No newline at end of file
diff --git a/third_party/libwebm/common/hdr_util.cc b/third_party/libwebm/common/hdr_util.cc
new file mode 100644
index 0000000..e1a9842
--- /dev/null
+++ b/third_party/libwebm/common/hdr_util.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2016 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 "hdr_util.h"
+
+#include <cstddef>
+#include <new>
+
+#include "mkvparser/mkvparser.h"
+
+namespace libwebm {
+bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc,
+ PrimaryChromaticityPtr* muxer_pc) {
+ muxer_pc->reset(new (std::nothrow)
+ mkvmuxer::PrimaryChromaticity(parser_pc.x, parser_pc.y));
+ if (!muxer_pc->get())
+ return false;
+ return true;
+}
+
+bool MasteringMetadataValuePresent(double value) {
+ return value != mkvparser::MasteringMetadata::kValueNotPresent;
+}
+
+bool CopyMasteringMetadata(const mkvparser::MasteringMetadata& parser_mm,
+ mkvmuxer::MasteringMetadata* muxer_mm) {
+ if (MasteringMetadataValuePresent(parser_mm.luminance_max))
+ muxer_mm->luminance_max = parser_mm.luminance_max;
+ if (MasteringMetadataValuePresent(parser_mm.luminance_min))
+ muxer_mm->luminance_min = parser_mm.luminance_min;
+
+ PrimaryChromaticityPtr r_ptr(NULL);
+ PrimaryChromaticityPtr g_ptr(NULL);
+ PrimaryChromaticityPtr b_ptr(NULL);
+ PrimaryChromaticityPtr wp_ptr(NULL);
+
+ if (parser_mm.r) {
+ if (!CopyPrimaryChromaticity(*parser_mm.r, &r_ptr))
+ return false;
+ }
+ if (parser_mm.g) {
+ if (!CopyPrimaryChromaticity(*parser_mm.g, &g_ptr))
+ return false;
+ }
+ if (parser_mm.b) {
+ if (!CopyPrimaryChromaticity(*parser_mm.b, &b_ptr))
+ return false;
+ }
+ if (parser_mm.white_point) {
+ if (!CopyPrimaryChromaticity(*parser_mm.white_point, &wp_ptr))
+ return false;
+ }
+
+ if (!muxer_mm->SetChromaticity(r_ptr.get(), g_ptr.get(), b_ptr.get(),
+ wp_ptr.get())) {
+ return false;
+ }
+
+ return true;
+}
+
+bool ColourValuePresent(long long value) {
+ return value != mkvparser::Colour::kValueNotPresent;
+}
+
+bool CopyColour(const mkvparser::Colour& parser_colour,
+ mkvmuxer::Colour* muxer_colour) {
+ if (!muxer_colour)
+ return false;
+
+ if (ColourValuePresent(parser_colour.matrix_coefficients))
+ muxer_colour->matrix_coefficients = parser_colour.matrix_coefficients;
+ if (ColourValuePresent(parser_colour.bits_per_channel))
+ muxer_colour->bits_per_channel = parser_colour.bits_per_channel;
+ if (ColourValuePresent(parser_colour.chroma_subsampling_horz))
+ muxer_colour->chroma_subsampling_horz =
+ parser_colour.chroma_subsampling_horz;
+ if (ColourValuePresent(parser_colour.chroma_subsampling_vert))
+ muxer_colour->chroma_subsampling_vert =
+ parser_colour.chroma_subsampling_vert;
+ if (ColourValuePresent(parser_colour.cb_subsampling_horz))
+ muxer_colour->cb_subsampling_horz = parser_colour.cb_subsampling_horz;
+ if (ColourValuePresent(parser_colour.cb_subsampling_vert))
+ muxer_colour->cb_subsampling_vert = parser_colour.cb_subsampling_vert;
+ if (ColourValuePresent(parser_colour.chroma_siting_horz))
+ muxer_colour->chroma_siting_horz = parser_colour.chroma_siting_horz;
+ if (ColourValuePresent(parser_colour.chroma_siting_vert))
+ muxer_colour->chroma_siting_vert = parser_colour.chroma_siting_vert;
+ if (ColourValuePresent(parser_colour.range))
+ muxer_colour->range = parser_colour.range;
+ if (ColourValuePresent(parser_colour.transfer_characteristics))
+ muxer_colour->transfer_characteristics =
+ parser_colour.transfer_characteristics;
+ if (ColourValuePresent(parser_colour.primaries))
+ muxer_colour->primaries = parser_colour.primaries;
+ if (ColourValuePresent(parser_colour.max_cll))
+ muxer_colour->max_cll = parser_colour.max_cll;
+ if (ColourValuePresent(parser_colour.max_fall))
+ muxer_colour->max_fall = parser_colour.max_fall;
+
+ if (parser_colour.mastering_metadata) {
+ mkvmuxer::MasteringMetadata muxer_mm;
+ if (!CopyMasteringMetadata(*parser_colour.mastering_metadata, &muxer_mm))
+ return false;
+ if (!muxer_colour->SetMasteringMetadata(muxer_mm))
+ return false;
+ }
+ return true;
+}
+
+// Format of VPx private data:
+//
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | ID Byte | Length | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+// | |
+// : Bytes 1..Length of Codec Feature :
+// | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// ID Byte Format
+// ID byte is an unsigned byte.
+// 0 1 2 3 4 5 6 7
+// +-+-+-+-+-+-+-+-+
+// |X| ID |
+// +-+-+-+-+-+-+-+-+
+//
+// The X bit is reserved.
+//
+// Currently only profile level is supported. ID byte must be set to 1, and
+// length must be 1. Supported values are:
+//
+// 10: Level 1
+// 11: Level 1.1
+// 20: Level 2
+// 21: Level 2.1
+// 30: Level 3
+// 31: Level 3.1
+// 40: Level 4
+// 41: Level 4.1
+// 50: Level 5
+// 51: Level 5.1
+// 52: Level 5.2
+// 60: Level 6
+// 61: Level 6.1
+// 62: Level 6.2
+//
+// See the following link for more information:
+// http://www.webmproject.org/vp9/profiles/
+int ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length) {
+ const int kVpxCodecPrivateLength = 3;
+ if (!private_data || length != kVpxCodecPrivateLength)
+ return 0;
+
+ const uint8_t id_byte = *private_data;
+ if (id_byte != 1)
+ return 0;
+
+ const int kVpxProfileLength = 1;
+ const uint8_t length_byte = private_data[1];
+ if (length_byte != kVpxProfileLength)
+ return 0;
+
+ const int level = static_cast<int>(private_data[2]);
+
+ const int kNumLevels = 14;
+ const int levels[kNumLevels] = {10, 11, 20, 21, 30, 31, 40,
+ 41, 50, 51, 52, 60, 61, 62};
+
+ for (int i = 0; i < kNumLevels; ++i) {
+ if (level == levels[i])
+ return level;
+ }
+
+ return 0;
+}
+} // namespace libwebm
diff --git a/third_party/libwebm/common/hdr_util.h b/third_party/libwebm/common/hdr_util.h
new file mode 100644
index 0000000..d30c2b9
--- /dev/null
+++ b/third_party/libwebm/common/hdr_util.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2016 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 LIBWEBM_COMMON_HDR_UTIL_H_
+#define LIBWEBM_COMMON_HDR_UTIL_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "mkvmuxer/mkvmuxer.h"
+
+namespace mkvparser {
+struct Colour;
+struct MasteringMetadata;
+struct PrimaryChromaticity;
+} // namespace mkvparser
+
+namespace libwebm {
+// Utility types and functions for working with the Colour element and its
+// children. Copiers return true upon success. Presence functions return true
+// when the specified element is present.
+
+// TODO(tomfinegan): These should be moved to libwebm_utils once c++11 is
+// required by libwebm.
+
+typedef std::auto_ptr<mkvmuxer::PrimaryChromaticity> PrimaryChromaticityPtr;
+
+bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc,
+ PrimaryChromaticityPtr* muxer_pc);
+
+bool MasteringMetadataValuePresent(double value);
+
+bool CopyMasteringMetadata(const mkvparser::MasteringMetadata& parser_mm,
+ mkvmuxer::MasteringMetadata* muxer_mm);
+
+bool ColourValuePresent(long long value);
+
+bool CopyColour(const mkvparser::Colour& parser_colour,
+ mkvmuxer::Colour* muxer_colour);
+
+// Returns VP9 profile upon success or 0 upon failure.
+int ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length);
+
+} // namespace libwebm
+
+#endif // LIBWEBM_COMMON_HDR_UTIL_H_
diff --git a/third_party/libwebm/webmids.hpp b/third_party/libwebm/common/webmids.h
similarity index 79%
rename from third_party/libwebm/webmids.hpp
rename to third_party/libwebm/common/webmids.h
index ad4ab57..32a0c5f 100644
--- a/third_party/libwebm/webmids.hpp
+++ b/third_party/libwebm/common/webmids.h
@@ -6,10 +6,10 @@
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
-#ifndef WEBMIDS_HPP
-#define WEBMIDS_HPP
+#ifndef COMMON_WEBMIDS_H_
+#define COMMON_WEBMIDS_H_
-namespace mkvmuxer {
+namespace libwebm {
enum MkvId {
kMkvEBML = 0x1A45DFA3,
@@ -95,6 +95,35 @@
kMkvAspectRatioType = 0x54B3,
kMkvFrameRate = 0x2383E3,
// end video
+ // colour
+ kMkvColour = 0x55B0,
+ kMkvMatrixCoefficients = 0x55B1,
+ kMkvBitsPerChannel = 0x55B2,
+ kMkvChromaSubsamplingHorz = 0x55B3,
+ kMkvChromaSubsamplingVert = 0x55B4,
+ kMkvCbSubsamplingHorz = 0x55B5,
+ kMkvCbSubsamplingVert = 0x55B6,
+ kMkvChromaSitingHorz = 0x55B7,
+ kMkvChromaSitingVert = 0x55B8,
+ kMkvRange = 0x55B9,
+ kMkvTransferCharacteristics = 0x55BA,
+ kMkvPrimaries = 0x55BB,
+ kMkvMaxCLL = 0x55BC,
+ kMkvMaxFALL = 0x55BD,
+ // mastering metadata
+ kMkvMasteringMetadata = 0x55D0,
+ kMkvPrimaryRChromaticityX = 0x55D1,
+ kMkvPrimaryRChromaticityY = 0x55D2,
+ kMkvPrimaryGChromaticityX = 0x55D3,
+ kMkvPrimaryGChromaticityY = 0x55D4,
+ kMkvPrimaryBChromaticityX = 0x55D5,
+ kMkvPrimaryBChromaticityY = 0x55D6,
+ kMkvWhitePointChromaticityX = 0x55D7,
+ kMkvWhitePointChromaticityY = 0x55D8,
+ kMkvLuminanceMax = 0x55D9,
+ kMkvLuminanceMin = 0x55DA,
+ // end mastering metadata
+ // end colour
// audio
kMkvAudio = 0xE1,
kMkvSamplingFrequency = 0xB5,
@@ -150,6 +179,6 @@
kMkvTagString = 0x4487
};
-} // end namespace mkvmuxer
+} // namespace libwebm
-#endif // WEBMIDS_HPP
+#endif // COMMON_WEBMIDS_H_
diff --git a/third_party/libwebm/mkvmuxer.cpp b/third_party/libwebm/mkvmuxer.cpp
deleted file mode 100644
index 9be3119..0000000
--- a/third_party/libwebm/mkvmuxer.cpp
+++ /dev/null
@@ -1,3277 +0,0 @@
-// 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 "mkvmuxer.hpp"
-
-#include <climits>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <ctime>
-#include <new>
-
-#include "mkvmuxerutil.hpp"
-#include "mkvparser.hpp"
-#include "mkvwriter.hpp"
-#include "webmids.hpp"
-
-#ifdef _MSC_VER
-// Disable MSVC warnings that suggest making code non-portable.
-#pragma warning(disable : 4996)
-#endif
-
-namespace mkvmuxer {
-
-namespace {
-// Deallocate the string designated by |dst|, and then copy the |src|
-// string to |dst|. The caller owns both the |src| string and the
-// |dst| copy (hence the caller is responsible for eventually
-// deallocating the strings, either directly, or indirectly via
-// StrCpy). Returns true if the source string was successfully copied
-// to the destination.
-bool StrCpy(const char* src, char** dst_ptr) {
- if (dst_ptr == NULL)
- return false;
-
- char*& dst = *dst_ptr;
-
- delete[] dst;
- dst = NULL;
-
- if (src == NULL)
- return true;
-
- const size_t size = strlen(src) + 1;
-
- dst = new (std::nothrow) char[size]; // NOLINT
- if (dst == NULL)
- return false;
-
- strcpy(dst, src); // NOLINT
- return true;
-}
-} // namespace
-
-///////////////////////////////////////////////////////////////
-//
-// IMkvWriter Class
-
-IMkvWriter::IMkvWriter() {}
-
-IMkvWriter::~IMkvWriter() {}
-
-bool WriteEbmlHeader(IMkvWriter* writer, uint64 doc_type_version) {
- // Level 0
- uint64 size = EbmlElementSize(kMkvEBMLVersion, 1ULL);
- size += EbmlElementSize(kMkvEBMLReadVersion, 1ULL);
- size += EbmlElementSize(kMkvEBMLMaxIDLength, 4ULL);
- size += EbmlElementSize(kMkvEBMLMaxSizeLength, 8ULL);
- size += EbmlElementSize(kMkvDocType, "webm");
- size += EbmlElementSize(kMkvDocTypeVersion, doc_type_version);
- size += EbmlElementSize(kMkvDocTypeReadVersion, 2ULL);
-
- if (!WriteEbmlMasterElement(writer, kMkvEBML, size))
- return false;
- if (!WriteEbmlElement(writer, kMkvEBMLVersion, 1ULL))
- return false;
- if (!WriteEbmlElement(writer, kMkvEBMLReadVersion, 1ULL))
- return false;
- if (!WriteEbmlElement(writer, kMkvEBMLMaxIDLength, 4ULL))
- return false;
- if (!WriteEbmlElement(writer, kMkvEBMLMaxSizeLength, 8ULL))
- return false;
- if (!WriteEbmlElement(writer, kMkvDocType, "webm"))
- return false;
- if (!WriteEbmlElement(writer, kMkvDocTypeVersion, doc_type_version))
- return false;
- if (!WriteEbmlElement(writer, kMkvDocTypeReadVersion, 2ULL))
- return false;
-
- return true;
-}
-
-bool WriteEbmlHeader(IMkvWriter* writer) {
- return WriteEbmlHeader(writer, mkvmuxer::Segment::kDefaultDocTypeVersion);
-}
-
-bool ChunkedCopy(mkvparser::IMkvReader* source, mkvmuxer::IMkvWriter* dst,
- mkvmuxer::int64 start, int64 size) {
- // TODO(vigneshv): Check if this is a reasonable value.
- const uint32 kBufSize = 2048;
- uint8* buf = new uint8[kBufSize];
- int64 offset = start;
- while (size > 0) {
- const int64 read_len = (size > kBufSize) ? kBufSize : size;
- if (source->Read(offset, static_cast<long>(read_len), buf))
- return false;
- dst->Write(buf, static_cast<uint32>(read_len));
- offset += read_len;
- size -= read_len;
- }
- delete[] buf;
- return true;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// Frame Class
-
-Frame::Frame()
- : add_id_(0),
- additional_(NULL),
- additional_length_(0),
- duration_(0),
- frame_(NULL),
- is_key_(false),
- length_(0),
- track_number_(0),
- timestamp_(0),
- discard_padding_(0),
- reference_block_timestamp_(0),
- reference_block_timestamp_set_(false) {}
-
-Frame::~Frame() {
- delete[] frame_;
- delete[] additional_;
-}
-
-bool Frame::CopyFrom(const Frame& frame) {
- delete[] frame_;
- frame_ = NULL;
- length_ = 0;
- if (frame.length() > 0 && frame.frame() != NULL &&
- !Init(frame.frame(), frame.length())) {
- return false;
- }
- add_id_ = 0;
- delete[] additional_;
- additional_ = NULL;
- additional_length_ = 0;
- if (frame.additional_length() > 0 && frame.additional() != NULL &&
- !AddAdditionalData(frame.additional(), frame.additional_length(),
- frame.add_id())) {
- return false;
- }
- duration_ = frame.duration();
- is_key_ = frame.is_key();
- track_number_ = frame.track_number();
- timestamp_ = frame.timestamp();
- discard_padding_ = frame.discard_padding();
- return true;
-}
-
-bool Frame::Init(const uint8* frame, uint64 length) {
- uint8* const data =
- new (std::nothrow) uint8[static_cast<size_t>(length)]; // NOLINT
- if (!data)
- return false;
-
- delete[] frame_;
- frame_ = data;
- length_ = length;
-
- memcpy(frame_, frame, static_cast<size_t>(length_));
- return true;
-}
-
-bool Frame::AddAdditionalData(const uint8* additional, uint64 length,
- uint64 add_id) {
- uint8* const data =
- new (std::nothrow) uint8[static_cast<size_t>(length)]; // NOLINT
- if (!data)
- return false;
-
- delete[] additional_;
- additional_ = data;
- additional_length_ = length;
- add_id_ = add_id;
-
- memcpy(additional_, additional, static_cast<size_t>(additional_length_));
- return true;
-}
-
-bool Frame::IsValid() const {
- if (length_ == 0 || !frame_) {
- return false;
- }
- if ((additional_length_ != 0 && !additional_) ||
- (additional_ != NULL && additional_length_ == 0)) {
- return false;
- }
- if (track_number_ == 0 || track_number_ > kMaxTrackNumber) {
- return false;
- }
- if (!CanBeSimpleBlock() && !is_key_ && !reference_block_timestamp_set_) {
- return false;
- }
- return true;
-}
-
-bool Frame::CanBeSimpleBlock() const {
- return additional_ == NULL && discard_padding_ == 0 && duration_ == 0;
-}
-
-void Frame::set_reference_block_timestamp(int64 reference_block_timestamp) {
- reference_block_timestamp_ = reference_block_timestamp;
- reference_block_timestamp_set_ = true;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// CuePoint Class
-
-CuePoint::CuePoint()
- : time_(0),
- track_(0),
- cluster_pos_(0),
- block_number_(1),
- output_block_number_(true) {}
-
-CuePoint::~CuePoint() {}
-
-bool CuePoint::Write(IMkvWriter* writer) const {
- if (!writer || track_ < 1 || cluster_pos_ < 1)
- return false;
-
- uint64 size = EbmlElementSize(kMkvCueClusterPosition, cluster_pos_);
- size += EbmlElementSize(kMkvCueTrack, track_);
- if (output_block_number_ && block_number_ > 1)
- size += EbmlElementSize(kMkvCueBlockNumber, block_number_);
- const uint64 track_pos_size =
- EbmlMasterElementSize(kMkvCueTrackPositions, size) + size;
- const uint64 payload_size =
- EbmlElementSize(kMkvCueTime, time_) + track_pos_size;
-
- if (!WriteEbmlMasterElement(writer, kMkvCuePoint, payload_size))
- return false;
-
- const int64 payload_position = writer->Position();
- if (payload_position < 0)
- return false;
-
- if (!WriteEbmlElement(writer, kMkvCueTime, time_))
- return false;
-
- if (!WriteEbmlMasterElement(writer, kMkvCueTrackPositions, size))
- return false;
- if (!WriteEbmlElement(writer, kMkvCueTrack, track_))
- return false;
- if (!WriteEbmlElement(writer, kMkvCueClusterPosition, cluster_pos_))
- return false;
- if (output_block_number_ && block_number_ > 1)
- if (!WriteEbmlElement(writer, kMkvCueBlockNumber, block_number_))
- return false;
-
- const int64 stop_position = writer->Position();
- if (stop_position < 0)
- return false;
-
- if (stop_position - payload_position != static_cast<int64>(payload_size))
- return false;
-
- return true;
-}
-
-uint64 CuePoint::PayloadSize() const {
- uint64 size = EbmlElementSize(kMkvCueClusterPosition, cluster_pos_);
- size += EbmlElementSize(kMkvCueTrack, track_);
- if (output_block_number_ && block_number_ > 1)
- size += EbmlElementSize(kMkvCueBlockNumber, block_number_);
- const uint64 track_pos_size =
- EbmlMasterElementSize(kMkvCueTrackPositions, size) + size;
- const uint64 payload_size =
- EbmlElementSize(kMkvCueTime, time_) + track_pos_size;
-
- return payload_size;
-}
-
-uint64 CuePoint::Size() const {
- const uint64 payload_size = PayloadSize();
- return EbmlMasterElementSize(kMkvCuePoint, payload_size) + payload_size;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// Cues Class
-
-Cues::Cues()
- : cue_entries_capacity_(0),
- cue_entries_size_(0),
- cue_entries_(NULL),
- output_block_number_(true) {}
-
-Cues::~Cues() {
- if (cue_entries_) {
- for (int32 i = 0; i < cue_entries_size_; ++i) {
- CuePoint* const cue = cue_entries_[i];
- delete cue;
- }
- delete[] cue_entries_;
- }
-}
-
-bool Cues::AddCue(CuePoint* cue) {
- if (!cue)
- return false;
-
- if ((cue_entries_size_ + 1) > cue_entries_capacity_) {
- // Add more CuePoints.
- const int32 new_capacity =
- (!cue_entries_capacity_) ? 2 : cue_entries_capacity_ * 2;
-
- if (new_capacity < 1)
- return false;
-
- CuePoint** const cues =
- new (std::nothrow) CuePoint*[new_capacity]; // NOLINT
- if (!cues)
- return false;
-
- for (int32 i = 0; i < cue_entries_size_; ++i) {
- cues[i] = cue_entries_[i];
- }
-
- delete[] cue_entries_;
-
- cue_entries_ = cues;
- cue_entries_capacity_ = new_capacity;
- }
-
- cue->set_output_block_number(output_block_number_);
- cue_entries_[cue_entries_size_++] = cue;
- return true;
-}
-
-CuePoint* Cues::GetCueByIndex(int32 index) const {
- if (cue_entries_ == NULL)
- return NULL;
-
- if (index >= cue_entries_size_)
- return NULL;
-
- return cue_entries_[index];
-}
-
-uint64 Cues::Size() {
- uint64 size = 0;
- for (int32 i = 0; i < cue_entries_size_; ++i)
- size += GetCueByIndex(i)->Size();
- size += EbmlMasterElementSize(kMkvCues, size);
- return size;
-}
-
-bool Cues::Write(IMkvWriter* writer) const {
- if (!writer)
- return false;
-
- uint64 size = 0;
- for (int32 i = 0; i < cue_entries_size_; ++i) {
- const CuePoint* const cue = GetCueByIndex(i);
-
- if (!cue)
- return false;
-
- size += cue->Size();
- }
-
- if (!WriteEbmlMasterElement(writer, kMkvCues, size))
- return false;
-
- const int64 payload_position = writer->Position();
- if (payload_position < 0)
- return false;
-
- for (int32 i = 0; i < cue_entries_size_; ++i) {
- const CuePoint* const cue = GetCueByIndex(i);
-
- if (!cue->Write(writer))
- return false;
- }
-
- const int64 stop_position = writer->Position();
- if (stop_position < 0)
- return false;
-
- if (stop_position - payload_position != static_cast<int64>(size))
- return false;
-
- return true;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// ContentEncAESSettings Class
-
-ContentEncAESSettings::ContentEncAESSettings() : cipher_mode_(kCTR) {}
-
-uint64 ContentEncAESSettings::Size() const {
- const uint64 payload = PayloadSize();
- const uint64 size =
- EbmlMasterElementSize(kMkvContentEncAESSettings, payload) + payload;
- return size;
-}
-
-bool ContentEncAESSettings::Write(IMkvWriter* writer) const {
- const uint64 payload = PayloadSize();
-
- if (!WriteEbmlMasterElement(writer, kMkvContentEncAESSettings, payload))
- return false;
-
- const int64 payload_position = writer->Position();
- if (payload_position < 0)
- return false;
-
- if (!WriteEbmlElement(writer, kMkvAESSettingsCipherMode, cipher_mode_))
- return false;
-
- const int64 stop_position = writer->Position();
- if (stop_position < 0 ||
- stop_position - payload_position != static_cast<int64>(payload))
- return false;
-
- return true;
-}
-
-uint64 ContentEncAESSettings::PayloadSize() const {
- uint64 size = EbmlElementSize(kMkvAESSettingsCipherMode, cipher_mode_);
- return size;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// ContentEncoding Class
-
-ContentEncoding::ContentEncoding()
- : enc_algo_(5),
- enc_key_id_(NULL),
- encoding_order_(0),
- encoding_scope_(1),
- encoding_type_(1),
- enc_key_id_length_(0) {}
-
-ContentEncoding::~ContentEncoding() { delete[] enc_key_id_; }
-
-bool ContentEncoding::SetEncryptionID(const uint8* id, uint64 length) {
- if (!id || length < 1)
- return false;
-
- delete[] enc_key_id_;
-
- enc_key_id_ =
- new (std::nothrow) uint8[static_cast<size_t>(length)]; // NOLINT
- if (!enc_key_id_)
- return false;
-
- memcpy(enc_key_id_, id, static_cast<size_t>(length));
- enc_key_id_length_ = length;
-
- return true;
-}
-
-uint64 ContentEncoding::Size() const {
- const uint64 encryption_size = EncryptionSize();
- const uint64 encoding_size = EncodingSize(0, encryption_size);
- const uint64 encodings_size =
- EbmlMasterElementSize(kMkvContentEncoding, encoding_size) + encoding_size;
-
- return encodings_size;
-}
-
-bool ContentEncoding::Write(IMkvWriter* writer) const {
- const uint64 encryption_size = EncryptionSize();
- const uint64 encoding_size = EncodingSize(0, encryption_size);
- const uint64 size =
- EbmlMasterElementSize(kMkvContentEncoding, encoding_size) + encoding_size;
-
- const int64 payload_position = writer->Position();
- if (payload_position < 0)
- return false;
-
- if (!WriteEbmlMasterElement(writer, kMkvContentEncoding, encoding_size))
- return false;
- if (!WriteEbmlElement(writer, kMkvContentEncodingOrder, encoding_order_))
- return false;
- if (!WriteEbmlElement(writer, kMkvContentEncodingScope, encoding_scope_))
- return false;
- if (!WriteEbmlElement(writer, kMkvContentEncodingType, encoding_type_))
- return false;
-
- if (!WriteEbmlMasterElement(writer, kMkvContentEncryption, encryption_size))
- return false;
- if (!WriteEbmlElement(writer, kMkvContentEncAlgo, enc_algo_))
- return false;
- if (!WriteEbmlElement(writer, kMkvContentEncKeyID, enc_key_id_,
- enc_key_id_length_))
- return false;
-
- if (!enc_aes_settings_.Write(writer))
- return false;
-
- const int64 stop_position = writer->Position();
- if (stop_position < 0 ||
- stop_position - payload_position != static_cast<int64>(size))
- return false;
-
- return true;
-}
-
-uint64 ContentEncoding::EncodingSize(uint64 compresion_size,
- uint64 encryption_size) const {
- // TODO(fgalligan): Add support for compression settings.
- if (compresion_size != 0)
- return 0;
-
- uint64 encoding_size = 0;
-
- if (encryption_size > 0) {
- encoding_size +=
- EbmlMasterElementSize(kMkvContentEncryption, encryption_size) +
- encryption_size;
- }
- encoding_size += EbmlElementSize(kMkvContentEncodingType, encoding_type_);
- encoding_size += EbmlElementSize(kMkvContentEncodingScope, encoding_scope_);
- encoding_size += EbmlElementSize(kMkvContentEncodingOrder, encoding_order_);
-
- return encoding_size;
-}
-
-uint64 ContentEncoding::EncryptionSize() const {
- const uint64 aes_size = enc_aes_settings_.Size();
-
- uint64 encryption_size =
- EbmlElementSize(kMkvContentEncKeyID, enc_key_id_, enc_key_id_length_);
- encryption_size += EbmlElementSize(kMkvContentEncAlgo, enc_algo_);
-
- return encryption_size + aes_size;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// Track Class
-
-Track::Track(unsigned int* seed)
- : codec_id_(NULL),
- codec_private_(NULL),
- language_(NULL),
- max_block_additional_id_(0),
- name_(NULL),
- number_(0),
- type_(0),
- uid_(MakeUID(seed)),
- codec_delay_(0),
- seek_pre_roll_(0),
- default_duration_(0),
- codec_private_length_(0),
- content_encoding_entries_(NULL),
- content_encoding_entries_size_(0) {}
-
-Track::~Track() {
- delete[] codec_id_;
- delete[] codec_private_;
- delete[] language_;
- delete[] name_;
-
- if (content_encoding_entries_) {
- for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
- ContentEncoding* const encoding = content_encoding_entries_[i];
- delete encoding;
- }
- delete[] content_encoding_entries_;
- }
-}
-
-bool Track::AddContentEncoding() {
- const uint32 count = content_encoding_entries_size_ + 1;
-
- ContentEncoding** const content_encoding_entries =
- new (std::nothrow) ContentEncoding*[count]; // NOLINT
- if (!content_encoding_entries)
- return false;
-
- ContentEncoding* const content_encoding =
- new (std::nothrow) ContentEncoding(); // NOLINT
- if (!content_encoding) {
- delete[] content_encoding_entries;
- return false;
- }
-
- for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
- content_encoding_entries[i] = content_encoding_entries_[i];
- }
-
- delete[] content_encoding_entries_;
-
- content_encoding_entries_ = content_encoding_entries;
- content_encoding_entries_[content_encoding_entries_size_] = content_encoding;
- content_encoding_entries_size_ = count;
- return true;
-}
-
-ContentEncoding* Track::GetContentEncodingByIndex(uint32 index) const {
- if (content_encoding_entries_ == NULL)
- return NULL;
-
- if (index >= content_encoding_entries_size_)
- return NULL;
-
- return content_encoding_entries_[index];
-}
-
-uint64 Track::PayloadSize() const {
- uint64 size = EbmlElementSize(kMkvTrackNumber, number_);
- size += EbmlElementSize(kMkvTrackUID, uid_);
- size += EbmlElementSize(kMkvTrackType, type_);
- if (codec_id_)
- size += EbmlElementSize(kMkvCodecID, codec_id_);
- if (codec_private_)
- size += EbmlElementSize(kMkvCodecPrivate, codec_private_,
- codec_private_length_);
- if (language_)
- size += EbmlElementSize(kMkvLanguage, language_);
- if (name_)
- size += EbmlElementSize(kMkvName, name_);
- if (max_block_additional_id_)
- size += EbmlElementSize(kMkvMaxBlockAdditionID, max_block_additional_id_);
- if (codec_delay_)
- size += EbmlElementSize(kMkvCodecDelay, codec_delay_);
- if (seek_pre_roll_)
- size += EbmlElementSize(kMkvSeekPreRoll, seek_pre_roll_);
- if (default_duration_)
- size += EbmlElementSize(kMkvDefaultDuration, default_duration_);
-
- if (content_encoding_entries_size_ > 0) {
- uint64 content_encodings_size = 0;
- for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
- ContentEncoding* const encoding = content_encoding_entries_[i];
- content_encodings_size += encoding->Size();
- }
-
- size +=
- EbmlMasterElementSize(kMkvContentEncodings, content_encodings_size) +
- content_encodings_size;
- }
-
- return size;
-}
-
-uint64 Track::Size() const {
- uint64 size = PayloadSize();
- size += EbmlMasterElementSize(kMkvTrackEntry, size);
- return size;
-}
-
-bool Track::Write(IMkvWriter* writer) const {
- if (!writer)
- return false;
-
- // mandatory elements without a default value.
- if (!type_ || !codec_id_)
- return false;
-
- // |size| may be bigger than what is written out in this function because
- // derived classes may write out more data in the Track element.
- const uint64 payload_size = PayloadSize();
-
- if (!WriteEbmlMasterElement(writer, kMkvTrackEntry, payload_size))
- return false;
-
- uint64 size = EbmlElementSize(kMkvTrackNumber, number_);
- size += EbmlElementSize(kMkvTrackUID, uid_);
- size += EbmlElementSize(kMkvTrackType, type_);
- if (codec_id_)
- size += EbmlElementSize(kMkvCodecID, codec_id_);
- if (codec_private_)
- size += EbmlElementSize(kMkvCodecPrivate, codec_private_,
- codec_private_length_);
- if (language_)
- size += EbmlElementSize(kMkvLanguage, language_);
- if (name_)
- size += EbmlElementSize(kMkvName, name_);
- if (max_block_additional_id_)
- size += EbmlElementSize(kMkvMaxBlockAdditionID, max_block_additional_id_);
- if (codec_delay_)
- size += EbmlElementSize(kMkvCodecDelay, codec_delay_);
- if (seek_pre_roll_)
- size += EbmlElementSize(kMkvSeekPreRoll, seek_pre_roll_);
- if (default_duration_)
- size += EbmlElementSize(kMkvDefaultDuration, default_duration_);
-
- const int64 payload_position = writer->Position();
- if (payload_position < 0)
- return false;
-
- if (!WriteEbmlElement(writer, kMkvTrackNumber, number_))
- return false;
- if (!WriteEbmlElement(writer, kMkvTrackUID, uid_))
- return false;
- if (!WriteEbmlElement(writer, kMkvTrackType, type_))
- return false;
- if (max_block_additional_id_) {
- if (!WriteEbmlElement(writer, kMkvMaxBlockAdditionID,
- max_block_additional_id_)) {
- return false;
- }
- }
- if (codec_delay_) {
- if (!WriteEbmlElement(writer, kMkvCodecDelay, codec_delay_))
- return false;
- }
- if (seek_pre_roll_) {
- if (!WriteEbmlElement(writer, kMkvSeekPreRoll, seek_pre_roll_))
- return false;
- }
- if (default_duration_) {
- if (!WriteEbmlElement(writer, kMkvDefaultDuration, default_duration_))
- return false;
- }
- if (codec_id_) {
- if (!WriteEbmlElement(writer, kMkvCodecID, codec_id_))
- return false;
- }
- if (codec_private_) {
- if (!WriteEbmlElement(writer, kMkvCodecPrivate, codec_private_,
- codec_private_length_))
- return false;
- }
- if (language_) {
- if (!WriteEbmlElement(writer, kMkvLanguage, language_))
- return false;
- }
- if (name_) {
- if (!WriteEbmlElement(writer, kMkvName, name_))
- return false;
- }
-
- int64 stop_position = writer->Position();
- if (stop_position < 0 ||
- stop_position - payload_position != static_cast<int64>(size))
- return false;
-
- if (content_encoding_entries_size_ > 0) {
- uint64 content_encodings_size = 0;
- for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
- ContentEncoding* const encoding = content_encoding_entries_[i];
- content_encodings_size += encoding->Size();
- }
-
- if (!WriteEbmlMasterElement(writer, kMkvContentEncodings,
- content_encodings_size))
- return false;
-
- for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
- ContentEncoding* const encoding = content_encoding_entries_[i];
- if (!encoding->Write(writer))
- return false;
- }
- }
-
- stop_position = writer->Position();
- if (stop_position < 0)
- return false;
- return true;
-}
-
-bool Track::SetCodecPrivate(const uint8* codec_private, uint64 length) {
- if (!codec_private || length < 1)
- return false;
-
- delete[] codec_private_;
-
- codec_private_ =
- new (std::nothrow) uint8[static_cast<size_t>(length)]; // NOLINT
- if (!codec_private_)
- return false;
-
- memcpy(codec_private_, codec_private, static_cast<size_t>(length));
- codec_private_length_ = length;
-
- return true;
-}
-
-void Track::set_codec_id(const char* codec_id) {
- if (codec_id) {
- delete[] codec_id_;
-
- const size_t length = strlen(codec_id) + 1;
- codec_id_ = new (std::nothrow) char[length]; // NOLINT
- if (codec_id_) {
-#ifdef _MSC_VER
- strcpy_s(codec_id_, length, codec_id);
-#else
- strcpy(codec_id_, codec_id);
-#endif
- }
- }
-}
-
-// TODO(fgalligan): Vet the language parameter.
-void Track::set_language(const char* language) {
- if (language) {
- delete[] language_;
-
- const size_t length = strlen(language) + 1;
- language_ = new (std::nothrow) char[length]; // NOLINT
- if (language_) {
-#ifdef _MSC_VER
- strcpy_s(language_, length, language);
-#else
- strcpy(language_, language);
-#endif
- }
- }
-}
-
-void Track::set_name(const char* name) {
- if (name) {
- delete[] name_;
-
- const size_t length = strlen(name) + 1;
- name_ = new (std::nothrow) char[length]; // NOLINT
- if (name_) {
-#ifdef _MSC_VER
- strcpy_s(name_, length, name);
-#else
- strcpy(name_, name);
-#endif
- }
- }
-}
-
-///////////////////////////////////////////////////////////////
-//
-// VideoTrack Class
-
-VideoTrack::VideoTrack(unsigned int* seed)
- : Track(seed),
- display_height_(0),
- display_width_(0),
- crop_left_(0),
- crop_right_(0),
- crop_top_(0),
- crop_bottom_(0),
- frame_rate_(0.0),
- height_(0),
- stereo_mode_(0),
- alpha_mode_(0),
- width_(0) {}
-
-VideoTrack::~VideoTrack() {}
-
-bool VideoTrack::SetStereoMode(uint64 stereo_mode) {
- if (stereo_mode != kMono && stereo_mode != kSideBySideLeftIsFirst &&
- stereo_mode != kTopBottomRightIsFirst &&
- stereo_mode != kTopBottomLeftIsFirst &&
- stereo_mode != kSideBySideRightIsFirst)
- return false;
-
- stereo_mode_ = stereo_mode;
- return true;
-}
-
-bool VideoTrack::SetAlphaMode(uint64 alpha_mode) {
- if (alpha_mode != kNoAlpha && alpha_mode != kAlpha)
- return false;
-
- alpha_mode_ = alpha_mode;
- return true;
-}
-
-uint64 VideoTrack::PayloadSize() const {
- const uint64 parent_size = Track::PayloadSize();
-
- uint64 size = VideoPayloadSize();
- size += EbmlMasterElementSize(kMkvVideo, size);
-
- return parent_size + size;
-}
-
-bool VideoTrack::Write(IMkvWriter* writer) const {
- if (!Track::Write(writer))
- return false;
-
- const uint64 size = VideoPayloadSize();
-
- if (!WriteEbmlMasterElement(writer, kMkvVideo, size))
- return false;
-
- const int64 payload_position = writer->Position();
- if (payload_position < 0)
- return false;
-
- if (!WriteEbmlElement(writer, kMkvPixelWidth, width_))
- return false;
- if (!WriteEbmlElement(writer, kMkvPixelHeight, height_))
- return false;
- if (display_width_ > 0) {
- if (!WriteEbmlElement(writer, kMkvDisplayWidth, display_width_))
- return false;
- }
- if (display_height_ > 0) {
- if (!WriteEbmlElement(writer, kMkvDisplayHeight, display_height_))
- return false;
- }
- if (crop_left_ > 0) {
- if (!WriteEbmlElement(writer, kMkvPixelCropLeft, crop_left_))
- return false;
- }
- if (crop_right_ > 0) {
- if (!WriteEbmlElement(writer, kMkvPixelCropRight, crop_right_))
- return false;
- }
- if (crop_top_ > 0) {
- if (!WriteEbmlElement(writer, kMkvPixelCropTop, crop_top_))
- return false;
- }
- if (crop_bottom_ > 0) {
- if (!WriteEbmlElement(writer, kMkvPixelCropBottom, crop_bottom_))
- return false;
- }
- if (stereo_mode_ > kMono) {
- if (!WriteEbmlElement(writer, kMkvStereoMode, stereo_mode_))
- return false;
- }
- if (alpha_mode_ > kNoAlpha) {
- if (!WriteEbmlElement(writer, kMkvAlphaMode, alpha_mode_))
- return false;
- }
- if (frame_rate_ > 0.0) {
- if (!WriteEbmlElement(writer, kMkvFrameRate,
- static_cast<float>(frame_rate_))) {
- return false;
- }
- }
-
- const int64 stop_position = writer->Position();
- if (stop_position < 0 ||
- stop_position - payload_position != static_cast<int64>(size)) {
- return false;
- }
-
- return true;
-}
-
-uint64 VideoTrack::VideoPayloadSize() const {
- uint64 size = EbmlElementSize(kMkvPixelWidth, width_);
- size += EbmlElementSize(kMkvPixelHeight, height_);
- if (display_width_ > 0)
- size += EbmlElementSize(kMkvDisplayWidth, display_width_);
- if (display_height_ > 0)
- size += EbmlElementSize(kMkvDisplayHeight, display_height_);
- if (crop_left_ > 0)
- size += EbmlElementSize(kMkvPixelCropLeft, crop_left_);
- if (crop_right_ > 0)
- size += EbmlElementSize(kMkvPixelCropRight, crop_right_);
- if (crop_top_ > 0)
- size += EbmlElementSize(kMkvPixelCropTop, crop_top_);
- if (crop_bottom_ > 0)
- size += EbmlElementSize(kMkvPixelCropBottom, crop_bottom_);
- if (stereo_mode_ > kMono)
- size += EbmlElementSize(kMkvStereoMode, stereo_mode_);
- if (alpha_mode_ > kNoAlpha)
- size += EbmlElementSize(kMkvAlphaMode, alpha_mode_);
- if (frame_rate_ > 0.0)
- size += EbmlElementSize(kMkvFrameRate, static_cast<float>(frame_rate_));
-
- return size;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// AudioTrack Class
-
-AudioTrack::AudioTrack(unsigned int* seed)
- : Track(seed), bit_depth_(0), channels_(1), sample_rate_(0.0) {}
-
-AudioTrack::~AudioTrack() {}
-
-uint64 AudioTrack::PayloadSize() const {
- const uint64 parent_size = Track::PayloadSize();
-
- uint64 size =
- EbmlElementSize(kMkvSamplingFrequency, static_cast<float>(sample_rate_));
- size += EbmlElementSize(kMkvChannels, channels_);
- if (bit_depth_ > 0)
- size += EbmlElementSize(kMkvBitDepth, bit_depth_);
- size += EbmlMasterElementSize(kMkvAudio, size);
-
- return parent_size + size;
-}
-
-bool AudioTrack::Write(IMkvWriter* writer) const {
- if (!Track::Write(writer))
- return false;
-
- // Calculate AudioSettings size.
- uint64 size =
- EbmlElementSize(kMkvSamplingFrequency, static_cast<float>(sample_rate_));
- size += EbmlElementSize(kMkvChannels, channels_);
- if (bit_depth_ > 0)
- size += EbmlElementSize(kMkvBitDepth, bit_depth_);
-
- if (!WriteEbmlMasterElement(writer, kMkvAudio, size))
- return false;
-
- const int64 payload_position = writer->Position();
- if (payload_position < 0)
- return false;
-
- if (!WriteEbmlElement(writer, kMkvSamplingFrequency,
- static_cast<float>(sample_rate_)))
- return false;
- if (!WriteEbmlElement(writer, kMkvChannels, channels_))
- return false;
- if (bit_depth_ > 0)
- if (!WriteEbmlElement(writer, kMkvBitDepth, bit_depth_))
- return false;
-
- const int64 stop_position = writer->Position();
- if (stop_position < 0 ||
- stop_position - payload_position != static_cast<int64>(size))
- return false;
-
- return true;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// Tracks Class
-
-const char Tracks::kOpusCodecId[] = "A_OPUS";
-const char Tracks::kVorbisCodecId[] = "A_VORBIS";
-const char Tracks::kVp8CodecId[] = "V_VP8";
-const char Tracks::kVp9CodecId[] = "V_VP9";
-const char Tracks::kVp10CodecId[] = "V_VP10";
-
-Tracks::Tracks() : track_entries_(NULL), track_entries_size_(0) {}
-
-Tracks::~Tracks() {
- if (track_entries_) {
- for (uint32 i = 0; i < track_entries_size_; ++i) {
- Track* const track = track_entries_[i];
- delete track;
- }
- delete[] track_entries_;
- }
-}
-
-bool Tracks::AddTrack(Track* track, int32 number) {
- if (number < 0)
- return false;
-
- // This muxer only supports track numbers in the range [1, 126], in
- // order to be able (to use Matroska integer representation) to
- // serialize the block header (of which the track number is a part)
- // for a frame using exactly 4 bytes.
-
- if (number > 0x7E)
- return false;
-
- uint32 track_num = number;
-
- if (track_num > 0) {
- // Check to make sure a track does not already have |track_num|.
- for (uint32 i = 0; i < track_entries_size_; ++i) {
- if (track_entries_[i]->number() == track_num)
- return false;
- }
- }
-
- const uint32 count = track_entries_size_ + 1;
-
- Track** const track_entries = new (std::nothrow) Track*[count]; // NOLINT
- if (!track_entries)
- return false;
-
- for (uint32 i = 0; i < track_entries_size_; ++i) {
- track_entries[i] = track_entries_[i];
- }
-
- delete[] track_entries_;
-
- // Find the lowest availible track number > 0.
- if (track_num == 0) {
- track_num = count;
-
- // Check to make sure a track does not already have |track_num|.
- bool exit = false;
- do {
- exit = true;
- for (uint32 i = 0; i < track_entries_size_; ++i) {
- if (track_entries[i]->number() == track_num) {
- track_num++;
- exit = false;
- break;
- }
- }
- } while (!exit);
- }
- track->set_number(track_num);
-
- track_entries_ = track_entries;
- track_entries_[track_entries_size_] = track;
- track_entries_size_ = count;
- return true;
-}
-
-const Track* Tracks::GetTrackByIndex(uint32 index) const {
- if (track_entries_ == NULL)
- return NULL;
-
- if (index >= track_entries_size_)
- return NULL;
-
- return track_entries_[index];
-}
-
-Track* Tracks::GetTrackByNumber(uint64 track_number) const {
- const int32 count = track_entries_size();
- for (int32 i = 0; i < count; ++i) {
- if (track_entries_[i]->number() == track_number)
- return track_entries_[i];
- }
-
- return NULL;
-}
-
-bool Tracks::TrackIsAudio(uint64 track_number) const {
- const Track* const track = GetTrackByNumber(track_number);
-
- if (track->type() == kAudio)
- return true;
-
- return false;
-}
-
-bool Tracks::TrackIsVideo(uint64 track_number) const {
- const Track* const track = GetTrackByNumber(track_number);
-
- if (track->type() == kVideo)
- return true;
-
- return false;
-}
-
-bool Tracks::Write(IMkvWriter* writer) const {
- uint64 size = 0;
- const int32 count = track_entries_size();
- for (int32 i = 0; i < count; ++i) {
- const Track* const track = GetTrackByIndex(i);
-
- if (!track)
- return false;
-
- size += track->Size();
- }
-
- if (!WriteEbmlMasterElement(writer, kMkvTracks, size))
- return false;
-
- const int64 payload_position = writer->Position();
- if (payload_position < 0)
- return false;
-
- for (int32 i = 0; i < count; ++i) {
- const Track* const track = GetTrackByIndex(i);
- if (!track->Write(writer))
- return false;
- }
-
- const int64 stop_position = writer->Position();
- if (stop_position < 0 ||
- stop_position - payload_position != static_cast<int64>(size))
- return false;
-
- return true;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// Chapter Class
-
-bool Chapter::set_id(const char* id) { return StrCpy(id, &id_); }
-
-void Chapter::set_time(const Segment& segment, uint64 start_ns, uint64 end_ns) {
- const SegmentInfo* const info = segment.GetSegmentInfo();
- const uint64 timecode_scale = info->timecode_scale();
- start_timecode_ = start_ns / timecode_scale;
- end_timecode_ = end_ns / timecode_scale;
-}
-
-bool Chapter::add_string(const char* title, const char* language,
- const char* country) {
- if (!ExpandDisplaysArray())
- return false;
-
- Display& d = displays_[displays_count_++];
- d.Init();
-
- if (!d.set_title(title))
- return false;
-
- if (!d.set_language(language))
- return false;
-
- if (!d.set_country(country))
- return false;
-
- return true;
-}
-
-Chapter::Chapter() {
- // This ctor only constructs the object. Proper initialization is
- // done in Init() (called in Chapters::AddChapter()). The only
- // reason we bother implementing this ctor is because we had to
- // declare it as private (along with the dtor), in order to prevent
- // clients from creating Chapter instances (a privelege we grant
- // only to the Chapters class). Doing no initialization here also
- // means that creating arrays of chapter objects is more efficient,
- // because we only initialize each new chapter object as it becomes
- // active on the array.
-}
-
-Chapter::~Chapter() {}
-
-void Chapter::Init(unsigned int* seed) {
- id_ = NULL;
- start_timecode_ = 0;
- end_timecode_ = 0;
- displays_ = NULL;
- displays_size_ = 0;
- displays_count_ = 0;
- uid_ = MakeUID(seed);
-}
-
-void Chapter::ShallowCopy(Chapter* dst) const {
- dst->id_ = id_;
- dst->start_timecode_ = start_timecode_;
- dst->end_timecode_ = end_timecode_;
- dst->uid_ = uid_;
- dst->displays_ = displays_;
- dst->displays_size_ = displays_size_;
- dst->displays_count_ = displays_count_;
-}
-
-void Chapter::Clear() {
- StrCpy(NULL, &id_);
-
- while (displays_count_ > 0) {
- Display& d = displays_[--displays_count_];
- d.Clear();
- }
-
- delete[] displays_;
- displays_ = NULL;
-
- displays_size_ = 0;
-}
-
-bool Chapter::ExpandDisplaysArray() {
- if (displays_size_ > displays_count_)
- return true; // nothing to do yet
-
- const int size = (displays_size_ == 0) ? 1 : 2 * displays_size_;
-
- Display* const displays = new (std::nothrow) Display[size]; // NOLINT
- if (displays == NULL)
- return false;
-
- for (int idx = 0; idx < displays_count_; ++idx) {
- displays[idx] = displays_[idx]; // shallow copy
- }
-
- delete[] displays_;
-
- displays_ = displays;
- displays_size_ = size;
-
- return true;
-}
-
-uint64 Chapter::WriteAtom(IMkvWriter* writer) const {
- uint64 payload_size = EbmlElementSize(kMkvChapterStringUID, id_) +
- EbmlElementSize(kMkvChapterUID, uid_) +
- EbmlElementSize(kMkvChapterTimeStart, start_timecode_) +
- EbmlElementSize(kMkvChapterTimeEnd, end_timecode_);
-
- for (int idx = 0; idx < displays_count_; ++idx) {
- const Display& d = displays_[idx];
- payload_size += d.WriteDisplay(NULL);
- }
-
- const uint64 atom_size =
- EbmlMasterElementSize(kMkvChapterAtom, payload_size) + payload_size;
-
- if (writer == NULL)
- return atom_size;
-
- const int64 start = writer->Position();
-
- if (!WriteEbmlMasterElement(writer, kMkvChapterAtom, payload_size))
- return 0;
-
- if (!WriteEbmlElement(writer, kMkvChapterStringUID, id_))
- return 0;
-
- if (!WriteEbmlElement(writer, kMkvChapterUID, uid_))
- return 0;
-
- if (!WriteEbmlElement(writer, kMkvChapterTimeStart, start_timecode_))
- return 0;
-
- if (!WriteEbmlElement(writer, kMkvChapterTimeEnd, end_timecode_))
- return 0;
-
- for (int idx = 0; idx < displays_count_; ++idx) {
- const Display& d = displays_[idx];
-
- if (!d.WriteDisplay(writer))
- return 0;
- }
-
- const int64 stop = writer->Position();
-
- if (stop >= start && uint64(stop - start) != atom_size)
- return 0;
-
- return atom_size;
-}
-
-void Chapter::Display::Init() {
- title_ = NULL;
- language_ = NULL;
- country_ = NULL;
-}
-
-void Chapter::Display::Clear() {
- StrCpy(NULL, &title_);
- StrCpy(NULL, &language_);
- StrCpy(NULL, &country_);
-}
-
-bool Chapter::Display::set_title(const char* title) {
- return StrCpy(title, &title_);
-}
-
-bool Chapter::Display::set_language(const char* language) {
- return StrCpy(language, &language_);
-}
-
-bool Chapter::Display::set_country(const char* country) {
- return StrCpy(country, &country_);
-}
-
-uint64 Chapter::Display::WriteDisplay(IMkvWriter* writer) const {
- uint64 payload_size = EbmlElementSize(kMkvChapString, title_);
-
- if (language_)
- payload_size += EbmlElementSize(kMkvChapLanguage, language_);
-
- if (country_)
- payload_size += EbmlElementSize(kMkvChapCountry, country_);
-
- const uint64 display_size =
- EbmlMasterElementSize(kMkvChapterDisplay, payload_size) + payload_size;
-
- if (writer == NULL)
- return display_size;
-
- const int64 start = writer->Position();
-
- if (!WriteEbmlMasterElement(writer, kMkvChapterDisplay, payload_size))
- return 0;
-
- if (!WriteEbmlElement(writer, kMkvChapString, title_))
- return 0;
-
- if (language_) {
- if (!WriteEbmlElement(writer, kMkvChapLanguage, language_))
- return 0;
- }
-
- if (country_) {
- if (!WriteEbmlElement(writer, kMkvChapCountry, country_))
- return 0;
- }
-
- const int64 stop = writer->Position();
-
- if (stop >= start && uint64(stop - start) != display_size)
- return 0;
-
- return display_size;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// Chapters Class
-
-Chapters::Chapters() : chapters_size_(0), chapters_count_(0), chapters_(NULL) {}
-
-Chapters::~Chapters() {
- while (chapters_count_ > 0) {
- Chapter& chapter = chapters_[--chapters_count_];
- chapter.Clear();
- }
-
- delete[] chapters_;
- chapters_ = NULL;
-}
-
-int Chapters::Count() const { return chapters_count_; }
-
-Chapter* Chapters::AddChapter(unsigned int* seed) {
- if (!ExpandChaptersArray())
- return NULL;
-
- Chapter& chapter = chapters_[chapters_count_++];
- chapter.Init(seed);
-
- return &chapter;
-}
-
-bool Chapters::Write(IMkvWriter* writer) const {
- if (writer == NULL)
- return false;
-
- const uint64 payload_size = WriteEdition(NULL); // return size only
-
- if (!WriteEbmlMasterElement(writer, kMkvChapters, payload_size))
- return false;
-
- const int64 start = writer->Position();
-
- if (WriteEdition(writer) == 0) // error
- return false;
-
- const int64 stop = writer->Position();
-
- if (stop >= start && uint64(stop - start) != payload_size)
- return false;
-
- return true;
-}
-
-bool Chapters::ExpandChaptersArray() {
- if (chapters_size_ > chapters_count_)
- return true; // nothing to do yet
-
- const int size = (chapters_size_ == 0) ? 1 : 2 * chapters_size_;
-
- Chapter* const chapters = new (std::nothrow) Chapter[size]; // NOLINT
- if (chapters == NULL)
- return false;
-
- for (int idx = 0; idx < chapters_count_; ++idx) {
- const Chapter& src = chapters_[idx];
- Chapter* const dst = chapters + idx;
- src.ShallowCopy(dst);
- }
-
- delete[] chapters_;
-
- chapters_ = chapters;
- chapters_size_ = size;
-
- return true;
-}
-
-uint64 Chapters::WriteEdition(IMkvWriter* writer) const {
- uint64 payload_size = 0;
-
- for (int idx = 0; idx < chapters_count_; ++idx) {
- const Chapter& chapter = chapters_[idx];
- payload_size += chapter.WriteAtom(NULL);
- }
-
- const uint64 edition_size =
- EbmlMasterElementSize(kMkvEditionEntry, payload_size) + payload_size;
-
- if (writer == NULL) // return size only
- return edition_size;
-
- const int64 start = writer->Position();
-
- if (!WriteEbmlMasterElement(writer, kMkvEditionEntry, payload_size))
- return 0; // error
-
- for (int idx = 0; idx < chapters_count_; ++idx) {
- const Chapter& chapter = chapters_[idx];
-
- const uint64 chapter_size = chapter.WriteAtom(writer);
- if (chapter_size == 0) // error
- return 0;
- }
-
- const int64 stop = writer->Position();
-
- if (stop >= start && uint64(stop - start) != edition_size)
- return 0;
-
- return edition_size;
-}
-
-// Tag Class
-
-bool Tag::add_simple_tag(const char* tag_name, const char* tag_string) {
- if (!ExpandSimpleTagsArray())
- return false;
-
- SimpleTag& st = simple_tags_[simple_tags_count_++];
- st.Init();
-
- if (!st.set_tag_name(tag_name))
- return false;
-
- if (!st.set_tag_string(tag_string))
- return false;
-
- return true;
-}
-
-Tag::Tag() {
- simple_tags_ = NULL;
- simple_tags_size_ = 0;
- simple_tags_count_ = 0;
-}
-
-Tag::~Tag() {}
-
-void Tag::ShallowCopy(Tag* dst) const {
- dst->simple_tags_ = simple_tags_;
- dst->simple_tags_size_ = simple_tags_size_;
- dst->simple_tags_count_ = simple_tags_count_;
-}
-
-void Tag::Clear() {
- while (simple_tags_count_ > 0) {
- SimpleTag& st = simple_tags_[--simple_tags_count_];
- st.Clear();
- }
-
- delete[] simple_tags_;
- simple_tags_ = NULL;
-
- simple_tags_size_ = 0;
-}
-
-bool Tag::ExpandSimpleTagsArray() {
- if (simple_tags_size_ > simple_tags_count_)
- return true; // nothing to do yet
-
- const int size = (simple_tags_size_ == 0) ? 1 : 2 * simple_tags_size_;
-
- SimpleTag* const simple_tags = new (std::nothrow) SimpleTag[size]; // NOLINT
- if (simple_tags == NULL)
- return false;
-
- for (int idx = 0; idx < simple_tags_count_; ++idx) {
- simple_tags[idx] = simple_tags_[idx]; // shallow copy
- }
-
- delete[] simple_tags_;
-
- simple_tags_ = simple_tags;
- simple_tags_size_ = size;
-
- return true;
-}
-
-uint64 Tag::Write(IMkvWriter* writer) const {
- uint64 payload_size = 0;
-
- for (int idx = 0; idx < simple_tags_count_; ++idx) {
- const SimpleTag& st = simple_tags_[idx];
- payload_size += st.Write(NULL);
- }
-
- const uint64 tag_size =
- EbmlMasterElementSize(kMkvTag, payload_size) + payload_size;
-
- if (writer == NULL)
- return tag_size;
-
- const int64 start = writer->Position();
-
- if (!WriteEbmlMasterElement(writer, kMkvTag, payload_size))
- return 0;
-
- for (int idx = 0; idx < simple_tags_count_; ++idx) {
- const SimpleTag& st = simple_tags_[idx];
-
- if (!st.Write(writer))
- return 0;
- }
-
- const int64 stop = writer->Position();
-
- if (stop >= start && uint64(stop - start) != tag_size)
- return 0;
-
- return tag_size;
-}
-
-// Tag::SimpleTag
-
-void Tag::SimpleTag::Init() {
- tag_name_ = NULL;
- tag_string_ = NULL;
-}
-
-void Tag::SimpleTag::Clear() {
- StrCpy(NULL, &tag_name_);
- StrCpy(NULL, &tag_string_);
-}
-
-bool Tag::SimpleTag::set_tag_name(const char* tag_name) {
- return StrCpy(tag_name, &tag_name_);
-}
-
-bool Tag::SimpleTag::set_tag_string(const char* tag_string) {
- return StrCpy(tag_string, &tag_string_);
-}
-
-uint64 Tag::SimpleTag::Write(IMkvWriter* writer) const {
- uint64 payload_size = EbmlElementSize(kMkvTagName, tag_name_);
-
- payload_size += EbmlElementSize(kMkvTagString, tag_string_);
-
- const uint64 simple_tag_size =
- EbmlMasterElementSize(kMkvSimpleTag, payload_size) + payload_size;
-
- if (writer == NULL)
- return simple_tag_size;
-
- const int64 start = writer->Position();
-
- if (!WriteEbmlMasterElement(writer, kMkvSimpleTag, payload_size))
- return 0;
-
- if (!WriteEbmlElement(writer, kMkvTagName, tag_name_))
- return 0;
-
- if (!WriteEbmlElement(writer, kMkvTagString, tag_string_))
- return 0;
-
- const int64 stop = writer->Position();
-
- if (stop >= start && uint64(stop - start) != simple_tag_size)
- return 0;
-
- return simple_tag_size;
-}
-
-// Tags Class
-
-Tags::Tags() : tags_size_(0), tags_count_(0), tags_(NULL) {}
-
-Tags::~Tags() {
- while (tags_count_ > 0) {
- Tag& tag = tags_[--tags_count_];
- tag.Clear();
- }
-
- delete[] tags_;
- tags_ = NULL;
-}
-
-int Tags::Count() const { return tags_count_; }
-
-Tag* Tags::AddTag() {
- if (!ExpandTagsArray())
- return NULL;
-
- Tag& tag = tags_[tags_count_++];
-
- return &tag;
-}
-
-bool Tags::Write(IMkvWriter* writer) const {
- if (writer == NULL)
- return false;
-
- uint64 payload_size = 0;
-
- for (int idx = 0; idx < tags_count_; ++idx) {
- const Tag& tag = tags_[idx];
- payload_size += tag.Write(NULL);
- }
-
- if (!WriteEbmlMasterElement(writer, kMkvTags, payload_size))
- return false;
-
- const int64 start = writer->Position();
-
- for (int idx = 0; idx < tags_count_; ++idx) {
- const Tag& tag = tags_[idx];
-
- const uint64 tag_size = tag.Write(writer);
- if (tag_size == 0) // error
- return 0;
- }
-
- const int64 stop = writer->Position();
-
- if (stop >= start && uint64(stop - start) != payload_size)
- return false;
-
- return true;
-}
-
-bool Tags::ExpandTagsArray() {
- if (tags_size_ > tags_count_)
- return true; // nothing to do yet
-
- const int size = (tags_size_ == 0) ? 1 : 2 * tags_size_;
-
- Tag* const tags = new (std::nothrow) Tag[size]; // NOLINT
- if (tags == NULL)
- return false;
-
- for (int idx = 0; idx < tags_count_; ++idx) {
- const Tag& src = tags_[idx];
- Tag* const dst = tags + idx;
- src.ShallowCopy(dst);
- }
-
- delete[] tags_;
-
- tags_ = tags;
- tags_size_ = size;
-
- return true;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// Cluster class
-
-Cluster::Cluster(uint64 timecode, int64 cues_pos, uint64 timecode_scale)
- : blocks_added_(0),
- finalized_(false),
- header_written_(false),
- payload_size_(0),
- position_for_cues_(cues_pos),
- size_position_(-1),
- timecode_(timecode),
- timecode_scale_(timecode_scale),
- writer_(NULL) {}
-
-Cluster::~Cluster() {}
-
-bool Cluster::Init(IMkvWriter* ptr_writer) {
- if (!ptr_writer) {
- return false;
- }
- writer_ = ptr_writer;
- return true;
-}
-
-bool Cluster::AddFrame(const Frame* const frame) { return DoWriteFrame(frame); }
-
-bool Cluster::AddFrame(const uint8* data, uint64 length, uint64 track_number,
- uint64 abs_timecode, bool is_key) {
- Frame frame;
- if (!frame.Init(data, length))
- return false;
- frame.set_track_number(track_number);
- frame.set_timestamp(abs_timecode);
- frame.set_is_key(is_key);
- return DoWriteFrame(&frame);
-}
-
-bool Cluster::AddFrameWithAdditional(const uint8* data, uint64 length,
- const uint8* additional,
- uint64 additional_length, uint64 add_id,
- uint64 track_number, uint64 abs_timecode,
- bool is_key) {
- if (!additional || additional_length == 0) {
- return false;
- }
- Frame frame;
- if (!frame.Init(data, length) ||
- !frame.AddAdditionalData(additional, additional_length, add_id)) {
- return false;
- }
- frame.set_track_number(track_number);
- frame.set_timestamp(abs_timecode);
- frame.set_is_key(is_key);
- return DoWriteFrame(&frame);
-}
-
-bool Cluster::AddFrameWithDiscardPadding(const uint8* data, uint64 length,
- int64 discard_padding,
- uint64 track_number,
- uint64 abs_timecode, bool is_key) {
- Frame frame;
- if (!frame.Init(data, length))
- return false;
- frame.set_discard_padding(discard_padding);
- frame.set_track_number(track_number);
- frame.set_timestamp(abs_timecode);
- frame.set_is_key(is_key);
- return DoWriteFrame(&frame);
-}
-
-bool Cluster::AddMetadata(const uint8* data, uint64 length, uint64 track_number,
- uint64 abs_timecode, uint64 duration_timecode) {
- Frame frame;
- if (!frame.Init(data, length))
- return false;
- frame.set_track_number(track_number);
- frame.set_timestamp(abs_timecode);
- frame.set_duration(duration_timecode);
- frame.set_is_key(true); // All metadata blocks are keyframes.
- return DoWriteFrame(&frame);
-}
-
-void Cluster::AddPayloadSize(uint64 size) { payload_size_ += size; }
-
-bool Cluster::Finalize() {
- if (!writer_ || finalized_ || size_position_ == -1)
- return false;
-
- if (writer_->Seekable()) {
- const int64 pos = writer_->Position();
-
- if (writer_->Position(size_position_))
- return false;
-
- if (WriteUIntSize(writer_, payload_size(), 8))
- return false;
-
- if (writer_->Position(pos))
- return false;
- }
-
- finalized_ = true;
-
- return true;
-}
-
-uint64 Cluster::Size() const {
- const uint64 element_size =
- EbmlMasterElementSize(kMkvCluster, 0xFFFFFFFFFFFFFFFFULL) + payload_size_;
- return element_size;
-}
-
-bool Cluster::PreWriteBlock() {
- if (finalized_)
- return false;
-
- if (!header_written_) {
- if (!WriteClusterHeader())
- return false;
- }
-
- return true;
-}
-
-void Cluster::PostWriteBlock(uint64 element_size) {
- AddPayloadSize(element_size);
- ++blocks_added_;
-}
-
-int64 Cluster::GetRelativeTimecode(int64 abs_timecode) const {
- const int64 cluster_timecode = this->Cluster::timecode();
- const int64 rel_timecode =
- static_cast<int64>(abs_timecode) - cluster_timecode;
-
- if (rel_timecode < 0 || rel_timecode > kMaxBlockTimecode)
- return -1;
-
- return rel_timecode;
-}
-
-bool Cluster::DoWriteFrame(const Frame* const frame) {
- if (!frame || !frame->IsValid())
- return false;
-
- if (!PreWriteBlock())
- return false;
-
- const uint64 element_size = WriteFrame(writer_, frame, this);
- if (element_size == 0)
- return false;
-
- PostWriteBlock(element_size);
- return true;
-}
-
-bool Cluster::WriteClusterHeader() {
- if (finalized_)
- return false;
-
- if (WriteID(writer_, kMkvCluster))
- return false;
-
- // Save for later.
- size_position_ = writer_->Position();
-
- // Write "unknown" (EBML coded -1) as cluster size value. We need to write 8
- // bytes because we do not know how big our cluster will be.
- if (SerializeInt(writer_, kEbmlUnknownValue, 8))
- return false;
-
- if (!WriteEbmlElement(writer_, kMkvTimecode, timecode()))
- return false;
- AddPayloadSize(EbmlElementSize(kMkvTimecode, timecode()));
- header_written_ = true;
-
- return true;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// SeekHead Class
-
-SeekHead::SeekHead() : start_pos_(0ULL) {
- for (int32 i = 0; i < kSeekEntryCount; ++i) {
- seek_entry_id_[i] = 0;
- seek_entry_pos_[i] = 0;
- }
-}
-
-SeekHead::~SeekHead() {}
-
-bool SeekHead::Finalize(IMkvWriter* writer) const {
- if (writer->Seekable()) {
- if (start_pos_ == -1)
- return false;
-
- uint64 payload_size = 0;
- uint64 entry_size[kSeekEntryCount];
-
- for (int32 i = 0; i < kSeekEntryCount; ++i) {
- if (seek_entry_id_[i] != 0) {
- entry_size[i] =
- EbmlElementSize(kMkvSeekID, static_cast<uint64>(seek_entry_id_[i]));
- entry_size[i] += EbmlElementSize(kMkvSeekPosition, seek_entry_pos_[i]);
-
- payload_size +=
- EbmlMasterElementSize(kMkvSeek, entry_size[i]) + entry_size[i];
- }
- }
-
- // No SeekHead elements
- if (payload_size == 0)
- return true;
-
- const int64 pos = writer->Position();
- if (writer->Position(start_pos_))
- return false;
-
- if (!WriteEbmlMasterElement(writer, kMkvSeekHead, payload_size))
- return false;
-
- for (int32 i = 0; i < kSeekEntryCount; ++i) {
- if (seek_entry_id_[i] != 0) {
- if (!WriteEbmlMasterElement(writer, kMkvSeek, entry_size[i]))
- return false;
-
- if (!WriteEbmlElement(writer, kMkvSeekID,
- static_cast<uint64>(seek_entry_id_[i])))
- return false;
-
- if (!WriteEbmlElement(writer, kMkvSeekPosition, seek_entry_pos_[i]))
- return false;
- }
- }
-
- const uint64 total_entry_size = kSeekEntryCount * MaxEntrySize();
- const uint64 total_size =
- EbmlMasterElementSize(kMkvSeekHead, total_entry_size) +
- total_entry_size;
- const int64 size_left = total_size - (writer->Position() - start_pos_);
-
- const uint64 bytes_written = WriteVoidElement(writer, size_left);
- if (!bytes_written)
- return false;
-
- if (writer->Position(pos))
- return false;
- }
-
- return true;
-}
-
-bool SeekHead::Write(IMkvWriter* writer) {
- const uint64 entry_size = kSeekEntryCount * MaxEntrySize();
- const uint64 size = EbmlMasterElementSize(kMkvSeekHead, entry_size);
-
- start_pos_ = writer->Position();
-
- const uint64 bytes_written = WriteVoidElement(writer, size + entry_size);
- if (!bytes_written)
- return false;
-
- return true;
-}
-
-bool SeekHead::AddSeekEntry(uint32 id, uint64 pos) {
- for (int32 i = 0; i < kSeekEntryCount; ++i) {
- if (seek_entry_id_[i] == 0) {
- seek_entry_id_[i] = id;
- seek_entry_pos_[i] = pos;
- return true;
- }
- }
- return false;
-}
-
-uint32 SeekHead::GetId(int index) const {
- if (index < 0 || index >= kSeekEntryCount)
- return UINT_MAX;
- return seek_entry_id_[index];
-}
-
-uint64 SeekHead::GetPosition(int index) const {
- if (index < 0 || index >= kSeekEntryCount)
- return ULLONG_MAX;
- return seek_entry_pos_[index];
-}
-
-bool SeekHead::SetSeekEntry(int index, uint32 id, uint64 position) {
- if (index < 0 || index >= kSeekEntryCount)
- return false;
- seek_entry_id_[index] = id;
- seek_entry_pos_[index] = position;
- return true;
-}
-
-uint64 SeekHead::MaxEntrySize() const {
- const uint64 max_entry_payload_size =
- EbmlElementSize(kMkvSeekID, 0xffffffffULL) +
- EbmlElementSize(kMkvSeekPosition, 0xffffffffffffffffULL);
- const uint64 max_entry_size =
- EbmlMasterElementSize(kMkvSeek, max_entry_payload_size) +
- max_entry_payload_size;
-
- return max_entry_size;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// SegmentInfo Class
-
-SegmentInfo::SegmentInfo()
- : duration_(-1.0),
- muxing_app_(NULL),
- timecode_scale_(1000000ULL),
- writing_app_(NULL),
- date_utc_(LLONG_MIN),
- duration_pos_(-1) {}
-
-SegmentInfo::~SegmentInfo() {
- delete[] muxing_app_;
- delete[] writing_app_;
-}
-
-bool SegmentInfo::Init() {
- int32 major;
- int32 minor;
- int32 build;
- int32 revision;
- GetVersion(&major, &minor, &build, &revision);
- char temp[256];
-#ifdef _MSC_VER
- sprintf_s(temp, sizeof(temp) / sizeof(temp[0]), "libwebm-%d.%d.%d.%d", major,
- minor, build, revision);
-#else
- snprintf(temp, sizeof(temp) / sizeof(temp[0]), "libwebm-%d.%d.%d.%d", major,
- minor, build, revision);
-#endif
-
- const size_t app_len = strlen(temp) + 1;
-
- delete[] muxing_app_;
-
- muxing_app_ = new (std::nothrow) char[app_len]; // NOLINT
- if (!muxing_app_)
- return false;
-
-#ifdef _MSC_VER
- strcpy_s(muxing_app_, app_len, temp);
-#else
- strcpy(muxing_app_, temp);
-#endif
-
- set_writing_app(temp);
- if (!writing_app_)
- return false;
- return true;
-}
-
-bool SegmentInfo::Finalize(IMkvWriter* writer) const {
- if (!writer)
- return false;
-
- if (duration_ > 0.0) {
- if (writer->Seekable()) {
- if (duration_pos_ == -1)
- return false;
-
- const int64 pos = writer->Position();
-
- if (writer->Position(duration_pos_))
- return false;
-
- if (!WriteEbmlElement(writer, kMkvDuration,
- static_cast<float>(duration_)))
- return false;
-
- if (writer->Position(pos))
- return false;
- }
- }
-
- return true;
-}
-
-bool SegmentInfo::Write(IMkvWriter* writer) {
- if (!writer || !muxing_app_ || !writing_app_)
- return false;
-
- uint64 size = EbmlElementSize(kMkvTimecodeScale, timecode_scale_);
- if (duration_ > 0.0)
- size += EbmlElementSize(kMkvDuration, static_cast<float>(duration_));
- if (date_utc_ != LLONG_MIN)
- size += EbmlDateElementSize(kMkvDateUTC);
- size += EbmlElementSize(kMkvMuxingApp, muxing_app_);
- size += EbmlElementSize(kMkvWritingApp, writing_app_);
-
- if (!WriteEbmlMasterElement(writer, kMkvInfo, size))
- return false;
-
- const int64 payload_position = writer->Position();
- if (payload_position < 0)
- return false;
-
- if (!WriteEbmlElement(writer, kMkvTimecodeScale, timecode_scale_))
- return false;
-
- if (duration_ > 0.0) {
- // Save for later
- duration_pos_ = writer->Position();
-
- if (!WriteEbmlElement(writer, kMkvDuration, static_cast<float>(duration_)))
- return false;
- }
-
- if (date_utc_ != LLONG_MIN)
- WriteEbmlDateElement(writer, kMkvDateUTC, date_utc_);
-
- if (!WriteEbmlElement(writer, kMkvMuxingApp, muxing_app_))
- return false;
- if (!WriteEbmlElement(writer, kMkvWritingApp, writing_app_))
- return false;
-
- const int64 stop_position = writer->Position();
- if (stop_position < 0 ||
- stop_position - payload_position != static_cast<int64>(size))
- return false;
-
- return true;
-}
-
-void SegmentInfo::set_muxing_app(const char* app) {
- if (app) {
- const size_t length = strlen(app) + 1;
- char* temp_str = new (std::nothrow) char[length]; // NOLINT
- if (!temp_str)
- return;
-
-#ifdef _MSC_VER
- strcpy_s(temp_str, length, app);
-#else
- strcpy(temp_str, app);
-#endif
-
- delete[] muxing_app_;
- muxing_app_ = temp_str;
- }
-}
-
-void SegmentInfo::set_writing_app(const char* app) {
- if (app) {
- const size_t length = strlen(app) + 1;
- char* temp_str = new (std::nothrow) char[length]; // NOLINT
- if (!temp_str)
- return;
-
-#ifdef _MSC_VER
- strcpy_s(temp_str, length, app);
-#else
- strcpy(temp_str, app);
-#endif
-
- delete[] writing_app_;
- writing_app_ = temp_str;
- }
-}
-
-///////////////////////////////////////////////////////////////
-//
-// Segment Class
-
-Segment::Segment()
- : chunk_count_(0),
- chunk_name_(NULL),
- chunk_writer_cluster_(NULL),
- chunk_writer_cues_(NULL),
- chunk_writer_header_(NULL),
- chunking_(false),
- chunking_base_name_(NULL),
- cluster_list_(NULL),
- cluster_list_capacity_(0),
- cluster_list_size_(0),
- cues_position_(kAfterClusters),
- cues_track_(0),
- force_new_cluster_(false),
- frames_(NULL),
- frames_capacity_(0),
- frames_size_(0),
- has_video_(false),
- header_written_(false),
- last_block_duration_(0),
- last_timestamp_(0),
- max_cluster_duration_(kDefaultMaxClusterDuration),
- max_cluster_size_(0),
- mode_(kFile),
- new_cuepoint_(false),
- output_cues_(true),
- payload_pos_(0),
- size_position_(0),
- doc_type_version_(kDefaultDocTypeVersion),
- doc_type_version_written_(0),
- writer_cluster_(NULL),
- writer_cues_(NULL),
- writer_header_(NULL) {
- const time_t curr_time = time(NULL);
- seed_ = static_cast<unsigned int>(curr_time);
-#ifdef _WIN32
- srand(seed_);
-#endif
-}
-
-Segment::~Segment() {
- if (cluster_list_) {
- for (int32 i = 0; i < cluster_list_size_; ++i) {
- Cluster* const cluster = cluster_list_[i];
- delete cluster;
- }
- delete[] cluster_list_;
- }
-
- if (frames_) {
- for (int32 i = 0; i < frames_size_; ++i) {
- Frame* const frame = frames_[i];
- delete frame;
- }
- delete[] frames_;
- }
-
- delete[] chunk_name_;
- delete[] chunking_base_name_;
-
- if (chunk_writer_cluster_) {
- chunk_writer_cluster_->Close();
- delete chunk_writer_cluster_;
- }
- if (chunk_writer_cues_) {
- chunk_writer_cues_->Close();
- delete chunk_writer_cues_;
- }
- if (chunk_writer_header_) {
- chunk_writer_header_->Close();
- delete chunk_writer_header_;
- }
-}
-
-void Segment::MoveCuesBeforeClustersHelper(uint64 diff, int32 index,
- uint64* cues_size) {
- CuePoint* const cue_point = cues_.GetCueByIndex(index);
- if (cue_point == NULL)
- return;
- const uint64 old_cue_point_size = cue_point->Size();
- const uint64 cluster_pos = cue_point->cluster_pos() + diff;
- cue_point->set_cluster_pos(cluster_pos); // update the new cluster position
- // New size of the cue is computed as follows
- // Let a = current sum of size of all CuePoints
- // Let b = Increase in Cue Point's size due to this iteration
- // Let c = Increase in size of Cues Element's length due to this iteration
- // (This is computed as CodedSize(a + b) - CodedSize(a))
- // Let d = b + c. Now d is the |diff| passed to the next recursive call.
- // Let e = a + b. Now e is the |cues_size| passed to the next recursive
- // call.
- const uint64 cue_point_size_diff = cue_point->Size() - old_cue_point_size;
- const uint64 cue_size_diff =
- GetCodedUIntSize(*cues_size + cue_point_size_diff) -
- GetCodedUIntSize(*cues_size);
- *cues_size += cue_point_size_diff;
- diff = cue_size_diff + cue_point_size_diff;
- if (diff > 0) {
- for (int32 i = 0; i < cues_.cue_entries_size(); ++i) {
- MoveCuesBeforeClustersHelper(diff, i, cues_size);
- }
- }
-}
-
-void Segment::MoveCuesBeforeClusters() {
- const uint64 current_cue_size = cues_.Size();
- uint64 cue_size = 0;
- for (int32 i = 0; i < cues_.cue_entries_size(); ++i)
- cue_size += cues_.GetCueByIndex(i)->Size();
- for (int32 i = 0; i < cues_.cue_entries_size(); ++i)
- MoveCuesBeforeClustersHelper(current_cue_size, i, &cue_size);
-
- // Adjust the Seek Entry to reflect the change in position
- // of Cluster and Cues
- int32 cluster_index = 0;
- int32 cues_index = 0;
- for (int32 i = 0; i < SeekHead::kSeekEntryCount; ++i) {
- if (seek_head_.GetId(i) == kMkvCluster)
- cluster_index = i;
- if (seek_head_.GetId(i) == kMkvCues)
- cues_index = i;
- }
- seek_head_.SetSeekEntry(cues_index, kMkvCues,
- seek_head_.GetPosition(cluster_index));
- seek_head_.SetSeekEntry(cluster_index, kMkvCluster,
- cues_.Size() + seek_head_.GetPosition(cues_index));
-}
-
-bool Segment::Init(IMkvWriter* ptr_writer) {
- if (!ptr_writer) {
- return false;
- }
- writer_cluster_ = ptr_writer;
- writer_cues_ = ptr_writer;
- writer_header_ = ptr_writer;
- return segment_info_.Init();
-}
-
-bool Segment::CopyAndMoveCuesBeforeClusters(mkvparser::IMkvReader* reader,
- IMkvWriter* writer) {
- if (!writer->Seekable() || chunking_)
- return false;
- const int64 cluster_offset =
- cluster_list_[0]->size_position() - GetUIntSize(kMkvCluster);
-
- // Copy the headers.
- if (!ChunkedCopy(reader, writer, 0, cluster_offset))
- return false;
-
- // Recompute cue positions and seek entries.
- MoveCuesBeforeClusters();
-
- // Write cues and seek entries.
- // TODO(vigneshv): As of now, it's safe to call seek_head_.Finalize() for the
- // second time with a different writer object. But the name Finalize() doesn't
- // indicate something we want to call more than once. So consider renaming it
- // to write() or some such.
- if (!cues_.Write(writer) || !seek_head_.Finalize(writer))
- return false;
-
- // Copy the Clusters.
- if (!ChunkedCopy(reader, writer, cluster_offset,
- cluster_end_offset_ - cluster_offset))
- return false;
-
- // Update the Segment size in case the Cues size has changed.
- const int64 pos = writer->Position();
- const int64 segment_size = writer->Position() - payload_pos_;
- if (writer->Position(size_position_) ||
- WriteUIntSize(writer, segment_size, 8) || writer->Position(pos))
- return false;
- return true;
-}
-
-bool Segment::Finalize() {
- if (WriteFramesAll() < 0)
- return false;
-
- if (mode_ == kFile) {
- if (cluster_list_size_ > 0) {
- // Update last cluster's size
- Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1];
-
- if (!old_cluster || !old_cluster->Finalize())
- return false;
- }
-
- if (chunking_ && chunk_writer_cluster_) {
- chunk_writer_cluster_->Close();
- chunk_count_++;
- }
-
- const double duration =
- (static_cast<double>(last_timestamp_) + last_block_duration_) /
- segment_info_.timecode_scale();
- segment_info_.set_duration(duration);
- if (!segment_info_.Finalize(writer_header_))
- return false;
-
- if (output_cues_)
- if (!seek_head_.AddSeekEntry(kMkvCues, MaxOffset()))
- return false;
-
- if (chunking_) {
- if (!chunk_writer_cues_)
- return false;
-
- char* name = NULL;
- if (!UpdateChunkName("cues", &name))
- return false;
-
- const bool cues_open = chunk_writer_cues_->Open(name);
- delete[] name;
- if (!cues_open)
- return false;
- }
-
- cluster_end_offset_ = writer_cluster_->Position();
-
- // Write the seek headers and cues
- if (output_cues_)
- if (!cues_.Write(writer_cues_))
- return false;
-
- if (!seek_head_.Finalize(writer_header_))
- return false;
-
- if (writer_header_->Seekable()) {
- if (size_position_ == -1)
- return false;
-
- const int64 segment_size = MaxOffset();
- if (segment_size < 1)
- return false;
-
- const int64 pos = writer_header_->Position();
- UpdateDocTypeVersion();
- if (doc_type_version_ != doc_type_version_written_) {
- if (writer_header_->Position(0))
- return false;
-
- if (!WriteEbmlHeader(writer_header_, doc_type_version_))
- return false;
- if (writer_header_->Position() != ebml_header_size_)
- return false;
-
- doc_type_version_written_ = doc_type_version_;
- }
-
- if (writer_header_->Position(size_position_))
- return false;
-
- if (WriteUIntSize(writer_header_, segment_size, 8))
- return false;
-
- if (writer_header_->Position(pos))
- return false;
- }
-
- if (chunking_) {
- // Do not close any writers until the segment size has been written,
- // otherwise the size may be off.
- if (!chunk_writer_cues_ || !chunk_writer_header_)
- return false;
-
- chunk_writer_cues_->Close();
- chunk_writer_header_->Close();
- }
- }
-
- return true;
-}
-
-Track* Segment::AddTrack(int32 number) {
- Track* const track = new (std::nothrow) Track(&seed_); // NOLINT
-
- if (!track)
- return NULL;
-
- if (!tracks_.AddTrack(track, number)) {
- delete track;
- return NULL;
- }
-
- return track;
-}
-
-Chapter* Segment::AddChapter() { return chapters_.AddChapter(&seed_); }
-
-Tag* Segment::AddTag() { return tags_.AddTag(); }
-
-uint64 Segment::AddVideoTrack(int32 width, int32 height, int32 number) {
- VideoTrack* const track = new (std::nothrow) VideoTrack(&seed_); // NOLINT
- if (!track)
- return 0;
-
- track->set_type(Tracks::kVideo);
- track->set_codec_id(Tracks::kVp8CodecId);
- track->set_width(width);
- track->set_height(height);
-
- tracks_.AddTrack(track, number);
- has_video_ = true;
-
- return track->number();
-}
-
-bool Segment::AddCuePoint(uint64 timestamp, uint64 track) {
- if (cluster_list_size_ < 1)
- return false;
-
- const Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
- if (!cluster)
- return false;
-
- CuePoint* const cue = new (std::nothrow) CuePoint(); // NOLINT
- if (!cue)
- return false;
-
- cue->set_time(timestamp / segment_info_.timecode_scale());
- cue->set_block_number(cluster->blocks_added());
- cue->set_cluster_pos(cluster->position_for_cues());
- cue->set_track(track);
- if (!cues_.AddCue(cue))
- return false;
-
- new_cuepoint_ = false;
- return true;
-}
-
-uint64 Segment::AddAudioTrack(int32 sample_rate, int32 channels, int32 number) {
- AudioTrack* const track = new (std::nothrow) AudioTrack(&seed_); // NOLINT
- if (!track)
- return 0;
-
- track->set_type(Tracks::kAudio);
- track->set_codec_id(Tracks::kVorbisCodecId);
- track->set_sample_rate(sample_rate);
- track->set_channels(channels);
-
- tracks_.AddTrack(track, number);
-
- return track->number();
-}
-
-bool Segment::AddFrame(const uint8* data, uint64 length, uint64 track_number,
- uint64 timestamp, bool is_key) {
- if (!data)
- return false;
-
- Frame frame;
- if (!frame.Init(data, length))
- return false;
- frame.set_track_number(track_number);
- frame.set_timestamp(timestamp);
- frame.set_is_key(is_key);
- return AddGenericFrame(&frame);
-}
-
-bool Segment::AddFrameWithAdditional(const uint8* data, uint64 length,
- const uint8* additional,
- uint64 additional_length, uint64 add_id,
- uint64 track_number, uint64 timestamp,
- bool is_key) {
- if (!data || !additional)
- return false;
-
- Frame frame;
- if (!frame.Init(data, length) ||
- !frame.AddAdditionalData(additional, additional_length, add_id)) {
- return false;
- }
- frame.set_track_number(track_number);
- frame.set_timestamp(timestamp);
- frame.set_is_key(is_key);
- return AddGenericFrame(&frame);
-}
-
-bool Segment::AddFrameWithDiscardPadding(const uint8* data, uint64 length,
- int64 discard_padding,
- uint64 track_number, uint64 timestamp,
- bool is_key) {
- if (!data)
- return false;
-
- Frame frame;
- if (!frame.Init(data, length))
- return false;
- frame.set_discard_padding(discard_padding);
- frame.set_track_number(track_number);
- frame.set_timestamp(timestamp);
- frame.set_is_key(is_key);
- return AddGenericFrame(&frame);
-}
-
-bool Segment::AddMetadata(const uint8* data, uint64 length, uint64 track_number,
- uint64 timestamp_ns, uint64 duration_ns) {
- if (!data)
- return false;
-
- Frame frame;
- if (!frame.Init(data, length))
- return false;
- frame.set_track_number(track_number);
- frame.set_timestamp(timestamp_ns);
- frame.set_duration(duration_ns);
- frame.set_is_key(true); // All metadata blocks are keyframes.
- return AddGenericFrame(&frame);
-}
-
-bool Segment::AddGenericFrame(const Frame* frame) {
- if (!frame)
- return false;
-
- if (!CheckHeaderInfo())
- return false;
-
- // Check for non-monotonically increasing timestamps.
- if (frame->timestamp() < last_timestamp_)
- return false;
-
- // Check if the track number is valid.
- if (!tracks_.GetTrackByNumber(frame->track_number()))
- return false;
-
- if (frame->discard_padding() != 0)
- doc_type_version_ = 4;
-
- // If the segment has a video track hold onto audio frames to make sure the
- // audio that is associated with the start time of a video key-frame is
- // muxed into the same cluster.
- if (has_video_ && tracks_.TrackIsAudio(frame->track_number()) &&
- !force_new_cluster_) {
- Frame* const new_frame = new (std::nothrow) Frame();
- if (!new_frame || !new_frame->CopyFrom(*frame))
- return false;
- return QueueFrame(new_frame);
- }
-
- if (!DoNewClusterProcessing(frame->track_number(), frame->timestamp(),
- frame->is_key())) {
- return false;
- }
-
- if (cluster_list_size_ < 1)
- return false;
-
- Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
- if (!cluster)
- return false;
-
- // If the Frame is not a SimpleBlock, then set the reference_block_timestamp
- // if it is not set already.
- bool frame_created = false;
- if (!frame->CanBeSimpleBlock() && !frame->is_key() &&
- !frame->reference_block_timestamp_set()) {
- Frame* const new_frame = new (std::nothrow) Frame();
- if (!new_frame->CopyFrom(*frame))
- return false;
- new_frame->set_reference_block_timestamp(
- last_track_timestamp_[frame->track_number() - 1]);
- frame = new_frame;
- frame_created = true;
- }
-
- if (!cluster->AddFrame(frame))
- return false;
-
- if (new_cuepoint_ && cues_track_ == frame->track_number()) {
- if (!AddCuePoint(frame->timestamp(), cues_track_))
- return false;
- }
-
- last_timestamp_ = frame->timestamp();
- last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
- last_block_duration_ = frame->duration();
-
- if (frame_created)
- delete frame;
-
- return true;
-}
-
-void Segment::OutputCues(bool output_cues) { output_cues_ = output_cues; }
-
-bool Segment::SetChunking(bool chunking, const char* filename) {
- if (chunk_count_ > 0)
- return false;
-
- if (chunking) {
- if (!filename)
- return false;
-
- // Check if we are being set to what is already set.
- if (chunking_ && !strcmp(filename, chunking_base_name_))
- return true;
-
- const size_t name_length = strlen(filename) + 1;
- char* const temp = new (std::nothrow) char[name_length]; // NOLINT
- if (!temp)
- return false;
-
-#ifdef _MSC_VER
- strcpy_s(temp, name_length, filename);
-#else
- strcpy(temp, filename);
-#endif
-
- delete[] chunking_base_name_;
- chunking_base_name_ = temp;
-
- if (!UpdateChunkName("chk", &chunk_name_))
- return false;
-
- if (!chunk_writer_cluster_) {
- chunk_writer_cluster_ = new (std::nothrow) MkvWriter(); // NOLINT
- if (!chunk_writer_cluster_)
- return false;
- }
-
- if (!chunk_writer_cues_) {
- chunk_writer_cues_ = new (std::nothrow) MkvWriter(); // NOLINT
- if (!chunk_writer_cues_)
- return false;
- }
-
- if (!chunk_writer_header_) {
- chunk_writer_header_ = new (std::nothrow) MkvWriter(); // NOLINT
- if (!chunk_writer_header_)
- return false;
- }
-
- if (!chunk_writer_cluster_->Open(chunk_name_))
- return false;
-
- const size_t header_length = strlen(filename) + strlen(".hdr") + 1;
- char* const header = new (std::nothrow) char[header_length]; // NOLINT
- if (!header)
- return false;
-
-#ifdef _MSC_VER
- strcpy_s(header, header_length - strlen(".hdr"), chunking_base_name_);
- strcat_s(header, header_length, ".hdr");
-#else
- strcpy(header, chunking_base_name_);
- strcat(header, ".hdr");
-#endif
- if (!chunk_writer_header_->Open(header)) {
- delete[] header;
- return false;
- }
-
- writer_cluster_ = chunk_writer_cluster_;
- writer_cues_ = chunk_writer_cues_;
- writer_header_ = chunk_writer_header_;
-
- delete[] header;
- }
-
- chunking_ = chunking;
-
- return true;
-}
-
-bool Segment::CuesTrack(uint64 track_number) {
- const Track* const track = GetTrackByNumber(track_number);
- if (!track)
- return false;
-
- cues_track_ = track_number;
- return true;
-}
-
-void Segment::ForceNewClusterOnNextFrame() { force_new_cluster_ = true; }
-
-Track* Segment::GetTrackByNumber(uint64 track_number) const {
- return tracks_.GetTrackByNumber(track_number);
-}
-
-bool Segment::WriteSegmentHeader() {
- UpdateDocTypeVersion();
-
- // TODO(fgalligan): Support more than one segment.
- if (!WriteEbmlHeader(writer_header_, doc_type_version_))
- return false;
- doc_type_version_written_ = doc_type_version_;
- ebml_header_size_ = static_cast<int32>(writer_header_->Position());
-
- // Write "unknown" (-1) as segment size value. If mode is kFile, Segment
- // will write over duration when the file is finalized.
- if (WriteID(writer_header_, kMkvSegment))
- return false;
-
- // Save for later.
- size_position_ = writer_header_->Position();
-
- // Write "unknown" (EBML coded -1) as segment size value. We need to write 8
- // bytes because if we are going to overwrite the segment size later we do
- // not know how big our segment will be.
- if (SerializeInt(writer_header_, kEbmlUnknownValue, 8))
- return false;
-
- payload_pos_ = writer_header_->Position();
-
- if (mode_ == kFile && writer_header_->Seekable()) {
- // Set the duration > 0.0 so SegmentInfo will write out the duration. When
- // the muxer is done writing we will set the correct duration and have
- // SegmentInfo upadte it.
- segment_info_.set_duration(1.0);
-
- if (!seek_head_.Write(writer_header_))
- return false;
- }
-
- if (!seek_head_.AddSeekEntry(kMkvInfo, MaxOffset()))
- return false;
- if (!segment_info_.Write(writer_header_))
- return false;
-
- if (!seek_head_.AddSeekEntry(kMkvTracks, MaxOffset()))
- return false;
- if (!tracks_.Write(writer_header_))
- return false;
-
- if (chapters_.Count() > 0) {
- if (!seek_head_.AddSeekEntry(kMkvChapters, MaxOffset()))
- return false;
- if (!chapters_.Write(writer_header_))
- return false;
- }
-
- if (tags_.Count() > 0) {
- if (!seek_head_.AddSeekEntry(kMkvTags, MaxOffset()))
- return false;
- if (!tags_.Write(writer_header_))
- return false;
- }
-
- if (chunking_ && (mode_ == kLive || !writer_header_->Seekable())) {
- if (!chunk_writer_header_)
- return false;
-
- chunk_writer_header_->Close();
- }
-
- header_written_ = true;
-
- return true;
-}
-
-// Here we are testing whether to create a new cluster, given a frame
-// having time frame_timestamp_ns.
-//
-int Segment::TestFrame(uint64 track_number, uint64 frame_timestamp_ns,
- bool is_key) const {
- if (force_new_cluster_)
- return 1;
-
- // If no clusters have been created yet, then create a new cluster
- // and write this frame immediately, in the new cluster. This path
- // should only be followed once, the first time we attempt to write
- // a frame.
-
- if (cluster_list_size_ <= 0)
- return 1;
-
- // There exists at least one cluster. We must compare the frame to
- // the last cluster, in order to determine whether the frame is
- // written to the existing cluster, or that a new cluster should be
- // created.
-
- const uint64 timecode_scale = segment_info_.timecode_scale();
- const uint64 frame_timecode = frame_timestamp_ns / timecode_scale;
-
- const Cluster* const last_cluster = cluster_list_[cluster_list_size_ - 1];
- const uint64 last_cluster_timecode = last_cluster->timecode();
-
- // For completeness we test for the case when the frame's timecode
- // is less than the cluster's timecode. Although in principle that
- // is allowed, this muxer doesn't actually write clusters like that,
- // so this indicates a bug somewhere in our algorithm.
-
- if (frame_timecode < last_cluster_timecode) // should never happen
- return -1;
-
- // If the frame has a timestamp significantly larger than the last
- // cluster (in Matroska, cluster-relative timestamps are serialized
- // using a 16-bit signed integer), then we cannot write this frame
- // to that cluster, and so we must create a new cluster.
-
- const int64 delta_timecode = frame_timecode - last_cluster_timecode;
-
- if (delta_timecode > kMaxBlockTimecode)
- return 2;
-
- // We decide to create a new cluster when we have a video keyframe.
- // This will flush queued (audio) frames, and write the keyframe
- // immediately, in the newly-created cluster.
-
- if (is_key && tracks_.TrackIsVideo(track_number))
- return 1;
-
- // Create a new cluster if we have accumulated too many frames
- // already, where "too many" is defined as "the total time of frames
- // in the cluster exceeds a threshold".
-
- const uint64 delta_ns = delta_timecode * timecode_scale;
-
- if (max_cluster_duration_ > 0 && delta_ns >= max_cluster_duration_)
- return 1;
-
- // This is similar to the case above, with the difference that a new
- // cluster is created when the size of the current cluster exceeds a
- // threshold.
-
- const uint64 cluster_size = last_cluster->payload_size();
-
- if (max_cluster_size_ > 0 && cluster_size >= max_cluster_size_)
- return 1;
-
- // There's no need to create a new cluster, so emit this frame now.
-
- return 0;
-}
-
-bool Segment::MakeNewCluster(uint64 frame_timestamp_ns) {
- const int32 new_size = cluster_list_size_ + 1;
-
- if (new_size > cluster_list_capacity_) {
- // Add more clusters.
- const int32 new_capacity =
- (cluster_list_capacity_ <= 0) ? 1 : cluster_list_capacity_ * 2;
- Cluster** const clusters =
- new (std::nothrow) Cluster*[new_capacity]; // NOLINT
- if (!clusters)
- return false;
-
- for (int32 i = 0; i < cluster_list_size_; ++i) {
- clusters[i] = cluster_list_[i];
- }
-
- delete[] cluster_list_;
-
- cluster_list_ = clusters;
- cluster_list_capacity_ = new_capacity;
- }
-
- if (!WriteFramesLessThan(frame_timestamp_ns))
- return false;
-
- if (mode_ == kFile) {
- if (cluster_list_size_ > 0) {
- // Update old cluster's size
- Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1];
-
- if (!old_cluster || !old_cluster->Finalize())
- return false;
- }
-
- if (output_cues_)
- new_cuepoint_ = true;
- }
-
- if (chunking_ && cluster_list_size_ > 0) {
- chunk_writer_cluster_->Close();
- chunk_count_++;
-
- if (!UpdateChunkName("chk", &chunk_name_))
- return false;
- if (!chunk_writer_cluster_->Open(chunk_name_))
- return false;
- }
-
- const uint64 timecode_scale = segment_info_.timecode_scale();
- const uint64 frame_timecode = frame_timestamp_ns / timecode_scale;
-
- uint64 cluster_timecode = frame_timecode;
-
- if (frames_size_ > 0) {
- const Frame* const f = frames_[0]; // earliest queued frame
- const uint64 ns = f->timestamp();
- const uint64 tc = ns / timecode_scale;
-
- if (tc < cluster_timecode)
- cluster_timecode = tc;
- }
-
- Cluster*& cluster = cluster_list_[cluster_list_size_];
- const int64 offset = MaxOffset();
- cluster = new (std::nothrow) Cluster(cluster_timecode, // NOLINT
- offset, segment_info_.timecode_scale());
- if (!cluster)
- return false;
-
- if (!cluster->Init(writer_cluster_))
- return false;
-
- cluster_list_size_ = new_size;
- return true;
-}
-
-bool Segment::DoNewClusterProcessing(uint64 track_number,
- uint64 frame_timestamp_ns, bool is_key) {
- for (;;) {
- // Based on the characteristics of the current frame and current
- // cluster, decide whether to create a new cluster.
- const int result = TestFrame(track_number, frame_timestamp_ns, is_key);
- if (result < 0) // error
- return false;
-
- // Always set force_new_cluster_ to false after TestFrame.
- force_new_cluster_ = false;
-
- // A non-zero result means create a new cluster.
- if (result > 0 && !MakeNewCluster(frame_timestamp_ns))
- return false;
-
- // Write queued (audio) frames.
- const int frame_count = WriteFramesAll();
- if (frame_count < 0) // error
- return false;
-
- // Write the current frame to the current cluster (if TestFrame
- // returns 0) or to a newly created cluster (TestFrame returns 1).
- if (result <= 1)
- return true;
-
- // TestFrame returned 2, which means there was a large time
- // difference between the cluster and the frame itself. Do the
- // test again, comparing the frame to the new cluster.
- }
-}
-
-bool Segment::CheckHeaderInfo() {
- if (!header_written_) {
- if (!WriteSegmentHeader())
- return false;
-
- if (!seek_head_.AddSeekEntry(kMkvCluster, MaxOffset()))
- return false;
-
- if (output_cues_ && cues_track_ == 0) {
- // Check for a video track
- for (uint32 i = 0; i < tracks_.track_entries_size(); ++i) {
- const Track* const track = tracks_.GetTrackByIndex(i);
- if (!track)
- return false;
-
- if (tracks_.TrackIsVideo(track->number())) {
- cues_track_ = track->number();
- break;
- }
- }
-
- // Set first track found
- if (cues_track_ == 0) {
- const Track* const track = tracks_.GetTrackByIndex(0);
- if (!track)
- return false;
-
- cues_track_ = track->number();
- }
- }
- }
- return true;
-}
-
-void Segment::UpdateDocTypeVersion() {
- for (uint32 index = 0; index < tracks_.track_entries_size(); ++index) {
- const Track* track = tracks_.GetTrackByIndex(index);
- if (track == NULL)
- break;
- if ((track->codec_delay() || track->seek_pre_roll()) &&
- doc_type_version_ < 4) {
- doc_type_version_ = 4;
- break;
- }
- }
-}
-
-bool Segment::UpdateChunkName(const char* ext, char** name) const {
- if (!name || !ext)
- return false;
-
- char ext_chk[64];
-#ifdef _MSC_VER
- sprintf_s(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext);
-#else
- snprintf(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext);
-#endif
-
- const size_t length = strlen(chunking_base_name_) + strlen(ext_chk) + 1;
- char* const str = new (std::nothrow) char[length]; // NOLINT
- if (!str)
- return false;
-
-#ifdef _MSC_VER
- strcpy_s(str, length - strlen(ext_chk), chunking_base_name_);
- strcat_s(str, length, ext_chk);
-#else
- strcpy(str, chunking_base_name_);
- strcat(str, ext_chk);
-#endif
-
- delete[] * name;
- *name = str;
-
- return true;
-}
-
-int64 Segment::MaxOffset() {
- if (!writer_header_)
- return -1;
-
- int64 offset = writer_header_->Position() - payload_pos_;
-
- if (chunking_) {
- for (int32 i = 0; i < cluster_list_size_; ++i) {
- Cluster* const cluster = cluster_list_[i];
- offset += cluster->Size();
- }
-
- if (writer_cues_)
- offset += writer_cues_->Position();
- }
-
- return offset;
-}
-
-bool Segment::QueueFrame(Frame* frame) {
- const int32 new_size = frames_size_ + 1;
-
- if (new_size > frames_capacity_) {
- // Add more frames.
- const int32 new_capacity = (!frames_capacity_) ? 2 : frames_capacity_ * 2;
-
- if (new_capacity < 1)
- return false;
-
- Frame** const frames = new (std::nothrow) Frame*[new_capacity]; // NOLINT
- if (!frames)
- return false;
-
- for (int32 i = 0; i < frames_size_; ++i) {
- frames[i] = frames_[i];
- }
-
- delete[] frames_;
- frames_ = frames;
- frames_capacity_ = new_capacity;
- }
-
- frames_[frames_size_++] = frame;
-
- return true;
-}
-
-int Segment::WriteFramesAll() {
- if (frames_ == NULL)
- return 0;
-
- if (cluster_list_size_ < 1)
- return -1;
-
- Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
-
- if (!cluster)
- return -1;
-
- for (int32 i = 0; i < frames_size_; ++i) {
- Frame*& frame = frames_[i];
- // TODO(jzern/vigneshv): using Segment::AddGenericFrame here would limit the
- // places where |doc_type_version_| needs to be updated.
- if (frame->discard_padding() != 0)
- doc_type_version_ = 4;
- if (!cluster->AddFrame(frame))
- return -1;
-
- if (new_cuepoint_ && cues_track_ == frame->track_number()) {
- if (!AddCuePoint(frame->timestamp(), cues_track_))
- return -1;
- }
-
- if (frame->timestamp() > last_timestamp_) {
- last_timestamp_ = frame->timestamp();
- last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
- }
-
- delete frame;
- frame = NULL;
- }
-
- const int result = frames_size_;
- frames_size_ = 0;
-
- return result;
-}
-
-bool Segment::WriteFramesLessThan(uint64 timestamp) {
- // Check |cluster_list_size_| to see if this is the first cluster. If it is
- // the first cluster the audio frames that are less than the first video
- // timesatmp will be written in a later step.
- if (frames_size_ > 0 && cluster_list_size_ > 0) {
- if (!frames_)
- return false;
-
- Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
- if (!cluster)
- return false;
-
- int32 shift_left = 0;
-
- // TODO(fgalligan): Change this to use the durations of frames instead of
- // the next frame's start time if the duration is accurate.
- for (int32 i = 1; i < frames_size_; ++i) {
- const Frame* const frame_curr = frames_[i];
-
- if (frame_curr->timestamp() > timestamp)
- break;
-
- const Frame* const frame_prev = frames_[i - 1];
- if (frame_prev->discard_padding() != 0)
- doc_type_version_ = 4;
- if (!cluster->AddFrame(frame_prev))
- return false;
-
- if (new_cuepoint_ && cues_track_ == frame_prev->track_number()) {
- if (!AddCuePoint(frame_prev->timestamp(), cues_track_))
- return false;
- }
-
- ++shift_left;
- if (frame_prev->timestamp() > last_timestamp_) {
- last_timestamp_ = frame_prev->timestamp();
- last_track_timestamp_[frame_prev->track_number() - 1] =
- frame_prev->timestamp();
- }
-
- delete frame_prev;
- }
-
- if (shift_left > 0) {
- if (shift_left >= frames_size_)
- return false;
-
- const int32 new_frames_size = frames_size_ - shift_left;
- for (int32 i = 0; i < new_frames_size; ++i) {
- frames_[i] = frames_[i + shift_left];
- }
-
- frames_size_ = new_frames_size;
- }
- }
-
- return true;
-}
-
-} // namespace mkvmuxer
diff --git a/third_party/libwebm/mkvmuxer/mkvmuxer.cc b/third_party/libwebm/mkvmuxer/mkvmuxer.cc
new file mode 100644
index 0000000..c79ce24
--- /dev/null
+++ b/third_party/libwebm/mkvmuxer/mkvmuxer.cc
@@ -0,0 +1,3769 @@
+// 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 "mkvmuxer/mkvmuxer.h"
+
+#include <cfloat>
+#include <climits>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <memory>
+#include <new>
+#include <vector>
+
+#include "common/webmids.h"
+#include "mkvmuxer/mkvmuxerutil.h"
+#include "mkvmuxer/mkvwriter.h"
+#include "mkvparser/mkvparser.h"
+
+namespace mkvmuxer {
+
+const float MasteringMetadata::kValueNotPresent = FLT_MAX;
+const uint64_t Colour::kValueNotPresent = UINT64_MAX;
+
+namespace {
+// Deallocate the string designated by |dst|, and then copy the |src|
+// string to |dst|. The caller owns both the |src| string and the
+// |dst| copy (hence the caller is responsible for eventually
+// deallocating the strings, either directly, or indirectly via
+// StrCpy). Returns true if the source string was successfully copied
+// to the destination.
+bool StrCpy(const char* src, char** dst_ptr) {
+ if (dst_ptr == NULL)
+ return false;
+
+ char*& dst = *dst_ptr;
+
+ delete[] dst;
+ dst = NULL;
+
+ if (src == NULL)
+ return true;
+
+ const size_t size = strlen(src) + 1;
+
+ dst = new (std::nothrow) char[size]; // NOLINT
+ if (dst == NULL)
+ return false;
+
+ strcpy(dst, src); // NOLINT
+ return true;
+}
+
+typedef std::auto_ptr<PrimaryChromaticity> PrimaryChromaticityPtr;
+bool CopyChromaticity(const PrimaryChromaticity* src,
+ PrimaryChromaticityPtr* dst) {
+ if (!dst)
+ return false;
+
+ dst->reset(new (std::nothrow) PrimaryChromaticity(src->x, src->y));
+ if (!dst->get())
+ return false;
+
+ return true;
+}
+
+} // namespace
+
+///////////////////////////////////////////////////////////////
+//
+// IMkvWriter Class
+
+IMkvWriter::IMkvWriter() {}
+
+IMkvWriter::~IMkvWriter() {}
+
+bool WriteEbmlHeader(IMkvWriter* writer, uint64_t doc_type_version) {
+ // Level 0
+ uint64_t size = EbmlElementSize(libwebm::kMkvEBMLVersion, UINT64_C(1));
+ size += EbmlElementSize(libwebm::kMkvEBMLReadVersion, UINT64_C(1));
+ size += EbmlElementSize(libwebm::kMkvEBMLMaxIDLength, UINT64_C(4));
+ size += EbmlElementSize(libwebm::kMkvEBMLMaxSizeLength, UINT64_C(8));
+ size += EbmlElementSize(libwebm::kMkvDocType, "webm");
+ size += EbmlElementSize(libwebm::kMkvDocTypeVersion, doc_type_version);
+ size += EbmlElementSize(libwebm::kMkvDocTypeReadVersion, UINT64_C(2));
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvEBML, size))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvEBMLVersion, UINT64_C(1)))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvEBMLReadVersion, UINT64_C(1)))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvEBMLMaxIDLength, UINT64_C(4)))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvEBMLMaxSizeLength, UINT64_C(8)))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvDocType, "webm"))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvDocTypeVersion, doc_type_version))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvDocTypeReadVersion, UINT64_C(2)))
+ return false;
+
+ return true;
+}
+
+bool WriteEbmlHeader(IMkvWriter* writer) {
+ return WriteEbmlHeader(writer, mkvmuxer::Segment::kDefaultDocTypeVersion);
+}
+
+bool ChunkedCopy(mkvparser::IMkvReader* source, mkvmuxer::IMkvWriter* dst,
+ int64_t start, int64_t size) {
+ // TODO(vigneshv): Check if this is a reasonable value.
+ const uint32_t kBufSize = 2048;
+ uint8_t* buf = new uint8_t[kBufSize];
+ int64_t offset = start;
+ while (size > 0) {
+ const int64_t read_len = (size > kBufSize) ? kBufSize : size;
+ if (source->Read(offset, static_cast<long>(read_len), buf))
+ return false;
+ dst->Write(buf, static_cast<uint32_t>(read_len));
+ offset += read_len;
+ size -= read_len;
+ }
+ delete[] buf;
+ return true;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// Frame Class
+
+Frame::Frame()
+ : add_id_(0),
+ additional_(NULL),
+ additional_length_(0),
+ duration_(0),
+ duration_set_(false),
+ frame_(NULL),
+ is_key_(false),
+ length_(0),
+ track_number_(0),
+ timestamp_(0),
+ discard_padding_(0),
+ reference_block_timestamp_(0),
+ reference_block_timestamp_set_(false) {}
+
+Frame::~Frame() {
+ delete[] frame_;
+ delete[] additional_;
+}
+
+bool Frame::CopyFrom(const Frame& frame) {
+ delete[] frame_;
+ frame_ = NULL;
+ length_ = 0;
+ if (frame.length() > 0 && frame.frame() != NULL &&
+ !Init(frame.frame(), frame.length())) {
+ return false;
+ }
+ add_id_ = 0;
+ delete[] additional_;
+ additional_ = NULL;
+ additional_length_ = 0;
+ if (frame.additional_length() > 0 && frame.additional() != NULL &&
+ !AddAdditionalData(frame.additional(), frame.additional_length(),
+ frame.add_id())) {
+ return false;
+ }
+ duration_ = frame.duration();
+ duration_set_ = frame.duration_set();
+ is_key_ = frame.is_key();
+ track_number_ = frame.track_number();
+ timestamp_ = frame.timestamp();
+ discard_padding_ = frame.discard_padding();
+ reference_block_timestamp_ = frame.reference_block_timestamp();
+ reference_block_timestamp_set_ = frame.reference_block_timestamp_set();
+ return true;
+}
+
+bool Frame::Init(const uint8_t* frame, uint64_t length) {
+ uint8_t* const data =
+ new (std::nothrow) uint8_t[static_cast<size_t>(length)]; // NOLINT
+ if (!data)
+ return false;
+
+ delete[] frame_;
+ frame_ = data;
+ length_ = length;
+
+ memcpy(frame_, frame, static_cast<size_t>(length_));
+ return true;
+}
+
+bool Frame::AddAdditionalData(const uint8_t* additional, uint64_t length,
+ uint64_t add_id) {
+ uint8_t* const data =
+ new (std::nothrow) uint8_t[static_cast<size_t>(length)]; // NOLINT
+ if (!data)
+ return false;
+
+ delete[] additional_;
+ additional_ = data;
+ additional_length_ = length;
+ add_id_ = add_id;
+
+ memcpy(additional_, additional, static_cast<size_t>(additional_length_));
+ return true;
+}
+
+bool Frame::IsValid() const {
+ if (length_ == 0 || !frame_) {
+ return false;
+ }
+ if ((additional_length_ != 0 && !additional_) ||
+ (additional_ != NULL && additional_length_ == 0)) {
+ return false;
+ }
+ if (track_number_ == 0 || track_number_ > kMaxTrackNumber) {
+ return false;
+ }
+ if (!CanBeSimpleBlock() && !is_key_ && !reference_block_timestamp_set_) {
+ return false;
+ }
+ return true;
+}
+
+bool Frame::CanBeSimpleBlock() const {
+ return additional_ == NULL && discard_padding_ == 0 && duration_ == 0;
+}
+
+void Frame::set_duration(uint64_t duration) {
+ duration_ = duration;
+ duration_set_ = true;
+}
+
+void Frame::set_reference_block_timestamp(int64_t reference_block_timestamp) {
+ reference_block_timestamp_ = reference_block_timestamp;
+ reference_block_timestamp_set_ = true;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// CuePoint Class
+
+CuePoint::CuePoint()
+ : time_(0),
+ track_(0),
+ cluster_pos_(0),
+ block_number_(1),
+ output_block_number_(true) {}
+
+CuePoint::~CuePoint() {}
+
+bool CuePoint::Write(IMkvWriter* writer) const {
+ if (!writer || track_ < 1 || cluster_pos_ < 1)
+ return false;
+
+ uint64_t size =
+ EbmlElementSize(libwebm::kMkvCueClusterPosition, cluster_pos_);
+ size += EbmlElementSize(libwebm::kMkvCueTrack, track_);
+ if (output_block_number_ && block_number_ > 1)
+ size += EbmlElementSize(libwebm::kMkvCueBlockNumber, block_number_);
+ const uint64_t track_pos_size =
+ EbmlMasterElementSize(libwebm::kMkvCueTrackPositions, size) + size;
+ const uint64_t payload_size =
+ EbmlElementSize(libwebm::kMkvCueTime, time_) + track_pos_size;
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvCuePoint, payload_size))
+ return false;
+
+ const int64_t payload_position = writer->Position();
+ if (payload_position < 0)
+ return false;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvCueTime, time_))
+ return false;
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvCueTrackPositions, size))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvCueTrack, track_))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvCueClusterPosition, cluster_pos_))
+ return false;
+ if (output_block_number_ && block_number_ > 1)
+ if (!WriteEbmlElement(writer, libwebm::kMkvCueBlockNumber, block_number_))
+ return false;
+
+ const int64_t stop_position = writer->Position();
+ if (stop_position < 0)
+ return false;
+
+ if (stop_position - payload_position != static_cast<int64_t>(payload_size))
+ return false;
+
+ return true;
+}
+
+uint64_t CuePoint::PayloadSize() const {
+ uint64_t size =
+ EbmlElementSize(libwebm::kMkvCueClusterPosition, cluster_pos_);
+ size += EbmlElementSize(libwebm::kMkvCueTrack, track_);
+ if (output_block_number_ && block_number_ > 1)
+ size += EbmlElementSize(libwebm::kMkvCueBlockNumber, block_number_);
+ const uint64_t track_pos_size =
+ EbmlMasterElementSize(libwebm::kMkvCueTrackPositions, size) + size;
+ const uint64_t payload_size =
+ EbmlElementSize(libwebm::kMkvCueTime, time_) + track_pos_size;
+
+ return payload_size;
+}
+
+uint64_t CuePoint::Size() const {
+ const uint64_t payload_size = PayloadSize();
+ return EbmlMasterElementSize(libwebm::kMkvCuePoint, payload_size) +
+ payload_size;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// Cues Class
+
+Cues::Cues()
+ : cue_entries_capacity_(0),
+ cue_entries_size_(0),
+ cue_entries_(NULL),
+ output_block_number_(true) {}
+
+Cues::~Cues() {
+ if (cue_entries_) {
+ for (int32_t i = 0; i < cue_entries_size_; ++i) {
+ CuePoint* const cue = cue_entries_[i];
+ delete cue;
+ }
+ delete[] cue_entries_;
+ }
+}
+
+bool Cues::AddCue(CuePoint* cue) {
+ if (!cue)
+ return false;
+
+ if ((cue_entries_size_ + 1) > cue_entries_capacity_) {
+ // Add more CuePoints.
+ const int32_t new_capacity =
+ (!cue_entries_capacity_) ? 2 : cue_entries_capacity_ * 2;
+
+ if (new_capacity < 1)
+ return false;
+
+ CuePoint** const cues =
+ new (std::nothrow) CuePoint*[new_capacity]; // NOLINT
+ if (!cues)
+ return false;
+
+ for (int32_t i = 0; i < cue_entries_size_; ++i) {
+ cues[i] = cue_entries_[i];
+ }
+
+ delete[] cue_entries_;
+
+ cue_entries_ = cues;
+ cue_entries_capacity_ = new_capacity;
+ }
+
+ cue->set_output_block_number(output_block_number_);
+ cue_entries_[cue_entries_size_++] = cue;
+ return true;
+}
+
+CuePoint* Cues::GetCueByIndex(int32_t index) const {
+ if (cue_entries_ == NULL)
+ return NULL;
+
+ if (index >= cue_entries_size_)
+ return NULL;
+
+ return cue_entries_[index];
+}
+
+uint64_t Cues::Size() {
+ uint64_t size = 0;
+ for (int32_t i = 0; i < cue_entries_size_; ++i)
+ size += GetCueByIndex(i)->Size();
+ size += EbmlMasterElementSize(libwebm::kMkvCues, size);
+ return size;
+}
+
+bool Cues::Write(IMkvWriter* writer) const {
+ if (!writer)
+ return false;
+
+ uint64_t size = 0;
+ for (int32_t i = 0; i < cue_entries_size_; ++i) {
+ const CuePoint* const cue = GetCueByIndex(i);
+
+ if (!cue)
+ return false;
+
+ size += cue->Size();
+ }
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvCues, size))
+ return false;
+
+ const int64_t payload_position = writer->Position();
+ if (payload_position < 0)
+ return false;
+
+ for (int32_t i = 0; i < cue_entries_size_; ++i) {
+ const CuePoint* const cue = GetCueByIndex(i);
+
+ if (!cue->Write(writer))
+ return false;
+ }
+
+ const int64_t stop_position = writer->Position();
+ if (stop_position < 0)
+ return false;
+
+ if (stop_position - payload_position != static_cast<int64_t>(size))
+ return false;
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// ContentEncAESSettings Class
+
+ContentEncAESSettings::ContentEncAESSettings() : cipher_mode_(kCTR) {}
+
+uint64_t ContentEncAESSettings::Size() const {
+ const uint64_t payload = PayloadSize();
+ const uint64_t size =
+ EbmlMasterElementSize(libwebm::kMkvContentEncAESSettings, payload) +
+ payload;
+ return size;
+}
+
+bool ContentEncAESSettings::Write(IMkvWriter* writer) const {
+ const uint64_t payload = PayloadSize();
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncAESSettings,
+ payload))
+ return false;
+
+ const int64_t payload_position = writer->Position();
+ if (payload_position < 0)
+ return false;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvAESSettingsCipherMode,
+ cipher_mode_))
+ return false;
+
+ const int64_t stop_position = writer->Position();
+ if (stop_position < 0 ||
+ stop_position - payload_position != static_cast<int64_t>(payload))
+ return false;
+
+ return true;
+}
+
+uint64_t ContentEncAESSettings::PayloadSize() const {
+ uint64_t size =
+ EbmlElementSize(libwebm::kMkvAESSettingsCipherMode, cipher_mode_);
+ return size;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// ContentEncoding Class
+
+ContentEncoding::ContentEncoding()
+ : enc_algo_(5),
+ enc_key_id_(NULL),
+ encoding_order_(0),
+ encoding_scope_(1),
+ encoding_type_(1),
+ enc_key_id_length_(0) {}
+
+ContentEncoding::~ContentEncoding() { delete[] enc_key_id_; }
+
+bool ContentEncoding::SetEncryptionID(const uint8_t* id, uint64_t length) {
+ if (!id || length < 1)
+ return false;
+
+ delete[] enc_key_id_;
+
+ enc_key_id_ =
+ new (std::nothrow) uint8_t[static_cast<size_t>(length)]; // NOLINT
+ if (!enc_key_id_)
+ return false;
+
+ memcpy(enc_key_id_, id, static_cast<size_t>(length));
+ enc_key_id_length_ = length;
+
+ return true;
+}
+
+uint64_t ContentEncoding::Size() const {
+ const uint64_t encryption_size = EncryptionSize();
+ const uint64_t encoding_size = EncodingSize(0, encryption_size);
+ const uint64_t encodings_size =
+ EbmlMasterElementSize(libwebm::kMkvContentEncoding, encoding_size) +
+ encoding_size;
+
+ return encodings_size;
+}
+
+bool ContentEncoding::Write(IMkvWriter* writer) const {
+ const uint64_t encryption_size = EncryptionSize();
+ const uint64_t encoding_size = EncodingSize(0, encryption_size);
+ const uint64_t size =
+ EbmlMasterElementSize(libwebm::kMkvContentEncoding, encoding_size) +
+ encoding_size;
+
+ const int64_t payload_position = writer->Position();
+ if (payload_position < 0)
+ return false;
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncoding,
+ encoding_size))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingOrder,
+ encoding_order_))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingScope,
+ encoding_scope_))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingType,
+ encoding_type_))
+ return false;
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncryption,
+ encryption_size))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvContentEncAlgo, enc_algo_))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvContentEncKeyID, enc_key_id_,
+ enc_key_id_length_))
+ return false;
+
+ if (!enc_aes_settings_.Write(writer))
+ return false;
+
+ const int64_t stop_position = writer->Position();
+ if (stop_position < 0 ||
+ stop_position - payload_position != static_cast<int64_t>(size))
+ return false;
+
+ return true;
+}
+
+uint64_t ContentEncoding::EncodingSize(uint64_t compresion_size,
+ uint64_t encryption_size) const {
+ // TODO(fgalligan): Add support for compression settings.
+ if (compresion_size != 0)
+ return 0;
+
+ uint64_t encoding_size = 0;
+
+ if (encryption_size > 0) {
+ encoding_size +=
+ EbmlMasterElementSize(libwebm::kMkvContentEncryption, encryption_size) +
+ encryption_size;
+ }
+ encoding_size +=
+ EbmlElementSize(libwebm::kMkvContentEncodingType, encoding_type_);
+ encoding_size +=
+ EbmlElementSize(libwebm::kMkvContentEncodingScope, encoding_scope_);
+ encoding_size +=
+ EbmlElementSize(libwebm::kMkvContentEncodingOrder, encoding_order_);
+
+ return encoding_size;
+}
+
+uint64_t ContentEncoding::EncryptionSize() const {
+ const uint64_t aes_size = enc_aes_settings_.Size();
+
+ uint64_t encryption_size = EbmlElementSize(libwebm::kMkvContentEncKeyID,
+ enc_key_id_, enc_key_id_length_);
+ encryption_size += EbmlElementSize(libwebm::kMkvContentEncAlgo, enc_algo_);
+
+ return encryption_size + aes_size;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// Track Class
+
+Track::Track(unsigned int* seed)
+ : codec_id_(NULL),
+ codec_private_(NULL),
+ language_(NULL),
+ max_block_additional_id_(0),
+ name_(NULL),
+ number_(0),
+ type_(0),
+ uid_(MakeUID(seed)),
+ codec_delay_(0),
+ seek_pre_roll_(0),
+ default_duration_(0),
+ codec_private_length_(0),
+ content_encoding_entries_(NULL),
+ content_encoding_entries_size_(0) {}
+
+Track::~Track() {
+ delete[] codec_id_;
+ delete[] codec_private_;
+ delete[] language_;
+ delete[] name_;
+
+ if (content_encoding_entries_) {
+ for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
+ ContentEncoding* const encoding = content_encoding_entries_[i];
+ delete encoding;
+ }
+ delete[] content_encoding_entries_;
+ }
+}
+
+bool Track::AddContentEncoding() {
+ const uint32_t count = content_encoding_entries_size_ + 1;
+
+ ContentEncoding** const content_encoding_entries =
+ new (std::nothrow) ContentEncoding*[count]; // NOLINT
+ if (!content_encoding_entries)
+ return false;
+
+ ContentEncoding* const content_encoding =
+ new (std::nothrow) ContentEncoding(); // NOLINT
+ if (!content_encoding) {
+ delete[] content_encoding_entries;
+ return false;
+ }
+
+ for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
+ content_encoding_entries[i] = content_encoding_entries_[i];
+ }
+
+ delete[] content_encoding_entries_;
+
+ content_encoding_entries_ = content_encoding_entries;
+ content_encoding_entries_[content_encoding_entries_size_] = content_encoding;
+ content_encoding_entries_size_ = count;
+ return true;
+}
+
+ContentEncoding* Track::GetContentEncodingByIndex(uint32_t index) const {
+ if (content_encoding_entries_ == NULL)
+ return NULL;
+
+ if (index >= content_encoding_entries_size_)
+ return NULL;
+
+ return content_encoding_entries_[index];
+}
+
+uint64_t Track::PayloadSize() const {
+ uint64_t size = EbmlElementSize(libwebm::kMkvTrackNumber, number_);
+ size += EbmlElementSize(libwebm::kMkvTrackUID, uid_);
+ size += EbmlElementSize(libwebm::kMkvTrackType, type_);
+ if (codec_id_)
+ size += EbmlElementSize(libwebm::kMkvCodecID, codec_id_);
+ if (codec_private_)
+ size += EbmlElementSize(libwebm::kMkvCodecPrivate, codec_private_,
+ codec_private_length_);
+ if (language_)
+ size += EbmlElementSize(libwebm::kMkvLanguage, language_);
+ if (name_)
+ size += EbmlElementSize(libwebm::kMkvName, name_);
+ if (max_block_additional_id_)
+ size += EbmlElementSize(libwebm::kMkvMaxBlockAdditionID,
+ max_block_additional_id_);
+ if (codec_delay_)
+ size += EbmlElementSize(libwebm::kMkvCodecDelay, codec_delay_);
+ if (seek_pre_roll_)
+ size += EbmlElementSize(libwebm::kMkvSeekPreRoll, seek_pre_roll_);
+ if (default_duration_)
+ size += EbmlElementSize(libwebm::kMkvDefaultDuration, default_duration_);
+
+ if (content_encoding_entries_size_ > 0) {
+ uint64_t content_encodings_size = 0;
+ for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
+ ContentEncoding* const encoding = content_encoding_entries_[i];
+ content_encodings_size += encoding->Size();
+ }
+
+ size += EbmlMasterElementSize(libwebm::kMkvContentEncodings,
+ content_encodings_size) +
+ content_encodings_size;
+ }
+
+ return size;
+}
+
+uint64_t Track::Size() const {
+ uint64_t size = PayloadSize();
+ size += EbmlMasterElementSize(libwebm::kMkvTrackEntry, size);
+ return size;
+}
+
+bool Track::Write(IMkvWriter* writer) const {
+ if (!writer)
+ return false;
+
+ // mandatory elements without a default value.
+ if (!type_ || !codec_id_)
+ return false;
+
+ // |size| may be bigger than what is written out in this function because
+ // derived classes may write out more data in the Track element.
+ const uint64_t payload_size = PayloadSize();
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvTrackEntry, payload_size))
+ return false;
+
+ uint64_t size = EbmlElementSize(libwebm::kMkvTrackNumber, number_);
+ size += EbmlElementSize(libwebm::kMkvTrackUID, uid_);
+ size += EbmlElementSize(libwebm::kMkvTrackType, type_);
+ if (codec_id_)
+ size += EbmlElementSize(libwebm::kMkvCodecID, codec_id_);
+ if (codec_private_)
+ size += EbmlElementSize(libwebm::kMkvCodecPrivate, codec_private_,
+ codec_private_length_);
+ if (language_)
+ size += EbmlElementSize(libwebm::kMkvLanguage, language_);
+ if (name_)
+ size += EbmlElementSize(libwebm::kMkvName, name_);
+ if (max_block_additional_id_)
+ size += EbmlElementSize(libwebm::kMkvMaxBlockAdditionID,
+ max_block_additional_id_);
+ if (codec_delay_)
+ size += EbmlElementSize(libwebm::kMkvCodecDelay, codec_delay_);
+ if (seek_pre_roll_)
+ size += EbmlElementSize(libwebm::kMkvSeekPreRoll, seek_pre_roll_);
+ if (default_duration_)
+ size += EbmlElementSize(libwebm::kMkvDefaultDuration, default_duration_);
+
+ const int64_t payload_position = writer->Position();
+ if (payload_position < 0)
+ return false;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvTrackNumber, number_))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvTrackUID, uid_))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvTrackType, type_))
+ return false;
+ if (max_block_additional_id_) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvMaxBlockAdditionID,
+ max_block_additional_id_)) {
+ return false;
+ }
+ }
+ if (codec_delay_) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvCodecDelay, codec_delay_))
+ return false;
+ }
+ if (seek_pre_roll_) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvSeekPreRoll, seek_pre_roll_))
+ return false;
+ }
+ if (default_duration_) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvDefaultDuration,
+ default_duration_))
+ return false;
+ }
+ if (codec_id_) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvCodecID, codec_id_))
+ return false;
+ }
+ if (codec_private_) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvCodecPrivate, codec_private_,
+ codec_private_length_))
+ return false;
+ }
+ if (language_) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvLanguage, language_))
+ return false;
+ }
+ if (name_) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvName, name_))
+ return false;
+ }
+
+ int64_t stop_position = writer->Position();
+ if (stop_position < 0 ||
+ stop_position - payload_position != static_cast<int64_t>(size))
+ return false;
+
+ if (content_encoding_entries_size_ > 0) {
+ uint64_t content_encodings_size = 0;
+ for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
+ ContentEncoding* const encoding = content_encoding_entries_[i];
+ content_encodings_size += encoding->Size();
+ }
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncodings,
+ content_encodings_size))
+ return false;
+
+ for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
+ ContentEncoding* const encoding = content_encoding_entries_[i];
+ if (!encoding->Write(writer))
+ return false;
+ }
+ }
+
+ stop_position = writer->Position();
+ if (stop_position < 0)
+ return false;
+ return true;
+}
+
+bool Track::SetCodecPrivate(const uint8_t* codec_private, uint64_t length) {
+ if (!codec_private || length < 1)
+ return false;
+
+ delete[] codec_private_;
+
+ codec_private_ =
+ new (std::nothrow) uint8_t[static_cast<size_t>(length)]; // NOLINT
+ if (!codec_private_)
+ return false;
+
+ memcpy(codec_private_, codec_private, static_cast<size_t>(length));
+ codec_private_length_ = length;
+
+ return true;
+}
+
+void Track::set_codec_id(const char* codec_id) {
+ if (codec_id) {
+ delete[] codec_id_;
+
+ const size_t length = strlen(codec_id) + 1;
+ codec_id_ = new (std::nothrow) char[length]; // NOLINT
+ if (codec_id_) {
+#ifdef _MSC_VER
+ strcpy_s(codec_id_, length, codec_id);
+#else
+ strcpy(codec_id_, codec_id);
+#endif
+ }
+ }
+}
+
+// TODO(fgalligan): Vet the language parameter.
+void Track::set_language(const char* language) {
+ if (language) {
+ delete[] language_;
+
+ const size_t length = strlen(language) + 1;
+ language_ = new (std::nothrow) char[length]; // NOLINT
+ if (language_) {
+#ifdef _MSC_VER
+ strcpy_s(language_, length, language);
+#else
+ strcpy(language_, language);
+#endif
+ }
+ }
+}
+
+void Track::set_name(const char* name) {
+ if (name) {
+ delete[] name_;
+
+ const size_t length = strlen(name) + 1;
+ name_ = new (std::nothrow) char[length]; // NOLINT
+ if (name_) {
+#ifdef _MSC_VER
+ strcpy_s(name_, length, name);
+#else
+ strcpy(name_, name);
+#endif
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////
+//
+// Colour and its child elements
+
+uint64_t PrimaryChromaticity::PrimaryChromaticityPayloadSize(
+ libwebm::MkvId x_id, libwebm::MkvId y_id) const {
+ return EbmlElementSize(x_id, x) + EbmlElementSize(y_id, y);
+}
+
+bool PrimaryChromaticity::Write(IMkvWriter* writer, libwebm::MkvId x_id,
+ libwebm::MkvId y_id) const {
+ return WriteEbmlElement(writer, x_id, x) && WriteEbmlElement(writer, y_id, y);
+}
+
+uint64_t MasteringMetadata::MasteringMetadataSize() const {
+ uint64_t size = PayloadSize();
+
+ if (size > 0)
+ size += EbmlMasterElementSize(libwebm::kMkvMasteringMetadata, size);
+
+ return size;
+}
+
+bool MasteringMetadata::Write(IMkvWriter* writer) const {
+ const uint64_t size = PayloadSize();
+
+ // Don't write an empty element.
+ if (size == 0)
+ return true;
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvMasteringMetadata, size))
+ return false;
+ if (luminance_max != kValueNotPresent &&
+ !WriteEbmlElement(writer, libwebm::kMkvLuminanceMax, luminance_max)) {
+ return false;
+ }
+ if (luminance_min != kValueNotPresent &&
+ !WriteEbmlElement(writer, libwebm::kMkvLuminanceMin, luminance_min)) {
+ return false;
+ }
+ if (r_ &&
+ !r_->Write(writer, libwebm::kMkvPrimaryRChromaticityX,
+ libwebm::kMkvPrimaryRChromaticityY)) {
+ return false;
+ }
+ if (g_ &&
+ !g_->Write(writer, libwebm::kMkvPrimaryGChromaticityX,
+ libwebm::kMkvPrimaryGChromaticityY)) {
+ return false;
+ }
+ if (b_ &&
+ !b_->Write(writer, libwebm::kMkvPrimaryBChromaticityX,
+ libwebm::kMkvPrimaryBChromaticityY)) {
+ return false;
+ }
+ if (white_point_ &&
+ !white_point_->Write(writer, libwebm::kMkvWhitePointChromaticityX,
+ libwebm::kMkvWhitePointChromaticityY)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool MasteringMetadata::SetChromaticity(
+ const PrimaryChromaticity* r, const PrimaryChromaticity* g,
+ const PrimaryChromaticity* b, const PrimaryChromaticity* white_point) {
+ PrimaryChromaticityPtr r_ptr(NULL);
+ if (r) {
+ if (!CopyChromaticity(r, &r_ptr))
+ return false;
+ }
+ PrimaryChromaticityPtr g_ptr(NULL);
+ if (g) {
+ if (!CopyChromaticity(g, &g_ptr))
+ return false;
+ }
+ PrimaryChromaticityPtr b_ptr(NULL);
+ if (b) {
+ if (!CopyChromaticity(b, &b_ptr))
+ return false;
+ }
+ PrimaryChromaticityPtr wp_ptr(NULL);
+ if (white_point) {
+ if (!CopyChromaticity(white_point, &wp_ptr))
+ return false;
+ }
+
+ r_ = r_ptr.release();
+ g_ = g_ptr.release();
+ b_ = b_ptr.release();
+ white_point_ = wp_ptr.release();
+ return true;
+}
+
+uint64_t MasteringMetadata::PayloadSize() const {
+ uint64_t size = 0;
+
+ if (luminance_max != kValueNotPresent)
+ size += EbmlElementSize(libwebm::kMkvLuminanceMax, luminance_max);
+ if (luminance_min != kValueNotPresent)
+ size += EbmlElementSize(libwebm::kMkvLuminanceMin, luminance_min);
+
+ if (r_) {
+ size += r_->PrimaryChromaticityPayloadSize(
+ libwebm::kMkvPrimaryRChromaticityX, libwebm::kMkvPrimaryRChromaticityY);
+ }
+ if (g_) {
+ size += g_->PrimaryChromaticityPayloadSize(
+ libwebm::kMkvPrimaryGChromaticityX, libwebm::kMkvPrimaryGChromaticityY);
+ }
+ if (b_) {
+ size += b_->PrimaryChromaticityPayloadSize(
+ libwebm::kMkvPrimaryBChromaticityX, libwebm::kMkvPrimaryBChromaticityY);
+ }
+ if (white_point_) {
+ size += white_point_->PrimaryChromaticityPayloadSize(
+ libwebm::kMkvWhitePointChromaticityX,
+ libwebm::kMkvWhitePointChromaticityY);
+ }
+
+ return size;
+}
+
+uint64_t Colour::ColourSize() const {
+ uint64_t size = PayloadSize();
+
+ if (size > 0)
+ size += EbmlMasterElementSize(libwebm::kMkvColour, size);
+
+ return size;
+}
+
+bool Colour::Write(IMkvWriter* writer) const {
+ const uint64_t size = PayloadSize();
+
+ // Don't write an empty element.
+ if (size == 0)
+ return true;
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvColour, size))
+ return false;
+
+ if (matrix_coefficients != kValueNotPresent &&
+ !WriteEbmlElement(writer, libwebm::kMkvMatrixCoefficients,
+ matrix_coefficients)) {
+ return false;
+ }
+ if (bits_per_channel != kValueNotPresent &&
+ !WriteEbmlElement(writer, libwebm::kMkvBitsPerChannel,
+ bits_per_channel)) {
+ return false;
+ }
+ if (chroma_subsampling_horz != kValueNotPresent &&
+ !WriteEbmlElement(writer, libwebm::kMkvChromaSubsamplingHorz,
+ chroma_subsampling_horz)) {
+ return false;
+ }
+ if (chroma_subsampling_vert != kValueNotPresent &&
+ !WriteEbmlElement(writer, libwebm::kMkvChromaSubsamplingVert,
+ chroma_subsampling_vert)) {
+ return false;
+ }
+
+ if (cb_subsampling_horz != kValueNotPresent &&
+ !WriteEbmlElement(writer, libwebm::kMkvCbSubsamplingHorz,
+ cb_subsampling_horz)) {
+ return false;
+ }
+ if (cb_subsampling_vert != kValueNotPresent &&
+ !WriteEbmlElement(writer, libwebm::kMkvCbSubsamplingVert,
+ cb_subsampling_vert)) {
+ return false;
+ }
+ if (chroma_siting_horz != kValueNotPresent &&
+ !WriteEbmlElement(writer, libwebm::kMkvChromaSitingHorz,
+ chroma_siting_horz)) {
+ return false;
+ }
+ if (chroma_siting_vert != kValueNotPresent &&
+ !WriteEbmlElement(writer, libwebm::kMkvChromaSitingVert,
+ chroma_siting_vert)) {
+ return false;
+ }
+ if (range != kValueNotPresent &&
+ !WriteEbmlElement(writer, libwebm::kMkvRange, range)) {
+ return false;
+ }
+ if (transfer_characteristics != kValueNotPresent &&
+ !WriteEbmlElement(writer, libwebm::kMkvTransferCharacteristics,
+ transfer_characteristics)) {
+ return false;
+ }
+ if (primaries != kValueNotPresent &&
+ !WriteEbmlElement(writer, libwebm::kMkvPrimaries, primaries)) {
+ return false;
+ }
+ if (max_cll != kValueNotPresent &&
+ !WriteEbmlElement(writer, libwebm::kMkvMaxCLL, max_cll)) {
+ return false;
+ }
+ if (max_fall != kValueNotPresent &&
+ !WriteEbmlElement(writer, libwebm::kMkvMaxFALL, max_fall)) {
+ return false;
+ }
+
+ if (mastering_metadata_ && !mastering_metadata_->Write(writer))
+ return false;
+
+ return true;
+}
+
+bool Colour::SetMasteringMetadata(const MasteringMetadata& mastering_metadata) {
+ std::auto_ptr<MasteringMetadata> mm_ptr(new MasteringMetadata());
+ if (!mm_ptr.get())
+ return false;
+
+ mm_ptr->luminance_max = mastering_metadata.luminance_max;
+ mm_ptr->luminance_min = mastering_metadata.luminance_min;
+
+ if (!mm_ptr->SetChromaticity(mastering_metadata.r(), mastering_metadata.g(),
+ mastering_metadata.b(),
+ mastering_metadata.white_point())) {
+ return false;
+ }
+
+ delete mastering_metadata_;
+ mastering_metadata_ = mm_ptr.release();
+ return true;
+}
+
+uint64_t Colour::PayloadSize() const {
+ uint64_t size = 0;
+
+ if (matrix_coefficients != kValueNotPresent)
+ size +=
+ EbmlElementSize(libwebm::kMkvMatrixCoefficients, matrix_coefficients);
+ if (bits_per_channel != kValueNotPresent)
+ size += EbmlElementSize(libwebm::kMkvBitsPerChannel, bits_per_channel);
+ if (chroma_subsampling_horz != kValueNotPresent)
+ size += EbmlElementSize(libwebm::kMkvChromaSubsamplingHorz,
+ chroma_subsampling_horz);
+ if (chroma_subsampling_vert != kValueNotPresent)
+ size += EbmlElementSize(libwebm::kMkvChromaSubsamplingVert,
+ chroma_subsampling_vert);
+ if (cb_subsampling_horz != kValueNotPresent)
+ size +=
+ EbmlElementSize(libwebm::kMkvCbSubsamplingHorz, cb_subsampling_horz);
+ if (cb_subsampling_vert != kValueNotPresent)
+ size +=
+ EbmlElementSize(libwebm::kMkvCbSubsamplingVert, cb_subsampling_vert);
+ if (chroma_siting_horz != kValueNotPresent)
+ size += EbmlElementSize(libwebm::kMkvChromaSitingHorz, chroma_siting_horz);
+ if (chroma_siting_vert != kValueNotPresent)
+ size += EbmlElementSize(libwebm::kMkvChromaSitingVert, chroma_siting_vert);
+ if (range != kValueNotPresent)
+ size += EbmlElementSize(libwebm::kMkvRange, range);
+ if (transfer_characteristics != kValueNotPresent)
+ size += EbmlElementSize(libwebm::kMkvTransferCharacteristics,
+ transfer_characteristics);
+ if (primaries != kValueNotPresent)
+ size += EbmlElementSize(libwebm::kMkvPrimaries, primaries);
+ if (max_cll != kValueNotPresent)
+ size += EbmlElementSize(libwebm::kMkvMaxCLL, max_cll);
+ if (max_fall != kValueNotPresent)
+ size += EbmlElementSize(libwebm::kMkvMaxFALL, max_fall);
+
+ if (mastering_metadata_)
+ size += mastering_metadata_->MasteringMetadataSize();
+
+ return size;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// VideoTrack Class
+
+VideoTrack::VideoTrack(unsigned int* seed)
+ : Track(seed),
+ display_height_(0),
+ display_width_(0),
+ crop_left_(0),
+ crop_right_(0),
+ crop_top_(0),
+ crop_bottom_(0),
+ frame_rate_(0.0),
+ height_(0),
+ stereo_mode_(0),
+ alpha_mode_(0),
+ width_(0),
+ colour_(NULL) {}
+
+VideoTrack::~VideoTrack() { delete colour_; }
+
+bool VideoTrack::SetStereoMode(uint64_t stereo_mode) {
+ if (stereo_mode != kMono && stereo_mode != kSideBySideLeftIsFirst &&
+ stereo_mode != kTopBottomRightIsFirst &&
+ stereo_mode != kTopBottomLeftIsFirst &&
+ stereo_mode != kSideBySideRightIsFirst)
+ return false;
+
+ stereo_mode_ = stereo_mode;
+ return true;
+}
+
+bool VideoTrack::SetAlphaMode(uint64_t alpha_mode) {
+ if (alpha_mode != kNoAlpha && alpha_mode != kAlpha)
+ return false;
+
+ alpha_mode_ = alpha_mode;
+ return true;
+}
+
+uint64_t VideoTrack::PayloadSize() const {
+ const uint64_t parent_size = Track::PayloadSize();
+
+ uint64_t size = VideoPayloadSize();
+ size += EbmlMasterElementSize(libwebm::kMkvVideo, size);
+
+ return parent_size + size;
+}
+
+bool VideoTrack::Write(IMkvWriter* writer) const {
+ if (!Track::Write(writer))
+ return false;
+
+ const uint64_t size = VideoPayloadSize();
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvVideo, size))
+ return false;
+
+ const int64_t payload_position = writer->Position();
+ if (payload_position < 0)
+ return false;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvPixelWidth, width_))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvPixelHeight, height_))
+ return false;
+ if (display_width_ > 0) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvDisplayWidth, display_width_))
+ return false;
+ }
+ if (display_height_ > 0) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvDisplayHeight, display_height_))
+ return false;
+ }
+ if (crop_left_ > 0) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropLeft, crop_left_))
+ return false;
+ }
+ if (crop_right_ > 0) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropRight, crop_right_))
+ return false;
+ }
+ if (crop_top_ > 0) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropTop, crop_top_))
+ return false;
+ }
+ if (crop_bottom_ > 0) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropBottom, crop_bottom_))
+ return false;
+ }
+ if (stereo_mode_ > kMono) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvStereoMode, stereo_mode_))
+ return false;
+ }
+ if (alpha_mode_ > kNoAlpha) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvAlphaMode, alpha_mode_))
+ return false;
+ }
+ if (frame_rate_ > 0.0) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvFrameRate,
+ static_cast<float>(frame_rate_))) {
+ return false;
+ }
+ }
+ if (colour_) {
+ if (!colour_->Write(writer))
+ return false;
+ }
+
+ const int64_t stop_position = writer->Position();
+ if (stop_position < 0 ||
+ stop_position - payload_position != static_cast<int64_t>(size)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool VideoTrack::SetColour(const Colour& colour) {
+ std::auto_ptr<Colour> colour_ptr(new Colour());
+ if (!colour_ptr.get())
+ return false;
+
+ if (colour.mastering_metadata()) {
+ if (!colour_ptr->SetMasteringMetadata(*colour.mastering_metadata()))
+ return false;
+ }
+
+ colour_ptr->matrix_coefficients = colour.matrix_coefficients;
+ colour_ptr->bits_per_channel = colour.bits_per_channel;
+ colour_ptr->chroma_subsampling_horz = colour.chroma_subsampling_horz;
+ colour_ptr->chroma_subsampling_vert = colour.chroma_subsampling_vert;
+ colour_ptr->cb_subsampling_horz = colour.cb_subsampling_horz;
+ colour_ptr->cb_subsampling_vert = colour.cb_subsampling_vert;
+ colour_ptr->chroma_siting_horz = colour.chroma_siting_horz;
+ colour_ptr->chroma_siting_vert = colour.chroma_siting_vert;
+ colour_ptr->range = colour.range;
+ colour_ptr->transfer_characteristics = colour.transfer_characteristics;
+ colour_ptr->primaries = colour.primaries;
+ colour_ptr->max_cll = colour.max_cll;
+ colour_ptr->max_fall = colour.max_fall;
+ colour_ = colour_ptr.release();
+ return true;
+}
+
+uint64_t VideoTrack::VideoPayloadSize() const {
+ uint64_t size = EbmlElementSize(libwebm::kMkvPixelWidth, width_);
+ size += EbmlElementSize(libwebm::kMkvPixelHeight, height_);
+ if (display_width_ > 0)
+ size += EbmlElementSize(libwebm::kMkvDisplayWidth, display_width_);
+ if (display_height_ > 0)
+ size += EbmlElementSize(libwebm::kMkvDisplayHeight, display_height_);
+ if (crop_left_ > 0)
+ size += EbmlElementSize(libwebm::kMkvPixelCropLeft, crop_left_);
+ if (crop_right_ > 0)
+ size += EbmlElementSize(libwebm::kMkvPixelCropRight, crop_right_);
+ if (crop_top_ > 0)
+ size += EbmlElementSize(libwebm::kMkvPixelCropTop, crop_top_);
+ if (crop_bottom_ > 0)
+ size += EbmlElementSize(libwebm::kMkvPixelCropBottom, crop_bottom_);
+ if (stereo_mode_ > kMono)
+ size += EbmlElementSize(libwebm::kMkvStereoMode, stereo_mode_);
+ if (alpha_mode_ > kNoAlpha)
+ size += EbmlElementSize(libwebm::kMkvAlphaMode, alpha_mode_);
+ if (frame_rate_ > 0.0)
+ size += EbmlElementSize(libwebm::kMkvFrameRate,
+ static_cast<float>(frame_rate_));
+ if (colour_)
+ size += colour_->ColourSize();
+
+ return size;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// AudioTrack Class
+
+AudioTrack::AudioTrack(unsigned int* seed)
+ : Track(seed), bit_depth_(0), channels_(1), sample_rate_(0.0) {}
+
+AudioTrack::~AudioTrack() {}
+
+uint64_t AudioTrack::PayloadSize() const {
+ const uint64_t parent_size = Track::PayloadSize();
+
+ uint64_t size = EbmlElementSize(libwebm::kMkvSamplingFrequency,
+ static_cast<float>(sample_rate_));
+ size += EbmlElementSize(libwebm::kMkvChannels, channels_);
+ if (bit_depth_ > 0)
+ size += EbmlElementSize(libwebm::kMkvBitDepth, bit_depth_);
+ size += EbmlMasterElementSize(libwebm::kMkvAudio, size);
+
+ return parent_size + size;
+}
+
+bool AudioTrack::Write(IMkvWriter* writer) const {
+ if (!Track::Write(writer))
+ return false;
+
+ // Calculate AudioSettings size.
+ uint64_t size = EbmlElementSize(libwebm::kMkvSamplingFrequency,
+ static_cast<float>(sample_rate_));
+ size += EbmlElementSize(libwebm::kMkvChannels, channels_);
+ if (bit_depth_ > 0)
+ size += EbmlElementSize(libwebm::kMkvBitDepth, bit_depth_);
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvAudio, size))
+ return false;
+
+ const int64_t payload_position = writer->Position();
+ if (payload_position < 0)
+ return false;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvSamplingFrequency,
+ static_cast<float>(sample_rate_)))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvChannels, channels_))
+ return false;
+ if (bit_depth_ > 0)
+ if (!WriteEbmlElement(writer, libwebm::kMkvBitDepth, bit_depth_))
+ return false;
+
+ const int64_t stop_position = writer->Position();
+ if (stop_position < 0 ||
+ stop_position - payload_position != static_cast<int64_t>(size))
+ return false;
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// Tracks Class
+
+const char Tracks::kOpusCodecId[] = "A_OPUS";
+const char Tracks::kVorbisCodecId[] = "A_VORBIS";
+const char Tracks::kVp8CodecId[] = "V_VP8";
+const char Tracks::kVp9CodecId[] = "V_VP9";
+const char Tracks::kVp10CodecId[] = "V_VP10";
+
+Tracks::Tracks()
+ : track_entries_(NULL), track_entries_size_(0), wrote_tracks_(false) {}
+
+Tracks::~Tracks() {
+ if (track_entries_) {
+ for (uint32_t i = 0; i < track_entries_size_; ++i) {
+ Track* const track = track_entries_[i];
+ delete track;
+ }
+ delete[] track_entries_;
+ }
+}
+
+bool Tracks::AddTrack(Track* track, int32_t number) {
+ if (number < 0 || wrote_tracks_)
+ return false;
+
+ // This muxer only supports track numbers in the range [1, 126], in
+ // order to be able (to use Matroska integer representation) to
+ // serialize the block header (of which the track number is a part)
+ // for a frame using exactly 4 bytes.
+
+ if (number > 0x7E)
+ return false;
+
+ uint32_t track_num = number;
+
+ if (track_num > 0) {
+ // Check to make sure a track does not already have |track_num|.
+ for (uint32_t i = 0; i < track_entries_size_; ++i) {
+ if (track_entries_[i]->number() == track_num)
+ return false;
+ }
+ }
+
+ const uint32_t count = track_entries_size_ + 1;
+
+ Track** const track_entries = new (std::nothrow) Track*[count]; // NOLINT
+ if (!track_entries)
+ return false;
+
+ for (uint32_t i = 0; i < track_entries_size_; ++i) {
+ track_entries[i] = track_entries_[i];
+ }
+
+ delete[] track_entries_;
+
+ // Find the lowest availible track number > 0.
+ if (track_num == 0) {
+ track_num = count;
+
+ // Check to make sure a track does not already have |track_num|.
+ bool exit = false;
+ do {
+ exit = true;
+ for (uint32_t i = 0; i < track_entries_size_; ++i) {
+ if (track_entries[i]->number() == track_num) {
+ track_num++;
+ exit = false;
+ break;
+ }
+ }
+ } while (!exit);
+ }
+ track->set_number(track_num);
+
+ track_entries_ = track_entries;
+ track_entries_[track_entries_size_] = track;
+ track_entries_size_ = count;
+ return true;
+}
+
+const Track* Tracks::GetTrackByIndex(uint32_t index) const {
+ if (track_entries_ == NULL)
+ return NULL;
+
+ if (index >= track_entries_size_)
+ return NULL;
+
+ return track_entries_[index];
+}
+
+Track* Tracks::GetTrackByNumber(uint64_t track_number) const {
+ const int32_t count = track_entries_size();
+ for (int32_t i = 0; i < count; ++i) {
+ if (track_entries_[i]->number() == track_number)
+ return track_entries_[i];
+ }
+
+ return NULL;
+}
+
+bool Tracks::TrackIsAudio(uint64_t track_number) const {
+ const Track* const track = GetTrackByNumber(track_number);
+
+ if (track->type() == kAudio)
+ return true;
+
+ return false;
+}
+
+bool Tracks::TrackIsVideo(uint64_t track_number) const {
+ const Track* const track = GetTrackByNumber(track_number);
+
+ if (track->type() == kVideo)
+ return true;
+
+ return false;
+}
+
+bool Tracks::Write(IMkvWriter* writer) const {
+ uint64_t size = 0;
+ const int32_t count = track_entries_size();
+ for (int32_t i = 0; i < count; ++i) {
+ const Track* const track = GetTrackByIndex(i);
+
+ if (!track)
+ return false;
+
+ size += track->Size();
+ }
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvTracks, size))
+ return false;
+
+ const int64_t payload_position = writer->Position();
+ if (payload_position < 0)
+ return false;
+
+ for (int32_t i = 0; i < count; ++i) {
+ const Track* const track = GetTrackByIndex(i);
+ if (!track->Write(writer))
+ return false;
+ }
+
+ const int64_t stop_position = writer->Position();
+ if (stop_position < 0 ||
+ stop_position - payload_position != static_cast<int64_t>(size))
+ return false;
+
+ wrote_tracks_ = true;
+ return true;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// Chapter Class
+
+bool Chapter::set_id(const char* id) { return StrCpy(id, &id_); }
+
+void Chapter::set_time(const Segment& segment, uint64_t start_ns,
+ uint64_t end_ns) {
+ const SegmentInfo* const info = segment.GetSegmentInfo();
+ const uint64_t timecode_scale = info->timecode_scale();
+ start_timecode_ = start_ns / timecode_scale;
+ end_timecode_ = end_ns / timecode_scale;
+}
+
+bool Chapter::add_string(const char* title, const char* language,
+ const char* country) {
+ if (!ExpandDisplaysArray())
+ return false;
+
+ Display& d = displays_[displays_count_++];
+ d.Init();
+
+ if (!d.set_title(title))
+ return false;
+
+ if (!d.set_language(language))
+ return false;
+
+ if (!d.set_country(country))
+ return false;
+
+ return true;
+}
+
+Chapter::Chapter() {
+ // This ctor only constructs the object. Proper initialization is
+ // done in Init() (called in Chapters::AddChapter()). The only
+ // reason we bother implementing this ctor is because we had to
+ // declare it as private (along with the dtor), in order to prevent
+ // clients from creating Chapter instances (a privelege we grant
+ // only to the Chapters class). Doing no initialization here also
+ // means that creating arrays of chapter objects is more efficient,
+ // because we only initialize each new chapter object as it becomes
+ // active on the array.
+}
+
+Chapter::~Chapter() {}
+
+void Chapter::Init(unsigned int* seed) {
+ id_ = NULL;
+ start_timecode_ = 0;
+ end_timecode_ = 0;
+ displays_ = NULL;
+ displays_size_ = 0;
+ displays_count_ = 0;
+ uid_ = MakeUID(seed);
+}
+
+void Chapter::ShallowCopy(Chapter* dst) const {
+ dst->id_ = id_;
+ dst->start_timecode_ = start_timecode_;
+ dst->end_timecode_ = end_timecode_;
+ dst->uid_ = uid_;
+ dst->displays_ = displays_;
+ dst->displays_size_ = displays_size_;
+ dst->displays_count_ = displays_count_;
+}
+
+void Chapter::Clear() {
+ StrCpy(NULL, &id_);
+
+ while (displays_count_ > 0) {
+ Display& d = displays_[--displays_count_];
+ d.Clear();
+ }
+
+ delete[] displays_;
+ displays_ = NULL;
+
+ displays_size_ = 0;
+}
+
+bool Chapter::ExpandDisplaysArray() {
+ if (displays_size_ > displays_count_)
+ return true; // nothing to do yet
+
+ const int size = (displays_size_ == 0) ? 1 : 2 * displays_size_;
+
+ Display* const displays = new (std::nothrow) Display[size]; // NOLINT
+ if (displays == NULL)
+ return false;
+
+ for (int idx = 0; idx < displays_count_; ++idx) {
+ displays[idx] = displays_[idx]; // shallow copy
+ }
+
+ delete[] displays_;
+
+ displays_ = displays;
+ displays_size_ = size;
+
+ return true;
+}
+
+uint64_t Chapter::WriteAtom(IMkvWriter* writer) const {
+ uint64_t payload_size =
+ EbmlElementSize(libwebm::kMkvChapterStringUID, id_) +
+ EbmlElementSize(libwebm::kMkvChapterUID, uid_) +
+ EbmlElementSize(libwebm::kMkvChapterTimeStart, start_timecode_) +
+ EbmlElementSize(libwebm::kMkvChapterTimeEnd, end_timecode_);
+
+ for (int idx = 0; idx < displays_count_; ++idx) {
+ const Display& d = displays_[idx];
+ payload_size += d.WriteDisplay(NULL);
+ }
+
+ const uint64_t atom_size =
+ EbmlMasterElementSize(libwebm::kMkvChapterAtom, payload_size) +
+ payload_size;
+
+ if (writer == NULL)
+ return atom_size;
+
+ const int64_t start = writer->Position();
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvChapterAtom, payload_size))
+ return 0;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvChapterStringUID, id_))
+ return 0;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvChapterUID, uid_))
+ return 0;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvChapterTimeStart, start_timecode_))
+ return 0;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvChapterTimeEnd, end_timecode_))
+ return 0;
+
+ for (int idx = 0; idx < displays_count_; ++idx) {
+ const Display& d = displays_[idx];
+
+ if (!d.WriteDisplay(writer))
+ return 0;
+ }
+
+ const int64_t stop = writer->Position();
+
+ if (stop >= start && uint64_t(stop - start) != atom_size)
+ return 0;
+
+ return atom_size;
+}
+
+void Chapter::Display::Init() {
+ title_ = NULL;
+ language_ = NULL;
+ country_ = NULL;
+}
+
+void Chapter::Display::Clear() {
+ StrCpy(NULL, &title_);
+ StrCpy(NULL, &language_);
+ StrCpy(NULL, &country_);
+}
+
+bool Chapter::Display::set_title(const char* title) {
+ return StrCpy(title, &title_);
+}
+
+bool Chapter::Display::set_language(const char* language) {
+ return StrCpy(language, &language_);
+}
+
+bool Chapter::Display::set_country(const char* country) {
+ return StrCpy(country, &country_);
+}
+
+uint64_t Chapter::Display::WriteDisplay(IMkvWriter* writer) const {
+ uint64_t payload_size = EbmlElementSize(libwebm::kMkvChapString, title_);
+
+ if (language_)
+ payload_size += EbmlElementSize(libwebm::kMkvChapLanguage, language_);
+
+ if (country_)
+ payload_size += EbmlElementSize(libwebm::kMkvChapCountry, country_);
+
+ const uint64_t display_size =
+ EbmlMasterElementSize(libwebm::kMkvChapterDisplay, payload_size) +
+ payload_size;
+
+ if (writer == NULL)
+ return display_size;
+
+ const int64_t start = writer->Position();
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvChapterDisplay,
+ payload_size))
+ return 0;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvChapString, title_))
+ return 0;
+
+ if (language_) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvChapLanguage, language_))
+ return 0;
+ }
+
+ if (country_) {
+ if (!WriteEbmlElement(writer, libwebm::kMkvChapCountry, country_))
+ return 0;
+ }
+
+ const int64_t stop = writer->Position();
+
+ if (stop >= start && uint64_t(stop - start) != display_size)
+ return 0;
+
+ return display_size;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// Chapters Class
+
+Chapters::Chapters() : chapters_size_(0), chapters_count_(0), chapters_(NULL) {}
+
+Chapters::~Chapters() {
+ while (chapters_count_ > 0) {
+ Chapter& chapter = chapters_[--chapters_count_];
+ chapter.Clear();
+ }
+
+ delete[] chapters_;
+ chapters_ = NULL;
+}
+
+int Chapters::Count() const { return chapters_count_; }
+
+Chapter* Chapters::AddChapter(unsigned int* seed) {
+ if (!ExpandChaptersArray())
+ return NULL;
+
+ Chapter& chapter = chapters_[chapters_count_++];
+ chapter.Init(seed);
+
+ return &chapter;
+}
+
+bool Chapters::Write(IMkvWriter* writer) const {
+ if (writer == NULL)
+ return false;
+
+ const uint64_t payload_size = WriteEdition(NULL); // return size only
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvChapters, payload_size))
+ return false;
+
+ const int64_t start = writer->Position();
+
+ if (WriteEdition(writer) == 0) // error
+ return false;
+
+ const int64_t stop = writer->Position();
+
+ if (stop >= start && uint64_t(stop - start) != payload_size)
+ return false;
+
+ return true;
+}
+
+bool Chapters::ExpandChaptersArray() {
+ if (chapters_size_ > chapters_count_)
+ return true; // nothing to do yet
+
+ const int size = (chapters_size_ == 0) ? 1 : 2 * chapters_size_;
+
+ Chapter* const chapters = new (std::nothrow) Chapter[size]; // NOLINT
+ if (chapters == NULL)
+ return false;
+
+ for (int idx = 0; idx < chapters_count_; ++idx) {
+ const Chapter& src = chapters_[idx];
+ Chapter* const dst = chapters + idx;
+ src.ShallowCopy(dst);
+ }
+
+ delete[] chapters_;
+
+ chapters_ = chapters;
+ chapters_size_ = size;
+
+ return true;
+}
+
+uint64_t Chapters::WriteEdition(IMkvWriter* writer) const {
+ uint64_t payload_size = 0;
+
+ for (int idx = 0; idx < chapters_count_; ++idx) {
+ const Chapter& chapter = chapters_[idx];
+ payload_size += chapter.WriteAtom(NULL);
+ }
+
+ const uint64_t edition_size =
+ EbmlMasterElementSize(libwebm::kMkvEditionEntry, payload_size) +
+ payload_size;
+
+ if (writer == NULL) // return size only
+ return edition_size;
+
+ const int64_t start = writer->Position();
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvEditionEntry, payload_size))
+ return 0; // error
+
+ for (int idx = 0; idx < chapters_count_; ++idx) {
+ const Chapter& chapter = chapters_[idx];
+
+ const uint64_t chapter_size = chapter.WriteAtom(writer);
+ if (chapter_size == 0) // error
+ return 0;
+ }
+
+ const int64_t stop = writer->Position();
+
+ if (stop >= start && uint64_t(stop - start) != edition_size)
+ return 0;
+
+ return edition_size;
+}
+
+// Tag Class
+
+bool Tag::add_simple_tag(const char* tag_name, const char* tag_string) {
+ if (!ExpandSimpleTagsArray())
+ return false;
+
+ SimpleTag& st = simple_tags_[simple_tags_count_++];
+ st.Init();
+
+ if (!st.set_tag_name(tag_name))
+ return false;
+
+ if (!st.set_tag_string(tag_string))
+ return false;
+
+ return true;
+}
+
+Tag::Tag() {
+ simple_tags_ = NULL;
+ simple_tags_size_ = 0;
+ simple_tags_count_ = 0;
+}
+
+Tag::~Tag() {}
+
+void Tag::ShallowCopy(Tag* dst) const {
+ dst->simple_tags_ = simple_tags_;
+ dst->simple_tags_size_ = simple_tags_size_;
+ dst->simple_tags_count_ = simple_tags_count_;
+}
+
+void Tag::Clear() {
+ while (simple_tags_count_ > 0) {
+ SimpleTag& st = simple_tags_[--simple_tags_count_];
+ st.Clear();
+ }
+
+ delete[] simple_tags_;
+ simple_tags_ = NULL;
+
+ simple_tags_size_ = 0;
+}
+
+bool Tag::ExpandSimpleTagsArray() {
+ if (simple_tags_size_ > simple_tags_count_)
+ return true; // nothing to do yet
+
+ const int size = (simple_tags_size_ == 0) ? 1 : 2 * simple_tags_size_;
+
+ SimpleTag* const simple_tags = new (std::nothrow) SimpleTag[size]; // NOLINT
+ if (simple_tags == NULL)
+ return false;
+
+ for (int idx = 0; idx < simple_tags_count_; ++idx) {
+ simple_tags[idx] = simple_tags_[idx]; // shallow copy
+ }
+
+ delete[] simple_tags_;
+
+ simple_tags_ = simple_tags;
+ simple_tags_size_ = size;
+
+ return true;
+}
+
+uint64_t Tag::Write(IMkvWriter* writer) const {
+ uint64_t payload_size = 0;
+
+ for (int idx = 0; idx < simple_tags_count_; ++idx) {
+ const SimpleTag& st = simple_tags_[idx];
+ payload_size += st.Write(NULL);
+ }
+
+ const uint64_t tag_size =
+ EbmlMasterElementSize(libwebm::kMkvTag, payload_size) + payload_size;
+
+ if (writer == NULL)
+ return tag_size;
+
+ const int64_t start = writer->Position();
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvTag, payload_size))
+ return 0;
+
+ for (int idx = 0; idx < simple_tags_count_; ++idx) {
+ const SimpleTag& st = simple_tags_[idx];
+
+ if (!st.Write(writer))
+ return 0;
+ }
+
+ const int64_t stop = writer->Position();
+
+ if (stop >= start && uint64_t(stop - start) != tag_size)
+ return 0;
+
+ return tag_size;
+}
+
+// Tag::SimpleTag
+
+void Tag::SimpleTag::Init() {
+ tag_name_ = NULL;
+ tag_string_ = NULL;
+}
+
+void Tag::SimpleTag::Clear() {
+ StrCpy(NULL, &tag_name_);
+ StrCpy(NULL, &tag_string_);
+}
+
+bool Tag::SimpleTag::set_tag_name(const char* tag_name) {
+ return StrCpy(tag_name, &tag_name_);
+}
+
+bool Tag::SimpleTag::set_tag_string(const char* tag_string) {
+ return StrCpy(tag_string, &tag_string_);
+}
+
+uint64_t Tag::SimpleTag::Write(IMkvWriter* writer) const {
+ uint64_t payload_size = EbmlElementSize(libwebm::kMkvTagName, tag_name_);
+
+ payload_size += EbmlElementSize(libwebm::kMkvTagString, tag_string_);
+
+ const uint64_t simple_tag_size =
+ EbmlMasterElementSize(libwebm::kMkvSimpleTag, payload_size) +
+ payload_size;
+
+ if (writer == NULL)
+ return simple_tag_size;
+
+ const int64_t start = writer->Position();
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvSimpleTag, payload_size))
+ return 0;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvTagName, tag_name_))
+ return 0;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvTagString, tag_string_))
+ return 0;
+
+ const int64_t stop = writer->Position();
+
+ if (stop >= start && uint64_t(stop - start) != simple_tag_size)
+ return 0;
+
+ return simple_tag_size;
+}
+
+// Tags Class
+
+Tags::Tags() : tags_size_(0), tags_count_(0), tags_(NULL) {}
+
+Tags::~Tags() {
+ while (tags_count_ > 0) {
+ Tag& tag = tags_[--tags_count_];
+ tag.Clear();
+ }
+
+ delete[] tags_;
+ tags_ = NULL;
+}
+
+int Tags::Count() const { return tags_count_; }
+
+Tag* Tags::AddTag() {
+ if (!ExpandTagsArray())
+ return NULL;
+
+ Tag& tag = tags_[tags_count_++];
+
+ return &tag;
+}
+
+bool Tags::Write(IMkvWriter* writer) const {
+ if (writer == NULL)
+ return false;
+
+ uint64_t payload_size = 0;
+
+ for (int idx = 0; idx < tags_count_; ++idx) {
+ const Tag& tag = tags_[idx];
+ payload_size += tag.Write(NULL);
+ }
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvTags, payload_size))
+ return false;
+
+ const int64_t start = writer->Position();
+
+ for (int idx = 0; idx < tags_count_; ++idx) {
+ const Tag& tag = tags_[idx];
+
+ const uint64_t tag_size = tag.Write(writer);
+ if (tag_size == 0) // error
+ return 0;
+ }
+
+ const int64_t stop = writer->Position();
+
+ if (stop >= start && uint64_t(stop - start) != payload_size)
+ return false;
+
+ return true;
+}
+
+bool Tags::ExpandTagsArray() {
+ if (tags_size_ > tags_count_)
+ return true; // nothing to do yet
+
+ const int size = (tags_size_ == 0) ? 1 : 2 * tags_size_;
+
+ Tag* const tags = new (std::nothrow) Tag[size]; // NOLINT
+ if (tags == NULL)
+ return false;
+
+ for (int idx = 0; idx < tags_count_; ++idx) {
+ const Tag& src = tags_[idx];
+ Tag* const dst = tags + idx;
+ src.ShallowCopy(dst);
+ }
+
+ delete[] tags_;
+
+ tags_ = tags;
+ tags_size_ = size;
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// Cluster class
+
+Cluster::Cluster(uint64_t timecode, int64_t cues_pos, uint64_t timecode_scale,
+ bool write_last_frame_with_duration, bool fixed_size_timecode)
+ : blocks_added_(0),
+ finalized_(false),
+ fixed_size_timecode_(fixed_size_timecode),
+ header_written_(false),
+ payload_size_(0),
+ position_for_cues_(cues_pos),
+ size_position_(-1),
+ timecode_(timecode),
+ timecode_scale_(timecode_scale),
+ write_last_frame_with_duration_(write_last_frame_with_duration),
+ writer_(NULL) {}
+
+Cluster::~Cluster() {}
+
+bool Cluster::Init(IMkvWriter* ptr_writer) {
+ if (!ptr_writer) {
+ return false;
+ }
+ writer_ = ptr_writer;
+ return true;
+}
+
+bool Cluster::AddFrame(const Frame* const frame) {
+ return QueueOrWriteFrame(frame);
+}
+
+bool Cluster::AddFrame(const uint8_t* data, uint64_t length,
+ uint64_t track_number, uint64_t abs_timecode,
+ bool is_key) {
+ Frame frame;
+ if (!frame.Init(data, length))
+ return false;
+ frame.set_track_number(track_number);
+ frame.set_timestamp(abs_timecode);
+ frame.set_is_key(is_key);
+ return QueueOrWriteFrame(&frame);
+}
+
+bool Cluster::AddFrameWithAdditional(const uint8_t* data, uint64_t length,
+ const uint8_t* additional,
+ uint64_t additional_length,
+ uint64_t add_id, uint64_t track_number,
+ uint64_t abs_timecode, bool is_key) {
+ if (!additional || additional_length == 0) {
+ return false;
+ }
+ Frame frame;
+ if (!frame.Init(data, length) ||
+ !frame.AddAdditionalData(additional, additional_length, add_id)) {
+ return false;
+ }
+ frame.set_track_number(track_number);
+ frame.set_timestamp(abs_timecode);
+ frame.set_is_key(is_key);
+ return QueueOrWriteFrame(&frame);
+}
+
+bool Cluster::AddFrameWithDiscardPadding(const uint8_t* data, uint64_t length,
+ int64_t discard_padding,
+ uint64_t track_number,
+ uint64_t abs_timecode, bool is_key) {
+ Frame frame;
+ if (!frame.Init(data, length))
+ return false;
+ frame.set_discard_padding(discard_padding);
+ frame.set_track_number(track_number);
+ frame.set_timestamp(abs_timecode);
+ frame.set_is_key(is_key);
+ return QueueOrWriteFrame(&frame);
+}
+
+bool Cluster::AddMetadata(const uint8_t* data, uint64_t length,
+ uint64_t track_number, uint64_t abs_timecode,
+ uint64_t duration_timecode) {
+ Frame frame;
+ if (!frame.Init(data, length))
+ return false;
+ frame.set_track_number(track_number);
+ frame.set_timestamp(abs_timecode);
+ frame.set_duration(duration_timecode);
+ frame.set_is_key(true); // All metadata blocks are keyframes.
+ return QueueOrWriteFrame(&frame);
+}
+
+void Cluster::AddPayloadSize(uint64_t size) { payload_size_ += size; }
+
+bool Cluster::Finalize() {
+ return !write_last_frame_with_duration_ && Finalize(false, 0);
+}
+
+bool Cluster::Finalize(bool set_last_frame_duration, uint64_t duration) {
+ if (!writer_ || finalized_)
+ return false;
+
+ if (write_last_frame_with_duration_) {
+ // Write out held back Frames. This essentially performs a k-way merge
+ // across all tracks in the increasing order of timestamps.
+ while (!stored_frames_.empty()) {
+ Frame* frame = stored_frames_.begin()->second.front();
+
+ // Get the next frame to write (frame with least timestamp across all
+ // tracks).
+ for (FrameMapIterator frames_iterator = ++stored_frames_.begin();
+ frames_iterator != stored_frames_.end(); ++frames_iterator) {
+ if (frames_iterator->second.front()->timestamp() < frame->timestamp()) {
+ frame = frames_iterator->second.front();
+ }
+ }
+
+ // Set the duration if it's the last frame for the track.
+ if (set_last_frame_duration &&
+ stored_frames_[frame->track_number()].size() == 1 &&
+ !frame->duration_set()) {
+ frame->set_duration(duration - frame->timestamp());
+ if (!frame->is_key() && !frame->reference_block_timestamp_set()) {
+ frame->set_reference_block_timestamp(
+ last_block_timestamp_[frame->track_number()]);
+ }
+ }
+
+ // Write the frame and remove it from |stored_frames_|.
+ const bool wrote_frame = DoWriteFrame(frame);
+ stored_frames_[frame->track_number()].pop_front();
+ if (stored_frames_[frame->track_number()].empty()) {
+ stored_frames_.erase(frame->track_number());
+ }
+ delete frame;
+ if (!wrote_frame)
+ return false;
+ }
+ }
+
+ if (size_position_ == -1)
+ return false;
+
+ if (writer_->Seekable()) {
+ const int64_t pos = writer_->Position();
+
+ if (writer_->Position(size_position_))
+ return false;
+
+ if (WriteUIntSize(writer_, payload_size(), 8))
+ return false;
+
+ if (writer_->Position(pos))
+ return false;
+ }
+
+ finalized_ = true;
+
+ return true;
+}
+
+uint64_t Cluster::Size() const {
+ const uint64_t element_size =
+ EbmlMasterElementSize(libwebm::kMkvCluster, 0xFFFFFFFFFFFFFFFFULL) +
+ payload_size_;
+ return element_size;
+}
+
+bool Cluster::PreWriteBlock() {
+ if (finalized_)
+ return false;
+
+ if (!header_written_) {
+ if (!WriteClusterHeader())
+ return false;
+ }
+
+ return true;
+}
+
+void Cluster::PostWriteBlock(uint64_t element_size) {
+ AddPayloadSize(element_size);
+ ++blocks_added_;
+}
+
+int64_t Cluster::GetRelativeTimecode(int64_t abs_timecode) const {
+ const int64_t cluster_timecode = this->Cluster::timecode();
+ const int64_t rel_timecode =
+ static_cast<int64_t>(abs_timecode) - cluster_timecode;
+
+ if (rel_timecode < 0 || rel_timecode > kMaxBlockTimecode)
+ return -1;
+
+ return rel_timecode;
+}
+
+bool Cluster::DoWriteFrame(const Frame* const frame) {
+ if (!frame || !frame->IsValid())
+ return false;
+
+ if (!PreWriteBlock())
+ return false;
+
+ const uint64_t element_size = WriteFrame(writer_, frame, this);
+ if (element_size == 0)
+ return false;
+
+ PostWriteBlock(element_size);
+ last_block_timestamp_[frame->track_number()] = frame->timestamp();
+ return true;
+}
+
+bool Cluster::QueueOrWriteFrame(const Frame* const frame) {
+ if (!frame || !frame->IsValid())
+ return false;
+
+ // If |write_last_frame_with_duration_| is not set, then write the frame right
+ // away.
+ if (!write_last_frame_with_duration_) {
+ return DoWriteFrame(frame);
+ }
+
+ // Queue the current frame.
+ uint64_t track_number = frame->track_number();
+ Frame* const frame_to_store = new Frame();
+ frame_to_store->CopyFrom(*frame);
+ stored_frames_[track_number].push_back(frame_to_store);
+
+ // Iterate through all queued frames in the current track except the last one
+ // and write it if it is okay to do so (i.e.) no other track has an held back
+ // frame with timestamp <= the timestamp of the frame in question.
+ std::vector<std::list<Frame*>::iterator> frames_to_erase;
+ for (std::list<Frame *>::iterator
+ current_track_iterator = stored_frames_[track_number].begin(),
+ end = --stored_frames_[track_number].end();
+ current_track_iterator != end; ++current_track_iterator) {
+ const Frame* const frame_to_write = *current_track_iterator;
+ bool okay_to_write = true;
+ for (FrameMapIterator track_iterator = stored_frames_.begin();
+ track_iterator != stored_frames_.end(); ++track_iterator) {
+ if (track_iterator->first == track_number) {
+ continue;
+ }
+ if (track_iterator->second.front()->timestamp() <
+ frame_to_write->timestamp()) {
+ okay_to_write = false;
+ break;
+ }
+ }
+ if (okay_to_write) {
+ const bool wrote_frame = DoWriteFrame(frame_to_write);
+ delete frame_to_write;
+ if (!wrote_frame)
+ return false;
+ frames_to_erase.push_back(current_track_iterator);
+ } else {
+ break;
+ }
+ }
+ for (std::vector<std::list<Frame*>::iterator>::iterator iterator =
+ frames_to_erase.begin();
+ iterator != frames_to_erase.end(); ++iterator) {
+ stored_frames_[track_number].erase(*iterator);
+ }
+ return true;
+}
+
+bool Cluster::WriteClusterHeader() {
+ if (finalized_)
+ return false;
+
+ if (WriteID(writer_, libwebm::kMkvCluster))
+ return false;
+
+ // Save for later.
+ size_position_ = writer_->Position();
+
+ // Write "unknown" (EBML coded -1) as cluster size value. We need to write 8
+ // bytes because we do not know how big our cluster will be.
+ if (SerializeInt(writer_, kEbmlUnknownValue, 8))
+ return false;
+
+ if (!WriteEbmlElement(writer_, libwebm::kMkvTimecode, timecode(),
+ fixed_size_timecode_ ? 8 : 0)) {
+ return false;
+ }
+ AddPayloadSize(EbmlElementSize(libwebm::kMkvTimecode, timecode(),
+ fixed_size_timecode_ ? 8 : 0));
+ header_written_ = true;
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// SeekHead Class
+
+SeekHead::SeekHead() : start_pos_(0ULL) {
+ for (int32_t i = 0; i < kSeekEntryCount; ++i) {
+ seek_entry_id_[i] = 0;
+ seek_entry_pos_[i] = 0;
+ }
+}
+
+SeekHead::~SeekHead() {}
+
+bool SeekHead::Finalize(IMkvWriter* writer) const {
+ if (writer->Seekable()) {
+ if (start_pos_ == -1)
+ return false;
+
+ uint64_t payload_size = 0;
+ uint64_t entry_size[kSeekEntryCount];
+
+ for (int32_t i = 0; i < kSeekEntryCount; ++i) {
+ if (seek_entry_id_[i] != 0) {
+ entry_size[i] = EbmlElementSize(
+ libwebm::kMkvSeekID, static_cast<uint64_t>(seek_entry_id_[i]));
+ entry_size[i] +=
+ EbmlElementSize(libwebm::kMkvSeekPosition, seek_entry_pos_[i]);
+
+ payload_size +=
+ EbmlMasterElementSize(libwebm::kMkvSeek, entry_size[i]) +
+ entry_size[i];
+ }
+ }
+
+ // No SeekHead elements
+ if (payload_size == 0)
+ return true;
+
+ const int64_t pos = writer->Position();
+ if (writer->Position(start_pos_))
+ return false;
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvSeekHead, payload_size))
+ return false;
+
+ for (int32_t i = 0; i < kSeekEntryCount; ++i) {
+ if (seek_entry_id_[i] != 0) {
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvSeek, entry_size[i]))
+ return false;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvSeekID,
+ static_cast<uint64_t>(seek_entry_id_[i])))
+ return false;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvSeekPosition,
+ seek_entry_pos_[i]))
+ return false;
+ }
+ }
+
+ const uint64_t total_entry_size = kSeekEntryCount * MaxEntrySize();
+ const uint64_t total_size =
+ EbmlMasterElementSize(libwebm::kMkvSeekHead, total_entry_size) +
+ total_entry_size;
+ const int64_t size_left = total_size - (writer->Position() - start_pos_);
+
+ const uint64_t bytes_written = WriteVoidElement(writer, size_left);
+ if (!bytes_written)
+ return false;
+
+ if (writer->Position(pos))
+ return false;
+ }
+
+ return true;
+}
+
+bool SeekHead::Write(IMkvWriter* writer) {
+ const uint64_t entry_size = kSeekEntryCount * MaxEntrySize();
+ const uint64_t size =
+ EbmlMasterElementSize(libwebm::kMkvSeekHead, entry_size);
+
+ start_pos_ = writer->Position();
+
+ const uint64_t bytes_written = WriteVoidElement(writer, size + entry_size);
+ if (!bytes_written)
+ return false;
+
+ return true;
+}
+
+bool SeekHead::AddSeekEntry(uint32_t id, uint64_t pos) {
+ for (int32_t i = 0; i < kSeekEntryCount; ++i) {
+ if (seek_entry_id_[i] == 0) {
+ seek_entry_id_[i] = id;
+ seek_entry_pos_[i] = pos;
+ return true;
+ }
+ }
+ return false;
+}
+
+uint32_t SeekHead::GetId(int index) const {
+ if (index < 0 || index >= kSeekEntryCount)
+ return UINT_MAX;
+ return seek_entry_id_[index];
+}
+
+uint64_t SeekHead::GetPosition(int index) const {
+ if (index < 0 || index >= kSeekEntryCount)
+ return ULLONG_MAX;
+ return seek_entry_pos_[index];
+}
+
+bool SeekHead::SetSeekEntry(int index, uint32_t id, uint64_t position) {
+ if (index < 0 || index >= kSeekEntryCount)
+ return false;
+ seek_entry_id_[index] = id;
+ seek_entry_pos_[index] = position;
+ return true;
+}
+
+uint64_t SeekHead::MaxEntrySize() const {
+ const uint64_t max_entry_payload_size =
+ EbmlElementSize(libwebm::kMkvSeekID, UINT64_C(0xffffffff)) +
+ EbmlElementSize(libwebm::kMkvSeekPosition, UINT64_C(0xffffffffffffffff));
+ const uint64_t max_entry_size =
+ EbmlMasterElementSize(libwebm::kMkvSeek, max_entry_payload_size) +
+ max_entry_payload_size;
+
+ return max_entry_size;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// SegmentInfo Class
+
+SegmentInfo::SegmentInfo()
+ : duration_(-1.0),
+ muxing_app_(NULL),
+ timecode_scale_(1000000ULL),
+ writing_app_(NULL),
+ date_utc_(LLONG_MIN),
+ duration_pos_(-1) {}
+
+SegmentInfo::~SegmentInfo() {
+ delete[] muxing_app_;
+ delete[] writing_app_;
+}
+
+bool SegmentInfo::Init() {
+ int32_t major;
+ int32_t minor;
+ int32_t build;
+ int32_t revision;
+ GetVersion(&major, &minor, &build, &revision);
+ char temp[256];
+#ifdef _MSC_VER
+ sprintf_s(temp, sizeof(temp) / sizeof(temp[0]), "libwebm-%d.%d.%d.%d", major,
+ minor, build, revision);
+#else
+ snprintf(temp, sizeof(temp) / sizeof(temp[0]), "libwebm-%d.%d.%d.%d", major,
+ minor, build, revision);
+#endif
+
+ const size_t app_len = strlen(temp) + 1;
+
+ delete[] muxing_app_;
+
+ muxing_app_ = new (std::nothrow) char[app_len]; // NOLINT
+ if (!muxing_app_)
+ return false;
+
+#ifdef _MSC_VER
+ strcpy_s(muxing_app_, app_len, temp);
+#else
+ strcpy(muxing_app_, temp);
+#endif
+
+ set_writing_app(temp);
+ if (!writing_app_)
+ return false;
+ return true;
+}
+
+bool SegmentInfo::Finalize(IMkvWriter* writer) const {
+ if (!writer)
+ return false;
+
+ if (duration_ > 0.0) {
+ if (writer->Seekable()) {
+ if (duration_pos_ == -1)
+ return false;
+
+ const int64_t pos = writer->Position();
+
+ if (writer->Position(duration_pos_))
+ return false;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvDuration,
+ static_cast<float>(duration_)))
+ return false;
+
+ if (writer->Position(pos))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool SegmentInfo::Write(IMkvWriter* writer) {
+ if (!writer || !muxing_app_ || !writing_app_)
+ return false;
+
+ uint64_t size = EbmlElementSize(libwebm::kMkvTimecodeScale, timecode_scale_);
+ if (duration_ > 0.0)
+ size +=
+ EbmlElementSize(libwebm::kMkvDuration, static_cast<float>(duration_));
+ if (date_utc_ != LLONG_MIN)
+ size += EbmlDateElementSize(libwebm::kMkvDateUTC);
+ size += EbmlElementSize(libwebm::kMkvMuxingApp, muxing_app_);
+ size += EbmlElementSize(libwebm::kMkvWritingApp, writing_app_);
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvInfo, size))
+ return false;
+
+ const int64_t payload_position = writer->Position();
+ if (payload_position < 0)
+ return false;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvTimecodeScale, timecode_scale_))
+ return false;
+
+ if (duration_ > 0.0) {
+ // Save for later
+ duration_pos_ = writer->Position();
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvDuration,
+ static_cast<float>(duration_)))
+ return false;
+ }
+
+ if (date_utc_ != LLONG_MIN)
+ WriteEbmlDateElement(writer, libwebm::kMkvDateUTC, date_utc_);
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvMuxingApp, muxing_app_))
+ return false;
+ if (!WriteEbmlElement(writer, libwebm::kMkvWritingApp, writing_app_))
+ return false;
+
+ const int64_t stop_position = writer->Position();
+ if (stop_position < 0 ||
+ stop_position - payload_position != static_cast<int64_t>(size))
+ return false;
+
+ return true;
+}
+
+void SegmentInfo::set_muxing_app(const char* app) {
+ if (app) {
+ const size_t length = strlen(app) + 1;
+ char* temp_str = new (std::nothrow) char[length]; // NOLINT
+ if (!temp_str)
+ return;
+
+#ifdef _MSC_VER
+ strcpy_s(temp_str, length, app);
+#else
+ strcpy(temp_str, app);
+#endif
+
+ delete[] muxing_app_;
+ muxing_app_ = temp_str;
+ }
+}
+
+void SegmentInfo::set_writing_app(const char* app) {
+ if (app) {
+ const size_t length = strlen(app) + 1;
+ char* temp_str = new (std::nothrow) char[length]; // NOLINT
+ if (!temp_str)
+ return;
+
+#ifdef _MSC_VER
+ strcpy_s(temp_str, length, app);
+#else
+ strcpy(temp_str, app);
+#endif
+
+ delete[] writing_app_;
+ writing_app_ = temp_str;
+ }
+}
+
+///////////////////////////////////////////////////////////////
+//
+// Segment Class
+
+Segment::Segment()
+ : chunk_count_(0),
+ chunk_name_(NULL),
+ chunk_writer_cluster_(NULL),
+ chunk_writer_cues_(NULL),
+ chunk_writer_header_(NULL),
+ chunking_(false),
+ chunking_base_name_(NULL),
+ cluster_list_(NULL),
+ cluster_list_capacity_(0),
+ cluster_list_size_(0),
+ cues_position_(kAfterClusters),
+ cues_track_(0),
+ force_new_cluster_(false),
+ frames_(NULL),
+ frames_capacity_(0),
+ frames_size_(0),
+ has_video_(false),
+ header_written_(false),
+ last_block_duration_(0),
+ last_timestamp_(0),
+ max_cluster_duration_(kDefaultMaxClusterDuration),
+ max_cluster_size_(0),
+ mode_(kFile),
+ new_cuepoint_(false),
+ output_cues_(true),
+ accurate_cluster_duration_(false),
+ fixed_size_cluster_timecode_(false),
+ payload_pos_(0),
+ size_position_(0),
+ doc_type_version_(kDefaultDocTypeVersion),
+ doc_type_version_written_(0),
+ writer_cluster_(NULL),
+ writer_cues_(NULL),
+ writer_header_(NULL) {
+ const time_t curr_time = time(NULL);
+ seed_ = static_cast<unsigned int>(curr_time);
+#ifdef _WIN32
+ srand(seed_);
+#endif
+}
+
+Segment::~Segment() {
+ if (cluster_list_) {
+ for (int32_t i = 0; i < cluster_list_size_; ++i) {
+ Cluster* const cluster = cluster_list_[i];
+ delete cluster;
+ }
+ delete[] cluster_list_;
+ }
+
+ if (frames_) {
+ for (int32_t i = 0; i < frames_size_; ++i) {
+ Frame* const frame = frames_[i];
+ delete frame;
+ }
+ delete[] frames_;
+ }
+
+ delete[] chunk_name_;
+ delete[] chunking_base_name_;
+
+ if (chunk_writer_cluster_) {
+ chunk_writer_cluster_->Close();
+ delete chunk_writer_cluster_;
+ }
+ if (chunk_writer_cues_) {
+ chunk_writer_cues_->Close();
+ delete chunk_writer_cues_;
+ }
+ if (chunk_writer_header_) {
+ chunk_writer_header_->Close();
+ delete chunk_writer_header_;
+ }
+}
+
+void Segment::MoveCuesBeforeClustersHelper(uint64_t diff, int32_t index,
+ uint64_t* cues_size) {
+ CuePoint* const cue_point = cues_.GetCueByIndex(index);
+ if (cue_point == NULL)
+ return;
+ const uint64_t old_cue_point_size = cue_point->Size();
+ const uint64_t cluster_pos = cue_point->cluster_pos() + diff;
+ cue_point->set_cluster_pos(cluster_pos); // update the new cluster position
+ // New size of the cue is computed as follows
+ // Let a = current sum of size of all CuePoints
+ // Let b = Increase in Cue Point's size due to this iteration
+ // Let c = Increase in size of Cues Element's length due to this iteration
+ // (This is computed as CodedSize(a + b) - CodedSize(a))
+ // Let d = b + c. Now d is the |diff| passed to the next recursive call.
+ // Let e = a + b. Now e is the |cues_size| passed to the next recursive
+ // call.
+ const uint64_t cue_point_size_diff = cue_point->Size() - old_cue_point_size;
+ const uint64_t cue_size_diff =
+ GetCodedUIntSize(*cues_size + cue_point_size_diff) -
+ GetCodedUIntSize(*cues_size);
+ *cues_size += cue_point_size_diff;
+ diff = cue_size_diff + cue_point_size_diff;
+ if (diff > 0) {
+ for (int32_t i = 0; i < cues_.cue_entries_size(); ++i) {
+ MoveCuesBeforeClustersHelper(diff, i, cues_size);
+ }
+ }
+}
+
+void Segment::MoveCuesBeforeClusters() {
+ const uint64_t current_cue_size = cues_.Size();
+ uint64_t cue_size = 0;
+ for (int32_t i = 0; i < cues_.cue_entries_size(); ++i)
+ cue_size += cues_.GetCueByIndex(i)->Size();
+ for (int32_t i = 0; i < cues_.cue_entries_size(); ++i)
+ MoveCuesBeforeClustersHelper(current_cue_size, i, &cue_size);
+
+ // Adjust the Seek Entry to reflect the change in position
+ // of Cluster and Cues
+ int32_t cluster_index = 0;
+ int32_t cues_index = 0;
+ for (int32_t i = 0; i < SeekHead::kSeekEntryCount; ++i) {
+ if (seek_head_.GetId(i) == libwebm::kMkvCluster)
+ cluster_index = i;
+ if (seek_head_.GetId(i) == libwebm::kMkvCues)
+ cues_index = i;
+ }
+ seek_head_.SetSeekEntry(cues_index, libwebm::kMkvCues,
+ seek_head_.GetPosition(cluster_index));
+ seek_head_.SetSeekEntry(cluster_index, libwebm::kMkvCluster,
+ cues_.Size() + seek_head_.GetPosition(cues_index));
+}
+
+bool Segment::Init(IMkvWriter* ptr_writer) {
+ if (!ptr_writer) {
+ return false;
+ }
+ writer_cluster_ = ptr_writer;
+ writer_cues_ = ptr_writer;
+ writer_header_ = ptr_writer;
+ return segment_info_.Init();
+}
+
+bool Segment::CopyAndMoveCuesBeforeClusters(mkvparser::IMkvReader* reader,
+ IMkvWriter* writer) {
+ if (!writer->Seekable() || chunking_)
+ return false;
+ const int64_t cluster_offset =
+ cluster_list_[0]->size_position() - GetUIntSize(libwebm::kMkvCluster);
+
+ // Copy the headers.
+ if (!ChunkedCopy(reader, writer, 0, cluster_offset))
+ return false;
+
+ // Recompute cue positions and seek entries.
+ MoveCuesBeforeClusters();
+
+ // Write cues and seek entries.
+ // TODO(vigneshv): As of now, it's safe to call seek_head_.Finalize() for the
+ // second time with a different writer object. But the name Finalize() doesn't
+ // indicate something we want to call more than once. So consider renaming it
+ // to write() or some such.
+ if (!cues_.Write(writer) || !seek_head_.Finalize(writer))
+ return false;
+
+ // Copy the Clusters.
+ if (!ChunkedCopy(reader, writer, cluster_offset,
+ cluster_end_offset_ - cluster_offset))
+ return false;
+
+ // Update the Segment size in case the Cues size has changed.
+ const int64_t pos = writer->Position();
+ const int64_t segment_size = writer->Position() - payload_pos_;
+ if (writer->Position(size_position_) ||
+ WriteUIntSize(writer, segment_size, 8) || writer->Position(pos))
+ return false;
+ return true;
+}
+
+bool Segment::Finalize() {
+ if (WriteFramesAll() < 0)
+ return false;
+
+ if (cluster_list_size_ > 0) {
+ // Update last cluster's size
+ Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1];
+
+ // For the last frame of the last Cluster, we don't write it as a BlockGroup
+ // with Duration unless the frame itself has duration set explicitly.
+ if (!old_cluster || !old_cluster->Finalize(false, 0))
+ return false;
+ }
+
+ if (mode_ == kFile) {
+ if (chunking_ && chunk_writer_cluster_) {
+ chunk_writer_cluster_->Close();
+ chunk_count_++;
+ }
+
+ const double duration =
+ (static_cast<double>(last_timestamp_) + last_block_duration_) /
+ segment_info_.timecode_scale();
+ segment_info_.set_duration(duration);
+ if (!segment_info_.Finalize(writer_header_))
+ return false;
+
+ if (output_cues_)
+ if (!seek_head_.AddSeekEntry(libwebm::kMkvCues, MaxOffset()))
+ return false;
+
+ if (chunking_) {
+ if (!chunk_writer_cues_)
+ return false;
+
+ char* name = NULL;
+ if (!UpdateChunkName("cues", &name))
+ return false;
+
+ const bool cues_open = chunk_writer_cues_->Open(name);
+ delete[] name;
+ if (!cues_open)
+ return false;
+ }
+
+ cluster_end_offset_ = writer_cluster_->Position();
+
+ // Write the seek headers and cues
+ if (output_cues_)
+ if (!cues_.Write(writer_cues_))
+ return false;
+
+ if (!seek_head_.Finalize(writer_header_))
+ return false;
+
+ if (writer_header_->Seekable()) {
+ if (size_position_ == -1)
+ return false;
+
+ const int64_t segment_size = MaxOffset();
+ if (segment_size < 1)
+ return false;
+
+ const int64_t pos = writer_header_->Position();
+ UpdateDocTypeVersion();
+ if (doc_type_version_ != doc_type_version_written_) {
+ if (writer_header_->Position(0))
+ return false;
+
+ if (!WriteEbmlHeader(writer_header_, doc_type_version_))
+ return false;
+ if (writer_header_->Position() != ebml_header_size_)
+ return false;
+
+ doc_type_version_written_ = doc_type_version_;
+ }
+
+ if (writer_header_->Position(size_position_))
+ return false;
+
+ if (WriteUIntSize(writer_header_, segment_size, 8))
+ return false;
+
+ if (writer_header_->Position(pos))
+ return false;
+ }
+
+ if (chunking_) {
+ // Do not close any writers until the segment size has been written,
+ // otherwise the size may be off.
+ if (!chunk_writer_cues_ || !chunk_writer_header_)
+ return false;
+
+ chunk_writer_cues_->Close();
+ chunk_writer_header_->Close();
+ }
+ }
+
+ return true;
+}
+
+Track* Segment::AddTrack(int32_t number) {
+ Track* const track = new (std::nothrow) Track(&seed_); // NOLINT
+
+ if (!track)
+ return NULL;
+
+ if (!tracks_.AddTrack(track, number)) {
+ delete track;
+ return NULL;
+ }
+
+ return track;
+}
+
+Chapter* Segment::AddChapter() { return chapters_.AddChapter(&seed_); }
+
+Tag* Segment::AddTag() { return tags_.AddTag(); }
+
+uint64_t Segment::AddVideoTrack(int32_t width, int32_t height, int32_t number) {
+ VideoTrack* const track = new (std::nothrow) VideoTrack(&seed_); // NOLINT
+ if (!track)
+ return 0;
+
+ track->set_type(Tracks::kVideo);
+ track->set_codec_id(Tracks::kVp8CodecId);
+ track->set_width(width);
+ track->set_height(height);
+
+ tracks_.AddTrack(track, number);
+ has_video_ = true;
+
+ return track->number();
+}
+
+bool Segment::AddCuePoint(uint64_t timestamp, uint64_t track) {
+ if (cluster_list_size_ < 1)
+ return false;
+
+ const Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
+ if (!cluster)
+ return false;
+
+ CuePoint* const cue = new (std::nothrow) CuePoint(); // NOLINT
+ if (!cue)
+ return false;
+
+ cue->set_time(timestamp / segment_info_.timecode_scale());
+ cue->set_block_number(cluster->blocks_added());
+ cue->set_cluster_pos(cluster->position_for_cues());
+ cue->set_track(track);
+ if (!cues_.AddCue(cue))
+ return false;
+
+ new_cuepoint_ = false;
+ return true;
+}
+
+uint64_t Segment::AddAudioTrack(int32_t sample_rate, int32_t channels,
+ int32_t number) {
+ AudioTrack* const track = new (std::nothrow) AudioTrack(&seed_); // NOLINT
+ if (!track)
+ return 0;
+
+ track->set_type(Tracks::kAudio);
+ track->set_codec_id(Tracks::kVorbisCodecId);
+ track->set_sample_rate(sample_rate);
+ track->set_channels(channels);
+
+ tracks_.AddTrack(track, number);
+
+ return track->number();
+}
+
+bool Segment::AddFrame(const uint8_t* data, uint64_t length,
+ uint64_t track_number, uint64_t timestamp, bool is_key) {
+ if (!data)
+ return false;
+
+ Frame frame;
+ if (!frame.Init(data, length))
+ return false;
+ frame.set_track_number(track_number);
+ frame.set_timestamp(timestamp);
+ frame.set_is_key(is_key);
+ return AddGenericFrame(&frame);
+}
+
+bool Segment::AddFrameWithAdditional(const uint8_t* data, uint64_t length,
+ const uint8_t* additional,
+ uint64_t additional_length,
+ uint64_t add_id, uint64_t track_number,
+ uint64_t timestamp, bool is_key) {
+ if (!data || !additional)
+ return false;
+
+ Frame frame;
+ if (!frame.Init(data, length) ||
+ !frame.AddAdditionalData(additional, additional_length, add_id)) {
+ return false;
+ }
+ frame.set_track_number(track_number);
+ frame.set_timestamp(timestamp);
+ frame.set_is_key(is_key);
+ return AddGenericFrame(&frame);
+}
+
+bool Segment::AddFrameWithDiscardPadding(const uint8_t* data, uint64_t length,
+ int64_t discard_padding,
+ uint64_t track_number,
+ uint64_t timestamp, bool is_key) {
+ if (!data)
+ return false;
+
+ Frame frame;
+ if (!frame.Init(data, length))
+ return false;
+ frame.set_discard_padding(discard_padding);
+ frame.set_track_number(track_number);
+ frame.set_timestamp(timestamp);
+ frame.set_is_key(is_key);
+ return AddGenericFrame(&frame);
+}
+
+bool Segment::AddMetadata(const uint8_t* data, uint64_t length,
+ uint64_t track_number, uint64_t timestamp_ns,
+ uint64_t duration_ns) {
+ if (!data)
+ return false;
+
+ Frame frame;
+ if (!frame.Init(data, length))
+ return false;
+ frame.set_track_number(track_number);
+ frame.set_timestamp(timestamp_ns);
+ frame.set_duration(duration_ns);
+ frame.set_is_key(true); // All metadata blocks are keyframes.
+ return AddGenericFrame(&frame);
+}
+
+bool Segment::AddGenericFrame(const Frame* frame) {
+ if (!frame)
+ return false;
+
+ if (!CheckHeaderInfo())
+ return false;
+
+ // Check for non-monotonically increasing timestamps.
+ if (frame->timestamp() < last_timestamp_)
+ return false;
+
+ // Check if the track number is valid.
+ if (!tracks_.GetTrackByNumber(frame->track_number()))
+ return false;
+
+ if (frame->discard_padding() != 0)
+ doc_type_version_ = 4;
+
+ // If the segment has a video track hold onto audio frames to make sure the
+ // audio that is associated with the start time of a video key-frame is
+ // muxed into the same cluster.
+ if (has_video_ && tracks_.TrackIsAudio(frame->track_number()) &&
+ !force_new_cluster_) {
+ Frame* const new_frame = new (std::nothrow) Frame();
+ if (!new_frame || !new_frame->CopyFrom(*frame))
+ return false;
+ return QueueFrame(new_frame);
+ }
+
+ if (!DoNewClusterProcessing(frame->track_number(), frame->timestamp(),
+ frame->is_key())) {
+ return false;
+ }
+
+ if (cluster_list_size_ < 1)
+ return false;
+
+ Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
+ if (!cluster)
+ return false;
+
+ // If the Frame is not a SimpleBlock, then set the reference_block_timestamp
+ // if it is not set already.
+ bool frame_created = false;
+ if (!frame->CanBeSimpleBlock() && !frame->is_key() &&
+ !frame->reference_block_timestamp_set()) {
+ Frame* const new_frame = new (std::nothrow) Frame();
+ if (!new_frame->CopyFrom(*frame))
+ return false;
+ new_frame->set_reference_block_timestamp(
+ last_track_timestamp_[frame->track_number() - 1]);
+ frame = new_frame;
+ frame_created = true;
+ }
+
+ if (!cluster->AddFrame(frame))
+ return false;
+
+ if (new_cuepoint_ && cues_track_ == frame->track_number()) {
+ if (!AddCuePoint(frame->timestamp(), cues_track_))
+ return false;
+ }
+
+ last_timestamp_ = frame->timestamp();
+ last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
+ last_block_duration_ = frame->duration();
+
+ if (frame_created)
+ delete frame;
+
+ return true;
+}
+
+void Segment::OutputCues(bool output_cues) { output_cues_ = output_cues; }
+
+void Segment::AccurateClusterDuration(bool accurate_cluster_duration) {
+ accurate_cluster_duration_ = accurate_cluster_duration;
+}
+
+void Segment::UseFixedSizeClusterTimecode(bool fixed_size_cluster_timecode) {
+ fixed_size_cluster_timecode_ = fixed_size_cluster_timecode;
+}
+
+bool Segment::SetChunking(bool chunking, const char* filename) {
+ if (chunk_count_ > 0)
+ return false;
+
+ if (chunking) {
+ if (!filename)
+ return false;
+
+ // Check if we are being set to what is already set.
+ if (chunking_ && !strcmp(filename, chunking_base_name_))
+ return true;
+
+ const size_t name_length = strlen(filename) + 1;
+ char* const temp = new (std::nothrow) char[name_length]; // NOLINT
+ if (!temp)
+ return false;
+
+#ifdef _MSC_VER
+ strcpy_s(temp, name_length, filename);
+#else
+ strcpy(temp, filename);
+#endif
+
+ delete[] chunking_base_name_;
+ chunking_base_name_ = temp;
+
+ if (!UpdateChunkName("chk", &chunk_name_))
+ return false;
+
+ if (!chunk_writer_cluster_) {
+ chunk_writer_cluster_ = new (std::nothrow) MkvWriter(); // NOLINT
+ if (!chunk_writer_cluster_)
+ return false;
+ }
+
+ if (!chunk_writer_cues_) {
+ chunk_writer_cues_ = new (std::nothrow) MkvWriter(); // NOLINT
+ if (!chunk_writer_cues_)
+ return false;
+ }
+
+ if (!chunk_writer_header_) {
+ chunk_writer_header_ = new (std::nothrow) MkvWriter(); // NOLINT
+ if (!chunk_writer_header_)
+ return false;
+ }
+
+ if (!chunk_writer_cluster_->Open(chunk_name_))
+ return false;
+
+ const size_t header_length = strlen(filename) + strlen(".hdr") + 1;
+ char* const header = new (std::nothrow) char[header_length]; // NOLINT
+ if (!header)
+ return false;
+
+#ifdef _MSC_VER
+ strcpy_s(header, header_length - strlen(".hdr"), chunking_base_name_);
+ strcat_s(header, header_length, ".hdr");
+#else
+ strcpy(header, chunking_base_name_);
+ strcat(header, ".hdr");
+#endif
+ if (!chunk_writer_header_->Open(header)) {
+ delete[] header;
+ return false;
+ }
+
+ writer_cluster_ = chunk_writer_cluster_;
+ writer_cues_ = chunk_writer_cues_;
+ writer_header_ = chunk_writer_header_;
+
+ delete[] header;
+ }
+
+ chunking_ = chunking;
+
+ return true;
+}
+
+bool Segment::CuesTrack(uint64_t track_number) {
+ const Track* const track = GetTrackByNumber(track_number);
+ if (!track)
+ return false;
+
+ cues_track_ = track_number;
+ return true;
+}
+
+void Segment::ForceNewClusterOnNextFrame() { force_new_cluster_ = true; }
+
+Track* Segment::GetTrackByNumber(uint64_t track_number) const {
+ return tracks_.GetTrackByNumber(track_number);
+}
+
+bool Segment::WriteSegmentHeader() {
+ UpdateDocTypeVersion();
+
+ // TODO(fgalligan): Support more than one segment.
+ if (!WriteEbmlHeader(writer_header_, doc_type_version_))
+ return false;
+ doc_type_version_written_ = doc_type_version_;
+ ebml_header_size_ = static_cast<int32_t>(writer_header_->Position());
+
+ // Write "unknown" (-1) as segment size value. If mode is kFile, Segment
+ // will write over duration when the file is finalized.
+ if (WriteID(writer_header_, libwebm::kMkvSegment))
+ return false;
+
+ // Save for later.
+ size_position_ = writer_header_->Position();
+
+ // Write "unknown" (EBML coded -1) as segment size value. We need to write 8
+ // bytes because if we are going to overwrite the segment size later we do
+ // not know how big our segment will be.
+ if (SerializeInt(writer_header_, kEbmlUnknownValue, 8))
+ return false;
+
+ payload_pos_ = writer_header_->Position();
+
+ if (mode_ == kFile && writer_header_->Seekable()) {
+ // Set the duration > 0.0 so SegmentInfo will write out the duration. When
+ // the muxer is done writing we will set the correct duration and have
+ // SegmentInfo upadte it.
+ segment_info_.set_duration(1.0);
+
+ if (!seek_head_.Write(writer_header_))
+ return false;
+ }
+
+ if (!seek_head_.AddSeekEntry(libwebm::kMkvInfo, MaxOffset()))
+ return false;
+ if (!segment_info_.Write(writer_header_))
+ return false;
+
+ if (!seek_head_.AddSeekEntry(libwebm::kMkvTracks, MaxOffset()))
+ return false;
+ if (!tracks_.Write(writer_header_))
+ return false;
+
+ if (chapters_.Count() > 0) {
+ if (!seek_head_.AddSeekEntry(libwebm::kMkvChapters, MaxOffset()))
+ return false;
+ if (!chapters_.Write(writer_header_))
+ return false;
+ }
+
+ if (tags_.Count() > 0) {
+ if (!seek_head_.AddSeekEntry(libwebm::kMkvTags, MaxOffset()))
+ return false;
+ if (!tags_.Write(writer_header_))
+ return false;
+ }
+
+ if (chunking_ && (mode_ == kLive || !writer_header_->Seekable())) {
+ if (!chunk_writer_header_)
+ return false;
+
+ chunk_writer_header_->Close();
+ }
+
+ header_written_ = true;
+
+ return true;
+}
+
+// Here we are testing whether to create a new cluster, given a frame
+// having time frame_timestamp_ns.
+//
+int Segment::TestFrame(uint64_t track_number, uint64_t frame_timestamp_ns,
+ bool is_key) const {
+ if (force_new_cluster_)
+ return 1;
+
+ // If no clusters have been created yet, then create a new cluster
+ // and write this frame immediately, in the new cluster. This path
+ // should only be followed once, the first time we attempt to write
+ // a frame.
+
+ if (cluster_list_size_ <= 0)
+ return 1;
+
+ // There exists at least one cluster. We must compare the frame to
+ // the last cluster, in order to determine whether the frame is
+ // written to the existing cluster, or that a new cluster should be
+ // created.
+
+ const uint64_t timecode_scale = segment_info_.timecode_scale();
+ const uint64_t frame_timecode = frame_timestamp_ns / timecode_scale;
+
+ const Cluster* const last_cluster = cluster_list_[cluster_list_size_ - 1];
+ const uint64_t last_cluster_timecode = last_cluster->timecode();
+
+ // For completeness we test for the case when the frame's timecode
+ // is less than the cluster's timecode. Although in principle that
+ // is allowed, this muxer doesn't actually write clusters like that,
+ // so this indicates a bug somewhere in our algorithm.
+
+ if (frame_timecode < last_cluster_timecode) // should never happen
+ return -1;
+
+ // If the frame has a timestamp significantly larger than the last
+ // cluster (in Matroska, cluster-relative timestamps are serialized
+ // using a 16-bit signed integer), then we cannot write this frame
+ // to that cluster, and so we must create a new cluster.
+
+ const int64_t delta_timecode = frame_timecode - last_cluster_timecode;
+
+ if (delta_timecode > kMaxBlockTimecode)
+ return 2;
+
+ // We decide to create a new cluster when we have a video keyframe.
+ // This will flush queued (audio) frames, and write the keyframe
+ // immediately, in the newly-created cluster.
+
+ if (is_key && tracks_.TrackIsVideo(track_number))
+ return 1;
+
+ // Create a new cluster if we have accumulated too many frames
+ // already, where "too many" is defined as "the total time of frames
+ // in the cluster exceeds a threshold".
+
+ const uint64_t delta_ns = delta_timecode * timecode_scale;
+
+ if (max_cluster_duration_ > 0 && delta_ns >= max_cluster_duration_)
+ return 1;
+
+ // This is similar to the case above, with the difference that a new
+ // cluster is created when the size of the current cluster exceeds a
+ // threshold.
+
+ const uint64_t cluster_size = last_cluster->payload_size();
+
+ if (max_cluster_size_ > 0 && cluster_size >= max_cluster_size_)
+ return 1;
+
+ // There's no need to create a new cluster, so emit this frame now.
+
+ return 0;
+}
+
+bool Segment::MakeNewCluster(uint64_t frame_timestamp_ns) {
+ const int32_t new_size = cluster_list_size_ + 1;
+
+ if (new_size > cluster_list_capacity_) {
+ // Add more clusters.
+ const int32_t new_capacity =
+ (cluster_list_capacity_ <= 0) ? 1 : cluster_list_capacity_ * 2;
+ Cluster** const clusters =
+ new (std::nothrow) Cluster*[new_capacity]; // NOLINT
+ if (!clusters)
+ return false;
+
+ for (int32_t i = 0; i < cluster_list_size_; ++i) {
+ clusters[i] = cluster_list_[i];
+ }
+
+ delete[] cluster_list_;
+
+ cluster_list_ = clusters;
+ cluster_list_capacity_ = new_capacity;
+ }
+
+ if (!WriteFramesLessThan(frame_timestamp_ns))
+ return false;
+
+ if (cluster_list_size_ > 0) {
+ // Update old cluster's size
+ Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1];
+
+ if (!old_cluster || !old_cluster->Finalize(true, frame_timestamp_ns))
+ return false;
+ }
+
+ if (output_cues_)
+ new_cuepoint_ = true;
+
+ if (chunking_ && cluster_list_size_ > 0) {
+ chunk_writer_cluster_->Close();
+ chunk_count_++;
+
+ if (!UpdateChunkName("chk", &chunk_name_))
+ return false;
+ if (!chunk_writer_cluster_->Open(chunk_name_))
+ return false;
+ }
+
+ const uint64_t timecode_scale = segment_info_.timecode_scale();
+ const uint64_t frame_timecode = frame_timestamp_ns / timecode_scale;
+
+ uint64_t cluster_timecode = frame_timecode;
+
+ if (frames_size_ > 0) {
+ const Frame* const f = frames_[0]; // earliest queued frame
+ const uint64_t ns = f->timestamp();
+ const uint64_t tc = ns / timecode_scale;
+
+ if (tc < cluster_timecode)
+ cluster_timecode = tc;
+ }
+
+ Cluster*& cluster = cluster_list_[cluster_list_size_];
+ const int64_t offset = MaxOffset();
+ cluster = new (std::nothrow)
+ Cluster(cluster_timecode, offset, segment_info_.timecode_scale(),
+ accurate_cluster_duration_, fixed_size_cluster_timecode_);
+ if (!cluster)
+ return false;
+
+ if (!cluster->Init(writer_cluster_))
+ return false;
+
+ cluster_list_size_ = new_size;
+ return true;
+}
+
+bool Segment::DoNewClusterProcessing(uint64_t track_number,
+ uint64_t frame_timestamp_ns, bool is_key) {
+ for (;;) {
+ // Based on the characteristics of the current frame and current
+ // cluster, decide whether to create a new cluster.
+ const int result = TestFrame(track_number, frame_timestamp_ns, is_key);
+ if (result < 0) // error
+ return false;
+
+ // Always set force_new_cluster_ to false after TestFrame.
+ force_new_cluster_ = false;
+
+ // A non-zero result means create a new cluster.
+ if (result > 0 && !MakeNewCluster(frame_timestamp_ns))
+ return false;
+
+ // Write queued (audio) frames.
+ const int frame_count = WriteFramesAll();
+ if (frame_count < 0) // error
+ return false;
+
+ // Write the current frame to the current cluster (if TestFrame
+ // returns 0) or to a newly created cluster (TestFrame returns 1).
+ if (result <= 1)
+ return true;
+
+ // TestFrame returned 2, which means there was a large time
+ // difference between the cluster and the frame itself. Do the
+ // test again, comparing the frame to the new cluster.
+ }
+}
+
+bool Segment::CheckHeaderInfo() {
+ if (!header_written_) {
+ if (!WriteSegmentHeader())
+ return false;
+
+ if (!seek_head_.AddSeekEntry(libwebm::kMkvCluster, MaxOffset()))
+ return false;
+
+ if (output_cues_ && cues_track_ == 0) {
+ // Check for a video track
+ for (uint32_t i = 0; i < tracks_.track_entries_size(); ++i) {
+ const Track* const track = tracks_.GetTrackByIndex(i);
+ if (!track)
+ return false;
+
+ if (tracks_.TrackIsVideo(track->number())) {
+ cues_track_ = track->number();
+ break;
+ }
+ }
+
+ // Set first track found
+ if (cues_track_ == 0) {
+ const Track* const track = tracks_.GetTrackByIndex(0);
+ if (!track)
+ return false;
+
+ cues_track_ = track->number();
+ }
+ }
+ }
+ return true;
+}
+
+void Segment::UpdateDocTypeVersion() {
+ for (uint32_t index = 0; index < tracks_.track_entries_size(); ++index) {
+ const Track* track = tracks_.GetTrackByIndex(index);
+ if (track == NULL)
+ break;
+ if ((track->codec_delay() || track->seek_pre_roll()) &&
+ doc_type_version_ < 4) {
+ doc_type_version_ = 4;
+ break;
+ }
+ }
+}
+
+bool Segment::UpdateChunkName(const char* ext, char** name) const {
+ if (!name || !ext)
+ return false;
+
+ char ext_chk[64];
+#ifdef _MSC_VER
+ sprintf_s(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext);
+#else
+ snprintf(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext);
+#endif
+
+ const size_t length = strlen(chunking_base_name_) + strlen(ext_chk) + 1;
+ char* const str = new (std::nothrow) char[length]; // NOLINT
+ if (!str)
+ return false;
+
+#ifdef _MSC_VER
+ strcpy_s(str, length - strlen(ext_chk), chunking_base_name_);
+ strcat_s(str, length, ext_chk);
+#else
+ strcpy(str, chunking_base_name_);
+ strcat(str, ext_chk);
+#endif
+
+ delete[] * name;
+ *name = str;
+
+ return true;
+}
+
+int64_t Segment::MaxOffset() {
+ if (!writer_header_)
+ return -1;
+
+ int64_t offset = writer_header_->Position() - payload_pos_;
+
+ if (chunking_) {
+ for (int32_t i = 0; i < cluster_list_size_; ++i) {
+ Cluster* const cluster = cluster_list_[i];
+ offset += cluster->Size();
+ }
+
+ if (writer_cues_)
+ offset += writer_cues_->Position();
+ }
+
+ return offset;
+}
+
+bool Segment::QueueFrame(Frame* frame) {
+ const int32_t new_size = frames_size_ + 1;
+
+ if (new_size > frames_capacity_) {
+ // Add more frames.
+ const int32_t new_capacity = (!frames_capacity_) ? 2 : frames_capacity_ * 2;
+
+ if (new_capacity < 1)
+ return false;
+
+ Frame** const frames = new (std::nothrow) Frame*[new_capacity]; // NOLINT
+ if (!frames)
+ return false;
+
+ for (int32_t i = 0; i < frames_size_; ++i) {
+ frames[i] = frames_[i];
+ }
+
+ delete[] frames_;
+ frames_ = frames;
+ frames_capacity_ = new_capacity;
+ }
+
+ frames_[frames_size_++] = frame;
+
+ return true;
+}
+
+int Segment::WriteFramesAll() {
+ if (frames_ == NULL)
+ return 0;
+
+ if (cluster_list_size_ < 1)
+ return -1;
+
+ Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
+
+ if (!cluster)
+ return -1;
+
+ for (int32_t i = 0; i < frames_size_; ++i) {
+ Frame*& frame = frames_[i];
+ // TODO(jzern/vigneshv): using Segment::AddGenericFrame here would limit the
+ // places where |doc_type_version_| needs to be updated.
+ if (frame->discard_padding() != 0)
+ doc_type_version_ = 4;
+ if (!cluster->AddFrame(frame))
+ return -1;
+
+ if (new_cuepoint_ && cues_track_ == frame->track_number()) {
+ if (!AddCuePoint(frame->timestamp(), cues_track_))
+ return -1;
+ }
+
+ if (frame->timestamp() > last_timestamp_) {
+ last_timestamp_ = frame->timestamp();
+ last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
+ }
+
+ delete frame;
+ frame = NULL;
+ }
+
+ const int result = frames_size_;
+ frames_size_ = 0;
+
+ return result;
+}
+
+bool Segment::WriteFramesLessThan(uint64_t timestamp) {
+ // Check |cluster_list_size_| to see if this is the first cluster. If it is
+ // the first cluster the audio frames that are less than the first video
+ // timesatmp will be written in a later step.
+ if (frames_size_ > 0 && cluster_list_size_ > 0) {
+ if (!frames_)
+ return false;
+
+ Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
+ if (!cluster)
+ return false;
+
+ int32_t shift_left = 0;
+
+ // TODO(fgalligan): Change this to use the durations of frames instead of
+ // the next frame's start time if the duration is accurate.
+ for (int32_t i = 1; i < frames_size_; ++i) {
+ const Frame* const frame_curr = frames_[i];
+
+ if (frame_curr->timestamp() > timestamp)
+ break;
+
+ const Frame* const frame_prev = frames_[i - 1];
+ if (frame_prev->discard_padding() != 0)
+ doc_type_version_ = 4;
+ if (!cluster->AddFrame(frame_prev))
+ return false;
+
+ if (new_cuepoint_ && cues_track_ == frame_prev->track_number()) {
+ if (!AddCuePoint(frame_prev->timestamp(), cues_track_))
+ return false;
+ }
+
+ ++shift_left;
+ if (frame_prev->timestamp() > last_timestamp_) {
+ last_timestamp_ = frame_prev->timestamp();
+ last_track_timestamp_[frame_prev->track_number() - 1] =
+ frame_prev->timestamp();
+ }
+
+ delete frame_prev;
+ }
+
+ if (shift_left > 0) {
+ if (shift_left >= frames_size_)
+ return false;
+
+ const int32_t new_frames_size = frames_size_ - shift_left;
+ for (int32_t i = 0; i < new_frames_size; ++i) {
+ frames_[i] = frames_[i + shift_left];
+ }
+
+ frames_size_ = new_frames_size;
+ }
+ }
+
+ return true;
+}
+
+} // namespace mkvmuxer
diff --git a/third_party/libwebm/mkvmuxer.hpp b/third_party/libwebm/mkvmuxer/mkvmuxer.h
similarity index 68%
rename from third_party/libwebm/mkvmuxer.hpp
rename to third_party/libwebm/mkvmuxer/mkvmuxer.h
index 03a002c..55ba071 100644
--- a/third_party/libwebm/mkvmuxer.hpp
+++ b/third_party/libwebm/mkvmuxer/mkvmuxer.h
@@ -6,24 +6,31 @@
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
-#ifndef MKVMUXER_HPP
-#define MKVMUXER_HPP
+#ifndef MKVMUXER_MKVMUXER_H_
+#define MKVMUXER_MKVMUXER_H_
-#include "mkvmuxertypes.hpp"
+#include <stdint.h>
+
+#include <cstddef>
+#include <list>
+#include <map>
+
+#include "common/webmids.h"
+#include "mkvmuxer/mkvmuxertypes.h"
// For a description of the WebM elements see
// http://www.webmproject.org/code/specs/container/.
namespace mkvparser {
class IMkvReader;
-} // end namespace
+} // namespace mkvparser
namespace mkvmuxer {
class MkvWriter;
class Segment;
-const uint64 kMaxTrackNumber = 126;
+const uint64_t kMaxTrackNumber = 126;
///////////////////////////////////////////////////////////////
// Interface used by the mkvmuxer to write out the Mkv data.
@@ -59,15 +66,15 @@
// Writes out the EBML header for a WebM file. This function must be called
// before any other libwebm writing functions are called.
-bool WriteEbmlHeader(IMkvWriter* writer, uint64 doc_type_version);
+bool WriteEbmlHeader(IMkvWriter* writer, uint64_t doc_type_version);
// Deprecated. Writes out EBML header with doc_type_version as
// kDefaultDocTypeVersion. Exists for backward compatibility.
bool WriteEbmlHeader(IMkvWriter* writer);
// Copies in Chunk from source to destination between the given byte positions
-bool ChunkedCopy(mkvparser::IMkvReader* source, IMkvWriter* dst, int64 start,
- int64 size);
+bool ChunkedCopy(mkvparser::IMkvReader* source, IMkvWriter* dst, int64_t start,
+ int64_t size);
///////////////////////////////////////////////////////////////
// Class to hold data the will be written to a block.
@@ -81,10 +88,11 @@
bool CopyFrom(const Frame& frame);
// Copies |frame| data into |frame_|. Returns true on success.
- bool Init(const uint8* frame, uint64 length);
+ bool Init(const uint8_t* frame, uint64_t length);
// Copies |additional| data into |additional_|. Returns true on success.
- bool AddAdditionalData(const uint8* additional, uint64 length, uint64 add_id);
+ bool AddAdditionalData(const uint8_t* additional, uint64_t length,
+ uint64_t add_id);
// Returns true if the frame has valid parameters.
bool IsValid() const;
@@ -93,62 +101,70 @@
// parameters.
bool CanBeSimpleBlock() const;
- uint64 add_id() const { return add_id_; }
- const uint8* additional() const { return additional_; }
- uint64 additional_length() const { return additional_length_; }
- void set_duration(uint64 duration) { duration_ = duration; }
- uint64 duration() const { return duration_; }
- const uint8* frame() const { return frame_; }
+ uint64_t add_id() const { return add_id_; }
+ const uint8_t* additional() const { return additional_; }
+ uint64_t additional_length() const { return additional_length_; }
+ void set_duration(uint64_t duration);
+ uint64_t duration() const { return duration_; }
+ bool duration_set() const { return duration_set_; }
+ const uint8_t* frame() const { return frame_; }
void set_is_key(bool key) { is_key_ = key; }
bool is_key() const { return is_key_; }
- uint64 length() const { return length_; }
- void set_track_number(uint64 track_number) { track_number_ = track_number; }
- uint64 track_number() const { return track_number_; }
- void set_timestamp(uint64 timestamp) { timestamp_ = timestamp; }
- uint64 timestamp() const { return timestamp_; }
- void set_discard_padding(int64 discard_padding) {
+ uint64_t length() const { return length_; }
+ void set_track_number(uint64_t track_number) { track_number_ = track_number; }
+ uint64_t track_number() const { return track_number_; }
+ void set_timestamp(uint64_t timestamp) { timestamp_ = timestamp; }
+ uint64_t timestamp() const { return timestamp_; }
+ void set_discard_padding(int64_t discard_padding) {
discard_padding_ = discard_padding;
}
- int64 discard_padding() const { return discard_padding_; }
- void set_reference_block_timestamp(int64 reference_block_timestamp);
- int64 reference_block_timestamp() const { return reference_block_timestamp_; }
+ int64_t discard_padding() const { return discard_padding_; }
+ void set_reference_block_timestamp(int64_t reference_block_timestamp);
+ int64_t reference_block_timestamp() const {
+ return reference_block_timestamp_;
+ }
bool reference_block_timestamp_set() const {
return reference_block_timestamp_set_;
}
private:
// Id of the Additional data.
- uint64 add_id_;
+ uint64_t add_id_;
// Pointer to additional data. Owned by this class.
- uint8* additional_;
+ uint8_t* additional_;
// Length of the additional data.
- uint64 additional_length_;
+ uint64_t additional_length_;
// Duration of the frame in nanoseconds.
- uint64 duration_;
+ uint64_t duration_;
+
+ // Flag indicating that |duration_| has been set. Setting duration causes the
+ // frame to be written out as a Block with BlockDuration instead of as a
+ // SimpleBlock.
+ bool duration_set_;
// Pointer to the data. Owned by this class.
- uint8* frame_;
+ uint8_t* frame_;
// Flag telling if the data should set the key flag of a block.
bool is_key_;
// Length of the data.
- uint64 length_;
+ uint64_t length_;
// Mkv track number the data is associated with.
- uint64 track_number_;
+ uint64_t track_number_;
// Timestamp of the data in nanoseconds.
- uint64 timestamp_;
+ uint64_t timestamp_;
// Discard padding for the frame.
- int64 discard_padding_;
+ int64_t discard_padding_;
// Reference block timestamp.
- int64 reference_block_timestamp_;
+ int64_t reference_block_timestamp_;
// Flag indicating if |reference_block_timestamp_| has been set.
bool reference_block_timestamp_set_;
@@ -164,19 +180,19 @@
~CuePoint();
// Returns the size in bytes for the entire CuePoint element.
- uint64 Size() const;
+ uint64_t Size() const;
// Output the CuePoint element to the writer. Returns true on success.
bool Write(IMkvWriter* writer) const;
- void set_time(uint64 time) { time_ = time; }
- uint64 time() const { return time_; }
- void set_track(uint64 track) { track_ = track; }
- uint64 track() const { return track_; }
- void set_cluster_pos(uint64 cluster_pos) { cluster_pos_ = cluster_pos; }
- uint64 cluster_pos() const { return cluster_pos_; }
- void set_block_number(uint64 block_number) { block_number_ = block_number; }
- uint64 block_number() const { return block_number_; }
+ void set_time(uint64_t time) { time_ = time; }
+ uint64_t time() const { return time_; }
+ void set_track(uint64_t track) { track_ = track; }
+ uint64_t track() const { return track_; }
+ void set_cluster_pos(uint64_t cluster_pos) { cluster_pos_ = cluster_pos; }
+ uint64_t cluster_pos() const { return cluster_pos_; }
+ void set_block_number(uint64_t block_number) { block_number_ = block_number; }
+ uint64_t block_number() const { return block_number_; }
void set_output_block_number(bool output_block_number) {
output_block_number_ = output_block_number;
}
@@ -184,19 +200,19 @@
private:
// Returns the size in bytes for the payload of the CuePoint element.
- uint64 PayloadSize() const;
+ uint64_t PayloadSize() const;
// Absolute timecode according to the segment time base.
- uint64 time_;
+ uint64_t time_;
// The Track element associated with the CuePoint.
- uint64 track_;
+ uint64_t track_;
// The position of the Cluster containing the Block.
- uint64 cluster_pos_;
+ uint64_t cluster_pos_;
// Number of the Block within the Cluster, starting from 1.
- uint64 block_number_;
+ uint64_t block_number_;
// If true the muxer will write out the block number for the cue if the
// block number is different than the default of 1. Default is set to true.
@@ -217,15 +233,15 @@
// Returns the cue point by index. Returns NULL if there is no cue point
// match.
- CuePoint* GetCueByIndex(int32 index) const;
+ CuePoint* GetCueByIndex(int32_t index) const;
// Returns the total size of the Cues element
- uint64 Size();
+ uint64_t Size();
// Output the Cues element to the writer. Returns true on success.
bool Write(IMkvWriter* writer) const;
- int32 cue_entries_size() const { return cue_entries_size_; }
+ int32_t cue_entries_size() const { return cue_entries_size_; }
void set_output_block_number(bool output_block_number) {
output_block_number_ = output_block_number;
}
@@ -233,10 +249,10 @@
private:
// Number of allocated elements in |cue_entries_|.
- int32 cue_entries_capacity_;
+ int32_t cue_entries_capacity_;
// Number of CuePoints in |cue_entries_|.
- int32 cue_entries_size_;
+ int32_t cue_entries_size_;
// CuePoint list.
CuePoint** cue_entries_;
@@ -258,21 +274,21 @@
~ContentEncAESSettings() {}
// Returns the size in bytes for the ContentEncAESSettings element.
- uint64 Size() const;
+ uint64_t Size() const;
// Writes out the ContentEncAESSettings element to |writer|. Returns true on
// success.
bool Write(IMkvWriter* writer) const;
- uint64 cipher_mode() const { return cipher_mode_; }
+ uint64_t cipher_mode() const { return cipher_mode_; }
private:
// Returns the size in bytes for the payload of the ContentEncAESSettings
// element.
- uint64 PayloadSize() const;
+ uint64_t PayloadSize() const;
// Sub elements
- uint64 cipher_mode_;
+ uint64_t cipher_mode_;
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncAESSettings);
};
@@ -291,45 +307,158 @@
// Sets the content encryption id. Copies |length| bytes from |id| to
// |enc_key_id_|. Returns true on success.
- bool SetEncryptionID(const uint8* id, uint64 length);
+ bool SetEncryptionID(const uint8_t* id, uint64_t length);
// Returns the size in bytes for the ContentEncoding element.
- uint64 Size() const;
+ uint64_t Size() const;
// Writes out the ContentEncoding element to |writer|. Returns true on
// success.
bool Write(IMkvWriter* writer) const;
- uint64 enc_algo() const { return enc_algo_; }
- uint64 encoding_order() const { return encoding_order_; }
- uint64 encoding_scope() const { return encoding_scope_; }
- uint64 encoding_type() const { return encoding_type_; }
+ uint64_t enc_algo() const { return enc_algo_; }
+ uint64_t encoding_order() const { return encoding_order_; }
+ uint64_t encoding_scope() const { return encoding_scope_; }
+ uint64_t encoding_type() const { return encoding_type_; }
ContentEncAESSettings* enc_aes_settings() { return &enc_aes_settings_; }
private:
// Returns the size in bytes for the encoding elements.
- uint64 EncodingSize(uint64 compresion_size, uint64 encryption_size) const;
+ uint64_t EncodingSize(uint64_t compresion_size,
+ uint64_t encryption_size) const;
// Returns the size in bytes for the encryption elements.
- uint64 EncryptionSize() const;
+ uint64_t EncryptionSize() const;
// Track element names
- uint64 enc_algo_;
- uint8* enc_key_id_;
- uint64 encoding_order_;
- uint64 encoding_scope_;
- uint64 encoding_type_;
+ uint64_t enc_algo_;
+ uint8_t* enc_key_id_;
+ uint64_t encoding_order_;
+ uint64_t encoding_scope_;
+ uint64_t encoding_type_;
// ContentEncAESSettings element.
ContentEncAESSettings enc_aes_settings_;
// Size of the ContentEncKeyID data in bytes.
- uint64 enc_key_id_length_;
+ uint64_t enc_key_id_length_;
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncoding);
};
///////////////////////////////////////////////////////////////
+// Colour element.
+struct PrimaryChromaticity {
+ PrimaryChromaticity(float x_val, float y_val) : x(x_val), y(y_val) {}
+ PrimaryChromaticity() : x(0), y(0) {}
+ ~PrimaryChromaticity() {}
+ uint64_t PrimaryChromaticityPayloadSize(libwebm::MkvId x_id,
+ libwebm::MkvId y_id) const;
+ bool Write(IMkvWriter* writer, libwebm::MkvId x_id,
+ libwebm::MkvId y_id) const;
+
+ float x;
+ float y;
+};
+
+class MasteringMetadata {
+ public:
+ static const float kValueNotPresent;
+
+ MasteringMetadata()
+ : luminance_max(kValueNotPresent),
+ luminance_min(kValueNotPresent),
+ r_(NULL),
+ g_(NULL),
+ b_(NULL),
+ white_point_(NULL) {}
+ ~MasteringMetadata() {
+ delete r_;
+ delete g_;
+ delete b_;
+ delete white_point_;
+ }
+
+ // Returns total size of the MasteringMetadata element.
+ uint64_t MasteringMetadataSize() const;
+ bool Write(IMkvWriter* writer) const;
+
+ // Copies non-null chromaticity.
+ bool SetChromaticity(const PrimaryChromaticity* r,
+ const PrimaryChromaticity* g,
+ const PrimaryChromaticity* b,
+ const PrimaryChromaticity* white_point);
+ const PrimaryChromaticity* r() const { return r_; }
+ const PrimaryChromaticity* g() const { return g_; }
+ const PrimaryChromaticity* b() const { return b_; }
+ const PrimaryChromaticity* white_point() const { return white_point_; }
+
+ float luminance_max;
+ float luminance_min;
+
+ private:
+ // Returns size of MasteringMetadata child elements.
+ uint64_t PayloadSize() const;
+
+ PrimaryChromaticity* r_;
+ PrimaryChromaticity* g_;
+ PrimaryChromaticity* b_;
+ PrimaryChromaticity* white_point_;
+};
+
+class Colour {
+ public:
+ static const uint64_t kValueNotPresent;
+ Colour()
+ : matrix_coefficients(kValueNotPresent),
+ bits_per_channel(kValueNotPresent),
+ chroma_subsampling_horz(kValueNotPresent),
+ chroma_subsampling_vert(kValueNotPresent),
+ cb_subsampling_horz(kValueNotPresent),
+ cb_subsampling_vert(kValueNotPresent),
+ chroma_siting_horz(kValueNotPresent),
+ chroma_siting_vert(kValueNotPresent),
+ range(kValueNotPresent),
+ transfer_characteristics(kValueNotPresent),
+ primaries(kValueNotPresent),
+ max_cll(kValueNotPresent),
+ max_fall(kValueNotPresent),
+ mastering_metadata_(NULL) {}
+ ~Colour() { delete mastering_metadata_; }
+
+ // Returns total size of the Colour element.
+ uint64_t ColourSize() const;
+ bool Write(IMkvWriter* writer) const;
+
+ // Deep copies |mastering_metadata|.
+ bool SetMasteringMetadata(const MasteringMetadata& mastering_metadata);
+
+ const MasteringMetadata* mastering_metadata() const {
+ return mastering_metadata_;
+ }
+
+ uint64_t matrix_coefficients;
+ uint64_t bits_per_channel;
+ uint64_t chroma_subsampling_horz;
+ uint64_t chroma_subsampling_vert;
+ uint64_t cb_subsampling_horz;
+ uint64_t cb_subsampling_vert;
+ uint64_t chroma_siting_horz;
+ uint64_t chroma_siting_vert;
+ uint64_t range;
+ uint64_t transfer_characteristics;
+ uint64_t primaries;
+ uint64_t max_cll;
+ uint64_t max_fall;
+
+ private:
+ // Returns size of Colour child elements.
+ uint64_t PayloadSize() const;
+
+ MasteringMetadata* mastering_metadata_;
+};
+
+///////////////////////////////////////////////////////////////
// Track element.
class Track {
public:
@@ -342,76 +471,76 @@
// Returns the ContentEncoding by index. Returns NULL if there is no
// ContentEncoding match.
- ContentEncoding* GetContentEncodingByIndex(uint32 index) const;
+ ContentEncoding* GetContentEncodingByIndex(uint32_t index) const;
// Returns the size in bytes for the payload of the Track element.
- virtual uint64 PayloadSize() const;
+ virtual uint64_t PayloadSize() const;
// Returns the size in bytes of the Track element.
- virtual uint64 Size() const;
+ virtual uint64_t Size() const;
// Output the Track element to the writer. Returns true on success.
virtual bool Write(IMkvWriter* writer) const;
// Sets the CodecPrivate element of the Track element. Copies |length|
// bytes from |codec_private| to |codec_private_|. Returns true on success.
- bool SetCodecPrivate(const uint8* codec_private, uint64 length);
+ bool SetCodecPrivate(const uint8_t* codec_private, uint64_t length);
void set_codec_id(const char* codec_id);
const char* codec_id() const { return codec_id_; }
- const uint8* codec_private() const { return codec_private_; }
+ const uint8_t* codec_private() const { return codec_private_; }
void set_language(const char* language);
const char* language() const { return language_; }
- void set_max_block_additional_id(uint64 max_block_additional_id) {
+ void set_max_block_additional_id(uint64_t max_block_additional_id) {
max_block_additional_id_ = max_block_additional_id;
}
- uint64 max_block_additional_id() const { return max_block_additional_id_; }
+ uint64_t max_block_additional_id() const { return max_block_additional_id_; }
void set_name(const char* name);
const char* name() const { return name_; }
- void set_number(uint64 number) { number_ = number; }
- uint64 number() const { return number_; }
- void set_type(uint64 type) { type_ = type; }
- uint64 type() const { return type_; }
- void set_uid(uint64 uid) { uid_ = uid; }
- uint64 uid() const { return uid_; }
- void set_codec_delay(uint64 codec_delay) { codec_delay_ = codec_delay; }
- uint64 codec_delay() const { return codec_delay_; }
- void set_seek_pre_roll(uint64 seek_pre_roll) {
+ void set_number(uint64_t number) { number_ = number; }
+ uint64_t number() const { return number_; }
+ void set_type(uint64_t type) { type_ = type; }
+ uint64_t type() const { return type_; }
+ void set_uid(uint64_t uid) { uid_ = uid; }
+ uint64_t uid() const { return uid_; }
+ void set_codec_delay(uint64_t codec_delay) { codec_delay_ = codec_delay; }
+ uint64_t codec_delay() const { return codec_delay_; }
+ void set_seek_pre_roll(uint64_t seek_pre_roll) {
seek_pre_roll_ = seek_pre_roll;
}
- uint64 seek_pre_roll() const { return seek_pre_roll_; }
- void set_default_duration(uint64 default_duration) {
+ uint64_t seek_pre_roll() const { return seek_pre_roll_; }
+ void set_default_duration(uint64_t default_duration) {
default_duration_ = default_duration;
}
- uint64 default_duration() const { return default_duration_; }
+ uint64_t default_duration() const { return default_duration_; }
- uint64 codec_private_length() const { return codec_private_length_; }
- uint32 content_encoding_entries_size() const {
+ uint64_t codec_private_length() const { return codec_private_length_; }
+ uint32_t content_encoding_entries_size() const {
return content_encoding_entries_size_;
}
private:
// Track element names.
char* codec_id_;
- uint8* codec_private_;
+ uint8_t* codec_private_;
char* language_;
- uint64 max_block_additional_id_;
+ uint64_t max_block_additional_id_;
char* name_;
- uint64 number_;
- uint64 type_;
- uint64 uid_;
- uint64 codec_delay_;
- uint64 seek_pre_roll_;
- uint64 default_duration_;
+ uint64_t number_;
+ uint64_t type_;
+ uint64_t uid_;
+ uint64_t codec_delay_;
+ uint64_t seek_pre_roll_;
+ uint64_t default_duration_;
// Size of the CodecPrivate data in bytes.
- uint64 codec_private_length_;
+ uint64_t codec_private_length_;
// ContentEncoding element list.
ContentEncoding** content_encoding_entries_;
// Number of ContentEncoding elements added.
- uint32 content_encoding_entries_size_;
+ uint32_t content_encoding_entries_size_;
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Track);
};
@@ -437,56 +566,63 @@
// Returns the size in bytes for the payload of the Track element plus the
// video specific elements.
- virtual uint64 PayloadSize() const;
+ virtual uint64_t PayloadSize() const;
// Output the VideoTrack element to the writer. Returns true on success.
virtual bool Write(IMkvWriter* writer) const;
// Sets the video's stereo mode. Returns true on success.
- bool SetStereoMode(uint64 stereo_mode);
+ bool SetStereoMode(uint64_t stereo_mode);
// Sets the video's alpha mode. Returns true on success.
- bool SetAlphaMode(uint64 alpha_mode);
+ bool SetAlphaMode(uint64_t alpha_mode);
- void set_display_height(uint64 height) { display_height_ = height; }
- uint64 display_height() const { return display_height_; }
- void set_display_width(uint64 width) { display_width_ = width; }
- uint64 display_width() const { return display_width_; }
+ void set_display_height(uint64_t height) { display_height_ = height; }
+ uint64_t display_height() const { return display_height_; }
+ void set_display_width(uint64_t width) { display_width_ = width; }
+ uint64_t display_width() const { return display_width_; }
- void set_crop_left(uint64 crop_left) { crop_left_ = crop_left; }
- uint64 crop_left() const { return crop_left_; }
- void set_crop_right(uint64 crop_right) { crop_right_ = crop_right; }
- uint64 crop_right() const { return crop_right_; }
- void set_crop_top(uint64 crop_top) { crop_top_ = crop_top; }
- uint64 crop_top() const { return crop_top_; }
- void set_crop_bottom(uint64 crop_bottom) { crop_bottom_ = crop_bottom; }
- uint64 crop_bottom() const { return crop_bottom_; }
+ void set_crop_left(uint64_t crop_left) { crop_left_ = crop_left; }
+ uint64_t crop_left() const { return crop_left_; }
+ void set_crop_right(uint64_t crop_right) { crop_right_ = crop_right; }
+ uint64_t crop_right() const { return crop_right_; }
+ void set_crop_top(uint64_t crop_top) { crop_top_ = crop_top; }
+ uint64_t crop_top() const { return crop_top_; }
+ void set_crop_bottom(uint64_t crop_bottom) { crop_bottom_ = crop_bottom; }
+ uint64_t crop_bottom() const { return crop_bottom_; }
void set_frame_rate(double frame_rate) { frame_rate_ = frame_rate; }
double frame_rate() const { return frame_rate_; }
- void set_height(uint64 height) { height_ = height; }
- uint64 height() const { return height_; }
- uint64 stereo_mode() { return stereo_mode_; }
- uint64 alpha_mode() { return alpha_mode_; }
- void set_width(uint64 width) { width_ = width; }
- uint64 width() const { return width_; }
+ void set_height(uint64_t height) { height_ = height; }
+ uint64_t height() const { return height_; }
+ uint64_t stereo_mode() { return stereo_mode_; }
+ uint64_t alpha_mode() { return alpha_mode_; }
+ void set_width(uint64_t width) { width_ = width; }
+ uint64_t width() const { return width_; }
+
+ Colour* colour() { return colour_; }
+
+ // Deep copies |colour|.
+ bool SetColour(const Colour& colour);
private:
// Returns the size in bytes of the Video element.
- uint64 VideoPayloadSize() const;
+ uint64_t VideoPayloadSize() const;
// Video track element names.
- uint64 display_height_;
- uint64 display_width_;
- uint64 crop_left_;
- uint64 crop_right_;
- uint64 crop_top_;
- uint64 crop_bottom_;
+ uint64_t display_height_;
+ uint64_t display_width_;
+ uint64_t crop_left_;
+ uint64_t crop_right_;
+ uint64_t crop_top_;
+ uint64_t crop_bottom_;
double frame_rate_;
- uint64 height_;
- uint64 stereo_mode_;
- uint64 alpha_mode_;
- uint64 width_;
+ uint64_t height_;
+ uint64_t stereo_mode_;
+ uint64_t alpha_mode_;
+ uint64_t width_;
+
+ Colour* colour_;
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(VideoTrack);
};
@@ -501,22 +637,22 @@
// Returns the size in bytes for the payload of the Track element plus the
// audio specific elements.
- virtual uint64 PayloadSize() const;
+ virtual uint64_t PayloadSize() const;
// Output the AudioTrack element to the writer. Returns true on success.
virtual bool Write(IMkvWriter* writer) const;
- void set_bit_depth(uint64 bit_depth) { bit_depth_ = bit_depth; }
- uint64 bit_depth() const { return bit_depth_; }
- void set_channels(uint64 channels) { channels_ = channels; }
- uint64 channels() const { return channels_; }
+ void set_bit_depth(uint64_t bit_depth) { bit_depth_ = bit_depth; }
+ uint64_t bit_depth() const { return bit_depth_; }
+ void set_channels(uint64_t channels) { channels_ = channels; }
+ uint64_t channels() const { return channels_; }
void set_sample_rate(double sample_rate) { sample_rate_ = sample_rate; }
double sample_rate() const { return sample_rate_; }
private:
// Audio track element names.
- uint64 bit_depth_;
- uint64 channels_;
+ uint64_t bit_depth_;
+ uint64_t channels_;
double sample_rate_;
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(AudioTrack);
@@ -542,32 +678,35 @@
// deleted by the Tracks object. Returns true on success. |number| is the
// number to use for the track. |number| must be >= 0. If |number| == 0
// then the muxer will decide on the track number.
- bool AddTrack(Track* track, int32 number);
+ bool AddTrack(Track* track, int32_t number);
// Returns the track by index. Returns NULL if there is no track match.
- const Track* GetTrackByIndex(uint32 idx) const;
+ const Track* GetTrackByIndex(uint32_t idx) const;
// Search the Tracks and return the track that matches |tn|. Returns NULL
// if there is no track match.
- Track* GetTrackByNumber(uint64 track_number) const;
+ Track* GetTrackByNumber(uint64_t track_number) const;
// Returns true if the track number is an audio track.
- bool TrackIsAudio(uint64 track_number) const;
+ bool TrackIsAudio(uint64_t track_number) const;
// Returns true if the track number is a video track.
- bool TrackIsVideo(uint64 track_number) const;
+ bool TrackIsVideo(uint64_t track_number) const;
// Output the Tracks element to the writer. Returns true on success.
bool Write(IMkvWriter* writer) const;
- uint32 track_entries_size() const { return track_entries_size_; }
+ uint32_t track_entries_size() const { return track_entries_size_; }
private:
// Track element list.
Track** track_entries_;
// Number of Track elements added.
- uint32 track_entries_size_;
+ uint32_t track_entries_size_;
+
+ // Whether or not Tracks element has already been written via IMkvWriter.
+ mutable bool wrote_tracks_;
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Tracks);
};
@@ -585,12 +724,12 @@
// Converts the nanosecond start and stop times of this chapter to
// their corresponding timecode values, and stores them that way.
- void set_time(const Segment& segment, uint64 start_time_ns,
- uint64 end_time_ns);
+ void set_time(const Segment& segment, uint64_t start_time_ns,
+ uint64_t end_time_ns);
// Sets the uid for this chapter. Primarily used to enable
// deterministic output from the muxer.
- void set_uid(const uint64 uid) { uid_ = uid; }
+ void set_uid(const uint64_t uid) { uid_ = uid; }
// Add a title string to this chapter, per the semantics described
// here:
@@ -637,7 +776,7 @@
// If |writer| is non-NULL, serialize the Display sub-element of
// the Atom into the stream. Returns the Display element size on
// success, 0 if error.
- uint64 WriteDisplay(IMkvWriter* writer) const;
+ uint64_t WriteDisplay(IMkvWriter* writer) const;
private:
char* title_;
@@ -670,20 +809,20 @@
// If |writer| is non-NULL, serialize the Atom sub-element into the
// stream. Returns the total size of the element on success, 0 if
// error.
- uint64 WriteAtom(IMkvWriter* writer) const;
+ uint64_t WriteAtom(IMkvWriter* writer) const;
// The string identifier for this chapter (corresponds to WebVTT cue
// identifier).
char* id_;
// Start timecode of the chapter.
- uint64 start_timecode_;
+ uint64_t start_timecode_;
// Stop timecode of the chapter.
- uint64 end_timecode_;
+ uint64_t end_timecode_;
// The binary identifier for this chapter.
- uint64 uid_;
+ uint64_t uid_;
// The Atom element can contain multiple Display sub-elements, as
// the same logical title can be rendered in different languages.
@@ -723,7 +862,7 @@
// If |writer| is non-NULL, serialize the Edition sub-element of the
// Chapters element into the stream. Returns the Edition element
// size on success, 0 if error.
- uint64 WriteEdition(IMkvWriter* writer) const;
+ uint64_t WriteEdition(IMkvWriter* writer) const;
// Total length of the chapters_ array.
int chapters_size_;
@@ -768,7 +907,7 @@
// If |writer| is non-NULL, serialize the SimpleTag sub-element of
// the Atom into the stream. Returns the SimpleTag element size on
// success, 0 if error.
- uint64 Write(IMkvWriter* writer) const;
+ uint64_t Write(IMkvWriter* writer) const;
private:
char* tag_name_;
@@ -795,7 +934,7 @@
// If |writer| is non-NULL, serialize the Tag sub-element into the
// stream. Returns the total size of the element on success, 0 if
// error.
- uint64 Write(IMkvWriter* writer) const;
+ uint64_t Write(IMkvWriter* writer) const;
// The Atom element can contain multiple SimpleTag sub-elements
SimpleTag* simple_tags_;
@@ -853,7 +992,9 @@
// |timecode| is the absolute timecode of the cluster. |cues_pos| is the
// position for the cluster within the segment that should be written in
// the cues element. |timecode_scale| is the timecode scale of the segment.
- Cluster(uint64 timecode, int64 cues_pos, uint64 timecode_scale);
+ Cluster(uint64_t timecode, int64_t cues_pos, uint64_t timecode_scale,
+ bool write_last_frame_with_duration = false,
+ bool fixed_size_timecode = false);
~Cluster();
bool Init(IMkvWriter* ptr_writer);
@@ -872,8 +1013,8 @@
// timecode: Absolute (not relative to cluster) timestamp of the
// frame, expressed in timecode units.
// is_key: Flag telling whether or not this frame is a key frame.
- bool AddFrame(const uint8* data, uint64 length, uint64 track_number,
- uint64 timecode, // timecode units (absolute)
+ bool AddFrame(const uint8_t* data, uint64_t length, uint64_t track_number,
+ uint64_t timecode, // timecode units (absolute)
bool is_key);
// Adds a frame to be output in the file. The frame is written out through
@@ -889,10 +1030,11 @@
// abs_timecode: Absolute (not relative to cluster) timestamp of the
// frame, expressed in timecode units.
// is_key: Flag telling whether or not this frame is a key frame.
- bool AddFrameWithAdditional(const uint8* data, uint64 length,
- const uint8* additional, uint64 additional_length,
- uint64 add_id, uint64 track_number,
- uint64 abs_timecode, bool is_key);
+ bool AddFrameWithAdditional(const uint8_t* data, uint64_t length,
+ const uint8_t* additional,
+ uint64_t additional_length, uint64_t add_id,
+ uint64_t track_number, uint64_t abs_timecode,
+ bool is_key);
// Adds a frame to be output in the file. The frame is written out through
// |writer_| if successful. Returns true on success.
@@ -905,9 +1047,10 @@
// abs_timecode: Absolute (not relative to cluster) timestamp of the
// frame, expressed in timecode units.
// is_key: Flag telling whether or not this frame is a key frame.
- bool AddFrameWithDiscardPadding(const uint8* data, uint64 length,
- int64 discard_padding, uint64 track_number,
- uint64 abs_timecode, bool is_key);
+ bool AddFrameWithDiscardPadding(const uint8_t* data, uint64_t length,
+ int64_t discard_padding,
+ uint64_t track_number, uint64_t abs_timecode,
+ bool is_key);
// Writes a frame of metadata to the output medium; returns true on
// success.
@@ -923,31 +1066,53 @@
// The metadata frame is written as a block group, with a duration
// sub-element but no reference time sub-elements (indicating that
// it is considered a keyframe, per Matroska semantics).
- bool AddMetadata(const uint8* data, uint64 length, uint64 track_number,
- uint64 timecode, uint64 duration);
+ bool AddMetadata(const uint8_t* data, uint64_t length, uint64_t track_number,
+ uint64_t timecode, uint64_t duration);
// Increments the size of the cluster's data in bytes.
- void AddPayloadSize(uint64 size);
+ void AddPayloadSize(uint64_t size);
+
+ // Closes the cluster so no more data can be written to it. Will update the
+ // cluster's size if |writer_| is seekable. Returns true on success. This
+ // variant of Finalize() fails when |write_last_frame_with_duration_| is set
+ // to true.
+ bool Finalize();
// Closes the cluster so no more data can be written to it. Will update the
// cluster's size if |writer_| is seekable. Returns true on success.
- bool Finalize();
+ // Inputs:
+ // set_last_frame_duration: Boolean indicating whether or not the duration
+ // of the last frame should be set. If set to
+ // false, the |duration| value is ignored and
+ // |write_last_frame_with_duration_| will not be
+ // honored.
+ // duration: Duration of the Cluster in timecode scale.
+ bool Finalize(bool set_last_frame_duration, uint64_t duration);
// Returns the size in bytes for the entire Cluster element.
- uint64 Size() const;
+ uint64_t Size() const;
// Given |abs_timecode|, calculates timecode relative to most recent timecode.
// Returns -1 on failure, or a relative timecode.
- int64 GetRelativeTimecode(int64 abs_timecode) const;
+ int64_t GetRelativeTimecode(int64_t abs_timecode) const;
- int64 size_position() const { return size_position_; }
- int32 blocks_added() const { return blocks_added_; }
- uint64 payload_size() const { return payload_size_; }
- int64 position_for_cues() const { return position_for_cues_; }
- uint64 timecode() const { return timecode_; }
- uint64 timecode_scale() const { return timecode_scale_; }
+ int64_t size_position() const { return size_position_; }
+ int32_t blocks_added() const { return blocks_added_; }
+ uint64_t payload_size() const { return payload_size_; }
+ int64_t position_for_cues() const { return position_for_cues_; }
+ uint64_t timecode() const { return timecode_; }
+ uint64_t timecode_scale() const { return timecode_scale_; }
+ void set_write_last_frame_with_duration(bool write_last_frame_with_duration) {
+ write_last_frame_with_duration_ = write_last_frame_with_duration;
+ }
+ bool write_last_frame_with_duration() const {
+ return write_last_frame_with_duration_;
+ }
private:
+ // Iterator type for the |stored_frames_| map.
+ typedef std::map<uint64_t, std::list<Frame*> >::iterator FrameMapIterator;
+
// Utility method that confirms that blocks can still be added, and that the
// cluster header has been written. Used by |DoWriteFrame*|. Returns true
// when successful.
@@ -955,37 +1120,58 @@
// Utility method used by the |DoWriteFrame*| methods that handles the book
// keeping required after each block is written.
- void PostWriteBlock(uint64 element_size);
+ void PostWriteBlock(uint64_t element_size);
// Does some verification and calls WriteFrame.
bool DoWriteFrame(const Frame* const frame);
+ // Either holds back the given frame, or writes it out depending on whether or
+ // not |write_last_frame_with_duration_| is set.
+ bool QueueOrWriteFrame(const Frame* const frame);
+
// Outputs the Cluster header to |writer_|. Returns true on success.
bool WriteClusterHeader();
// Number of blocks added to the cluster.
- int32 blocks_added_;
+ int32_t blocks_added_;
// Flag telling if the cluster has been closed.
bool finalized_;
+ // Flag indicating whether the cluster's timecode will always be written out
+ // using 8 bytes.
+ bool fixed_size_timecode_;
+
// Flag telling if the cluster's header has been written.
bool header_written_;
// The size of the cluster elements in bytes.
- uint64 payload_size_;
+ uint64_t payload_size_;
// The file position used for cue points.
- const int64 position_for_cues_;
+ const int64_t position_for_cues_;
// The file position of the cluster's size element.
- int64 size_position_;
+ int64_t size_position_;
// The absolute timecode of the cluster.
- const uint64 timecode_;
+ const uint64_t timecode_;
// The timecode scale of the Segment containing the cluster.
- const uint64 timecode_scale_;
+ const uint64_t timecode_scale_;
+
+ // Flag indicating whether the last frame of the cluster should be written as
+ // a Block with Duration. If set to true, then it will result in holding back
+ // of frames and the parameterized version of Finalize() must be called to
+ // finish writing the Cluster.
+ bool write_last_frame_with_duration_;
+
+ // Map used to hold back frames, if required. Track number is the key.
+ std::map<uint64_t, std::list<Frame*> > stored_frames_;
+
+ // Map from track number to the timestamp of the last block written for that
+ // track.
+ std::map<uint64_t, uint64_t> last_block_timestamp_;
// Pointer to the writer object. Not owned by this class.
IMkvWriter* writer_;
@@ -1006,42 +1192,42 @@
// Adds a seek entry to be written out when the element is finalized. |id|
// must be the coded mkv element id. |pos| is the file position of the
// element. Returns true on success.
- bool AddSeekEntry(uint32 id, uint64 pos);
+ bool AddSeekEntry(uint32_t id, uint64_t pos);
// Writes out SeekHead and SeekEntry elements. Returns true on success.
bool Finalize(IMkvWriter* writer) const;
// Returns the id of the Seek Entry at the given index. Returns -1 if index is
// out of range.
- uint32 GetId(int index) const;
+ uint32_t GetId(int index) const;
// Returns the position of the Seek Entry at the given index. Returns -1 if
// index is out of range.
- uint64 GetPosition(int index) const;
+ uint64_t GetPosition(int index) const;
// Sets the Seek Entry id and position at given index.
// Returns true on success.
- bool SetSeekEntry(int index, uint32 id, uint64 position);
+ bool SetSeekEntry(int index, uint32_t id, uint64_t position);
// Reserves space by writing out a Void element which will be updated with
// a SeekHead element later. Returns true on success.
bool Write(IMkvWriter* writer);
// We are going to put a cap on the number of Seek Entries.
- const static int32 kSeekEntryCount = 5;
+ const static int32_t kSeekEntryCount = 5;
private:
// Returns the maximum size in bytes of one seek entry.
- uint64 MaxEntrySize() const;
+ uint64_t MaxEntrySize() const;
// Seek entry id element list.
- uint32 seek_entry_id_[kSeekEntryCount];
+ uint32_t seek_entry_id_[kSeekEntryCount];
// Seek entry pos element list.
- uint64 seek_entry_pos_[kSeekEntryCount];
+ uint64_t seek_entry_pos_[kSeekEntryCount];
// The file position of SeekHead element.
- int64 start_pos_;
+ int64_t start_pos_;
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(SeekHead);
};
@@ -1067,12 +1253,12 @@
double duration() const { return duration_; }
void set_muxing_app(const char* app);
const char* muxing_app() const { return muxing_app_; }
- void set_timecode_scale(uint64 scale) { timecode_scale_ = scale; }
- uint64 timecode_scale() const { return timecode_scale_; }
+ void set_timecode_scale(uint64_t scale) { timecode_scale_ = scale; }
+ uint64_t timecode_scale() const { return timecode_scale_; }
void set_writing_app(const char* app);
const char* writing_app() const { return writing_app_; }
- void set_date_utc(int64 date_utc) { date_utc_ = date_utc; }
- int64 date_utc() const { return date_utc_; }
+ void set_date_utc(int64_t date_utc) { date_utc_ = date_utc; }
+ int64_t date_utc() const { return date_utc_; }
private:
// Segment Information element names.
@@ -1081,14 +1267,14 @@
double duration_;
// Set to libwebm-%d.%d.%d.%d, major, minor, build, revision.
char* muxing_app_;
- uint64 timecode_scale_;
+ uint64_t timecode_scale_;
// Initially set to libwebm-%d.%d.%d.%d, major, minor, build, revision.
char* writing_app_;
// LLONG_MIN when DateUTC is not set.
- int64 date_utc_;
+ int64_t date_utc_;
// The file position of the duration element.
- int64 duration_pos_;
+ int64_t duration_pos_;
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(SegmentInfo);
};
@@ -1108,8 +1294,8 @@
kBeforeClusters = 0x1 // Position Cues before Clusters
};
- const static uint32 kDefaultDocTypeVersion = 2;
- const static uint64 kDefaultMaxClusterDuration = 30000000000ULL;
+ const static uint32_t kDefaultDocTypeVersion = 2;
+ const static uint64_t kDefaultMaxClusterDuration = 30000000000ULL;
Segment();
~Segment();
@@ -1123,13 +1309,13 @@
// error. |number| is the number to use for the track. |number|
// must be >= 0. If |number| == 0 then the muxer will decide on the
// track number.
- Track* AddTrack(int32 number);
+ Track* AddTrack(int32_t number);
// Adds a Vorbis audio track to the segment. Returns the number of the track
// on success, 0 on error. |number| is the number to use for the audio track.
// |number| must be >= 0. If |number| == 0 then the muxer will decide on
// the track number.
- uint64 AddAudioTrack(int32 sample_rate, int32 channels, int32 number);
+ uint64_t AddAudioTrack(int32_t sample_rate, int32_t channels, int32_t number);
// Adds an empty chapter to the chapters of this segment. Returns
// non-NULL on success. After adding the chapter, the caller should
@@ -1145,7 +1331,7 @@
// nanoseconds of the cue's time. |track| is the Track of the Cue. This
// function must be called after AddFrame to calculate the correct
// BlockNumber for the CuePoint. Returns true on success.
- bool AddCuePoint(uint64 timestamp, uint64 track);
+ bool AddCuePoint(uint64_t timestamp, uint64_t track);
// Adds a frame to be output in the file. Returns true on success.
// Inputs:
@@ -1155,8 +1341,8 @@
// functions.
// timestamp: Timestamp of the frame in nanoseconds from 0.
// is_key: Flag telling whether or not this frame is a key frame.
- bool AddFrame(const uint8* data, uint64 length, uint64 track_number,
- uint64 timestamp_ns, bool is_key);
+ bool AddFrame(const uint8_t* data, uint64_t length, uint64_t track_number,
+ uint64_t timestamp_ns, bool is_key);
// Writes a frame of metadata to the output medium; returns true on
// success.
@@ -1172,8 +1358,8 @@
// The metadata frame is written as a block group, with a duration
// sub-element but no reference time sub-elements (indicating that
// it is considered a keyframe, per Matroska semantics).
- bool AddMetadata(const uint8* data, uint64 length, uint64 track_number,
- uint64 timestamp_ns, uint64 duration_ns);
+ bool AddMetadata(const uint8_t* data, uint64_t length, uint64_t track_number,
+ uint64_t timestamp_ns, uint64_t duration_ns);
// Writes a frame with additional data to the output medium; returns true on
// success.
@@ -1188,10 +1374,11 @@
// timestamp: Absolute timestamp of the frame, expressed in nanosecond
// units.
// is_key: Flag telling whether or not this frame is a key frame.
- bool AddFrameWithAdditional(const uint8* data, uint64 length,
- const uint8* additional, uint64 additional_length,
- uint64 add_id, uint64 track_number,
- uint64 timestamp, bool is_key);
+ bool AddFrameWithAdditional(const uint8_t* data, uint64_t length,
+ const uint8_t* additional,
+ uint64_t additional_length, uint64_t add_id,
+ uint64_t track_number, uint64_t timestamp,
+ bool is_key);
// Writes a frame with DiscardPadding to the output medium; returns true on
// success.
@@ -1204,9 +1391,10 @@
// timestamp: Absolute timestamp of the frame, expressed in nanosecond
// units.
// is_key: Flag telling whether or not this frame is a key frame.
- bool AddFrameWithDiscardPadding(const uint8* data, uint64 length,
- int64 discard_padding, uint64 track_number,
- uint64 timestamp, bool is_key);
+ bool AddFrameWithDiscardPadding(const uint8_t* data, uint64_t length,
+ int64_t discard_padding,
+ uint64_t track_number, uint64_t timestamp,
+ bool is_key);
// Writes a Frame to the output medium. Chooses the correct way of writing
// the frame (Block vs SimpleBlock) based on the parameters passed.
@@ -1218,7 +1406,7 @@
// success, 0 on error. |number| is the number to use for the video track.
// |number| must be >= 0. If |number| == 0 then the muxer will decide on
// the track number.
- uint64 AddVideoTrack(int32 width, int32 height, int32 number);
+ uint64_t AddVideoTrack(int32_t width, int32_t height, int32_t number);
// This function must be called after Finalize() if you need a copy of the
// output with Cues written before the Clusters. It will return false if the
@@ -1237,7 +1425,7 @@
// Sets which track to use for the Cues element. Must have added the track
// before calling this function. Returns true on success. |track_number| is
// returned by the Add track functions.
- bool CuesTrack(uint64 track_number);
+ bool CuesTrack(uint64_t track_number);
// This will force the muxer to create a new Cluster when the next frame is
// added.
@@ -1257,11 +1445,17 @@
// Search the Tracks and return the track that matches |track_number|.
// Returns NULL if there is no track match.
- Track* GetTrackByNumber(uint64 track_number) const;
+ Track* GetTrackByNumber(uint64_t track_number) const;
// Toggles whether to output a cues element.
void OutputCues(bool output_cues);
+ // Toggles whether to write the last frame in each Cluster with Duration.
+ void AccurateClusterDuration(bool accurate_cluster_duration);
+
+ // Toggles whether to write the Cluster Timecode using exactly 8 bytes.
+ void UseFixedSizeClusterTimecode(bool fixed_size_cluster_timecode);
+
// Sets if the muxer will output files in chunks or not. |chunking| is a
// flag telling whether or not to turn on chunking. |filename| is the base
// filename for the chunk files. The header chunk file will be named
@@ -1274,15 +1468,15 @@
bool SetChunking(bool chunking, const char* filename);
bool chunking() const { return chunking_; }
- uint64 cues_track() const { return cues_track_; }
- void set_max_cluster_duration(uint64 max_cluster_duration) {
+ uint64_t cues_track() const { return cues_track_; }
+ void set_max_cluster_duration(uint64_t max_cluster_duration) {
max_cluster_duration_ = max_cluster_duration;
}
- uint64 max_cluster_duration() const { return max_cluster_duration_; }
- void set_max_cluster_size(uint64 max_cluster_size) {
+ uint64_t max_cluster_duration() const { return max_cluster_duration_; }
+ void set_max_cluster_size(uint64_t max_cluster_size) {
max_cluster_size_ = max_cluster_size;
}
- uint64 max_cluster_size() const { return max_cluster_size_; }
+ uint64_t max_cluster_size() const { return max_cluster_size_; }
void set_mode(Mode mode) { mode_ = mode; }
Mode mode() const { return mode_; }
CuesPosition cues_position() const { return cues_position_; }
@@ -1306,7 +1500,7 @@
// Returns the maximum offset within the segment's payload. When chunking
// this function is needed to determine offsets of elements within the
// chunked files. Returns -1 on error.
- int64 MaxOffset();
+ int64_t MaxOffset();
// Adds the frame to our frame array.
bool QueueFrame(Frame* frame);
@@ -1318,7 +1512,7 @@
// Output all frames that are queued that have an end time that is less
// then |timestamp|. Returns true on success and if there are no frames
// queued.
- bool WriteFramesLessThan(uint64 timestamp);
+ bool WriteFramesLessThan(uint64_t timestamp);
// Outputs the segment header, Segment Information element, SeekHead element,
// and Tracks element to |writer_|.
@@ -1332,16 +1526,17 @@
// 0 = do not create a new cluster, and write frame to the existing cluster
// 1 = create a new cluster, and write frame to that new cluster
// 2 = create a new cluster, and re-run test
- int TestFrame(uint64 track_num, uint64 timestamp_ns, bool key) const;
+ int TestFrame(uint64_t track_num, uint64_t timestamp_ns, bool key) const;
// Create a new cluster, using the earlier of the first enqueued
// frame, or the indicated time. Returns true on success.
- bool MakeNewCluster(uint64 timestamp_ns);
+ bool MakeNewCluster(uint64_t timestamp_ns);
// Checks whether a new cluster needs to be created, and if so
// creates a new cluster. Returns false if creation of a new cluster
// was necessary but creation was not successful.
- bool DoNewClusterProcessing(uint64 track_num, uint64 timestamp_ns, bool key);
+ bool DoNewClusterProcessing(uint64_t track_num, uint64_t timestamp_ns,
+ bool key);
// Adjusts Cue Point values (to place Cues before Clusters) so that they
// reflect the correct offsets.
@@ -1355,7 +1550,8 @@
// accounted for.
// index - index in the list of Cues which is currently being adjusted.
// cue_size - sum of size of all the CuePoint elements.
- void MoveCuesBeforeClustersHelper(uint64 diff, int index, uint64* cue_size);
+ void MoveCuesBeforeClustersHelper(uint64_t diff, int index,
+ uint64_t* cue_size);
// Seeds the random number generator used to make UIDs.
unsigned int seed_;
@@ -1394,22 +1590,22 @@
char* chunking_base_name_;
// File position offset where the Clusters end.
- int64 cluster_end_offset_;
+ int64_t cluster_end_offset_;
// List of clusters.
Cluster** cluster_list_;
// Number of cluster pointers allocated in the cluster list.
- int32 cluster_list_capacity_;
+ int32_t cluster_list_capacity_;
// Number of clusters in the cluster list.
- int32 cluster_list_size_;
+ int32_t cluster_list_size_;
// Indicates whether Cues should be written before or after Clusters
CuesPosition cues_position_;
// Track number that is associated with the cues element for this segment.
- uint64 cues_track_;
+ uint64_t cues_track_;
// Tells the muxer to force a new cluster on the next Block.
bool force_new_cluster_;
@@ -1421,10 +1617,10 @@
Frame** frames_;
// Number of frame pointers allocated in the frame list.
- int32 frames_capacity_;
+ int32_t frames_capacity_;
// Number of frames in the frame list.
- int32 frames_size_;
+ int32_t frames_size_;
// Flag telling if a video track has been added to the segment.
bool has_video_;
@@ -1433,23 +1629,23 @@
bool header_written_;
// Duration of the last block in nanoseconds.
- uint64 last_block_duration_;
+ uint64_t last_block_duration_;
// Last timestamp in nanoseconds added to a cluster.
- uint64 last_timestamp_;
+ uint64_t last_timestamp_;
// Last timestamp in nanoseconds by track number added to a cluster.
- uint64 last_track_timestamp_[kMaxTrackNumber];
+ uint64_t last_track_timestamp_[kMaxTrackNumber];
// Maximum time in nanoseconds for a cluster duration. This variable is a
// guideline and some clusters may have a longer duration. Default is 30
// seconds.
- uint64 max_cluster_duration_;
+ uint64_t max_cluster_duration_;
// Maximum size in bytes for a cluster. This variable is a guideline and
// some clusters may have a larger size. Default is 0 which signifies that
// the muxer will decide the size.
- uint64 max_cluster_size_;
+ uint64_t max_cluster_size_;
// The mode that segment is in. If set to |kLive| the writer must not
// seek backwards.
@@ -1462,22 +1658,29 @@
// Flag whether or not the muxer should output a Cues element.
bool output_cues_;
+ // Flag whether or not the last frame in each Cluster will have a Duration
+ // element in it.
+ bool accurate_cluster_duration_;
+
+ // Flag whether or not to write the Cluster Timecode using exactly 8 bytes.
+ bool fixed_size_cluster_timecode_;
+
// The size of the EBML header, used to validate the header if
// WriteEbmlHeader() is called more than once.
- int32 ebml_header_size_;
+ int32_t ebml_header_size_;
// The file position of the segment's payload.
- int64 payload_pos_;
+ int64_t payload_pos_;
// The file position of the element's size.
- int64 size_position_;
+ int64_t size_position_;
// Current DocTypeVersion (|doc_type_version_|) and that written in
// WriteSegmentHeader().
// WriteEbmlHeader() will be called from Finalize() if |doc_type_version_|
// differs from |doc_type_version_written_|.
- uint32 doc_type_version_;
- uint32 doc_type_version_written_;
+ uint32_t doc_type_version_;
+ uint32_t doc_type_version_written_;
// Pointer to the writer objects. Not owned by this class.
IMkvWriter* writer_cluster_;
@@ -1487,6 +1690,6 @@
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Segment);
};
-} // end namespace mkvmuxer
+} // namespace mkvmuxer
-#endif // MKVMUXER_HPP
+#endif // MKVMUXER_MKVMUXER_H_
diff --git a/third_party/libwebm/mkvmuxertypes.hpp b/third_party/libwebm/mkvmuxer/mkvmuxertypes.h
similarity index 86%
rename from third_party/libwebm/mkvmuxertypes.hpp
rename to third_party/libwebm/mkvmuxer/mkvmuxertypes.h
index d0fc9fe..e5db121 100644
--- a/third_party/libwebm/mkvmuxertypes.hpp
+++ b/third_party/libwebm/mkvmuxer/mkvmuxertypes.h
@@ -6,8 +6,17 @@
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
-#ifndef MKVMUXERTYPES_HPP
-#define MKVMUXERTYPES_HPP
+#ifndef MKVMUXER_MKVMUXERTYPES_H_
+#define MKVMUXER_MKVMUXERTYPES_H_
+
+namespace mkvmuxer {
+typedef unsigned char uint8;
+typedef short int16;
+typedef int int32;
+typedef unsigned int uint32;
+typedef long long int64;
+typedef unsigned long long uint64;
+} // namespace mkvmuxer
// Copied from Chromium basictypes.h
// A macro to disallow the copy constructor and operator= functions
@@ -16,15 +25,4 @@
TypeName(const TypeName&); \
void operator=(const TypeName&)
-namespace mkvmuxer {
-
-typedef unsigned char uint8;
-typedef short int16;
-typedef int int32;
-typedef unsigned int uint32;
-typedef long long int64;
-typedef unsigned long long uint64;
-
-} // end namespace mkvmuxer
-
-#endif // MKVMUXERTYPES_HPP
+#endif // MKVMUXER_MKVMUXERTYPES_HPP_
diff --git a/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc b/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc
new file mode 100644
index 0000000..3562b8a
--- /dev/null
+++ b/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc
@@ -0,0 +1,650 @@
+// 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 "mkvmuxer/mkvmuxerutil.h"
+
+#ifdef __ANDROID__
+#include <fcntl.h>
+#endif
+
+#include <cassert>
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <new>
+
+#include "common/webmids.h"
+#include "mkvmuxer/mkvmuxer.h"
+#include "mkvmuxer/mkvwriter.h"
+
+namespace mkvmuxer {
+
+namespace {
+
+// Date elements are always 8 octets in size.
+const int kDateElementSize = 8;
+
+uint64_t WriteBlock(IMkvWriter* writer, const Frame* const frame,
+ int64_t timecode, uint64_t timecode_scale) {
+ uint64_t block_additional_elem_size = 0;
+ uint64_t block_addid_elem_size = 0;
+ uint64_t block_more_payload_size = 0;
+ uint64_t block_more_elem_size = 0;
+ uint64_t block_additions_payload_size = 0;
+ uint64_t block_additions_elem_size = 0;
+ if (frame->additional()) {
+ block_additional_elem_size =
+ EbmlElementSize(libwebm::kMkvBlockAdditional, frame->additional(),
+ frame->additional_length());
+ block_addid_elem_size =
+ EbmlElementSize(libwebm::kMkvBlockAddID, frame->add_id());
+
+ block_more_payload_size =
+ block_addid_elem_size + block_additional_elem_size;
+ block_more_elem_size =
+ EbmlMasterElementSize(libwebm::kMkvBlockMore, block_more_payload_size) +
+ block_more_payload_size;
+ block_additions_payload_size = block_more_elem_size;
+ block_additions_elem_size =
+ EbmlMasterElementSize(libwebm::kMkvBlockAdditions,
+ block_additions_payload_size) +
+ block_additions_payload_size;
+ }
+
+ uint64_t discard_padding_elem_size = 0;
+ if (frame->discard_padding() != 0) {
+ discard_padding_elem_size =
+ EbmlElementSize(libwebm::kMkvDiscardPadding, frame->discard_padding());
+ }
+
+ const uint64_t reference_block_timestamp =
+ frame->reference_block_timestamp() / timecode_scale;
+ uint64_t reference_block_elem_size = 0;
+ if (!frame->is_key()) {
+ reference_block_elem_size =
+ EbmlElementSize(libwebm::kMkvReferenceBlock, reference_block_timestamp);
+ }
+
+ const uint64_t duration = frame->duration() / timecode_scale;
+ uint64_t block_duration_elem_size = 0;
+ if (duration > 0)
+ block_duration_elem_size =
+ EbmlElementSize(libwebm::kMkvBlockDuration, duration);
+
+ const uint64_t block_payload_size = 4 + frame->length();
+ const uint64_t block_elem_size =
+ EbmlMasterElementSize(libwebm::kMkvBlock, block_payload_size) +
+ block_payload_size;
+
+ const uint64_t block_group_payload_size =
+ block_elem_size + block_additions_elem_size + block_duration_elem_size +
+ discard_padding_elem_size + reference_block_elem_size;
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlockGroup,
+ block_group_payload_size)) {
+ return 0;
+ }
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlock, block_payload_size))
+ return 0;
+
+ if (WriteUInt(writer, frame->track_number()))
+ return 0;
+
+ if (SerializeInt(writer, timecode, 2))
+ return 0;
+
+ // For a Block, flags is always 0.
+ if (SerializeInt(writer, 0, 1))
+ return 0;
+
+ if (writer->Write(frame->frame(), static_cast<uint32_t>(frame->length())))
+ return 0;
+
+ if (frame->additional()) {
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlockAdditions,
+ block_additions_payload_size)) {
+ return 0;
+ }
+
+ if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlockMore,
+ block_more_payload_size))
+ return 0;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvBlockAddID, frame->add_id()))
+ return 0;
+
+ if (!WriteEbmlElement(writer, libwebm::kMkvBlockAdditional,
+ frame->additional(), frame->additional_length())) {
+ return 0;
+ }
+ }
+
+ if (frame->discard_padding() != 0 &&
+ !WriteEbmlElement(writer, libwebm::kMkvDiscardPadding,
+ frame->discard_padding())) {
+ return false;
+ }
+
+ if (!frame->is_key() &&
+ !WriteEbmlElement(writer, libwebm::kMkvReferenceBlock,
+ reference_block_timestamp)) {
+ return false;
+ }
+
+ if (duration > 0 &&
+ !WriteEbmlElement(writer, libwebm::kMkvBlockDuration, duration)) {
+ return false;
+ }
+ return EbmlMasterElementSize(libwebm::kMkvBlockGroup,
+ block_group_payload_size) +
+ block_group_payload_size;
+}
+
+uint64_t WriteSimpleBlock(IMkvWriter* writer, const Frame* const frame,
+ int64_t timecode) {
+ if (WriteID(writer, libwebm::kMkvSimpleBlock))
+ return 0;
+
+ const int32_t size = static_cast<int32_t>(frame->length()) + 4;
+ if (WriteUInt(writer, size))
+ return 0;
+
+ if (WriteUInt(writer, static_cast<uint64_t>(frame->track_number())))
+ return 0;
+
+ if (SerializeInt(writer, timecode, 2))
+ return 0;
+
+ uint64_t flags = 0;
+ if (frame->is_key())
+ flags |= 0x80;
+
+ if (SerializeInt(writer, flags, 1))
+ return 0;
+
+ if (writer->Write(frame->frame(), static_cast<uint32_t>(frame->length())))
+ return 0;
+
+ return static_cast<uint64_t>(GetUIntSize(libwebm::kMkvSimpleBlock) +
+ GetCodedUIntSize(size) + 4 + frame->length());
+}
+
+} // namespace
+
+int32_t GetCodedUIntSize(uint64_t value) {
+ if (value < 0x000000000000007FULL)
+ return 1;
+ else if (value < 0x0000000000003FFFULL)
+ return 2;
+ else if (value < 0x00000000001FFFFFULL)
+ return 3;
+ else if (value < 0x000000000FFFFFFFULL)
+ return 4;
+ else if (value < 0x00000007FFFFFFFFULL)
+ return 5;
+ else if (value < 0x000003FFFFFFFFFFULL)
+ return 6;
+ else if (value < 0x0001FFFFFFFFFFFFULL)
+ return 7;
+ return 8;
+}
+
+int32_t GetUIntSize(uint64_t value) {
+ if (value < 0x0000000000000100ULL)
+ return 1;
+ else if (value < 0x0000000000010000ULL)
+ return 2;
+ else if (value < 0x0000000001000000ULL)
+ return 3;
+ else if (value < 0x0000000100000000ULL)
+ return 4;
+ else if (value < 0x0000010000000000ULL)
+ return 5;
+ else if (value < 0x0001000000000000ULL)
+ return 6;
+ else if (value < 0x0100000000000000ULL)
+ return 7;
+ return 8;
+}
+
+int32_t GetIntSize(int64_t value) {
+ // Doubling the requested value ensures positive values with their high bit
+ // set are written with 0-padding to avoid flipping the signedness.
+ const uint64_t v = (value < 0) ? value ^ -1LL : value;
+ return GetUIntSize(2 * v);
+}
+
+uint64_t EbmlMasterElementSize(uint64_t type, uint64_t value) {
+ // Size of EBML ID
+ int32_t ebml_size = GetUIntSize(type);
+
+ // Datasize
+ ebml_size += GetCodedUIntSize(value);
+
+ return static_cast<uint64_t>(ebml_size);
+}
+
+uint64_t EbmlElementSize(uint64_t type, int64_t value) {
+ // Size of EBML ID
+ int32_t ebml_size = GetUIntSize(type);
+
+ // Datasize
+ ebml_size += GetIntSize(value);
+
+ // Size of Datasize
+ ebml_size++;
+
+ return static_cast<uint64_t>(ebml_size);
+}
+
+uint64_t EbmlElementSize(uint64_t type, uint64_t value) {
+ return EbmlElementSize(type, value, 0);
+}
+
+uint64_t EbmlElementSize(uint64_t type, uint64_t value, uint64_t fixed_size) {
+ // Size of EBML ID
+ uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
+
+ // Datasize
+ ebml_size +=
+ (fixed_size > 0) ? fixed_size : static_cast<uint64_t>(GetUIntSize(value));
+
+ // Size of Datasize
+ ebml_size++;
+
+ return ebml_size;
+}
+
+uint64_t EbmlElementSize(uint64_t type, float /* value */) {
+ // Size of EBML ID
+ uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
+
+ // Datasize
+ ebml_size += sizeof(float);
+
+ // Size of Datasize
+ ebml_size++;
+
+ return ebml_size;
+}
+
+uint64_t EbmlElementSize(uint64_t type, const char* value) {
+ if (!value)
+ return 0;
+
+ // Size of EBML ID
+ uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
+
+ // Datasize
+ ebml_size += strlen(value);
+
+ // Size of Datasize
+ ebml_size++;
+
+ return ebml_size;
+}
+
+uint64_t EbmlElementSize(uint64_t type, const uint8_t* value, uint64_t size) {
+ if (!value)
+ return 0;
+
+ // Size of EBML ID
+ uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
+
+ // Datasize
+ ebml_size += size;
+
+ // Size of Datasize
+ ebml_size += GetCodedUIntSize(size);
+
+ return ebml_size;
+}
+
+uint64_t EbmlDateElementSize(uint64_t type) {
+ // Size of EBML ID
+ uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
+
+ // Datasize
+ ebml_size += kDateElementSize;
+
+ // Size of Datasize
+ ebml_size++;
+
+ return ebml_size;
+}
+
+int32_t SerializeInt(IMkvWriter* writer, int64_t value, int32_t size) {
+ if (!writer || size < 1 || size > 8)
+ return -1;
+
+ for (int32_t i = 1; i <= size; ++i) {
+ const int32_t byte_count = size - i;
+ const int32_t bit_count = byte_count * 8;
+
+ const int64_t bb = value >> bit_count;
+ const uint8_t b = static_cast<uint8_t>(bb);
+
+ const int32_t status = writer->Write(&b, 1);
+
+ if (status < 0)
+ return status;
+ }
+
+ return 0;
+}
+
+int32_t SerializeFloat(IMkvWriter* writer, float f) {
+ if (!writer)
+ return -1;
+
+ assert(sizeof(uint32_t) == sizeof(float));
+ // This union is merely used to avoid a reinterpret_cast from float& to
+ // uint32& which will result in violation of strict aliasing.
+ union U32 {
+ uint32_t u32;
+ float f;
+ } value;
+ value.f = f;
+
+ for (int32_t i = 1; i <= 4; ++i) {
+ const int32_t byte_count = 4 - i;
+ const int32_t bit_count = byte_count * 8;
+
+ const uint8_t byte = static_cast<uint8_t>(value.u32 >> bit_count);
+
+ const int32_t status = writer->Write(&byte, 1);
+
+ if (status < 0)
+ return status;
+ }
+
+ return 0;
+}
+
+int32_t WriteUInt(IMkvWriter* writer, uint64_t value) {
+ if (!writer)
+ return -1;
+
+ int32_t size = GetCodedUIntSize(value);
+
+ return WriteUIntSize(writer, value, size);
+}
+
+int32_t WriteUIntSize(IMkvWriter* writer, uint64_t value, int32_t size) {
+ if (!writer || size < 0 || size > 8)
+ return -1;
+
+ if (size > 0) {
+ const uint64_t bit = 1LL << (size * 7);
+
+ if (value > (bit - 2))
+ return -1;
+
+ value |= bit;
+ } else {
+ size = 1;
+ int64_t bit;
+
+ for (;;) {
+ bit = 1LL << (size * 7);
+ const uint64_t max = bit - 2;
+
+ if (value <= max)
+ break;
+
+ ++size;
+ }
+
+ if (size > 8)
+ return false;
+
+ value |= bit;
+ }
+
+ return SerializeInt(writer, value, size);
+}
+
+int32_t WriteID(IMkvWriter* writer, uint64_t type) {
+ if (!writer)
+ return -1;
+
+ writer->ElementStartNotify(type, writer->Position());
+
+ const int32_t size = GetUIntSize(type);
+
+ return SerializeInt(writer, type, size);
+}
+
+bool WriteEbmlMasterElement(IMkvWriter* writer, uint64_t type, uint64_t size) {
+ if (!writer)
+ return false;
+
+ if (WriteID(writer, type))
+ return false;
+
+ if (WriteUInt(writer, size))
+ return false;
+
+ return true;
+}
+
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value) {
+ return WriteEbmlElement(writer, type, value, 0);
+}
+
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value,
+ uint64_t fixed_size) {
+ if (!writer)
+ return false;
+
+ if (WriteID(writer, type))
+ return false;
+
+ uint64_t size = static_cast<uint64_t>(GetUIntSize(value));
+ if (fixed_size > 0) {
+ if (size > fixed_size)
+ return false;
+ size = fixed_size;
+ }
+ if (WriteUInt(writer, size))
+ return false;
+
+ if (SerializeInt(writer, value, static_cast<int32_t>(size)))
+ return false;
+
+ return true;
+}
+
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, int64_t value) {
+ if (!writer)
+ return false;
+
+ if (WriteID(writer, type))
+ return 0;
+
+ const uint64_t size = GetIntSize(value);
+ if (WriteUInt(writer, size))
+ return false;
+
+ if (SerializeInt(writer, value, static_cast<int32_t>(size)))
+ return false;
+
+ return true;
+}
+
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, float value) {
+ if (!writer)
+ return false;
+
+ if (WriteID(writer, type))
+ return false;
+
+ if (WriteUInt(writer, 4))
+ return false;
+
+ if (SerializeFloat(writer, value))
+ return false;
+
+ return true;
+}
+
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const char* value) {
+ if (!writer || !value)
+ return false;
+
+ if (WriteID(writer, type))
+ return false;
+
+ const uint64_t length = strlen(value);
+ if (WriteUInt(writer, length))
+ return false;
+
+ if (writer->Write(value, static_cast<const uint32_t>(length)))
+ return false;
+
+ return true;
+}
+
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const uint8_t* value,
+ uint64_t size) {
+ if (!writer || !value || size < 1)
+ return false;
+
+ if (WriteID(writer, type))
+ return false;
+
+ if (WriteUInt(writer, size))
+ return false;
+
+ if (writer->Write(value, static_cast<uint32_t>(size)))
+ return false;
+
+ return true;
+}
+
+bool WriteEbmlDateElement(IMkvWriter* writer, uint64_t type, int64_t value) {
+ if (!writer)
+ return false;
+
+ if (WriteID(writer, type))
+ return false;
+
+ if (WriteUInt(writer, kDateElementSize))
+ return false;
+
+ if (SerializeInt(writer, value, kDateElementSize))
+ return false;
+
+ return true;
+}
+
+uint64_t WriteFrame(IMkvWriter* writer, const Frame* const frame,
+ Cluster* cluster) {
+ if (!writer || !frame || !frame->IsValid() || !cluster ||
+ !cluster->timecode_scale())
+ return 0;
+
+ // Technically the timecode for a block can be less than the
+ // timecode for the cluster itself (remember that block timecode
+ // is a signed, 16-bit integer). However, as a simplification we
+ // only permit non-negative cluster-relative timecodes for blocks.
+ const int64_t relative_timecode = cluster->GetRelativeTimecode(
+ frame->timestamp() / cluster->timecode_scale());
+ if (relative_timecode < 0 || relative_timecode > kMaxBlockTimecode)
+ return 0;
+
+ return frame->CanBeSimpleBlock() ?
+ WriteSimpleBlock(writer, frame, relative_timecode) :
+ WriteBlock(writer, frame, relative_timecode,
+ cluster->timecode_scale());
+}
+
+uint64_t WriteVoidElement(IMkvWriter* writer, uint64_t size) {
+ if (!writer)
+ return false;
+
+ // Subtract one for the void ID and the coded size.
+ uint64_t void_entry_size = size - 1 - GetCodedUIntSize(size - 1);
+ uint64_t void_size =
+ EbmlMasterElementSize(libwebm::kMkvVoid, void_entry_size) +
+ void_entry_size;
+
+ if (void_size != size)
+ return 0;
+
+ const int64_t payload_position = writer->Position();
+ if (payload_position < 0)
+ return 0;
+
+ if (WriteID(writer, libwebm::kMkvVoid))
+ return 0;
+
+ if (WriteUInt(writer, void_entry_size))
+ return 0;
+
+ const uint8_t value = 0;
+ for (int32_t i = 0; i < static_cast<int32_t>(void_entry_size); ++i) {
+ if (writer->Write(&value, 1))
+ return 0;
+ }
+
+ const int64_t stop_position = writer->Position();
+ if (stop_position < 0 ||
+ stop_position - payload_position != static_cast<int64_t>(void_size))
+ return 0;
+
+ return void_size;
+}
+
+void GetVersion(int32_t* major, int32_t* minor, int32_t* build,
+ int32_t* revision) {
+ *major = 0;
+ *minor = 2;
+ *build = 1;
+ *revision = 0;
+}
+
+uint64_t MakeUID(unsigned int* seed) {
+ uint64_t uid = 0;
+
+#ifdef __MINGW32__
+ srand(*seed);
+#endif
+
+ for (int i = 0; i < 7; ++i) { // avoid problems with 8-byte values
+ uid <<= 8;
+
+// TODO(fgalligan): Move random number generation to platform specific code.
+#ifdef _MSC_VER
+ (void)seed;
+ const int32_t nn = rand();
+#elif __ANDROID__
+ int32_t temp_num = 1;
+ int fd = open("/dev/urandom", O_RDONLY);
+ if (fd != -1) {
+ read(fd, &temp_num, sizeof(temp_num));
+ close(fd);
+ }
+ const int32_t nn = temp_num;
+#elif defined __MINGW32__
+ const int32_t nn = rand();
+#else
+ const int32_t nn = rand_r(seed);
+#endif
+ const int32_t n = 0xFF & (nn >> 4); // throw away low-order bits
+
+ uid |= n;
+ }
+
+ return uid;
+}
+
+} // namespace mkvmuxer
diff --git a/third_party/libwebm/mkvmuxer/mkvmuxerutil.h b/third_party/libwebm/mkvmuxer/mkvmuxerutil.h
new file mode 100644
index 0000000..0e21a2d
--- /dev/null
+++ b/third_party/libwebm/mkvmuxer/mkvmuxerutil.h
@@ -0,0 +1,95 @@
+// 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 MKVMUXER_MKVMUXERUTIL_H_
+#define MKVMUXER_MKVMUXERUTIL_H_
+
+#include <stdint.h>
+
+namespace mkvmuxer {
+class Cluster;
+class Frame;
+class IMkvWriter;
+
+const uint64_t kEbmlUnknownValue = 0x01FFFFFFFFFFFFFFULL;
+const int64_t kMaxBlockTimecode = 0x07FFFLL;
+
+// Writes out |value| in Big Endian order. Returns 0 on success.
+int32_t SerializeInt(IMkvWriter* writer, int64_t value, int32_t size);
+
+// Returns the size in bytes of the element.
+int32_t GetUIntSize(uint64_t value);
+int32_t GetIntSize(int64_t value);
+int32_t GetCodedUIntSize(uint64_t value);
+uint64_t EbmlMasterElementSize(uint64_t type, uint64_t value);
+uint64_t EbmlElementSize(uint64_t type, int64_t value);
+uint64_t EbmlElementSize(uint64_t type, uint64_t value);
+uint64_t EbmlElementSize(uint64_t type, float value);
+uint64_t EbmlElementSize(uint64_t type, const char* value);
+uint64_t EbmlElementSize(uint64_t type, const uint8_t* value, uint64_t size);
+uint64_t EbmlDateElementSize(uint64_t type);
+
+// Returns the size in bytes of the element assuming that the element was
+// written using |fixed_size| bytes. If |fixed_size| is set to zero, then it
+// computes the necessary number of bytes based on |value|.
+uint64_t EbmlElementSize(uint64_t type, uint64_t value, uint64_t fixed_size);
+
+// Creates an EBML coded number from |value| and writes it out. The size of
+// the coded number is determined by the value of |value|. |value| must not
+// be in a coded form. Returns 0 on success.
+int32_t WriteUInt(IMkvWriter* writer, uint64_t value);
+
+// Creates an EBML coded number from |value| and writes it out. The size of
+// the coded number is determined by the value of |size|. |value| must not
+// be in a coded form. Returns 0 on success.
+int32_t WriteUIntSize(IMkvWriter* writer, uint64_t value, int32_t size);
+
+// Output an Mkv master element. Returns true if the element was written.
+bool WriteEbmlMasterElement(IMkvWriter* writer, uint64_t value, uint64_t size);
+
+// Outputs an Mkv ID, calls |IMkvWriter::ElementStartNotify|, and passes the
+// ID to |SerializeInt|. Returns 0 on success.
+int32_t WriteID(IMkvWriter* writer, uint64_t type);
+
+// Output an Mkv non-master element. Returns true if the element was written.
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value);
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, int64_t value);
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, float value);
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const char* value);
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const uint8_t* value,
+ uint64_t size);
+bool WriteEbmlDateElement(IMkvWriter* writer, uint64_t type, int64_t value);
+
+// Output an Mkv non-master element using fixed size. The element will be
+// written out using exactly |fixed_size| bytes. If |fixed_size| is set to zero
+// then it computes the necessary number of bytes based on |value|. Returns true
+// if the element was written.
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value,
+ uint64_t fixed_size);
+
+// Output a Mkv Frame. It decides the correct element to write (Block vs
+// SimpleBlock) based on the parameters of the Frame.
+uint64_t WriteFrame(IMkvWriter* writer, const Frame* const frame,
+ Cluster* cluster);
+
+// Output a void element. |size| must be the entire size in bytes that will be
+// void. The function will calculate the size of the void header and subtract
+// it from |size|.
+uint64_t WriteVoidElement(IMkvWriter* writer, uint64_t size);
+
+// Returns the version number of the muxer in |major|, |minor|, |build|,
+// and |revision|.
+void GetVersion(int32_t* major, int32_t* minor, int32_t* build,
+ int32_t* revision);
+
+// Returns a random number to be used for UID, using |seed| to seed
+// the random-number generator (see POSIX rand_r() for semantics).
+uint64_t MakeUID(unsigned int* seed);
+
+} // namespace mkvmuxer
+
+#endif // MKVMUXER_MKVMUXERUTIL_H_
diff --git a/third_party/libwebm/mkvwriter.cpp b/third_party/libwebm/mkvmuxer/mkvwriter.cc
similarity index 96%
rename from third_party/libwebm/mkvwriter.cpp
rename to third_party/libwebm/mkvmuxer/mkvwriter.cc
index 75d4350..ca48e14 100644
--- a/third_party/libwebm/mkvwriter.cpp
+++ b/third_party/libwebm/mkvmuxer/mkvwriter.cc
@@ -6,14 +6,12 @@
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
-#include "mkvwriter.hpp"
+#include "mkvmuxer/mkvwriter.h"
#ifdef _MSC_VER
#include <share.h> // for _SH_DENYWR
#endif
-#include <new>
-
namespace mkvmuxer {
MkvWriter::MkvWriter() : file_(NULL), writer_owns_file_(true) {}
diff --git a/third_party/libwebm/mkvwriter.hpp b/third_party/libwebm/mkvmuxer/mkvwriter.h
similarity index 86%
rename from third_party/libwebm/mkvwriter.hpp
rename to third_party/libwebm/mkvmuxer/mkvwriter.h
index 684560c..4227c63 100644
--- a/third_party/libwebm/mkvwriter.hpp
+++ b/third_party/libwebm/mkvmuxer/mkvwriter.h
@@ -6,13 +6,13 @@
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
-#ifndef MKVWRITER_HPP
-#define MKVWRITER_HPP
+#ifndef MKVMUXER_MKVWRITER_H_
+#define MKVMUXER_MKVWRITER_H_
#include <stdio.h>
-#include "mkvmuxer.hpp"
-#include "mkvmuxertypes.hpp"
+#include "mkvmuxer/mkvmuxer.h"
+#include "mkvmuxer/mkvmuxertypes.h"
namespace mkvmuxer {
@@ -46,6 +46,6 @@
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(MkvWriter);
};
-} // end namespace mkvmuxer
+} // namespace mkvmuxer
-#endif // MKVWRITER_HPP
+#endif // MKVMUXER_MKVWRITER_H_
diff --git a/third_party/libwebm/mkvmuxerutil.cpp b/third_party/libwebm/mkvmuxerutil.cpp
deleted file mode 100644
index 27ab15d..0000000
--- a/third_party/libwebm/mkvmuxerutil.cpp
+++ /dev/null
@@ -1,629 +0,0 @@
-// 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 "mkvmuxerutil.hpp"
-
-#ifdef __ANDROID__
-#include <fcntl.h>
-#endif
-
-#include <cassert>
-#include <cmath>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <ctime>
-#include <new>
-
-#include "mkvwriter.hpp"
-#include "webmids.hpp"
-
-#ifdef _MSC_VER
-// Disable MSVC warnings that suggest making code non-portable.
-#pragma warning(disable : 4996)
-#endif
-
-namespace mkvmuxer {
-
-namespace {
-
-// Date elements are always 8 octets in size.
-const int kDateElementSize = 8;
-
-uint64 WriteBlock(IMkvWriter* writer, const Frame* const frame, int64 timecode,
- uint64 timecode_scale) {
- uint64 block_additional_elem_size = 0;
- uint64 block_addid_elem_size = 0;
- uint64 block_more_payload_size = 0;
- uint64 block_more_elem_size = 0;
- uint64 block_additions_payload_size = 0;
- uint64 block_additions_elem_size = 0;
- if (frame->additional()) {
- block_additional_elem_size = EbmlElementSize(
- kMkvBlockAdditional, frame->additional(), frame->additional_length());
- block_addid_elem_size = EbmlElementSize(kMkvBlockAddID, frame->add_id());
-
- block_more_payload_size =
- block_addid_elem_size + block_additional_elem_size;
- block_more_elem_size =
- EbmlMasterElementSize(kMkvBlockMore, block_more_payload_size) +
- block_more_payload_size;
- block_additions_payload_size = block_more_elem_size;
- block_additions_elem_size =
- EbmlMasterElementSize(kMkvBlockAdditions,
- block_additions_payload_size) +
- block_additions_payload_size;
- }
-
- uint64 discard_padding_elem_size = 0;
- if (frame->discard_padding() != 0) {
- discard_padding_elem_size =
- EbmlElementSize(kMkvDiscardPadding, frame->discard_padding());
- }
-
- const uint64 reference_block_timestamp =
- frame->reference_block_timestamp() / timecode_scale;
- uint64 reference_block_elem_size = 0;
- if (!frame->is_key()) {
- reference_block_elem_size =
- EbmlElementSize(kMkvReferenceBlock, reference_block_timestamp);
- }
-
- const uint64 duration = frame->duration() / timecode_scale;
- uint64 block_duration_elem_size = 0;
- if (duration > 0)
- block_duration_elem_size = EbmlElementSize(kMkvBlockDuration, duration);
-
- const uint64 block_payload_size = 4 + frame->length();
- const uint64 block_elem_size =
- EbmlMasterElementSize(kMkvBlock, block_payload_size) + block_payload_size;
-
- const uint64 block_group_payload_size =
- block_elem_size + block_additions_elem_size + block_duration_elem_size +
- discard_padding_elem_size + reference_block_elem_size;
-
- if (!WriteEbmlMasterElement(writer, kMkvBlockGroup,
- block_group_payload_size)) {
- return 0;
- }
-
- if (!WriteEbmlMasterElement(writer, kMkvBlock, block_payload_size))
- return 0;
-
- if (WriteUInt(writer, frame->track_number()))
- return 0;
-
- if (SerializeInt(writer, timecode, 2))
- return 0;
-
- // For a Block, flags is always 0.
- if (SerializeInt(writer, 0, 1))
- return 0;
-
- if (writer->Write(frame->frame(), static_cast<uint32>(frame->length())))
- return 0;
-
- if (frame->additional()) {
- if (!WriteEbmlMasterElement(writer, kMkvBlockAdditions,
- block_additions_payload_size)) {
- return 0;
- }
-
- if (!WriteEbmlMasterElement(writer, kMkvBlockMore, block_more_payload_size))
- return 0;
-
- if (!WriteEbmlElement(writer, kMkvBlockAddID, frame->add_id()))
- return 0;
-
- if (!WriteEbmlElement(writer, kMkvBlockAdditional, frame->additional(),
- frame->additional_length())) {
- return 0;
- }
- }
-
- if (frame->discard_padding() != 0 &&
- !WriteEbmlElement(writer, kMkvDiscardPadding, frame->discard_padding())) {
- return false;
- }
-
- if (!frame->is_key() &&
- !WriteEbmlElement(writer, kMkvReferenceBlock,
- reference_block_timestamp)) {
- return false;
- }
-
- if (duration > 0 && !WriteEbmlElement(writer, kMkvBlockDuration, duration)) {
- return false;
- }
- return EbmlMasterElementSize(kMkvBlockGroup, block_group_payload_size) +
- block_group_payload_size;
-}
-
-uint64 WriteSimpleBlock(IMkvWriter* writer, const Frame* const frame,
- int64 timecode) {
- if (WriteID(writer, kMkvSimpleBlock))
- return 0;
-
- const int32 size = static_cast<int32>(frame->length()) + 4;
- if (WriteUInt(writer, size))
- return 0;
-
- if (WriteUInt(writer, static_cast<uint64>(frame->track_number())))
- return 0;
-
- if (SerializeInt(writer, timecode, 2))
- return 0;
-
- uint64 flags = 0;
- if (frame->is_key())
- flags |= 0x80;
-
- if (SerializeInt(writer, flags, 1))
- return 0;
-
- if (writer->Write(frame->frame(), static_cast<uint32>(frame->length())))
- return 0;
-
- return GetUIntSize(kMkvSimpleBlock) + GetCodedUIntSize(size) + 4 +
- frame->length();
-}
-
-} // namespace
-
-int32 GetCodedUIntSize(uint64 value) {
- if (value < 0x000000000000007FULL)
- return 1;
- else if (value < 0x0000000000003FFFULL)
- return 2;
- else if (value < 0x00000000001FFFFFULL)
- return 3;
- else if (value < 0x000000000FFFFFFFULL)
- return 4;
- else if (value < 0x00000007FFFFFFFFULL)
- return 5;
- else if (value < 0x000003FFFFFFFFFFULL)
- return 6;
- else if (value < 0x0001FFFFFFFFFFFFULL)
- return 7;
- return 8;
-}
-
-int32 GetUIntSize(uint64 value) {
- if (value < 0x0000000000000100ULL)
- return 1;
- else if (value < 0x0000000000010000ULL)
- return 2;
- else if (value < 0x0000000001000000ULL)
- return 3;
- else if (value < 0x0000000100000000ULL)
- return 4;
- else if (value < 0x0000010000000000ULL)
- return 5;
- else if (value < 0x0001000000000000ULL)
- return 6;
- else if (value < 0x0100000000000000ULL)
- return 7;
- return 8;
-}
-
-int32 GetIntSize(int64 value) {
- // Doubling the requested value ensures positive values with their high bit
- // set are written with 0-padding to avoid flipping the signedness.
- const uint64 v = (value < 0) ? value ^ -1LL : value;
- return GetUIntSize(2 * v);
-}
-
-uint64 EbmlMasterElementSize(uint64 type, uint64 value) {
- // Size of EBML ID
- int32 ebml_size = GetUIntSize(type);
-
- // Datasize
- ebml_size += GetCodedUIntSize(value);
-
- return ebml_size;
-}
-
-uint64 EbmlElementSize(uint64 type, int64 value) {
- // Size of EBML ID
- int32 ebml_size = GetUIntSize(type);
-
- // Datasize
- ebml_size += GetIntSize(value);
-
- // Size of Datasize
- ebml_size++;
-
- return ebml_size;
-}
-
-uint64 EbmlElementSize(uint64 type, uint64 value) {
- // Size of EBML ID
- int32 ebml_size = GetUIntSize(type);
-
- // Datasize
- ebml_size += GetUIntSize(value);
-
- // Size of Datasize
- ebml_size++;
-
- return ebml_size;
-}
-
-uint64 EbmlElementSize(uint64 type, float /* value */) {
- // Size of EBML ID
- uint64 ebml_size = GetUIntSize(type);
-
- // Datasize
- ebml_size += sizeof(float);
-
- // Size of Datasize
- ebml_size++;
-
- return ebml_size;
-}
-
-uint64 EbmlElementSize(uint64 type, const char* value) {
- if (!value)
- return 0;
-
- // Size of EBML ID
- uint64 ebml_size = GetUIntSize(type);
-
- // Datasize
- ebml_size += strlen(value);
-
- // Size of Datasize
- ebml_size++;
-
- return ebml_size;
-}
-
-uint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size) {
- if (!value)
- return 0;
-
- // Size of EBML ID
- uint64 ebml_size = GetUIntSize(type);
-
- // Datasize
- ebml_size += size;
-
- // Size of Datasize
- ebml_size += GetCodedUIntSize(size);
-
- return ebml_size;
-}
-
-uint64 EbmlDateElementSize(uint64 type) {
- // Size of EBML ID
- uint64 ebml_size = GetUIntSize(type);
-
- // Datasize
- ebml_size += kDateElementSize;
-
- // Size of Datasize
- ebml_size++;
-
- return ebml_size;
-}
-
-int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size) {
- if (!writer || size < 1 || size > 8)
- return -1;
-
- for (int32 i = 1; i <= size; ++i) {
- const int32 byte_count = size - i;
- const int32 bit_count = byte_count * 8;
-
- const int64 bb = value >> bit_count;
- const uint8 b = static_cast<uint8>(bb);
-
- const int32 status = writer->Write(&b, 1);
-
- if (status < 0)
- return status;
- }
-
- return 0;
-}
-
-int32 SerializeFloat(IMkvWriter* writer, float f) {
- if (!writer)
- return -1;
-
- assert(sizeof(uint32) == sizeof(float));
- // This union is merely used to avoid a reinterpret_cast from float& to
- // uint32& which will result in violation of strict aliasing.
- union U32 {
- uint32 u32;
- float f;
- } value;
- value.f = f;
-
- for (int32 i = 1; i <= 4; ++i) {
- const int32 byte_count = 4 - i;
- const int32 bit_count = byte_count * 8;
-
- const uint8 byte = static_cast<uint8>(value.u32 >> bit_count);
-
- const int32 status = writer->Write(&byte, 1);
-
- if (status < 0)
- return status;
- }
-
- return 0;
-}
-
-int32 WriteUInt(IMkvWriter* writer, uint64 value) {
- if (!writer)
- return -1;
-
- int32 size = GetCodedUIntSize(value);
-
- return WriteUIntSize(writer, value, size);
-}
-
-int32 WriteUIntSize(IMkvWriter* writer, uint64 value, int32 size) {
- if (!writer || size < 0 || size > 8)
- return -1;
-
- if (size > 0) {
- const uint64 bit = 1LL << (size * 7);
-
- if (value > (bit - 2))
- return -1;
-
- value |= bit;
- } else {
- size = 1;
- int64 bit;
-
- for (;;) {
- bit = 1LL << (size * 7);
- const uint64 max = bit - 2;
-
- if (value <= max)
- break;
-
- ++size;
- }
-
- if (size > 8)
- return false;
-
- value |= bit;
- }
-
- return SerializeInt(writer, value, size);
-}
-
-int32 WriteID(IMkvWriter* writer, uint64 type) {
- if (!writer)
- return -1;
-
- writer->ElementStartNotify(type, writer->Position());
-
- const int32 size = GetUIntSize(type);
-
- return SerializeInt(writer, type, size);
-}
-
-bool WriteEbmlMasterElement(IMkvWriter* writer, uint64 type, uint64 size) {
- if (!writer)
- return false;
-
- if (WriteID(writer, type))
- return false;
-
- if (WriteUInt(writer, size))
- return false;
-
- return true;
-}
-
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value) {
- if (!writer)
- return false;
-
- if (WriteID(writer, type))
- return false;
-
- const uint64 size = GetUIntSize(value);
- if (WriteUInt(writer, size))
- return false;
-
- if (SerializeInt(writer, value, static_cast<int32>(size)))
- return false;
-
- return true;
-}
-
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, int64 value) {
- if (!writer)
- return false;
-
- if (WriteID(writer, type))
- return 0;
-
- const uint64 size = GetIntSize(value);
- if (WriteUInt(writer, size))
- return false;
-
- if (SerializeInt(writer, value, static_cast<int32>(size)))
- return false;
-
- return true;
-}
-
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, float value) {
- if (!writer)
- return false;
-
- if (WriteID(writer, type))
- return false;
-
- if (WriteUInt(writer, 4))
- return false;
-
- if (SerializeFloat(writer, value))
- return false;
-
- return true;
-}
-
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const char* value) {
- if (!writer || !value)
- return false;
-
- if (WriteID(writer, type))
- return false;
-
- const uint64 length = strlen(value);
- if (WriteUInt(writer, length))
- return false;
-
- if (writer->Write(value, static_cast<const uint32>(length)))
- return false;
-
- return true;
-}
-
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const uint8* value,
- uint64 size) {
- if (!writer || !value || size < 1)
- return false;
-
- if (WriteID(writer, type))
- return false;
-
- if (WriteUInt(writer, size))
- return false;
-
- if (writer->Write(value, static_cast<uint32>(size)))
- return false;
-
- return true;
-}
-
-bool WriteEbmlDateElement(IMkvWriter* writer, uint64 type, int64 value) {
- if (!writer)
- return false;
-
- if (WriteID(writer, type))
- return false;
-
- if (WriteUInt(writer, kDateElementSize))
- return false;
-
- if (SerializeInt(writer, value, kDateElementSize))
- return false;
-
- return true;
-}
-
-uint64 WriteFrame(IMkvWriter* writer, const Frame* const frame,
- Cluster* cluster) {
- if (!writer || !frame || !frame->IsValid() || !cluster ||
- !cluster->timecode_scale())
- return 0;
-
- // Technically the timecode for a block can be less than the
- // timecode for the cluster itself (remember that block timecode
- // is a signed, 16-bit integer). However, as a simplification we
- // only permit non-negative cluster-relative timecodes for blocks.
- const int64 relative_timecode = cluster->GetRelativeTimecode(
- frame->timestamp() / cluster->timecode_scale());
- if (relative_timecode < 0 || relative_timecode > kMaxBlockTimecode)
- return 0;
-
- return frame->CanBeSimpleBlock() ?
- WriteSimpleBlock(writer, frame, relative_timecode) :
- WriteBlock(writer, frame, relative_timecode,
- cluster->timecode_scale());
-}
-
-uint64 WriteVoidElement(IMkvWriter* writer, uint64 size) {
- if (!writer)
- return false;
-
- // Subtract one for the void ID and the coded size.
- uint64 void_entry_size = size - 1 - GetCodedUIntSize(size - 1);
- uint64 void_size =
- EbmlMasterElementSize(kMkvVoid, void_entry_size) + void_entry_size;
-
- if (void_size != size)
- return 0;
-
- const int64 payload_position = writer->Position();
- if (payload_position < 0)
- return 0;
-
- if (WriteID(writer, kMkvVoid))
- return 0;
-
- if (WriteUInt(writer, void_entry_size))
- return 0;
-
- const uint8 value = 0;
- for (int32 i = 0; i < static_cast<int32>(void_entry_size); ++i) {
- if (writer->Write(&value, 1))
- return 0;
- }
-
- const int64 stop_position = writer->Position();
- if (stop_position < 0 ||
- stop_position - payload_position != static_cast<int64>(void_size))
- return 0;
-
- return void_size;
-}
-
-void GetVersion(int32* major, int32* minor, int32* build, int32* revision) {
- *major = 0;
- *minor = 2;
- *build = 1;
- *revision = 0;
-}
-
-} // namespace mkvmuxer
-
-mkvmuxer::uint64 mkvmuxer::MakeUID(unsigned int* seed) {
- uint64 uid = 0;
-
-#ifdef __MINGW32__
- srand(*seed);
-#endif
-
- for (int i = 0; i < 7; ++i) { // avoid problems with 8-byte values
- uid <<= 8;
-
-// TODO(fgalligan): Move random number generation to platform specific code.
-#ifdef _MSC_VER
- (void)seed;
- const int32 nn = rand();
-#elif __ANDROID__
- int32 temp_num = 1;
- int fd = open("/dev/urandom", O_RDONLY);
- if (fd != -1) {
- read(fd, &temp_num, sizeof(int32));
- close(fd);
- }
- const int32 nn = temp_num;
-#elif defined __MINGW32__
- const int32 nn = rand();
-#else
- const int32 nn = rand_r(seed);
-#endif
- const int32 n = 0xFF & (nn >> 4); // throw away low-order bits
-
- uid |= n;
- }
-
- return uid;
-}
diff --git a/third_party/libwebm/mkvmuxerutil.hpp b/third_party/libwebm/mkvmuxerutil.hpp
deleted file mode 100644
index e318576..0000000
--- a/third_party/libwebm/mkvmuxerutil.hpp
+++ /dev/null
@@ -1,83 +0,0 @@
-// 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 MKVMUXERUTIL_HPP
-#define MKVMUXERUTIL_HPP
-
-#include "mkvmuxer.hpp"
-#include "mkvmuxertypes.hpp"
-
-namespace mkvmuxer {
-
-class IMkvWriter;
-
-const uint64 kEbmlUnknownValue = 0x01FFFFFFFFFFFFFFULL;
-const int64 kMaxBlockTimecode = 0x07FFFLL;
-
-// Writes out |value| in Big Endian order. Returns 0 on success.
-int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size);
-
-// Returns the size in bytes of the element.
-int32 GetUIntSize(uint64 value);
-int32 GetIntSize(int64 value);
-int32 GetCodedUIntSize(uint64 value);
-uint64 EbmlMasterElementSize(uint64 type, uint64 value);
-uint64 EbmlElementSize(uint64 type, int64 value);
-uint64 EbmlElementSize(uint64 type, uint64 value);
-uint64 EbmlElementSize(uint64 type, float value);
-uint64 EbmlElementSize(uint64 type, const char* value);
-uint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size);
-uint64 EbmlDateElementSize(uint64 type);
-
-// Creates an EBML coded number from |value| and writes it out. The size of
-// the coded number is determined by the value of |value|. |value| must not
-// be in a coded form. Returns 0 on success.
-int32 WriteUInt(IMkvWriter* writer, uint64 value);
-
-// Creates an EBML coded number from |value| and writes it out. The size of
-// the coded number is determined by the value of |size|. |value| must not
-// be in a coded form. Returns 0 on success.
-int32 WriteUIntSize(IMkvWriter* writer, uint64 value, int32 size);
-
-// Output an Mkv master element. Returns true if the element was written.
-bool WriteEbmlMasterElement(IMkvWriter* writer, uint64 value, uint64 size);
-
-// Outputs an Mkv ID, calls |IMkvWriter::ElementStartNotify|, and passes the
-// ID to |SerializeInt|. Returns 0 on success.
-int32 WriteID(IMkvWriter* writer, uint64 type);
-
-// Output an Mkv non-master element. Returns true if the element was written.
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value);
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, int64 value);
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, float value);
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const char* value);
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const uint8* value,
- uint64 size);
-bool WriteEbmlDateElement(IMkvWriter* writer, uint64 type, int64 value);
-
-// Output a Mkv Frame. It decides the correct element to write (Block vs
-// SimpleBlock) based on the parameters of the Frame.
-uint64 WriteFrame(IMkvWriter* writer, const Frame* const frame,
- Cluster* cluster);
-
-// Output a void element. |size| must be the entire size in bytes that will be
-// void. The function will calculate the size of the void header and subtract
-// it from |size|.
-uint64 WriteVoidElement(IMkvWriter* writer, uint64 size);
-
-// Returns the version number of the muxer in |major|, |minor|, |build|,
-// and |revision|.
-void GetVersion(int32* major, int32* minor, int32* build, int32* revision);
-
-// Returns a random number to be used for UID, using |seed| to seed
-// the random-number generator (see POSIX rand_r() for semantics).
-uint64 MakeUID(unsigned int* seed);
-
-} // end namespace mkvmuxer
-
-#endif // MKVMUXERUTIL_HPP
diff --git a/third_party/libwebm/mkvparser.cpp b/third_party/libwebm/mkvparser/mkvparser.cc
similarity index 91%
rename from third_party/libwebm/mkvparser.cpp
rename to third_party/libwebm/mkvparser/mkvparser.cc
index f2855d5..2180115 100644
--- a/third_party/libwebm/mkvparser.cpp
+++ b/third_party/libwebm/mkvparser/mkvparser.cc
@@ -5,8 +5,7 @@
// 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 "mkvparser.hpp"
+#include "mkvparser/mkvparser.h"
#if defined(_MSC_VER) && _MSC_VER < 1800
#include <float.h> // _isnan() / _finite()
@@ -14,19 +13,18 @@
#endif
#include <cassert>
+#include <cfloat>
#include <climits>
#include <cmath>
#include <cstring>
+#include <memory>
#include <new>
-#include "webmids.hpp"
-
-#ifdef _MSC_VER
-// Disable MSVC warnings that suggest making code non-portable.
-#pragma warning(disable : 4996)
-#endif
+#include "common/webmids.h"
namespace mkvparser {
+const float MasteringMetadata::kValueNotPresent = FLT_MAX;
+const long long Colour::kValueNotPresent = LLONG_MAX;
#ifdef MSC_COMPAT
inline bool isnan(double val) { return !!_isnan(val); }
@@ -38,8 +36,9 @@
IMkvReader::~IMkvReader() {}
-template<typename Type> Type* SafeArrayAlloc(unsigned long long num_elements,
- unsigned long long element_size) {
+template <typename Type>
+Type* SafeArrayAlloc(unsigned long long num_elements,
+ unsigned long long element_size) {
if (num_elements == 0 || element_size == 0)
return NULL;
@@ -350,9 +349,8 @@
return 0;
}
-long ParseElementHeader(IMkvReader* pReader, long long& pos,
- long long stop, long long& id,
- long long& size) {
+long ParseElementHeader(IMkvReader* pReader, long long& pos, long long stop,
+ long long& id, long long& size) {
if (stop >= 0 && pos >= stop)
return E_FILE_FORMAT_INVALID;
@@ -386,7 +384,7 @@
// pos now designates payload
- if (stop >= 0 && pos >= stop)
+ if (stop >= 0 && pos > stop)
return E_FILE_FORMAT_INVALID;
return 0; // success
@@ -520,7 +518,6 @@
return status;
pos = 0;
- long long end = (available >= 1024) ? 1024 : available;
// Scan until we find what looks like the first byte of the EBML header.
const long long kMaxScanBytes = (available >= 1024) ? 1024 : available;
@@ -544,8 +541,10 @@
long len = 0;
const long long ebml_id = ReadID(pReader, pos, len);
- // TODO(tomfinegan): Move Matroska ID constants into a common namespace.
- if (len != 4 || ebml_id != mkvmuxer::kMkvEBML)
+ if (ebml_id == E_BUFFER_NOT_FULL)
+ return E_BUFFER_NOT_FULL;
+
+ if (len != 4 || ebml_id != libwebm::kMkvEBML)
return E_FILE_FORMAT_INVALID;
// Move read pos forward to the EBML header size field.
@@ -584,7 +583,7 @@
if ((available - pos) < result)
return pos + result;
- end = pos + result;
+ const long long end = pos + result;
Init();
@@ -599,27 +598,27 @@
if (size == 0)
return E_FILE_FORMAT_INVALID;
- if (id == mkvmuxer::kMkvEBMLVersion) {
+ if (id == libwebm::kMkvEBMLVersion) {
m_version = UnserializeUInt(pReader, pos, size);
if (m_version <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvEBMLReadVersion) {
+ } else if (id == libwebm::kMkvEBMLReadVersion) {
m_readVersion = UnserializeUInt(pReader, pos, size);
if (m_readVersion <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvEBMLMaxIDLength) {
+ } else if (id == libwebm::kMkvEBMLMaxIDLength) {
m_maxIdLength = UnserializeUInt(pReader, pos, size);
if (m_maxIdLength <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvEBMLMaxSizeLength) {
+ } else if (id == libwebm::kMkvEBMLMaxSizeLength) {
m_maxSizeLength = UnserializeUInt(pReader, pos, size);
if (m_maxSizeLength <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvDocType) {
+ } else if (id == libwebm::kMkvDocType) {
if (m_docType)
return E_FILE_FORMAT_INVALID;
@@ -627,12 +626,12 @@
if (status) // error
return status;
- } else if (id == mkvmuxer::kMkvDocTypeVersion) {
+ } else if (id == libwebm::kMkvDocTypeVersion) {
m_docTypeVersion = UnserializeUInt(pReader, pos, size);
if (m_docTypeVersion <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvDocTypeReadVersion) {
+ } else if (id == libwebm::kMkvDocTypeReadVersion) {
m_docTypeReadVersion = UnserializeUInt(pReader, pos, size);
if (m_docTypeReadVersion <= 0)
@@ -650,8 +649,8 @@
return E_FILE_FORMAT_INVALID;
// Make sure EBMLMaxIDLength and EBMLMaxSizeLength are valid.
- if (m_maxIdLength <= 0 || m_maxIdLength > 4 ||
- m_maxSizeLength <= 0 || m_maxSizeLength > 8)
+ if (m_maxIdLength <= 0 || m_maxIdLength > 4 || m_maxSizeLength <= 0 ||
+ m_maxSizeLength > 8)
return E_FILE_FORMAT_INVALID;
return 0;
@@ -786,7 +785,7 @@
// Handle "unknown size" for live streaming of webm files.
const long long unknown_size = (1LL << (7 * len)) - 1;
- if (id == mkvmuxer::kMkvSegment) {
+ if (id == libwebm::kMkvSegment) {
if (size == unknown_size)
size = -1;
@@ -878,7 +877,7 @@
if (id < 0)
return E_FILE_FORMAT_INVALID;
- if (id == mkvmuxer::kMkvCluster)
+ if (id == libwebm::kMkvCluster)
break;
pos += len; // consume ID
@@ -930,7 +929,7 @@
if ((pos + size) > available)
return pos + size;
- if (id == mkvmuxer::kMkvInfo) {
+ if (id == libwebm::kMkvInfo) {
if (m_pInfo)
return E_FILE_FORMAT_INVALID;
@@ -944,7 +943,7 @@
if (status)
return status;
- } else if (id == mkvmuxer::kMkvTracks) {
+ } else if (id == libwebm::kMkvTracks) {
if (m_pTracks)
return E_FILE_FORMAT_INVALID;
@@ -958,7 +957,7 @@
if (status)
return status;
- } else if (id == mkvmuxer::kMkvCues) {
+ } else if (id == libwebm::kMkvCues) {
if (m_pCues == NULL) {
m_pCues = new (std::nothrow)
Cues(this, pos, size, element_start, element_size);
@@ -966,7 +965,7 @@
if (m_pCues == NULL)
return -1;
}
- } else if (id == mkvmuxer::kMkvSeekHead) {
+ } else if (id == libwebm::kMkvSeekHead) {
if (m_pSeekHead == NULL) {
m_pSeekHead = new (std::nothrow)
SeekHead(this, pos, size, element_start, element_size);
@@ -979,7 +978,7 @@
if (status)
return status;
}
- } else if (id == mkvmuxer::kMkvChapters) {
+ } else if (id == libwebm::kMkvChapters) {
if (m_pChapters == NULL) {
m_pChapters = new (std::nothrow)
Chapters(this, pos, size, element_start, element_size);
@@ -992,7 +991,7 @@
if (status)
return status;
}
- } else if (id == mkvmuxer::kMkvTags) {
+ } else if (id == libwebm::kMkvTags) {
if (m_pTags == NULL) {
m_pTags = new (std::nothrow)
Tags(this, pos, size, element_start, element_size);
@@ -1131,7 +1130,7 @@
return E_FILE_FORMAT_INVALID;
}
- if (id == mkvmuxer::kMkvCues) {
+ if (id == libwebm::kMkvCues) {
if (size == unknown_size) {
// Cues element of unknown size: Not supported.
return E_FILE_FORMAT_INVALID;
@@ -1149,7 +1148,7 @@
continue;
}
- if (id != mkvmuxer::kMkvCluster) {
+ if (id != libwebm::kMkvCluster) {
// Besides the Segment, Libwebm allows only cluster elements of unknown
// size. Fail the parse upon encountering a non-cluster element reporting
// unknown size.
@@ -1466,7 +1465,7 @@
return E_FILE_FORMAT_INVALID;
for (;;) {
- const int status = LoadCluster();
+ const long status = LoadCluster();
if (status < 0) // error
return status;
@@ -1512,9 +1511,9 @@
if (status < 0) // error
return status;
- if (id == mkvmuxer::kMkvSeek)
+ if (id == libwebm::kMkvSeek)
++entry_count;
- else if (id == mkvmuxer::kMkvVoid)
+ else if (id == libwebm::kMkvVoid)
++void_element_count;
pos += size; // consume payload
@@ -1553,14 +1552,14 @@
if (status < 0) // error
return status;
- if (id == mkvmuxer::kMkvSeek) {
+ if (id == libwebm::kMkvSeek) {
if (ParseEntry(pReader, pos, size, pEntry)) {
Entry& e = *pEntry++;
e.element_start = idpos;
e.element_size = (pos + size) - idpos;
}
- } else if (id == mkvmuxer::kMkvVoid) {
+ } else if (id == libwebm::kMkvVoid) {
VoidElement& e = *pVoidElement++;
e.element_start = idpos;
@@ -1664,7 +1663,7 @@
const long long id = ReadID(m_pReader, idpos, len);
- if (id != mkvmuxer::kMkvCues)
+ if (id != libwebm::kMkvCues)
return E_FILE_FORMAT_INVALID;
pos += len; // consume ID
@@ -1746,7 +1745,7 @@
if (seekIdId < 0)
return false;
- if (seekIdId != mkvmuxer::kMkvSeekID)
+ if (seekIdId != libwebm::kMkvSeekID)
return false;
if ((pos + len) > stop)
@@ -1790,7 +1789,7 @@
const long long seekPosId = ReadID(pReader, pos, len);
- if (seekPosId != mkvmuxer::kMkvSeekPosition)
+ if (seekPosId != libwebm::kMkvSeekPosition)
return false;
if ((pos + len) > stop)
@@ -1900,7 +1899,7 @@
return false;
}
- if (id == mkvmuxer::kMkvCuePoint) {
+ if (id == libwebm::kMkvCuePoint) {
if (!PreloadCuePoint(cue_points_size, idpos))
return false;
}
@@ -1975,7 +1974,7 @@
if ((m_pos + size) > stop)
return false;
- if (id != mkvmuxer::kMkvCuePoint) {
+ if (id != libwebm::kMkvCuePoint) {
m_pos += size; // consume payload
if (m_pos > stop)
return false;
@@ -2105,8 +2104,8 @@
}
const CuePoint* Cues::GetNext(const CuePoint* pCurr) const {
- if (pCurr == NULL || pCurr->GetTimeCode() < 0 ||
- m_cue_points == NULL || m_count < 1) {
+ if (pCurr == NULL || pCurr->GetTimeCode() < 0 || m_cue_points == NULL ||
+ m_count < 1) {
return NULL;
}
@@ -2286,7 +2285,7 @@
long len;
const long long id = ReadID(pReader, pos_, len);
- if (id != mkvmuxer::kMkvCuePoint)
+ if (id != libwebm::kMkvCuePoint)
return false;
pos_ += len; // consume ID
@@ -2326,10 +2325,10 @@
return false;
}
- if (id == mkvmuxer::kMkvCueTime)
+ if (id == libwebm::kMkvCueTime)
m_timecode = UnserializeUInt(pReader, pos, size);
- else if (id == mkvmuxer::kMkvCueTrackPositions)
+ else if (id == libwebm::kMkvCueTrackPositions)
++m_track_positions_count;
pos += size; // consume payload
@@ -2368,7 +2367,7 @@
pos += len; // consume Size field
assert((pos + size) <= stop);
- if (id == mkvmuxer::kMkvCueTrackPositions) {
+ if (id == libwebm::kMkvCueTrackPositions) {
TrackPosition& tp = *p++;
if (!tp.Parse(pReader, pos, size)) {
return false;
@@ -2417,11 +2416,11 @@
return false;
}
- if (id == mkvmuxer::kMkvCueTrack)
+ if (id == libwebm::kMkvCueTrack)
m_track = UnserializeUInt(pReader, pos, size);
- else if (id == mkvmuxer::kMkvCueClusterPosition)
+ else if (id == libwebm::kMkvCueClusterPosition)
m_pos = UnserializeUInt(pReader, pos, size);
- else if (id == mkvmuxer::kMkvCueBlockNumber)
+ else if (id == libwebm::kMkvCueBlockNumber)
m_block = UnserializeUInt(pReader, pos, size);
pos += size; // consume payload
@@ -2555,7 +2554,7 @@
return NULL;
const long long id = ReadID(m_pReader, pos, len);
- if (id != mkvmuxer::kMkvCluster)
+ if (id != libwebm::kMkvCluster)
return NULL;
pos += len; // consume ID
@@ -2612,7 +2611,7 @@
if (size == 0) // weird
continue;
- if (id == mkvmuxer::kMkvCluster) {
+ if (id == libwebm::kMkvCluster) {
const long long off_next_ = idpos - m_start;
long long pos_;
@@ -2762,7 +2761,7 @@
const long long id = ReadUInt(m_pReader, pos, len);
- if (id != mkvmuxer::kMkvCluster)
+ if (id != libwebm::kMkvCluster)
return -1;
pos += len; // consume ID
@@ -2927,7 +2926,7 @@
return E_FILE_FORMAT_INVALID;
}
- if (id == mkvmuxer::kMkvCues) {
+ if (id == libwebm::kMkvCues) {
if (size == unknown_size)
return E_FILE_FORMAT_INVALID;
@@ -2953,7 +2952,7 @@
continue;
}
- if (id != mkvmuxer::kMkvCluster) { // not a Cluster ID
+ if (id != libwebm::kMkvCluster) { // not a Cluster ID
if (size == unknown_size)
return E_FILE_FORMAT_INVALID;
@@ -3091,7 +3090,7 @@
// that we have exhausted the sub-element's inside the cluster
// whose ID we parsed earlier.
- if (id == mkvmuxer::kMkvCluster || id == mkvmuxer::kMkvCues)
+ if (id == libwebm::kMkvCluster || id == libwebm::kMkvCues)
break;
pos += len; // consume ID (of sub-element)
@@ -3259,7 +3258,7 @@
if (size == 0) // weird
continue;
- if (id == mkvmuxer::kMkvEditionEntry) {
+ if (id == libwebm::kMkvEditionEntry) {
status = ParseEdition(pos, size);
if (status < 0) // error
@@ -3375,7 +3374,7 @@
if (size == 0)
continue;
- if (id == mkvmuxer::kMkvChapterAtom) {
+ if (id == libwebm::kMkvChapterAtom) {
status = ParseAtom(pReader, pos, size);
if (status < 0) // error
@@ -3508,17 +3507,17 @@
if (size == 0) // 0 length payload, skip.
continue;
- if (id == mkvmuxer::kMkvChapterDisplay) {
+ if (id == libwebm::kMkvChapterDisplay) {
status = ParseDisplay(pReader, pos, size);
if (status < 0) // error
return status;
- } else if (id == mkvmuxer::kMkvChapterStringUID) {
+ } else if (id == libwebm::kMkvChapterStringUID) {
status = UnserializeString(pReader, pos, size, m_string_uid);
if (status < 0) // error
return status;
- } else if (id == mkvmuxer::kMkvChapterUID) {
+ } else if (id == libwebm::kMkvChapterUID) {
long long val;
status = UnserializeInt(pReader, pos, size, val);
@@ -3526,14 +3525,14 @@
return status;
m_uid = static_cast<unsigned long long>(val);
- } else if (id == mkvmuxer::kMkvChapterTimeStart) {
+ } else if (id == libwebm::kMkvChapterTimeStart) {
const long long val = UnserializeUInt(pReader, pos, size);
if (val < 0) // error
return static_cast<long>(val);
m_start_timecode = val;
- } else if (id == mkvmuxer::kMkvChapterTimeEnd) {
+ } else if (id == libwebm::kMkvChapterTimeEnd) {
const long long val = UnserializeUInt(pReader, pos, size);
if (val < 0) // error
@@ -3661,17 +3660,17 @@
if (size == 0) // No payload.
continue;
- if (id == mkvmuxer::kMkvChapString) {
+ if (id == libwebm::kMkvChapString) {
status = UnserializeString(pReader, pos, size, m_string);
if (status)
return status;
- } else if (id == mkvmuxer::kMkvChapLanguage) {
+ } else if (id == libwebm::kMkvChapLanguage) {
status = UnserializeString(pReader, pos, size, m_language);
if (status)
return status;
- } else if (id == mkvmuxer::kMkvChapCountry) {
+ } else if (id == libwebm::kMkvChapCountry) {
status = UnserializeString(pReader, pos, size, m_country);
if (status)
@@ -3724,7 +3723,7 @@
if (size == 0) // 0 length tag, read another
continue;
- if (id == mkvmuxer::kMkvTag) {
+ if (id == libwebm::kMkvTag) {
status = ParseTag(pos, size);
if (status < 0)
@@ -3840,7 +3839,7 @@
if (size == 0) // 0 length tag, read another
continue;
- if (id == mkvmuxer::kMkvSimpleTag) {
+ if (id == libwebm::kMkvSimpleTag) {
status = ParseSimpleTag(pReader, pos, size);
if (status < 0)
@@ -3931,12 +3930,12 @@
if (size == 0) // weird
continue;
- if (id == mkvmuxer::kMkvTagName) {
+ if (id == libwebm::kMkvTagName) {
status = UnserializeString(pReader, pos, size, m_tag_name);
if (status)
return status;
- } else if (id == mkvmuxer::kMkvTagString) {
+ } else if (id == libwebm::kMkvTagString) {
status = UnserializeString(pReader, pos, size, m_tag_string);
if (status)
@@ -3996,12 +3995,12 @@
if (status < 0) // error
return status;
- if (id == mkvmuxer::kMkvTimecodeScale) {
+ if (id == libwebm::kMkvTimecodeScale) {
m_timecodeScale = UnserializeUInt(pReader, pos, size);
if (m_timecodeScale <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvDuration) {
+ } else if (id == libwebm::kMkvDuration) {
const long status = UnserializeFloat(pReader, pos, size, m_duration);
if (status < 0)
@@ -4009,19 +4008,19 @@
if (m_duration < 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvMuxingApp) {
+ } else if (id == libwebm::kMkvMuxingApp) {
const long status =
UnserializeString(pReader, pos, size, m_pMuxingAppAsUTF8);
if (status)
return status;
- } else if (id == mkvmuxer::kMkvWritingApp) {
+ } else if (id == libwebm::kMkvWritingApp) {
const long status =
UnserializeString(pReader, pos, size, m_pWritingAppAsUTF8);
if (status)
return status;
- } else if (id == mkvmuxer::kMkvTitle) {
+ } else if (id == libwebm::kMkvTitle) {
const long status = UnserializeString(pReader, pos, size, m_pTitleAsUTF8);
if (status)
@@ -4176,7 +4175,7 @@
if (status < 0) // error
return status;
- if (id == mkvmuxer::kMkvAESSettingsCipherMode) {
+ if (id == libwebm::kMkvAESSettingsCipherMode) {
aes->cipher_mode = UnserializeUInt(pReader, pos, size);
if (aes->cipher_mode != 1)
return E_FILE_FORMAT_INVALID;
@@ -4207,10 +4206,10 @@
if (status < 0) // error
return status;
- if (id == mkvmuxer::kMkvContentCompression)
+ if (id == libwebm::kMkvContentCompression)
++compression_count;
- if (id == mkvmuxer::kMkvContentEncryption)
+ if (id == libwebm::kMkvContentEncryption)
++encryption_count;
pos += size; // consume payload
@@ -4246,15 +4245,15 @@
if (status < 0) // error
return status;
- if (id == mkvmuxer::kMkvContentEncodingOrder) {
+ if (id == libwebm::kMkvContentEncodingOrder) {
encoding_order_ = UnserializeUInt(pReader, pos, size);
- } else if (id == mkvmuxer::kMkvContentEncodingScope) {
+ } else if (id == libwebm::kMkvContentEncodingScope) {
encoding_scope_ = UnserializeUInt(pReader, pos, size);
if (encoding_scope_ < 1)
return -1;
- } else if (id == mkvmuxer::kMkvContentEncodingType) {
+ } else if (id == libwebm::kMkvContentEncodingType) {
encoding_type_ = UnserializeUInt(pReader, pos, size);
- } else if (id == mkvmuxer::kMkvContentCompression) {
+ } else if (id == libwebm::kMkvContentCompression) {
ContentCompression* const compression =
new (std::nothrow) ContentCompression();
if (!compression)
@@ -4266,7 +4265,7 @@
return status;
}
*compression_entries_end_++ = compression;
- } else if (id == mkvmuxer::kMkvContentEncryption) {
+ } else if (id == libwebm::kMkvContentEncryption) {
ContentEncryption* const encryption =
new (std::nothrow) ContentEncryption();
if (!encryption)
@@ -4307,13 +4306,13 @@
if (status < 0) // error
return status;
- if (id == mkvmuxer::kMkvContentCompAlgo) {
+ if (id == libwebm::kMkvContentCompAlgo) {
long long algo = UnserializeUInt(pReader, pos, size);
if (algo < 0)
return E_FILE_FORMAT_INVALID;
compression->algo = algo;
valid = true;
- } else if (id == mkvmuxer::kMkvContentCompSettings) {
+ } else if (id == libwebm::kMkvContentCompSettings) {
if (size <= 0)
return E_FILE_FORMAT_INVALID;
@@ -4360,11 +4359,11 @@
if (status < 0) // error
return status;
- if (id == mkvmuxer::kMkvContentEncAlgo) {
+ if (id == libwebm::kMkvContentEncAlgo) {
encryption->algo = UnserializeUInt(pReader, pos, size);
if (encryption->algo != 5)
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvContentEncKeyID) {
+ } else if (id == libwebm::kMkvContentEncKeyID) {
delete[] encryption->key_id;
encryption->key_id = NULL;
encryption->key_id_len = 0;
@@ -4386,7 +4385,7 @@
encryption->key_id = buf;
encryption->key_id_len = buflen;
- } else if (id == mkvmuxer::kMkvContentSignature) {
+ } else if (id == libwebm::kMkvContentSignature) {
delete[] encryption->signature;
encryption->signature = NULL;
encryption->signature_len = 0;
@@ -4408,7 +4407,7 @@
encryption->signature = buf;
encryption->signature_len = buflen;
- } else if (id == mkvmuxer::kMkvContentSigKeyID) {
+ } else if (id == libwebm::kMkvContentSigKeyID) {
delete[] encryption->sig_key_id;
encryption->sig_key_id = NULL;
encryption->sig_key_id_len = 0;
@@ -4430,11 +4429,11 @@
encryption->sig_key_id = buf;
encryption->sig_key_id_len = buflen;
- } else if (id == mkvmuxer::kMkvContentSigAlgo) {
+ } else if (id == libwebm::kMkvContentSigAlgo) {
encryption->sig_algo = UnserializeUInt(pReader, pos, size);
- } else if (id == mkvmuxer::kMkvContentSigHashAlgo) {
+ } else if (id == libwebm::kMkvContentSigHashAlgo) {
encryption->sig_hash_algo = UnserializeUInt(pReader, pos, size);
- } else if (id == mkvmuxer::kMkvContentEncAESSettings) {
+ } else if (id == libwebm::kMkvContentEncAESSettings) {
const long status = ParseContentEncAESSettingsEntry(
pos, size, pReader, &encryption->aes_settings);
if (status)
@@ -4921,7 +4920,7 @@
return status;
// pos now designates start of element
- if (id == mkvmuxer::kMkvContentEncoding)
+ if (id == libwebm::kMkvContentEncoding)
++count;
pos += size; // consume payload
@@ -4946,7 +4945,7 @@
return status;
// pos now designates start of element
- if (id == mkvmuxer::kMkvContentEncoding) {
+ if (id == libwebm::kMkvContentEncoding) {
ContentEncoding* const content_encoding =
new (std::nothrow) ContentEncoding();
if (!content_encoding)
@@ -4978,9 +4977,222 @@
const Block* Track::EOSBlock::GetBlock() const { return NULL; }
+bool PrimaryChromaticity::Parse(IMkvReader* reader, long long read_pos,
+ long long value_size, bool is_x,
+ PrimaryChromaticity** chromaticity) {
+ if (!reader)
+ return false;
+
+ std::auto_ptr<PrimaryChromaticity> chromaticity_ptr;
+
+ if (!*chromaticity) {
+ chromaticity_ptr.reset(new PrimaryChromaticity());
+ } else {
+ chromaticity_ptr.reset(*chromaticity);
+ }
+
+ if (!chromaticity_ptr.get())
+ return false;
+
+ float* value = is_x ? &chromaticity_ptr->x : &chromaticity_ptr->y;
+
+ double parser_value = 0;
+ const long long value_parse_status =
+ UnserializeFloat(reader, read_pos, value_size, parser_value);
+
+ *value = static_cast<float>(parser_value);
+
+ if (value_parse_status < 0 || *value < 0.0 || *value > 1.0)
+ return false;
+
+ *chromaticity = chromaticity_ptr.release();
+ return true;
+}
+
+bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start,
+ long long mm_size, MasteringMetadata** mm) {
+ if (!reader || *mm)
+ return false;
+
+ std::auto_ptr<MasteringMetadata> mm_ptr(new MasteringMetadata());
+ if (!mm_ptr.get())
+ return false;
+
+ const long long mm_end = mm_start + mm_size;
+ long long read_pos = mm_start;
+
+ while (read_pos < mm_end) {
+ long long child_id = 0;
+ long long child_size = 0;
+
+ const long long status =
+ ParseElementHeader(reader, read_pos, mm_end, child_id, child_size);
+ if (status < 0)
+ return false;
+
+ if (child_id == libwebm::kMkvLuminanceMax) {
+ double value = 0;
+ const long long value_parse_status =
+ UnserializeFloat(reader, read_pos, child_size, value);
+ mm_ptr->luminance_max = static_cast<float>(value);
+ if (value_parse_status < 0 || mm_ptr->luminance_max < 0.0 ||
+ mm_ptr->luminance_max > 9999.99) {
+ return false;
+ }
+ } else if (child_id == libwebm::kMkvLuminanceMin) {
+ double value = 0;
+ const long long value_parse_status =
+ UnserializeFloat(reader, read_pos, child_size, value);
+ mm_ptr->luminance_min = static_cast<float>(value);
+ if (value_parse_status < 0 || mm_ptr->luminance_min < 0.0 ||
+ mm_ptr->luminance_min > 999.9999) {
+ return false;
+ }
+ } else {
+ bool is_x = false;
+ PrimaryChromaticity** chromaticity;
+ switch (child_id) {
+ case libwebm::kMkvPrimaryRChromaticityX:
+ case libwebm::kMkvPrimaryRChromaticityY:
+ is_x = child_id == libwebm::kMkvPrimaryRChromaticityX;
+ chromaticity = &mm_ptr->r;
+ break;
+ case libwebm::kMkvPrimaryGChromaticityX:
+ case libwebm::kMkvPrimaryGChromaticityY:
+ is_x = child_id == libwebm::kMkvPrimaryGChromaticityX;
+ chromaticity = &mm_ptr->g;
+ break;
+ case libwebm::kMkvPrimaryBChromaticityX:
+ case libwebm::kMkvPrimaryBChromaticityY:
+ is_x = child_id == libwebm::kMkvPrimaryBChromaticityX;
+ chromaticity = &mm_ptr->b;
+ break;
+ case libwebm::kMkvWhitePointChromaticityX:
+ case libwebm::kMkvWhitePointChromaticityY:
+ is_x = child_id == libwebm::kMkvWhitePointChromaticityX;
+ chromaticity = &mm_ptr->white_point;
+ break;
+ default:
+ return false;
+ }
+ const bool value_parse_status = PrimaryChromaticity::Parse(
+ reader, read_pos, child_size, is_x, chromaticity);
+ if (!value_parse_status)
+ return false;
+ }
+
+ read_pos += child_size;
+ if (read_pos > mm_end)
+ return false;
+ }
+
+ *mm = mm_ptr.release();
+ return true;
+}
+
+bool Colour::Parse(IMkvReader* reader, long long colour_start,
+ long long colour_size, Colour** colour) {
+ if (!reader || *colour)
+ return false;
+
+ std::auto_ptr<Colour> colour_ptr(new Colour());
+ if (!colour_ptr.get())
+ return false;
+
+ const long long colour_end = colour_start + colour_size;
+ long long read_pos = colour_start;
+
+ while (read_pos < colour_end) {
+ long long child_id = 0;
+ long long child_size = 0;
+
+ const long status =
+ ParseElementHeader(reader, read_pos, colour_end, child_id, child_size);
+ if (status < 0)
+ return false;
+
+ if (child_id == libwebm::kMkvMatrixCoefficients) {
+ colour_ptr->matrix_coefficients =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->matrix_coefficients < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvBitsPerChannel) {
+ colour_ptr->bits_per_channel =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->bits_per_channel < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvChromaSubsamplingHorz) {
+ colour_ptr->chroma_subsampling_horz =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->chroma_subsampling_horz < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvChromaSubsamplingVert) {
+ colour_ptr->chroma_subsampling_vert =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->chroma_subsampling_vert < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvCbSubsamplingHorz) {
+ colour_ptr->cb_subsampling_horz =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->cb_subsampling_horz < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvCbSubsamplingVert) {
+ colour_ptr->cb_subsampling_vert =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->cb_subsampling_vert < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvChromaSitingHorz) {
+ colour_ptr->chroma_siting_horz =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->chroma_siting_horz < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvChromaSitingVert) {
+ colour_ptr->chroma_siting_vert =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->chroma_siting_vert < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvRange) {
+ colour_ptr->range = UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->range < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvTransferCharacteristics) {
+ colour_ptr->transfer_characteristics =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->transfer_characteristics < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvPrimaries) {
+ colour_ptr->primaries = UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->primaries < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvMaxCLL) {
+ colour_ptr->max_cll = UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->max_cll < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvMaxFALL) {
+ colour_ptr->max_fall = UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->max_fall < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvMasteringMetadata) {
+ if (!MasteringMetadata::Parse(reader, read_pos, child_size,
+ &colour_ptr->mastering_metadata))
+ return false;
+ } else {
+ return false;
+ }
+
+ read_pos += child_size;
+ if (read_pos > colour_end)
+ return false;
+ }
+ *colour = colour_ptr.release();
+ return true;
+}
+
VideoTrack::VideoTrack(Segment* pSegment, long long element_start,
long long element_size)
- : Track(pSegment, element_start, element_size) {}
+ : Track(pSegment, element_start, element_size), m_colour(NULL) {}
+
+VideoTrack::~VideoTrack() { delete m_colour; }
long VideoTrack::Parse(Segment* pSegment, const Info& info,
long long element_start, long long element_size,
@@ -5011,6 +5223,8 @@
const long long stop = pos + s.size;
+ Colour* colour = NULL;
+
while (pos < stop) {
long long id, size;
@@ -5019,37 +5233,37 @@
if (status < 0) // error
return status;
- if (id == mkvmuxer::kMkvPixelWidth) {
+ if (id == libwebm::kMkvPixelWidth) {
width = UnserializeUInt(pReader, pos, size);
if (width <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvPixelHeight) {
+ } else if (id == libwebm::kMkvPixelHeight) {
height = UnserializeUInt(pReader, pos, size);
if (height <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvDisplayWidth) {
+ } else if (id == libwebm::kMkvDisplayWidth) {
display_width = UnserializeUInt(pReader, pos, size);
if (display_width <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvDisplayHeight) {
+ } else if (id == libwebm::kMkvDisplayHeight) {
display_height = UnserializeUInt(pReader, pos, size);
if (display_height <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvDisplayUnit) {
+ } else if (id == libwebm::kMkvDisplayUnit) {
display_unit = UnserializeUInt(pReader, pos, size);
if (display_unit < 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvStereoMode) {
+ } else if (id == libwebm::kMkvStereoMode) {
stereo_mode = UnserializeUInt(pReader, pos, size);
if (stereo_mode < 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvFrameRate) {
+ } else if (id == libwebm::kMkvFrameRate) {
const long status = UnserializeFloat(pReader, pos, size, rate);
if (status < 0)
@@ -5057,6 +5271,9 @@
if (rate <= 0)
return E_FILE_FORMAT_INVALID;
+ } else if (id == libwebm::kMkvColour) {
+ if (!Colour::Parse(pReader, pos, size, &colour))
+ return E_FILE_FORMAT_INVALID;
}
pos += size; // consume payload
@@ -5087,6 +5304,7 @@
pTrack->m_display_unit = display_unit;
pTrack->m_stereo_mode = stereo_mode;
pTrack->m_rate = rate;
+ pTrack->m_colour = colour;
pResult = pTrack;
return 0; // success
@@ -5185,6 +5403,8 @@
return 0;
}
+Colour* VideoTrack::GetColour() const { return m_colour; }
+
long long VideoTrack::GetWidth() const { return m_width; }
long long VideoTrack::GetHeight() const { return m_height; }
@@ -5239,7 +5459,7 @@
if (status < 0) // error
return status;
- if (id == mkvmuxer::kMkvSamplingFrequency) {
+ if (id == libwebm::kMkvSamplingFrequency) {
status = UnserializeFloat(pReader, pos, size, rate);
if (status < 0)
@@ -5247,12 +5467,12 @@
if (rate <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvChannels) {
+ } else if (id == libwebm::kMkvChannels) {
channels = UnserializeUInt(pReader, pos, size);
if (channels <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvBitDepth) {
+ } else if (id == libwebm::kMkvBitDepth) {
bit_depth = UnserializeUInt(pReader, pos, size);
if (bit_depth <= 0)
@@ -5325,7 +5545,7 @@
if (size == 0) // weird
continue;
- if (id == mkvmuxer::kMkvTrackEntry)
+ if (id == libwebm::kMkvTrackEntry)
++count;
pos += size; // consume payload
@@ -5367,7 +5587,7 @@
const long long element_size = payload_stop - element_start;
- if (id == mkvmuxer::kMkvTrackEntry) {
+ if (id == libwebm::kMkvTrackEntry) {
Track*& pTrack = *m_trackEntriesEnd;
pTrack = NULL;
@@ -5443,16 +5663,16 @@
const long long start = pos;
- if (id == mkvmuxer::kMkvVideo) {
+ if (id == libwebm::kMkvVideo) {
v.start = start;
v.size = size;
- } else if (id == mkvmuxer::kMkvAudio) {
+ } else if (id == libwebm::kMkvAudio) {
a.start = start;
a.size = size;
- } else if (id == mkvmuxer::kMkvContentEncodings) {
+ } else if (id == libwebm::kMkvContentEncodings) {
e.start = start;
e.size = size;
- } else if (id == mkvmuxer::kMkvTrackUID) {
+ } else if (id == libwebm::kMkvTrackUID) {
if (size > 8)
return E_FILE_FORMAT_INVALID;
@@ -5474,49 +5694,49 @@
++pos_;
}
- } else if (id == mkvmuxer::kMkvTrackNumber) {
+ } else if (id == libwebm::kMkvTrackNumber) {
const long long num = UnserializeUInt(pReader, pos, size);
if ((num <= 0) || (num > 127))
return E_FILE_FORMAT_INVALID;
info.number = static_cast<long>(num);
- } else if (id == mkvmuxer::kMkvTrackType) {
+ } else if (id == libwebm::kMkvTrackType) {
const long long type = UnserializeUInt(pReader, pos, size);
if ((type <= 0) || (type > 254))
return E_FILE_FORMAT_INVALID;
info.type = static_cast<long>(type);
- } else if (id == mkvmuxer::kMkvName) {
+ } else if (id == libwebm::kMkvName) {
const long status =
UnserializeString(pReader, pos, size, info.nameAsUTF8);
if (status)
return status;
- } else if (id == mkvmuxer::kMkvLanguage) {
+ } else if (id == libwebm::kMkvLanguage) {
const long status = UnserializeString(pReader, pos, size, info.language);
if (status)
return status;
- } else if (id == mkvmuxer::kMkvDefaultDuration) {
+ } else if (id == libwebm::kMkvDefaultDuration) {
const long long duration = UnserializeUInt(pReader, pos, size);
if (duration < 0)
return E_FILE_FORMAT_INVALID;
info.defaultDuration = static_cast<unsigned long long>(duration);
- } else if (id == mkvmuxer::kMkvCodecID) {
+ } else if (id == libwebm::kMkvCodecID) {
const long status = UnserializeString(pReader, pos, size, info.codecId);
if (status)
return status;
- } else if (id == mkvmuxer::kMkvFlagLacing) {
+ } else if (id == libwebm::kMkvFlagLacing) {
lacing = UnserializeUInt(pReader, pos, size);
if ((lacing < 0) || (lacing > 1))
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvCodecPrivate) {
+ } else if (id == libwebm::kMkvCodecPrivate) {
delete[] info.codecPrivate;
info.codecPrivate = NULL;
info.codecPrivateSize = 0;
@@ -5539,15 +5759,15 @@
info.codecPrivate = buf;
info.codecPrivateSize = buflen;
}
- } else if (id == mkvmuxer::kMkvCodecName) {
+ } else if (id == libwebm::kMkvCodecName) {
const long status =
UnserializeString(pReader, pos, size, info.codecNameAsUTF8);
if (status)
return status;
- } else if (id == mkvmuxer::kMkvCodecDelay) {
+ } else if (id == libwebm::kMkvCodecDelay) {
info.codecDelay = UnserializeUInt(pReader, pos, size);
- } else if (id == mkvmuxer::kMkvSeekPreRoll) {
+ } else if (id == libwebm::kMkvSeekPreRoll) {
info.seekPreRoll = UnserializeUInt(pReader, pos, size);
}
@@ -5730,7 +5950,7 @@
if (id_ < 0) // error
return static_cast<long>(id_);
- if (id_ != mkvmuxer::kMkvCluster)
+ if (id_ != libwebm::kMkvCluster)
return E_FILE_FORMAT_INVALID;
pos += len; // consume id
@@ -5812,10 +6032,10 @@
// that we have exhausted the sub-element's inside the cluster
// whose ID we parsed earlier.
- if (id == mkvmuxer::kMkvCluster)
+ if (id == libwebm::kMkvCluster)
break;
- if (id == mkvmuxer::kMkvCues)
+ if (id == libwebm::kMkvCues)
break;
pos += len; // consume ID field
@@ -5864,7 +6084,7 @@
if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
return E_FILE_FORMAT_INVALID;
- if (id == mkvmuxer::kMkvTimecode) {
+ if (id == libwebm::kMkvTimecode) {
len = static_cast<long>(size);
if ((pos + size) > avail)
@@ -5879,10 +6099,10 @@
if (bBlock)
break;
- } else if (id == mkvmuxer::kMkvBlockGroup) {
+ } else if (id == libwebm::kMkvBlockGroup) {
bBlock = true;
break;
- } else if (id == mkvmuxer::kMkvSimpleBlock) {
+ } else if (id == libwebm::kMkvSimpleBlock) {
bBlock = true;
break;
}
@@ -5980,7 +6200,7 @@
// that we have exhausted the sub-element's inside the cluster
// whose ID we parsed earlier.
- if ((id == mkvmuxer::kMkvCluster) || (id == mkvmuxer::kMkvCues)) {
+ if ((id == libwebm::kMkvCluster) || (id == libwebm::kMkvCues)) {
if (m_element_size < 0)
m_element_size = pos - m_element_start;
@@ -6035,8 +6255,7 @@
if (cluster_stop >= 0) {
if (block_stop > cluster_stop) {
- if (id == mkvmuxer::kMkvBlockGroup ||
- id == mkvmuxer::kMkvSimpleBlock) {
+ if (id == libwebm::kMkvBlockGroup || id == libwebm::kMkvSimpleBlock) {
return E_FILE_FORMAT_INVALID;
}
@@ -6054,10 +6273,10 @@
Cluster* const this_ = const_cast<Cluster*>(this);
- if (id == mkvmuxer::kMkvBlockGroup)
+ if (id == libwebm::kMkvBlockGroup)
return this_->ParseBlockGroup(size, pos, len);
- if (id == mkvmuxer::kMkvSimpleBlock)
+ if (id == libwebm::kMkvSimpleBlock)
return this_->ParseSimpleBlock(size, pos, len);
pos += size; // consume payload
@@ -6188,8 +6407,7 @@
return E_BUFFER_NOT_FULL;
}
- status = CreateBlock(mkvmuxer::kMkvSimpleBlock,
- block_start, block_size,
+ status = CreateBlock(libwebm::kMkvSimpleBlock, block_start, block_size,
0); // DiscardPadding
if (status != 0)
@@ -6299,14 +6517,14 @@
if (size == unknown_size)
return E_FILE_FORMAT_INVALID;
- if (id == mkvmuxer::kMkvDiscardPadding) {
+ if (id == libwebm::kMkvDiscardPadding) {
status = UnserializeInt(pReader, pos, size, discard_padding);
if (status < 0) // error
return status;
}
- if (id != mkvmuxer::kMkvBlock) {
+ if (id != libwebm::kMkvBlock) {
pos += size; // consume sub-part of block group
if (pos > payload_stop)
@@ -6399,8 +6617,8 @@
if (pos != payload_stop)
return E_FILE_FORMAT_INVALID;
- status = CreateBlock(mkvmuxer::kMkvBlockGroup,
- payload_start, payload_size, discard_padding);
+ status = CreateBlock(libwebm::kMkvBlockGroup, payload_start, payload_size,
+ discard_padding);
if (status != 0)
return status;
@@ -6565,7 +6783,7 @@
if (id < 0) // error
return static_cast<long>(id);
- if (id != mkvmuxer::kMkvCluster)
+ if (id != libwebm::kMkvCluster)
return E_PARSE_FAILED;
pos += len; // consume Cluster ID field
@@ -6653,10 +6871,10 @@
// that we have exhausted the sub-element's inside the cluster
// whose ID we parsed earlier.
- if (id == mkvmuxer::kMkvCluster)
+ if (id == libwebm::kMkvCluster)
return 0; // no entries found
- if (id == mkvmuxer::kMkvCues)
+ if (id == libwebm::kMkvCues)
return 0; // no entries found
pos += len; // consume id field
@@ -6708,10 +6926,10 @@
if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
return E_FILE_FORMAT_INVALID;
- if (id == mkvmuxer::kMkvBlockGroup)
+ if (id == libwebm::kMkvBlockGroup)
return 1; // have at least one entry
- if (id == mkvmuxer::kMkvSimpleBlock)
+ if (id == libwebm::kMkvSimpleBlock)
return 1; // have at least one entry
pos += size; // consume payload
@@ -6786,7 +7004,7 @@
long Cluster::CreateBlock(long long id,
long long pos, // absolute pos of payload
long long size, long long discard_padding) {
- if (id != mkvmuxer::kMkvBlockGroup && id != mkvmuxer::kMkvSimpleBlock)
+ if (id != libwebm::kMkvBlockGroup && id != libwebm::kMkvSimpleBlock)
return E_PARSE_FAILED;
if (m_entries_count < 0) { // haven't parsed anything yet
@@ -6826,7 +7044,7 @@
}
}
- if (id == mkvmuxer::kMkvBlockGroup)
+ if (id == libwebm::kMkvBlockGroup)
return CreateBlockGroup(pos, size, discard_padding);
else
return CreateSimpleBlock(pos, size);
@@ -6871,12 +7089,12 @@
pos += len; // consume size
- if (id == mkvmuxer::kMkvBlock) {
+ if (id == libwebm::kMkvBlock) {
if (bpos < 0) { // Block ID
bpos = pos;
bsize = size;
}
- } else if (id == mkvmuxer::kMkvBlockDuration) {
+ } else if (id == libwebm::kMkvBlockDuration) {
if (size > 8)
return E_FILE_FORMAT_INVALID;
@@ -6884,7 +7102,7 @@
if (duration < 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == mkvmuxer::kMkvReferenceBlock) {
+ } else if (id == libwebm::kMkvReferenceBlock) {
if (size > 8 || size <= 0)
return E_FILE_FORMAT_INVALID;
const long size_ = static_cast<long>(size);
@@ -7231,7 +7449,6 @@
BlockEntry::BlockEntry(Cluster* p, long idx) : m_pCluster(p), m_index(idx) {}
BlockEntry::~BlockEntry() {}
-bool BlockEntry::EOS() const { return (GetKind() == kBlockEOS); }
const Cluster* BlockEntry::GetCluster() const { return m_pCluster; }
long BlockEntry::GetIndex() const { return m_index; }
@@ -7555,7 +7772,6 @@
if (pf >= pf_end)
return E_FILE_FORMAT_INVALID;
-
const Frame& prev = *pf++;
assert(prev.len == frame_size);
if (prev.len != frame_size)
@@ -7581,7 +7797,7 @@
if (pos > stop)
return E_FILE_FORMAT_INVALID;
- const int exp = 7 * len - 1;
+ const long exp = 7 * len - 1;
const long long bias = (1LL << exp) - 1LL;
const long long delta_size = delta_size_ - bias;
@@ -7721,4 +7937,4 @@
long long Block::GetDiscardPadding() const { return m_discard_padding; }
-} // end namespace mkvparser
+} // namespace mkvparser
diff --git a/third_party/libwebm/mkvparser.hpp b/third_party/libwebm/mkvparser/mkvparser.h
similarity index 89%
rename from third_party/libwebm/mkvparser.hpp
rename to third_party/libwebm/mkvparser/mkvparser.h
index 75ef69d..42e6e88 100644
--- a/third_party/libwebm/mkvparser.hpp
+++ b/third_party/libwebm/mkvparser/mkvparser.h
@@ -5,13 +5,10 @@
// 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 MKVPARSER_HPP
-#define MKVPARSER_HPP
+#ifndef MKVPARSER_MKVPARSER_H_
+#define MKVPARSER_MKVPARSER_H_
#include <cstddef>
-#include <cstdio>
-#include <cstdlib>
namespace mkvparser {
@@ -28,8 +25,9 @@
virtual ~IMkvReader();
};
-template<typename Type> Type* SafeArrayAlloc(unsigned long long num_elements,
- unsigned long long element_size);
+template <typename Type>
+Type* SafeArrayAlloc(unsigned long long num_elements,
+ unsigned long long element_size);
long long GetUIntLength(IMkvReader*, long long, long&);
long long ReadUInt(IMkvReader*, long long, long&);
long long ReadID(IMkvReader* pReader, long long pos, long& len);
@@ -128,7 +126,7 @@
public:
virtual ~BlockEntry();
- bool EOS() const;
+ bool EOS() const { return (GetKind() == kBlockEOS); }
const Cluster* GetCluster() const;
long GetIndex() const;
virtual const Block* GetBlock() const = 0;
@@ -391,6 +389,90 @@
ContentEncoding** content_encoding_entries_end_;
};
+struct PrimaryChromaticity {
+ PrimaryChromaticity() : x(0), y(0) {}
+ ~PrimaryChromaticity() {}
+ static bool Parse(IMkvReader* reader, long long read_pos,
+ long long value_size, bool is_x,
+ PrimaryChromaticity** chromaticity);
+ float x;
+ float y;
+};
+
+struct MasteringMetadata {
+ static const float kValueNotPresent;
+
+ MasteringMetadata()
+ : r(NULL),
+ g(NULL),
+ b(NULL),
+ white_point(NULL),
+ luminance_max(kValueNotPresent),
+ luminance_min(kValueNotPresent) {}
+ ~MasteringMetadata() {
+ delete r;
+ delete g;
+ delete b;
+ delete white_point;
+ }
+
+ static bool Parse(IMkvReader* reader, long long element_start,
+ long long element_size,
+ MasteringMetadata** mastering_metadata);
+
+ PrimaryChromaticity* r;
+ PrimaryChromaticity* g;
+ PrimaryChromaticity* b;
+ PrimaryChromaticity* white_point;
+ float luminance_max;
+ float luminance_min;
+};
+
+struct Colour {
+ static const long long kValueNotPresent;
+
+ // Unless otherwise noted all values assigned upon construction are the
+ // equivalent of unspecified/default.
+ Colour()
+ : matrix_coefficients(kValueNotPresent),
+ bits_per_channel(kValueNotPresent),
+ chroma_subsampling_horz(kValueNotPresent),
+ chroma_subsampling_vert(kValueNotPresent),
+ cb_subsampling_horz(kValueNotPresent),
+ cb_subsampling_vert(kValueNotPresent),
+ chroma_siting_horz(kValueNotPresent),
+ chroma_siting_vert(kValueNotPresent),
+ range(kValueNotPresent),
+ transfer_characteristics(kValueNotPresent),
+ primaries(kValueNotPresent),
+ max_cll(kValueNotPresent),
+ max_fall(kValueNotPresent),
+ mastering_metadata(NULL) {}
+ ~Colour() {
+ delete mastering_metadata;
+ mastering_metadata = NULL;
+ }
+
+ static bool Parse(IMkvReader* reader, long long element_start,
+ long long element_size, Colour** colour);
+
+ long long matrix_coefficients;
+ long long bits_per_channel;
+ long long chroma_subsampling_horz;
+ long long chroma_subsampling_vert;
+ long long cb_subsampling_horz;
+ long long cb_subsampling_vert;
+ long long chroma_siting_horz;
+ long long chroma_siting_vert;
+ long long range;
+ long long transfer_characteristics;
+ long long primaries;
+ long long max_cll;
+ long long max_fall;
+
+ MasteringMetadata* mastering_metadata;
+};
+
class VideoTrack : public Track {
VideoTrack(const VideoTrack&);
VideoTrack& operator=(const VideoTrack&);
@@ -398,6 +480,7 @@
VideoTrack(Segment*, long long element_start, long long element_size);
public:
+ virtual ~VideoTrack();
static long Parse(Segment*, const Info&, long long element_start,
long long element_size, VideoTrack*&);
@@ -412,6 +495,8 @@
bool VetEntry(const BlockEntry*) const;
long Seek(long long time_ns, const BlockEntry*&) const;
+ Colour* GetColour() const;
+
private:
long long m_width;
long long m_height;
@@ -421,6 +506,8 @@
long long m_stereo_mode;
double m_rate;
+
+ Colour* m_colour;
};
class AudioTrack : public Track {
@@ -1013,7 +1100,7 @@
const BlockEntry* GetBlock(const CuePoint&, const CuePoint::TrackPosition&);
};
-} // end namespace mkvparser
+} // namespace mkvparser
inline long mkvparser::Segment::LoadCluster() {
long long pos;
@@ -1022,4 +1109,4 @@
return LoadCluster(pos, size);
}
-#endif // MKVPARSER_HPP
+#endif // MKVPARSER_MKVPARSER_H_
diff --git a/third_party/libwebm/mkvreader.cpp b/third_party/libwebm/mkvparser/mkvreader.cc
similarity index 96%
rename from third_party/libwebm/mkvreader.cpp
rename to third_party/libwebm/mkvparser/mkvreader.cc
index eaf9e0a..9f90d8c 100644
--- a/third_party/libwebm/mkvreader.cpp
+++ b/third_party/libwebm/mkvparser/mkvreader.cc
@@ -5,8 +5,7 @@
// 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 "mkvreader.hpp"
+#include "mkvparser/mkvreader.h"
#include <cassert>
@@ -129,4 +128,4 @@
return 0; // success
}
-} // end namespace mkvparser
+} // namespace mkvparser
\ No newline at end of file
diff --git a/third_party/libwebm/mkvreader.hpp b/third_party/libwebm/mkvparser/mkvreader.h
similarity index 86%
rename from third_party/libwebm/mkvreader.hpp
rename to third_party/libwebm/mkvparser/mkvreader.h
index 82ebad5..9831ecf 100644
--- a/third_party/libwebm/mkvreader.hpp
+++ b/third_party/libwebm/mkvparser/mkvreader.h
@@ -5,13 +5,13 @@
// 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 MKVPARSER_MKVREADER_H_
+#define MKVPARSER_MKVREADER_H_
-#ifndef MKVREADER_HPP
-#define MKVREADER_HPP
-
-#include "mkvparser.hpp"
#include <cstdio>
+#include "mkvparser/mkvparser.h"
+
namespace mkvparser {
class MkvReader : public IMkvReader {
@@ -40,6 +40,6 @@
bool reader_owns_file_;
};
-} // end namespace mkvparser
+} // namespace mkvparser
-#endif // MKVREADER_HPP
+#endif // MKVPARSER_MKVREADER_H_
diff --git a/vp10/common/blockd.h b/vp10/common/blockd.h
index 4ed7f81..fbcba09 100644
--- a/vp10/common/blockd.h
+++ b/vp10/common/blockd.h
@@ -705,7 +705,11 @@
#if CONFIG_OBMC
static INLINE int is_obmc_allowed(const MB_MODE_INFO *mbmi) {
+#if CONFIG_EXT_INTER
+ return (mbmi->sb_type >= BLOCK_8X8 && mbmi->ref_frame[1] != INTRA_FRAME);
+#else
return (mbmi->sb_type >= BLOCK_8X8);
+#endif // CONFIG_EXT_INTER
}
static INLINE int is_neighbor_overlappable(const MB_MODE_INFO *mbmi) {
diff --git a/vp10/common/idct.c b/vp10/common/idct.c
index b06a5e9..b7da81b 100644
--- a/vp10/common/idct.c
+++ b/vp10/common/idct.c
@@ -24,11 +24,7 @@
(void) tx_type;
#if CONFIG_VP9_HIGHBITDEPTH
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
- if (xd->bd == BITDEPTH_10) {
- return 0;
- } else {
- return tx_size == TX_32X32;
- }
+ return tx_size == TX_32X32;
}
#else
(void)xd;
@@ -1306,16 +1302,20 @@
switch (tx_type) {
case DCT_DCT:
- if (bd == BITDEPTH_10)
- vp10_inv_txfm2d_add_4x4(input, CONVERT_TO_SHORTPTR(dest), stride,
- &inv_txfm_2d_cfg_dct_dct_4, bd);
- else
- vp10_highbd_idct4x4_add(input, dest, stride, eob, bd);
+ vp10_inv_txfm2d_add_4x4(input, CONVERT_TO_SHORTPTR(dest), stride,
+ &inv_txfm_2d_cfg_dct_dct_4, bd);
break;
case ADST_DCT:
+ vp10_inv_txfm2d_add_4x4(input, CONVERT_TO_SHORTPTR(dest), stride,
+ &inv_txfm_2d_cfg_adst_dct_4, bd);
+ break;
case DCT_ADST:
+ vp10_inv_txfm2d_add_4x4(input, CONVERT_TO_SHORTPTR(dest), stride,
+ &inv_txfm_2d_cfg_dct_adst_4, bd);
+ break;
case ADST_ADST:
- vp10_highbd_iht4x4_16_add(input, dest, stride, tx_type, bd);
+ vp10_inv_txfm2d_add_4x4(input, CONVERT_TO_SHORTPTR(dest), stride,
+ &inv_txfm_2d_cfg_adst_adst_4, bd);
break;
#if CONFIG_EXT_TX
case FLIPADST_DCT:
@@ -1347,18 +1347,23 @@
void vp10_highbd_inv_txfm_add_8x8(const tran_low_t *input, uint8_t *dest,
int stride, int eob, int bd,
TX_TYPE tx_type) {
+ (void)eob;
switch (tx_type) {
case DCT_DCT:
- if (bd == BITDEPTH_10)
- vp10_inv_txfm2d_add_8x8(input, CONVERT_TO_SHORTPTR(dest), stride,
- &inv_txfm_2d_cfg_dct_dct_8, bd);
- else
- vp10_highbd_idct8x8_add(input, dest, stride, eob, bd);
+ vp10_inv_txfm2d_add_8x8(input, CONVERT_TO_SHORTPTR(dest), stride,
+ &inv_txfm_2d_cfg_dct_dct_8, bd);
break;
case ADST_DCT:
+ vp10_inv_txfm2d_add_8x8(input, CONVERT_TO_SHORTPTR(dest), stride,
+ &inv_txfm_2d_cfg_adst_dct_8, bd);
+ break;
case DCT_ADST:
+ vp10_inv_txfm2d_add_8x8(input, CONVERT_TO_SHORTPTR(dest), stride,
+ &inv_txfm_2d_cfg_dct_adst_8, bd);
+ break;
case ADST_ADST:
- vp10_highbd_iht8x8_64_add(input, dest, stride, tx_type, bd);
+ vp10_inv_txfm2d_add_8x8(input, CONVERT_TO_SHORTPTR(dest), stride,
+ &inv_txfm_2d_cfg_adst_adst_8, bd);
break;
#if CONFIG_EXT_TX
case FLIPADST_DCT:
@@ -1390,18 +1395,23 @@
void vp10_highbd_inv_txfm_add_16x16(const tran_low_t *input, uint8_t *dest,
int stride, int eob, int bd,
TX_TYPE tx_type) {
+ (void)eob;
switch (tx_type) {
case DCT_DCT:
- if (bd == BITDEPTH_10)
- vp10_inv_txfm2d_add_16x16(input, CONVERT_TO_SHORTPTR(dest), stride,
- &inv_txfm_2d_cfg_dct_dct_16, bd);
- else
- vp10_highbd_idct16x16_add(input, dest, stride, eob, bd);
+ vp10_inv_txfm2d_add_16x16(input, CONVERT_TO_SHORTPTR(dest), stride,
+ &inv_txfm_2d_cfg_dct_dct_16, bd);
break;
case ADST_DCT:
+ vp10_inv_txfm2d_add_16x16(input, CONVERT_TO_SHORTPTR(dest), stride,
+ &inv_txfm_2d_cfg_adst_dct_16, bd);
+ break;
case DCT_ADST:
+ vp10_inv_txfm2d_add_16x16(input, CONVERT_TO_SHORTPTR(dest), stride,
+ &inv_txfm_2d_cfg_dct_adst_16, bd);
+ break;
case ADST_ADST:
- vp10_highbd_iht16x16_256_add(input, dest, stride, tx_type, bd);
+ vp10_inv_txfm2d_add_16x16(input, CONVERT_TO_SHORTPTR(dest), stride,
+ &inv_txfm_2d_cfg_adst_adst_16, bd);
break;
#if CONFIG_EXT_TX
case FLIPADST_DCT:
@@ -1433,13 +1443,11 @@
void vp10_highbd_inv_txfm_add_32x32(const tran_low_t *input, uint8_t *dest,
int stride, int eob, int bd,
TX_TYPE tx_type) {
+ (void)eob;
switch (tx_type) {
case DCT_DCT:
- if (bd == BITDEPTH_10)
- vp10_inv_txfm2d_add_32x32(input, CONVERT_TO_SHORTPTR(dest), stride,
- &inv_txfm_2d_cfg_dct_dct_32, bd);
- else
- vp10_highbd_idct32x32_add(input, dest, stride, eob, bd);
+ vp10_inv_txfm2d_add_32x32(input, CONVERT_TO_SHORTPTR(dest), stride,
+ &inv_txfm_2d_cfg_dct_dct_32, bd);
break;
#if CONFIG_EXT_TX
case ADST_DCT:
diff --git a/vp10/common/mvref_common.c b/vp10/common/mvref_common.c
index 7c6633f..3023589 100644
--- a/vp10/common/mvref_common.c
+++ b/vp10/common/mvref_common.c
@@ -61,6 +61,8 @@
int alt_block = 3 - block;
this_refmv =
get_sub_block_mv(candidate_mi, ref, col, alt_block);
+ lower_mv_precision(&this_refmv.as_mv, use_hp);
+
for (index = 0; index < *refmv_count; ++index)
if (ref_mv_stack[index].this_mv.as_int == this_refmv.as_int)
break;
@@ -95,6 +97,9 @@
get_sub_block_mv(candidate_mi, 1, col, block)
};
+ for (ref = 0; ref < 2; ++ref)
+ lower_mv_precision(&this_refmv[ref].as_mv, use_hp);
+
for (index = 0; index < *refmv_count; ++index)
if ((ref_mv_stack[index].this_mv.as_int == this_refmv[0].as_int) &&
(ref_mv_stack[index].comp_mv.as_int == this_refmv[1].as_int))
@@ -123,6 +128,9 @@
this_refmv[0] = get_sub_block_mv(candidate_mi, 0, col, alt_block);
this_refmv[1] = get_sub_block_mv(candidate_mi, 1, col, alt_block);
+ for (ref = 0; ref < 2; ++ref)
+ lower_mv_precision(&this_refmv[ref].as_mv, use_hp);
+
for (index = 0; index < *refmv_count; ++index)
if (ref_mv_stack[index].this_mv.as_int == this_refmv[0].as_int &&
ref_mv_stack[index].comp_mv.as_int == this_refmv[1].as_int)
diff --git a/vp10/common/scan.c b/vp10/common/scan.c
index 9fef038..8cfeb97 100644
--- a/vp10/common/scan.c
+++ b/vp10/common/scan.c
@@ -787,10 +787,8 @@
};
#endif // CONFIG_EXT_TX
-// Neighborhood 5-tuples for various scans and blocksizes,
-// in {top, left, topleft, topright, bottomleft} order
-// for each position in raster scan order.
-// -1 indicates the neighbor does not exist.
+// Neighborhood 2-tuples for various scans and blocksizes,
+// in {top, left} order for each position in corresponding scan order.
DECLARE_ALIGNED(16, static const int16_t,
default_scan_4x4_neighbors[17 * MAX_NEIGHBORS]) = {
0, 0, 0, 0, 4, 0, 1, 4, 4, 5, 5, 1,
@@ -2964,7 +2962,7 @@
{default_scan_4x4, vp10_default_iscan_4x4, default_scan_4x4_neighbors},
{default_scan_4x4, vp10_default_iscan_4x4, default_scan_4x4_neighbors},
{default_scan_4x4, vp10_default_iscan_4x4, default_scan_4x4_neighbors},
- {default_scan_4x4, vp10_default_iscan_4x4, default_scan_4x4_neighbors},
+ {mrow_scan_4x4, vp10_mrow_iscan_4x4, mrow_scan_4x4_neighbors},
{row_scan_4x4, vp10_row_iscan_4x4, row_scan_4x4_neighbors},
{col_scan_4x4, vp10_col_iscan_4x4, col_scan_4x4_neighbors},
{row_scan_4x4, vp10_row_iscan_4x4, row_scan_4x4_neighbors},
@@ -2981,7 +2979,7 @@
{default_scan_8x8, vp10_default_iscan_8x8, default_scan_8x8_neighbors},
{default_scan_8x8, vp10_default_iscan_8x8, default_scan_8x8_neighbors},
{default_scan_8x8, vp10_default_iscan_8x8, default_scan_8x8_neighbors},
- {default_scan_8x8, vp10_default_iscan_8x8, default_scan_8x8_neighbors},
+ {mrow_scan_8x8, vp10_mrow_iscan_8x8, mrow_scan_8x8_neighbors},
{row_scan_8x8, vp10_row_iscan_8x8, row_scan_8x8_neighbors},
{col_scan_8x8, vp10_col_iscan_8x8, col_scan_8x8_neighbors},
{row_scan_8x8, vp10_row_iscan_8x8, row_scan_8x8_neighbors},
@@ -3005,8 +3003,7 @@
default_scan_16x16_neighbors},
{default_scan_16x16, vp10_default_iscan_16x16,
default_scan_16x16_neighbors},
- {default_scan_16x16, vp10_default_iscan_16x16,
- default_scan_16x16_neighbors},
+ {mrow_scan_16x16, vp10_mrow_iscan_16x16, mrow_scan_16x16_neighbors},
{row_scan_16x16, vp10_row_iscan_16x16, row_scan_16x16_neighbors},
{col_scan_16x16, vp10_col_iscan_16x16, col_scan_16x16_neighbors},
{row_scan_16x16, vp10_row_iscan_16x16, row_scan_16x16_neighbors},
@@ -3032,8 +3029,7 @@
qtr_scan_32x32_neighbors},
{qtr_scan_32x32, vp10_qtr_iscan_32x32,
qtr_scan_32x32_neighbors},
- {default_scan_32x32, vp10_default_iscan_32x32,
- default_scan_32x32_neighbors},
+ {mrow_scan_32x32, vp10_mrow_iscan_32x32, mrow_scan_32x32_neighbors},
{mrow_scan_32x32, vp10_mrow_iscan_32x32, mrow_scan_32x32_neighbors},
{mcol_scan_32x32, vp10_mcol_iscan_32x32, mcol_scan_32x32_neighbors},
{mrow_scan_32x32, vp10_mrow_iscan_32x32, mrow_scan_32x32_neighbors},
@@ -3054,7 +3050,7 @@
{default_scan_4x4, vp10_default_iscan_4x4, default_scan_4x4_neighbors},
{default_scan_4x4, vp10_default_iscan_4x4, default_scan_4x4_neighbors},
{default_scan_4x4, vp10_default_iscan_4x4, default_scan_4x4_neighbors},
- {default_scan_4x4, vp10_default_iscan_4x4, default_scan_4x4_neighbors},
+ {mrow_scan_4x4, vp10_mrow_iscan_4x4, mrow_scan_4x4_neighbors},
{mrow_scan_4x4, vp10_mrow_iscan_4x4, mrow_scan_4x4_neighbors},
{mcol_scan_4x4, vp10_mcol_iscan_4x4, mcol_scan_4x4_neighbors},
{mrow_scan_4x4, vp10_mrow_iscan_4x4, mrow_scan_4x4_neighbors},
@@ -3071,7 +3067,7 @@
{default_scan_8x8, vp10_default_iscan_8x8, default_scan_8x8_neighbors},
{default_scan_8x8, vp10_default_iscan_8x8, default_scan_8x8_neighbors},
{default_scan_8x8, vp10_default_iscan_8x8, default_scan_8x8_neighbors},
- {default_scan_8x8, vp10_default_iscan_8x8, default_scan_8x8_neighbors},
+ {mrow_scan_8x8, vp10_mrow_iscan_8x8, mrow_scan_8x8_neighbors},
{mrow_scan_8x8, vp10_mrow_iscan_8x8, mrow_scan_8x8_neighbors},
{mcol_scan_8x8, vp10_mcol_iscan_8x8, mcol_scan_8x8_neighbors},
{mrow_scan_8x8, vp10_mrow_iscan_8x8, mrow_scan_8x8_neighbors},
@@ -3097,8 +3093,7 @@
default_scan_16x16_neighbors},
{default_scan_16x16, vp10_default_iscan_16x16,
default_scan_16x16_neighbors},
- {default_scan_16x16, vp10_default_iscan_16x16,
- default_scan_16x16_neighbors},
+ {mrow_scan_16x16, vp10_mrow_iscan_16x16, mrow_scan_16x16_neighbors},
{mrow_scan_16x16, vp10_mrow_iscan_16x16, mrow_scan_16x16_neighbors},
{mcol_scan_16x16, vp10_mcol_iscan_16x16, mcol_scan_16x16_neighbors},
{mrow_scan_16x16, vp10_mrow_iscan_16x16, mrow_scan_16x16_neighbors},
@@ -3124,8 +3119,7 @@
qtr_scan_32x32_neighbors},
{qtr_scan_32x32, vp10_qtr_iscan_32x32,
qtr_scan_32x32_neighbors},
- {default_scan_32x32, vp10_default_iscan_32x32,
- default_scan_32x32_neighbors},
+ {mrow_scan_32x32, vp10_mrow_iscan_32x32, mrow_scan_32x32_neighbors},
{mrow_scan_32x32, vp10_mrow_iscan_32x32, mrow_scan_32x32_neighbors},
{mcol_scan_32x32, vp10_mcol_iscan_32x32, mcol_scan_32x32_neighbors},
{mrow_scan_32x32, vp10_mrow_iscan_32x32, mrow_scan_32x32_neighbors},
diff --git a/vp10/common/vp10_fwd_txfm2d.c b/vp10/common/vp10_fwd_txfm2d.c
index dd7101a..d54a174 100644
--- a/vp10/common/vp10_fwd_txfm2d.c
+++ b/vp10/common/vp10_fwd_txfm2d.c
@@ -11,9 +11,6 @@
#include "vp10/common/vp10_txfm.h"
#include "vp10/common/vp10_fwd_txfm1d.h"
-typedef void (*TxfmFunc)(const int32_t *input, int32_t *output,
- const int8_t *cos_bit, const int8_t *stage_range);
-
static inline TxfmFunc fwd_txfm_type_to_func(TXFM_TYPE txfm_type) {
switch (txfm_type) {
case TXFM_TYPE_DCT4:
diff --git a/vp10/common/vp10_fwd_txfm2d_cfg.h b/vp10/common/vp10_fwd_txfm2d_cfg.h
index 3c0a906..e8c82fd 100644
--- a/vp10/common/vp10_fwd_txfm2d_cfg.h
+++ b/vp10/common/vp10_fwd_txfm2d_cfg.h
@@ -12,16 +12,17 @@
#define VP10_FWD_TXFM2D_CFG_H_
#include "vp10/common/vp10_fwd_txfm1d.h"
// ---------------- config fwd_dct_dct_4 ----------------
-static const int8_t fwd_shift_dct_dct_4[3] = {4, 0, -2};
+static const int8_t fwd_shift_dct_dct_4[3] = {2, 0, 0};
static const int8_t fwd_stage_range_col_dct_dct_4[4] = {15, 16, 17, 17};
static const int8_t fwd_stage_range_row_dct_dct_4[4] = {17, 18, 18, 18};
-static const int8_t fwd_cos_bit_col_dct_dct_4[4] = {15, 15, 15, 15};
-static const int8_t fwd_cos_bit_row_dct_dct_4[4] = {15, 14, 14, 14};
+static const int8_t fwd_cos_bit_col_dct_dct_4[4] = {13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_dct_dct_4[4] = {13, 13, 13, 13};
static const TXFM_2D_CFG fwd_txfm_2d_cfg_dct_dct_4 = {
- 4, // .txfm_size
- 4, // .stage_num_col
- 4, // .stage_num_row
+ 4, // .txfm_size
+ 4, // .stage_num_col
+ 4, // .stage_num_row
+ // 0, // .log_scale
fwd_shift_dct_dct_4, // .shift
fwd_stage_range_col_dct_dct_4, // .stage_range_col
fwd_stage_range_row_dct_dct_4, // .stage_range_row
@@ -31,16 +32,17 @@
TXFM_TYPE_DCT4}; // .txfm_type_row
// ---------------- config fwd_dct_dct_8 ----------------
-static const int8_t fwd_shift_dct_dct_8[3] = {5, -3, -1};
-static const int8_t fwd_stage_range_col_dct_dct_8[6] = {16, 17, 18, 19, 19, 19};
-static const int8_t fwd_stage_range_row_dct_dct_8[6] = {16, 17, 18, 18, 18, 18};
-static const int8_t fwd_cos_bit_col_dct_dct_8[6] = {15, 15, 14, 13, 13, 13};
-static const int8_t fwd_cos_bit_row_dct_dct_8[6] = {15, 15, 14, 14, 14, 14};
+static const int8_t fwd_shift_dct_dct_8[3] = {2, -1, 0};
+static const int8_t fwd_stage_range_col_dct_dct_8[6] = {15, 16, 17, 18, 18, 18};
+static const int8_t fwd_stage_range_row_dct_dct_8[6] = {17, 18, 19, 19, 19, 19};
+static const int8_t fwd_cos_bit_col_dct_dct_8[6] = {13, 13, 13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_dct_dct_8[6] = {13, 13, 13, 13, 13, 13};
static const TXFM_2D_CFG fwd_txfm_2d_cfg_dct_dct_8 = {
- 8, // .txfm_size
- 6, // .stage_num_col
- 6, // .stage_num_row
+ 8, // .txfm_size
+ 6, // .stage_num_col
+ 6, // .stage_num_row
+ // 0, // .log_scale
fwd_shift_dct_dct_8, // .shift
fwd_stage_range_col_dct_dct_8, // .stage_range_col
fwd_stage_range_row_dct_dct_8, // .stage_range_row
@@ -50,20 +52,21 @@
TXFM_TYPE_DCT8}; // .txfm_type_row
// ---------------- config fwd_dct_dct_16 ----------------
-static const int8_t fwd_shift_dct_dct_16[3] = {4, -3, -1};
+static const int8_t fwd_shift_dct_dct_16[3] = {2, -2, 0};
static const int8_t fwd_stage_range_col_dct_dct_16[8] = {15, 16, 17, 18,
19, 19, 19, 19};
-static const int8_t fwd_stage_range_row_dct_dct_16[8] = {16, 17, 18, 19,
- 19, 19, 19, 19};
-static const int8_t fwd_cos_bit_col_dct_dct_16[8] = {15, 15, 15, 14,
+static const int8_t fwd_stage_range_row_dct_dct_16[8] = {17, 18, 19, 20,
+ 20, 20, 20, 20};
+static const int8_t fwd_cos_bit_col_dct_dct_16[8] = {13, 13, 13, 13,
13, 13, 13, 13};
-static const int8_t fwd_cos_bit_row_dct_dct_16[8] = {15, 15, 14, 13,
- 13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_dct_dct_16[8] = {12, 12, 12, 12,
+ 12, 12, 12, 12};
static const TXFM_2D_CFG fwd_txfm_2d_cfg_dct_dct_16 = {
- 16, // .txfm_size
- 8, // .stage_num_col
- 8, // .stage_num_row
+ 16, // .txfm_size
+ 8, // .stage_num_col
+ 8, // .stage_num_row
+ // 0, // .log_scale
fwd_shift_dct_dct_16, // .shift
fwd_stage_range_col_dct_dct_16, // .stage_range_col
fwd_stage_range_row_dct_dct_16, // .stage_range_row
@@ -73,20 +76,21 @@
TXFM_TYPE_DCT16}; // .txfm_type_row
// ---------------- config fwd_dct_dct_32 ----------------
-static const int8_t fwd_shift_dct_dct_32[3] = {3, -3, -1};
-static const int8_t fwd_stage_range_col_dct_dct_32[10] = {14, 15, 16, 17, 18,
- 19, 19, 19, 19, 19};
+static const int8_t fwd_shift_dct_dct_32[3] = {2, -4, 0};
+static const int8_t fwd_stage_range_col_dct_dct_32[10] = {15, 16, 17, 18, 19,
+ 20, 20, 20, 20, 20};
static const int8_t fwd_stage_range_row_dct_dct_32[10] = {16, 17, 18, 19, 20,
20, 20, 20, 20, 20};
-static const int8_t fwd_cos_bit_col_dct_dct_32[10] = {15, 15, 15, 15, 14,
- 13, 13, 13, 13, 13};
-static const int8_t fwd_cos_bit_row_dct_dct_32[10] = {15, 15, 14, 13, 12,
+static const int8_t fwd_cos_bit_col_dct_dct_32[10] = {12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12};
+static const int8_t fwd_cos_bit_row_dct_dct_32[10] = {12, 12, 12, 12, 12,
12, 12, 12, 12, 12};
static const TXFM_2D_CFG fwd_txfm_2d_cfg_dct_dct_32 = {
- 32, // .txfm_size
- 10, // .stage_num_col
- 10, // .stage_num_row
+ 32, // .txfm_size
+ 10, // .stage_num_col
+ 10, // .stage_num_row
+ // 1, // .log_scale
fwd_shift_dct_dct_32, // .shift
fwd_stage_range_col_dct_dct_32, // .stage_range_col
fwd_stage_range_row_dct_dct_32, // .stage_range_row
@@ -119,17 +123,18 @@
TXFM_TYPE_DCT64}; // .txfm_type_row
// ---------------- config fwd_dct_adst_4 ----------------
-static const int8_t fwd_shift_dct_adst_4[3] = {5, -2, -1};
-static const int8_t fwd_stage_range_col_dct_adst_4[4] = {16, 17, 18, 18};
-static const int8_t fwd_stage_range_row_dct_adst_4[6] = {16, 16, 16,
- 17, 17, 17};
-static const int8_t fwd_cos_bit_col_dct_adst_4[4] = {15, 15, 14, 14};
-static const int8_t fwd_cos_bit_row_dct_adst_4[6] = {15, 15, 15, 15, 15, 15};
+static const int8_t fwd_shift_dct_adst_4[3] = {2, 0, 0};
+static const int8_t fwd_stage_range_col_dct_adst_4[4] = {15, 16, 17, 17};
+static const int8_t fwd_stage_range_row_dct_adst_4[6] = {17, 17, 17,
+ 18, 18, 18};
+static const int8_t fwd_cos_bit_col_dct_adst_4[4] = {13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_dct_adst_4[6] = {13, 13, 13, 13, 13, 13};
static const TXFM_2D_CFG fwd_txfm_2d_cfg_dct_adst_4 = {
- 4, // .txfm_size
- 4, // .stage_num_col
- 6, // .stage_num_row
+ 4, // .txfm_size
+ 4, // .stage_num_col
+ 6, // .stage_num_row
+ // 0, // .log_scale
fwd_shift_dct_adst_4, // .shift
fwd_stage_range_col_dct_adst_4, // .stage_range_col
fwd_stage_range_row_dct_adst_4, // .stage_range_row
@@ -139,19 +144,20 @@
TXFM_TYPE_ADST4}; // .txfm_type_row
// ---------------- config fwd_dct_adst_8 ----------------
-static const int8_t fwd_shift_dct_adst_8[3] = {7, -3, -3};
-static const int8_t fwd_stage_range_col_dct_adst_8[6] = {18, 19, 20,
- 21, 21, 21};
-static const int8_t fwd_stage_range_row_dct_adst_8[8] = {18, 18, 18, 19,
- 19, 20, 20, 20};
-static const int8_t fwd_cos_bit_col_dct_adst_8[6] = {14, 13, 12, 11, 11, 11};
-static const int8_t fwd_cos_bit_row_dct_adst_8[8] = {14, 14, 14, 13,
- 13, 12, 12, 12};
+static const int8_t fwd_shift_dct_adst_8[3] = {2, -1, 0};
+static const int8_t fwd_stage_range_col_dct_adst_8[6] = {15, 16, 17,
+ 18, 18, 18};
+static const int8_t fwd_stage_range_row_dct_adst_8[8] = {17, 17, 17, 18,
+ 18, 19, 19, 19};
+static const int8_t fwd_cos_bit_col_dct_adst_8[6] = {13, 13, 13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_dct_adst_8[8] = {13, 13, 13, 13,
+ 13, 13, 13, 13};
static const TXFM_2D_CFG fwd_txfm_2d_cfg_dct_adst_8 = {
- 8, // .txfm_size
- 6, // .stage_num_col
- 8, // .stage_num_row
+ 8, // .txfm_size
+ 6, // .stage_num_col
+ 8, // .stage_num_row
+ // 0, // .log_scale
fwd_shift_dct_adst_8, // .shift
fwd_stage_range_col_dct_adst_8, // .stage_range_col
fwd_stage_range_row_dct_adst_8, // .stage_range_row
@@ -161,20 +167,21 @@
TXFM_TYPE_ADST8}; // .txfm_type_row
// ---------------- config fwd_dct_adst_16 ----------------
-static const int8_t fwd_shift_dct_adst_16[3] = {4, -1, -3};
+static const int8_t fwd_shift_dct_adst_16[3] = {2, -2, 0};
static const int8_t fwd_stage_range_col_dct_adst_16[8] = {15, 16, 17, 18,
19, 19, 19, 19};
-static const int8_t fwd_stage_range_row_dct_adst_16[10] = {18, 18, 18, 19, 19,
- 20, 20, 21, 21, 21};
-static const int8_t fwd_cos_bit_col_dct_adst_16[8] = {15, 15, 15, 14,
+static const int8_t fwd_stage_range_row_dct_adst_16[10] = {17, 17, 17, 18, 18,
+ 19, 19, 20, 20, 20};
+static const int8_t fwd_cos_bit_col_dct_adst_16[8] = {13, 13, 13, 13,
13, 13, 13, 13};
-static const int8_t fwd_cos_bit_row_dct_adst_16[10] = {14, 14, 14, 13, 13,
- 12, 12, 11, 11, 11};
+static const int8_t fwd_cos_bit_row_dct_adst_16[10] = {12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12};
static const TXFM_2D_CFG fwd_txfm_2d_cfg_dct_adst_16 = {
- 16, // .txfm_size
- 8, // .stage_num_col
- 10, // .stage_num_row
+ 16, // .txfm_size
+ 8, // .stage_num_col
+ 10, // .stage_num_row
+ // 0, // .log_scale
fwd_shift_dct_adst_16, // .shift
fwd_stage_range_col_dct_adst_16, // .stage_range_col
fwd_stage_range_row_dct_adst_16, // .stage_range_row
@@ -184,20 +191,21 @@
TXFM_TYPE_ADST16}; // .txfm_type_row
// ---------------- config fwd_dct_adst_32 ----------------
-static const int8_t fwd_shift_dct_adst_32[3] = {3, -1, -3};
-static const int8_t fwd_stage_range_col_dct_adst_32[10] = {14, 15, 16, 17, 18,
- 19, 19, 19, 19, 19};
+static const int8_t fwd_shift_dct_adst_32[3] = {2, -4, 0};
+static const int8_t fwd_stage_range_col_dct_adst_32[10] = {15, 16, 17, 18, 19,
+ 20, 20, 20, 20, 20};
static const int8_t fwd_stage_range_row_dct_adst_32[12] = {
- 18, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 22};
-static const int8_t fwd_cos_bit_col_dct_adst_32[10] = {15, 15, 15, 15, 14,
- 13, 13, 13, 13, 13};
-static const int8_t fwd_cos_bit_row_dct_adst_32[12] = {14, 14, 14, 13, 13, 12,
- 12, 11, 11, 10, 10, 10};
+ 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 20};
+static const int8_t fwd_cos_bit_col_dct_adst_32[10] = {12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12};
+static const int8_t fwd_cos_bit_row_dct_adst_32[12] = {12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12};
static const TXFM_2D_CFG fwd_txfm_2d_cfg_dct_adst_32 = {
- 32, // .txfm_size
- 10, // .stage_num_col
- 12, // .stage_num_row
+ 32, // .txfm_size
+ 10, // .stage_num_col
+ 12, // .stage_num_row
+ // 1, // .log_scale
fwd_shift_dct_adst_32, // .shift
fwd_stage_range_col_dct_adst_32, // .stage_range_col
fwd_stage_range_row_dct_adst_32, // .stage_range_row
@@ -205,20 +213,20 @@
fwd_cos_bit_row_dct_adst_32, // .cos_bit_row
TXFM_TYPE_DCT32, // .txfm_type_col
TXFM_TYPE_ADST32}; // .txfm_type_row
-
// ---------------- config fwd_adst_adst_4 ----------------
-static const int8_t fwd_shift_adst_adst_4[3] = {6, 1, -5};
-static const int8_t fwd_stage_range_col_adst_adst_4[6] = {17, 17, 18,
- 19, 19, 19};
-static const int8_t fwd_stage_range_row_adst_adst_4[6] = {20, 20, 20,
- 21, 21, 21};
-static const int8_t fwd_cos_bit_col_adst_adst_4[6] = {15, 15, 14, 13, 13, 13};
-static const int8_t fwd_cos_bit_row_adst_adst_4[6] = {12, 12, 12, 11, 11, 11};
+static const int8_t fwd_shift_adst_adst_4[3] = {2, 0, 0};
+static const int8_t fwd_stage_range_col_adst_adst_4[6] = {15, 15, 16,
+ 17, 17, 17};
+static const int8_t fwd_stage_range_row_adst_adst_4[6] = {17, 17, 17,
+ 18, 18, 18};
+static const int8_t fwd_cos_bit_col_adst_adst_4[6] = {13, 13, 13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_adst_adst_4[6] = {13, 13, 13, 13, 13, 13};
static const TXFM_2D_CFG fwd_txfm_2d_cfg_adst_adst_4 = {
- 4, // .txfm_size
- 6, // .stage_num_col
- 6, // .stage_num_row
+ 4, // .txfm_size
+ 6, // .stage_num_col
+ 6, // .stage_num_row
+ // 0, // .log_scale
fwd_shift_adst_adst_4, // .shift
fwd_stage_range_col_adst_adst_4, // .stage_range_col
fwd_stage_range_row_adst_adst_4, // .stage_range_row
@@ -228,20 +236,21 @@
TXFM_TYPE_ADST4}; // .txfm_type_row
// ---------------- config fwd_adst_adst_8 ----------------
-static const int8_t fwd_shift_adst_adst_8[3] = {3, -1, -1};
-static const int8_t fwd_stage_range_col_adst_adst_8[8] = {14, 14, 15, 16,
- 16, 17, 17, 17};
-static const int8_t fwd_stage_range_row_adst_adst_8[8] = {16, 16, 16, 17,
+static const int8_t fwd_shift_adst_adst_8[3] = {2, -1, 0};
+static const int8_t fwd_stage_range_col_adst_adst_8[8] = {15, 15, 16, 17,
17, 18, 18, 18};
-static const int8_t fwd_cos_bit_col_adst_adst_8[8] = {15, 15, 15, 15,
- 15, 15, 15, 15};
-static const int8_t fwd_cos_bit_row_adst_adst_8[8] = {15, 15, 15, 15,
- 15, 14, 14, 14};
+static const int8_t fwd_stage_range_row_adst_adst_8[8] = {17, 17, 17, 18,
+ 18, 19, 19, 19};
+static const int8_t fwd_cos_bit_col_adst_adst_8[8] = {13, 13, 13, 13,
+ 13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_adst_adst_8[8] = {13, 13, 13, 13,
+ 13, 13, 13, 13};
static const TXFM_2D_CFG fwd_txfm_2d_cfg_adst_adst_8 = {
- 8, // .txfm_size
- 8, // .stage_num_col
- 8, // .stage_num_row
+ 8, // .txfm_size
+ 8, // .stage_num_col
+ 8, // .stage_num_row
+ // 0, // .log_scale
fwd_shift_adst_adst_8, // .shift
fwd_stage_range_col_adst_adst_8, // .stage_range_col
fwd_stage_range_row_adst_adst_8, // .stage_range_row
@@ -251,20 +260,21 @@
TXFM_TYPE_ADST8}; // .txfm_type_row
// ---------------- config fwd_adst_adst_16 ----------------
-static const int8_t fwd_shift_adst_adst_16[3] = {2, 0, -2};
-static const int8_t fwd_stage_range_col_adst_adst_16[10] = {13, 13, 14, 15, 15,
- 16, 16, 17, 17, 17};
+static const int8_t fwd_shift_adst_adst_16[3] = {2, -2, 0};
+static const int8_t fwd_stage_range_col_adst_adst_16[10] = {15, 15, 16, 17, 17,
+ 18, 18, 19, 19, 19};
static const int8_t fwd_stage_range_row_adst_adst_16[10] = {17, 17, 17, 18, 18,
19, 19, 20, 20, 20};
-static const int8_t fwd_cos_bit_col_adst_adst_16[10] = {15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15};
-static const int8_t fwd_cos_bit_row_adst_adst_16[10] = {15, 15, 15, 14, 14,
- 13, 13, 12, 12, 12};
+static const int8_t fwd_cos_bit_col_adst_adst_16[10] = {13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_adst_adst_16[10] = {12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12};
static const TXFM_2D_CFG fwd_txfm_2d_cfg_adst_adst_16 = {
- 16, // .txfm_size
- 10, // .stage_num_col
- 10, // .stage_num_row
+ 16, // .txfm_size
+ 10, // .stage_num_col
+ 10, // .stage_num_row
+ // 0, // .log_scale
fwd_shift_adst_adst_16, // .shift
fwd_stage_range_col_adst_adst_16, // .stage_range_col
fwd_stage_range_row_adst_adst_16, // .stage_range_row
@@ -274,20 +284,21 @@
TXFM_TYPE_ADST16}; // .txfm_type_row
// ---------------- config fwd_adst_adst_32 ----------------
-static const int8_t fwd_shift_adst_adst_32[3] = {4, -2, -3};
+static const int8_t fwd_shift_adst_adst_32[3] = {2, -4, 0};
static const int8_t fwd_stage_range_col_adst_adst_32[12] = {
15, 15, 16, 17, 17, 18, 18, 19, 19, 20, 20, 20};
static const int8_t fwd_stage_range_row_adst_adst_32[12] = {
- 18, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 22};
-static const int8_t fwd_cos_bit_col_adst_adst_32[12] = {15, 15, 15, 15, 15, 14,
- 14, 13, 13, 12, 12, 12};
-static const int8_t fwd_cos_bit_row_adst_adst_32[12] = {14, 14, 14, 13, 13, 12,
- 12, 11, 11, 10, 10, 10};
+ 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 20};
+static const int8_t fwd_cos_bit_col_adst_adst_32[12] = {12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12};
+static const int8_t fwd_cos_bit_row_adst_adst_32[12] = {12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12};
static const TXFM_2D_CFG fwd_txfm_2d_cfg_adst_adst_32 = {
- 32, // .txfm_size
- 12, // .stage_num_col
- 12, // .stage_num_row
+ 32, // .txfm_size
+ 12, // .stage_num_col
+ 12, // .stage_num_row
+ // 1, // .log_scale
fwd_shift_adst_adst_32, // .shift
fwd_stage_range_col_adst_adst_32, // .stage_range_col
fwd_stage_range_row_adst_adst_32, // .stage_range_row
@@ -297,17 +308,18 @@
TXFM_TYPE_ADST32}; // .txfm_type_row
// ---------------- config fwd_adst_dct_4 ----------------
-static const int8_t fwd_shift_adst_dct_4[3] = {5, -4, 1};
-static const int8_t fwd_stage_range_col_adst_dct_4[6] = {16, 16, 17,
- 18, 18, 18};
-static const int8_t fwd_stage_range_row_adst_dct_4[4] = {14, 15, 15, 15};
-static const int8_t fwd_cos_bit_col_adst_dct_4[6] = {15, 15, 15, 14, 14, 14};
-static const int8_t fwd_cos_bit_row_adst_dct_4[4] = {15, 15, 15, 15};
+static const int8_t fwd_shift_adst_dct_4[3] = {2, 0, 0};
+static const int8_t fwd_stage_range_col_adst_dct_4[6] = {15, 15, 16,
+ 17, 17, 17};
+static const int8_t fwd_stage_range_row_adst_dct_4[4] = {17, 18, 18, 18};
+static const int8_t fwd_cos_bit_col_adst_dct_4[6] = {13, 13, 13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_adst_dct_4[4] = {13, 13, 13, 13};
static const TXFM_2D_CFG fwd_txfm_2d_cfg_adst_dct_4 = {
- 4, // .txfm_size
- 6, // .stage_num_col
- 4, // .stage_num_row
+ 4, // .txfm_size
+ 6, // .stage_num_col
+ 4, // .stage_num_row
+ // 0, // .log_scale
fwd_shift_adst_dct_4, // .shift
fwd_stage_range_col_adst_dct_4, // .stage_range_col
fwd_stage_range_row_adst_dct_4, // .stage_range_row
@@ -317,19 +329,20 @@
TXFM_TYPE_DCT4}; // .txfm_type_row
// ---------------- config fwd_adst_dct_8 ----------------
-static const int8_t fwd_shift_adst_dct_8[3] = {5, 1, -5};
-static const int8_t fwd_stage_range_col_adst_dct_8[8] = {16, 16, 17, 18,
- 18, 19, 19, 19};
-static const int8_t fwd_stage_range_row_adst_dct_8[6] = {20, 21, 22,
- 22, 22, 22};
-static const int8_t fwd_cos_bit_col_adst_dct_8[8] = {15, 15, 15, 14,
- 14, 13, 13, 13};
-static const int8_t fwd_cos_bit_row_adst_dct_8[6] = {12, 11, 10, 10, 10, 10};
+static const int8_t fwd_shift_adst_dct_8[3] = {2, -1, 0};
+static const int8_t fwd_stage_range_col_adst_dct_8[8] = {15, 15, 16, 17,
+ 17, 18, 18, 18};
+static const int8_t fwd_stage_range_row_adst_dct_8[6] = {17, 18, 19,
+ 19, 19, 19};
+static const int8_t fwd_cos_bit_col_adst_dct_8[8] = {13, 13, 13, 13,
+ 13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_adst_dct_8[6] = {13, 13, 13, 13, 13, 13};
static const TXFM_2D_CFG fwd_txfm_2d_cfg_adst_dct_8 = {
- 8, // .txfm_size
- 8, // .stage_num_col
- 6, // .stage_num_row
+ 8, // .txfm_size
+ 8, // .stage_num_col
+ 6, // .stage_num_row
+ // 0, // .log_scale
fwd_shift_adst_dct_8, // .shift
fwd_stage_range_col_adst_dct_8, // .stage_range_col
fwd_stage_range_row_adst_dct_8, // .stage_range_row
@@ -339,20 +352,21 @@
TXFM_TYPE_DCT8}; // .txfm_type_row
// ---------------- config fwd_adst_dct_16 ----------------
-static const int8_t fwd_shift_adst_dct_16[3] = {4, -3, -1};
+static const int8_t fwd_shift_adst_dct_16[3] = {2, -2, 0};
static const int8_t fwd_stage_range_col_adst_dct_16[10] = {15, 15, 16, 17, 17,
18, 18, 19, 19, 19};
-static const int8_t fwd_stage_range_row_adst_dct_16[8] = {16, 17, 18, 19,
- 19, 19, 19, 19};
-static const int8_t fwd_cos_bit_col_adst_dct_16[10] = {15, 15, 15, 15, 15,
- 14, 14, 13, 13, 13};
-static const int8_t fwd_cos_bit_row_adst_dct_16[8] = {15, 15, 14, 13,
- 13, 13, 13, 13};
+static const int8_t fwd_stage_range_row_adst_dct_16[8] = {17, 18, 19, 20,
+ 20, 20, 20, 20};
+static const int8_t fwd_cos_bit_col_adst_dct_16[10] = {13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_adst_dct_16[8] = {12, 12, 12, 12,
+ 12, 12, 12, 12};
static const TXFM_2D_CFG fwd_txfm_2d_cfg_adst_dct_16 = {
- 16, // .txfm_size
- 10, // .stage_num_col
- 8, // .stage_num_row
+ 16, // .txfm_size
+ 10, // .stage_num_col
+ 8, // .stage_num_row
+ // 0, // .log_scale
fwd_shift_adst_dct_16, // .shift
fwd_stage_range_col_adst_dct_16, // .stage_range_col
fwd_stage_range_row_adst_dct_16, // .stage_range_row
@@ -362,20 +376,21 @@
TXFM_TYPE_DCT16}; // .txfm_type_row
// ---------------- config fwd_adst_dct_32 ----------------
-static const int8_t fwd_shift_adst_dct_32[3] = {5, -4, -2};
+static const int8_t fwd_shift_adst_dct_32[3] = {2, -4, 0};
static const int8_t fwd_stage_range_col_adst_dct_32[12] = {
- 16, 16, 17, 18, 18, 19, 19, 20, 20, 21, 21, 21};
-static const int8_t fwd_stage_range_row_adst_dct_32[10] = {17, 18, 19, 20, 21,
- 21, 21, 21, 21, 21};
-static const int8_t fwd_cos_bit_col_adst_dct_32[12] = {15, 15, 15, 14, 14, 13,
- 13, 12, 12, 11, 11, 11};
-static const int8_t fwd_cos_bit_row_adst_dct_32[10] = {15, 14, 13, 12, 11,
- 11, 11, 11, 11, 11};
+ 15, 15, 16, 17, 17, 18, 18, 19, 19, 20, 20, 20};
+static const int8_t fwd_stage_range_row_adst_dct_32[10] = {16, 17, 18, 19, 20,
+ 20, 20, 20, 20, 20};
+static const int8_t fwd_cos_bit_col_adst_dct_32[12] = {12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12};
+static const int8_t fwd_cos_bit_row_adst_dct_32[10] = {12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12};
static const TXFM_2D_CFG fwd_txfm_2d_cfg_adst_dct_32 = {
- 32, // .txfm_size
- 12, // .stage_num_col
- 10, // .stage_num_row
+ 32, // .txfm_size
+ 12, // .stage_num_col
+ 10, // .stage_num_row
+ // 1, // .log_scale
fwd_shift_adst_dct_32, // .shift
fwd_stage_range_col_adst_dct_32, // .stage_range_col
fwd_stage_range_row_adst_dct_32, // .stage_range_row
diff --git a/vp10/common/vp10_inv_txfm2d.c b/vp10/common/vp10_inv_txfm2d.c
index d9f713c..a1ad4b8 100644
--- a/vp10/common/vp10_inv_txfm2d.c
+++ b/vp10/common/vp10_inv_txfm2d.c
@@ -11,9 +11,6 @@
#include "vp10/common/vp10_txfm.h"
#include "vp10/common/vp10_inv_txfm1d.h"
-typedef void (*TxfmFunc)(const int32_t *input, int32_t *output,
- const int8_t *cos_bit, const int8_t *stage_range);
-
static inline TxfmFunc inv_txfm_type_to_func(TXFM_TYPE txfm_type) {
switch (txfm_type) {
case TXFM_TYPE_DCT4:
diff --git a/vp10/common/vp10_inv_txfm2d_cfg.h b/vp10/common/vp10_inv_txfm2d_cfg.h
index ee965ba..9199068 100644
--- a/vp10/common/vp10_inv_txfm2d_cfg.h
+++ b/vp10/common/vp10_inv_txfm2d_cfg.h
@@ -12,16 +12,17 @@
#define VP10_INV_TXFM2D_CFG_H_
#include "vp10/common/vp10_inv_txfm1d.h"
// ---------------- config inv_dct_dct_4 ----------------
-static const int8_t inv_shift_dct_dct_4[2] = {1, -5};
-static const int8_t inv_stage_range_col_dct_dct_4[4] = {17, 17, 16, 16};
-static const int8_t inv_stage_range_row_dct_dct_4[4] = {16, 16, 16, 16};
-static const int8_t inv_cos_bit_col_dct_dct_4[4] = {15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_dct_dct_4[4] = {15, 15, 15, 15};
+static const int8_t inv_shift_dct_dct_4[2] = {0, -4};
+static const int8_t inv_stage_range_col_dct_dct_4[4] = {18, 18, 17, 17};
+static const int8_t inv_stage_range_row_dct_dct_4[4] = {18, 18, 18, 18};
+static const int8_t inv_cos_bit_col_dct_dct_4[4] = {13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_dct_dct_4[4] = {13, 13, 13, 13};
static const TXFM_2D_CFG inv_txfm_2d_cfg_dct_dct_4 = {
- 4, // .txfm_size
- 4, // .stage_num_col
- 4, // .stage_num_row
+ 4, // .txfm_size
+ 4, // .stage_num_col
+ 4, // .stage_num_row
+ // 0, // .log_scale
inv_shift_dct_dct_4, // .shift
inv_stage_range_col_dct_dct_4, // .stage_range_col
inv_stage_range_row_dct_dct_4, // .stage_range_row
@@ -32,15 +33,16 @@
// ---------------- config inv_dct_dct_8 ----------------
static const int8_t inv_shift_dct_dct_8[2] = {0, -5};
-static const int8_t inv_stage_range_col_dct_dct_8[6] = {17, 17, 17, 17, 16, 16};
-static const int8_t inv_stage_range_row_dct_dct_8[6] = {17, 17, 17, 17, 17, 17};
-static const int8_t inv_cos_bit_col_dct_dct_8[6] = {15, 15, 15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_dct_dct_8[6] = {15, 15, 15, 15, 15, 15};
+static const int8_t inv_stage_range_col_dct_dct_8[6] = {19, 19, 19, 19, 18, 18};
+static const int8_t inv_stage_range_row_dct_dct_8[6] = {19, 19, 19, 19, 19, 19};
+static const int8_t inv_cos_bit_col_dct_dct_8[6] = {13, 13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_dct_dct_8[6] = {13, 13, 13, 13, 13, 13};
static const TXFM_2D_CFG inv_txfm_2d_cfg_dct_dct_8 = {
- 8, // .txfm_size
- 6, // .stage_num_col
- 6, // .stage_num_row
+ 8, // .txfm_size
+ 6, // .stage_num_col
+ 6, // .stage_num_row
+ // 0, // .log_scale
inv_shift_dct_dct_8, // .shift
inv_stage_range_col_dct_dct_8, // .stage_range_col
inv_stage_range_row_dct_dct_8, // .stage_range_row
@@ -50,20 +52,21 @@
TXFM_TYPE_DCT8}; // .txfm_type_row
// ---------------- config inv_dct_dct_16 ----------------
-static const int8_t inv_shift_dct_dct_16[2] = {0, -6};
-static const int8_t inv_stage_range_col_dct_dct_16[8] = {18, 18, 18, 18,
- 18, 18, 17, 17};
-static const int8_t inv_stage_range_row_dct_dct_16[8] = {18, 18, 18, 18,
- 18, 18, 18, 18};
-static const int8_t inv_cos_bit_col_dct_dct_16[8] = {14, 14, 14, 14,
- 14, 14, 14, 15};
-static const int8_t inv_cos_bit_row_dct_dct_16[8] = {14, 14, 14, 14,
- 14, 14, 14, 14};
+static const int8_t inv_shift_dct_dct_16[2] = {-1, -5};
+static const int8_t inv_stage_range_col_dct_dct_16[8] = {19, 19, 19, 19,
+ 19, 19, 18, 18};
+static const int8_t inv_stage_range_row_dct_dct_16[8] = {20, 20, 20, 20,
+ 20, 20, 20, 20};
+static const int8_t inv_cos_bit_col_dct_dct_16[8] = {13, 13, 13, 13,
+ 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_dct_dct_16[8] = {12, 12, 12, 12,
+ 12, 12, 12, 12};
static const TXFM_2D_CFG inv_txfm_2d_cfg_dct_dct_16 = {
- 16, // .txfm_size
- 8, // .stage_num_col
- 8, // .stage_num_row
+ 16, // .txfm_size
+ 8, // .stage_num_col
+ 8, // .stage_num_row
+ // 0, // .log_scale
inv_shift_dct_dct_16, // .shift
inv_stage_range_col_dct_dct_16, // .stage_range_col
inv_stage_range_row_dct_dct_16, // .stage_range_row
@@ -73,20 +76,21 @@
TXFM_TYPE_DCT16}; // .txfm_type_row
// ---------------- config inv_dct_dct_32 ----------------
-static const int8_t inv_shift_dct_dct_32[2] = {-1, -6};
-static const int8_t inv_stage_range_col_dct_dct_32[10] = {18, 18, 18, 18, 18,
- 18, 18, 18, 17, 17};
-static const int8_t inv_stage_range_row_dct_dct_32[10] = {19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19};
-static const int8_t inv_cos_bit_col_dct_dct_32[10] = {14, 14, 14, 14, 14,
- 14, 14, 14, 14, 15};
-static const int8_t inv_cos_bit_row_dct_dct_32[10] = {13, 13, 13, 13, 13,
+static const int8_t inv_shift_dct_dct_32[2] = {-1, -5};
+static const int8_t inv_stage_range_col_dct_dct_32[10] = {19, 19, 19, 19, 19,
+ 19, 19, 19, 18, 18};
+static const int8_t inv_stage_range_row_dct_dct_32[10] = {20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20};
+static const int8_t inv_cos_bit_col_dct_dct_32[10] = {13, 13, 13, 13, 13,
13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_dct_dct_32[10] = {12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12};
static const TXFM_2D_CFG inv_txfm_2d_cfg_dct_dct_32 = {
- 32, // .txfm_size
- 10, // .stage_num_col
- 10, // .stage_num_row
+ 32, // .txfm_size
+ 10, // .stage_num_col
+ 10, // .stage_num_row
+ // 1, // .log_scale
inv_shift_dct_dct_32, // .shift
inv_stage_range_col_dct_dct_32, // .stage_range_col
inv_stage_range_row_dct_dct_32, // .stage_range_row
@@ -102,7 +106,7 @@
static const int8_t inv_stage_range_row_dct_dct_64[12] = {
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20};
static const int8_t inv_cos_bit_col_dct_dct_64[12] = {13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 14};
+ 13, 13, 13, 13, 13, 13};
static const int8_t inv_cos_bit_row_dct_dct_64[12] = {12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12};
@@ -119,17 +123,18 @@
TXFM_TYPE_DCT64}; // .txfm_type_row
// ---------------- config inv_dct_adst_4 ----------------
-static const int8_t inv_shift_dct_adst_4[2] = {1, -5};
-static const int8_t inv_stage_range_col_dct_adst_4[4] = {17, 17, 16, 16};
-static const int8_t inv_stage_range_row_dct_adst_4[6] = {16, 16, 16,
- 16, 16, 16};
-static const int8_t inv_cos_bit_col_dct_adst_4[4] = {15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_dct_adst_4[6] = {15, 15, 15, 15, 15, 15};
+static const int8_t inv_shift_dct_adst_4[2] = {0, -4};
+static const int8_t inv_stage_range_col_dct_adst_4[4] = {18, 18, 17, 17};
+static const int8_t inv_stage_range_row_dct_adst_4[6] = {18, 18, 18,
+ 18, 18, 18};
+static const int8_t inv_cos_bit_col_dct_adst_4[4] = {13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_dct_adst_4[6] = {13, 13, 13, 13, 13, 13};
static const TXFM_2D_CFG inv_txfm_2d_cfg_dct_adst_4 = {
- 4, // .txfm_size
- 4, // .stage_num_col
- 6, // .stage_num_row
+ 4, // .txfm_size
+ 4, // .stage_num_col
+ 6, // .stage_num_row
+ // 0, // .log_scale
inv_shift_dct_adst_4, // .shift
inv_stage_range_col_dct_adst_4, // .stage_range_col
inv_stage_range_row_dct_adst_4, // .stage_range_row
@@ -139,19 +144,20 @@
TXFM_TYPE_ADST4}; // .txfm_type_row
// ---------------- config inv_dct_adst_8 ----------------
-static const int8_t inv_shift_dct_adst_8[2] = {-1, -4};
-static const int8_t inv_stage_range_col_dct_adst_8[6] = {16, 16, 16,
- 16, 15, 15};
-static const int8_t inv_stage_range_row_dct_adst_8[8] = {17, 17, 17, 17,
- 17, 17, 17, 17};
-static const int8_t inv_cos_bit_col_dct_adst_8[6] = {15, 15, 15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_dct_adst_8[8] = {15, 15, 15, 15,
- 15, 15, 15, 15};
+static const int8_t inv_shift_dct_adst_8[2] = {0, -5};
+static const int8_t inv_stage_range_col_dct_adst_8[6] = {19, 19, 19,
+ 19, 18, 18};
+static const int8_t inv_stage_range_row_dct_adst_8[8] = {19, 19, 19, 19,
+ 19, 19, 19, 19};
+static const int8_t inv_cos_bit_col_dct_adst_8[6] = {13, 13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_dct_adst_8[8] = {13, 13, 13, 13,
+ 13, 13, 13, 13};
static const TXFM_2D_CFG inv_txfm_2d_cfg_dct_adst_8 = {
- 8, // .txfm_size
- 6, // .stage_num_col
- 8, // .stage_num_row
+ 8, // .txfm_size
+ 6, // .stage_num_col
+ 8, // .stage_num_row
+ // 0, // .log_scale
inv_shift_dct_adst_8, // .shift
inv_stage_range_col_dct_adst_8, // .stage_range_col
inv_stage_range_row_dct_adst_8, // .stage_range_row
@@ -161,20 +167,21 @@
TXFM_TYPE_ADST8}; // .txfm_type_row
// ---------------- config inv_dct_adst_16 ----------------
-static const int8_t inv_shift_dct_adst_16[2] = {1, -7};
+static const int8_t inv_shift_dct_adst_16[2] = {-1, -5};
static const int8_t inv_stage_range_col_dct_adst_16[8] = {19, 19, 19, 19,
19, 19, 18, 18};
-static const int8_t inv_stage_range_row_dct_adst_16[10] = {18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18};
+static const int8_t inv_stage_range_row_dct_adst_16[10] = {20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20};
static const int8_t inv_cos_bit_col_dct_adst_16[8] = {13, 13, 13, 13,
- 13, 13, 13, 14};
-static const int8_t inv_cos_bit_row_dct_adst_16[10] = {14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14};
+ 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_dct_adst_16[10] = {12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12};
static const TXFM_2D_CFG inv_txfm_2d_cfg_dct_adst_16 = {
- 16, // .txfm_size
- 8, // .stage_num_col
- 10, // .stage_num_row
+ 16, // .txfm_size
+ 8, // .stage_num_col
+ 10, // .stage_num_row
+ // 0, // .log_scale
inv_shift_dct_adst_16, // .shift
inv_stage_range_col_dct_adst_16, // .stage_range_col
inv_stage_range_row_dct_adst_16, // .stage_range_row
@@ -184,20 +191,21 @@
TXFM_TYPE_ADST16}; // .txfm_type_row
// ---------------- config inv_dct_adst_32 ----------------
-static const int8_t inv_shift_dct_adst_32[2] = {-1, -6};
-static const int8_t inv_stage_range_col_dct_adst_32[10] = {18, 18, 18, 18, 18,
- 18, 18, 18, 17, 17};
+static const int8_t inv_shift_dct_adst_32[2] = {-1, -5};
+static const int8_t inv_stage_range_col_dct_adst_32[10] = {19, 19, 19, 19, 19,
+ 19, 19, 19, 18, 18};
static const int8_t inv_stage_range_row_dct_adst_32[12] = {
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19};
-static const int8_t inv_cos_bit_col_dct_adst_32[10] = {14, 14, 14, 14, 14,
- 14, 14, 14, 14, 15};
-static const int8_t inv_cos_bit_row_dct_adst_32[12] = {13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13};
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20};
+static const int8_t inv_cos_bit_col_dct_adst_32[10] = {13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_dct_adst_32[12] = {12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12};
static const TXFM_2D_CFG inv_txfm_2d_cfg_dct_adst_32 = {
- 32, // .txfm_size
- 10, // .stage_num_col
- 12, // .stage_num_row
+ 32, // .txfm_size
+ 10, // .stage_num_col
+ 12, // .stage_num_row
+ // 1, // .log_scale
inv_shift_dct_adst_32, // .shift
inv_stage_range_col_dct_adst_32, // .stage_range_col
inv_stage_range_row_dct_adst_32, // .stage_range_row
@@ -208,17 +216,18 @@
// ---------------- config inv_adst_adst_4 ----------------
static const int8_t inv_shift_adst_adst_4[2] = {0, -4};
-static const int8_t inv_stage_range_col_adst_adst_4[6] = {16, 16, 16,
- 16, 15, 15};
-static const int8_t inv_stage_range_row_adst_adst_4[6] = {16, 16, 16,
- 16, 16, 16};
-static const int8_t inv_cos_bit_col_adst_adst_4[6] = {15, 15, 15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_adst_adst_4[6] = {15, 15, 15, 15, 15, 15};
+static const int8_t inv_stage_range_col_adst_adst_4[6] = {18, 18, 18,
+ 18, 17, 17};
+static const int8_t inv_stage_range_row_adst_adst_4[6] = {18, 18, 18,
+ 18, 18, 18};
+static const int8_t inv_cos_bit_col_adst_adst_4[6] = {13, 13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_adst_adst_4[6] = {13, 13, 13, 13, 13, 13};
static const TXFM_2D_CFG inv_txfm_2d_cfg_adst_adst_4 = {
- 4, // .txfm_size
- 6, // .stage_num_col
- 6, // .stage_num_row
+ 4, // .txfm_size
+ 6, // .stage_num_col
+ 6, // .stage_num_row
+ // 0, // .log_scale
inv_shift_adst_adst_4, // .shift
inv_stage_range_col_adst_adst_4, // .stage_range_col
inv_stage_range_row_adst_adst_4, // .stage_range_row
@@ -228,20 +237,21 @@
TXFM_TYPE_ADST4}; // .txfm_type_row
// ---------------- config inv_adst_adst_8 ----------------
-static const int8_t inv_shift_adst_adst_8[2] = {-1, -4};
-static const int8_t inv_stage_range_col_adst_adst_8[8] = {16, 16, 16, 16,
- 16, 16, 15, 15};
-static const int8_t inv_stage_range_row_adst_adst_8[8] = {17, 17, 17, 17,
- 17, 17, 17, 17};
-static const int8_t inv_cos_bit_col_adst_adst_8[8] = {15, 15, 15, 15,
- 15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_adst_adst_8[8] = {15, 15, 15, 15,
- 15, 15, 15, 15};
+static const int8_t inv_shift_adst_adst_8[2] = {0, -5};
+static const int8_t inv_stage_range_col_adst_adst_8[8] = {19, 19, 19, 19,
+ 19, 19, 18, 18};
+static const int8_t inv_stage_range_row_adst_adst_8[8] = {19, 19, 19, 19,
+ 19, 19, 19, 19};
+static const int8_t inv_cos_bit_col_adst_adst_8[8] = {13, 13, 13, 13,
+ 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_adst_adst_8[8] = {13, 13, 13, 13,
+ 13, 13, 13, 13};
static const TXFM_2D_CFG inv_txfm_2d_cfg_adst_adst_8 = {
- 8, // .txfm_size
- 8, // .stage_num_col
- 8, // .stage_num_row
+ 8, // .txfm_size
+ 8, // .stage_num_col
+ 8, // .stage_num_row
+ // 0, // .log_scale
inv_shift_adst_adst_8, // .shift
inv_stage_range_col_adst_adst_8, // .stage_range_col
inv_stage_range_row_adst_adst_8, // .stage_range_row
@@ -251,20 +261,21 @@
TXFM_TYPE_ADST8}; // .txfm_type_row
// ---------------- config inv_adst_adst_16 ----------------
-static const int8_t inv_shift_adst_adst_16[2] = {0, -6};
-static const int8_t inv_stage_range_col_adst_adst_16[10] = {18, 18, 18, 18, 18,
- 18, 18, 18, 17, 17};
-static const int8_t inv_stage_range_row_adst_adst_16[10] = {18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18};
-static const int8_t inv_cos_bit_col_adst_adst_16[10] = {14, 14, 14, 14, 14,
- 14, 14, 14, 14, 15};
-static const int8_t inv_cos_bit_row_adst_adst_16[10] = {14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14};
+static const int8_t inv_shift_adst_adst_16[2] = {-1, -5};
+static const int8_t inv_stage_range_col_adst_adst_16[10] = {19, 19, 19, 19, 19,
+ 19, 19, 19, 18, 18};
+static const int8_t inv_stage_range_row_adst_adst_16[10] = {20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20};
+static const int8_t inv_cos_bit_col_adst_adst_16[10] = {13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_adst_adst_16[10] = {12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12};
static const TXFM_2D_CFG inv_txfm_2d_cfg_adst_adst_16 = {
- 16, // .txfm_size
- 10, // .stage_num_col
- 10, // .stage_num_row
+ 16, // .txfm_size
+ 10, // .stage_num_col
+ 10, // .stage_num_row
+ // 0, // .log_scale
inv_shift_adst_adst_16, // .shift
inv_stage_range_col_adst_adst_16, // .stage_range_col
inv_stage_range_row_adst_adst_16, // .stage_range_row
@@ -274,20 +285,21 @@
TXFM_TYPE_ADST16}; // .txfm_type_row
// ---------------- config inv_adst_adst_32 ----------------
-static const int8_t inv_shift_adst_adst_32[2] = {-1, -6};
+static const int8_t inv_shift_adst_adst_32[2] = {-1, -5};
static const int8_t inv_stage_range_col_adst_adst_32[12] = {
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 17, 17};
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 18, 18};
static const int8_t inv_stage_range_row_adst_adst_32[12] = {
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19};
-static const int8_t inv_cos_bit_col_adst_adst_32[12] = {14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 15};
-static const int8_t inv_cos_bit_row_adst_adst_32[12] = {13, 13, 13, 13, 13, 13,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20};
+static const int8_t inv_cos_bit_col_adst_adst_32[12] = {13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_adst_adst_32[12] = {12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12};
static const TXFM_2D_CFG inv_txfm_2d_cfg_adst_adst_32 = {
- 32, // .txfm_size
- 12, // .stage_num_col
- 12, // .stage_num_row
+ 32, // .txfm_size
+ 12, // .stage_num_col
+ 12, // .stage_num_row
+ // 1, // .log_scale
inv_shift_adst_adst_32, // .shift
inv_stage_range_col_adst_adst_32, // .stage_range_col
inv_stage_range_row_adst_adst_32, // .stage_range_row
@@ -297,17 +309,18 @@
TXFM_TYPE_ADST32}; // .txfm_type_row
// ---------------- config inv_adst_dct_4 ----------------
-static const int8_t inv_shift_adst_dct_4[2] = {1, -5};
-static const int8_t inv_stage_range_col_adst_dct_4[6] = {17, 17, 17,
- 17, 16, 16};
-static const int8_t inv_stage_range_row_adst_dct_4[4] = {16, 16, 16, 16};
-static const int8_t inv_cos_bit_col_adst_dct_4[6] = {15, 15, 15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_adst_dct_4[4] = {15, 15, 15, 15};
+static const int8_t inv_shift_adst_dct_4[2] = {0, -4};
+static const int8_t inv_stage_range_col_adst_dct_4[6] = {18, 18, 18,
+ 18, 17, 17};
+static const int8_t inv_stage_range_row_adst_dct_4[4] = {18, 18, 18, 18};
+static const int8_t inv_cos_bit_col_adst_dct_4[6] = {13, 13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_adst_dct_4[4] = {13, 13, 13, 13};
static const TXFM_2D_CFG inv_txfm_2d_cfg_adst_dct_4 = {
- 4, // .txfm_size
- 6, // .stage_num_col
- 4, // .stage_num_row
+ 4, // .txfm_size
+ 6, // .stage_num_col
+ 4, // .stage_num_row
+ // 0, // .log_scale
inv_shift_adst_dct_4, // .shift
inv_stage_range_col_adst_dct_4, // .stage_range_col
inv_stage_range_row_adst_dct_4, // .stage_range_row
@@ -317,19 +330,20 @@
TXFM_TYPE_DCT4}; // .txfm_type_row
// ---------------- config inv_adst_dct_8 ----------------
-static const int8_t inv_shift_adst_dct_8[2] = {-1, -4};
-static const int8_t inv_stage_range_col_adst_dct_8[8] = {16, 16, 16, 16,
- 16, 16, 15, 15};
-static const int8_t inv_stage_range_row_adst_dct_8[6] = {17, 17, 17,
- 17, 17, 17};
-static const int8_t inv_cos_bit_col_adst_dct_8[8] = {15, 15, 15, 15,
- 15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_adst_dct_8[6] = {15, 15, 15, 15, 15, 15};
+static const int8_t inv_shift_adst_dct_8[2] = {0, -5};
+static const int8_t inv_stage_range_col_adst_dct_8[8] = {19, 19, 19, 19,
+ 19, 19, 18, 18};
+static const int8_t inv_stage_range_row_adst_dct_8[6] = {19, 19, 19,
+ 19, 19, 19};
+static const int8_t inv_cos_bit_col_adst_dct_8[8] = {13, 13, 13, 13,
+ 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_adst_dct_8[6] = {13, 13, 13, 13, 13, 13};
static const TXFM_2D_CFG inv_txfm_2d_cfg_adst_dct_8 = {
- 8, // .txfm_size
- 8, // .stage_num_col
- 6, // .stage_num_row
+ 8, // .txfm_size
+ 8, // .stage_num_col
+ 6, // .stage_num_row
+ // 0, // .log_scale
inv_shift_adst_dct_8, // .shift
inv_stage_range_col_adst_dct_8, // .stage_range_col
inv_stage_range_row_adst_dct_8, // .stage_range_row
@@ -340,19 +354,20 @@
// ---------------- config inv_adst_dct_16 ----------------
static const int8_t inv_shift_adst_dct_16[2] = {-1, -5};
-static const int8_t inv_stage_range_col_adst_dct_16[10] = {17, 17, 17, 17, 17,
- 17, 17, 17, 16, 16};
-static const int8_t inv_stage_range_row_adst_dct_16[8] = {18, 18, 18, 18,
- 18, 18, 18, 18};
-static const int8_t inv_cos_bit_col_adst_dct_16[10] = {15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_adst_dct_16[8] = {14, 14, 14, 14,
- 14, 14, 14, 14};
+static const int8_t inv_stage_range_col_adst_dct_16[10] = {19, 19, 19, 19, 19,
+ 19, 19, 19, 18, 18};
+static const int8_t inv_stage_range_row_adst_dct_16[8] = {20, 20, 20, 20,
+ 20, 20, 20, 20};
+static const int8_t inv_cos_bit_col_adst_dct_16[10] = {13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_adst_dct_16[8] = {12, 12, 12, 12,
+ 12, 12, 12, 12};
static const TXFM_2D_CFG inv_txfm_2d_cfg_adst_dct_16 = {
- 16, // .txfm_size
- 10, // .stage_num_col
- 8, // .stage_num_row
+ 16, // .txfm_size
+ 10, // .stage_num_col
+ 8, // .stage_num_row
+ // 0, // .log_scale
inv_shift_adst_dct_16, // .shift
inv_stage_range_col_adst_dct_16, // .stage_range_col
inv_stage_range_row_adst_dct_16, // .stage_range_row
@@ -362,20 +377,21 @@
TXFM_TYPE_DCT16}; // .txfm_type_row
// ---------------- config inv_adst_dct_32 ----------------
-static const int8_t inv_shift_adst_dct_32[2] = {-1, -6};
+static const int8_t inv_shift_adst_dct_32[2] = {-1, -5};
static const int8_t inv_stage_range_col_adst_dct_32[12] = {
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 17, 17};
-static const int8_t inv_stage_range_row_adst_dct_32[10] = {19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19};
-static const int8_t inv_cos_bit_col_adst_dct_32[12] = {14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 15};
-static const int8_t inv_cos_bit_row_adst_dct_32[10] = {13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13};
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 18, 18};
+static const int8_t inv_stage_range_row_adst_dct_32[10] = {20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20};
+static const int8_t inv_cos_bit_col_adst_dct_32[12] = {13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_adst_dct_32[10] = {12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12};
static const TXFM_2D_CFG inv_txfm_2d_cfg_adst_dct_32 = {
- 32, // .txfm_size
- 12, // .stage_num_col
- 10, // .stage_num_row
+ 32, // .txfm_size
+ 12, // .stage_num_col
+ 10, // .stage_num_row
+ // 1, // .log_scale
inv_shift_adst_dct_32, // .shift
inv_stage_range_col_adst_dct_32, // .stage_range_col
inv_stage_range_row_adst_dct_32, // .stage_range_row
diff --git a/vp10/decoder/decodeframe.c b/vp10/decoder/decodeframe.c
index 17e7401..0e51b15 100644
--- a/vp10/decoder/decodeframe.c
+++ b/vp10/decoder/decodeframe.c
@@ -291,7 +291,7 @@
token_tab,
#endif // CONFIG_ANS
plane, sc, col, row, tx_size,
- r, mbmi->segment_id);
+ tx_type, r, mbmi->segment_id);
inverse_transform_block(xd, plane, tx_type, tx_size,
dst, pd->dst.stride, eob);
}
@@ -327,7 +327,7 @@
const scan_order *sc = get_scan(tx_size, tx_type, 1);
const int eob = vp10_decode_block_tokens(xd, plane, sc,
blk_col, blk_row, tx_size,
- r, mbmi->segment_id);
+ tx_type, r, mbmi->segment_id);
inverse_transform_block(xd, plane, tx_type, tx_size,
&pd->dst.buf[4 * blk_row * pd->dst.stride + 4 * blk_col],
pd->dst.stride, eob);
@@ -373,7 +373,8 @@
#if CONFIG_ANS
token_tab,
#endif
- plane, sc, col, row, tx_size, r,
+ plane, sc, col, row,
+ tx_size, tx_type, r,
mbmi->segment_id);
inverse_transform_block(xd, plane, tx_type, tx_size,
diff --git a/vp10/decoder/decodemv.c b/vp10/decoder/decodemv.c
index b52696d..3c91a66 100644
--- a/vp10/decoder/decodemv.c
+++ b/vp10/decoder/decodemv.c
@@ -64,10 +64,10 @@
#if CONFIG_EXT_INTER
static INTERINTRA_MODE read_interintra_mode(VP10_COMMON *cm, MACROBLOCKD *xd,
- vpx_reader *r, int size_group) {
+ vp10_reader *r, int size_group) {
const INTERINTRA_MODE ii_mode =
- (INTERINTRA_MODE)vpx_read_tree(r, vp10_interintra_mode_tree,
- cm->fc->interintra_mode_prob[size_group]);
+ (INTERINTRA_MODE)vp10_read_tree(r, vp10_interintra_mode_tree,
+ cm->fc->interintra_mode_prob[size_group]);
FRAME_COUNTS *counts = xd->counts;
if (counts)
++counts->interintra_mode[size_group][ii_mode];
@@ -1230,14 +1230,6 @@
mi_row, mi_col, fpm_sync, (void *)pbi, inter_mode_ctx);
}
-#if CONFIG_OBMC
- mbmi->obmc = 0;
-#if CONFIG_SUPERTX
- if (!supertx_enabled)
-#endif // CONFIG_SUPERTX
- mbmi->obmc = read_is_obmc_block(cm, xd, r);
-#endif // CONFIG_OBMC
-
#if CONFIG_REF_MV
#if CONFIG_EXT_INTER
if (is_compound)
@@ -1293,7 +1285,6 @@
if (mbmi->ref_mv_idx > 0) {
int_mv cur_mv =
xd->ref_mv_stack[mbmi->ref_frame[0]][1 + mbmi->ref_mv_idx].this_mv;
- lower_mv_precision(&cur_mv.as_mv, cm->allow_high_precision_mv);
nearmv[0] = cur_mv;
}
@@ -1310,15 +1301,11 @@
#else
if (xd->ref_mv_count[ref_frame_type] == 1 && mbmi->mode == NEARESTMV) {
#endif // CONFIG_EXT_INTER
- int i;
#if CONFIG_EXT_INTER
if (mbmi->mode == NEAREST_NEARESTMV) {
#endif // CONFIG_EXT_INTER
nearestmv[0] = xd->ref_mv_stack[ref_frame_type][0].this_mv;
nearestmv[1] = xd->ref_mv_stack[ref_frame_type][0].comp_mv;
-
- for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i)
- lower_mv_precision(&nearestmv[i].as_mv, allow_hp);
#if CONFIG_EXT_INTER
} else if (mbmi->mode == NEAREST_NEWMV || mbmi->mode == NEAREST_NEARMV) {
nearestmv[0] = xd->ref_mv_stack[ref_frame_type][0].this_mv;
@@ -1344,17 +1331,11 @@
}
#else
if (xd->ref_mv_count[ref_frame_type] > 1) {
- int i;
int ref_mv_idx = 1 + mbmi->ref_mv_idx;
nearestmv[0] = xd->ref_mv_stack[ref_frame_type][0].this_mv;
nearestmv[1] = xd->ref_mv_stack[ref_frame_type][0].comp_mv;
nearmv[0] = xd->ref_mv_stack[ref_frame_type][ref_mv_idx].this_mv;
nearmv[1] = xd->ref_mv_stack[ref_frame_type][ref_mv_idx].comp_mv;
-
- for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) {
- lower_mv_precision(&nearestmv[i].as_mv, allow_hp);
- lower_mv_precision(&nearmv[i].as_mv, allow_hp);
- }
}
#endif // CONFIG_EXT_INTER
}
@@ -1495,7 +1476,6 @@
xd->ref_mv_stack[ref_frame_type][mbmi->ref_mv_idx].this_mv :
xd->ref_mv_stack[ref_frame_type][mbmi->ref_mv_idx].comp_mv;
clamp_mv_ref(&ref_mv[ref].as_mv, xd->n8_w << 3, xd->n8_h << 3, xd);
- lower_mv_precision(&ref_mv[ref].as_mv, allow_hp);
}
#endif
nearestmv[ref] = ref_mv[ref];
@@ -1516,18 +1496,14 @@
}
#if CONFIG_EXT_INTER
- mbmi->use_wedge_interintra = 0;
- mbmi->use_wedge_interinter = 0;
+ mbmi->use_wedge_interintra = 0;
if (cm->reference_mode != COMPOUND_REFERENCE &&
-#if CONFIG_OBMC
- !(is_obmc_allowed(mbmi) && mbmi->obmc) &&
-#endif // CONFIG_OBMC
#if CONFIG_SUPERTX
!supertx_enabled &&
#endif
is_interintra_allowed(mbmi)) {
const int bsize_group = size_group_lookup[bsize];
- const int interintra = vpx_read(r, cm->fc->interintra_prob[bsize_group]);
+ const int interintra = vp10_read(r, cm->fc->interintra_prob[bsize_group]);
if (xd->counts)
xd->counts->interintra[bsize_group][interintra]++;
assert(mbmi->ref_frame[1] == NONE);
@@ -1557,6 +1533,21 @@
}
}
}
+#endif // CONFIG_EXT_INTER
+
+#if CONFIG_OBMC
+ mbmi->obmc = 0;
+#if CONFIG_SUPERTX
+ if (!supertx_enabled)
+#endif // CONFIG_SUPERTX
+#if CONFIG_EXT_INTER
+ if (mbmi->ref_frame[1] != INTRA_FRAME)
+#endif // CONFIG_EXT_INTER
+ mbmi->obmc = read_is_obmc_block(cm, xd, r);
+#endif // CONFIG_OBMC
+
+#if CONFIG_EXT_INTER
+ mbmi->use_wedge_interinter = 0;
if (cm->reference_mode != SINGLE_REFERENCE &&
is_inter_compound_mode(mbmi->mode) &&
#if CONFIG_OBMC
diff --git a/vp10/decoder/detokenize.c b/vp10/decoder/detokenize.c
index 58cd9e6..def3d7a 100644
--- a/vp10/decoder/detokenize.c
+++ b/vp10/decoder/detokenize.c
@@ -47,7 +47,8 @@
static int decode_coefs(const MACROBLOCKD *xd,
PLANE_TYPE type,
- tran_low_t *dqcoeff, TX_SIZE tx_size, const int16_t *dq,
+ tran_low_t *dqcoeff, TX_SIZE tx_size, TX_TYPE tx_type,
+ const int16_t *dq,
int ctx, const int16_t *scan, const int16_t *nb,
vp10_reader *r) {
FRAME_COUNTS *counts = xd->counts;
@@ -111,7 +112,7 @@
cat6_prob = vp10_cat6_prob;
#endif
- dq_shift = get_tx_scale(xd, 0, tx_size);
+ dq_shift = get_tx_scale(xd, tx_type, tx_size);
while (c < max_eob) {
int val = -1;
@@ -222,6 +223,7 @@
const rans_dec_lut *const token_tab,
PLANE_TYPE type,
tran_low_t *dqcoeff, TX_SIZE tx_size,
+ TX_TYPE tx_type,
const int16_t *dq,
int ctx, const int16_t *scan, const int16_t *nb,
struct AnsDecoder *const ans) {
@@ -247,7 +249,7 @@
const uint8_t *cat5_prob;
const uint8_t *cat6_prob;
- dq_shift = get_tx_scale(xd, 0, tx_size);
+ dq_shift = get_tx_scale(xd, tx_type, tx_size);
if (counts) {
coef_counts = counts->coef[tx_size][type][ref];
@@ -462,6 +464,7 @@
int plane, const scan_order *sc,
int x, int y,
TX_SIZE tx_size,
+ TX_TYPE tx_type,
#if CONFIG_ANS
struct AnsDecoder *const r,
#else
@@ -474,11 +477,11 @@
pd->left_context + y);
#if !CONFIG_ANS
const int eob = decode_coefs(xd, pd->plane_type,
- pd->dqcoeff, tx_size,
+ pd->dqcoeff, tx_size, tx_type,
dequant, ctx, sc->scan, sc->neighbors, r);
#else
const int eob = decode_coefs_ans(xd, token_tab, pd->plane_type,
- pd->dqcoeff, tx_size,
+ pd->dqcoeff, tx_size, tx_type,
dequant, ctx, sc->scan, sc->neighbors, r);
#endif // !CONFIG_ANS
dec_set_contexts(xd, pd, tx_size, eob > 0, x, y);
diff --git a/vp10/decoder/detokenize.h b/vp10/decoder/detokenize.h
index 4688d0a..a19d90f 100644
--- a/vp10/decoder/detokenize.h
+++ b/vp10/decoder/detokenize.h
@@ -29,6 +29,7 @@
int plane, const scan_order *sc,
int x, int y,
TX_SIZE tx_size,
+ TX_TYPE tx_type,
#if CONFIG_ANS
struct AnsDecoder *const r,
#else
diff --git a/vp10/encoder/bitstream.c b/vp10/encoder/bitstream.c
index 3687073..b7bd6fc 100644
--- a/vp10/encoder/bitstream.c
+++ b/vp10/encoder/bitstream.c
@@ -145,7 +145,7 @@
}
#if CONFIG_EXT_INTER
-static void write_interintra_mode(vpx_writer *w, INTERINTRA_MODE mode,
+static void write_interintra_mode(vp10_writer *w, INTERINTRA_MODE mode,
const vpx_prob *probs) {
vp10_write_token(w, vp10_interintra_mode_tree, probs,
&interintra_mode_encodings[mode]);
@@ -1115,14 +1115,6 @@
int16_t mode_ctx = mbmi_ext->mode_context[mbmi->ref_frame[0]];
write_ref_frames(cm, xd, w);
-#if CONFIG_OBMC
-#if CONFIG_SUPERTX
- if (!supertx_enabled)
-#endif // CONFIG_SUPERTX
- if (is_obmc_allowed(mbmi))
- vp10_write(w, mbmi->obmc, cm->fc->obmc_prob[bsize]);
-#endif // CONFIG_OBMC
-
#if CONFIG_REF_MV
#if CONFIG_EXT_INTER
if (is_compound)
@@ -1286,24 +1278,21 @@
#if CONFIG_EXT_INTER
if (cpi->common.reference_mode != COMPOUND_REFERENCE &&
-#if CONFIG_OBMC
- !(is_obmc_allowed(mbmi) && mbmi->obmc) &&
-#endif // CONFIG_OBMC
#if CONFIG_SUPERTX
!supertx_enabled &&
#endif // CONFIG_SUPERTX
is_interintra_allowed(mbmi)) {
const int interintra = mbmi->ref_frame[1] == INTRA_FRAME;
const int bsize_group = size_group_lookup[bsize];
- vpx_write(w, interintra, cm->fc->interintra_prob[bsize_group]);
+ vp10_write(w, interintra, cm->fc->interintra_prob[bsize_group]);
if (interintra) {
write_interintra_mode(
w, mbmi->interintra_mode,
cm->fc->interintra_mode_prob[bsize_group]);
assert(mbmi->interintra_mode == mbmi->interintra_uv_mode);
if (is_interintra_wedge_used(bsize)) {
- vpx_write(w, mbmi->use_wedge_interintra,
- cm->fc->wedge_interintra_prob[bsize]);
+ vp10_write(w, mbmi->use_wedge_interintra,
+ cm->fc->wedge_interintra_prob[bsize]);
if (mbmi->use_wedge_interintra) {
vp10_write_literal(w, mbmi->interintra_wedge_index,
get_wedge_bits(bsize));
@@ -1311,14 +1300,28 @@
}
}
}
+#endif // CONFIG_EXT_INTER
+
+#if CONFIG_OBMC
+#if CONFIG_SUPERTX
+ if (!supertx_enabled)
+#endif // CONFIG_SUPERTX
+#if CONFIG_EXT_INTER
+ if (mbmi->ref_frame[1] != INTRA_FRAME)
+#endif // CONFIG_EXT_INTER
+ if (is_obmc_allowed(mbmi))
+ vp10_write(w, mbmi->obmc, cm->fc->obmc_prob[bsize]);
+#endif // CONFIG_OBMC
+
+#if CONFIG_EXT_INTER
if (cpi->common.reference_mode != SINGLE_REFERENCE &&
is_inter_compound_mode(mbmi->mode) &&
#if CONFIG_OBMC
!(is_obmc_allowed(mbmi) && mbmi->obmc) &&
#endif // CONFIG_OBMC
is_interinter_wedge_used(bsize)) {
- vpx_write(w, mbmi->use_wedge_interinter,
- cm->fc->wedge_interinter_prob[bsize]);
+ vp10_write(w, mbmi->use_wedge_interinter,
+ cm->fc->wedge_interinter_prob[bsize]);
if (mbmi->use_wedge_interinter)
vp10_write_literal(w, mbmi->interinter_wedge_index,
get_wedge_bits(bsize));
diff --git a/vp10/encoder/block.h b/vp10/encoder/block.h
index 2e8af98..095aee5 100644
--- a/vp10/encoder/block.h
+++ b/vp10/encoder/block.h
@@ -104,6 +104,7 @@
int mv_best_ref_index[MAX_REF_FRAMES];
unsigned int max_mv_context[MAX_REF_FRAMES];
unsigned int source_variance;
+ unsigned int recon_variance;
#if CONFIG_OBMC
unsigned int pred_variance;
#endif // CONFIG_OBMC
diff --git a/vp10/encoder/encodeframe.c b/vp10/encoder/encodeframe.c
index 06463c1..45505f1 100644
--- a/vp10/encoder/encodeframe.c
+++ b/vp10/encoder/encodeframe.c
@@ -1067,7 +1067,6 @@
x->mbmi_ext->ref_mv_stack[rf_type][mbmi->ref_mv_idx].this_mv :
x->mbmi_ext->ref_mv_stack[rf_type][mbmi->ref_mv_idx].comp_mv;
clamp_mv_ref(&this_mv.as_mv, xd->n8_w << 3, xd->n8_h << 3, xd);
- lower_mv_precision(&this_mv.as_mv, cm->allow_high_precision_mv);
x->mbmi_ext->ref_mvs[mbmi->ref_frame[i]][0] = this_mv;
mbmi->pred_mv[i] = this_mv;
}
@@ -1890,21 +1889,8 @@
#endif // CONFIG_EXT_REFS
}
-#if CONFIG_OBMC
-#if CONFIG_SUPERTX
- if (!supertx_enabled)
-#endif // CONFIG_SUPERTX
- if (is_obmc_allowed(mbmi))
- counts->obmc[mbmi->sb_type][mbmi->obmc]++;
-#endif // CONFIG_OBMC
- }
- }
-
#if CONFIG_EXT_INTER
if (cm->reference_mode != COMPOUND_REFERENCE &&
-#if CONFIG_OBMC
- !(is_obmc_allowed(mbmi) && mbmi->obmc) &&
-#endif
#if CONFIG_SUPERTX
!supertx_enabled &&
#endif
@@ -1919,16 +1905,32 @@
counts->interintra[bsize_group][0]++;
}
}
- if (cm->reference_mode != SINGLE_REFERENCE &&
- is_inter_compound_mode(mbmi->mode) &&
-#if CONFIG_OBMC
- !(is_obmc_allowed(mbmi) && mbmi->obmc) &&
-#endif // CONFIG_OBMC
- is_interinter_wedge_used(bsize)) {
- counts->wedge_interinter[bsize][mbmi->use_wedge_interinter]++;
- }
#endif // CONFIG_EXT_INTER
+#if CONFIG_OBMC
+#if CONFIG_SUPERTX
+ if (!supertx_enabled)
+#endif // CONFIG_SUPERTX
+#if CONFIG_EXT_INTER
+ if (mbmi->ref_frame[1] != INTRA_FRAME)
+#endif // CONFIG_EXT_INTER
+ if (is_obmc_allowed(mbmi))
+ counts->obmc[mbmi->sb_type][mbmi->obmc]++;
+#endif // CONFIG_OBMC
+
+#if CONFIG_EXT_INTER
+ if (cm->reference_mode != SINGLE_REFERENCE &&
+ is_inter_compound_mode(mbmi->mode) &&
+#if CONFIG_OBMC
+ !(is_obmc_allowed(mbmi) && mbmi->obmc) &&
+#endif // CONFIG_OBMC
+ is_interinter_wedge_used(bsize)) {
+ counts->wedge_interinter[bsize][mbmi->use_wedge_interinter]++;
+ }
+#endif // CONFIG_EXT_INTER
+ }
+ }
+
if (inter_block &&
!segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) {
int16_t mode_ctx = mbmi_ext->mode_context[mbmi->ref_frame[0]];
diff --git a/vp10/encoder/encoder.c b/vp10/encoder/encoder.c
index 7776c22..2d51114 100644
--- a/vp10/encoder/encoder.c
+++ b/vp10/encoder/encoder.c
@@ -4107,14 +4107,14 @@
const int last2_is_last =
map[cpi->lst_fb_idxes[1]] == map[cpi->lst_fb_idxes[0]];
const int gld_is_last2 = map[cpi->gld_fb_idx] == map[cpi->lst_fb_idxes[1]];
- const int alt_is_last2 = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idxes[1]];
+ const int last2_is_alt = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idxes[1]];
const int last3_is_last =
map[cpi->lst_fb_idxes[2]] == map[cpi->lst_fb_idxes[0]];
const int last3_is_last2 =
map[cpi->lst_fb_idxes[2]] == map[cpi->lst_fb_idxes[1]];
const int gld_is_last3 = map[cpi->gld_fb_idx] == map[cpi->lst_fb_idxes[2]];
- const int alt_is_last3 = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idxes[2]];
+ const int last3_is_alt = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idxes[2]];
const int last4_is_last =
map[cpi->lst_fb_idxes[3]] == map[cpi->lst_fb_idxes[0]];
@@ -4123,21 +4123,16 @@
const int last4_is_last3 =
map[cpi->lst_fb_idxes[3]] == map[cpi->lst_fb_idxes[2]];
const int gld_is_last4 = map[cpi->gld_fb_idx] == map[cpi->lst_fb_idxes[3]];
- const int alt_is_last4 = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idxes[3]];
+ const int last4_is_alt = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idxes[3]];
#else
const int gld_is_last = map[cpi->gld_fb_idx] == map[cpi->lst_fb_idx];
const int alt_is_last = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idx];
#endif // CONFIG_EXT_REFS
const int gld_is_alt = map[cpi->gld_fb_idx] == map[cpi->alt_fb_idx];
- int flags = VP9_ALT_FLAG | VP9_GOLD_FLAG | VP9_LAST_FLAG;
-#if CONFIG_EXT_REFS
- flags |= VP9_LAST2_FLAG;
- flags |= VP9_LAST3_FLAG;
- flags |= VP9_LAST4_FLAG;
-#endif // CONFIG_EXT_REFS
+ int flags = VP9_REFFRAME_ALL;
- if (gld_is_last)
+ if (gld_is_alt || gld_is_last)
flags &= ~VP9_GOLD_FLAG;
if (cpi->rc.frames_till_gf_update_due == INT_MAX)
@@ -4146,24 +4141,18 @@
if (alt_is_last)
flags &= ~VP9_ALT_FLAG;
- if (gld_is_alt)
- flags &= ~VP9_ALT_FLAG;
-
#if CONFIG_EXT_REFS
- if (last4_is_last || last4_is_last2 || last4_is_last3)
+ if (last4_is_alt || last4_is_last || last4_is_last2 || last4_is_last3)
flags &= ~VP9_LAST4_FLAG;
- if (last3_is_last || last3_is_last2)
+ if (last3_is_alt || last3_is_last || last3_is_last2)
flags &= ~VP9_LAST3_FLAG;
- if (last2_is_last)
+ if (last2_is_alt || last2_is_last)
flags &= ~VP9_LAST2_FLAG;
if (gld_is_last4 || gld_is_last3 || gld_is_last2)
flags &= ~VP9_GOLD_FLAG;
-
- if (alt_is_last4 || alt_is_last3 || alt_is_last2)
- flags &= ~VP9_ALT_FLAG;
#endif // CONFIG_EXT_REFS
return flags;
diff --git a/vp10/encoder/hybrid_fwd_txfm.c b/vp10/encoder/hybrid_fwd_txfm.c
index 3ccaf39..b192164 100644
--- a/vp10/encoder/hybrid_fwd_txfm.c
+++ b/vp10/encoder/hybrid_fwd_txfm.c
@@ -195,17 +195,20 @@
switch (tx_type) {
case DCT_DCT:
- if (bd == BITDEPTH_10) {
- vp10_fwd_txfm2d_4x4(src_diff, coeff, diff_stride,
- &fwd_txfm_2d_cfg_dct_dct_4, bd);
- } else {
- vp10_highbd_fht4x4(src_diff, coeff, diff_stride, tx_type);
- }
+ vp10_fwd_txfm2d_4x4(src_diff, coeff, diff_stride,
+ &fwd_txfm_2d_cfg_dct_dct_4, bd);
break;
case ADST_DCT:
+ vp10_fwd_txfm2d_4x4(src_diff, coeff, diff_stride,
+ &fwd_txfm_2d_cfg_adst_dct_4, bd);
+ break;
case DCT_ADST:
+ vp10_fwd_txfm2d_4x4(src_diff, coeff, diff_stride,
+ &fwd_txfm_2d_cfg_dct_adst_4, bd);
+ break;
case ADST_ADST:
- vp10_highbd_fht4x4_c(src_diff, coeff, diff_stride, tx_type);
+ vp10_fwd_txfm2d_4x4(src_diff, coeff, diff_stride,
+ &fwd_txfm_2d_cfg_adst_adst_4, bd);
break;
#if CONFIG_EXT_TX
case FLIPADST_DCT:
@@ -239,18 +242,20 @@
(void)fwd_txfm_opt;
switch (tx_type) {
case DCT_DCT:
- if (bd == BITDEPTH_10) {
- vp10_fwd_txfm2d_8x8(src_diff, coeff, diff_stride,
- &fwd_txfm_2d_cfg_dct_dct_8, bd);
- break;
- }
+ vp10_fwd_txfm2d_8x8(src_diff, coeff, diff_stride,
+ &fwd_txfm_2d_cfg_dct_dct_8, bd);
+ break;
case ADST_DCT:
+ vp10_fwd_txfm2d_8x8(src_diff, coeff, diff_stride,
+ &fwd_txfm_2d_cfg_adst_dct_8, bd);
+ break;
case DCT_ADST:
+ vp10_fwd_txfm2d_8x8(src_diff, coeff, diff_stride,
+ &fwd_txfm_2d_cfg_dct_adst_8, bd);
+ break;
case ADST_ADST:
- if (fwd_txfm_opt == FWD_TXFM_OPT_NORMAL)
- vp10_highbd_fht8x8(src_diff, coeff, diff_stride, tx_type);
- else // FWD_TXFM_OPT_DC
- vpx_highbd_fdct8x8_1(src_diff, coeff, diff_stride);
+ vp10_fwd_txfm2d_8x8(src_diff, coeff, diff_stride,
+ &fwd_txfm_2d_cfg_adst_adst_8, bd);
break;
#if CONFIG_EXT_TX
case FLIPADST_DCT:
@@ -285,18 +290,20 @@
(void)fwd_txfm_opt;
switch (tx_type) {
case DCT_DCT:
- if (bd == BITDEPTH_10) {
- vp10_fwd_txfm2d_16x16(src_diff, coeff, diff_stride,
- &fwd_txfm_2d_cfg_dct_dct_16, bd);
- break;
- }
+ vp10_fwd_txfm2d_16x16(src_diff, coeff, diff_stride,
+ &fwd_txfm_2d_cfg_dct_dct_16, bd);
+ break;
case ADST_DCT:
+ vp10_fwd_txfm2d_16x16(src_diff, coeff, diff_stride,
+ &fwd_txfm_2d_cfg_adst_dct_16, bd);
+ break;
case DCT_ADST:
+ vp10_fwd_txfm2d_16x16(src_diff, coeff, diff_stride,
+ &fwd_txfm_2d_cfg_dct_adst_16, bd);
+ break;
case ADST_ADST:
- if (fwd_txfm_opt == FWD_TXFM_OPT_NORMAL)
- vp10_highbd_fht16x16(src_diff, coeff, diff_stride, tx_type);
- else // FWD_TXFM_OPT_DC
- vpx_highbd_fdct16x16_1(src_diff, coeff, diff_stride);
+ vp10_fwd_txfm2d_16x16(src_diff, coeff, diff_stride,
+ &fwd_txfm_2d_cfg_adst_adst_16, bd);
break;
#if CONFIG_EXT_TX
case FLIPADST_DCT:
@@ -329,18 +336,12 @@
tran_low_t *coeff, int diff_stride,
TX_TYPE tx_type, FWD_TXFM_OPT fwd_txfm_opt,
const int bd) {
- (void)bd;
+ (void)rd_transform;
+ (void)fwd_txfm_opt;
switch (tx_type) {
case DCT_DCT:
- if (bd == BITDEPTH_10) {
- vp10_fwd_txfm2d_32x32(src_diff, coeff, diff_stride,
- &fwd_txfm_2d_cfg_dct_dct_32, bd);
- } else {
- if (fwd_txfm_opt == FWD_TXFM_OPT_NORMAL)
- highbd_fdct32x32(rd_transform, src_diff, coeff, diff_stride);
- else // FWD_TXFM_OPT_DC
- vpx_highbd_fdct32x32_1(src_diff, coeff, diff_stride);
- }
+ vp10_fwd_txfm2d_32x32(src_diff, coeff, diff_stride,
+ &fwd_txfm_2d_cfg_dct_dct_32, bd);
break;
#if CONFIG_EXT_TX
case ADST_DCT:
diff --git a/vp10/encoder/rdopt.c b/vp10/encoder/rdopt.c
index 05cb75c..e7762a5 100644
--- a/vp10/encoder/rdopt.c
+++ b/vp10/encoder/rdopt.c
@@ -81,12 +81,6 @@
#define MIN_EARLY_TERM_INDEX 3
#define NEW_MV_DISCOUNT_FACTOR 8
-#if CONFIG_EXT_TX
-const double ext_tx_th = 0.99;
-#else
-const double ext_tx_th = 0.99;
-#endif
-
const double ADST_FLIP_SVM[8] = {-6.6623, -2.8062, -3.2531, 3.1671, // vert
-7.7051, -3.2234, -3.6193, 3.4533}; // horz
@@ -1001,7 +995,8 @@
const struct macroblock_plane *const p = &x->plane[plane];
const struct macroblockd_plane *const pd = &xd->plane[plane];
int64_t this_sse;
- int shift = (MAX_TX_SCALE - get_tx_scale(xd, 0, tx_size)) * 2;
+ int tx_type = get_tx_type(pd->plane_type, xd, block, tx_size);
+ int shift = (MAX_TX_SCALE - get_tx_scale(xd, tx_type, tx_size)) * 2;
tran_low_t *const coeff = BLOCK_OFFSET(p->coeff, block);
tran_low_t *const dqcoeff = BLOCK_OFFSET(pd->dqcoeff, block);
#if CONFIG_VP9_HIGHBITDEPTH
@@ -1175,7 +1170,9 @@
const int64_t orig_sse = (int64_t)coeff[0] * coeff[0];
const int64_t resd_sse = coeff[0] - dqcoeff[0];
int64_t dc_correct = orig_sse - resd_sse * resd_sse;
- int shift = (MAX_TX_SCALE - get_tx_scale(xd, 0, tx_size)) * 2;
+ const struct macroblockd_plane *const pd = &xd->plane[plane];
+ TX_TYPE tx_type = get_tx_type(pd->plane_type, xd, block, tx_size);
+ int shift = (MAX_TX_SCALE - get_tx_scale(xd, tx_type, tx_size)) * 2;
#if CONFIG_VP9_HIGHBITDEPTH
dc_correct >>= ((xd->bd - 8) * 2);
#endif
@@ -1435,7 +1432,9 @@
last_rd = INT64_MAX;
for (n = start_tx; n >= end_tx; --n) {
if (FIXED_TX_TYPE && tx_type != get_default_tx_type(0, xd, 0, n))
- continue;
+ continue;
+ if (max_tx_size == TX_32X32 && n == TX_4X4)
+ continue;
#if CONFIG_EXT_TX
ext_tx_set = get_ext_tx_set(n, bs, is_inter);
if (is_inter) {
@@ -1562,7 +1561,7 @@
if (is_inter_block(mbmi) && !xd->lossless[mbmi->segment_id] && !s)
this_rd = VPXMIN(this_rd, RDCOST(x->rdmult, x->rddiv, s1, psse));
- if (this_rd < ((best_tx_type == DCT_DCT) ? ext_tx_th : 1) * best_rd) {
+ if (this_rd < best_rd) {
best_rd = this_rd;
best_tx_type = mbmi->tx_type;
}
@@ -1597,7 +1596,7 @@
if (is_inter && !xd->lossless[mbmi->segment_id] && !s)
this_rd = VPXMIN(this_rd, RDCOST(x->rdmult, x->rddiv, s1, psse));
- if (this_rd < ((best_tx_type == DCT_DCT) ? ext_tx_th : 1) * best_rd) {
+ if (this_rd < best_rd) {
best_rd = this_rd;
best_tx_type = mbmi->tx_type;
}
@@ -1658,9 +1657,13 @@
*psse = INT64_MAX;
for (tx_type = DCT_DCT; tx_type < TX_TYPES; ++tx_type) {
+#if CONFIG_REF_MV
+ if (tx_type != DCT_DCT && is_inter && mbmi->ref_mv_idx > 0)
+ continue;
+#endif
rd = choose_tx_size_fix_type(cpi, x, &r, &d, &s, &sse, ref_best_rd, bs,
tx_type, prune);
- if (rd < (is_inter && best_tx_type == DCT_DCT ? ext_tx_th : 1) * best_rd) {
+ if (rd < best_rd) {
best_rd = rd;
*distortion = d;
*rate = r;
@@ -1678,12 +1681,6 @@
if (mbmi->tx_size >= TX_32X32)
assert(mbmi->tx_type == DCT_DCT);
#endif
-
- txfm_rd_in_plane(x,
- cpi,
- &r, &d, &s,
- &sse, ref_best_rd, 0, bs, best_tx,
- cpi->sf.use_fast_coef_costing);
}
static void super_block_yrd(VP10_COMP *cpi, MACROBLOCK *x, int *rate,
@@ -3282,7 +3279,7 @@
rd = select_tx_size_fix_type(cpi, x, &this_rate, &this_dist, &this_skip,
&this_sse, bsize, ref_best_rd, tx_type);
- if (rd < (is_inter && best_tx_type == DCT_DCT ? ext_tx_th : 1) * best_rd) {
+ if (rd < best_rd) {
best_rd = rd;
*distortion = this_dist;
*rate = this_rate;
@@ -4951,7 +4948,7 @@
#if CONFIG_REF_MV
run_mv_search = 2;
#if !CONFIG_EXT_INTER
- if (filter_idx > 0) {
+ if (filter_idx > 0 && this_mode == NEWMV) {
BEST_SEG_INFO* ref_bsi = bsi_buf;
SEG_RDSTAT *ref_rdstat = &ref_bsi->rdstat[i][mode_idx];
@@ -5345,6 +5342,24 @@
ref_bsi->rdstat[i + 2][mode_idx].eobs;
if (bsi->rdstat[i][mode_idx].brdcost < best_rd) {
+#if CONFIG_REF_MV
+ // If the NEWMV mode is using the same motion vector as the
+ // NEARESTMV mode, skip the rest rate-distortion calculations
+ // and use the inferred motion vector modes.
+ if (this_mode == NEWMV) {
+ if (has_second_rf) {
+ if (bsi->rdstat[i][mode_idx].mvs[0].as_int ==
+ bsi->ref_mv[0]->as_int &&
+ bsi->rdstat[i][mode_idx].mvs[1].as_int ==
+ bsi->ref_mv[1]->as_int)
+ continue;
+ } else {
+ if (bsi->rdstat[i][mode_idx].mvs[0].as_int ==
+ bsi->ref_mv[0]->as_int)
+ continue;
+ }
+ }
+#endif
mode_selected = this_mode;
best_rd = bsi->rdstat[i][mode_idx].brdcost;
}
@@ -5375,6 +5390,24 @@
}
if (bsi->rdstat[i][mode_idx].brdcost < best_rd) {
+#if CONFIG_REF_MV
+ // If the NEWMV mode is using the same motion vector as the
+ // NEARESTMV mode, skip the rest rate-distortion calculations
+ // and use the inferred motion vector modes.
+ if (this_mode == NEWMV) {
+ if (has_second_rf) {
+ if (bsi->rdstat[i][mode_idx].mvs[0].as_int ==
+ bsi->ref_mv[0]->as_int &&
+ bsi->rdstat[i][mode_idx].mvs[1].as_int ==
+ bsi->ref_mv[1]->as_int)
+ continue;
+ } else {
+ if (bsi->rdstat[i][mode_idx].mvs[0].as_int ==
+ bsi->ref_mv[0]->as_int)
+ continue;
+ }
+ }
+#endif
mode_selected = this_mode;
best_rd = bsi->rdstat[i][mode_idx].brdcost;
}
@@ -6241,6 +6274,10 @@
int64_t best_distortion = INT64_MAX;
unsigned int best_pred_var = UINT_MAX;
MB_MODE_INFO best_mbmi;
+#if CONFIG_EXT_INTER
+ int rate2_bmc_nocoeff;
+ MB_MODE_INFO best_bmc_mbmi;
+#endif // CONFIG_EXT_INTER
#endif // CONFIG_OBMC
int pred_exists = 0;
@@ -6271,9 +6308,6 @@
assert(!is_comp_interintra_pred || is_interintra_allowed(mbmi));
#endif // CONFIG_EXT_INTER
-#if CONFIG_OBMC
- tmp_rd = 0;
-#endif // CONFIG_OBMC
#if CONFIG_REF_MV
#if CONFIG_EXT_INTER
if (is_comp_pred)
@@ -6414,7 +6448,6 @@
cur_mv[1] = mbmi_ext->ref_mv_stack[ref_frame_type][0].comp_mv;
for (i = 0; i < 2; ++i) {
- lower_mv_precision(&cur_mv[i].as_mv, cm->allow_high_precision_mv);
clamp_mv2(&cur_mv[i].as_mv, xd);
if (mv_check_bounds(x, &cur_mv[i].as_mv))
return INT64_MAX;
@@ -6476,7 +6509,6 @@
cur_mv[1] = mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].comp_mv;
for (i = 0; i < 2; ++i) {
- lower_mv_precision(&cur_mv[i].as_mv, cm->allow_high_precision_mv);
clamp_mv2(&cur_mv[i].as_mv, xd);
if (mv_check_bounds(x, &cur_mv[i].as_mv))
return INT64_MAX;
@@ -6636,6 +6668,12 @@
rs = cm->interp_filter == SWITCHABLE ? vp10_get_switchable_rate(cpi, xd) : 0;
#if CONFIG_EXT_INTER
+#if CONFIG_OBMC
+ best_bmc_mbmi = *mbmi;
+ rate2_bmc_nocoeff = *rate2;
+ if (cm->interp_filter == SWITCHABLE)
+ rate2_bmc_nocoeff += rs;
+#endif // CONFIG_OBMC
if (is_comp_pred && is_interinter_wedge_used(bsize)) {
int wedge_index, best_wedge_index = WEDGE_NONE, rs;
int rate_sum;
@@ -6748,7 +6786,6 @@
xd, bsize, mi_row, mi_col, 1, preds1, strides);
for (wedge_index = 0; wedge_index < wedge_types; ++wedge_index) {
mbmi->interinter_wedge_index = wedge_index;
- // vp10_build_inter_predictors_sb(xd, mi_row, mi_col, bsize);
vp10_build_wedge_inter_predictor_from_buf(xd, bsize, mi_row, mi_col,
preds0, strides,
preds1, strides);
@@ -6767,12 +6804,8 @@
mbmi->use_wedge_interinter = 0;
}
}
-#if CONFIG_OBMC
- if (mbmi->use_wedge_interinter)
- allow_obmc = 0;
-#endif // CONFIG_OBMC
if (ref_best_rd < INT64_MAX &&
- VPXMIN(best_rd_wedge, best_rd_nowedge) / 2 > ref_best_rd)
+ VPXMIN(best_rd_wedge, best_rd_nowedge) / 3 > ref_best_rd)
return INT64_MAX;
pred_exists = 0;
@@ -7072,7 +7105,6 @@
memcpy(x->skip_txfm, skip_txfm, sizeof(skip_txfm));
memcpy(x->bsse, bsse, sizeof(bsse));
-
#if CONFIG_OBMC
best_rd = INT64_MAX;
for (mbmi->obmc = 0; mbmi->obmc <= allow_obmc; mbmi->obmc++) {
@@ -7080,6 +7112,12 @@
int tmp_rate;
if (mbmi->obmc) {
+#if CONFIG_EXT_INTER
+ *mbmi = best_bmc_mbmi;
+ assert(!mbmi->use_wedge_interinter);
+ vp10_build_inter_predictors_sb(xd, mi_row, mi_col, bsize);
+ mbmi->obmc = 1;
+#endif // CONFIG_EXT_INTER
vp10_build_obmc_inter_prediction(cm, xd, mi_row, mi_col, 0,
NULL, NULL,
dst_buf1, dst_stride1,
@@ -7099,13 +7137,16 @@
x->pred_variance =
vp10_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize);
#endif // CONFIG_VP9_HIGHBITDEPTH
-
x->skip = 0;
+#if CONFIG_EXT_INTER
+ *rate2 = mbmi->obmc ? rate2_bmc_nocoeff : rate2_nocoeff;
+#else
*rate2 = rate2_nocoeff;
- *distortion = 0;
+#endif // CONFIG_EXT_INTER
if (allow_obmc)
*rate2 += cpi->obmc_cost[bsize][mbmi->obmc];
+ *distortion = 0;
#endif // CONFIG_OBMC
if (!skip_txfm_sb) {
int skippable_y, skippable_uv;
@@ -7260,6 +7301,20 @@
if (!is_comp_pred)
single_skippable[this_mode][refs[0]] = *skippable;
+#if CONFIG_VP9_HIGHBITDEPTH
+ if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
+ x->recon_variance =
+ vp10_high_get_sby_perpixel_variance(cpi, &xd->plane[0].dst,
+ bsize, xd->bd);
+ } else {
+ x->recon_variance =
+ vp10_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize);
+ }
+#else
+ x->recon_variance =
+ vp10_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize);
+#endif // CONFIG_VP9_HIGHBITDEPTH
+
restore_dst_buf(xd, orig_dst, orig_dst_stride);
return 0; // The rate-distortion cost will be re-calculated by caller.
}
@@ -7320,17 +7375,14 @@
#define LOW_VAR_THRESH 16
#define VLOW_ADJ_MAX 25
#define VHIGH_ADJ_MAX 8
-static void rd_variance_adjustment(VP10_COMP *cpi,
- MACROBLOCK *x,
- BLOCK_SIZE bsize,
+static void rd_variance_adjustment(MACROBLOCK *x,
int64_t *this_rd,
MV_REFERENCE_FRAME ref_frame,
#if CONFIG_OBMC
int is_pred_var_available,
#endif // CONFIG_OBMC
unsigned int source_variance) {
- MACROBLOCKD *const xd = &x->e_mbd;
- unsigned int recon_variance;
+ unsigned int recon_variance = x->recon_variance;
unsigned int absvar_diff = 0;
int64_t var_error = 0;
int64_t var_factor = 0;
@@ -7339,24 +7391,8 @@
return;
#if CONFIG_OBMC
- if (is_pred_var_available) {
+ if (is_pred_var_available)
recon_variance = x->pred_variance;
- } else {
-#endif // CONFIG_OBMC
-#if CONFIG_VP9_HIGHBITDEPTH
- if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
- recon_variance =
- vp10_high_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize, xd->bd);
- } else {
- recon_variance =
- vp10_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize);
- }
-#else
- recon_variance =
- vp10_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize);
-#endif // CONFIG_VP9_HIGHBITDEPTH
-#if CONFIG_OBMC
- }
#endif // CONFIG_OBMC
if ((source_variance + recon_variance) > LOW_VAR_THRESH) {
@@ -7780,6 +7816,7 @@
if (cpi->rc.is_src_frame_alt_ref) {
if (sf->alt_ref_search_fp) {
+ assert(cpi->ref_frame_flags & flag_list[ALTREF_FRAME]);
mode_skip_mask[ALTREF_FRAME] = 0;
ref_frame_skip_mask[0] = ~(1 << ALTREF_FRAME);
ref_frame_skip_mask[1] = SECOND_REF_FRAME_MASK;
@@ -8206,6 +8243,20 @@
if (this_mode != DC_PRED && this_mode != TM_PRED)
rate2 += intra_cost_penalty;
distortion2 = distortion_y + distortion_uv;
+ vp10_encode_intra_block_plane(x, bsize, 0);
+#if CONFIG_VP9_HIGHBITDEPTH
+ if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
+ x->recon_variance =
+ vp10_high_get_sby_perpixel_variance(cpi, &xd->plane[0].dst,
+ bsize, xd->bd);
+ } else {
+ x->recon_variance =
+ vp10_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize);
+ }
+#else
+ x->recon_variance =
+ vp10_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize);
+#endif // CONFIG_VP9_HIGHBITDEPTH
} else {
#if CONFIG_REF_MV
int_mv backup_ref_mv[2];
@@ -8243,7 +8294,6 @@
mbmi_ext->ref_mv_stack[ref_frame_type][0].this_mv :
mbmi_ext->ref_mv_stack[ref_frame_type][0].comp_mv;
clamp_mv_ref(&this_mv.as_mv, xd->n8_w << 3, xd->n8_h << 3, xd);
- lower_mv_precision(&this_mv.as_mv, cm->allow_high_precision_mv);
mbmi_ext->ref_mvs[mbmi->ref_frame[ref]][0] = this_mv;
}
}
@@ -8333,13 +8383,11 @@
mbmi_ext->ref_mv_stack[ref_frame_type]
[mbmi->ref_mv_idx].comp_mv;
clamp_mv_ref(&this_mv.as_mv, xd->n8_w << 3, xd->n8_h << 3, xd);
- lower_mv_precision(&this_mv.as_mv, cm->allow_high_precision_mv);
mbmi_ext->ref_mvs[mbmi->ref_frame[ref]][0] = this_mv;
}
cur_mv = mbmi_ext->ref_mv_stack[ref_frame]
[mbmi->ref_mv_idx + idx_offset].this_mv;
- lower_mv_precision(&cur_mv.as_mv, cm->allow_high_precision_mv);
clamp_mv2(&cur_mv.as_mv, xd);
if (!mv_check_bounds(x, &cur_mv.as_mv)) {
@@ -8465,6 +8513,9 @@
#if CONFIG_EXT_INTER
rate2 += compmode_interintra_cost;
if (cm->reference_mode != SINGLE_REFERENCE && comp_pred)
+#if CONFIG_OBMC
+ if (mbmi->obmc == 0)
+#endif // CONFIG_OBMC
rate2 += compmode_wedge_cost;
#endif // CONFIG_EXT_INTER
@@ -8519,7 +8570,7 @@
// Apply an adjustment to the rd value based on the similarity of the
// source variance and reconstructed variance.
- rd_variance_adjustment(cpi, x, bsize, &this_rd, ref_frame,
+ rd_variance_adjustment(x, &this_rd, ref_frame,
#if CONFIG_OBMC
is_inter_block(mbmi),
#endif // CONFIG_OBMC
@@ -8571,7 +8622,7 @@
*returnrate_nocoef -= vp10_cost_bit(vp10_get_intra_inter_prob(cm, xd),
mbmi->ref_frame[0] != INTRA_FRAME);
#if CONFIG_OBMC
- if (is_neighbor_overlappable(mbmi) && is_obmc_allowed(mbmi))
+ if (is_inter_block(mbmi) && is_obmc_allowed(mbmi))
*returnrate_nocoef -= cpi->obmc_cost[bsize][mbmi->obmc];
#endif // CONFIG_OBMC
#endif // CONFIG_SUPERTX
@@ -8785,7 +8836,6 @@
for (i = 0; i <= ref_set && ref_set != INT_MAX; ++i) {
int_mv cur_mv = mbmi_ext->ref_mv_stack[rf_type][i + 1].this_mv;
- lower_mv_precision(&cur_mv.as_mv, cm->allow_high_precision_mv);
if (cur_mv.as_int == best_mbmode.mv[0].as_int) {
best_mbmode.mode = NEARMV;
best_mbmode.ref_mv_idx = i;
@@ -8798,7 +8848,6 @@
best_mbmode.mode = ZEROMV;
} else {
int i;
- const int allow_hp = cm->allow_high_precision_mv;
int_mv nearestmv[2] = { frame_mv[NEARESTMV][refs[0]],
frame_mv[NEARESTMV][refs[1]] };
int_mv nearmv[2] = { frame_mv[NEARMV][refs[0]],
@@ -8816,8 +8865,6 @@
for (i = 0; i <= ref_set && ref_set != INT_MAX; ++i) {
nearmv[0] = mbmi_ext->ref_mv_stack[rf_type][i + 1].this_mv;
nearmv[1] = mbmi_ext->ref_mv_stack[rf_type][i + 1].comp_mv;
- lower_mv_precision(&nearmv[0].as_mv, allow_hp);
- lower_mv_precision(&nearmv[1].as_mv, allow_hp);
if (nearmv[0].as_int == best_mbmode.mv[0].as_int &&
nearmv[1].as_int == best_mbmode.mv[1].as_int) {
@@ -8832,11 +8879,6 @@
nearestmv[1] = mbmi_ext->ref_mv_stack[rf_type][0].comp_mv;
}
- for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) {
- lower_mv_precision(&nearestmv[i].as_mv, allow_hp);
- lower_mv_precision(&nearmv[i].as_mv, allow_hp);
- }
-
if (nearestmv[0].as_int == best_mbmode.mv[0].as_int &&
nearestmv[1].as_int == best_mbmode.mv[1].as_int)
#if CONFIG_EXT_INTER
diff --git a/vp10/encoder/resize.c b/vp10/encoder/resize.c
index e339fa3..353e513 100644
--- a/vp10/encoder/resize.c
+++ b/vp10/encoder/resize.c
@@ -445,7 +445,7 @@
int length,
uint8_t *output,
int olength,
- uint8_t *buf) {
+ uint8_t *otmp) {
int steps;
if (length == olength) {
memcpy(output, input, sizeof(output[0]) * length);
@@ -456,16 +456,10 @@
if (steps > 0) {
int s;
uint8_t *out = NULL;
- uint8_t *tmpbuf = NULL;
- uint8_t *otmp, *otmp2;
+ uint8_t *otmp2;
int filteredlength = length;
- if (!tmpbuf) {
- tmpbuf = (uint8_t *)malloc(sizeof(uint8_t) * length);
- if (tmpbuf == NULL) return;
- otmp = tmpbuf;
- } else {
- otmp = buf;
- }
+
+ assert(otmp != NULL);
otmp2 = otmp + get_down2_length(length, 1);
for (s = 0; s < steps; ++s) {
const int proj_filteredlength = get_down2_length(filteredlength, 1);
@@ -483,8 +477,6 @@
if (filteredlength != olength) {
interpolate(out, filteredlength, output, olength);
}
- if (tmpbuf)
- free(tmpbuf);
} else {
interpolate(input, length, output, olength);
}
@@ -520,8 +512,11 @@
uint8_t *intbuf = (uint8_t *)malloc(sizeof(uint8_t) * width2 * height);
uint8_t *tmpbuf = (uint8_t *)malloc(sizeof(uint8_t) *
(width < height ? height : width));
- uint8_t *arrbuf = (uint8_t *)malloc(sizeof(uint8_t) * (height + height2));
- if (intbuf == NULL || tmpbuf == NULL || arrbuf == NULL) goto Error;
+ uint8_t *arrbuf = (uint8_t *)malloc(sizeof(uint8_t) * height);
+ uint8_t *arrbuf2 = (uint8_t *)malloc(sizeof(uint8_t) * height2);
+ if (intbuf == NULL || tmpbuf == NULL ||
+ arrbuf == NULL || arrbuf2 == NULL)
+ goto Error;
assert(width > 0);
assert(height > 0);
assert(width2 > 0);
@@ -531,14 +526,15 @@
intbuf + width2 * i, width2, tmpbuf);
for (i = 0; i < width2; ++i) {
fill_col_to_arr(intbuf + i, width2, height, arrbuf);
- resize_multistep(arrbuf, height, arrbuf + height, height2, tmpbuf);
- fill_arr_to_col(output + i, out_stride, height2, arrbuf + height);
+ resize_multistep(arrbuf, height, arrbuf2, height2, tmpbuf);
+ fill_arr_to_col(output + i, out_stride, height2, arrbuf2);
}
Error:
free(intbuf);
free(tmpbuf);
free(arrbuf);
+ free(arrbuf2);
}
#if CONFIG_VP9_HIGHBITDEPTH
@@ -741,7 +737,7 @@
int length,
uint16_t *output,
int olength,
- uint16_t *buf,
+ uint16_t *otmp,
int bd) {
int steps;
if (length == olength) {
@@ -753,16 +749,10 @@
if (steps > 0) {
int s;
uint16_t *out = NULL;
- uint16_t *tmpbuf = NULL;
- uint16_t *otmp, *otmp2;
+ uint16_t *otmp2;
int filteredlength = length;
- if (!tmpbuf) {
- tmpbuf = (uint16_t *)malloc(sizeof(uint16_t) * length);
- if (tmpbuf == NULL) return;
- otmp = tmpbuf;
- } else {
- otmp = buf;
- }
+
+ assert(otmp != NULL);
otmp2 = otmp + get_down2_length(length, 1);
for (s = 0; s < steps; ++s) {
const int proj_filteredlength = get_down2_length(filteredlength, 1);
@@ -780,8 +770,6 @@
if (filteredlength != olength) {
highbd_interpolate(out, filteredlength, output, olength, bd);
}
- if (tmpbuf)
- free(tmpbuf);
} else {
highbd_interpolate(input, length, output, olength, bd);
}
@@ -820,24 +808,27 @@
uint16_t *intbuf = (uint16_t *)malloc(sizeof(uint16_t) * width2 * height);
uint16_t *tmpbuf = (uint16_t *)malloc(sizeof(uint16_t) *
(width < height ? height : width));
- uint16_t *arrbuf = (uint16_t *)malloc(sizeof(uint16_t) * (height + height2));
- if (intbuf == NULL || tmpbuf == NULL || arrbuf == NULL) goto Error;
+ uint16_t *arrbuf = (uint16_t *)malloc(sizeof(uint16_t) * height);
+ uint16_t *arrbuf2 = (uint16_t *)malloc(sizeof(uint16_t) * height2);
+ if (intbuf == NULL || tmpbuf == NULL ||
+ arrbuf == NULL || arrbuf2 == NULL) goto Error;
for (i = 0; i < height; ++i) {
highbd_resize_multistep(CONVERT_TO_SHORTPTR(input + in_stride * i), width,
intbuf + width2 * i, width2, tmpbuf, bd);
}
for (i = 0; i < width2; ++i) {
highbd_fill_col_to_arr(intbuf + i, width2, height, arrbuf);
- highbd_resize_multistep(arrbuf, height, arrbuf + height, height2, tmpbuf,
+ highbd_resize_multistep(arrbuf, height, arrbuf2, height2, tmpbuf,
bd);
highbd_fill_arr_to_col(CONVERT_TO_SHORTPTR(output + i), out_stride, height2,
- arrbuf + height);
+ arrbuf2);
}
Error:
free(intbuf);
free(tmpbuf);
free(arrbuf);
+ free(arrbuf2);
}
#endif // CONFIG_VP9_HIGHBITDEPTH
diff --git a/vp10/encoder/x86/highbd_fwd_txfm_sse4.c b/vp10/encoder/x86/highbd_fwd_txfm_sse4.c
index 5fa4fc8..16323b3 100644
--- a/vp10/encoder/x86/highbd_fwd_txfm_sse4.c
+++ b/vp10/encoder/x86/highbd_fwd_txfm_sse4.c
@@ -13,15 +13,14 @@
#include "./vp10_rtcd.h"
#include "./vpx_config.h"
+#include "vp10/common/vp10_fwd_txfm2d_cfg.h"
+#include "vp10/common/vp10_txfm.h"
#include "vpx_dsp/txfm_common.h"
#include "vpx_ports/mem.h"
static INLINE void load_buffer_4x4(const int16_t *input, __m128i *in,
- int stride, int flipud, int fliplr) {
- const __m128i k__nonzero_bias_a = _mm_setr_epi32(0, 1, 1, 1);
- const __m128i k__nonzero_bias_b = _mm_setr_epi32(1, 0, 0, 0);
- __m128i mask;
-
+ int stride, int flipud, int fliplr,
+ int shift) {
if (!flipud) {
in[0] = _mm_loadl_epi64((const __m128i *)(input + 0 * stride));
in[1] = _mm_loadl_epi64((const __m128i *)(input + 1 * stride));
@@ -46,120 +45,73 @@
in[2] = _mm_cvtepi16_epi32(in[2]);
in[3] = _mm_cvtepi16_epi32(in[3]);
- in[0] = _mm_slli_epi32(in[0], 4);
- in[1] = _mm_slli_epi32(in[1], 4);
- in[2] = _mm_slli_epi32(in[2], 4);
- in[3] = _mm_slli_epi32(in[3], 4);
-
- mask = _mm_cmpeq_epi32(in[0], k__nonzero_bias_a);
- in[0] = _mm_add_epi32(in[0], mask);
- in[0] = _mm_add_epi32(in[0], k__nonzero_bias_b);
+ in[0] = _mm_slli_epi32(in[0], shift);
+ in[1] = _mm_slli_epi32(in[1], shift);
+ in[2] = _mm_slli_epi32(in[2], shift);
+ in[3] = _mm_slli_epi32(in[3], shift);
}
-static void fdct4x4_sse4_1(__m128i *in) {
- const __m128i k__cospi_p16_p16 = _mm_set1_epi64x(cospi_16_64);
- const __m128i k__cospi_m16_m16 = _mm_set1_epi64x(-cospi_16_64);
- const __m128i k__cospi_p08_p08 = _mm_set1_epi64x(cospi_8_64);
- const __m128i k__cospi_m08_m08 = _mm_set1_epi64x(-cospi_8_64);
- const __m128i k__cospi_p24_p24 = _mm_set1_epi64x(cospi_24_64);
- const __m128i k__DCT_CONST_ROUNDING = _mm_set1_epi64x(DCT_CONST_ROUNDING);
-
- __m128i s[8];
+// We only use stage-2 bit;
+// shift[0] is used in load_buffer_4x4()
+// shift[1] is used in txfm_func_col()
+// shift[2] is used in txfm_func_row()
+static void fdct4x4_sse4_1(__m128i *in, int bit) {
+ const int32_t *cospi = cospi_arr[bit - cos_bit_min];
+ const __m128i cospi32 = _mm_set1_epi32(cospi[32]);
+ const __m128i cospi48 = _mm_set1_epi32(cospi[48]);
+ const __m128i cospi16 = _mm_set1_epi32(cospi[16]);
+ const __m128i rnding = _mm_set1_epi32(1 << (bit - 1));
+ __m128i s0, s1, s2, s3;
__m128i u0, u1, u2, u3;
- __m128i v0, v1, v2, v3, v4, v5, v6, v7;
+ __m128i v0, v1, v2, v3;
- s[0] = _mm_add_epi32(in[0], in[3]);
- s[1] = _mm_add_epi32(in[1], in[2]);
- s[2] = _mm_sub_epi32(in[1], in[2]);
- s[3] = _mm_sub_epi32(in[0], in[3]);
+ s0 = _mm_add_epi32(in[0], in[3]);
+ s1 = _mm_add_epi32(in[1], in[2]);
+ s2 = _mm_sub_epi32(in[1], in[2]);
+ s3 = _mm_sub_epi32(in[0], in[3]);
- v0 = _mm_cvtepi32_epi64(s[0]); // s01 s00
- v1 = _mm_cvtepi32_epi64(_mm_unpackhi_epi64(s[0], s[0])); // s03 s02
- v2 = _mm_cvtepi32_epi64(s[1]); // s11 s10
- v3 = _mm_cvtepi32_epi64(_mm_unpackhi_epi64(s[1], s[1])); // s13 s12
- v4 = _mm_cvtepi32_epi64(s[2]); // s21 s20
- v5 = _mm_cvtepi32_epi64(_mm_unpackhi_epi64(s[2], s[2])); // s23 s22
- v6 = _mm_cvtepi32_epi64(s[3]); // s31 s30
- v7 = _mm_cvtepi32_epi64(_mm_unpackhi_epi64(s[3], s[3])); // s33 s32
+ // btf_32_sse4_1_type0(cospi32, cospi32, s[01], u[02], bit);
+ u0 = _mm_mullo_epi32(s0, cospi32);
+ u1 = _mm_mullo_epi32(s1, cospi32);
+ u2 = _mm_add_epi32(u0, u1);
+ v0 = _mm_sub_epi32(u0, u1);
- u0 = _mm_mul_epi32(v0, k__cospi_p16_p16);
- u1 = _mm_mul_epi32(v1, k__cospi_p16_p16);
- u2 = _mm_mul_epi32(v2, k__cospi_p16_p16);
- u3 = _mm_mul_epi32(v3, k__cospi_p16_p16);
+ u3 = _mm_add_epi32(u2, rnding);
+ v1 = _mm_add_epi32(v0, rnding);
- s[0] = _mm_add_epi64(u0, u2); // y10 y00
- s[1] = _mm_add_epi64(u1, u3); // y30 y20
+ u0 = _mm_srai_epi32(u3, bit);
+ u2 = _mm_srai_epi32(v1, bit);
- u2 = _mm_mul_epi32(v2, k__cospi_m16_m16);
- u3 = _mm_mul_epi32(v3, k__cospi_m16_m16);
+ // btf_32_sse4_1_type1(cospi48, cospi16, s[23], u[13], bit);
+ v0 = _mm_mullo_epi32(s2, cospi48);
+ v1 = _mm_mullo_epi32(s3, cospi16);
+ v2 = _mm_add_epi32(v0, v1);
- s[2] = _mm_add_epi64(u0, u2); // y12 y02
- s[3] = _mm_add_epi64(u1, u3); // y32 y22
+ v3 = _mm_add_epi32(v2, rnding);
+ u1 = _mm_srai_epi32(v3, bit);
- u0 = _mm_mul_epi32(v6, k__cospi_p08_p08);
- u1 = _mm_mul_epi32(v5, k__cospi_p24_p24);
- u2 = _mm_mul_epi32(v4, k__cospi_p24_p24);
- u3 = _mm_mul_epi32(v7, k__cospi_p08_p08);
+ v0 = _mm_mullo_epi32(s2, cospi16);
+ v1 = _mm_mullo_epi32(s3, cospi48);
+ v2 = _mm_sub_epi32(v1, v0);
- s[4] = _mm_add_epi64(u0, u2); // y11 y01
- s[5] = _mm_add_epi64(u1, u3); // y31 y21
+ v3 = _mm_add_epi32(v2, rnding);
+ u3 = _mm_srai_epi32(v3, bit);
- u0 = _mm_mul_epi32(v4, k__cospi_m08_m08);
- u1 = _mm_mul_epi32(v5, k__cospi_m08_m08);
- u2 = _mm_mul_epi32(v6, k__cospi_p24_p24);
- u3 = _mm_mul_epi32(v7, k__cospi_p24_p24);
+ // Note: shift[1] and shift[2] are zeros
- s[6] = _mm_add_epi64(u0, u2); // y13 y03
- s[7] = _mm_add_epi64(u1, u3); // y33 y23
+ // Transpose 4x4 32-bit
+ v0 = _mm_unpacklo_epi32(u0, u1);
+ v1 = _mm_unpackhi_epi32(u0, u1);
+ v2 = _mm_unpacklo_epi32(u2, u3);
+ v3 = _mm_unpackhi_epi32(u2, u3);
- s[0] = _mm_add_epi64(s[0], k__DCT_CONST_ROUNDING);
- s[1] = _mm_add_epi64(s[1], k__DCT_CONST_ROUNDING);
- s[2] = _mm_add_epi64(s[2], k__DCT_CONST_ROUNDING);
- s[3] = _mm_add_epi64(s[3], k__DCT_CONST_ROUNDING);
- s[4] = _mm_add_epi64(s[4], k__DCT_CONST_ROUNDING);
- s[5] = _mm_add_epi64(s[5], k__DCT_CONST_ROUNDING);
- s[6] = _mm_add_epi64(s[6], k__DCT_CONST_ROUNDING);
- s[7] = _mm_add_epi64(s[7], k__DCT_CONST_ROUNDING);
-
- s[0] = _mm_srli_epi64(s[0], DCT_CONST_BITS);
- s[1] = _mm_srli_epi64(s[1], DCT_CONST_BITS);
- s[2] = _mm_srli_epi64(s[2], DCT_CONST_BITS);
- s[3] = _mm_srli_epi64(s[3], DCT_CONST_BITS);
- s[4] = _mm_srli_epi64(s[4], DCT_CONST_BITS);
- s[5] = _mm_srli_epi64(s[5], DCT_CONST_BITS);
- s[6] = _mm_srli_epi64(s[6], DCT_CONST_BITS);
- s[7] = _mm_srli_epi64(s[7], DCT_CONST_BITS);
-
- s[0] = _mm_shuffle_epi32(s[0], 0x88);
- s[1] = _mm_shuffle_epi32(s[1], 0x88);
- s[2] = _mm_shuffle_epi32(s[2], 0x88);
- s[3] = _mm_shuffle_epi32(s[3], 0x88);
- s[4] = _mm_shuffle_epi32(s[4], 0x88);
- s[5] = _mm_shuffle_epi32(s[5], 0x88);
- s[6] = _mm_shuffle_epi32(s[6], 0x88);
- s[7] = _mm_shuffle_epi32(s[7], 0x88);
-
- v0 = _mm_unpacklo_epi32(s[0], s[4]);
- v1 = _mm_unpacklo_epi32(s[2], s[6]);
- v2 = _mm_unpacklo_epi32(s[1], s[5]);
- v3 = _mm_unpacklo_epi32(s[3], s[7]);
-
- in[0] = _mm_unpacklo_epi64(v0, v1);
- in[1] = _mm_unpackhi_epi64(v0, v1);
- in[2] = _mm_unpacklo_epi64(v2, v3);
- in[3] = _mm_unpackhi_epi64(v2, v3);
+ in[0] = _mm_unpacklo_epi64(v0, v2);
+ in[1] = _mm_unpackhi_epi64(v0, v2);
+ in[2] = _mm_unpacklo_epi64(v1, v3);
+ in[3] = _mm_unpackhi_epi64(v1, v3);
}
static INLINE void write_buffer_4x4(tran_low_t *output, __m128i *res) {
- const __m128i kOne = _mm_set1_epi32(1);
- res[0] = _mm_add_epi32(res[0], kOne);
- res[1] = _mm_add_epi32(res[1], kOne);
- res[2] = _mm_add_epi32(res[2], kOne);
- res[3] = _mm_add_epi32(res[3], kOne);
- res[0] = _mm_srai_epi32(res[0], 2);
- res[1] = _mm_srai_epi32(res[1], 2);
- res[2] = _mm_srai_epi32(res[2], 2);
- res[3] = _mm_srai_epi32(res[3], 2);
_mm_store_si128((__m128i *)(output + 0 * 4), res[0]);
_mm_store_si128((__m128i *)(output + 1 * 4), res[1]);
_mm_store_si128((__m128i *)(output + 2 * 4), res[2]);
@@ -169,12 +121,17 @@
void vp10_highbd_fht4x4_sse4_1(const int16_t *input, tran_low_t *output,
int stride, int tx_type) {
__m128i in[4];
+ const TXFM_2D_CFG *cfg;
+ int bit;
switch (tx_type) {
case DCT_DCT:
- load_buffer_4x4(input, in, stride, 0, 0);
- fdct4x4_sse4_1(in);
- fdct4x4_sse4_1(in);
+ cfg = &fwd_txfm_2d_cfg_dct_dct_4;
+ load_buffer_4x4(input, in, stride, 0, 0, cfg->shift[0]);
+ bit = cfg->cos_bit_col[2];
+ fdct4x4_sse4_1(in, bit);
+ bit = cfg->cos_bit_row[2];
+ fdct4x4_sse4_1(in, bit);
write_buffer_4x4(output, in);
break;
case ADST_DCT:
diff --git a/vp10/vp10_common.mk b/vp10/vp10_common.mk
index 40699a3..89b0edb 100644
--- a/vp10/vp10_common.mk
+++ b/vp10/vp10_common.mk
@@ -68,10 +68,8 @@
VP10_COMMON_SRCS-yes += common/vp10_fwd_txfm1d.c
VP10_COMMON_SRCS-yes += common/vp10_inv_txfm1d.h
VP10_COMMON_SRCS-yes += common/vp10_inv_txfm1d.c
-VP10_COMMON_SRCS-yes += common/vp10_fwd_txfm2d.h
VP10_COMMON_SRCS-yes += common/vp10_fwd_txfm2d.c
VP10_COMMON_SRCS-yes += common/vp10_fwd_txfm2d_cfg.h
-VP10_COMMON_SRCS-yes += common/vp10_inv_txfm2d.h
VP10_COMMON_SRCS-yes += common/vp10_inv_txfm2d.c
VP10_COMMON_SRCS-yes += common/vp10_inv_txfm2d_cfg.h
VP10_COMMON_SRCS-yes += common/vp10_convolve.c
diff --git a/vp8/encoder/denoising.c b/vp8/encoder/denoising.c
index 5ae44e8..cff99c0 100644
--- a/vp8/encoder/denoising.c
+++ b/vp8/encoder/denoising.c
@@ -497,7 +497,8 @@
loop_filter_info_n *lfi_n,
int mb_row,
int mb_col,
- int block_index)
+ int block_index,
+ int consec_zero_last)
{
int mv_row;
@@ -571,58 +572,69 @@
best_sse = zero_mv_sse;
}
- saved_pre = filter_xd->pre;
- saved_dst = filter_xd->dst;
+ mv_row = x->best_sse_mv.as_mv.row;
+ mv_col = x->best_sse_mv.as_mv.col;
+ motion_magnitude2 = mv_row * mv_row + mv_col * mv_col;
+ motion_threshold = denoiser->denoise_pars.scale_motion_thresh *
+ NOISE_MOTION_THRESHOLD;
- /* Compensate the running average. */
- filter_xd->pre.y_buffer = src->y_buffer + recon_yoffset;
- filter_xd->pre.u_buffer = src->u_buffer + recon_uvoffset;
- filter_xd->pre.v_buffer = src->v_buffer + recon_uvoffset;
- /* Write the compensated running average to the destination buffer. */
- filter_xd->dst.y_buffer = dst->y_buffer + recon_yoffset;
- filter_xd->dst.u_buffer = dst->u_buffer + recon_uvoffset;
- filter_xd->dst.v_buffer = dst->v_buffer + recon_uvoffset;
+ if (motion_magnitude2 <
+ denoiser->denoise_pars.scale_increase_filter * NOISE_MOTION_THRESHOLD)
+ x->increase_denoising = 1;
- if (!x->skip)
- {
- vp8_build_inter_predictors_mb(filter_xd);
+ sse_thresh = denoiser->denoise_pars.scale_sse_thresh * SSE_THRESHOLD;
+ if (x->increase_denoising)
+ sse_thresh =
+ denoiser->denoise_pars.scale_sse_thresh * SSE_THRESHOLD_HIGH;
+
+ if (best_sse > sse_thresh || motion_magnitude2 > motion_threshold)
+ decision = COPY_BLOCK;
+
+ // If block is considered skin, don't denoise if the block
+ // (1) is selected as non-zero motion for current frame, or
+ // (2) has not been selected as ZERO_LAST mode at least x past frames
+ // in a row.
+ // TODO(marpan): Parameter "x" should be varied with framerate.
+ // In particualar, should be reduced for layers (base layer/LAST).
+ if (x->is_skin && (consec_zero_last < 2 || motion_magnitude2 > 0))
+ decision = COPY_BLOCK;
+
+ if (decision == FILTER_BLOCK) {
+ saved_pre = filter_xd->pre;
+ saved_dst = filter_xd->dst;
+
+ /* Compensate the running average. */
+ filter_xd->pre.y_buffer = src->y_buffer + recon_yoffset;
+ filter_xd->pre.u_buffer = src->u_buffer + recon_uvoffset;
+ filter_xd->pre.v_buffer = src->v_buffer + recon_uvoffset;
+ /* Write the compensated running average to the destination buffer. */
+ filter_xd->dst.y_buffer = dst->y_buffer + recon_yoffset;
+ filter_xd->dst.u_buffer = dst->u_buffer + recon_uvoffset;
+ filter_xd->dst.v_buffer = dst->v_buffer + recon_uvoffset;
+
+ if (!x->skip)
+ {
+ vp8_build_inter_predictors_mb(filter_xd);
+ }
+ else
+ {
+ vp8_build_inter16x16_predictors_mb(filter_xd,
+ filter_xd->dst.y_buffer,
+ filter_xd->dst.u_buffer,
+ filter_xd->dst.v_buffer,
+ filter_xd->dst.y_stride,
+ filter_xd->dst.uv_stride);
+ }
+ filter_xd->pre = saved_pre;
+ filter_xd->dst = saved_dst;
+ *mbmi = saved_mbmi;
}
- else
- {
- vp8_build_inter16x16_predictors_mb(filter_xd,
- filter_xd->dst.y_buffer,
- filter_xd->dst.u_buffer,
- filter_xd->dst.v_buffer,
- filter_xd->dst.y_stride,
- filter_xd->dst.uv_stride);
- }
- filter_xd->pre = saved_pre;
- filter_xd->dst = saved_dst;
- *mbmi = saved_mbmi;
-
- }
-
- mv_row = x->best_sse_mv.as_mv.row;
- mv_col = x->best_sse_mv.as_mv.col;
- motion_magnitude2 = mv_row * mv_row + mv_col * mv_col;
- motion_threshold = denoiser->denoise_pars.scale_motion_thresh *
- NOISE_MOTION_THRESHOLD;
-
- // If block is considered to be skin area, lower the motion threshold.
- // In current version set threshold = 0, so only denoise zero mv on skin.
- if (x->is_skin)
- motion_threshold = 0;
-
- if (motion_magnitude2 <
- denoiser->denoise_pars.scale_increase_filter * NOISE_MOTION_THRESHOLD)
- x->increase_denoising = 1;
-
- sse_thresh = denoiser->denoise_pars.scale_sse_thresh * SSE_THRESHOLD;
- if (x->increase_denoising)
- sse_thresh = denoiser->denoise_pars.scale_sse_thresh * SSE_THRESHOLD_HIGH;
-
- if (best_sse > sse_thresh || motion_magnitude2 > motion_threshold)
+ } else {
+ // zero_frame should always be 1 for real-time mode, as the
+ // ZEROMV mode is always checked, so we should never go into this branch.
+ // If case ZEROMV is not checked, then we will force no denoise (COPY).
decision = COPY_BLOCK;
+ }
if (decision == FILTER_BLOCK)
{
diff --git a/vp8/encoder/denoising.h b/vp8/encoder/denoising.h
index 148ccda..34c561d 100644
--- a/vp8/encoder/denoising.h
+++ b/vp8/encoder/denoising.h
@@ -108,7 +108,8 @@
loop_filter_info_n *lfi_n,
int mb_row,
int mb_col,
- int block_index);
+ int block_index,
+ int consec_zero_last);
#ifdef __cplusplus
} // extern "C"
diff --git a/vp8/encoder/pickinter.c b/vp8/encoder/pickinter.c
index 51fbe54..0708d65 100644
--- a/vp8/encoder/pickinter.c
+++ b/vp8/encoder/pickinter.c
@@ -36,7 +36,7 @@
extern unsigned int cnt_pm;
#endif
-#define MODEL_MODE 0
+#define MODEL_MODE 1
extern const int vp8_ref_frame_order[MAX_MODES];
extern const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES];
@@ -1477,7 +1477,8 @@
vp8_denoiser_denoise_mb(&cpi->denoiser, x, best_sse, zero_mv_sse,
recon_yoffset, recon_uvoffset,
&cpi->common.lf_info, mb_row, mb_col,
- block_index);
+ block_index,
+ cpi->consec_zero_last_mvbias[block_index]);
// Reevaluate ZEROMV after denoising: for large noise content
// (i.e., cpi->mse_source_denoised is above threshold), do this for all
diff --git a/vp8/encoder/rdopt.c b/vp8/encoder/rdopt.c
index ab0ad15..9063cea 100644
--- a/vp8/encoder/rdopt.c
+++ b/vp8/encoder/rdopt.c
@@ -2530,7 +2530,7 @@
vp8_denoiser_denoise_mb(&cpi->denoiser, x, best_sse, zero_mv_sse,
recon_yoffset, recon_uvoffset,
&cpi->common.lf_info, mb_row, mb_col,
- block_index);
+ block_index, 0);
/* Reevaluate ZEROMV after denoising. */
if (best_mode.mbmode.ref_frame == INTRA_FRAME &&
diff --git a/vp8/vp8_dx_iface.c b/vp8/vp8_dx_iface.c
index 9b58f81..9c78de1 100644
--- a/vp8/vp8_dx_iface.c
+++ b/vp8/vp8_dx_iface.c
@@ -9,6 +9,7 @@
*/
+#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "./vp8_rtcd.h"
@@ -154,6 +155,8 @@
{
vpx_codec_err_t res = VPX_CODEC_OK;
+ assert(data != NULL);
+
if(data + data_sz <= data)
{
res = VPX_CODEC_INVALID_PARAM;
diff --git a/vp9/common/vp9_blockd.h b/vp9/common/vp9_blockd.h
index ae2f66a..3d26fb2 100644
--- a/vp9/common/vp9_blockd.h
+++ b/vp9/common/vp9_blockd.h
@@ -158,8 +158,8 @@
MODE_INFO *left_mi;
MODE_INFO *above_mi;
- int up_available;
- int left_available;
+ unsigned int max_blocks_wide;
+ unsigned int max_blocks_high;
const vpx_prob (*partition_probs)[PARTITION_TYPES - 1];
diff --git a/vp9/common/vp9_onyxc_int.h b/vp9/common/vp9_onyxc_int.h
index fd674cb..3fd935e 100644
--- a/vp9/common/vp9_onyxc_int.h
+++ b/vp9/common/vp9_onyxc_int.h
@@ -404,20 +404,8 @@
xd->mb_to_right_edge = ((mi_cols - bw - mi_col) * MI_SIZE) * 8;
// Are edges available for intra prediction?
- xd->up_available = (mi_row != 0);
- xd->left_available = (mi_col > tile->mi_col_start);
- // TODO(slavarnway): eliminate up/left available ???
- if (xd->up_available) {
- xd->above_mi = xd->mi[-xd->mi_stride];
- } else {
- xd->above_mi = NULL;
- }
-
- if (xd->left_available) {
- xd->left_mi = xd->mi[-1];
- } else {
- xd->left_mi = NULL;
- }
+ xd->above_mi = (mi_row != 0) ? xd->mi[-xd->mi_stride] : NULL;
+ xd->left_mi = (mi_col > tile->mi_col_start) ? xd->mi[-1] : NULL;
}
static INLINE void update_partition_context(MACROBLOCKD *xd,
diff --git a/vp9/common/vp9_pred_common.c b/vp9/common/vp9_pred_common.c
index 0a36dba..b5751fc 100644
--- a/vp9/common/vp9_pred_common.c
+++ b/vp9/common/vp9_pred_common.c
@@ -20,10 +20,10 @@
// left of the entries corresponding to real macroblocks.
// The prediction flags in these dummy entries are initialized to 0.
const MODE_INFO *const left_mi = xd->left_mi;
- const int left_type = xd->left_available && is_inter_block(left_mi) ?
+ const int left_type = left_mi && is_inter_block(left_mi) ?
left_mi->interp_filter : SWITCHABLE_FILTERS;
const MODE_INFO *const above_mi = xd->above_mi;
- const int above_type = xd->up_available && is_inter_block(above_mi) ?
+ const int above_type = above_mi && is_inter_block(above_mi) ?
above_mi->interp_filter : SWITCHABLE_FILTERS;
if (left_type == above_type)
@@ -36,38 +36,13 @@
return SWITCHABLE_FILTERS;
}
-// The mode info data structure has a one element border above and to the
-// left of the entries corresponding to real macroblocks.
-// The prediction flags in these dummy entries are initialized to 0.
-// 0 - inter/inter, inter/--, --/inter, --/--
-// 1 - intra/inter, inter/intra
-// 2 - intra/--, --/intra
-// 3 - intra/intra
-int vp9_get_intra_inter_context(const MACROBLOCKD *xd) {
- const MODE_INFO *const above_mi = xd->above_mi;
- const MODE_INFO *const left_mi = xd->left_mi;
- const int has_above = xd->up_available;
- const int has_left = xd->left_available;
-
- if (has_above && has_left) { // both edges available
- const int above_intra = !is_inter_block(above_mi);
- const int left_intra = !is_inter_block(left_mi);
- return left_intra && above_intra ? 3
- : left_intra || above_intra;
- } else if (has_above || has_left) { // one edge available
- return 2 * !is_inter_block(has_above ? above_mi : left_mi);
- } else {
- return 0;
- }
-}
-
int vp9_get_reference_mode_context(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
int ctx;
const MODE_INFO *const above_mi = xd->above_mi;
const MODE_INFO *const left_mi = xd->left_mi;
- const int has_above = xd->up_available;
- const int has_left = xd->left_available;
+ const int has_above = !!above_mi;
+ const int has_left = !!left_mi;
// Note:
// The mode info data structure has a one element border above and to the
// left of the entries corresponding to real macroblocks.
@@ -109,8 +84,8 @@
int pred_context;
const MODE_INFO *const above_mi = xd->above_mi;
const MODE_INFO *const left_mi = xd->left_mi;
- const int above_in_image = xd->up_available;
- const int left_in_image = xd->left_available;
+ const int above_in_image = !!above_mi;
+ const int left_in_image = !!left_mi;
// Note:
// The mode info data structure has a one element border above and to the
@@ -190,9 +165,8 @@
int pred_context;
const MODE_INFO *const above_mi = xd->above_mi;
const MODE_INFO *const left_mi = xd->left_mi;
- const int has_above = xd->up_available;
- const int has_left = xd->left_available;
-
+ const int has_above = !!above_mi;
+ const int has_left = !!left_mi;
// Note:
// The mode info data structure has a one element border above and to the
// left of the entries corresponding to real macroblocks.
@@ -257,8 +231,8 @@
int pred_context;
const MODE_INFO *const above_mi = xd->above_mi;
const MODE_INFO *const left_mi = xd->left_mi;
- const int has_above = xd->up_available;
- const int has_left = xd->left_available;
+ const int has_above = !!above_mi;
+ const int has_left = !!left_mi;
// Note:
// The mode info data structure has a one element border above and to the
diff --git a/vp9/common/vp9_pred_common.h b/vp9/common/vp9_pred_common.h
index 254cb8b..f3c676e 100644
--- a/vp9/common/vp9_pred_common.h
+++ b/vp9/common/vp9_pred_common.h
@@ -68,11 +68,32 @@
int vp9_get_pred_context_switchable_interp(const MACROBLOCKD *xd);
-int vp9_get_intra_inter_context(const MACROBLOCKD *xd);
+// The mode info data structure has a one element border above and to the
+// left of the entries corresponding to real macroblocks.
+// The prediction flags in these dummy entries are initialized to 0.
+// 0 - inter/inter, inter/--, --/inter, --/--
+// 1 - intra/inter, inter/intra
+// 2 - intra/--, --/intra
+// 3 - intra/intra
+static INLINE int get_intra_inter_context(const MACROBLOCKD *xd) {
+ const MODE_INFO *const above_mi = xd->above_mi;
+ const MODE_INFO *const left_mi = xd->left_mi;
+ const int has_above = !!above_mi;
+ const int has_left = !!left_mi;
+
+ if (has_above && has_left) { // both edges available
+ const int above_intra = !is_inter_block(above_mi);
+ const int left_intra = !is_inter_block(left_mi);
+ return left_intra && above_intra ? 3 : left_intra || above_intra;
+ } else if (has_above || has_left) { // one edge available
+ return 2 * !is_inter_block(has_above ? above_mi : left_mi);
+ }
+ return 0;
+}
static INLINE vpx_prob vp9_get_intra_inter_prob(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
- return cm->fc->intra_inter_prob[vp9_get_intra_inter_context(xd)];
+ return cm->fc->intra_inter_prob[get_intra_inter_context(xd)];
}
int vp9_get_reference_mode_context(const VP9_COMMON *cm, const MACROBLOCKD *xd);
@@ -113,8 +134,8 @@
const int max_tx_size = max_txsize_lookup[xd->mi[0]->sb_type];
const MODE_INFO *const above_mi = xd->above_mi;
const MODE_INFO *const left_mi = xd->left_mi;
- const int has_above = xd->up_available;
- const int has_left = xd->left_available;
+ const int has_above = !!above_mi;
+ const int has_left = !!left_mi;
int above_ctx = (has_above && !above_mi->skip) ? (int)above_mi->tx_size
: max_tx_size;
int left_ctx = (has_left && !left_mi->skip) ? (int)left_mi->tx_size
diff --git a/vp9/common/vp9_reconintra.c b/vp9/common/vp9_reconintra.c
index 13a95ae..c4d91c8 100644
--- a/vp9/common/vp9_reconintra.c
+++ b/vp9/common/vp9_reconintra.c
@@ -425,8 +425,8 @@
int aoff, int loff, int plane) {
const int bw = (1 << bwl_in);
const int txw = (1 << tx_size);
- const int have_top = loff || xd->up_available;
- const int have_left = aoff || xd->left_available;
+ const int have_top = loff || (xd->above_mi != NULL);
+ const int have_left = aoff || (xd->left_mi != NULL);
const int have_right = (aoff + txw) < bw;
const int x = aoff * 4;
const int y = loff * 4;
diff --git a/vp9/common/vp9_rtcd_defs.pl b/vp9/common/vp9_rtcd_defs.pl
index d6a0ce9..1cf636c 100644
--- a/vp9/common/vp9_rtcd_defs.pl
+++ b/vp9/common/vp9_rtcd_defs.pl
@@ -276,7 +276,7 @@
$vp9_full_search_sad_sse4_1=vp9_full_search_sadx8;
add_proto qw/int vp9_diamond_search_sad/, "const struct macroblock *x, const struct search_site_config *cfg, struct mv *ref_mv, struct mv *best_mv, int search_param, int sad_per_bit, int *num00, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv";
-specialize qw/vp9_diamond_search_sad avx/;
+specialize qw/vp9_diamond_search_sad/;
add_proto qw/void vp9_temporal_filter_apply/, "uint8_t *frame1, unsigned int stride, uint8_t *frame2, unsigned int block_width, unsigned int block_height, int strength, int filter_weight, unsigned int *accumulator, uint16_t *count";
specialize qw/vp9_temporal_filter_apply sse2 msa/;
diff --git a/vp9/common/vp9_scan.c b/vp9/common/vp9_scan.c
index d6fb8b2..8b8b09f 100644
--- a/vp9/common/vp9_scan.c
+++ b/vp9/common/vp9_scan.c
@@ -229,10 +229,8 @@
990, 959, 1022, 991, 1023,
};
-// Neighborhood 5-tuples for various scans and blocksizes,
-// in {top, left, topleft, topright, bottomleft} order
-// for each position in raster scan order.
-// -1 indicates the neighbor does not exist.
+// Neighborhood 2-tuples for various scans and blocksizes,
+// in {top, left} order for each position in corresponding scan order.
DECLARE_ALIGNED(16, static const int16_t,
default_scan_4x4_neighbors[17 * MAX_NEIGHBORS]) = {
0, 0, 0, 0, 0, 0, 1, 4, 4, 4, 1, 1, 8, 8, 5, 8, 2, 2, 2, 5, 9, 12, 6, 9,
diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c
index 32c7219..2c2c0ba 100644
--- a/vp9/decoder/vp9_decodeframe.c
+++ b/vp9/decoder/vp9_decodeframe.c
@@ -883,6 +883,9 @@
const int max_blocks_high = num_4x4_h + (xd->mb_to_bottom_edge >= 0 ?
0 : xd->mb_to_bottom_edge >> (5 + pd->subsampling_y));
+ xd->max_blocks_wide = xd->mb_to_right_edge >= 0 ? 0 : max_blocks_wide;
+ xd->max_blocks_high = xd->mb_to_bottom_edge >= 0 ? 0 : max_blocks_high;
+
for (row = 0; row < max_blocks_high; row += step)
for (col = 0; col < max_blocks_wide; col += step)
predict_and_reconstruct_intra_block(xd, r, mi, plane,
@@ -911,6 +914,9 @@
const int max_blocks_high = num_4x4_h + (xd->mb_to_bottom_edge >= 0 ?
0 : xd->mb_to_bottom_edge >> (5 + pd->subsampling_y));
+ xd->max_blocks_wide = xd->mb_to_right_edge >= 0 ? 0 : max_blocks_wide;
+ xd->max_blocks_high = xd->mb_to_bottom_edge >= 0 ? 0 : max_blocks_high;
+
for (row = 0; row < max_blocks_high; row += step)
for (col = 0; col < max_blocks_wide; col += step)
eobtotal += reconstruct_inter_block(xd, r, mi, plane, row, col,
@@ -1462,7 +1468,7 @@
TileBuffer tile_buffers[4][1 << 6];
int tile_row, tile_col;
int mi_row, mi_col;
- TileData *tile_data = NULL;
+ TileWorkerData *tile_data = NULL;
if (cm->lf.filter_level && !cm->skip_loop_filter &&
pbi->lf_worker.data1 == NULL) {
@@ -1498,28 +1504,17 @@
get_tile_buffers(pbi, data, data_end, tile_cols, tile_rows, tile_buffers);
- if (pbi->tile_data == NULL ||
- (tile_cols * tile_rows) != pbi->total_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;
- }
-
// 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 = pbi->tile_worker_data + tile_cols * tile_row + tile_col;
tile_data->xd = pbi->mb;
tile_data->xd.corrupted = 0;
- tile_data->xd.counts = cm->frame_parallel_decoding_mode ?
- NULL : &cm->counts;
+ tile_data->xd.counts =
+ cm->frame_parallel_decoding_mode ? NULL : &cm->counts;
vp9_zero(tile_data->dqcoeff);
- vp9_tile_init(&tile_data->xd.tile, tile_data->cm, tile_row, tile_col);
+ vp9_tile_init(&tile_data->xd.tile, cm, 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);
@@ -1535,8 +1530,8 @@
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;
- vp9_tile_set_col(&tile, tile_data->cm, col);
+ tile_data = pbi->tile_worker_data + tile_cols * tile_row + col;
+ vp9_tile_set_col(&tile, cm, 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;
@@ -1588,7 +1583,7 @@
}
// Get last tile data.
- tile_data = pbi->tile_data + tile_cols * tile_rows - 1;
+ tile_data = pbi->tile_worker_data + tile_cols * tile_rows - 1;
if (pbi->frame_parallel_decode)
vp9_frameworker_broadcast(pbi->cur_buf, INT_MAX);
@@ -1673,12 +1668,6 @@
const int num_threads = pbi->max_threads;
CHECK_MEM_ERROR(cm, pbi->tile_workers,
vpx_malloc(num_threads * sizeof(*pbi->tile_workers)));
- // Ensure tile data offsets will be properly aligned. This may fail on
- // platforms without DECLARE_ALIGNED().
- assert((sizeof(*pbi->tile_worker_data) % 16) == 0);
- CHECK_MEM_ERROR(cm, pbi->tile_worker_data,
- vpx_memalign(32, num_threads *
- sizeof(*pbi->tile_worker_data)));
for (n = 0; n < num_threads; ++n) {
VPxWorker *const worker = &pbi->tile_workers[n];
++pbi->num_tile_workers;
@@ -1694,7 +1683,8 @@
// Reset tile decoding hook
for (n = 0; n < num_workers; ++n) {
VPxWorker *const worker = &pbi->tile_workers[n];
- TileWorkerData *const tile_data = &pbi->tile_worker_data[n];
+ TileWorkerData *const tile_data =
+ &pbi->tile_worker_data[n + pbi->total_tiles];
winterface->sync(worker);
tile_data->xd = pbi->mb;
tile_data->xd.counts =
@@ -2223,6 +2213,19 @@
vp9_frameworker_unlock_stats(worker);
}
+ if (pbi->tile_worker_data == NULL ||
+ (tile_cols * tile_rows) != pbi->total_tiles) {
+ const int num_tile_workers = tile_cols * tile_rows +
+ ((pbi->max_threads > 1) ? pbi->max_threads : 0);
+ const size_t twd_size = num_tile_workers * sizeof(*pbi->tile_worker_data);
+ // Ensure tile data offsets will be properly aligned. This may fail on
+ // platforms without DECLARE_ALIGNED().
+ assert((sizeof(*pbi->tile_worker_data) % 16) == 0);
+ vpx_free(pbi->tile_worker_data);
+ CHECK_MEM_ERROR(cm, pbi->tile_worker_data, vpx_memalign(32, twd_size));
+ pbi->total_tiles = tile_rows * tile_cols;
+ }
+
if (pbi->max_threads > 1 && tile_rows == 1 && tile_cols > 1) {
// Multi-threaded tile decoder
*p_data_end = decode_tiles_mt(pbi, data + first_partition_size, data_end);
diff --git a/vp9/decoder/vp9_decodemv.c b/vp9/decoder/vp9_decodemv.c
index 596427c..8831de9 100644
--- a/vp9/decoder/vp9_decodemv.c
+++ b/vp9/decoder/vp9_decodemv.c
@@ -353,11 +353,36 @@
}
}
+// TODO(slavarnway): Move this decoder version of
+// vp9_get_pred_context_switchable_interp() to vp9_pred_common.h and update the
+// encoder.
+//
+// Returns a context number for the given MB prediction signal
+static int dec_get_pred_context_switchable_interp(const MACROBLOCKD *xd) {
+ // Note:
+ // The mode info data structure has a one element border above and to the
+ // left of the entries corresponding to real macroblocks.
+ // The prediction flags in these dummy entries are initialized to 0.
+ const MODE_INFO *const left_mi = xd->left_mi;
+ const int left_type = left_mi ? left_mi->interp_filter : SWITCHABLE_FILTERS;
+ const MODE_INFO *const above_mi = xd->above_mi;
+ const int above_type = above_mi ? above_mi->interp_filter
+ : SWITCHABLE_FILTERS;
+
+ if (left_type == above_type)
+ return left_type;
+ else if (left_type == SWITCHABLE_FILTERS && above_type != SWITCHABLE_FILTERS)
+ return above_type;
+ else if (left_type != SWITCHABLE_FILTERS && above_type == SWITCHABLE_FILTERS)
+ return left_type;
+ else
+ return SWITCHABLE_FILTERS;
+}
static INLINE INTERP_FILTER read_switchable_interp_filter(
VP9_COMMON *const cm, MACROBLOCKD *const xd,
vpx_reader *r) {
- const int ctx = vp9_get_pred_context_switchable_interp(xd);
+ const int ctx = dec_get_pred_context_switchable_interp(xd);
const INTERP_FILTER type =
(INTERP_FILTER)vpx_read_tree(r, vp9_switchable_interp_tree,
cm->fc->switchable_interp_prob[ctx]);
@@ -373,9 +398,6 @@
const BLOCK_SIZE bsize = mi->sb_type;
int i;
- mi->ref_frame[0] = INTRA_FRAME;
- mi->ref_frame[1] = NONE;
-
switch (bsize) {
case BLOCK_4X4:
for (i = 0; i < 4; ++i)
@@ -399,6 +421,13 @@
}
mi->uv_mode = read_intra_mode_uv(cm, xd, r, mi->mode);
+
+ // Initialize interp_filter here so we do not have to check for inter block
+ // modes in dec_get_pred_context_switchable_interp()
+ mi->interp_filter = SWITCHABLE_FILTERS;
+
+ mi->ref_frame[0] = INTRA_FRAME;
+ mi->ref_frame[1] = NONE;
}
static INLINE int is_mv_valid(const MV *mv) {
@@ -454,7 +483,7 @@
if (segfeature_active(&cm->seg, segment_id, SEG_LVL_REF_FRAME)) {
return get_segdata(&cm->seg, segment_id, SEG_LVL_REF_FRAME) != INTRA_FRAME;
} else {
- const int ctx = vp9_get_intra_inter_context(xd);
+ const int ctx = get_intra_inter_context(xd);
const int is_inter = vpx_read(r, cm->fc->intra_inter_prob[ctx]);
FRAME_COUNTS *counts = xd->counts;
if (counts)
diff --git a/vp9/decoder/vp9_decoder.c b/vp9/decoder/vp9_decoder.c
index 3e06c8e..dde609b 100644
--- a/vp9/decoder/vp9_decoder.c
+++ b/vp9/decoder/vp9_decoder.c
@@ -131,11 +131,12 @@
vpx_get_worker_interface()->end(&pbi->lf_worker);
vpx_free(pbi->lf_worker.data1);
- vpx_free(pbi->tile_data);
+
for (i = 0; i < pbi->num_tile_workers; ++i) {
VPxWorker *const worker = &pbi->tile_workers[i];
vpx_get_worker_interface()->end(worker);
}
+
vpx_free(pbi->tile_worker_data);
vpx_free(pbi->tile_workers);
@@ -239,7 +240,6 @@
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.
@@ -308,8 +308,11 @@
&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 VPX_CODEC_MEM_ERROR;
+ if (cm->new_fb_idx == INVALID_IDX) {
+ vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
+ "Unable to find free frame buffer");
+ return cm->error.error_code;
+ }
// Assign a MV array to the frame buffer.
cm->cur_frame = &pool->frame_bufs[cm->new_fb_idx];
diff --git a/vp9/decoder/vp9_decoder.h b/vp9/decoder/vp9_decoder.h
index afa4009..7111a36 100644
--- a/vp9/decoder/vp9_decoder.h
+++ b/vp9/decoder/vp9_decoder.h
@@ -27,15 +27,6 @@
extern "C" {
#endif
-// TODO(hkuang): combine this with TileWorkerData.
-typedef struct TileData {
- VP9_COMMON *cm;
- vpx_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[32 * 32]);
-} TileData;
-
typedef struct TileBuffer {
const uint8_t *data;
size_t size;
@@ -74,8 +65,6 @@
TileWorkerData *tile_worker_data;
TileBuffer tile_buffers[64];
int num_tile_workers;
-
- TileData *tile_data;
int total_tiles;
VP9LfSync lf_row_sync;
diff --git a/vp9/decoder/vp9_detokenize.c b/vp9/decoder/vp9_detokenize.c
index dcc75b9..47dc107 100644
--- a/vp9/decoder/vp9_detokenize.c
+++ b/vp9/decoder/vp9_detokenize.c
@@ -152,65 +152,73 @@
return c;
}
-// TODO(slavarnway): Decode version of vp9_set_context. Modify vp9_set_context
-// after testing is complete, then delete this version.
-static
-void dec_set_contexts(const MACROBLOCKD *xd, struct macroblockd_plane *pd,
- TX_SIZE tx_size, int has_eob,
- int aoff, int loff) {
- ENTROPY_CONTEXT *const a = pd->above_context + aoff;
- ENTROPY_CONTEXT *const l = pd->left_context + loff;
- const int tx_size_in_blocks = 1 << tx_size;
-
- // above
- if (has_eob && xd->mb_to_right_edge < 0) {
- int i;
- const int blocks_wide = pd->n4_w +
- (xd->mb_to_right_edge >> (5 + pd->subsampling_x));
- int above_contexts = tx_size_in_blocks;
- if (above_contexts + aoff > blocks_wide)
- above_contexts = blocks_wide - aoff;
-
- for (i = 0; i < above_contexts; ++i)
- a[i] = has_eob;
- for (i = above_contexts; i < tx_size_in_blocks; ++i)
- a[i] = 0;
- } else {
- memset(a, has_eob, sizeof(ENTROPY_CONTEXT) * tx_size_in_blocks);
+static void get_ctx_shift(MACROBLOCKD *xd, int *ctx_shift_a, int *ctx_shift_l,
+ int x, int y, unsigned int tx_size_in_blocks) {
+ if (xd->max_blocks_wide) {
+ if (tx_size_in_blocks + x > xd->max_blocks_wide)
+ *ctx_shift_a = (tx_size_in_blocks - (xd->max_blocks_wide - x)) * 8;
}
-
- // left
- if (has_eob && xd->mb_to_bottom_edge < 0) {
- int i;
- const int blocks_high = pd->n4_h +
- (xd->mb_to_bottom_edge >> (5 + pd->subsampling_y));
- int left_contexts = tx_size_in_blocks;
- if (left_contexts + loff > blocks_high)
- left_contexts = blocks_high - loff;
-
- for (i = 0; i < left_contexts; ++i)
- l[i] = has_eob;
- for (i = left_contexts; i < tx_size_in_blocks; ++i)
- l[i] = 0;
- } else {
- memset(l, has_eob, sizeof(ENTROPY_CONTEXT) * tx_size_in_blocks);
+ if (xd->max_blocks_high) {
+ if (tx_size_in_blocks + y > xd->max_blocks_high)
+ *ctx_shift_l = (tx_size_in_blocks - (xd->max_blocks_high - y)) * 8;
}
}
-int vp9_decode_block_tokens(MACROBLOCKD *xd,
- int plane, const scan_order *sc,
- int x, int y,
- TX_SIZE tx_size, vpx_reader *r,
+int vp9_decode_block_tokens(MACROBLOCKD *xd, int plane, const scan_order *sc,
+ int x, int y, TX_SIZE tx_size, vpx_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);
- const int eob = decode_coefs(xd, get_plane_type(plane),
- pd->dqcoeff, tx_size,
- dequant, ctx, sc->scan, sc->neighbors, r);
- dec_set_contexts(xd, pd, tx_size, eob > 0, x, y);
+ int eob;
+ ENTROPY_CONTEXT *a = pd->above_context + x;
+ ENTROPY_CONTEXT *l = pd->left_context + y;
+ int ctx;
+ int ctx_shift_a = 0;
+ int ctx_shift_l = 0;
+
+ switch (tx_size) {
+ case TX_4X4:
+ ctx = a[0] != 0;
+ ctx += l[0] != 0;
+ eob = decode_coefs(xd, get_plane_type(plane), pd->dqcoeff, tx_size,
+ dequant, ctx, sc->scan, sc->neighbors, r);
+ a[0] = l[0] = (eob > 0);
+ break;
+ case TX_8X8:
+ get_ctx_shift(xd, &ctx_shift_a, &ctx_shift_l, x, y, 1 << TX_8X8);
+ ctx = !!*(const uint16_t *)a;
+ ctx += !!*(const uint16_t *)l;
+ eob = decode_coefs(xd, get_plane_type(plane), pd->dqcoeff, tx_size,
+ dequant, ctx, sc->scan, sc->neighbors, r);
+ *(uint16_t *)a = ((eob > 0) * 0x0101) >> ctx_shift_a;
+ *(uint16_t *)l = ((eob > 0) * 0x0101) >> ctx_shift_l;
+ break;
+ case TX_16X16:
+ get_ctx_shift(xd, &ctx_shift_a, &ctx_shift_l, x, y, 1 << TX_16X16);
+ ctx = !!*(const uint32_t *)a;
+ ctx += !!*(const uint32_t *)l;
+ eob = decode_coefs(xd, get_plane_type(plane), pd->dqcoeff, tx_size,
+ dequant, ctx, sc->scan, sc->neighbors, r);
+ *(uint32_t *)a = ((eob > 0) * 0x01010101) >> ctx_shift_a;
+ *(uint32_t *)l = ((eob > 0) * 0x01010101) >> ctx_shift_l;
+ break;
+ case TX_32X32:
+ get_ctx_shift(xd, &ctx_shift_a, &ctx_shift_l, x, y, 1 << TX_32X32);
+ // NOTE: casting to uint64_t here is safe because the default memory
+ // alignment is at least 8 bytes and the TX_32X32 is aligned on 8 byte
+ // boundaries.
+ ctx = !!*(const uint64_t *)a;
+ ctx += !!*(const uint64_t *)l;
+ eob = decode_coefs(xd, get_plane_type(plane), pd->dqcoeff, tx_size,
+ dequant, ctx, sc->scan, sc->neighbors, r);
+ *(uint64_t *)a = ((eob > 0) * 0x0101010101010101ULL) >> ctx_shift_a;
+ *(uint64_t *)l = ((eob > 0) * 0x0101010101010101ULL) >> ctx_shift_l;
+ break;
+ default:
+ assert(0 && "Invalid transform size.");
+ eob = 0;
+ break;
+ }
+
return eob;
}
-
-
diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c
index 9f8004b..5600ed4 100644
--- a/vp9/encoder/vp9_bitstream.c
+++ b/vp9/encoder/vp9_bitstream.c
@@ -210,7 +210,7 @@
if (cm->reference_mode == REFERENCE_MODE_SELECT) {
vpx_write(w, is_compound, vp9_get_reference_mode_prob(cm, xd));
} else {
- assert((!is_compound) == (cm->reference_mode == SINGLE_REFERENCE));
+ assert(!is_compound == (cm->reference_mode == SINGLE_REFERENCE));
}
if (is_compound) {
diff --git a/vp9/encoder/vp9_denoiser.c b/vp9/encoder/vp9_denoiser.c
index 9bc9f26..dbca633 100644
--- a/vp9/encoder/vp9_denoiser.c
+++ b/vp9/encoder/vp9_denoiser.c
@@ -183,7 +183,7 @@
static uint8_t *block_start(uint8_t *framebuf, int stride,
int mi_row, int mi_col) {
- return framebuf + (stride * mi_row * 8) + (mi_col * 8);
+ return framebuf + (stride * mi_row << 3) + (mi_col << 3);
}
static VP9_DENOISER_DECISION perform_motion_compensation(VP9_DENOISER *denoiser,
@@ -195,24 +195,27 @@
PICK_MODE_CONTEXT *ctx,
int motion_magnitude,
int is_skin,
- int *zeromv_filter) {
- int mv_col, mv_row;
+ int *zeromv_filter,
+ int consec_zeromv) {
int sse_diff = ctx->zeromv_sse - ctx->newmv_sse;
MV_REFERENCE_FRAME frame;
MACROBLOCKD *filter_mbd = &mb->e_mbd;
MODE_INFO *mi = filter_mbd->mi[0];
MODE_INFO saved_mi;
- int i, j;
+ int i;
struct buf_2d saved_dst[MAX_MB_PLANE];
- struct buf_2d saved_pre[MAX_MB_PLANE][2]; // 2 pre buffers
+ struct buf_2d saved_pre[MAX_MB_PLANE];
- mv_col = ctx->best_sse_mv.as_mv.col;
- mv_row = ctx->best_sse_mv.as_mv.row;
frame = ctx->best_reference_frame;
-
saved_mi = *mi;
- if (is_skin && motion_magnitude > 0)
+ if (is_skin && (motion_magnitude > 0 || consec_zeromv < 4))
+ return COPY_BLOCK;
+
+ // Avoid denoising for small block (unless motion is small).
+ // Small blocks are selected in variance partition (before encoding) and
+ // will typically lie on moving areas.
+ if (motion_magnitude > 16 && bs <= BLOCK_8X8)
return COPY_BLOCK;
// If the best reference frame uses inter-prediction and there is enough of a
@@ -255,34 +258,31 @@
// We will restore these after motion compensation.
for (i = 0; i < MAX_MB_PLANE; ++i) {
- for (j = 0; j < 2; ++j) {
- saved_pre[i][j] = filter_mbd->plane[i].pre[j];
- }
+ saved_pre[i] = filter_mbd->plane[i].pre[0];
saved_dst[i] = filter_mbd->plane[i].dst;
}
// Set the pointers in the MACROBLOCKD to point to the buffers in the denoiser
// struct.
- for (j = 0; j < 2; ++j) {
- filter_mbd->plane[0].pre[j].buf =
- block_start(denoiser->running_avg_y[frame].y_buffer,
- denoiser->running_avg_y[frame].y_stride,
- mi_row, mi_col);
- filter_mbd->plane[0].pre[j].stride =
- denoiser->running_avg_y[frame].y_stride;
- filter_mbd->plane[1].pre[j].buf =
- block_start(denoiser->running_avg_y[frame].u_buffer,
- denoiser->running_avg_y[frame].uv_stride,
- mi_row, mi_col);
- filter_mbd->plane[1].pre[j].stride =
- denoiser->running_avg_y[frame].uv_stride;
- filter_mbd->plane[2].pre[j].buf =
- block_start(denoiser->running_avg_y[frame].v_buffer,
- denoiser->running_avg_y[frame].uv_stride,
- mi_row, mi_col);
- filter_mbd->plane[2].pre[j].stride =
- denoiser->running_avg_y[frame].uv_stride;
- }
+ filter_mbd->plane[0].pre[0].buf =
+ block_start(denoiser->running_avg_y[frame].y_buffer,
+ denoiser->running_avg_y[frame].y_stride,
+ mi_row, mi_col);
+ filter_mbd->plane[0].pre[0].stride =
+ denoiser->running_avg_y[frame].y_stride;
+ filter_mbd->plane[1].pre[0].buf =
+ block_start(denoiser->running_avg_y[frame].u_buffer,
+ denoiser->running_avg_y[frame].uv_stride,
+ mi_row, mi_col);
+ filter_mbd->plane[1].pre[0].stride =
+ denoiser->running_avg_y[frame].uv_stride;
+ filter_mbd->plane[2].pre[0].buf =
+ block_start(denoiser->running_avg_y[frame].v_buffer,
+ denoiser->running_avg_y[frame].uv_stride,
+ mi_row, mi_col);
+ filter_mbd->plane[2].pre[0].stride =
+ denoiser->running_avg_y[frame].uv_stride;
+
filter_mbd->plane[0].dst.buf =
block_start(denoiser->mc_running_avg_y.y_buffer,
denoiser->mc_running_avg_y.y_stride,
@@ -299,30 +299,26 @@
mi_row, mi_col);
filter_mbd->plane[2].dst.stride = denoiser->mc_running_avg_y.uv_stride;
- vp9_build_inter_predictors_sby(filter_mbd, mv_row, mv_col, bs);
+ vp9_build_inter_predictors_sby(filter_mbd, mi_row, mi_col, bs);
// Restore everything to its original state
*mi = saved_mi;
for (i = 0; i < MAX_MB_PLANE; ++i) {
- for (j = 0; j < 2; ++j) {
- filter_mbd->plane[i].pre[j] = saved_pre[i][j];
- }
+ filter_mbd->plane[i].pre[0] = saved_pre[i];
filter_mbd->plane[i].dst = saved_dst[i];
}
- mv_row = ctx->best_sse_mv.as_mv.row;
- mv_col = ctx->best_sse_mv.as_mv.col;
-
return FILTER_BLOCK;
}
-void vp9_denoiser_denoise(VP9_DENOISER *denoiser, MACROBLOCK *mb,
+void vp9_denoiser_denoise(VP9_COMP *cpi, MACROBLOCK *mb,
int mi_row, int mi_col, BLOCK_SIZE bs,
PICK_MODE_CONTEXT *ctx,
VP9_DENOISER_DECISION *denoiser_decision) {
int mv_col, mv_row;
int motion_magnitude = 0;
int zeromv_filter = 0;
+ VP9_DENOISER *denoiser = &cpi->denoiser;
VP9_DENOISER_DECISION decision = COPY_BLOCK;
YV12_BUFFER_CONFIG avg = denoiser->running_avg_y[INTRA_FRAME];
YV12_BUFFER_CONFIG mc_avg = denoiser->mc_running_avg_y;
@@ -331,21 +327,54 @@
mi_row, mi_col);
struct buf_2d src = mb->plane[0].src;
int is_skin = 0;
+ int consec_zeromv = 0;
+ mv_col = ctx->best_sse_mv.as_mv.col;
+ mv_row = ctx->best_sse_mv.as_mv.row;
+ motion_magnitude = mv_row * mv_row + mv_col * mv_col;
- if (bs <= BLOCK_32X32 && denoiser->denoising_level >= kDenLow) {
+ if (cpi->use_skin_detection &&
+ bs <= BLOCK_32X32 &&
+ denoiser->denoising_level >= kDenLow) {
+ int motion_level = (motion_magnitude < 16) ? 0 : 1;
+ // If motion for current block is small/zero, compute consec_zeromv for
+ // skin detection (early exit in skin detection is done for large
+ // consec_zeromv when current block has small/zero motion).
+ consec_zeromv = 0;
+ if (motion_level == 0) {
+ CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
+ VP9_COMMON * const cm = &cpi->common;
+ int j, i;
+ // Loop through the 8x8 sub-blocks.
+ const int bw = num_8x8_blocks_wide_lookup[BLOCK_64X64];
+ const int bh = num_8x8_blocks_high_lookup[BLOCK_64X64];
+ const int xmis = VPXMIN(cm->mi_cols - mi_col, bw);
+ const int ymis = VPXMIN(cm->mi_rows - mi_row, bh);
+ const int block_index = mi_row * cm->mi_cols + mi_col;
+ consec_zeromv = 100;
+ for (i = 0; i < ymis; i++) {
+ for (j = 0; j < xmis; j++) {
+ int bl_index = block_index + i * cm->mi_cols + j;
+ consec_zeromv = VPXMIN(cr->consec_zero_mv[bl_index], consec_zeromv);
+ // No need to keep checking 8x8 blocks if any of the sub-blocks
+ // has small consec_zeromv (since threshold for no_skin based on
+ // zero/small motion in skin detection is high, i.e, > 4).
+ if (consec_zeromv < 4) {
+ i = ymis;
+ j = xmis;
+ }
+ }
+ }
+ }
+ // TODO(marpan): Compute skin detection over sub-blocks.
is_skin = vp9_compute_skin_block(mb->plane[0].src.buf,
mb->plane[1].src.buf,
mb->plane[2].src.buf,
mb->plane[0].src.stride,
mb->plane[1].src.stride,
bs,
- 0,
- 0);
+ consec_zeromv,
+ motion_level);
}
-
- mv_col = ctx->best_sse_mv.as_mv.col;
- mv_row = ctx->best_sse_mv.as_mv.row;
- motion_magnitude = mv_row * mv_row + mv_col * mv_col;
if (!is_skin &&
denoiser->denoising_level == kDenHigh &&
motion_magnitude < 16) {
@@ -360,7 +389,8 @@
mi_row, mi_col, ctx,
motion_magnitude,
is_skin,
- &zeromv_filter);
+ &zeromv_filter,
+ consec_zeromv);
if (decision == FILTER_BLOCK) {
decision = vp9_denoiser_filter(src.buf, src.stride,
@@ -420,11 +450,12 @@
int resized) {
// Copy source into denoised reference buffers on KEY_FRAME or
// if the just encoded frame was resized.
- if (frame_type == KEY_FRAME || resized != 0) {
+ if (frame_type == KEY_FRAME || resized != 0 || denoiser->reset) {
int i;
// Start at 1 so as not to overwrite the INTRA_FRAME
for (i = 1; i < MAX_REF_FRAMES; ++i)
copy_frame(&denoiser->running_avg_y[i], &src);
+ denoiser->reset = 0;
return;
}
@@ -537,6 +568,8 @@
denoiser->increase_denoising = 0;
denoiser->frame_buffer_initialized = 1;
denoiser->denoising_level = kDenLow;
+ denoiser->prev_denoising_level = kDenLow;
+ denoiser->reset = 0;
return 0;
}
@@ -556,6 +589,12 @@
void vp9_denoiser_set_noise_level(VP9_DENOISER *denoiser,
int noise_level) {
denoiser->denoising_level = noise_level;
+ if (denoiser->denoising_level > kDenLowLow &&
+ denoiser->prev_denoising_level == kDenLowLow)
+ denoiser->reset = 1;
+ else
+ denoiser->reset = 0;
+ denoiser->prev_denoising_level = denoiser->denoising_level;
}
#ifdef OUTPUT_YUV_DENOISED
diff --git a/vp9/encoder/vp9_denoiser.h b/vp9/encoder/vp9_denoiser.h
index 9f13bd5..84189b4 100644
--- a/vp9/encoder/vp9_denoiser.h
+++ b/vp9/encoder/vp9_denoiser.h
@@ -40,7 +40,9 @@
YV12_BUFFER_CONFIG last_source;
int increase_denoising;
int frame_buffer_initialized;
+ int reset;
VP9_DENOISER_LEVEL denoising_level;
+ VP9_DENOISER_LEVEL prev_denoising_level;
} VP9_DENOISER;
struct VP9_COMP;
@@ -53,7 +55,7 @@
int refresh_last_frame,
int resized);
-void vp9_denoiser_denoise(VP9_DENOISER *denoiser, MACROBLOCK *mb,
+void vp9_denoiser_denoise(struct VP9_COMP *cpi, MACROBLOCK *mb,
int mi_row, int mi_col, BLOCK_SIZE bs,
PICK_MODE_CONTEXT *ctx ,
VP9_DENOISER_DECISION *denoiser_decision);
diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c
index 9076b31..1d8bfa9 100644
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -1228,10 +1228,10 @@
MODE_INFO *const mi = xd->mi[0];
INTERP_FILTER filter_ref;
- if (xd->up_available)
- filter_ref = xd->mi[-xd->mi_stride]->interp_filter;
- else if (xd->left_available)
- filter_ref = xd->mi[-1]->interp_filter;
+ if (xd->above_mi)
+ filter_ref = xd->above_mi->interp_filter;
+ else if (xd->left_mi)
+ filter_ref = xd->left_mi->interp_filter;
else
filter_ref = EIGHTTAP;
@@ -1404,7 +1404,7 @@
const int seg_ref_active = segfeature_active(&cm->seg, mi->segment_id,
SEG_LVL_REF_FRAME);
if (!seg_ref_active) {
- counts->intra_inter[vp9_get_intra_inter_context(xd)][inter_block]++;
+ counts->intra_inter[get_intra_inter_context(xd)][inter_block]++;
// If the segment reference feature is enabled we have only a single
// reference frame allowed for the segment so exclude it from
// the reference frame counts used to work out probabilities.
@@ -2266,8 +2266,8 @@
BLOCK_SIZE *max_block_size) {
VP9_COMMON *const cm = &cpi->common;
MODE_INFO **mi = xd->mi;
- const int left_in_image = xd->left_available && mi[-1];
- const int above_in_image = xd->up_available && mi[-xd->mi_stride];
+ const int left_in_image = !!xd->left_mi;
+ const int above_in_image = !!xd->above_mi;
const int row8x8_remaining = tile->mi_row_end - mi_row;
const int col8x8_remaining = tile->mi_col_end - mi_col;
int bh, bw;
@@ -2362,7 +2362,7 @@
}
}
- if (xd->left_available) {
+ if (xd->left_mi) {
for (idy = 0; idy < mi_height; ++idy) {
mi = xd->mi[idy * cm->mi_stride - 1];
bs = mi ? mi->sb_type : bsize;
@@ -2371,7 +2371,7 @@
}
}
- if (xd->up_available) {
+ if (xd->above_mi) {
for (idx = 0; idx < mi_width; ++idx) {
mi = xd->mi[idx - cm->mi_stride];
bs = mi ? mi->sb_type : bsize;
@@ -4316,7 +4316,8 @@
vp9_encode_intra_block_plane(x, VPXMAX(bsize, BLOCK_8X8), plane);
if (output_enabled)
sum_intra_stats(td->counts, mi);
- vp9_tokenize_sb(cpi, td, t, !output_enabled, VPXMAX(bsize, BLOCK_8X8));
+ vp9_tokenize_sb(cpi, td, t, !output_enabled, seg_skip,
+ VPXMAX(bsize, BLOCK_8X8));
} else {
int ref;
const int is_compound = has_second_ref(mi);
@@ -4336,7 +4337,8 @@
VPXMAX(bsize, BLOCK_8X8));
vp9_encode_sb(x, VPXMAX(bsize, BLOCK_8X8));
- vp9_tokenize_sb(cpi, td, t, !output_enabled, VPXMAX(bsize, BLOCK_8X8));
+ vp9_tokenize_sb(cpi, td, t, !output_enabled, seg_skip,
+ VPXMAX(bsize, BLOCK_8X8));
}
if (output_enabled) {
diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c
index 01855ea..845f5aa 100644
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -1687,6 +1687,7 @@
cpi->common.buffer_pool = pool;
cpi->rc.high_source_sad = 0;
+ cpi->rc.count_last_scene_change = 0;
init_config(cpi, oxcf);
vp9_rc_init(&cpi->oxcf, oxcf->pass, &cpi->rc);
@@ -2571,7 +2572,8 @@
sizeof(cpi->interp_filter_selected[0]));
}
#if CONFIG_VP9_TEMPORAL_DENOISING
- if (cpi->oxcf.noise_sensitivity > 0) {
+ if (cpi->oxcf.noise_sensitivity > 0 &&
+ cpi->denoiser.denoising_level > kDenLowLow) {
vp9_denoiser_update_frame_info(&cpi->denoiser,
*cpi->Source,
cpi->common.frame_type,
diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c
index 10fd6c0..3e34c01 100644
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -65,7 +65,7 @@
#define NCOUNT_INTRA_THRESH 8192
#define NCOUNT_INTRA_FACTOR 3
-#define NCOUNT_FRAME_II_THRESH 5.0
+
#define DOUBLE_DIVIDE_CHECK(x) ((x) < 0 ? (x) - 0.000001 : (x) + 0.000001)
@@ -115,7 +115,7 @@
fprintf(fpfile, "%12.0lf %12.4lf %12.0lf %12.0lf %12.0lf %12.4lf %12.4lf"
"%12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf"
- "%12.4lf %12.4lf %12.0lf %12.0lf %12.0lf %12.4lf\n",
+ "%12.4lf %12.4lf %12.4lf %12.0lf %12.0lf %12.0lf %12.4lf\n",
stats->frame,
stats->weight,
stats->intra_error,
@@ -126,6 +126,7 @@
stats->pcnt_second_ref,
stats->pcnt_neutral,
stats->intra_skip_pct,
+ stats->intra_smooth_pct,
stats->inactive_zone_rows,
stats->inactive_zone_cols,
stats->MVr,
@@ -165,6 +166,7 @@
section->pcnt_second_ref = 0.0;
section->pcnt_neutral = 0.0;
section->intra_skip_pct = 0.0;
+ section->intra_smooth_pct = 0.0;
section->inactive_zone_rows = 0.0;
section->inactive_zone_cols = 0.0;
section->MVr = 0.0;
@@ -193,6 +195,7 @@
section->pcnt_second_ref += frame->pcnt_second_ref;
section->pcnt_neutral += frame->pcnt_neutral;
section->intra_skip_pct += frame->intra_skip_pct;
+ section->intra_smooth_pct += frame->intra_smooth_pct;
section->inactive_zone_rows += frame->inactive_zone_rows;
section->inactive_zone_cols += frame->inactive_zone_cols;
section->MVr += frame->MVr;
@@ -219,6 +222,7 @@
section->pcnt_second_ref -= frame->pcnt_second_ref;
section->pcnt_neutral -= frame->pcnt_neutral;
section->intra_skip_pct -= frame->intra_skip_pct;
+ section->intra_smooth_pct -= frame->intra_smooth_pct;
section->inactive_zone_rows -= frame->inactive_zone_rows;
section->inactive_zone_cols -= frame->inactive_zone_cols;
section->MVr -= frame->MVr;
@@ -493,12 +497,12 @@
// This threshold is used to track blocks where to all intents and purposes
// the intra prediction error 0. Though the metric we test against
// is technically a sse we are mainly interested in blocks where all the pixels
-// int he 8 bit domain have an error of <= 1 (where error = sse) so a
+// in the 8 bit domain have an error of <= 1 (where error = sse) so a
// linear scaling for 10 and 12 bit gives similar results.
#define UL_INTRA_THRESH 50
-#if CONFIG_VP9_HIGHBITDEPTH
static int get_ul_intra_threshold(VP9_COMMON *cm) {
int ret_val = UL_INTRA_THRESH;
+#if CONFIG_VP9_HIGHBITDEPTH
if (cm->use_highbitdepth) {
switch (cm->bit_depth) {
case VPX_BITS_8:
@@ -515,9 +519,37 @@
"VPX_BITS_10 or VPX_BITS_12");
}
}
+#else
+ (void) cm;
+#endif // CONFIG_VP9_HIGHBITDEPTH
return ret_val;
}
+
+#define SMOOTH_INTRA_THRESH 4000
+static int get_smooth_intra_threshold(VP9_COMMON *cm) {
+ int ret_val = SMOOTH_INTRA_THRESH;
+#if CONFIG_VP9_HIGHBITDEPTH
+ if (cm->use_highbitdepth) {
+ switch (cm->bit_depth) {
+ case VPX_BITS_8:
+ ret_val = SMOOTH_INTRA_THRESH;
+ break;
+ case VPX_BITS_10:
+ ret_val = SMOOTH_INTRA_THRESH >> 2;
+ break;
+ case VPX_BITS_12:
+ ret_val = SMOOTH_INTRA_THRESH >> 4;
+ break;
+ default:
+ assert(0 && "cm->bit_depth should be VPX_BITS_8, "
+ "VPX_BITS_10 or VPX_BITS_12");
+ }
+ }
+#else
+ (void) cm;
#endif // CONFIG_VP9_HIGHBITDEPTH
+ return ret_val;
+}
#define INVALID_ROW -1
void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) {
@@ -545,6 +577,7 @@
const int intrapenalty = INTRA_MODE_PENALTY;
double neutral_count;
int intra_skip_count = 0;
+ int intra_smooth_count = 0;
int image_data_start_row = INVALID_ROW;
int new_mv_count = 0;
int sum_in_vectors = 0;
@@ -563,6 +596,7 @@
double intra_factor;
double brightness_factor;
BufferPool *const pool = cm->buffer_pool;
+ MODE_INFO mi_above, mi_left;
// First pass code requires valid last and new frame buffers.
assert(new_yv12 != NULL);
@@ -695,6 +729,12 @@
mb_row << 1, num_8x8_blocks_high_lookup[bsize],
mb_col << 1, num_8x8_blocks_wide_lookup[bsize],
cm->mi_rows, cm->mi_cols);
+ // Are edges available for intra prediction?
+ // Since the firstpass does not populate the mi_grid_visible,
+ // above_mi/left_mi must be overwritten with a nonzero value when edges
+ // are available. Required by vp9_predict_intra_block().
+ xd->above_mi = (mb_row != 0) ? &mi_above : NULL;
+ xd->left_mi = (mb_col > tile.mi_col_start) ? &mi_left : NULL;
// Do intra 16x16 prediction.
x->skip_encode = 0;
@@ -709,15 +749,14 @@
// domain). In natural videos this is uncommon, but it is much more
// common in animations, graphics and screen content, so may be used
// as a signal to detect these types of content.
-#if CONFIG_VP9_HIGHBITDEPTH
if (this_error < get_ul_intra_threshold(cm)) {
-#else
- if (this_error < UL_INTRA_THRESH) {
-#endif
++intra_skip_count;
} else if ((mb_col > 0) && (image_data_start_row == INVALID_ROW)) {
image_data_start_row = mb_row;
}
+ if (this_error < get_smooth_intra_threshold(cm)) {
+ ++intra_smooth_count;
+ }
#if CONFIG_VP9_HIGHBITDEPTH
if (cm->use_highbitdepth) {
@@ -1083,6 +1122,7 @@
fps.pcnt_second_ref = (double)second_ref_count / num_mbs;
fps.pcnt_neutral = (double)neutral_count / num_mbs;
fps.intra_skip_pct = (double)intra_skip_count / num_mbs;
+ fps.intra_smooth_pct = (double)intra_smooth_count / num_mbs;
fps.inactive_zone_rows = (double)image_data_start_row;
fps.inactive_zone_cols = (double)0; // TODO(paulwilkins): fix
@@ -1371,11 +1411,12 @@
}
#define SR_DIFF_PART 0.0015
-#define MOTION_AMP_PART 0.003
#define INTRA_PART 0.005
#define DEFAULT_DECAY_LIMIT 0.75
#define LOW_SR_DIFF_TRHESH 0.1
#define SR_DIFF_MAX 128.0
+#define LOW_CODED_ERR_PER_MB 10.0
+#define NCOUNT_FRAME_II_THRESH 6.0
static double get_sr_decay_rate(const VP9_COMP *cpi,
const FIRSTPASS_STATS *frame) {
@@ -1386,12 +1427,15 @@
double sr_decay = 1.0;
double modified_pct_inter;
double modified_pcnt_intra;
- const double motion_amplitude_factor =
- frame->pcnt_motion * ((frame->mvc_abs + frame->mvr_abs) / 2);
+ const double motion_amplitude_part =
+ frame->pcnt_motion *
+ ((frame->mvc_abs + frame->mvr_abs) /
+ (cpi->initial_height + cpi->initial_width));
modified_pct_inter = frame->pcnt_inter;
- if ((frame->intra_error / DOUBLE_DIVIDE_CHECK(frame->coded_error)) <
- (double)NCOUNT_FRAME_II_THRESH) {
+ if (((frame->coded_error / num_mbs) > LOW_CODED_ERR_PER_MB) &&
+ ((frame->intra_error / DOUBLE_DIVIDE_CHECK(frame->coded_error)) <
+ (double)NCOUNT_FRAME_II_THRESH)) {
modified_pct_inter = frame->pcnt_inter - frame->pcnt_neutral;
}
modified_pcnt_intra = 100 * (1.0 - modified_pct_inter);
@@ -1400,7 +1444,7 @@
if ((sr_diff > LOW_SR_DIFF_TRHESH)) {
sr_diff = VPXMIN(sr_diff, SR_DIFF_MAX);
sr_decay = 1.0 - (SR_DIFF_PART * sr_diff) -
- (MOTION_AMP_PART * motion_amplitude_factor) -
+ motion_amplitude_part -
(INTRA_PART * modified_pcnt_intra);
}
return VPXMAX(sr_decay, VPXMIN(DEFAULT_DECAY_LIMIT, modified_pct_inter));
@@ -1957,7 +2001,8 @@
int int_lbq =
(int)(vp9_convert_qindex_to_q(rc->last_boosted_qindex,
cpi->common.bit_depth));
- active_min_gf_interval = rc->min_gf_interval + VPXMIN(2, int_max_q / 200);
+ active_min_gf_interval =
+ rc->min_gf_interval + arf_active_or_kf + VPXMIN(2, int_max_q / 200);
if (active_min_gf_interval > rc->max_gf_interval)
active_min_gf_interval = rc->max_gf_interval;
@@ -1968,13 +2013,20 @@
// bits to spare and are better with a smaller interval and smaller boost.
// At high Q when there are few bits to spare we are better with a longer
// interval to spread the cost of the GF.
- active_max_gf_interval = 12 + VPXMIN(4, (int_lbq / 6));
+ active_max_gf_interval =
+ 12 + arf_active_or_kf + VPXMIN(4, (int_lbq / 6));
// We have: active_min_gf_interval <= rc->max_gf_interval
if (active_max_gf_interval < active_min_gf_interval)
active_max_gf_interval = active_min_gf_interval;
else if (active_max_gf_interval > rc->max_gf_interval)
active_max_gf_interval = rc->max_gf_interval;
+
+ // Would the active max drop us out just before the near the next kf?
+ if ((active_max_gf_interval <= rc->frames_to_key) &&
+ (active_max_gf_interval >=
+ (rc->frames_to_key - rc->min_gf_interval)))
+ active_max_gf_interval = rc->frames_to_key / 2;
}
}
@@ -2032,11 +2084,13 @@
// Break out conditions.
if (
// Break at active_max_gf_interval unless almost totally static.
- (i >= (active_max_gf_interval + arf_active_or_kf) &&
- zero_motion_accumulator < 0.995) ||
+ ((i >= active_max_gf_interval) &&
+ (zero_motion_accumulator < 0.995)) ||
(
// Don't break out with a very short interval.
- (i >= active_min_gf_interval + arf_active_or_kf) &&
+ (i >= active_min_gf_interval) &&
+ // If possible dont break very close to a kf
+ ((rc->frames_to_key - i) >= rc->min_gf_interval) &&
(!flash_detected) &&
((mv_ratio_accumulator > mv_ratio_accumulator_thresh) ||
(abs_mv_in_out_accumulator > 3.0) ||
@@ -2782,6 +2836,7 @@
// applied when combining MB error values for the frame.
twopass->mb_av_energy =
log(((this_frame.intra_error * 256.0) / num_mbs) + 1.0);
+ twopass->mb_smooth_pct = this_frame.intra_smooth_pct;
}
// Update the total stats remaining structure.
diff --git a/vp9/encoder/vp9_firstpass.h b/vp9/encoder/vp9_firstpass.h
index 5875a7b..7eb44fa 100644
--- a/vp9/encoder/vp9_firstpass.h
+++ b/vp9/encoder/vp9_firstpass.h
@@ -52,6 +52,7 @@
double pcnt_second_ref;
double pcnt_neutral;
double intra_skip_pct;
+ double intra_smooth_pct; // % of blocks that are smooth
double inactive_zone_rows; // Image mask rows top and bottom.
double inactive_zone_cols; // Image mask columns at left and right edges.
double MVr;
@@ -107,6 +108,7 @@
double modified_error_max;
double modified_error_left;
double mb_av_energy;
+ double mb_smooth_pct;
#if CONFIG_FP_MB_STATS
uint8_t *frame_mb_stats_buf;
diff --git a/vp9/encoder/vp9_mbgraph.c b/vp9/encoder/vp9_mbgraph.c
index 7ce86b4..3ae5b21 100644
--- a/vp9/encoder/vp9_mbgraph.c
+++ b/vp9/encoder/vp9_mbgraph.c
@@ -243,13 +243,16 @@
int mb_y_offset = 0, arf_y_offset = 0, gld_y_offset = 0;
MV gld_top_mv = {0, 0};
MODE_INFO mi_local;
+ MODE_INFO mi_above, mi_left;
vp9_zero(mi_local);
// Set up limit values for motion vectors to prevent them extending outside
// the UMV borders.
x->mv_row_min = -BORDER_MV_PIXELS_B16;
x->mv_row_max = (cm->mb_rows - 1) * 8 + BORDER_MV_PIXELS_B16;
- xd->up_available = 0;
+ // Signal to vp9_predict_intra_block() that above is not available
+ xd->above_mi = NULL;
+
xd->plane[0].dst.stride = buf->y_stride;
xd->plane[0].pre[0].stride = buf->y_stride;
xd->plane[1].dst.stride = buf->uv_stride;
@@ -268,7 +271,8 @@
// the UMV borders.
x->mv_col_min = -BORDER_MV_PIXELS_B16;
x->mv_col_max = (cm->mb_cols - 1) * 8 + BORDER_MV_PIXELS_B16;
- xd->left_available = 0;
+ // Signal to vp9_predict_intra_block() that left is not available
+ xd->left_mi = NULL;
for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
MBGRAPH_MB_STATS *mb_stats = &stats->mb_stats[offset + mb_col];
@@ -280,14 +284,19 @@
if (mb_col == 0) {
gld_top_mv = gld_left_mv;
}
- xd->left_available = 1;
+ // Signal to vp9_predict_intra_block() that left is available
+ xd->left_mi = &mi_left;
+
mb_y_in_offset += 16;
gld_y_in_offset += 16;
arf_y_in_offset += 16;
x->mv_col_min -= 16;
x->mv_col_max -= 16;
}
- xd->up_available = 1;
+
+ // Signal to vp9_predict_intra_block() that above is available
+ xd->above_mi = &mi_above;
+
mb_y_offset += buf->y_stride * 16;
gld_y_offset += golden_ref->y_stride * 16;
if (alt_ref)
diff --git a/vp9/encoder/vp9_noise_estimate.c b/vp9/encoder/vp9_noise_estimate.c
index d505629..10ea010 100644
--- a/vp9/encoder/vp9_noise_estimate.c
+++ b/vp9/encoder/vp9_noise_estimate.c
@@ -91,7 +91,7 @@
} else {
if (ne->value > ne->thresh)
noise_level = kMedium;
- else if (ne->value > (ne->thresh >> 1))
+ else if (ne->value > ((9 * ne->thresh) >> 4))
noise_level = kLow;
else
noise_level = kLowLow;
diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c
index 3ea2ccd..2e27f94 100644
--- a/vp9/encoder/vp9_pickmode.c
+++ b/vp9/encoder/vp9_pickmode.c
@@ -701,10 +701,9 @@
}
}
- if (*skippable == 0) {
- *rate <<= (2 + VP9_PROB_COST_SHIFT);
- *rate += (eob_cost << VP9_PROB_COST_SHIFT);
- }
+ // If skippable is set, rate gets clobbered later.
+ *rate <<= (2 + VP9_PROB_COST_SHIFT);
+ *rate += (eob_cost << VP9_PROB_COST_SHIFT);
}
#endif
@@ -906,6 +905,7 @@
VP9_COMP *cpi;
MACROBLOCK *x;
PREDICTION_MODE mode;
+ int skippable;
int rate;
int64_t dist;
};
@@ -941,13 +941,9 @@
if (plane == 0) {
int64_t this_sse = INT64_MAX;
- int is_skippable;
// TODO(jingning): This needs further refactoring.
- block_yrd(cpi, x, &rate, &dist, &is_skippable, &this_sse, 0,
+ block_yrd(cpi, x, &rate, &dist, &args->skippable, &this_sse, 0,
bsize_tx, VPXMIN(tx_size, TX_16X16));
- x->skip_txfm[0] = is_skippable;
- // TODO(jingning): Skip is signalled per prediciton block not per tx block.
- rate += vp9_cost_bit(vp9_get_skip_prob(&cpi->common, xd), is_skippable);
} else {
unsigned int var = 0;
unsigned int sse = 0;
@@ -1011,14 +1007,14 @@
MODE_INFO *const mi = xd->mi[0];
RD_COST this_rdc, best_rdc;
PREDICTION_MODE this_mode;
- struct estimate_block_intra_args args = { cpi, x, DC_PRED, 0, 0 };
+ struct estimate_block_intra_args args = { cpi, x, DC_PRED, 1, 0, 0 };
const TX_SIZE intra_tx_size =
VPXMIN(max_txsize_lookup[bsize],
tx_mode_to_biggest_tx_size[cpi->common.tx_mode]);
MODE_INFO *const mic = xd->mi[0];
int *bmode_costs;
- const MODE_INFO *above_mi = xd->mi[-xd->mi_stride];
- const MODE_INFO *left_mi = xd->left_available ? xd->mi[-1] : NULL;
+ const MODE_INFO *above_mi = xd->above_mi;
+ const MODE_INFO *left_mi = xd->left_mi;
const PREDICTION_MODE A = vp9_above_block_mode(mic, above_mi, 0);
const PREDICTION_MODE L = vp9_left_block_mode(mic, left_mi, 0);
bmode_costs = cpi->y_mode_costs[A][L];
@@ -1036,11 +1032,19 @@
// mode tests.
for (this_mode = DC_PRED; this_mode <= H_PRED; ++this_mode) {
args.mode = this_mode;
+ args.skippable = 1;
args.rate = 0;
args.dist = 0;
mi->tx_size = intra_tx_size;
vp9_foreach_transformed_block_in_plane(xd, bsize, 0,
estimate_block_intra, &args);
+ if (args.skippable) {
+ x->skip_txfm[0] = SKIP_TXFM_AC_DC;
+ args.rate = vp9_cost_bit(vp9_get_skip_prob(&cpi->common, xd), 1);
+ } else {
+ x->skip_txfm[0] = SKIP_TXFM_NONE;
+ args.rate += vp9_cost_bit(vp9_get_skip_prob(&cpi->common, xd), 0);
+ }
this_rdc.rate = args.rate;
this_rdc.dist = args.dist;
this_rdc.rate += bmode_costs[this_mode];
@@ -1242,10 +1246,10 @@
x->skip_encode = cpi->sf.skip_encode_frame && x->q_index < QIDX_SKIP_THRESH;
x->skip = 0;
- if (xd->up_available)
- filter_ref = xd->mi[-xd->mi_stride]->interp_filter;
- else if (xd->left_available)
- filter_ref = xd->mi[-1]->interp_filter;
+ if (xd->above_mi)
+ filter_ref = xd->above_mi->interp_filter;
+ else if (xd->left_mi)
+ filter_ref = xd->left_mi->interp_filter;
else
filter_ref = cm->interp_filter;
@@ -1270,7 +1274,10 @@
}
#if CONFIG_VP9_TEMPORAL_DENOISING
- vp9_denoiser_reset_frame_stats(ctx);
+ if (cpi->oxcf.noise_sensitivity > 0 &&
+ cpi->denoiser.denoising_level > kDenLowLow) {
+ vp9_denoiser_reset_frame_stats(ctx);
+ }
#endif
if (cpi->rc.frames_since_golden == 0 && !cpi->use_svc) {
@@ -1642,7 +1649,8 @@
}
#if CONFIG_VP9_TEMPORAL_DENOISING
- if (cpi->oxcf.noise_sensitivity > 0) {
+ if (cpi->oxcf.noise_sensitivity > 0 &&
+ cpi->denoiser.denoising_level > kDenLowLow) {
vp9_denoiser_update_frame_stats(mi, sse_y, this_mode, ctx);
// Keep track of zero_last cost.
if (ref_frame == LAST_FRAME && frame_mv[this_mode][ref_frame].as_int == 0)
@@ -1706,7 +1714,7 @@
((best_rdc.rdcost == INT64_MAX ||
(!x->skip && best_rdc.rdcost > inter_mode_thresh &&
bsize <= cpi->sf.max_intra_bsize)))) {
- struct estimate_block_intra_args args = { cpi, x, DC_PRED, 0, 0 };
+ struct estimate_block_intra_args args = { cpi, x, DC_PRED, 1, 0, 0 };
int i;
TX_SIZE best_intra_tx_size = TX_SIZES;
TX_SIZE intra_tx_size =
@@ -1756,11 +1764,21 @@
mi->mode = this_mode;
mi->ref_frame[0] = INTRA_FRAME;
args.mode = this_mode;
+ args.skippable = 1;
args.rate = 0;
args.dist = 0;
mi->tx_size = intra_tx_size;
vp9_foreach_transformed_block_in_plane(xd, bsize, 0,
estimate_block_intra, &args);
+ // Check skip cost here since skippable is not set for for uv, this
+ // mirrors the behavior used by inter
+ if (args.skippable) {
+ x->skip_txfm[0] = SKIP_TXFM_AC_DC;
+ args.rate = vp9_cost_bit(vp9_get_skip_prob(&cpi->common, xd), 1);
+ } else {
+ x->skip_txfm[0] = SKIP_TXFM_NONE;
+ args.rate += vp9_cost_bit(vp9_get_skip_prob(&cpi->common, xd), 0);
+ }
// Inter and intra RD will mismatch in scale for non-screen content.
if (cpi->oxcf.content == VP9E_CONTENT_SCREEN) {
if (x->color_sensitivity[0])
@@ -1823,10 +1841,12 @@
#if CONFIG_VP9_TEMPORAL_DENOISING
if (cpi->oxcf.noise_sensitivity > 0 &&
- cpi->resize_pending == 0) {
+ cpi->resize_pending == 0 &&
+ cpi->denoiser.denoising_level > kDenLowLow &&
+ cpi->denoiser.reset == 0) {
VP9_DENOISER_DECISION decision = COPY_BLOCK;
- vp9_denoiser_denoise(&cpi->denoiser, x, mi_row, mi_col,
- VPXMAX(BLOCK_8X8, bsize), ctx, &decision);
+ vp9_denoiser_denoise(cpi, x, mi_row, mi_col, VPXMAX(BLOCK_8X8, bsize),
+ ctx, &decision);
// If INTRA or GOLDEN reference was selected, re-evaluate ZEROMV on denoised
// result. Only do this under noise conditions, and if rdcost of ZEROMV on
// original source is not significantly higher than rdcost of best mode.
diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c
index 61bb35e..dab7f67 100644
--- a/vp9/encoder/vp9_ratectrl.c
+++ b/vp9/encoder/vp9_ratectrl.c
@@ -133,7 +133,7 @@
kf_high_m[i] = get_minq_index(maxq, 0.0000021, -0.00125, 0.55, bit_depth);
arfgf_low[i] = get_minq_index(maxq, 0.0000015, -0.0009, 0.30, bit_depth);
arfgf_high[i] = get_minq_index(maxq, 0.0000021, -0.00125, 0.55, bit_depth);
- inter[i] = get_minq_index(maxq, 0.00000271, -0.00113, 0.90, bit_depth);
+ inter[i] = get_minq_index(maxq, 0.00000271, -0.00113, 0.70, bit_depth);
rtc[i] = get_minq_index(maxq, 0.00000271, -0.00113, 0.70, bit_depth);
}
}
@@ -621,15 +621,16 @@
if (cpi->common.frame_type == KEY_FRAME) {
active_worst_quality = curr_frame == 0 ? rc->worst_quality
- : rc->last_q[KEY_FRAME] * 2;
+ : rc->last_q[KEY_FRAME] << 1;
} else {
if (!rc->is_src_frame_alt_ref &&
(cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) {
- active_worst_quality = curr_frame == 1 ? rc->last_q[KEY_FRAME] * 5 / 4
+ active_worst_quality = curr_frame == 1 ? rc->last_q[KEY_FRAME] * 5 >> 2
: rc->last_q[INTER_FRAME];
} else {
- active_worst_quality = curr_frame == 1 ? rc->last_q[KEY_FRAME] * 2
- : rc->last_q[INTER_FRAME] * 2;
+ active_worst_quality = curr_frame == 1 ? rc->last_q[KEY_FRAME] << 1 :
+ VPXMIN(rc->last_q[INTER_FRAME] << 1,
+ (rc->avg_frame_qindex[INTER_FRAME] * 3 >> 1));
}
}
return VPXMIN(active_worst_quality, rc->worst_quality);
@@ -662,7 +663,7 @@
VPXMIN(rc->avg_frame_qindex[INTER_FRAME],
rc->avg_frame_qindex[KEY_FRAME]) :
rc->avg_frame_qindex[INTER_FRAME];
- active_worst_quality = VPXMIN(rc->worst_quality, ambient_qp * 5 / 4);
+ active_worst_quality = VPXMIN(rc->worst_quality, ambient_qp * 5 >> 2);
if (rc->buffer_level > rc->optimal_buffer_level) {
// Adjust down.
// Maximum limit for down adjustment, ~30%.
@@ -811,8 +812,8 @@
return q;
}
-static int get_active_cq_level(const RATE_CONTROL *rc,
- const VP9EncoderConfig *const oxcf) {
+static int get_active_cq_level_one_pass(
+ const RATE_CONTROL *rc, const VP9EncoderConfig *const oxcf) {
static const double cq_adjust_threshold = 0.1;
int active_cq_level = oxcf->cq_level;
if (oxcf->rc_mode == VPX_CQ &&
@@ -825,13 +826,36 @@
return active_cq_level;
}
+#define SMOOTH_PCT_MIN 0.1
+#define SMOOTH_PCT_DIV 0.05
+static int get_active_cq_level_two_pass(
+ const TWO_PASS *twopass, const RATE_CONTROL *rc,
+ const VP9EncoderConfig *const oxcf) {
+ static const double cq_adjust_threshold = 0.1;
+ int active_cq_level = oxcf->cq_level;
+ if (oxcf->rc_mode == VPX_CQ) {
+ if (twopass->mb_smooth_pct > SMOOTH_PCT_MIN) {
+ active_cq_level -= (int)((twopass->mb_smooth_pct - SMOOTH_PCT_MIN) /
+ SMOOTH_PCT_DIV);
+ active_cq_level = VPXMAX(active_cq_level, 0);
+ }
+ if (rc->total_target_bits > 0) {
+ const double x = (double)rc->total_actual_bits / rc->total_target_bits;
+ if (x < cq_adjust_threshold) {
+ active_cq_level = (int)(active_cq_level * x / cq_adjust_threshold);
+ }
+ }
+ }
+ return active_cq_level;
+}
+
static int rc_pick_q_and_bounds_one_pass_vbr(const VP9_COMP *cpi,
int *bottom_index,
int *top_index) {
const VP9_COMMON *const cm = &cpi->common;
const RATE_CONTROL *const rc = &cpi->rc;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
- const int cq_level = get_active_cq_level(rc, oxcf);
+ const int cq_level = get_active_cq_level_one_pass(rc, oxcf);
int active_best_quality;
int active_worst_quality = calc_active_worst_quality_one_pass_vbr(cpi);
int q;
@@ -881,9 +905,12 @@
// Use the lower of active_worst_quality and recent
// average Q as basis for GF/ARF best Q limit unless last frame was
// a key frame.
- if (rc->frames_since_key > 1 &&
- rc->avg_frame_qindex[INTER_FRAME] < active_worst_quality) {
- q = rc->avg_frame_qindex[INTER_FRAME];
+ if (rc->frames_since_key > 1) {
+ if (rc->avg_frame_qindex[INTER_FRAME] < active_worst_quality) {
+ q = rc->avg_frame_qindex[INTER_FRAME];
+ } else {
+ q = active_worst_quality;
+ }
} else {
q = rc->avg_frame_qindex[KEY_FRAME];
}
@@ -1017,7 +1044,7 @@
const RATE_CONTROL *const rc = &cpi->rc;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
const GF_GROUP *gf_group = &cpi->twopass.gf_group;
- const int cq_level = get_active_cq_level(rc, oxcf);
+ const int cq_level = get_active_cq_level_two_pass(&cpi->twopass, rc, oxcf);
int active_best_quality;
int active_worst_quality = cpi->twopass.active_worst_quality;
int q;
@@ -2047,8 +2074,8 @@
// for cases where there is small change from content that is completely
// static.
if (cpi->oxcf.rc_mode == VPX_VBR) {
- min_thresh = 30000;
- thresh = 2.0f;
+ min_thresh = 60000;
+ thresh = 2.1f;
}
if (avg_sad >
VPXMAX(min_thresh, (unsigned int)(rc->avg_source_sad * thresh)) &&
@@ -2057,20 +2084,25 @@
else
rc->high_source_sad = 0;
if (avg_sad > 0 || cpi->oxcf.rc_mode == VPX_CBR)
- rc->avg_source_sad = (rc->avg_source_sad + avg_sad) >> 1;
+ rc->avg_source_sad = (3 * rc->avg_source_sad + avg_sad) >> 2;
// For VBR, under scene change/high content change, force golden refresh.
if (cpi->oxcf.rc_mode == VPX_VBR &&
rc->high_source_sad &&
- cpi->refresh_golden_frame == 0 &&
+ rc->count_last_scene_change > 4 &&
cpi->ext_refresh_frame_flags_pending == 0) {
int target;
cpi->refresh_golden_frame = 1;
+ rc->gfu_boost = DEFAULT_GF_BOOST >> 1;
+ rc->baseline_gf_interval = VPXMIN(20,
+ VPXMAX(10, rc->baseline_gf_interval));
rc->frames_till_gf_update_due = rc->baseline_gf_interval;
if (rc->frames_till_gf_update_due > rc->frames_to_key)
rc->frames_till_gf_update_due = rc->frames_to_key;
- rc->gfu_boost = DEFAULT_GF_BOOST;
target = calc_pframe_target_size_one_pass_vbr(cpi);
vp9_rc_set_frame_target(cpi, target);
+ rc->count_last_scene_change = 0;
+ } else {
+ rc->count_last_scene_change++;
}
}
}
diff --git a/vp9/encoder/vp9_ratectrl.h b/vp9/encoder/vp9_ratectrl.h
index 3df909c..4cd4b12 100644
--- a/vp9/encoder/vp9_ratectrl.h
+++ b/vp9/encoder/vp9_ratectrl.h
@@ -161,6 +161,7 @@
uint64_t avg_source_sad;
int high_source_sad;
+ int count_last_scene_change;
} RATE_CONTROL;
struct VP9_COMP;
diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c
index 508c596..a304182 100644
--- a/vp9/encoder/vp9_rdopt.c
+++ b/vp9/encoder/vp9_rdopt.c
@@ -2460,10 +2460,10 @@
if (pred_filter_search) {
INTERP_FILTER af = SWITCHABLE, lf = SWITCHABLE;
- if (xd->up_available)
- af = xd->mi[-xd->mi_stride]->interp_filter;
- if (xd->left_available)
- lf = xd->mi[-1]->interp_filter;
+ if (xd->above_mi)
+ af = xd->above_mi->interp_filter;
+ if (xd->left_mi)
+ lf = xd->left_mi->interp_filter;
if ((this_mode != NEWMV) || (af == lf))
best_filter = af;
diff --git a/vp9/encoder/vp9_resize.c b/vp9/encoder/vp9_resize.c
index 63f0ce2..307a112 100644
--- a/vp9/encoder/vp9_resize.c
+++ b/vp9/encoder/vp9_resize.c
@@ -446,7 +446,7 @@
int length,
uint8_t *output,
int olength,
- uint8_t *buf) {
+ uint8_t *otmp) {
int steps;
if (length == olength) {
memcpy(output, input, sizeof(output[0]) * length);
@@ -457,16 +457,10 @@
if (steps > 0) {
int s;
uint8_t *out = NULL;
- uint8_t *tmpbuf = NULL;
- uint8_t *otmp, *otmp2;
+ uint8_t *otmp2;
int filteredlength = length;
- if (!tmpbuf) {
- tmpbuf = (uint8_t *)malloc(sizeof(uint8_t) * length);
- if (tmpbuf == NULL) return;
- otmp = tmpbuf;
- } else {
- otmp = buf;
- }
+
+ assert(otmp != NULL);
otmp2 = otmp + get_down2_length(length, 1);
for (s = 0; s < steps; ++s) {
const int proj_filteredlength = get_down2_length(filteredlength, 1);
@@ -484,8 +478,6 @@
if (filteredlength != olength) {
interpolate(out, filteredlength, output, olength);
}
- if (tmpbuf)
- free(tmpbuf);
} else {
interpolate(input, length, output, olength);
}
@@ -521,25 +513,29 @@
uint8_t *intbuf = (uint8_t *)malloc(sizeof(uint8_t) * width2 * height);
uint8_t *tmpbuf = (uint8_t *)malloc(sizeof(uint8_t) *
(width < height ? height : width));
- uint8_t *arrbuf = (uint8_t *)malloc(sizeof(uint8_t) * (height + height2));
- if (intbuf == NULL || tmpbuf == NULL || arrbuf == NULL) goto Error;
+ uint8_t *arrbuf = (uint8_t *)malloc(sizeof(uint8_t) * height);
+ uint8_t *arrbuf2 = (uint8_t *)malloc(sizeof(uint8_t) * height2);
+ if (intbuf == NULL || tmpbuf == NULL ||
+ arrbuf == NULL || arrbuf2 == NULL)
+ goto Error;
assert(width > 0);
assert(height > 0);
assert(width2 > 0);
assert(height2 > 0);
for (i = 0; i < height; ++i)
resize_multistep(input + in_stride * i, width,
- intbuf + width2 * i, width2, tmpbuf);
+ intbuf + width2 * i, width2, tmpbuf);
for (i = 0; i < width2; ++i) {
fill_col_to_arr(intbuf + i, width2, height, arrbuf);
- resize_multistep(arrbuf, height, arrbuf + height, height2, tmpbuf);
- fill_arr_to_col(output + i, out_stride, height2, arrbuf + height);
+ resize_multistep(arrbuf, height, arrbuf2, height2, tmpbuf);
+ fill_arr_to_col(output + i, out_stride, height2, arrbuf2);
}
Error:
free(intbuf);
free(tmpbuf);
free(arrbuf);
+ free(arrbuf2);
}
#if CONFIG_VP9_HIGHBITDEPTH
@@ -742,7 +738,7 @@
int length,
uint16_t *output,
int olength,
- uint16_t *buf,
+ uint16_t *otmp,
int bd) {
int steps;
if (length == olength) {
@@ -754,16 +750,10 @@
if (steps > 0) {
int s;
uint16_t *out = NULL;
- uint16_t *tmpbuf = NULL;
- uint16_t *otmp, *otmp2;
+ uint16_t *otmp2;
int filteredlength = length;
- if (!tmpbuf) {
- tmpbuf = (uint16_t *)malloc(sizeof(uint16_t) * length);
- if (tmpbuf == NULL) return;
- otmp = tmpbuf;
- } else {
- otmp = buf;
- }
+
+ assert(otmp != NULL);
otmp2 = otmp + get_down2_length(length, 1);
for (s = 0; s < steps; ++s) {
const int proj_filteredlength = get_down2_length(filteredlength, 1);
@@ -781,8 +771,6 @@
if (filteredlength != olength) {
highbd_interpolate(out, filteredlength, output, olength, bd);
}
- if (tmpbuf)
- free(tmpbuf);
} else {
highbd_interpolate(input, length, output, olength, bd);
}
@@ -821,24 +809,28 @@
uint16_t *intbuf = (uint16_t *)malloc(sizeof(uint16_t) * width2 * height);
uint16_t *tmpbuf = (uint16_t *)malloc(sizeof(uint16_t) *
(width < height ? height : width));
- uint16_t *arrbuf = (uint16_t *)malloc(sizeof(uint16_t) * (height + height2));
- if (intbuf == NULL || tmpbuf == NULL || arrbuf == NULL) goto Error;
+ uint16_t *arrbuf = (uint16_t *)malloc(sizeof(uint16_t) * height);
+ uint16_t *arrbuf2 = (uint16_t *)malloc(sizeof(uint16_t) * height2);
+ if (intbuf == NULL || tmpbuf == NULL ||
+ arrbuf == NULL || arrbuf2 == NULL)
+ goto Error;
for (i = 0; i < height; ++i) {
highbd_resize_multistep(CONVERT_TO_SHORTPTR(input + in_stride * i), width,
intbuf + width2 * i, width2, tmpbuf, bd);
}
for (i = 0; i < width2; ++i) {
highbd_fill_col_to_arr(intbuf + i, width2, height, arrbuf);
- highbd_resize_multistep(arrbuf, height, arrbuf + height, height2, tmpbuf,
+ highbd_resize_multistep(arrbuf, height, arrbuf2, height2, tmpbuf,
bd);
highbd_fill_arr_to_col(CONVERT_TO_SHORTPTR(output + i), out_stride, height2,
- arrbuf + height);
+ arrbuf2);
}
Error:
free(intbuf);
free(tmpbuf);
free(arrbuf);
+ free(arrbuf2);
}
#endif // CONFIG_VP9_HIGHBITDEPTH
diff --git a/vp9/encoder/vp9_tokenize.c b/vp9/encoder/vp9_tokenize.c
index ee1d08a..edec755 100644
--- a/vp9/encoder/vp9_tokenize.c
+++ b/vp9/encoder/vp9_tokenize.c
@@ -18,7 +18,6 @@
#include "vp9/common/vp9_entropy.h"
#include "vp9/common/vp9_pred_common.h"
#include "vp9/common/vp9_scan.h"
-#include "vp9/common/vp9_seg_common.h"
#include "vp9/encoder/vp9_cost.h"
#include "vp9/encoder/vp9_encoder.h"
@@ -354,12 +353,6 @@
++counts[token];
}
-static INLINE int get_tx_eob(const struct segmentation *seg, int segment_id,
- TX_SIZE tx_size) {
- const int eob_max = 16 << (tx_size << 1);
- return segfeature_active(seg, segment_id, SEG_LVL_SKIP) ? 0 : eob_max;
-}
-
static void tokenize_b(int plane, int block, BLOCK_SIZE plane_bsize,
TX_SIZE tx_size, void *arg) {
struct tokenize_b_args* const args = arg;
@@ -378,7 +371,6 @@
int eob = p->eobs[block];
const PLANE_TYPE type = get_plane_type(plane);
const tran_low_t *qcoeff = BLOCK_OFFSET(p->qcoeff, block);
- const int segment_id = mi->segment_id;
const int16_t *scan, *nb;
const scan_order *so;
const int ref = is_inter_block(mi);
@@ -389,7 +381,7 @@
unsigned int (*const eob_branch)[COEFF_CONTEXTS] =
td->counts->eob_branch[tx_size][type][ref];
const uint8_t *const band = get_band_translate(tx_size);
- const int seg_eob = get_tx_eob(&cpi->common.seg, segment_id, tx_size);
+ const int tx_eob = 16 << (tx_size << 1);
int16_t token;
EXTRABIT extra;
int aoff, loff;
@@ -426,7 +418,7 @@
++c;
pt = get_coef_context(nb, token_cache, c);
}
- if (c < seg_eob) {
+ if (c < tx_eob) {
++eob_branch[band[c]][pt];
add_token_no_extra(&t, coef_probs[band[c]][pt], EOB_TOKEN,
counts[band[c]][pt]);
@@ -481,24 +473,26 @@
}
void vp9_tokenize_sb(VP9_COMP *cpi, ThreadData *td, TOKENEXTRA **t,
- int dry_run, BLOCK_SIZE bsize) {
- VP9_COMMON *const cm = &cpi->common;
+ int dry_run, int seg_skip, BLOCK_SIZE bsize) {
MACROBLOCK *const x = &td->mb;
MACROBLOCKD *const xd = &x->e_mbd;
MODE_INFO *const mi = xd->mi[0];
const int ctx = vp9_get_skip_context(xd);
- const int skip_inc = !segfeature_active(&cm->seg, mi->segment_id,
- SEG_LVL_SKIP);
struct tokenize_b_args arg = {cpi, td, t};
+
+ if (seg_skip) {
+ assert(mi->skip);
+ }
+
if (mi->skip) {
- if (!dry_run)
- td->counts->skip[ctx][1] += skip_inc;
+ if (!dry_run && !seg_skip)
+ ++td->counts->skip[ctx][1];
reset_skip_context(xd, bsize);
return;
}
if (!dry_run) {
- td->counts->skip[ctx][0] += skip_inc;
+ ++td->counts->skip[ctx][0];
vp9_foreach_transformed_block(xd, bsize, tokenize_b, &arg);
} else {
vp9_foreach_transformed_block(xd, bsize, set_entropy_context_b, &arg);
diff --git a/vp9/encoder/vp9_tokenize.h b/vp9/encoder/vp9_tokenize.h
index fad7988..1caab2a 100644
--- a/vp9/encoder/vp9_tokenize.h
+++ b/vp9/encoder/vp9_tokenize.h
@@ -51,7 +51,8 @@
struct ThreadData;
void vp9_tokenize_sb(struct VP9_COMP *cpi, struct ThreadData *td,
- TOKENEXTRA **t, int dry_run, BLOCK_SIZE bsize);
+ TOKENEXTRA **t, int dry_run, int seg_skip,
+ BLOCK_SIZE bsize);
typedef struct {
const vpx_prob *prob;
diff --git a/vpx_dsp/avg.c b/vpx_dsp/avg.c
index d3695a9..2e9dfd4 100644
--- a/vpx_dsp/avg.c
+++ b/vpx_dsp/avg.c
@@ -62,7 +62,7 @@
coeff[5] = c3 - c7;
}
-void vpx_hadamard_8x8_c(int16_t const *src_diff, int src_stride,
+void vpx_hadamard_8x8_c(const int16_t *src_diff, int src_stride,
int16_t *coeff) {
int idx;
int16_t buffer[64];
@@ -85,12 +85,12 @@
}
// In place 16x16 2D Hadamard transform
-void vpx_hadamard_16x16_c(int16_t const *src_diff, int src_stride,
+void vpx_hadamard_16x16_c(const int16_t *src_diff, int src_stride,
int16_t *coeff) {
int idx;
for (idx = 0; idx < 4; ++idx) {
// src_diff: 9 bit, dynamic range [-255, 255]
- int16_t const *src_ptr = src_diff + (idx >> 1) * 8 * src_stride
+ const int16_t *src_ptr = src_diff + (idx >> 1) * 8 * src_stride
+ (idx & 0x01) * 8;
vpx_hadamard_8x8_c(src_ptr, src_stride, coeff + idx * 64);
}
@@ -130,7 +130,7 @@
// Integer projection onto row vectors.
// height: value range {16, 32, 64}.
-void vpx_int_pro_row_c(int16_t hbuf[16], uint8_t const *ref,
+void vpx_int_pro_row_c(int16_t hbuf[16], const uint8_t *ref,
const int ref_stride, const int height) {
int idx;
const int norm_factor = height >> 1;
@@ -147,7 +147,7 @@
}
// width: value range {16, 32, 64}.
-int16_t vpx_int_pro_col_c(uint8_t const *ref, const int width) {
+int16_t vpx_int_pro_col_c(const uint8_t *ref, const int width) {
int idx;
int16_t sum = 0;
// sum: 14 bit, dynamic range [0, 16320]
@@ -159,7 +159,7 @@
// ref: [0 - 510]
// src: [0 - 510]
// bwl: {2, 3, 4}
-int vpx_vector_var_c(int16_t const *ref, int16_t const *src,
+int vpx_vector_var_c(const int16_t *ref, const int16_t *src,
const int bwl) {
int i;
int width = 4 << bwl;
diff --git a/vpx_dsp/fwd_txfm.c b/vpx_dsp/fwd_txfm.c
index 7baaa8b..a5802e1 100644
--- a/vpx_dsp/fwd_txfm.c
+++ b/vpx_dsp/fwd_txfm.c
@@ -85,7 +85,6 @@
sum += input[r * stride + c];
output[0] = sum << 1;
- output[1] = 0;
}
void vpx_fdct8x8_c(const int16_t *input, tran_low_t *final_output, int stride) {
@@ -182,7 +181,6 @@
sum += input[r * stride + c];
output[0] = sum;
- output[1] = 0;
}
void vpx_fdct16x16_c(const int16_t *input, tran_low_t *output, int stride) {
@@ -367,13 +365,12 @@
void vpx_fdct16x16_1_c(const int16_t *input, tran_low_t *output, int stride) {
int r, c;
- tran_low_t sum = 0;
+ int sum = 0;
for (r = 0; r < 16; ++r)
for (c = 0; c < 16; ++c)
sum += input[r * stride + c];
- output[0] = sum >> 1;
- output[1] = 0;
+ output[0] = (tran_low_t)(sum >> 1);
}
static INLINE tran_high_t dct_32_round(tran_high_t input) {
@@ -771,13 +768,12 @@
void vpx_fdct32x32_1_c(const int16_t *input, tran_low_t *output, int stride) {
int r, c;
- tran_low_t sum = 0;
+ int sum = 0;
for (r = 0; r < 32; ++r)
for (c = 0; c < 32; ++c)
sum += input[r * stride + c];
- output[0] = sum >> 3;
- output[1] = 0;
+ output[0] = (tran_low_t)(sum >> 3);
}
#if CONFIG_VP9_HIGHBITDEPTH
diff --git a/vpx_dsp/mips/fwd_dct32x32_msa.c b/vpx_dsp/mips/fwd_dct32x32_msa.c
index 2115a34..f29c14b 100644
--- a/vpx_dsp/mips/fwd_dct32x32_msa.c
+++ b/vpx_dsp/mips/fwd_dct32x32_msa.c
@@ -933,23 +933,21 @@
}
void vpx_fdct32x32_1_msa(const int16_t *input, int16_t *out, int32_t stride) {
- out[1] = 0;
-
- out[0] = LD_HADD(input, stride);
- out[0] += LD_HADD(input + 8, stride);
- out[0] += LD_HADD(input + 16, stride);
- out[0] += LD_HADD(input + 24, stride);
- out[0] += LD_HADD(input + 32 * 8, stride);
- out[0] += LD_HADD(input + 32 * 8 + 8, stride);
- out[0] += LD_HADD(input + 32 * 8 + 16, stride);
- out[0] += LD_HADD(input + 32 * 8 + 24, stride);
- out[0] += LD_HADD(input + 32 * 16, stride);
- out[0] += LD_HADD(input + 32 * 16 + 8, stride);
- out[0] += LD_HADD(input + 32 * 16 + 16, stride);
- out[0] += LD_HADD(input + 32 * 16 + 24, stride);
- out[0] += LD_HADD(input + 32 * 24, stride);
- out[0] += LD_HADD(input + 32 * 24 + 8, stride);
- out[0] += LD_HADD(input + 32 * 24 + 16, stride);
- out[0] += LD_HADD(input + 32 * 24 + 24, stride);
- out[0] >>= 3;
+ int sum = LD_HADD(input, stride);
+ sum += LD_HADD(input + 8, stride);
+ sum += LD_HADD(input + 16, stride);
+ sum += LD_HADD(input + 24, stride);
+ sum += LD_HADD(input + 32 * 8, stride);
+ sum += LD_HADD(input + 32 * 8 + 8, stride);
+ sum += LD_HADD(input + 32 * 8 + 16, stride);
+ sum += LD_HADD(input + 32 * 8 + 24, stride);
+ sum += LD_HADD(input + 32 * 16, stride);
+ sum += LD_HADD(input + 32 * 16 + 8, stride);
+ sum += LD_HADD(input + 32 * 16 + 16, stride);
+ sum += LD_HADD(input + 32 * 16 + 24, stride);
+ sum += LD_HADD(input + 32 * 24, stride);
+ sum += LD_HADD(input + 32 * 24 + 8, stride);
+ sum += LD_HADD(input + 32 * 24 + 16, stride);
+ sum += LD_HADD(input + 32 * 24 + 24, stride);
+ out[0] = (int16_t)(sum >> 3);
}
diff --git a/vpx_dsp/mips/fwd_txfm_msa.c b/vpx_dsp/mips/fwd_txfm_msa.c
index f66dd5f..0dd141f 100644
--- a/vpx_dsp/mips/fwd_txfm_msa.c
+++ b/vpx_dsp/mips/fwd_txfm_msa.c
@@ -237,11 +237,9 @@
}
void vpx_fdct16x16_1_msa(const int16_t *input, int16_t *out, int32_t stride) {
- out[1] = 0;
-
- out[0] = LD_HADD(input, stride);
- out[0] += LD_HADD(input + 8, stride);
- out[0] += LD_HADD(input + 16 * 8, stride);
- out[0] += LD_HADD(input + 16 * 8 + 8, stride);
- out[0] >>= 1;
+ int sum = LD_HADD(input, stride);
+ sum += LD_HADD(input + 8, stride);
+ sum += LD_HADD(input + 16 * 8, stride);
+ sum += LD_HADD(input + 16 * 8 + 8, stride);
+ out[0] = (int16_t)(sum >> 1);
}
diff --git a/vpx_dsp/vpx_dsp_rtcd_defs.pl b/vpx_dsp/vpx_dsp_rtcd_defs.pl
index a648e45..779c41a 100644
--- a/vpx_dsp/vpx_dsp_rtcd_defs.pl
+++ b/vpx_dsp/vpx_dsp_rtcd_defs.pl
@@ -924,9 +924,9 @@
$vpx_idct32x32_135_add_msa=vpx_idct32x32_1024_add_msa;
add_proto qw/void vpx_idct32x32_34_add/, "const tran_low_t *input, uint8_t *dest, int dest_stride";
- specialize qw/vpx_idct32x32_34_add sse2 neon_asm dspr2 msa/, "$ssse3_x86_64_x86inc";
+ specialize qw/vpx_idct32x32_34_add sse2 neon dspr2 msa/, "$ssse3_x86_64_x86inc";
# Need to add 34 eob idct32x32 neon implementation.
- $vpx_idct32x32_34_add_neon_asm=vpx_idct32x32_1024_add_neon;
+ $vpx_idct32x32_34_add_neon=vpx_idct32x32_1024_add_neon;
add_proto qw/void vpx_idct32x32_1_add/, "const tran_low_t *input, uint8_t *dest, int dest_stride";
specialize qw/vpx_idct32x32_1_add sse2 neon dspr2 msa/;
@@ -1001,22 +1001,22 @@
specialize qw/vpx_highbd_minmax_8x8/;
}
- add_proto qw/void vpx_hadamard_8x8/, "int16_t const *src_diff, int src_stride, int16_t *coeff";
+ add_proto qw/void vpx_hadamard_8x8/, "const int16_t *src_diff, int src_stride, int16_t *coeff";
specialize qw/vpx_hadamard_8x8 sse2/, "$ssse3_x86_64_x86inc";
- add_proto qw/void vpx_hadamard_16x16/, "int16_t const *src_diff, int src_stride, int16_t *coeff";
+ add_proto qw/void vpx_hadamard_16x16/, "const int16_t *src_diff, int src_stride, int16_t *coeff";
specialize qw/vpx_hadamard_16x16 sse2/;
add_proto qw/int vpx_satd/, "const int16_t *coeff, int length";
specialize qw/vpx_satd sse2 neon/;
- add_proto qw/void vpx_int_pro_row/, "int16_t *hbuf, uint8_t const *ref, const int ref_stride, const int height";
+ add_proto qw/void vpx_int_pro_row/, "int16_t *hbuf, const uint8_t *ref, const int ref_stride, const int height";
specialize qw/vpx_int_pro_row sse2 neon/;
- add_proto qw/int16_t vpx_int_pro_col/, "uint8_t const *ref, const int width";
+ add_proto qw/int16_t vpx_int_pro_col/, "const uint8_t *ref, const int width";
specialize qw/vpx_int_pro_col sse2 neon/;
- add_proto qw/int vpx_vector_var/, "int16_t const *ref, int16_t const *src, const int bwl";
+ add_proto qw/int vpx_vector_var/, "const int16_t *ref, const int16_t *src, const int bwl";
specialize qw/vpx_vector_var neon sse2/;
} # CONFIG_VP9_ENCODER || CONFIG_VP10_ENCODER
diff --git a/vpx_dsp/x86/fwd_txfm_sse2.c b/vpx_dsp/x86/fwd_txfm_sse2.c
index bca72e8..e4deeec 100644
--- a/vpx_dsp/x86/fwd_txfm_sse2.c
+++ b/vpx_dsp/x86/fwd_txfm_sse2.c
@@ -40,7 +40,7 @@
in1 = _mm_add_epi32(tmp, in0);
in0 = _mm_slli_epi32(in1, 1);
- store_output(&in0, output);
+ output[0] = (tran_low_t)_mm_cvtsi128_si32(in0);
}
void vpx_fdct8x8_1_sse2(const int16_t *input, tran_low_t *output, int stride) {
@@ -80,7 +80,7 @@
in0 = _mm_srli_si128(sum, 8);
in1 = _mm_add_epi32(sum, in0);
- store_output(&in1, output);
+ output[0] = (tran_low_t)_mm_cvtsi128_si32(in1);
}
void vpx_fdct16x16_1_sse2(const int16_t *input, tran_low_t *output,
@@ -91,40 +91,39 @@
int i;
for (i = 0; i < 2; ++i) {
- input += 8 * i;
- in0 = _mm_load_si128((const __m128i *)(input + 0 * stride));
- in1 = _mm_load_si128((const __m128i *)(input + 1 * stride));
- in2 = _mm_load_si128((const __m128i *)(input + 2 * stride));
- in3 = _mm_load_si128((const __m128i *)(input + 3 * stride));
+ in0 = _mm_load_si128((const __m128i *)(input + 0 * stride + 0));
+ in1 = _mm_load_si128((const __m128i *)(input + 0 * stride + 8));
+ in2 = _mm_load_si128((const __m128i *)(input + 1 * stride + 0));
+ in3 = _mm_load_si128((const __m128i *)(input + 1 * stride + 8));
u0 = _mm_add_epi16(in0, in1);
u1 = _mm_add_epi16(in2, in3);
sum = _mm_add_epi16(sum, u0);
- in0 = _mm_load_si128((const __m128i *)(input + 4 * stride));
- in1 = _mm_load_si128((const __m128i *)(input + 5 * stride));
- in2 = _mm_load_si128((const __m128i *)(input + 6 * stride));
- in3 = _mm_load_si128((const __m128i *)(input + 7 * stride));
+ in0 = _mm_load_si128((const __m128i *)(input + 2 * stride + 0));
+ in1 = _mm_load_si128((const __m128i *)(input + 2 * stride + 8));
+ in2 = _mm_load_si128((const __m128i *)(input + 3 * stride + 0));
+ in3 = _mm_load_si128((const __m128i *)(input + 3 * stride + 8));
sum = _mm_add_epi16(sum, u1);
u0 = _mm_add_epi16(in0, in1);
u1 = _mm_add_epi16(in2, in3);
sum = _mm_add_epi16(sum, u0);
- in0 = _mm_load_si128((const __m128i *)(input + 8 * stride));
- in1 = _mm_load_si128((const __m128i *)(input + 9 * stride));
- in2 = _mm_load_si128((const __m128i *)(input + 10 * stride));
- in3 = _mm_load_si128((const __m128i *)(input + 11 * stride));
+ in0 = _mm_load_si128((const __m128i *)(input + 4 * stride + 0));
+ in1 = _mm_load_si128((const __m128i *)(input + 4 * stride + 8));
+ in2 = _mm_load_si128((const __m128i *)(input + 5 * stride + 0));
+ in3 = _mm_load_si128((const __m128i *)(input + 5 * stride + 8));
sum = _mm_add_epi16(sum, u1);
u0 = _mm_add_epi16(in0, in1);
u1 = _mm_add_epi16(in2, in3);
sum = _mm_add_epi16(sum, u0);
- in0 = _mm_load_si128((const __m128i *)(input + 12 * stride));
- in1 = _mm_load_si128((const __m128i *)(input + 13 * stride));
- in2 = _mm_load_si128((const __m128i *)(input + 14 * stride));
- in3 = _mm_load_si128((const __m128i *)(input + 15 * stride));
+ in0 = _mm_load_si128((const __m128i *)(input + 6 * stride + 0));
+ in1 = _mm_load_si128((const __m128i *)(input + 6 * stride + 8));
+ in2 = _mm_load_si128((const __m128i *)(input + 7 * stride + 0));
+ in3 = _mm_load_si128((const __m128i *)(input + 7 * stride + 8));
sum = _mm_add_epi16(sum, u1);
u0 = _mm_add_epi16(in0, in1);
@@ -132,6 +131,7 @@
sum = _mm_add_epi16(sum, u0);
sum = _mm_add_epi16(sum, u1);
+ input += 8 * stride;
}
u0 = _mm_setzero_si128();
@@ -149,7 +149,7 @@
in1 = _mm_add_epi32(sum, in0);
in1 = _mm_srai_epi32(in1, 1);
- store_output(&in1, output);
+ output[0] = (tran_low_t)_mm_cvtsi128_si32(in1);
}
void vpx_fdct32x32_1_sse2(const int16_t *input, tran_low_t *output,
@@ -221,7 +221,7 @@
in1 = _mm_add_epi32(sum, in0);
in1 = _mm_srai_epi32(in1, 3);
- store_output(&in1, output);
+ output[0] = (tran_low_t)_mm_cvtsi128_si32(in1);
}
#define DCT_HIGH_BIT_DEPTH 0
diff --git a/vpx_ports/mem_ops.h b/vpx_ports/mem_ops.h
index d4a3d77..1f8f914 100644
--- a/vpx_ports/mem_ops.h
+++ b/vpx_ports/mem_ops.h
@@ -168,8 +168,8 @@
static VPX_INLINE void mem_put_be16(void *vmem, MEM_VALUE_T val) {
MAU_T *mem = (MAU_T *)vmem;
- mem[0] = (val >> 8) & 0xff;
- mem[1] = (val >> 0) & 0xff;
+ mem[0] = (MAU_T)((val >> 8) & 0xff);
+ mem[1] = (MAU_T)((val >> 0) & 0xff);
}
#undef mem_put_be24
@@ -177,9 +177,9 @@
static VPX_INLINE void mem_put_be24(void *vmem, MEM_VALUE_T val) {
MAU_T *mem = (MAU_T *)vmem;
- mem[0] = (val >> 16) & 0xff;
- mem[1] = (val >> 8) & 0xff;
- mem[2] = (val >> 0) & 0xff;
+ mem[0] = (MAU_T)((val >> 16) & 0xff);
+ mem[1] = (MAU_T)((val >> 8) & 0xff);
+ mem[2] = (MAU_T)((val >> 0) & 0xff);
}
#undef mem_put_be32
@@ -187,10 +187,10 @@
static VPX_INLINE void mem_put_be32(void *vmem, MEM_VALUE_T val) {
MAU_T *mem = (MAU_T *)vmem;
- mem[0] = (val >> 24) & 0xff;
- mem[1] = (val >> 16) & 0xff;
- mem[2] = (val >> 8) & 0xff;
- mem[3] = (val >> 0) & 0xff;
+ mem[0] = (MAU_T)((val >> 24) & 0xff);
+ mem[1] = (MAU_T)((val >> 16) & 0xff);
+ mem[2] = (MAU_T)((val >> 8) & 0xff);
+ mem[3] = (MAU_T)((val >> 0) & 0xff);
}
#undef mem_put_le16
@@ -198,8 +198,8 @@
static VPX_INLINE void mem_put_le16(void *vmem, MEM_VALUE_T val) {
MAU_T *mem = (MAU_T *)vmem;
- mem[0] = (val >> 0) & 0xff;
- mem[1] = (val >> 8) & 0xff;
+ mem[0] = (MAU_T)((val >> 0) & 0xff);
+ mem[1] = (MAU_T)((val >> 8) & 0xff);
}
#undef mem_put_le24
@@ -207,9 +207,9 @@
static VPX_INLINE void mem_put_le24(void *vmem, MEM_VALUE_T val) {
MAU_T *mem = (MAU_T *)vmem;
- mem[0] = (val >> 0) & 0xff;
- mem[1] = (val >> 8) & 0xff;
- mem[2] = (val >> 16) & 0xff;
+ mem[0] = (MAU_T)((val >> 0) & 0xff);
+ mem[1] = (MAU_T)((val >> 8) & 0xff);
+ mem[2] = (MAU_T)((val >> 16) & 0xff);
}
#undef mem_put_le32
@@ -217,10 +217,10 @@
static VPX_INLINE void mem_put_le32(void *vmem, MEM_VALUE_T val) {
MAU_T *mem = (MAU_T *)vmem;
- mem[0] = (val >> 0) & 0xff;
- mem[1] = (val >> 8) & 0xff;
- mem[2] = (val >> 16) & 0xff;
- mem[3] = (val >> 24) & 0xff;
+ mem[0] = (MAU_T)((val >> 0) & 0xff);
+ mem[1] = (MAU_T)((val >> 8) & 0xff);
+ mem[2] = (MAU_T)((val >> 16) & 0xff);
+ mem[3] = (MAU_T)((val >> 24) & 0xff);
}
#endif // VPX_PORTS_MEM_OPS_H_
diff --git a/vpx_ports/mem_ops_aligned.h b/vpx_ports/mem_ops_aligned.h
index c16111f..46f6173 100644
--- a/vpx_ports/mem_ops_aligned.h
+++ b/vpx_ports/mem_ops_aligned.h
@@ -28,8 +28,8 @@
* could redefine these macros.
*/
#define swap_endian_16(val,raw) do {\
- val = ((raw>>8) & 0x00ff) \
- | ((raw<<8) & 0xff00);\
+ val = (uint16_t)(((raw>>8) & 0x00ff) \
+ | ((raw<<8) & 0xff00));\
} while(0)
#define swap_endian_32(val,raw) do {\
val = ((raw>>24) & 0x000000ff) \
diff --git a/webmdec.cc b/webmdec.cc
index f541cfe..81150aa 100644
--- a/webmdec.cc
+++ b/webmdec.cc
@@ -13,8 +13,8 @@
#include <cstring>
#include <cstdio>
-#include "third_party/libwebm/mkvparser.hpp"
-#include "third_party/libwebm/mkvreader.hpp"
+#include "third_party/libwebm/mkvparser/mkvparser.h"
+#include "third_party/libwebm/mkvparser/mkvreader.h"
namespace {
@@ -164,7 +164,7 @@
}
get_new_block = true;
}
- if (status) {
+ if (status || block_entry == NULL) {
return -1;
}
if (get_new_block) {
diff --git a/webmenc.cc b/webmenc.cc
index d41e700..caf4391 100644
--- a/webmenc.cc
+++ b/webmenc.cc
@@ -11,9 +11,9 @@
#include <string>
-#include "third_party/libwebm/mkvmuxer.hpp"
-#include "third_party/libwebm/mkvmuxerutil.hpp"
-#include "third_party/libwebm/mkvwriter.hpp"
+#include "third_party/libwebm/mkvmuxer/mkvmuxer.h"
+#include "third_party/libwebm/mkvmuxer/mkvmuxerutil.h"
+#include "third_party/libwebm/mkvmuxer/mkvwriter.h"
namespace {
const uint64_t kDebugTrackUid = 0xDEADBEEF;