7 #include "packager/media/formats/mp4/encrypting_fragmenter.h"
11 #include "packager/media/base/aes_encryptor.h"
12 #include "packager/media/base/buffer_reader.h"
13 #include "packager/media/base/key_source.h"
14 #include "packager/media/base/media_sample.h"
15 #include "packager/media/filters/nalu_reader.h"
16 #include "packager/media/filters/vp8_parser.h"
17 #include "packager/media/filters/vp9_parser.h"
18 #include "packager/media/formats/mp4/box_definitions.h"
20 namespace edash_packager {
25 const size_t kCencBlockSize = 16u;
29 void AddSubsamples(uint64_t clear_bytes,
30 uint64_t cipher_bytes,
31 std::vector<SubsampleEntry>* subsamples) {
32 CHECK_LT(cipher_bytes, std::numeric_limits<uint32_t>::max());
33 const uint64_t kUInt16Max = std::numeric_limits<uint16_t>::max();
34 while (clear_bytes > kUInt16Max) {
35 subsamples->push_back(SubsampleEntry(kUInt16Max, 0));
36 clear_bytes -= kUInt16Max;
39 if (clear_bytes > 0 || cipher_bytes > 0)
40 subsamples->push_back(SubsampleEntry(clear_bytes, cipher_bytes));
43 VideoCodec GetVideoCodec(
const StreamInfo& stream_info) {
44 if (stream_info.stream_type() != kStreamVideo)
45 return kUnknownVideoCodec;
46 const VideoStreamInfo& video_stream_info =
47 static_cast<const VideoStreamInfo&
>(stream_info);
48 return video_stream_info.codec();
51 uint8_t GetNaluLengthSize(
const StreamInfo& stream_info) {
52 if (stream_info.stream_type() != kStreamVideo)
55 const VideoStreamInfo& video_stream_info =
56 static_cast<const VideoStreamInfo&
>(stream_info);
57 return video_stream_info.nalu_length_size();
62 scoped_refptr<StreamInfo> info,
64 scoped_ptr<EncryptionKey> encryption_key,
66 FourCC protection_scheme)
69 encryption_key_(encryption_key.Pass()),
70 nalu_length_size_(GetNaluLengthSize(*info)),
71 video_codec_(GetVideoCodec(*info)),
72 clear_time_(clear_time),
73 protection_scheme_(protection_scheme) {
74 DCHECK(encryption_key_);
75 if (video_codec_ == kCodecVP8) {
77 }
else if (video_codec_ == kCodecVP9) {
79 }
else if (video_codec_ == kCodecH264) {
81 }
else if (video_codec_ == kCodecHVC1 || video_codec_ == kCodecHEV1) {
83 }
else if (nalu_length_size_ > 0) {
84 LOG(WARNING) <<
"Unknown video codec '" << video_codec_
85 <<
"', whole subsamples will be encrypted.";
89 EncryptingFragmenter::~EncryptingFragmenter() {}
93 if (!fragment_initialized()) {
99 Status status = EncryptSample(sample);
111 if (header_parser_ && !header_parser_->Initialize(info_->extra_data()))
112 return Status(error::MUXER_FAILURE,
"Fail to read SPS and PPS data.");
114 traf()->auxiliary_size.sample_info_sizes.clear();
115 traf()->auxiliary_offset.offsets.clear();
116 if (IsSubsampleEncryptionRequired()) {
117 traf()->sample_encryption.flags |=
118 SampleEncryption::kUseSubsampleEncryption;
120 traf()->sample_encryption.sample_encryption_entries.clear();
122 const bool enable_encryption = clear_time_ <= 0;
123 if (!enable_encryption) {
127 const uint32_t kClearSampleDescriptionIndex = 2;
129 traf()->header.flags |=
130 TrackFragmentHeader::kSampleDescriptionIndexPresentMask;
131 traf()->header.sample_description_index = kClearSampleDescriptionIndex;
138 DCHECK_LE(clear_time_, 0);
141 DCHECK_GT(clear_time_, 0);
142 clear_time_ -= fragment_duration();
148 bool enable_encryption) {
149 return (!enable_encryption || encryptor_) ? Status::OK :
CreateEncryptor();
154 traf()->auxiliary_offset.offsets.push_back(0);
158 saiz.sample_count = traf()->runs[0].sample_sizes.size();
159 if (!saiz.sample_info_sizes.empty()) {
161 &saiz.default_sample_info_size)) {
162 saiz.default_sample_info_size = 0;
167 DCHECK(!IsSubsampleEncryptionRequired());
168 saiz.default_sample_info_size = encryptor_->iv().size();
170 traf()->sample_encryption.iv_size = encryptor_->iv().size();
174 DCHECK(encryption_key_);
175 scoped_ptr<AesCryptor> encryptor;
176 switch (protection_scheme_) {
184 return Status(error::MUXER_FAILURE,
"Unsupported protection scheme.");
187 DCHECK(!encryption_key_->iv.empty());
188 const bool initialized =
189 encryptor->InitializeWithIv(encryption_key_->key, encryption_key_->iv);
191 return Status(error::MUXER_FAILURE,
"Failed to create the encryptor.");
192 encryptor_ = encryptor.Pass();
196 void EncryptingFragmenter::EncryptBytes(uint8_t* data, uint32_t size) {
198 CHECK(encryptor_->Crypt(data, size, data));
201 Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {
204 SampleEncryptionEntry sample_encryption_entry;
205 sample_encryption_entry.initialization_vector = encryptor_->iv();
206 uint8_t* data = sample->writable_data();
207 if (IsSubsampleEncryptionRequired()) {
209 std::vector<VPxFrameInfo> vpx_frames;
210 if (!vpx_parser_->Parse(sample->data(), sample->data_size(),
212 return Status(error::MUXER_FAILURE,
"Failed to parse vpx frame.");
215 const bool is_superframe = vpx_frames.size() > 1;
216 for (
const VPxFrameInfo& frame : vpx_frames) {
217 SubsampleEntry subsample;
218 subsample.clear_bytes = frame.uncompressed_header_size;
219 subsample.cipher_bytes =
220 frame.frame_size - frame.uncompressed_header_size;
228 if (is_superframe || protection_scheme_ == FOURCC_cbc1) {
229 const uint16_t misalign_bytes =
230 subsample.cipher_bytes % kCencBlockSize;
231 subsample.clear_bytes += misalign_bytes;
232 subsample.cipher_bytes -= misalign_bytes;
235 sample_encryption_entry.subsamples.push_back(subsample);
236 if (subsample.cipher_bytes > 0)
237 EncryptBytes(data + subsample.clear_bytes, subsample.cipher_bytes);
238 data += frame.frame_size;
241 const NaluReader::NaluType nalu_type =
242 (video_codec_ == kCodecHVC1 || video_codec_ == kCodecHEV1)
245 NaluReader reader(nalu_type, nalu_length_size_, data,
246 sample->data_size());
250 uint64_t accumulated_clear_bytes = 0;
253 NaluReader::Result result;
254 while ((result = reader.Advance(&nalu)) == NaluReader::kOk) {
255 if (nalu.is_video_slice()) {
259 const int64_t video_slice_header_size =
260 header_parser_ ? header_parser_->GetHeaderSize(nalu) : 0;
261 if (video_slice_header_size < 0)
262 return Status(error::MUXER_FAILURE,
"Failed to read slice header.");
264 uint64_t current_clear_bytes =
265 nalu.header_size() + video_slice_header_size;
266 uint64_t cipher_bytes = nalu.payload_size() - video_slice_header_size;
270 if (protection_scheme_ == FOURCC_cbc1) {
271 const uint16_t misalign_bytes = cipher_bytes % kCencBlockSize;
272 current_clear_bytes += misalign_bytes;
273 cipher_bytes -= misalign_bytes;
276 const uint8_t* nalu_data = nalu.data() + current_clear_bytes;
277 EncryptBytes(const_cast<uint8_t*>(nalu_data), cipher_bytes);
280 accumulated_clear_bytes + nalu_length_size_ + current_clear_bytes,
281 cipher_bytes, &sample_encryption_entry.subsamples);
282 accumulated_clear_bytes = 0;
285 accumulated_clear_bytes +=
286 nalu_length_size_ + nalu.header_size() + nalu.payload_size();
289 if (result != NaluReader::kEOStream)
290 return Status(error::MUXER_FAILURE,
"Failed to parse NAL units.");
291 AddSubsamples(accumulated_clear_bytes, 0,
292 &sample_encryption_entry.subsamples);
296 traf()->auxiliary_size.sample_info_sizes.push_back(
297 sample_encryption_entry.ComputeSize());
299 uint64_t encryption_data_size = sample->data_size();
302 if (protection_scheme_ == FOURCC_cbc1)
303 encryption_data_size -= encryption_data_size % kCencBlockSize;
304 EncryptBytes(data, encryption_data_size);
307 traf()->sample_encryption.sample_encryption_entries.push_back(
308 sample_encryption_entry);
309 encryptor_->UpdateIv();
313 bool EncryptingFragmenter::IsSubsampleEncryptionRequired() {
314 return vpx_parser_ || nalu_length_size_ != 0;