Add parsing support for new features in CodecPrivate.
Adds support for parsing bit depth and chroma subsampling features. BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1198 Change-Id: I8d11829f5d43a518cbe0e5c0bdd4fd37db7b6266
This commit is contained in:
@@ -7,12 +7,15 @@
|
|||||||
// be found in the AUTHORS file in the root of the source tree.
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
#include "hdr_util.h"
|
#include "hdr_util.h"
|
||||||
|
|
||||||
|
#include <climits>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#include "mkvparser/mkvparser.h"
|
#include "mkvparser/mkvparser.h"
|
||||||
|
|
||||||
namespace libwebm {
|
namespace libwebm {
|
||||||
|
const int Vp9CodecFeatures::kValueNotPresent = INT_MAX;
|
||||||
|
|
||||||
bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc,
|
bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc,
|
||||||
PrimaryChromaticityPtr* muxer_pc) {
|
PrimaryChromaticityPtr* muxer_pc) {
|
||||||
muxer_pc->reset(new (std::nothrow)
|
muxer_pc->reset(new (std::nothrow)
|
||||||
@@ -135,19 +138,23 @@ bool CopyColour(const mkvparser::Colour& parser_colour,
|
|||||||
// See the following link for more information:
|
// See the following link for more information:
|
||||||
// http://www.webmproject.org/vp9/profiles/
|
// http://www.webmproject.org/vp9/profiles/
|
||||||
bool ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length,
|
bool ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length,
|
||||||
int* profile, int* level) {
|
Vp9CodecFeatures* features) {
|
||||||
const int kVpxCodecPrivateMinLength = 3;
|
const int kVpxCodecPrivateMinLength = 3;
|
||||||
if (!private_data || !profile || !level || length < kVpxCodecPrivateMinLength)
|
if (!private_data || !features || length < kVpxCodecPrivateMinLength)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const uint8_t kVp9ProfileId = 1;
|
const uint8_t kVp9ProfileId = 1;
|
||||||
const uint8_t kVp9LevelId = 2;
|
const uint8_t kVp9LevelId = 2;
|
||||||
|
const uint8_t kVp9BitDepthId = 3;
|
||||||
|
const uint8_t kVp9ChromaSubsamplingId = 4;
|
||||||
const int kVpxFeatureLength = 1;
|
const int kVpxFeatureLength = 1;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
|
||||||
// Set profile and level to not set.
|
// Set features to not set.
|
||||||
*profile = -1;
|
features->profile = Vp9CodecFeatures::kValueNotPresent;
|
||||||
*level = -1;
|
features->level = Vp9CodecFeatures::kValueNotPresent;
|
||||||
|
features->bit_depth = Vp9CodecFeatures::kValueNotPresent;
|
||||||
|
features->chroma_subsampling = Vp9CodecFeatures::kValueNotPresent;
|
||||||
do {
|
do {
|
||||||
const uint8_t id_byte = private_data[offset++];
|
const uint8_t id_byte = private_data[offset++];
|
||||||
const uint8_t length_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++]);
|
const int priv_profile = static_cast<int>(private_data[offset++]);
|
||||||
if (priv_profile < 0 || priv_profile > 3)
|
if (priv_profile < 0 || priv_profile > 3)
|
||||||
return false;
|
return false;
|
||||||
if (*profile != -1 && *profile != priv_profile)
|
if (features->profile != Vp9CodecFeatures::kValueNotPresent &&
|
||||||
|
features->profile != priv_profile) {
|
||||||
return false;
|
return false;
|
||||||
*profile = priv_profile;
|
}
|
||||||
|
features->profile = priv_profile;
|
||||||
} else if (id_byte == kVp9LevelId) {
|
} else if (id_byte == kVp9LevelId) {
|
||||||
const int priv_level = static_cast<int>(private_data[offset++]);
|
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) {
|
for (int i = 0; i < kNumLevels; ++i) {
|
||||||
if (priv_level == levels[i]) {
|
if (priv_level == levels[i]) {
|
||||||
if (*level != -1 && *level != priv_level)
|
if (features->level != Vp9CodecFeatures::kValueNotPresent &&
|
||||||
|
features->level != priv_level) {
|
||||||
return false;
|
return false;
|
||||||
*level = priv_level;
|
}
|
||||||
|
features->level = priv_level;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (*level == -1)
|
if (features->level == Vp9CodecFeatures::kValueNotPresent)
|
||||||
return false;
|
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 {
|
} else {
|
||||||
// Invalid ID.
|
// Invalid ID.
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -28,6 +28,25 @@ namespace libwebm {
|
|||||||
// TODO(tomfinegan): These should be moved to libwebm_utils once c++11 is
|
// TODO(tomfinegan): These should be moved to libwebm_utils once c++11 is
|
||||||
// required by libwebm.
|
// 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;
|
typedef std::auto_ptr<mkvmuxer::PrimaryChromaticity> PrimaryChromaticityPtr;
|
||||||
|
|
||||||
bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc,
|
bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc,
|
||||||
@@ -43,12 +62,9 @@ bool ColourValuePresent(long long value);
|
|||||||
bool CopyColour(const mkvparser::Colour& parser_colour,
|
bool CopyColour(const mkvparser::Colour& parser_colour,
|
||||||
mkvmuxer::Colour* muxer_colour);
|
mkvmuxer::Colour* muxer_colour);
|
||||||
|
|
||||||
// Returns true if |profile| and |level| are set to valid values. Returns VP9
|
// Returns true if |features| is set to one or more valid values.
|
||||||
// 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.
|
|
||||||
bool ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length,
|
bool ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length,
|
||||||
int* profile, int* level);
|
Vp9CodecFeatures* features);
|
||||||
|
|
||||||
} // namespace libwebm
|
} // namespace libwebm
|
||||||
|
|
||||||
|
|||||||
@@ -666,67 +666,99 @@ TEST_F(ParserTest, StereoModeParsedCorrectly) {
|
|||||||
TEST_F(ParserTest, Vp9CodecLevelTest) {
|
TEST_F(ParserTest, Vp9CodecLevelTest) {
|
||||||
const int kCodecPrivateLength = 3;
|
const int kCodecPrivateLength = 3;
|
||||||
const uint8_t good_codec_private_level[kCodecPrivateLength] = {2, 1, 11};
|
const uint8_t good_codec_private_level[kCodecPrivateLength] = {2, 1, 11};
|
||||||
int profile;
|
libwebm::Vp9CodecFeatures features;
|
||||||
int level;
|
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0],
|
||||||
EXPECT_EQ(true, libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0],
|
kCodecPrivateLength, &features));
|
||||||
kCodecPrivateLength, &profile,
|
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.profile);
|
||||||
&level));
|
EXPECT_EQ(11, features.level);
|
||||||
EXPECT_EQ(-1, profile);
|
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.bit_depth);
|
||||||
EXPECT_EQ(11, level);
|
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent,
|
||||||
|
features.chroma_subsampling);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserTest, Vp9CodecProfileTest) {
|
TEST_F(ParserTest, Vp9CodecProfileTest) {
|
||||||
const int kCodecPrivateLength = 3;
|
const int kCodecPrivateLength = 3;
|
||||||
const uint8_t good_codec_private_profile[kCodecPrivateLength] = {1, 1, 1};
|
const uint8_t good_codec_private_profile[kCodecPrivateLength] = {1, 1, 1};
|
||||||
int profile;
|
libwebm::Vp9CodecFeatures features;
|
||||||
int level;
|
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&good_codec_private_profile[0],
|
||||||
EXPECT_EQ(true, libwebm::ParseVpxCodecPrivate(&good_codec_private_profile[0],
|
kCodecPrivateLength, &features));
|
||||||
kCodecPrivateLength, &profile,
|
EXPECT_EQ(1, features.profile);
|
||||||
&level));
|
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.level);
|
||||||
EXPECT_EQ(1, profile);
|
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.bit_depth);
|
||||||
EXPECT_EQ(-1, level);
|
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) {
|
TEST_F(ParserTest, Vp9CodecProfileLevelTest) {
|
||||||
const int kCodecPrivateLength = 6;
|
const int kCodecPrivateLength = 6;
|
||||||
const uint8_t codec_private[kCodecPrivateLength] = {1, 1, 1, 2, 1, 11};
|
const uint8_t codec_private[kCodecPrivateLength] = {1, 1, 1, 2, 1, 11};
|
||||||
int profile;
|
libwebm::Vp9CodecFeatures features;
|
||||||
int level;
|
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&codec_private[0],
|
||||||
EXPECT_EQ(true,
|
kCodecPrivateLength, &features));
|
||||||
libwebm::ParseVpxCodecPrivate(
|
EXPECT_EQ(1, features.profile);
|
||||||
&codec_private[0], kCodecPrivateLength, &profile, &level));
|
EXPECT_EQ(11, features.level);
|
||||||
EXPECT_EQ(1, profile);
|
}
|
||||||
EXPECT_EQ(11, 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) {
|
TEST_F(ParserTest, Vp9CodecPrivateBadTest) {
|
||||||
const int kCodecPrivateLength = 3;
|
const int kCodecPrivateLength = 3;
|
||||||
int profile;
|
libwebm::Vp9CodecFeatures features;
|
||||||
int level;
|
|
||||||
|
|
||||||
// Test invalid codec private data; all of these should return false.
|
// Test invalid codec private data; all of these should return false.
|
||||||
const uint8_t bad_codec_private[kCodecPrivateLength] = {0, 0, 0};
|
const uint8_t bad_codec_private[kCodecPrivateLength] = {0, 0, 0};
|
||||||
EXPECT_EQ(false, libwebm::ParseVpxCodecPrivate(NULL, kCodecPrivateLength,
|
EXPECT_FALSE(
|
||||||
&profile, &level));
|
libwebm::ParseVpxCodecPrivate(NULL, kCodecPrivateLength, &features));
|
||||||
EXPECT_EQ(false, libwebm::ParseVpxCodecPrivate(&bad_codec_private[0], 0,
|
EXPECT_FALSE(
|
||||||
&profile, &level));
|
libwebm::ParseVpxCodecPrivate(&bad_codec_private[0], 0, &features));
|
||||||
EXPECT_EQ(false,
|
EXPECT_FALSE(libwebm::ParseVpxCodecPrivate(&bad_codec_private[0],
|
||||||
libwebm::ParseVpxCodecPrivate(
|
kCodecPrivateLength, &features));
|
||||||
&bad_codec_private[0], kCodecPrivateLength, &profile, &level));
|
|
||||||
const uint8_t good_codec_private_level[kCodecPrivateLength] = {2, 1, 11};
|
const uint8_t good_codec_private_level[kCodecPrivateLength] = {2, 1, 11};
|
||||||
|
|
||||||
// Test parse of codec private chunks, but lie about length.
|
// Test parse of codec private chunks, but lie about length.
|
||||||
EXPECT_EQ(false, libwebm::ParseVpxCodecPrivate(&bad_codec_private[0], 0,
|
EXPECT_FALSE(
|
||||||
&profile, &level));
|
libwebm::ParseVpxCodecPrivate(&bad_codec_private[0], 0, &features));
|
||||||
EXPECT_EQ(false, libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0],
|
EXPECT_FALSE(libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0], 0,
|
||||||
0, &profile, &level));
|
&features));
|
||||||
EXPECT_EQ(false,
|
EXPECT_FALSE(libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0],
|
||||||
libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0],
|
kCodecPrivateLength, NULL));
|
||||||
kCodecPrivateLength, NULL, &level));
|
|
||||||
EXPECT_EQ(false,
|
|
||||||
libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0],
|
|
||||||
kCodecPrivateLength, &profile, NULL));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
|||||||
26
webm_info.cc
26
webm_info.cc
@@ -35,7 +35,7 @@ using libwebm::Indent;
|
|||||||
using libwebm::kNanosecondsPerSecond;
|
using libwebm::kNanosecondsPerSecond;
|
||||||
using libwebm::kNanosecondsPerSecondi;
|
using libwebm::kNanosecondsPerSecondi;
|
||||||
|
|
||||||
const char VERSION_STRING[] = "1.0.4.0";
|
const char VERSION_STRING[] = "1.0.4.1";
|
||||||
|
|
||||||
struct Options {
|
struct Options {
|
||||||
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 codec_id = track->GetCodecId();
|
||||||
const std::string v_vp9 = "V_VP9";
|
const std::string v_vp9 = "V_VP9";
|
||||||
if (codec_id == v_vp9) {
|
if (codec_id == v_vp9) {
|
||||||
int profile;
|
libwebm::Vp9CodecFeatures features;
|
||||||
int level;
|
|
||||||
|
|
||||||
if (!libwebm::ParseVpxCodecPrivate(private_data,
|
if (!libwebm::ParseVpxCodecPrivate(private_data,
|
||||||
static_cast<int32_t>(private_size),
|
static_cast<int32_t>(private_size),
|
||||||
&profile, &level)) {
|
&features)) {
|
||||||
fprintf(stderr, "Error parsing VpxCodecPrivate.\n");
|
fprintf(stderr, "Error parsing VpxCodecPrivate.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (profile != -1)
|
if (features.profile != -1)
|
||||||
fprintf(o, "%sVP9 profile : %d\n", indent->indent_str().c_str(),
|
fprintf(o, "%sVP9 profile : %d\n",
|
||||||
profile);
|
indent->indent_str().c_str(), features.profile);
|
||||||
if (level != -1)
|
if (features.level != -1)
|
||||||
fprintf(o, "%sVP9 level : %d\n", indent->indent_str().c_str(),
|
fprintf(o, "%sVP9 level : %d\n",
|
||||||
level);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user