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  const int64_t current_crypto_period_index =
231  clear_sample->dts() / crypto_period_duration_;
232  if (current_crypto_period_index != prev_crypto_period_index_) {
233  EncryptionKey encryption_key;
234  Status status = key_source_->GetCryptoPeriodKey(
235  current_crypto_period_index, stream_label_, &encryption_key);
236  if (!status.ok())
237  return status;
238  if (!CreateEncryptor(encryption_key))
239  return Status(error::ENCRYPTION_FAILURE, "Failed to create encryptor");
240  prev_crypto_period_index_ = current_crypto_period_index;
241  }
242  check_new_crypto_period_ = false;
243  }
244 
245  // Since there is no encryption needed right now, send the clear copy
246  // downstream so we can save the costs of copying it.
247  if (remaining_clear_lead_ > 0) {
248  return DispatchMediaSample(kStreamIndex, std::move(clear_sample));
249  }
250 
251  std::unique_ptr<DecryptConfig> decrypt_config(new DecryptConfig(
252  encryption_config_->key_id,
253  encryptor_->iv(),
254  std::vector<SubsampleEntry>(),
255  protection_scheme_,
256  crypt_byte_block_,
257  skip_byte_block_));
258 
259  // Now that we know that this sample must be encrypted, make a copy of
260  // the sample first so that all the encryption operations can be done
261  // in-place.
262  std::shared_ptr<MediaSample> cipher_sample(clear_sample->Clone());
263  // |cipher_sample| above still contains the old clear sample data. We will
264  // use |cipher_sample_data| to hold cipher sample data then transfer it to
265  // |cipher_sample| after encryption.
266  std::shared_ptr<uint8_t> cipher_sample_data(
267  new uint8_t[clear_sample->data_size()], std::default_delete<uint8_t[]>());
268 
269  if (vpx_parser_) {
270  if (!EncryptVpxFrame(vpx_frames, clear_sample->data(),
271  clear_sample->data_size(),
272  &cipher_sample_data.get()[0], decrypt_config.get())) {
273  return Status(error::ENCRYPTION_FAILURE, "Failed to encrypt VPX frame.");
274  }
275  DCHECK_EQ(decrypt_config->GetTotalSizeOfSubsamples(),
276  clear_sample->data_size());
277  } else if (header_parser_) {
278  if (!EncryptNalFrame(clear_sample->data(), clear_sample->data_size(),
279  &cipher_sample_data.get()[0], decrypt_config.get())) {
280  return Status(error::ENCRYPTION_FAILURE, "Failed to encrypt NAL frame.");
281  }
282  DCHECK_EQ(decrypt_config->GetTotalSizeOfSubsamples(),
283  clear_sample->data_size());
284  } else {
285  memcpy(&cipher_sample_data.get()[0], clear_sample->data(),
286  std::min(clear_sample->data_size(), leading_clear_bytes_size_));
287  if (clear_sample->data_size() > leading_clear_bytes_size_) {
288  // The residual block is left unecrypted (copied without encryption). No
289  // need to do special handling here.
290  EncryptBytes(clear_sample->data() + leading_clear_bytes_size_,
291  clear_sample->data_size() - leading_clear_bytes_size_,
292  &cipher_sample_data.get()[leading_clear_bytes_size_]);
293  }
294  }
295 
296  cipher_sample->TransferData(std::move(cipher_sample_data),
297  clear_sample->data_size());
298  // Finish initializing the sample before sending it downstream. We must
299  // wait until now to finish the initialization as we will lose access to
300  // |decrypt_config| once we set it.
301  cipher_sample->set_is_encrypted(true);
302  cipher_sample->set_decrypt_config(std::move(decrypt_config));
303 
304  encryptor_->UpdateIv();
305 
306  return DispatchMediaSample(kStreamIndex, std::move(cipher_sample));
307 }
308 
309 Status EncryptionHandler::SetupProtectionPattern(StreamType stream_type) {
310  switch (protection_scheme_) {
311  case kAppleSampleAesProtectionScheme: {
312  const size_t kH264LeadingClearBytesSize = 32u;
313  const size_t kSmallNalUnitSize = 32u + 16u;
314  const size_t kAudioLeadingClearBytesSize = 16u;
315  switch (codec_) {
316  case kCodecH264:
317  // Apple Sample AES uses 1:9 pattern for video.
318  crypt_byte_block_ = 1u;
319  skip_byte_block_ = 9u;
320  leading_clear_bytes_size_ = kH264LeadingClearBytesSize;
321  min_protected_data_size_ = kSmallNalUnitSize + 1u;
322  break;
323  case kCodecAAC:
324  FALLTHROUGH_INTENDED;
325  case kCodecAC3:
326  FALLTHROUGH_INTENDED;
327  case kCodecEAC3:
328  // Audio is whole sample encrypted. We could not use a
329  // crypto_byte_block_ of 1 here as if there is one crypto block
330  // remaining, it need not be encrypted for video but it needs to be
331  // encrypted for audio.
332  crypt_byte_block_ = 0u;
333  skip_byte_block_ = 0u;
334  // E-AC3 encryption is handled by SampleAesEc3Cryptor, which also
335  // manages leading clear bytes.
336  leading_clear_bytes_size_ =
337  codec_ == kCodecEAC3 ? 0 : kAudioLeadingClearBytesSize;
338  min_protected_data_size_ = leading_clear_bytes_size_ + 15u;
339  break;
340  default:
341  return Status(
342  error::ENCRYPTION_FAILURE,
343  "Only AAC/AC3/EAC3 and H264 are supported in Sample AES.");
344  }
345  break;
346  }
347  case FOURCC_cbcs:
348  FALLTHROUGH_INTENDED;
349  case FOURCC_cens:
350  if (stream_type == kStreamVideo) {
351  // Use 1:9 pattern for video.
352  crypt_byte_block_ = 1u;
353  skip_byte_block_ = 9u;
354  } else {
355  // Tracks other than video are protected using whole-block full-sample
356  // encryption, which is essentially a pattern of 1:0. Note that this may
357  // not be the same as the non-pattern based encryption counterparts,
358  // e.g. in 'cens' for full sample encryption, the whole sample is
359  // encrypted up to the last 16-byte boundary, see 23001-7:2016(E) 9.7;
360  // while in 'cenc' for full sample encryption, the last partial 16-byte
361  // block is also encrypted, see 23001-7:2016(E) 9.4.2. Another
362  // difference is the use of constant iv.
363  crypt_byte_block_ = 1u;
364  skip_byte_block_ = 0u;
365  }
366  break;
367  default:
368  // Not using pattern encryption.
369  crypt_byte_block_ = 0u;
370  skip_byte_block_ = 0u;
371  break;
372  }
373  return Status::OK;
374 }
375 
376 bool EncryptionHandler::CreateEncryptor(const EncryptionKey& encryption_key) {
377  std::unique_ptr<AesCryptor> encryptor;
378  switch (protection_scheme_) {
379  case FOURCC_cenc:
380  encryptor.reset(new AesCtrEncryptor);
381  break;
382  case FOURCC_cbc1:
383  encryptor.reset(new AesCbcEncryptor(kNoPadding));
384  break;
385  case FOURCC_cens:
386  encryptor.reset(new AesPatternCryptor(
387  crypt_byte_block_, skip_byte_block_,
389  AesCryptor::kDontUseConstantIv,
390  std::unique_ptr<AesCryptor>(new AesCtrEncryptor())));
391  break;
392  case FOURCC_cbcs:
393  encryptor.reset(new AesPatternCryptor(
394  crypt_byte_block_, skip_byte_block_,
396  AesCryptor::kUseConstantIv,
397  std::unique_ptr<AesCryptor>(new AesCbcEncryptor(kNoPadding))));
398  break;
399  case kAppleSampleAesProtectionScheme:
400  if (crypt_byte_block_ == 0 && skip_byte_block_ == 0) {
401  if (codec_ == kCodecEAC3) {
402  encryptor.reset(new SampleAesEc3Cryptor(
403  std::unique_ptr<AesCryptor>(new AesCbcEncryptor(kNoPadding))));
404  } else {
405  encryptor.reset(
406  new AesCbcEncryptor(kNoPadding, AesCryptor::kUseConstantIv));
407  }
408  } else {
409  encryptor.reset(new AesPatternCryptor(
410  crypt_byte_block_, skip_byte_block_,
412  AesCryptor::kUseConstantIv,
413  std::unique_ptr<AesCryptor>(new AesCbcEncryptor(kNoPadding))));
414  }
415  break;
416  default:
417  LOG(ERROR) << "Unsupported protection scheme.";
418  return false;
419  }
420 
421  std::vector<uint8_t> iv = encryption_key.iv;
422  if (iv.empty()) {
423  if (!AesCryptor::GenerateRandomIv(protection_scheme_, &iv)) {
424  LOG(ERROR) << "Failed to generate random iv.";
425  return false;
426  }
427  }
428  const bool initialized =
429  encryptor->InitializeWithIv(encryption_key.key, iv);
430  encryptor_ = std::move(encryptor);
431 
432  encryption_config_.reset(new EncryptionConfig);
433  encryption_config_->protection_scheme = protection_scheme_;
434  encryption_config_->crypt_byte_block = crypt_byte_block_;
435  encryption_config_->skip_byte_block = skip_byte_block_;
436  if (encryptor_->use_constant_iv()) {
437  encryption_config_->per_sample_iv_size = 0;
438  encryption_config_->constant_iv = iv;
439  } else {
440  encryption_config_->per_sample_iv_size = static_cast<uint8_t>(iv.size());
441  }
442  encryption_config_->key_id = encryption_key.key_id;
443  encryption_config_->key_system_info = encryption_key.key_system_info;
444  return initialized;
445 }
446 
447 bool EncryptionHandler::EncryptVpxFrame(
448  const std::vector<VPxFrameInfo>& vpx_frames,
449  const uint8_t* source,
450  size_t source_size,
451  uint8_t* dest,
452  DecryptConfig* decrypt_config) {
453  const uint8_t* data = source;
454  for (const VPxFrameInfo& frame : vpx_frames) {
455  uint16_t clear_bytes =
456  static_cast<uint16_t>(frame.uncompressed_header_size);
457  uint32_t cipher_bytes = static_cast<uint32_t>(
458  frame.frame_size - frame.uncompressed_header_size);
459 
460  // "VP Codec ISO Media File Format Binding" document requires that the
461  // encrypted bytes of each frame within the superframe must be block
462  // aligned so that the counter state can be computed for each frame
463  // within the superframe.
464  // ISO/IEC 23001-7:2016 10.2 'cbc1' 10.3 'cens'
465  // The BytesOfProtectedData size SHALL be a multiple of 16 bytes to
466  // avoid partial blocks in Subsamples.
467  // For consistency, apply block alignment to all frames.
468  const uint16_t misalign_bytes = cipher_bytes % kCencBlockSize;
469  clear_bytes += misalign_bytes;
470  cipher_bytes -= misalign_bytes;
471 
472  decrypt_config->AddSubsample(clear_bytes, cipher_bytes);
473  memcpy(dest, data, clear_bytes);
474  if (cipher_bytes > 0)
475  EncryptBytes(data + clear_bytes, cipher_bytes, dest + clear_bytes);
476  data += frame.frame_size;
477  dest += frame.frame_size;
478  }
479  // Add subsample for the superframe index if exists.
480  const bool is_superframe = vpx_frames.size() > 1;
481  if (is_superframe) {
482  size_t index_size = source + source_size - data;
483  DCHECK_LE(index_size, 2 + vpx_frames.size() * 4);
484  DCHECK_GE(index_size, 2 + vpx_frames.size() * 1);
485  uint16_t clear_bytes = static_cast<uint16_t>(index_size);
486  uint32_t cipher_bytes = 0;
487  decrypt_config->AddSubsample(clear_bytes, cipher_bytes);
488  memcpy(dest, data, clear_bytes);
489  }
490  return true;
491 }
492 
493 bool EncryptionHandler::EncryptNalFrame(const uint8_t* source,
494  size_t source_size,
495  uint8_t* dest,
496  DecryptConfig* decrypt_config) {
497  DCHECK_NE(nalu_length_size_, 0u);
498  DCHECK(header_parser_);
499  const Nalu::CodecType nalu_type =
500  (codec_ == kCodecH265) ? Nalu::kH265 : Nalu::kH264;
501  NaluReader reader(nalu_type, nalu_length_size_, source, source_size);
502 
503  // Store the current length of clear data. This is used to squash
504  // multiple unencrypted NAL units into fewer subsample entries.
505  uint64_t accumulated_clear_bytes = 0;
506 
507  Nalu nalu;
508  NaluReader::Result result;
509  while ((result = reader.Advance(&nalu)) == NaluReader::kOk) {
510  const uint64_t nalu_total_size = nalu.header_size() + nalu.payload_size();
511  if (nalu.is_video_slice() && nalu_total_size >= min_protected_data_size_) {
512  uint64_t current_clear_bytes = leading_clear_bytes_size_;
513  if (current_clear_bytes == 0) {
514  // For video-slice NAL units, encrypt the video slice. This skips
515  // the frame header.
516  const int64_t video_slice_header_size =
517  header_parser_->GetHeaderSize(nalu);
518  if (video_slice_header_size < 0) {
519  LOG(ERROR) << "Failed to read slice header.";
520  return false;
521  }
522  current_clear_bytes = nalu.header_size() + video_slice_header_size;
523  }
524  uint64_t cipher_bytes = nalu_total_size - current_clear_bytes;
525 
526  // ISO/IEC 23001-7:2016 10.2 'cbc1' 10.3 'cens'
527  // The BytesOfProtectedData size SHALL be a multiple of 16 bytes to
528  // avoid partial blocks in Subsamples.
529  // CMAF requires 'cenc' scheme BytesOfProtectedData SHALL be a multiple
530  // of 16 bytes; while 'cbcs' scheme BytesOfProtectedData SHALL start on
531  // the first byte of video data following the slice header.
532  if (protection_scheme_ == FOURCC_cbc1 ||
533  protection_scheme_ == FOURCC_cens ||
534  protection_scheme_ == FOURCC_cenc) {
535  const uint16_t misalign_bytes = cipher_bytes % kCencBlockSize;
536  current_clear_bytes += misalign_bytes;
537  cipher_bytes -= misalign_bytes;
538  }
539 
540  accumulated_clear_bytes += nalu_length_size_ + current_clear_bytes;
541  AddSubsample(accumulated_clear_bytes, cipher_bytes, decrypt_config);
542  memcpy(dest, source, accumulated_clear_bytes);
543  source += accumulated_clear_bytes;
544  dest += accumulated_clear_bytes;
545  accumulated_clear_bytes = 0;
546 
547  DCHECK_EQ(nalu.data() + current_clear_bytes, source);
548  EncryptBytes(source, cipher_bytes, dest);
549  source += cipher_bytes;
550  dest += cipher_bytes;
551  } else {
552  // For non-video-slice or small NAL units, don't encrypt.
553  accumulated_clear_bytes += nalu_length_size_ + nalu_total_size;
554  }
555  }
556  if (result != NaluReader::kEOStream) {
557  LOG(ERROR) << "Failed to parse NAL units.";
558  return false;
559  }
560  AddSubsample(accumulated_clear_bytes, 0, decrypt_config);
561  memcpy(dest, source, accumulated_clear_bytes);
562  return true;
563 }
564 
565 void EncryptionHandler::EncryptBytes(const uint8_t* source,
566  size_t source_size,
567  uint8_t* dest) {
568  DCHECK(source);
569  DCHECK(dest);
570  DCHECK(encryptor_);
571  CHECK(encryptor_->Crypt(source, source_size, dest));
572 }
573 
574 void EncryptionHandler::InjectVpxParserForTesting(
575  std::unique_ptr<VPxParser> vpx_parser) {
576  vpx_parser_ = std::move(vpx_parser);
577 }
578 
579 void EncryptionHandler::InjectVideoSliceHeaderParserForTesting(
580  std::unique_ptr<VideoSliceHeaderParser> header_parser) {
581  header_parser_ = std::move(header_parser);
582 }
583 
584 } // namespace media
585 } // 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