Merge "Add parsing support for new features in CodecPrivate."

This commit is contained in:
Frank Galligan 2016-04-29 00:17:28 +00:00 committed by Gerrit Code Review
commit eacb314525
4 changed files with 148 additions and 67 deletions

View File

@ -7,12 +7,15 @@
// be found in the AUTHORS file in the root of the source tree.
#include "hdr_util.h"
#include <climits>
#include <cstddef>
#include <new>
#include "mkvparser/mkvparser.h"
namespace libwebm {
const int Vp9CodecFeatures::kValueNotPresent = INT_MAX;
bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc,
PrimaryChromaticityPtr* muxer_pc) {
muxer_pc->reset(new (std::nothrow)
@ -135,19 +138,23 @@ bool CopyColour(const mkvparser::Colour& parser_colour,
// See the following link for more information:
// http://www.webmproject.org/vp9/profiles/
bool ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length,
int* profile, int* level) {
Vp9CodecFeatures* features) {
const int kVpxCodecPrivateMinLength = 3;
if (!private_data || !profile || !level || length < kVpxCodecPrivateMinLength)
if (!private_data || !features || length < kVpxCodecPrivateMinLength)
return false;
const uint8_t kVp9ProfileId = 1;
const uint8_t kVp9LevelId = 2;
const uint8_t kVp9BitDepthId = 3;
const uint8_t kVp9ChromaSubsamplingId = 4;
const int kVpxFeatureLength = 1;
int offset = 0;
// Set profile and level to not set.
*profile = -1;
*level = -1;
// Set features to not set.
features->profile = Vp9CodecFeatures::kValueNotPresent;
features->level = Vp9CodecFeatures::kValueNotPresent;
features->bit_depth = Vp9CodecFeatures::kValueNotPresent;
features->chroma_subsampling = Vp9CodecFeatures::kValueNotPresent;
do {
const uint8_t id_byte = private_data[offset++];
const uint8_t length_byte = private_data[offset++];
@ -157,9 +164,11 @@ bool ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length,
const int priv_profile = static_cast<int>(private_data[offset++]);
if (priv_profile < 0 || priv_profile > 3)
return false;
if (*profile != -1 && *profile != priv_profile)
if (features->profile != Vp9CodecFeatures::kValueNotPresent &&
features->profile != priv_profile) {
return false;
*profile = priv_profile;
}
features->profile = priv_profile;
} else if (id_byte == kVp9LevelId) {
const int priv_level = static_cast<int>(private_data[offset++]);
@ -169,14 +178,34 @@ bool ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length,
for (int i = 0; i < kNumLevels; ++i) {
if (priv_level == levels[i]) {
if (*level != -1 && *level != priv_level)
if (features->level != Vp9CodecFeatures::kValueNotPresent &&
features->level != priv_level) {
return false;
*level = priv_level;
}
features->level = priv_level;
break;
}
}
if (*level == -1)
if (features->level == Vp9CodecFeatures::kValueNotPresent)
return false;
} else if (id_byte == kVp9BitDepthId) {
const int priv_profile = static_cast<int>(private_data[offset++]);
if (priv_profile != 8 && priv_profile != 10 && priv_profile != 12)
return false;
if (features->bit_depth != Vp9CodecFeatures::kValueNotPresent &&
features->bit_depth != priv_profile) {
return false;
}
features->bit_depth = priv_profile;
} else if (id_byte == kVp9ChromaSubsamplingId) {
const int priv_profile = static_cast<int>(private_data[offset++]);
if (priv_profile != 0 && priv_profile != 2 && priv_profile != 3)
return false;
if (features->chroma_subsampling != Vp9CodecFeatures::kValueNotPresent &&
features->chroma_subsampling != priv_profile) {
return false;
}
features->chroma_subsampling = priv_profile;
} else {
// Invalid ID.
return false;

View File

@ -28,6 +28,25 @@ namespace libwebm {
// TODO(tomfinegan): These should be moved to libwebm_utils once c++11 is
// required by libwebm.
// Features of the VP9 codec that may be set in the CodecPrivate of a VP9 video
// stream. A value of kValueNotPresent represents that the value was not set in
// the CodecPrivate.
struct Vp9CodecFeatures {
static const int kValueNotPresent;
Vp9CodecFeatures()
: profile(kValueNotPresent),
level(kValueNotPresent),
bit_depth(kValueNotPresent),
chroma_subsampling(kValueNotPresent) {}
~Vp9CodecFeatures(){};
int profile;
int level;
int bit_depth;
int chroma_subsampling;
};
typedef std::auto_ptr<mkvmuxer::PrimaryChromaticity> PrimaryChromaticityPtr;
bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc,
@ -43,12 +62,9 @@ bool ColourValuePresent(long long value);
bool CopyColour(const mkvparser::Colour& parser_colour,
mkvmuxer::Colour* muxer_colour);
// Returns true if |profile| and |level| are set to valid values. Returns VP9
// profile in |profile| or -1 if there was no profile set in CodecPrivate data.
// Returns VP9 level in |level| or -1 if there was no level set in CodecPrivate
// data.
// Returns true if |features| is set to one or more valid values.
bool ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length,
int* profile, int* level);
Vp9CodecFeatures* features);
} // namespace libwebm

View File

@ -666,67 +666,99 @@ TEST_F(ParserTest, StereoModeParsedCorrectly) {
TEST_F(ParserTest, Vp9CodecLevelTest) {
const int kCodecPrivateLength = 3;
const uint8_t good_codec_private_level[kCodecPrivateLength] = {2, 1, 11};
int profile;
int level;
EXPECT_EQ(true, libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0],
kCodecPrivateLength, &profile,
&level));
EXPECT_EQ(-1, profile);
EXPECT_EQ(11, level);
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0],
kCodecPrivateLength, &features));
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.profile);
EXPECT_EQ(11, features.level);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.bit_depth);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent,
features.chroma_subsampling);
}
TEST_F(ParserTest, Vp9CodecProfileTest) {
const int kCodecPrivateLength = 3;
const uint8_t good_codec_private_profile[kCodecPrivateLength] = {1, 1, 1};
int profile;
int level;
EXPECT_EQ(true, libwebm::ParseVpxCodecPrivate(&good_codec_private_profile[0],
kCodecPrivateLength, &profile,
&level));
EXPECT_EQ(1, profile);
EXPECT_EQ(-1, level);
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&good_codec_private_profile[0],
kCodecPrivateLength, &features));
EXPECT_EQ(1, features.profile);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.level);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.bit_depth);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent,
features.chroma_subsampling);
}
TEST_F(ParserTest, Vp9CodecBitDepthTest) {
const int kCodecPrivateLength = 3;
const uint8_t good_codec_private_profile[kCodecPrivateLength] = {3, 1, 8};
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&good_codec_private_profile[0],
kCodecPrivateLength, &features));
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.profile);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.level);
EXPECT_EQ(8, features.bit_depth);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent,
features.chroma_subsampling);
}
TEST_F(ParserTest, Vp9CodecChromaSubsamplingTest) {
const int kCodecPrivateLength = 3;
const uint8_t good_codec_private_profile[kCodecPrivateLength] = {4, 1, 0};
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&good_codec_private_profile[0],
kCodecPrivateLength, &features));
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.profile);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.level);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.bit_depth);
EXPECT_EQ(0, features.chroma_subsampling);
}
TEST_F(ParserTest, Vp9CodecProfileLevelTest) {
const int kCodecPrivateLength = 6;
const uint8_t codec_private[kCodecPrivateLength] = {1, 1, 1, 2, 1, 11};
int profile;
int level;
EXPECT_EQ(true,
libwebm::ParseVpxCodecPrivate(
&codec_private[0], kCodecPrivateLength, &profile, &level));
EXPECT_EQ(1, profile);
EXPECT_EQ(11, level);
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&codec_private[0],
kCodecPrivateLength, &features));
EXPECT_EQ(1, features.profile);
EXPECT_EQ(11, features.level);
}
TEST_F(ParserTest, Vp9CodecAllTest) {
const int kCodecPrivateLength = 12;
const uint8_t codec_private[kCodecPrivateLength] = {1, 1, 1, 2, 1, 11,
3, 1, 8, 4, 1, 0};
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&codec_private[0],
kCodecPrivateLength, &features));
EXPECT_EQ(1, features.profile);
EXPECT_EQ(11, features.level);
EXPECT_EQ(8, features.bit_depth);
EXPECT_EQ(0, features.chroma_subsampling);
}
TEST_F(ParserTest, Vp9CodecPrivateBadTest) {
const int kCodecPrivateLength = 3;
int profile;
int level;
libwebm::Vp9CodecFeatures features;
// Test invalid codec private data; all of these should return false.
const uint8_t bad_codec_private[kCodecPrivateLength] = {0, 0, 0};
EXPECT_EQ(false, libwebm::ParseVpxCodecPrivate(NULL, kCodecPrivateLength,
&profile, &level));
EXPECT_EQ(false, libwebm::ParseVpxCodecPrivate(&bad_codec_private[0], 0,
&profile, &level));
EXPECT_EQ(false,
libwebm::ParseVpxCodecPrivate(
&bad_codec_private[0], kCodecPrivateLength, &profile, &level));
EXPECT_FALSE(
libwebm::ParseVpxCodecPrivate(NULL, kCodecPrivateLength, &features));
EXPECT_FALSE(
libwebm::ParseVpxCodecPrivate(&bad_codec_private[0], 0, &features));
EXPECT_FALSE(libwebm::ParseVpxCodecPrivate(&bad_codec_private[0],
kCodecPrivateLength, &features));
const uint8_t good_codec_private_level[kCodecPrivateLength] = {2, 1, 11};
// Test parse of codec private chunks, but lie about length.
EXPECT_EQ(false, libwebm::ParseVpxCodecPrivate(&bad_codec_private[0], 0,
&profile, &level));
EXPECT_EQ(false, libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0],
0, &profile, &level));
EXPECT_EQ(false,
libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0],
kCodecPrivateLength, NULL, &level));
EXPECT_EQ(false,
libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0],
kCodecPrivateLength, &profile, NULL));
EXPECT_FALSE(
libwebm::ParseVpxCodecPrivate(&bad_codec_private[0], 0, &features));
EXPECT_FALSE(libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0], 0,
&features));
EXPECT_FALSE(libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0],
kCodecPrivateLength, NULL));
}
} // namespace test
int main(int argc, char* argv[]) {

View File

@ -35,7 +35,7 @@ using libwebm::Indent;
using libwebm::kNanosecondsPerSecond;
using libwebm::kNanosecondsPerSecondi;
const char VERSION_STRING[] = "1.0.4.0";
const char VERSION_STRING[] = "1.0.4.1";
struct Options {
Options();
@ -379,21 +379,25 @@ bool OutputTracks(const mkvparser::Segment& segment, const Options& options,
const std::string codec_id = track->GetCodecId();
const std::string v_vp9 = "V_VP9";
if (codec_id == v_vp9) {
int profile;
int level;
libwebm::Vp9CodecFeatures features;
if (!libwebm::ParseVpxCodecPrivate(private_data,
static_cast<int32_t>(private_size),
&profile, &level)) {
&features)) {
fprintf(stderr, "Error parsing VpxCodecPrivate.\n");
return false;
}
if (profile != -1)
fprintf(o, "%sVP9 profile : %d\n", indent->indent_str().c_str(),
profile);
if (level != -1)
fprintf(o, "%sVP9 level : %d\n", indent->indent_str().c_str(),
level);
if (features.profile != -1)
fprintf(o, "%sVP9 profile : %d\n",
indent->indent_str().c_str(), features.profile);
if (features.level != -1)
fprintf(o, "%sVP9 level : %d\n",
indent->indent_str().c_str(), features.level);
if (features.bit_depth != -1)
fprintf(o, "%sVP9 bit_depth : %d\n",
indent->indent_str().c_str(), features.bit_depth);
if (features.chroma_subsampling != -1)
fprintf(o, "%sVP9 chroma subsampling : %d\n",
indent->indent_str().c_str(), features.chroma_subsampling);
}
}
}