Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(565)

Unified Diff: media/mp4/mp4_stream_parser.cc

Issue 10651006: Add Common Encryption support to BMFF, including subsample decryption. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Remove references to non-public encrypted files in tests Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/mp4/mp4_stream_parser.cc
diff --git a/media/mp4/mp4_stream_parser.cc b/media/mp4/mp4_stream_parser.cc
index 4f4a6db12818e03483bb2cfd59f884b4d94714b2..f955ec6b3dd5474e2ec069f38a7d62910af292b9 100644
--- a/media/mp4/mp4_stream_parser.cc
+++ b/media/mp4/mp4_stream_parser.cc
@@ -100,13 +100,14 @@ bool MP4StreamParser::Parse(const uint8* buf, int size) {
return false;
}
- if (!audio_buffers.empty() &&
- (audio_cb_.is_null() || !audio_cb_.Run(audio_buffers)))
- return false;
- if (!video_buffers.empty() &&
- (video_cb_.is_null() || !video_cb_.Run(video_buffers)))
- return false;
-
+ if (!audio_buffers.empty()) {
+ CHECK(!audio_cb_.is_null());
+ RCHECK(audio_cb_.Run(audio_buffers));
+ }
+ if (!video_buffers.empty()) {
+ CHECK(!video_cb_.is_null());
+ RCHECK(video_cb_.Run(video_buffers));
+ }
return true;
}
@@ -166,6 +167,7 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) {
// RCHECK(entry.format == FOURCC_MP4A ||
// (entry.format == FOURCC_ENCA &&
// entry.sinf.format.format == FOURCC_MP4A));
+ RCHECK(EmitKeyNeeded(entry.sinf.info.track_encryption));
const ChannelLayout layout =
AVC::ConvertAACChannelCountToChannelLayout(entry.channelcount);
@@ -181,6 +183,7 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) {
// RCHECK(entry.format == FOURCC_AVC1 ||
// (entry.format == FOURCC_ENCV &&
// entry.sinf.format.format == FOURCC_AVC1));
+ RCHECK(EmitKeyNeeded(entry.sinf.info.track_encryption));
// TODO(strobe): Recover correct crop box and pixel aspect ratio
video_config.Initialize(kCodecH264, H264PROFILE_MAIN, VideoFrame::YV12,
@@ -227,6 +230,14 @@ bool MP4StreamParser::ParseMoof(BoxReader* reader) {
return true;
}
+bool MP4StreamParser::EmitKeyNeeded(const TrackEncryption& track_encryption) {
+ if (!track_encryption.is_encrypted) return true;
+ scoped_array<uint8> kid(new uint8[track_encryption.default_kid.size()]);
+ memcpy(kid.get(), &track_encryption.default_kid[0],
+ track_encryption.default_kid.size());
+ return need_key_cb_.Run(kid.Pass(), track_encryption.default_kid.size());
ddorwin 2012/06/26 23:16:20 For ISO, the initData is supposed to be the PSSH.
strobe_ 2012/06/27 02:01:21 Oh, duh, that makes a lot more sense! Where's that
ddorwin 2012/07/03 21:03:46 This is based on discussions with others, though t
strobe_ 2012/07/13 00:47:07 OK, comment added.
+}
+
bool MP4StreamParser::EnqueueSample(BufferQueue* audio_buffers,
BufferQueue* video_buffers,
bool* err) {
@@ -260,18 +271,41 @@ bool MP4StreamParser::EnqueueSample(BufferQueue* audio_buffers,
// quite small compared to sample data, so this pattern is useful on
// memory-constrained devices where the source buffer consumes a substantial
// portion of the total system memory.
- if (runs_.NeedsCENC()) {
- queue_.PeekAt(runs_.cenc_offset() + moof_head_, &buf, &size);
- return runs_.CacheCENC(buf, size);
+ if (runs_.AuxInfoRequired()) {
+ queue_.PeekAt(runs_.aux_info_offset() + moof_head_, &buf, &size);
+ if (size < runs_.aux_info_size()) return false;
+ *err = !runs_.CacheAuxInfo(buf, size);
+ return !*err;
}
queue_.PeekAt(runs_.offset() + moof_head_, &buf, &size);
if (size < runs_.size()) return false;
+ scoped_ptr<DecryptConfig> decrypt_config;
+ if (runs_.is_encrypted())
+ decrypt_config = runs_.GetDecryptConfig();
+
std::vector<uint8> frame_buf(buf, buf + runs_.size());
if (video) {
+ // TODO(strobe): move all this to separate method, add unittest
RCHECK(AVC::ConvertToAnnexB(size_of_nalu_length_, &frame_buf));
+
+ if (decrypt_config.get()) {
+ const int nalu_size_diff = 4 - size_of_nalu_length_;
+ size_t expected_size = runs_.size() +
ddorwin 2012/06/26 06:09:19 expected size of what? what is runs_.size()? It se
strobe_ 2012/06/27 02:01:21 size() is the size of the current sample; IV and s
+ decrypt_config->subsample_count() * nalu_size_diff;
+ RCHECK(frame_buf.size() == expected_size);
+ for (int i = 0; i < decrypt_config->subsample_count(); i++)
+ decrypt_config->mutable_subsamples()[i].clear_bytes += nalu_size_diff;
ddorwin 2012/06/26 06:09:19 Rather than mutable_subsamples, you could have an
strobe_ 2012/06/27 02:01:21 Two reasons we need to mutate: 1. To convert each
ddorwin 2012/07/03 21:03:46 Since we are just passing the DecryptConfig to som
strobe_ 2012/07/13 00:47:07 Done.
+ }
+
if (!parameter_sets_inserted_) {
+ if (!runs_.is_keyframe()) {
+ LOG(INFO) << "XXX skipping initial non-keyframe sample";
+ runs_.AdvanceSample();
+ return true;
+ }
+
const AVCDecoderConfigurationRecord* avc_config = NULL;
for (size_t t = 0; t < moov_->tracks.size(); t++) {
if (moov_->tracks[t].header.track_id == runs_.track_id()) {
@@ -281,7 +315,14 @@ bool MP4StreamParser::EnqueueSample(BufferQueue* audio_buffers,
}
}
RCHECK(avc_config != NULL);
- RCHECK(AVC::InsertParameterSets(*avc_config, &frame_buf));
+ std::vector<uint8> param_sets;
+ RCHECK(AVC::ConvertParameterSets(*avc_config, &param_sets));
+ frame_buf.insert(frame_buf.begin(),
+ param_sets.begin(), param_sets.end());
+ if (decrypt_config.get()) {
+ decrypt_config->mutable_subsamples()[0].clear_bytes +=
ddorwin 2012/06/26 06:09:19 Hmm, another mutable use. I guess it's not as simp
strobe_ 2012/06/27 02:01:21 see above
+ param_sets.size();
+ }
parameter_sets_inserted_ = true;
}
}
@@ -290,6 +331,9 @@ bool MP4StreamParser::EnqueueSample(BufferQueue* audio_buffers,
StreamParserBuffer::CopyFrom(&frame_buf[0], frame_buf.size(),
runs_.is_keyframe());
+ if (runs_.is_encrypted())
+ stream_buf->SetDecryptConfig(decrypt_config.Pass());
+
stream_buf->SetDuration(runs_.duration());
// We depend on the decoder performing frame reordering without reordering
// timestamps, and only provide the decode timestamp in the buffer.

Powered by Google App Engine
This is Rietveld 408576698