Modify WVM media parser to support encrypted media sample.

Change-Id: I8e696527a09fcec22b6c9713e0d1d3096720ce9c
This commit is contained in:
Ramji Chandramouli 2015-01-12 13:17:10 -08:00 committed by Gerrit Code Review
parent 50c3f3a52e
commit a99af5a015
6 changed files with 111 additions and 75 deletions

View File

@ -19,7 +19,11 @@ MediaSample::MediaSample(const uint8_t* data,
const uint8_t* side_data,
size_t side_data_size,
bool is_key_frame)
: dts_(0), pts_(0), duration_(0), is_key_frame_(is_key_frame) {
: dts_(0),
pts_(0),
duration_(0),
is_key_frame_(is_key_frame),
is_encrypted_(false) {
if (!data) {
CHECK_EQ(size, 0u);
CHECK(!side_data);
@ -31,9 +35,11 @@ MediaSample::MediaSample(const uint8_t* data,
side_data_.assign(side_data, side_data + side_data_size);
}
MediaSample::MediaSample() : dts_(0), pts_(0),
MediaSample::MediaSample() : dts_(0),
pts_(0),
duration_(0),
is_key_frame_(false) {}
is_key_frame_(false),
is_encrypted_(false) {}
MediaSample::~MediaSample() {}

View File

@ -83,6 +83,10 @@ class MediaSample : public base::RefCountedThreadSafe<MediaSample> {
return is_key_frame_;
}
bool is_encrypted() const {
DCHECK(!end_of_stream());
return is_encrypted_;
}
const uint8_t* data() const {
DCHECK(!end_of_stream());
return &data_[0];
@ -116,6 +120,10 @@ class MediaSample : public base::RefCountedThreadSafe<MediaSample> {
is_key_frame_ = value;
}
void set_is_encrypted(bool value) {
is_encrypted_ = value;
}
// If there's no data in this buffer, it represents end of stream.
bool end_of_stream() const { return data_.size() == 0; }
@ -142,6 +150,8 @@ class MediaSample : public base::RefCountedThreadSafe<MediaSample> {
int64_t pts_;
int64_t duration_;
bool is_key_frame_;
// is sample encrypted ?
bool is_encrypted_;
// Main buffer data.
std::vector<uint8_t> data_;

View File

@ -91,6 +91,9 @@ Status Muxer::AddSample(const MediaStream* stream,
// to Muxer. In this case, there should be only one stream in Muxer.
DCHECK_EQ(1u, streams_.size());
return Finalize();
} else if (sample->is_encrypted()) {
LOG(ERROR) << "Unable to multiplex encrypted media sample";
return Status(error::INTERNAL_ERROR, "Encrypted media sample.");
}
return DoAddSample(stream, sample);
}

View File

@ -373,7 +373,7 @@ bool WvmMediaParser::Parse(const uint8_t* buf, int size) {
parse_state_ = IndexPayload;
continue;
default:
if (!DemuxNextPes(read_ptr, false)) {
if (!DemuxNextPes(false)) {
return false;
}
parse_state_ = EsPayload;
@ -460,7 +460,7 @@ bool WvmMediaParser::Parse(const uint8_t* buf, int size) {
case ProgramEnd:
parse_state_ = StartCode1;
metadata_is_complete_ = true;
if (!DemuxNextPes(read_ptr, true)) {
if (!DemuxNextPes(true)) {
return false;
}
Flush();
@ -728,33 +728,34 @@ bool WvmMediaParser::ParseIndexEntry() {
return true;
}
bool WvmMediaParser::DemuxNextPes(uint8_t* read_ptr, bool is_program_end) {
bool WvmMediaParser::DemuxNextPes(bool is_program_end) {
bool output_encrypted_sample = false;
if (!sample_data_.empty() && (prev_pes_flags_1_ & kScramblingBitsMask)) {
// Decrypt crypto unit.
if (!content_decryptor_) {
LOG(ERROR) << "Source content is encrypted, but decryption not enabled";
return false;
}
output_encrypted_sample = true;
} else {
content_decryptor_->Decrypt(&sample_data_[crypto_unit_start_pos_],
sample_data_.size() - crypto_unit_start_pos_,
&sample_data_[crypto_unit_start_pos_]);
}
}
// Demux media sample if we are at program end or if we are not at a
// continuation PES.
if ((pes_flags_2_ & kPesOptPts) || is_program_end) {
if (!sample_data_.empty()) {
if (!Output()) {
if (!Output(output_encrypted_sample)) {
return false;
}
}
StartMediaSampleDemux(read_ptr);
StartMediaSampleDemux();
}
crypto_unit_start_pos_ = sample_data_.size();
return true;
}
void WvmMediaParser::StartMediaSampleDemux(uint8_t* read_ptr) {
void WvmMediaParser::StartMediaSampleDemux() {
bool is_key_frame = ((pes_flags_1_ & kPesOptAlign) != 0);
media_sample_ = MediaSample::CreateEmptyMediaSample();
media_sample_->set_dts(dts_);
@ -764,7 +765,11 @@ void WvmMediaParser::StartMediaSampleDemux(uint8_t* read_ptr) {
sample_data_.clear();
}
bool WvmMediaParser::Output() {
bool WvmMediaParser::Output(bool output_encrypted_sample) {
if (output_encrypted_sample) {
media_sample_->set_data(&sample_data_[0], sample_data_.size());
media_sample_->set_is_encrypted(true);
} else {
if ((prev_pes_stream_id_ & kPesStreamIdVideoMask) == kPesStreamIdVideo) {
// Set data on the video stream from the NalUnitStream.
std::vector<uint8_t> nal_unit_stream;
@ -826,6 +831,7 @@ bool WvmMediaParser::Output() {
}
}
}
}
if (!is_initialized_) {
bool is_extra_data_in_stream_infos = true;

View File

@ -164,9 +164,9 @@ class WvmMediaParser : public MediaParser {
// Index denotes 'search index' in the WVM content.
bool ParseIndexEntry();
bool DemuxNextPes(uint8_t* start, bool is_program_end);
bool DemuxNextPes(bool is_program_end);
void StartMediaSampleDemux(uint8_t* start);
void StartMediaSampleDemux();
template <typename T>
Tag GetTag(const uint8_t& tag,
@ -195,7 +195,9 @@ class WvmMediaParser : public MediaParser {
return Tag(tag);
}
bool Output();
// |must_process_encrypted| setting determines if Output() should attempt
// to ouput media sample as encrypted.
bool Output(bool must_process_encrypted);
bool GetAssetKey(const uint32_t asset_id, EncryptionKey* encryption_key);

View File

@ -28,6 +28,7 @@ const char kWvmFile[] = "hb2_4stream_encrypted.wvm";
const uint32_t kExpectedStreams = 4;
const int kExpectedVideoFrameCount = 6665;
const int kExpectedAudioFrameCount = 11964;
const int kExpectedEncryptedSampleCount = 17287;
const uint8_t kExpectedAssetKey[] =
"\x06\x81\x7f\x48\x6b\xf2\x7f\x3e\xc7\x39\xa8\x3f\x12\x0a\xd2\xfc";
const uint8_t k64ByteAssetKey[] =
@ -66,6 +67,7 @@ class WvmMediaParserTest : public testing::Test {
WvmMediaParserTest()
: audio_frame_count_(0),
video_frame_count_(0),
encrypted_sample_count_(0),
video_max_dts_(kNoTimestamp),
current_track_id_(-1) {
parser_.reset(new WvmMediaParser());
@ -82,6 +84,7 @@ class WvmMediaParserTest : public testing::Test {
StreamMap stream_map_;
int audio_frame_count_;
int video_frame_count_;
int encrypted_sample_count_;
int64_t video_max_dts_;
uint32_t current_track_id_;
EncryptionKey encryption_key_;
@ -128,6 +131,9 @@ class WvmMediaParserTest : public testing::Test {
}
}
if (sample->is_encrypted()) {
++encrypted_sample_count_;
}
return true;
}
@ -149,12 +155,14 @@ class WvmMediaParserTest : public testing::Test {
};
TEST_F(WvmMediaParserTest, ParseWvmWithoutKeySource) {
// Parsing should fail but it will get the streams successfully.
key_source_.reset();
InitializeParser();
std::vector<uint8_t> buffer = ReadTestDataFile(kWvmFile);
EXPECT_FALSE(parser_->Parse(buffer.data(), buffer.size()));
EXPECT_TRUE(parser_->Parse(buffer.data(), buffer.size()));
EXPECT_EQ(kExpectedStreams, stream_map_.size());
EXPECT_EQ(kExpectedVideoFrameCount, video_frame_count_);
EXPECT_EQ(kExpectedAudioFrameCount, audio_frame_count_);
EXPECT_EQ(kExpectedEncryptedSampleCount, encrypted_sample_count_);
}
TEST_F(WvmMediaParserTest, ParseWvmInitWithoutKeySource) {
@ -173,6 +181,7 @@ TEST_F(WvmMediaParserTest, ParseWvm) {
EXPECT_EQ(kExpectedStreams, stream_map_.size());
EXPECT_EQ(kExpectedVideoFrameCount, video_frame_count_);
EXPECT_EQ(kExpectedAudioFrameCount, audio_frame_count_);
EXPECT_EQ(0, encrypted_sample_count_);
}
TEST_F(WvmMediaParserTest, ParseWvmWith64ByteAssetKey) {