DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
key_rotation_fragmenter.cc
1 // Copyright 2014 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/formats/mp4/key_rotation_fragmenter.h"
8 
9 #include "packager/media/base/aes_encryptor.h"
10 #include "packager/media/formats/mp4/box_definitions.h"
11 
12 namespace shaka {
13 namespace media {
14 namespace mp4 {
15 
16 namespace {
17 const bool kInitialEncryptionInfo = true;
18 } // namespace
19 
21  scoped_refptr<StreamInfo> info,
22  TrackFragment* traf,
23  KeySource* encryption_key_source,
24  KeySource::TrackType track_type,
25  int64_t crypto_period_duration,
26  int64_t clear_time,
27  FourCC protection_scheme,
28  uint8_t crypt_byte_block,
29  uint8_t skip_byte_block,
30  MuxerListener* muxer_listener)
31  : EncryptingFragmenter(info,
32  traf,
33  scoped_ptr<EncryptionKey>(new EncryptionKey()),
34  clear_time,
35  protection_scheme,
36  crypt_byte_block,
37  skip_byte_block,
38  muxer_listener),
39  moof_(moof),
40  encryption_key_source_(encryption_key_source),
41  track_type_(track_type),
42  crypto_period_duration_(crypto_period_duration),
43  prev_crypto_period_index_(-1),
44  muxer_listener_(muxer_listener) {
45  DCHECK(moof);
46  DCHECK(encryption_key_source);
47 }
48 
49 KeyRotationFragmenter::~KeyRotationFragmenter() {}
50 
52  bool enable_encryption) {
53  bool need_to_refresh_encryptor = !encryptor();
54 
55  size_t current_crypto_period_index =
56  traf()->decode_time.decode_time / crypto_period_duration_;
57  if (current_crypto_period_index != prev_crypto_period_index_) {
58  scoped_ptr<EncryptionKey> encryption_key(new EncryptionKey());
59  Status status = encryption_key_source_->GetCryptoPeriodKey(
60  current_crypto_period_index, track_type_, encryption_key.get());
61  if (!status.ok())
62  return status;
63  if (encryption_key->iv.empty()) {
64  if (!AesCryptor::GenerateRandomIv(protection_scheme(),
65  &encryption_key->iv)) {
66  return Status(error::INTERNAL_ERROR, "Failed to generate random iv.");
67  }
68  }
69  set_encryption_key(encryption_key.Pass());
70  prev_crypto_period_index_ = current_crypto_period_index;
71  need_to_refresh_encryptor = true;
72  }
73 
74  DCHECK(encryption_key());
75  const std::vector<ProtectionSystemSpecificInfo>& system_info =
76  encryption_key()->key_system_info;
77  moof_->pssh.resize(system_info.size());
78  for (size_t i = 0; i < system_info.size(); i++) {
79  moof_->pssh[i].raw_box = system_info[i].CreateBox();
80  }
81 
82  if (muxer_listener_) {
83  muxer_listener_->OnEncryptionInfoReady(
84  !kInitialEncryptionInfo, protection_scheme(), encryption_key()->key_id,
85  encryption_key()->iv, encryption_key()->key_system_info);
86  }
87 
88  // Skip the following steps if the current fragment is not going to be
89  // encrypted. 'pssh' box needs to be included in the fragment, which is
90  // performed above, regardless of whether the fragment is encrypted. This is
91  // necessary for two reasons: 1) Requesting keys before reaching encrypted
92  // content avoids playback delay due to license requests; 2) In Chrome, CDM
93  // must be initialized before starting the playback and CDM can only be
94  // initialized with a valid 'pssh'.
95  if (!enable_encryption) {
96  DCHECK(!encryptor());
97  return Status::OK;
98  }
99 
100  if (need_to_refresh_encryptor) {
101  Status status = CreateEncryptor();
102  if (!status.ok())
103  return status;
104  }
105  DCHECK(encryptor());
106 
107  // Key rotation happens in fragment boundary only in this implementation,
108  // i.e. there is at most one key for the fragment. So there should be only
109  // one entry in SampleGroupDescription box and one entry in SampleToGroup box.
110  // Fill in SampleGroupDescription box information.
111  traf()->sample_group_descriptions.resize(
112  traf()->sample_group_descriptions.size() + 1);
113  SampleGroupDescription& sample_group_description =
114  traf()->sample_group_descriptions.back();
115  sample_group_description.grouping_type = FOURCC_seig;
116 
117  sample_group_description.cenc_sample_encryption_info_entries.resize(1);
118  CencSampleEncryptionInfoEntry& sample_group_entry =
119  sample_group_description.cenc_sample_encryption_info_entries.back();
120  sample_group_entry.is_protected = 1;
121  if (protection_scheme() == FOURCC_cbcs) {
122  // For 'cbcs' scheme, Constant IVs SHALL be used.
123  sample_group_entry.per_sample_iv_size = 0;
124  sample_group_entry.constant_iv = encryptor()->iv();
125  } else {
126  sample_group_entry.per_sample_iv_size = encryptor()->iv().size();
127  }
128  sample_group_entry.crypt_byte_block = crypt_byte_block();
129  sample_group_entry.skip_byte_block = skip_byte_block();
130  sample_group_entry.key_id = encryption_key()->key_id;
131 
132  return Status::OK;
133 }
134 
135 } // namespace mp4
136 } // namespace media
137 } // namespace shaka
virtual void OnEncryptionInfoReady(bool is_initial_encryption_info, FourCC protection_scheme, const std::vector< uint8_t > &key_id, const std::vector< uint8_t > &iv, const std::vector< ProtectionSystemSpecificInfo > &key_system_info)=0
KeyRotationFragmenter(MovieFragment *moof, scoped_refptr< StreamInfo > info, TrackFragment *traf, KeySource *encryption_key_source, KeySource::TrackType track_type, int64_t crypto_period_duration, int64_t clear_time, FourCC protection_scheme, uint8_t crypt_byte_block, uint8_t skip_byte_block, MuxerListener *muxer_listener)
virtual Status GetCryptoPeriodKey(uint32_t crypto_period_index, TrackType track_type, EncryptionKey *key)=0
const std::vector< uint8_t > & iv() const
Definition: aes_cryptor.h:81
static bool GenerateRandomIv(FourCC protection_scheme, std::vector< uint8_t > *iv)
Definition: aes_cryptor.cc:109
EncryptingFragmenter generates MP4 fragments with sample encrypted.
KeySource is responsible for encryption key acquisition.
Definition: key_source.h:31
Status PrepareFragmentForEncryption(bool enable_encryption) override