7 #include "packager/media/crypto/encryption_handler.h"
14 #include "packager/media/base/aes_encryptor.h"
15 #include "packager/media/base/aes_pattern_cryptor.h"
16 #include "packager/media/base/key_source.h"
17 #include "packager/media/base/media_sample.h"
18 #include "packager/media/base/video_stream_info.h"
19 #include "packager/media/codecs/video_slice_header_parser.h"
20 #include "packager/media/codecs/vp8_parser.h"
21 #include "packager/media/codecs/vp9_parser.h"
27 const size_t kCencBlockSize = 16u;
31 void AddSubsample(uint64_t clear_bytes,
32 uint64_t cipher_bytes,
33 DecryptConfig* decrypt_config) {
34 CHECK_LT(cipher_bytes, std::numeric_limits<uint32_t>::max());
35 const uint64_t kUInt16Max = std::numeric_limits<uint16_t>::max();
36 while (clear_bytes > kUInt16Max) {
37 decrypt_config->AddSubsample(kUInt16Max, 0);
38 clear_bytes -= kUInt16Max;
41 if (clear_bytes > 0 || cipher_bytes > 0)
42 decrypt_config->AddSubsample(clear_bytes, cipher_bytes);
45 Codec GetVideoCodec(
const StreamInfo& stream_info) {
46 if (stream_info.stream_type() != kStreamVideo)
return kUnknownCodec;
47 const VideoStreamInfo& video_stream_info =
48 static_cast<const VideoStreamInfo&
>(stream_info);
49 return video_stream_info.codec();
52 uint8_t GetNaluLengthSize(
const StreamInfo& stream_info) {
53 if (stream_info.stream_type() != kStreamVideo)
56 const VideoStreamInfo& video_stream_info =
57 static_cast<const VideoStreamInfo&
>(stream_info);
58 return video_stream_info.nalu_length_size();
61 KeySource::TrackType GetTrackTypeForEncryption(
const StreamInfo& stream_info,
62 uint32_t max_sd_pixels,
63 uint32_t max_hd_pixels,
64 uint32_t max_uhd1_pixels) {
65 if (stream_info.stream_type() == kStreamAudio)
66 return KeySource::TRACK_TYPE_AUDIO;
68 if (stream_info.stream_type() != kStreamVideo)
69 return KeySource::TRACK_TYPE_UNKNOWN;
71 DCHECK_EQ(kStreamVideo, stream_info.stream_type());
72 const VideoStreamInfo& video_stream_info =
73 static_cast<const VideoStreamInfo&
>(stream_info);
74 uint32_t pixels = video_stream_info.width() * video_stream_info.height();
75 if (pixels <= max_sd_pixels) {
76 return KeySource::TRACK_TYPE_SD;
77 }
else if (pixels <= max_hd_pixels) {
78 return KeySource::TRACK_TYPE_HD;
79 }
else if (pixels <= max_uhd1_pixels) {
80 return KeySource::TRACK_TYPE_UHD1;
82 return KeySource::TRACK_TYPE_UHD2;
86 EncryptionHandler::EncryptionHandler(
87 const EncryptionOptions& encryption_options,
88 KeySource* key_source)
89 : encryption_options_(encryption_options), key_source_(key_source) {}
91 EncryptionHandler::~EncryptionHandler() {}
94 if (num_input_streams() != 1 || next_output_stream_index() != 1) {
95 return Status(error::INVALID_ARGUMENT,
96 "Expects exactly one input and output.");
103 switch (stream_data->stream_data_type) {
104 case StreamDataType::kStreamInfo:
105 status = ProcessStreamInfo(stream_data->stream_info.get());
107 case StreamDataType::kSegmentInfo:
108 if (!stream_data->segment_info->is_subsegment) {
110 if (remaining_clear_lead_ > 0)
111 remaining_clear_lead_ -= stream_data->segment_info->duration;
113 stream_data->segment_info->is_encrypted =
true;
116 case StreamDataType::kMediaSample:
117 status = ProcessMediaSample(stream_data->media_sample.get());
120 VLOG(3) <<
"Stream data type "
121 <<
static_cast<int>(stream_data->stream_data_type) <<
" ignored.";
124 return status.ok() ?
Dispatch(std::move(stream_data)) : status;
128 if (stream_info->is_encrypted()) {
129 return Status(error::INVALID_ARGUMENT,
130 "Input stream is already encrypted.");
133 remaining_clear_lead_ =
135 crypto_period_duration_ =
137 stream_info->time_scale();
138 nalu_length_size_ = GetNaluLengthSize(*stream_info);
139 video_codec_ = GetVideoCodec(*stream_info);
140 track_type_ = GetTrackTypeForEncryption(
143 switch (video_codec_) {
145 vpx_parser_.reset(
new VP8Parser);
148 vpx_parser_.reset(
new VP9Parser);
151 header_parser_.reset(
new H264VideoSliceHeaderParser);
154 FALLTHROUGH_INTENDED;
156 header_parser_.reset(
new H265VideoSliceHeaderParser);
160 if (nalu_length_size_ > 0) {
161 LOG(WARNING) <<
"Unknown video codec '" << video_codec_ <<
"'";
162 return Status(error::ENCRYPTION_FAILURE,
"Unknown video codec.");
165 if (header_parser_ &&
166 !header_parser_->Initialize(stream_info->codec_config())) {
167 return Status(error::ENCRYPTION_FAILURE,
"Fail to read SPS and PPS data.");
173 if (stream_info->stream_type() == kStreamVideo) {
175 crypt_byte_block_ = 1u;
176 skip_byte_block_ = 9u;
186 crypt_byte_block_ = 1u;
187 skip_byte_block_ = 0u;
191 crypt_byte_block_ = 0u;
192 skip_byte_block_ = 0u;
195 stream_info->set_is_encrypted(
true);
199 Status EncryptionHandler::ProcessMediaSample(MediaSample* sample) {
203 std::vector<VPxFrameInfo> vpx_frames;
205 !vpx_parser_->Parse(sample->data(), sample->data_size(), &vpx_frames)) {
206 return Status(error::ENCRYPTION_FAILURE,
"Failed to parse vpx frame.");
208 if (remaining_clear_lead_ > 0)
213 EncryptionKey encryption_key;
214 bool create_encryptor =
false;
215 if (crypto_period_duration_ != 0) {
216 const int64_t current_crypto_period_index =
217 sample->dts() / crypto_period_duration_;
218 if (current_crypto_period_index != prev_crypto_period_index_) {
220 track_type_, &encryption_key);
223 create_encryptor =
true;
225 }
else if (!encryptor_) {
226 status = key_source_->
GetKey(track_type_, &encryption_key);
229 create_encryptor =
true;
231 if (create_encryptor && !CreateEncryptor(&encryption_key))
232 return Status(error::ENCRYPTION_FAILURE,
"Failed to create encryptor");
233 new_segment_ =
false;
236 std::unique_ptr<DecryptConfig> decrypt_config(
new DecryptConfig(
237 key_id_, encryptor_->iv(), std::vector<SubsampleEntry>(),
241 if (!EncryptVpxFrame(vpx_frames, sample, decrypt_config.get()))
242 return Status(error::ENCRYPTION_FAILURE,
"Failed to encrypt VPx frames.");
243 DCHECK_EQ(decrypt_config->GetTotalSizeOfSubsamples(), sample->data_size());
244 }
else if (nalu_length_size_ > 0) {
245 if (!EncryptNalFrame(sample, decrypt_config.get())) {
246 return Status(error::ENCRYPTION_FAILURE,
247 "Failed to encrypt video frames.");
249 DCHECK_EQ(decrypt_config->GetTotalSizeOfSubsamples(), sample->data_size());
251 DCHECK_LE(crypt_byte_block_, 1u);
252 DCHECK_EQ(skip_byte_block_, 0u);
253 EncryptBytes(sample->writable_data(), sample->data_size());
255 sample->set_decrypt_config(std::move(decrypt_config));
256 encryptor_->UpdateIv();
260 bool EncryptionHandler::CreateEncryptor(EncryptionKey* encryption_key) {
261 std::unique_ptr<AesCryptor> encryptor;
264 encryptor.reset(
new AesCtrEncryptor);
267 encryptor.reset(
new AesCbcEncryptor(kNoPadding));
270 encryptor.reset(
new AesPatternCryptor(
271 crypt_byte_block_, skip_byte_block_,
273 AesCryptor::kDontUseConstantIv,
274 std::unique_ptr<AesCryptor>(
new AesCtrEncryptor())));
277 encryptor.reset(
new AesPatternCryptor(
278 crypt_byte_block_, skip_byte_block_,
280 AesCryptor::kUseConstantIv,
281 std::unique_ptr<AesCryptor>(
new AesCbcEncryptor(kNoPadding))));
284 LOG(ERROR) <<
"Unsupported protection scheme.";
288 if (encryption_key->iv.empty()) {
290 &encryption_key->iv)) {
291 LOG(ERROR) <<
"Failed to generate random iv.";
295 const bool initialized =
296 encryptor->InitializeWithIv(encryption_key->key, encryption_key->iv);
297 encryptor_ = std::move(encryptor);
298 key_id_ = encryption_key->key_id;
302 bool EncryptionHandler::EncryptVpxFrame(
const std::vector<VPxFrameInfo>& vpx_frames,
304 DecryptConfig* decrypt_config) {
305 uint8_t* data = sample->writable_data();
306 const bool is_superframe = vpx_frames.size() > 1;
307 for (
const VPxFrameInfo& frame : vpx_frames) {
308 uint16_t clear_bytes =
309 static_cast<uint16_t
>(frame.uncompressed_header_size);
310 uint32_t cipher_bytes =
static_cast<uint32_t
>(
311 frame.frame_size - frame.uncompressed_header_size);
322 const uint16_t misalign_bytes = cipher_bytes % kCencBlockSize;
323 clear_bytes += misalign_bytes;
324 cipher_bytes -= misalign_bytes;
327 decrypt_config->AddSubsample(clear_bytes, cipher_bytes);
328 if (cipher_bytes > 0)
329 EncryptBytes(data + clear_bytes, cipher_bytes);
330 data += frame.frame_size;
334 size_t index_size = sample->data() + sample->data_size() - data;
335 DCHECK_LE(index_size, 2 + vpx_frames.size() * 4);
336 DCHECK_GE(index_size, 2 + vpx_frames.size() * 1);
337 uint16_t clear_bytes =
static_cast<uint16_t
>(index_size);
338 uint32_t cipher_bytes = 0;
339 decrypt_config->AddSubsample(clear_bytes, cipher_bytes);
344 bool EncryptionHandler::EncryptNalFrame(MediaSample* sample,
345 DecryptConfig* decrypt_config) {
346 const Nalu::CodecType nalu_type =
347 (video_codec_ == kCodecHVC1 || video_codec_ == kCodecHEV1) ? Nalu::kH265
349 NaluReader reader(nalu_type, nalu_length_size_, sample->writable_data(),
350 sample->data_size());
354 uint64_t accumulated_clear_bytes = 0;
357 NaluReader::Result result;
358 while ((result = reader.Advance(&nalu)) == NaluReader::kOk) {
359 if (nalu.is_video_slice()) {
363 const int64_t video_slice_header_size =
364 header_parser_ ? header_parser_->GetHeaderSize(nalu) : 0;
365 if (video_slice_header_size < 0) {
366 LOG(ERROR) <<
"Failed to read slice header.";
370 uint64_t current_clear_bytes =
371 nalu.header_size() + video_slice_header_size;
372 uint64_t cipher_bytes = nalu.payload_size() - video_slice_header_size;
379 const uint16_t misalign_bytes = cipher_bytes % kCencBlockSize;
380 current_clear_bytes += misalign_bytes;
381 cipher_bytes -= misalign_bytes;
384 const uint8_t* nalu_data = nalu.data() + current_clear_bytes;
385 EncryptBytes(const_cast<uint8_t*>(nalu_data), cipher_bytes);
388 accumulated_clear_bytes + nalu_length_size_ + current_clear_bytes,
389 cipher_bytes, decrypt_config);
390 accumulated_clear_bytes = 0;
393 accumulated_clear_bytes +=
394 nalu_length_size_ + nalu.header_size() + nalu.payload_size();
397 if (result != NaluReader::kEOStream) {
398 LOG(ERROR) <<
"Failed to parse NAL units.";
401 AddSubsample(accumulated_clear_bytes, 0, decrypt_config);
405 void EncryptionHandler::EncryptBytes(uint8_t* data,
size_t size) {
407 CHECK(encryptor_->Crypt(data, size, data));
410 void EncryptionHandler::InjectVpxParserForTesting(
411 std::unique_ptr<VPxParser> vpx_parser) {
412 vpx_parser_ = std::move(vpx_parser);
415 void EncryptionHandler::InjectVideoSliceHeaderParserForTesting(
416 std::unique_ptr<VideoSliceHeaderParser> header_parser) {
417 header_parser_ = std::move(header_parser);