Merge "Add parsing support for new features in CodecPrivate."
This commit is contained in:
commit
eacb314525
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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[]) {
|
||||
|
26
webm_info.cc
26
webm_info.cc
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user