Add support for parsing VPx track codec private data.

Currently only the VP9 profile level is supported.

http://www.webmproject.org/vp9/profiles/

Change-Id: Iff7238e104621b53fdd51a67d752bd72b2dbbacb
This commit is contained in:
Tom Finegan 2016-04-01 10:29:14 -07:00
parent 4cbdbf1978
commit 5c50e310e7
4 changed files with 109 additions and 1 deletions

View File

@ -111,4 +111,72 @@ bool CopyColour(const mkvparser::Colour& parser_colour,
}
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

View File

@ -8,6 +8,8 @@
#ifndef LIBWEBM_COMMON_HDR_UTIL_H_
#define LIBWEBM_COMMON_HDR_UTIL_H_
#include <stdint.h>
#include <memory>
#include "mkvmuxer/mkvmuxer.h"
@ -41,6 +43,9 @@ 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_

View File

@ -14,6 +14,7 @@
#include <iomanip>
#include <string>
#include "common/hdr_util.h"
#include "mkvparser/mkvparser.h"
#include "mkvparser/mkvreader.h"
#include "testing/test_util.h"
@ -662,6 +663,27 @@ TEST_F(ParserTest, StereoModeParsedCorrectly) {
EXPECT_EQ(144, video_track->GetDisplayHeight());
}
TEST_F(ParserTest, Vp9CodecProfileTest) {
const int kCodecPrivateLength = 3;
// Test invalid codec private data; all of these should return 0.
const uint8_t bad_codec_private[kCodecPrivateLength] = {0, 0, 0};
EXPECT_EQ(0, libwebm::ParseVpxCodecPrivate(NULL, kCodecPrivateLength));
EXPECT_EQ(0, libwebm::ParseVpxCodecPrivate(&bad_codec_private[0], 0));
EXPECT_EQ(0, libwebm::ParseVpxCodecPrivate(&bad_codec_private[0],
kCodecPrivateLength));
const uint8_t good_codec_private[kCodecPrivateLength] = {1, 1, 11};
// Test parse of codec private chunks, but lie about length.
EXPECT_EQ(0, libwebm::ParseVpxCodecPrivate(&bad_codec_private[0], 0));
EXPECT_EQ(0, libwebm::ParseVpxCodecPrivate(&good_codec_private[0], 0));
// Test a valid codec private; this should return 11.
// ID: 1, Length: 1, Profile: 11
EXPECT_EQ(11, libwebm::ParseVpxCodecPrivate(&good_codec_private[0],
kCodecPrivateLength));
}
} // namespace test
int main(int argc, char* argv[]) {

View File

@ -16,6 +16,7 @@
#include <string>
#include <vector>
#include "common/hdr_util.h"
#include "common/indent.h"
#include "common/webm_constants.h"
#include "common/webm_endian.h"
@ -364,10 +365,22 @@ bool OutputTracks(const mkvparser::Segment& segment, const Options& options,
size_t private_size;
const unsigned char* const private_data =
track->GetCodecPrivate(private_size);
if (private_data)
if (private_data) {
fprintf(o, "%sPrivateData(size): %d\n", indent->indent_str().c_str(),
static_cast<int>(private_size));
if (track_type == mkvparser::Track::kVideo) {
const std::string codec_id = track->GetCodecId();
const std::string v_vp9 = "V_VP9";
if (codec_id == v_vp9) {
const int vp9_profile_level =
libwebm::ParseVpxCodecPrivate(private_data, private_size);
fprintf(o, "%sVP9 profile level: %d\n", indent->indent_str().c_str(),
vp9_profile_level);
}
}
}
const uint64_t default_duration = track->GetDefaultDuration();
if (default_duration > 0)
fprintf(o, "%sDefaultDuration: %" PRIu64 "\n",