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 {
26 const size_t kDefaultIvSizeForCtr = 8u;
27 const size_t kDefaultIvSizeForCbc = 16u;
28 const size_t kCencBlockSize = 16u;
32 void AddSubsamples(uint64_t clear_bytes,
33 uint64_t cipher_bytes,
34 std::vector<SubsampleEntry>* subsamples) {
35 CHECK_LT(cipher_bytes, std::numeric_limits<uint32_t>::max());
36 const uint64_t kUInt16Max = std::numeric_limits<uint16_t>::max();
37 while (clear_bytes > kUInt16Max) {
38 subsamples->push_back(SubsampleEntry(kUInt16Max, 0));
39 clear_bytes -= kUInt16Max;
42 if (clear_bytes > 0 || cipher_bytes > 0)
43 subsamples->push_back(SubsampleEntry(clear_bytes, cipher_bytes));
46 VideoCodec GetVideoCodec(
const StreamInfo& stream_info) {
47 if (stream_info.stream_type() != kStreamVideo)
48 return kUnknownVideoCodec;
49 const VideoStreamInfo& video_stream_info =
50 static_cast<const VideoStreamInfo&
>(stream_info);
51 return video_stream_info.codec();
54 uint8_t GetNaluLengthSize(
const StreamInfo& stream_info) {
55 if (stream_info.stream_type() != kStreamVideo)
58 const VideoStreamInfo& video_stream_info =
59 static_cast<const VideoStreamInfo&
>(stream_info);
60 return video_stream_info.nalu_length_size();
65 scoped_refptr<StreamInfo> info,
67 scoped_ptr<EncryptionKey> encryption_key,
69 EncryptionMode encryption_mode)
72 encryption_key_(encryption_key.Pass()),
73 nalu_length_size_(GetNaluLengthSize(*info)),
74 video_codec_(GetVideoCodec(*info)),
75 clear_time_(clear_time),
76 encryption_mode_(encryption_mode) {
77 DCHECK(encryption_key_);
78 if (video_codec_ == kCodecVP8) {
80 }
else if (video_codec_ == kCodecVP9) {
82 }
else if (video_codec_ == kCodecH264) {
84 }
else if (video_codec_ == kCodecHVC1 || video_codec_ == kCodecHEV1) {
86 }
else if (nalu_length_size_ > 0) {
87 LOG(WARNING) <<
"Unknown video codec '" << video_codec_
88 <<
"', whole subsamples will be encrypted.";
92 EncryptingFragmenter::~EncryptingFragmenter() {}
96 if (!fragment_initialized()) {
102 Status status = EncryptSample(sample);
114 if (header_parser_ && !header_parser_->Initialize(info_->extra_data()))
115 return Status(error::MUXER_FAILURE,
"Fail to read SPS and PPS data.");
117 traf()->auxiliary_size.sample_info_sizes.clear();
118 traf()->auxiliary_offset.offsets.clear();
119 if (IsSubsampleEncryptionRequired()) {
120 traf()->sample_encryption.flags |=
121 SampleEncryption::kUseSubsampleEncryption;
123 traf()->sample_encryption.sample_encryption_entries.clear();
125 const bool enable_encryption = clear_time_ <= 0;
126 if (!enable_encryption) {
130 const uint32_t kClearSampleDescriptionIndex = 2;
132 traf()->header.flags |=
133 TrackFragmentHeader::kSampleDescriptionIndexPresentMask;
134 traf()->header.sample_description_index = kClearSampleDescriptionIndex;
141 DCHECK_LE(clear_time_, 0);
144 DCHECK_GT(clear_time_, 0);
145 clear_time_ -= fragment_duration();
151 bool enable_encryption) {
152 return (!enable_encryption || encryptor_) ? Status::OK :
CreateEncryptor();
157 traf()->auxiliary_offset.offsets.push_back(0);
161 saiz.sample_count = traf()->runs[0].sample_sizes.size();
162 if (!saiz.sample_info_sizes.empty()) {
164 &saiz.default_sample_info_size)) {
165 saiz.default_sample_info_size = 0;
170 DCHECK(!IsSubsampleEncryptionRequired());
171 saiz.default_sample_info_size = encryptor_->iv().size();
173 traf()->sample_encryption.iv_size = encryptor_->iv().size();
177 DCHECK(encryption_key_);
178 scoped_ptr<AesEncryptor> encryptor;
179 size_t default_iv_size = 0;
180 if (encryption_mode_ == kEncryptionModeAesCtr) {
182 default_iv_size = kDefaultIvSizeForCtr;
183 }
else if (encryption_mode_ == kEncryptionModeAesCbc) {
185 default_iv_size = kDefaultIvSizeForCbc;
187 return Status(error::MUXER_FAILURE,
"Unsupported encryption mode.");
189 const bool initialized = encryption_key_->iv.empty()
190 ? encryptor->InitializeWithRandomIv(
191 encryption_key_->key, default_iv_size)
192 : encryptor->InitializeWithIv(
193 encryption_key_->key, encryption_key_->iv);
195 return Status(error::MUXER_FAILURE,
"Failed to create the encryptor.");
196 encryptor_ = encryptor.Pass();
200 void EncryptingFragmenter::EncryptBytes(uint8_t* data, uint32_t size) {
202 CHECK(encryptor_->Encrypt(data, size, data));
205 Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {
208 SampleEncryptionEntry sample_encryption_entry;
209 sample_encryption_entry.initialization_vector = encryptor_->iv();
210 uint8_t* data = sample->writable_data();
211 if (IsSubsampleEncryptionRequired()) {
213 std::vector<VPxFrameInfo> vpx_frames;
214 if (!vpx_parser_->Parse(sample->data(), sample->data_size(),
216 return Status(error::MUXER_FAILURE,
"Failed to parse vpx frame.");
219 const bool is_superframe = vpx_frames.size() > 1;
220 for (
const VPxFrameInfo& frame : vpx_frames) {
221 SubsampleEntry subsample;
222 subsample.clear_bytes = frame.uncompressed_header_size;
223 subsample.cipher_bytes =
224 frame.frame_size - frame.uncompressed_header_size;
232 if (is_superframe || encryption_mode_ == kEncryptionModeAesCbc) {
233 const uint16_t misalign_bytes =
234 subsample.cipher_bytes % kCencBlockSize;
235 subsample.clear_bytes += misalign_bytes;
236 subsample.cipher_bytes -= misalign_bytes;
239 sample_encryption_entry.subsamples.push_back(subsample);
240 if (subsample.cipher_bytes > 0)
241 EncryptBytes(data + subsample.clear_bytes, subsample.cipher_bytes);
242 data += frame.frame_size;
245 const NaluReader::NaluType nalu_type =
246 (video_codec_ == kCodecHVC1 || video_codec_ == kCodecHEV1)
249 NaluReader reader(nalu_type, nalu_length_size_, data,
250 sample->data_size());
254 uint64_t accumulated_clear_bytes = 0;
257 NaluReader::Result result;
258 while ((result = reader.Advance(&nalu)) == NaluReader::kOk) {
259 if (nalu.is_video_slice()) {
263 const int64_t video_slice_header_size =
264 header_parser_ ? header_parser_->GetHeaderSize(nalu) : 0;
265 if (video_slice_header_size < 0)
266 return Status(error::MUXER_FAILURE,
"Failed to read slice header.");
268 uint64_t current_clear_bytes =
269 nalu.header_size() + video_slice_header_size;
270 uint64_t cipher_bytes = nalu.payload_size() - video_slice_header_size;
274 if (encryption_mode_ == kEncryptionModeAesCbc) {
275 const uint16_t misalign_bytes = cipher_bytes % kCencBlockSize;
276 current_clear_bytes += misalign_bytes;
277 cipher_bytes -= misalign_bytes;
280 const uint8_t* nalu_data = nalu.data() + current_clear_bytes;
281 EncryptBytes(const_cast<uint8_t*>(nalu_data), cipher_bytes);
284 accumulated_clear_bytes + nalu_length_size_ + current_clear_bytes,
285 cipher_bytes, &sample_encryption_entry.subsamples);
286 accumulated_clear_bytes = 0;
289 accumulated_clear_bytes +=
290 nalu_length_size_ + nalu.header_size() + nalu.payload_size();
293 if (result != NaluReader::kEOStream)
294 return Status(error::MUXER_FAILURE,
"Failed to parse NAL units.");
295 AddSubsamples(accumulated_clear_bytes, 0,
296 &sample_encryption_entry.subsamples);
300 traf()->auxiliary_size.sample_info_sizes.push_back(
301 sample_encryption_entry.ComputeSize());
303 uint64_t encryption_data_size = sample->data_size();
306 if (encryption_mode_ == kEncryptionModeAesCbc)
307 encryption_data_size -= encryption_data_size % kCencBlockSize;
308 EncryptBytes(data, encryption_data_size);
311 traf()->sample_encryption.sample_encryption_entries.push_back(
312 sample_encryption_entry);
313 encryptor_->UpdateIv();
317 bool EncryptingFragmenter::IsSubsampleEncryptionRequired() {
318 return vpx_parser_ || nalu_length_size_ != 0;