Shaka Packager SDK
encryption_handler.cc
1 // Copyright 2017 Google Inc. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include "packager/media/crypto/encryption_handler.h"
8 
9 #include <stddef.h>
10 #include <stdint.h>
11 
12 #include <algorithm>
13 #include <limits>
14 
15 #include "packager/media/base/aes_encryptor.h"
16 #include "packager/media/base/aes_pattern_cryptor.h"
17 #include "packager/media/base/audio_stream_info.h"
18 #include "packager/media/base/key_source.h"
19 #include "packager/media/base/media_sample.h"
20 #include "packager/media/base/video_stream_info.h"
21 #include "packager/media/codecs/video_slice_header_parser.h"
22 #include "packager/media/codecs/vp8_parser.h"
23 #include "packager/media/codecs/vp9_parser.h"
24 #include "packager/media/crypto/sample_aes_ec3_cryptor.h"
25 
26 namespace shaka {
27 namespace media {
28 
29 namespace {
30 const size_t kCencBlockSize = 16u;
31 
32 // The encryption handler only supports a single output.
33 const size_t kStreamIndex = 0;
34 
35 // The default KID for key rotation is all 0s.
36 const uint8_t kKeyRotationDefaultKeyId[] = {
37  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
38 };
39 
40 // Adds one or more subsamples to |*decrypt_config|. This may add more than one
41 // if one of the values overflows the integer in the subsample.
42 void AddSubsample(uint64_t clear_bytes,
43  uint64_t cipher_bytes,
44  DecryptConfig* decrypt_config) {
45  CHECK_LT(cipher_bytes, std::numeric_limits<uint32_t>::max());
46  const uint64_t kUInt16Max = std::numeric_limits<uint16_t>::max();
47  while (clear_bytes > kUInt16Max) {
48  decrypt_config->AddSubsample(kUInt16Max, 0);
49  clear_bytes -= kUInt16Max;
50  }
51 
52  if (clear_bytes > 0 || cipher_bytes > 0)
53  decrypt_config->AddSubsample(clear_bytes, cipher_bytes);
54 }
55 
56 uint8_t GetNaluLengthSize(const StreamInfo& stream_info) {
57  if (stream_info.stream_type() != kStreamVideo)
58  return 0;
59 
60  const VideoStreamInfo& video_stream_info =
61  static_cast<const VideoStreamInfo&>(stream_info);
62  return video_stream_info.nalu_length_size();
63 }
64 
65 std::string GetStreamLabelForEncryption(
66  const StreamInfo& stream_info,
67  const std::function<std::string(
68  const EncryptionParams::EncryptedStreamAttributes& stream_attributes)>&
69  stream_label_func) {
70  EncryptionParams::EncryptedStreamAttributes stream_attributes;
71  if (stream_info.stream_type() == kStreamAudio) {
72  stream_attributes.stream_type =
73  EncryptionParams::EncryptedStreamAttributes::kAudio;
74  } else if (stream_info.stream_type() == kStreamVideo) {
75  const VideoStreamInfo& video_stream_info =
76  static_cast<const VideoStreamInfo&>(stream_info);
77  stream_attributes.stream_type =
78  EncryptionParams::EncryptedStreamAttributes::kVideo;
79  stream_attributes.oneof.video.width = video_stream_info.width();
80  stream_attributes.oneof.video.height = video_stream_info.height();
81  }
82  return stream_label_func(stream_attributes);
83 }
84 } // namespace
85 
86 EncryptionHandler::EncryptionHandler(const EncryptionParams& encryption_params,
87  KeySource* key_source)
88  : encryption_params_(encryption_params),
89  protection_scheme_(
90  static_cast<FourCC>(encryption_params.protection_scheme)),
91  key_source_(key_source) {}
92 
93 EncryptionHandler::~EncryptionHandler() {}
94 
96  if (!encryption_params_.stream_label_func) {
97  return Status(error::INVALID_ARGUMENT, "Stream label function not set.");
98  }
99  if (num_input_streams() != 1 || next_output_stream_index() != 1) {
100  return Status(error::INVALID_ARGUMENT,
101  "Expects exactly one input and output.");
102  }
103  return Status::OK;
104 }
105 
106 Status EncryptionHandler::Process(std::unique_ptr<StreamData> stream_data) {
107  switch (stream_data->stream_data_type) {
108  case StreamDataType::kStreamInfo:
109  return ProcessStreamInfo(*stream_data->stream_info);
110  case StreamDataType::kSegmentInfo: {
111  std::shared_ptr<SegmentInfo> segment_info(new SegmentInfo(
112  *stream_data->segment_info));
113 
114  segment_info->is_encrypted = remaining_clear_lead_ <= 0;
115 
116  const bool key_rotation_enabled = crypto_period_duration_ != 0;
117  if (key_rotation_enabled)
118  segment_info->key_rotation_encryption_config = encryption_config_;
119  if (!segment_info->is_subsegment) {
120  if (key_rotation_enabled)
121  check_new_crypto_period_ = true;
122  if (remaining_clear_lead_ > 0)
123  remaining_clear_lead_ -= segment_info->duration;
124  }
125 
126  return DispatchSegmentInfo(kStreamIndex, segment_info);
127  }
128  case StreamDataType::kMediaSample:
129  return ProcessMediaSample(std::move(stream_data->media_sample));
130  default:
131  VLOG(3) << "Stream data type "
132  << static_cast<int>(stream_data->stream_data_type) << " ignored.";
133  return Dispatch(std::move(stream_data));
134  }
135 }
136 
137 Status EncryptionHandler::ProcessStreamInfo(const StreamInfo& clear_info) {
138  if (clear_info.is_encrypted()) {
139  return Status(error::INVALID_ARGUMENT,
140  "Input stream is already encrypted.");
141  }
142 
143  DCHECK_NE(kStreamUnknown, clear_info.stream_type());
144  DCHECK_NE(kStreamText, clear_info.stream_type());
145  std::shared_ptr<StreamInfo> stream_info = clear_info.Clone();
146 
147  remaining_clear_lead_ =
148  encryption_params_.clear_lead_in_seconds * stream_info->time_scale();
149  crypto_period_duration_ =
150  encryption_params_.crypto_period_duration_in_seconds *
151  stream_info->time_scale();
152  codec_ = stream_info->codec();
153  nalu_length_size_ = GetNaluLengthSize(*stream_info);
154  stream_label_ = GetStreamLabelForEncryption(
155  *stream_info, encryption_params_.stream_label_func);
156  switch (codec_) {
157  case kCodecVP9:
158  if (encryption_params_.vp9_subsample_encryption)
159  vpx_parser_.reset(new VP9Parser);
160  break;
161  case kCodecH264:
162  header_parser_.reset(new H264VideoSliceHeaderParser);
163  break;
164  case kCodecH265:
165  header_parser_.reset(new H265VideoSliceHeaderParser);
166  break;
167  default:
168  // Other codecs should have nalu length size == 0.
169  if (nalu_length_size_ > 0) {
170  LOG(WARNING) << "Unknown video codec '" << codec_ << "'";
171  return Status(error::ENCRYPTION_FAILURE, "Unknown video codec.");
172  }
173  }
174  if (header_parser_) {
175  CHECK_NE(nalu_length_size_, 0u) << "AnnexB stream is not supported yet";
176  if (!header_parser_->Initialize(stream_info->codec_config())) {
177  return Status(error::ENCRYPTION_FAILURE,
178  "Fail to read SPS and PPS data.");
179  }
180  }
181 
182  Status status = SetupProtectionPattern(stream_info->stream_type());
183  if (!status.ok())
184  return status;
185 
186  EncryptionKey encryption_key;
187  const bool key_rotation_enabled = crypto_period_duration_ != 0;
188  if (key_rotation_enabled) {
189  check_new_crypto_period_ = true;
190  // Setup dummy key id and key to signal encryption for key rotation.
191  encryption_key.key_id.assign(
192  kKeyRotationDefaultKeyId,
193  kKeyRotationDefaultKeyId + sizeof(kKeyRotationDefaultKeyId));
194  // The key is not really used to encrypt any data. It is there just for
195  // convenience.
196  encryption_key.key = encryption_key.key_id;
197  } else {
198  status = key_source_->GetKey(stream_label_, &encryption_key);
199  if (!status.ok())
200  return status;
201  }
202  if (!CreateEncryptor(encryption_key))
203  return Status(error::ENCRYPTION_FAILURE, "Failed to create encryptor");
204 
205  stream_info->set_is_encrypted(true);
206  stream_info->set_has_clear_lead(encryption_params_.clear_lead_in_seconds > 0);
207  stream_info->set_encryption_config(*encryption_config_);
208 
209  return DispatchStreamInfo(kStreamIndex, stream_info);
210 }
211 
212 Status EncryptionHandler::ProcessMediaSample(
213  std::shared_ptr<const MediaSample> clear_sample) {
214  DCHECK(clear_sample);
215 
216  // We need to parse the frame (which also updates the vpx parser) even if the
217  // frame is not encrypted as the next (encrypted) frame may be dependent on
218  // this clear frame.
219  std::vector<VPxFrameInfo> vpx_frames;
220  if (vpx_parser_ && !vpx_parser_->Parse(clear_sample->data(),
221  clear_sample->data_size(),
222  &vpx_frames)) {
223  return Status(error::ENCRYPTION_FAILURE, "Failed to parse vpx frame.");
224  }
225 
226  // Need to setup the encryptor for new segments even if this segment does not
227  // need to be encrypted, so we can signal encryption metadata earlier to
228  // allows clients to prefetch the keys.
229  if (check_new_crypto_period_) {
230  // |dts| can be negative, e.g. after EditList adjustments. Normalized to 0
231  // in that case.
232  const int64_t dts = std::max(clear_sample->dts(), static_cast<int64_t>(0));
233  const int64_t current_crypto_period_index = dts / crypto_period_duration_;
234  if (current_crypto_period_index != prev_crypto_period_index_) {
235  EncryptionKey encryption_key;
236  Status status = key_source_->GetCryptoPeriodKey(
237  current_crypto_period_index, stream_label_, &encryption_key);
238  if (!status.ok())
239  return status;
240  if (!CreateEncryptor(encryption_key))
241  return Status(error::ENCRYPTION_FAILURE, "Failed to create encryptor");
242  prev_crypto_period_index_ = current_crypto_period_index;
243  }
244  check_new_crypto_period_ = false;
245  }
246 
247  // Since there is no encryption needed right now, send the clear copy
248  // downstream so we can save the costs of copying it.
249  if (remaining_clear_lead_ > 0) {
250  return DispatchMediaSample(kStreamIndex, std::move(clear_sample));
251  }
252 
253  std::unique_ptr<DecryptConfig> decrypt_config(new DecryptConfig(
254  encryption_config_->key_id,
255  encryptor_->iv(),
256  std::vector<SubsampleEntry>(),
257  protection_scheme_,
258  crypt_byte_block_,
259  skip_byte_block_));
260 
261  // Now that we know that this sample must be encrypted, make a copy of
262  // the sample first so that all the encryption operations can be done
263  // in-place.
264  std::shared_ptr<MediaSample> cipher_sample(clear_sample->Clone());
265  // |cipher_sample| above still contains the old clear sample data. We will
266  // use |cipher_sample_data| to hold cipher sample data then transfer it to
267  // |cipher_sample| after encryption.
268  std::shared_ptr<uint8_t> cipher_sample_data(
269  new uint8_t[clear_sample->data_size()], std::default_delete<uint8_t[]>());
270 
271  if (vpx_parser_) {
272  if (!EncryptVpxFrame(vpx_frames, clear_sample->data(),
273  clear_sample->data_size(),
274  &cipher_sample_data.get()[0], decrypt_config.get())) {
275  return Status(error::ENCRYPTION_FAILURE, "Failed to encrypt VPX frame.");
276  }
277  DCHECK_EQ(decrypt_config->GetTotalSizeOfSubsamples(),
278  clear_sample->data_size());
279  } else if (header_parser_) {
280  if (!EncryptNalFrame(clear_sample->data(), clear_sample->data_size(),
281  &cipher_sample_data.get()[0], decrypt_config.get())) {
282  return Status(error::ENCRYPTION_FAILURE, "Failed to encrypt NAL frame.");
283  }
284  DCHECK_EQ(decrypt_config->GetTotalSizeOfSubsamples(),
285  clear_sample->data_size());
286  } else {
287  memcpy(&cipher_sample_data.get()[0], clear_sample->data(),
288  std::min(clear_sample->data_size(), leading_clear_bytes_size_));
289  if (clear_sample->data_size() > leading_clear_bytes_size_) {
290  // The residual block is left unecrypted (copied without encryption). No
291  // need to do special handling here.
292  EncryptBytes(clear_sample->data() + leading_clear_bytes_size_,
293  clear_sample->data_size() - leading_clear_bytes_size_,
294  &cipher_sample_data.get()[leading_clear_bytes_size_]);
295  }
296  }
297 
298  cipher_sample->TransferData(std::move(cipher_sample_data),
299  clear_sample->data_size());
300  // Finish initializing the sample before sending it downstream. We must
301  // wait until now to finish the initialization as we will lose access to
302  // |decrypt_config| once we set it.
303  cipher_sample->set_is_encrypted(true);
304  cipher_sample->set_decrypt_config(std::move(decrypt_config));
305 
306  encryptor_->UpdateIv();
307 
308  return DispatchMediaSample(kStreamIndex, std::move(cipher_sample));
309 }
310 
311 Status EncryptionHandler::SetupProtectionPattern(StreamType stream_type) {
312  switch (protection_scheme_) {
313  case kAppleSampleAesProtectionScheme: {
314  const size_t kH264LeadingClearBytesSize = 32u;
315  const size_t kSmallNalUnitSize = 32u + 16u;
316  const size_t kAudioLeadingClearBytesSize = 16u;
317  switch (codec_) {
318  case kCodecH264:
319  // Apple Sample AES uses 1:9 pattern for video.
320  crypt_byte_block_ = 1u;
321  skip_byte_block_ = 9u;
322  leading_clear_bytes_size_ = kH264LeadingClearBytesSize;
323  min_protected_data_size_ = kSmallNalUnitSize + 1u;
324  break;
325  case kCodecAAC:
326  FALLTHROUGH_INTENDED;
327  case kCodecAC3:
328  FALLTHROUGH_INTENDED;
329  case kCodecEAC3:
330  // Audio is whole sample encrypted. We could not use a
331  // crypto_byte_block_ of 1 here as if there is one crypto block
332  // remaining, it need not be encrypted for video but it needs to be
333  // encrypted for audio.
334  crypt_byte_block_ = 0u;
335  skip_byte_block_ = 0u;
336  // E-AC3 encryption is handled by SampleAesEc3Cryptor, which also
337  // manages leading clear bytes.
338  leading_clear_bytes_size_ =
339  codec_ == kCodecEAC3 ? 0 : kAudioLeadingClearBytesSize;
340  min_protected_data_size_ = leading_clear_bytes_size_ + 15u;
341  break;
342  default:
343  return Status(
344  error::ENCRYPTION_FAILURE,
345  "Only AAC/AC3/EAC3 and H264 are supported in Sample AES.");
346  }
347  break;
348  }
349  case FOURCC_cbcs:
350  FALLTHROUGH_INTENDED;
351  case FOURCC_cens:
352  if (stream_type == kStreamVideo) {
353  // Use 1:9 pattern for video.
354  crypt_byte_block_ = 1u;
355  skip_byte_block_ = 9u;
356  } else {
357  // Tracks other than video are protected using whole-block full-sample
358  // encryption, which is essentially a pattern of 1:0. Note that this may
359  // not be the same as the non-pattern based encryption counterparts,
360  // e.g. in 'cens' for full sample encryption, the whole sample is
361  // encrypted up to the last 16-byte boundary, see 23001-7:2016(E) 9.7;
362  // while in 'cenc' for full sample encryption, the last partial 16-byte
363  // block is also encrypted, see 23001-7:2016(E) 9.4.2. Another
364  // difference is the use of constant iv.
365  crypt_byte_block_ = 1u;
366  skip_byte_block_ = 0u;
367  }
368  break;
369  default:
370  // Not using pattern encryption.
371  crypt_byte_block_ = 0u;
372  skip_byte_block_ = 0u;
373  break;
374  }
375  return Status::OK;
376 }
377 
378 bool EncryptionHandler::CreateEncryptor(const EncryptionKey& encryption_key) {
379  std::unique_ptr<AesCryptor> encryptor;
380  switch (protection_scheme_) {
381  case FOURCC_cenc:
382  encryptor.reset(new AesCtrEncryptor);
383  break;
384  case FOURCC_cbc1:
385  encryptor.reset(new AesCbcEncryptor(kNoPadding));
386  break;
387  case FOURCC_cens:
388  encryptor.reset(new AesPatternCryptor(
389  crypt_byte_block_, skip_byte_block_,
391  AesCryptor::kDontUseConstantIv,
392  std::unique_ptr<AesCryptor>(new AesCtrEncryptor())));
393  break;
394  case FOURCC_cbcs:
395  encryptor.reset(new AesPatternCryptor(
396  crypt_byte_block_, skip_byte_block_,
398  AesCryptor::kUseConstantIv,
399  std::unique_ptr<AesCryptor>(new AesCbcEncryptor(kNoPadding))));
400  break;
401  case kAppleSampleAesProtectionScheme:
402  if (crypt_byte_block_ == 0 && skip_byte_block_ == 0) {
403  if (codec_ == kCodecEAC3) {
404  encryptor.reset(new SampleAesEc3Cryptor(
405  std::unique_ptr<AesCryptor>(new AesCbcEncryptor(kNoPadding))));
406  } else {
407  encryptor.reset(
408  new AesCbcEncryptor(kNoPadding, AesCryptor::kUseConstantIv));
409  }
410  } else {
411  encryptor.reset(new AesPatternCryptor(
412  crypt_byte_block_, skip_byte_block_,
414  AesCryptor::kUseConstantIv,
415  std::unique_ptr<AesCryptor>(new AesCbcEncryptor(kNoPadding))));
416  }
417  break;
418  default:
419  LOG(ERROR) << "Unsupported protection scheme.";
420  return false;
421  }
422 
423  std::vector<uint8_t> iv = encryption_key.iv;
424  if (iv.empty()) {
425  if (!AesCryptor::GenerateRandomIv(protection_scheme_, &iv)) {
426  LOG(ERROR) << "Failed to generate random iv.";
427  return false;
428  }
429  }
430  const bool initialized =
431  encryptor->InitializeWithIv(encryption_key.key, iv);
432  encryptor_ = std::move(encryptor);
433 
434  encryption_config_.reset(new EncryptionConfig);
435  encryption_config_->protection_scheme = protection_scheme_;
436  encryption_config_->crypt_byte_block = crypt_byte_block_;
437  encryption_config_->skip_byte_block = skip_byte_block_;
438  if (encryptor_->use_constant_iv()) {
439  encryption_config_->per_sample_iv_size = 0;
440  encryption_config_->constant_iv = iv;
441  } else {
442  encryption_config_->per_sample_iv_size = static_cast<uint8_t>(iv.size());
443  }
444  encryption_config_->key_id = encryption_key.key_id;
445  encryption_config_->key_system_info = encryption_key.key_system_info;
446  return initialized;
447 }
448 
449 bool EncryptionHandler::EncryptVpxFrame(
450  const std::vector<VPxFrameInfo>& vpx_frames,
451  const uint8_t* source,
452  size_t source_size,
453  uint8_t* dest,
454  DecryptConfig* decrypt_config) {
455  const uint8_t* data = source;
456  for (const VPxFrameInfo& frame : vpx_frames) {
457  uint16_t clear_bytes =
458  static_cast<uint16_t>(frame.uncompressed_header_size);
459  uint32_t cipher_bytes = static_cast<uint32_t>(
460  frame.frame_size - frame.uncompressed_header_size);
461 
462  // "VP Codec ISO Media File Format Binding" document requires that the
463  // encrypted bytes of each frame within the superframe must be block
464  // aligned so that the counter state can be computed for each frame
465  // within the superframe.
466  // ISO/IEC 23001-7:2016 10.2 'cbc1' 10.3 'cens'
467  // The BytesOfProtectedData size SHALL be a multiple of 16 bytes to
468  // avoid partial blocks in Subsamples.
469  // For consistency, apply block alignment to all frames.
470  const uint16_t misalign_bytes = cipher_bytes % kCencBlockSize;
471  clear_bytes += misalign_bytes;
472  cipher_bytes -= misalign_bytes;
473 
474  decrypt_config->AddSubsample(clear_bytes, cipher_bytes);
475  memcpy(dest, data, clear_bytes);
476  if (cipher_bytes > 0)
477  EncryptBytes(data + clear_bytes, cipher_bytes, dest + clear_bytes);
478  data += frame.frame_size;
479  dest += frame.frame_size;
480  }
481  // Add subsample for the superframe index if exists.
482  const bool is_superframe = vpx_frames.size() > 1;
483  if (is_superframe) {
484  size_t index_size = source + source_size - data;
485  DCHECK_LE(index_size, 2 + vpx_frames.size() * 4);
486  DCHECK_GE(index_size, 2 + vpx_frames.size() * 1);
487  uint16_t clear_bytes = static_cast<uint16_t>(index_size);
488  uint32_t cipher_bytes = 0;
489  decrypt_config->AddSubsample(clear_bytes, cipher_bytes);
490  memcpy(dest, data, clear_bytes);
491  }
492  return true;
493 }
494 
495 bool EncryptionHandler::EncryptNalFrame(const uint8_t* source,
496  size_t source_size,
497  uint8_t* dest,
498  DecryptConfig* decrypt_config) {
499  DCHECK_NE(nalu_length_size_, 0u);
500  DCHECK(header_parser_);
501  const Nalu::CodecType nalu_type =
502  (codec_ == kCodecH265) ? Nalu::kH265 : Nalu::kH264;
503  NaluReader reader(nalu_type, nalu_length_size_, source, source_size);
504 
505  // Store the current length of clear data. This is used to squash
506  // multiple unencrypted NAL units into fewer subsample entries.
507  uint64_t accumulated_clear_bytes = 0;
508 
509  Nalu nalu;
510  NaluReader::Result result;
511  while ((result = reader.Advance(&nalu)) == NaluReader::kOk) {
512  const uint64_t nalu_total_size = nalu.header_size() + nalu.payload_size();
513  if (nalu.is_video_slice() && nalu_total_size >= min_protected_data_size_) {
514  uint64_t current_clear_bytes = leading_clear_bytes_size_;
515  if (current_clear_bytes == 0) {
516  // For video-slice NAL units, encrypt the video slice. This skips
517  // the frame header.
518  const int64_t video_slice_header_size =
519  header_parser_->GetHeaderSize(nalu);
520  if (video_slice_header_size < 0) {
521  LOG(ERROR) << "Failed to read slice header.";
522  return false;
523  }
524  current_clear_bytes = nalu.header_size() + video_slice_header_size;
525  }
526  uint64_t cipher_bytes = nalu_total_size - current_clear_bytes;
527 
528  // ISO/IEC 23001-7:2016 10.2 'cbc1' 10.3 'cens'
529  // The BytesOfProtectedData size SHALL be a multiple of 16 bytes to
530  // avoid partial blocks in Subsamples.
531  // CMAF requires 'cenc' scheme BytesOfProtectedData SHALL be a multiple
532  // of 16 bytes; while 'cbcs' scheme BytesOfProtectedData SHALL start on
533  // the first byte of video data following the slice header.
534  if (protection_scheme_ == FOURCC_cbc1 ||
535  protection_scheme_ == FOURCC_cens ||
536  protection_scheme_ == FOURCC_cenc) {
537  const uint16_t misalign_bytes = cipher_bytes % kCencBlockSize;
538  current_clear_bytes += misalign_bytes;
539  cipher_bytes -= misalign_bytes;
540  }
541 
542  accumulated_clear_bytes += nalu_length_size_ + current_clear_bytes;
543  AddSubsample(accumulated_clear_bytes, cipher_bytes, decrypt_config);
544  memcpy(dest, source, accumulated_clear_bytes);
545  source += accumulated_clear_bytes;
546  dest += accumulated_clear_bytes;
547  accumulated_clear_bytes = 0;
548 
549  DCHECK_EQ(nalu.data() + current_clear_bytes, source);
550  EncryptBytes(source, cipher_bytes, dest);
551  source += cipher_bytes;
552  dest += cipher_bytes;
553  } else {
554  // For non-video-slice or small NAL units, don't encrypt.
555  accumulated_clear_bytes += nalu_length_size_ + nalu_total_size;
556  }
557  }
558  if (result != NaluReader::kEOStream) {
559  LOG(ERROR) << "Failed to parse NAL units.";
560  return false;
561  }
562  AddSubsample(accumulated_clear_bytes, 0, decrypt_config);
563  memcpy(dest, source, accumulated_clear_bytes);
564  return true;
565 }
566 
567 void EncryptionHandler::EncryptBytes(const uint8_t* source,
568  size_t source_size,
569  uint8_t* dest) {
570  DCHECK(source);
571  DCHECK(dest);
572  DCHECK(encryptor_);
573  CHECK(encryptor_->Crypt(source, source_size, dest));
574 }
575 
576 void EncryptionHandler::InjectVpxParserForTesting(
577  std::unique_ptr<VPxParser> vpx_parser) {
578  vpx_parser_ = std::move(vpx_parser);
579 }
580 
581 void EncryptionHandler::InjectVideoSliceHeaderParserForTesting(
582  std::unique_ptr<VideoSliceHeaderParser> header_parser) {
583  header_parser_ = std::move(header_parser);
584 }
585 
586 } // namespace media
587 } // namespace shaka
Abstract class holds stream information.
Definition: stream_info.h:61
bool is_video_slice() const
Slice data partition NALs are not considered as slice NALs.
Definition: nalu_reader.h:117
virtual std::unique_ptr< StreamInfo > Clone() const =0
const uint8_t * data() const
This is the pointer to the Nalu data, pointing to the header.
Definition: nalu_reader.h:97
All the methods that are virtual are virtual for mocking.
uint64_t header_size() const
The size of the header, e.g. 1 for H.264.
Definition: nalu_reader.h:100
Status Process(std::unique_ptr< StreamData > stream_data) override
static bool GenerateRandomIv(FourCC protection_scheme, std::vector< uint8_t > *iv)
Definition: aes_cryptor.cc:107
Result Advance(Nalu *nalu)
Definition: nalu_reader.cc:239
Class to parse a vp9 bit stream.
Definition: vp9_parser.h:20
Implements pattern-based encryption/decryption.
void AddSubsample(uint16_t clear_bytes, uint32_t cipher_bytes)
uint64_t payload_size() const
Size of this Nalu minus header_size().
Definition: nalu_reader.h:102