7 #include "packager/media/formats/mp4/encrypting_fragmenter.h"
11 #include "packager/media/base/aes_encryptor.h"
12 #include "packager/media/base/aes_pattern_cryptor.h"
13 #include "packager/media/base/buffer_reader.h"
14 #include "packager/media/base/key_source.h"
15 #include "packager/media/base/media_sample.h"
16 #include "packager/media/codecs/nalu_reader.h"
17 #include "packager/media/codecs/vp8_parser.h"
18 #include "packager/media/codecs/vp9_parser.h"
19 #include "packager/media/formats/mp4/box_definitions.h"
26 const size_t kCencBlockSize = 16u;
30 void AddSubsamples(uint64_t clear_bytes,
31 uint64_t cipher_bytes,
32 std::vector<SubsampleEntry>* subsamples) {
33 CHECK_LT(cipher_bytes, std::numeric_limits<uint32_t>::max());
34 const uint64_t kUInt16Max = std::numeric_limits<uint16_t>::max();
35 while (clear_bytes > kUInt16Max) {
36 subsamples->push_back(SubsampleEntry(kUInt16Max, 0));
37 clear_bytes -= kUInt16Max;
40 if (clear_bytes > 0 || cipher_bytes > 0)
41 subsamples->push_back(SubsampleEntry(clear_bytes, cipher_bytes));
44 Codec GetCodec(
const StreamInfo& stream_info) {
45 if (stream_info.stream_type() != kStreamVideo)
return kUnknownCodec;
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 std::unique_ptr<EncryptionKey> encryption_key,
66 FourCC protection_scheme,
67 uint8_t crypt_byte_block,
68 uint8_t skip_byte_block,
72 encryption_key_(std::move(encryption_key)),
73 nalu_length_size_(GetNaluLengthSize(*info)),
74 video_codec_(GetCodec(*info)),
75 clear_time_(clear_time),
76 protection_scheme_(protection_scheme),
77 crypt_byte_block_(crypt_byte_block),
78 skip_byte_block_(skip_byte_block),
80 DCHECK(encryption_key_);
81 switch (video_codec_) {
97 if (nalu_length_size_ > 0) {
98 LOG(WARNING) <<
"Unknown video codec '" << video_codec_
99 <<
"', whole subsamples will be encrypted.";
104 EncryptingFragmenter::~EncryptingFragmenter() {}
108 if (!fragment_initialized()) {
114 Status status = EncryptSample(sample);
126 if (header_parser_ && !header_parser_->Initialize(info_->codec_config()))
127 return Status(error::MUXER_FAILURE,
"Fail to read SPS and PPS data.");
129 traf()->auxiliary_size.sample_info_sizes.clear();
130 traf()->auxiliary_offset.offsets.clear();
131 if (IsSubsampleEncryptionRequired()) {
132 traf()->sample_encryption.flags |=
133 SampleEncryption::kUseSubsampleEncryption;
135 traf()->sample_encryption.sample_encryption_entries.clear();
137 const bool enable_encryption = clear_time_ <= 0;
138 if (!enable_encryption) {
142 const uint32_t kClearSampleDescriptionIndex = 2;
144 traf()->header.flags |=
145 TrackFragmentHeader::kSampleDescriptionIndexPresentMask;
146 traf()->header.sample_description_index = kClearSampleDescriptionIndex;
156 DCHECK_LE(clear_time_, 0);
159 DCHECK_GT(clear_time_, 0);
160 clear_time_ -= fragment_duration();
166 bool enable_encryption) {
167 return (!enable_encryption || encryptor_) ? Status::OK :
CreateEncryptor();
172 traf()->auxiliary_offset.offsets.push_back(0);
175 const uint8_t per_sample_iv_size =
176 (protection_scheme_ == FOURCC_cbcs) ? 0 :
177 static_cast<uint8_t>(encryptor_->iv().size());
178 traf()->sample_encryption.iv_size = per_sample_iv_size;
183 static_cast<uint32_t
>(traf()->runs[0].sample_sizes.size());
184 if (!saiz.sample_info_sizes.empty()) {
186 &saiz.default_sample_info_size)) {
187 saiz.default_sample_info_size = 0;
192 DCHECK(!IsSubsampleEncryptionRequired());
193 saiz.default_sample_info_size =
static_cast<uint8_t
>(per_sample_iv_size);
198 if (saiz.default_sample_info_size == 0 && saiz.sample_info_sizes.empty()) {
199 DCHECK_EQ(protection_scheme_, FOURCC_cbcs);
200 DCHECK(!IsSubsampleEncryptionRequired());
204 saiz.sample_count = 0;
205 traf()->auxiliary_offset.offsets.clear();
210 DCHECK(encryption_key_);
211 std::unique_ptr<AesCryptor> encryptor;
212 switch (protection_scheme_) {
221 crypt_byte_block(), skip_byte_block(),
223 AesCryptor::kDontUseConstantIv,
228 crypt_byte_block(), skip_byte_block(),
230 AesCryptor::kUseConstantIv,
234 return Status(error::MUXER_FAILURE,
"Unsupported protection scheme.");
237 DCHECK(!encryption_key_->iv.empty());
238 const bool initialized =
239 encryptor->InitializeWithIv(encryption_key_->key, encryption_key_->iv);
241 return Status(error::MUXER_FAILURE,
"Failed to create the encryptor.");
242 encryptor_ = std::move(encryptor);
246 void EncryptingFragmenter::EncryptBytes(uint8_t* data,
size_t size) {
248 CHECK(encryptor_->Crypt(data, size, data));
251 Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {
254 SampleEncryptionEntry sample_encryption_entry;
256 if (protection_scheme_ != FOURCC_cbcs)
257 sample_encryption_entry.initialization_vector = encryptor_->iv();
258 uint8_t* data = sample->writable_data();
259 if (IsSubsampleEncryptionRequired()) {
261 std::vector<VPxFrameInfo> vpx_frames;
262 if (!vpx_parser_->Parse(sample->data(), sample->data_size(),
264 return Status(error::MUXER_FAILURE,
"Failed to parse vpx frame.");
267 const bool is_superframe = vpx_frames.size() > 1;
268 for (
const VPxFrameInfo& frame : vpx_frames) {
269 SubsampleEntry subsample;
270 subsample.clear_bytes =
271 static_cast<uint16_t
>(frame.uncompressed_header_size);
272 subsample.cipher_bytes =
static_cast<uint32_t
>(
273 frame.frame_size - frame.uncompressed_header_size);
282 if (is_superframe || protection_scheme_ == FOURCC_cbc1 ||
283 protection_scheme_ == FOURCC_cens) {
284 const uint16_t misalign_bytes =
285 subsample.cipher_bytes % kCencBlockSize;
286 subsample.clear_bytes += misalign_bytes;
287 subsample.cipher_bytes -= misalign_bytes;
290 sample_encryption_entry.subsamples.push_back(subsample);
291 if (subsample.cipher_bytes > 0)
292 EncryptBytes(data + subsample.clear_bytes, subsample.cipher_bytes);
293 data += frame.frame_size;
297 size_t index_size = sample->data() + sample->data_size() - data;
298 DCHECK_LE(index_size, 2 + vpx_frames.size() * 4);
299 DCHECK_GE(index_size, 2 + vpx_frames.size() * 1);
300 SubsampleEntry subsample;
301 subsample.clear_bytes =
static_cast<uint16_t
>(index_size);
302 subsample.cipher_bytes = 0;
303 sample_encryption_entry.subsamples.push_back(subsample);
306 const Nalu::CodecType nalu_type =
307 (video_codec_ == kCodecHVC1 || video_codec_ == kCodecHEV1)
310 NaluReader reader(nalu_type, nalu_length_size_, data,
311 sample->data_size());
315 uint64_t accumulated_clear_bytes = 0;
318 NaluReader::Result result;
319 while ((result = reader.Advance(&nalu)) == NaluReader::kOk) {
320 if (nalu.is_video_slice()) {
324 const int64_t video_slice_header_size =
325 header_parser_ ? header_parser_->GetHeaderSize(nalu) : 0;
326 if (video_slice_header_size < 0)
327 return Status(error::MUXER_FAILURE,
"Failed to read slice header.");
329 uint64_t current_clear_bytes =
330 nalu.header_size() + video_slice_header_size;
331 uint64_t cipher_bytes = nalu.payload_size() - video_slice_header_size;
336 if (protection_scheme_ == FOURCC_cbc1 ||
337 protection_scheme_ == FOURCC_cens) {
338 const uint16_t misalign_bytes = cipher_bytes % kCencBlockSize;
339 current_clear_bytes += misalign_bytes;
340 cipher_bytes -= misalign_bytes;
343 const uint8_t* nalu_data = nalu.data() + current_clear_bytes;
344 EncryptBytes(const_cast<uint8_t*>(nalu_data), cipher_bytes);
347 accumulated_clear_bytes + nalu_length_size_ + current_clear_bytes,
348 cipher_bytes, &sample_encryption_entry.subsamples);
349 accumulated_clear_bytes = 0;
352 accumulated_clear_bytes +=
353 nalu_length_size_ + nalu.header_size() + nalu.payload_size();
356 if (result != NaluReader::kEOStream)
357 return Status(error::MUXER_FAILURE,
"Failed to parse NAL units.");
358 AddSubsamples(accumulated_clear_bytes, 0,
359 &sample_encryption_entry.subsamples);
361 DCHECK_EQ(sample_encryption_entry.GetTotalSizeOfSubsamples(),
362 sample->data_size());
365 traf()->auxiliary_size.sample_info_sizes.push_back(
366 sample_encryption_entry.ComputeSize());
368 DCHECK_LE(crypt_byte_block(), 1u);
369 DCHECK_EQ(skip_byte_block(), 0u);
370 EncryptBytes(data, sample->data_size());
373 traf()->sample_encryption.sample_encryption_entries.push_back(
374 sample_encryption_entry);
375 encryptor_->UpdateIv();
379 bool EncryptingFragmenter::IsSubsampleEncryptionRequired() {
380 return vpx_parser_ || nalu_length_size_ != 0;