DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs 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 edash_packager {
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  MuxerListener* muxer_listener)
29  : EncryptingFragmenter(info,
30  traf,
31  scoped_ptr<EncryptionKey>(new EncryptionKey()),
32  clear_time,
33  protection_scheme),
34  moof_(moof),
35  encryption_key_source_(encryption_key_source),
36  track_type_(track_type),
37  crypto_period_duration_(crypto_period_duration),
38  prev_crypto_period_index_(-1),
39  muxer_listener_(muxer_listener) {
40  DCHECK(moof);
41  DCHECK(encryption_key_source);
42 }
43 
44 KeyRotationFragmenter::~KeyRotationFragmenter() {}
45 
47  bool enable_encryption) {
48  bool need_to_refresh_encryptor = !encryptor();
49 
50  size_t current_crypto_period_index =
51  traf()->decode_time.decode_time / crypto_period_duration_;
52  if (current_crypto_period_index != prev_crypto_period_index_) {
53  scoped_ptr<EncryptionKey> encryption_key(new EncryptionKey());
54  Status status = encryption_key_source_->GetCryptoPeriodKey(
55  current_crypto_period_index, track_type_, encryption_key.get());
56  if (!status.ok())
57  return status;
58  if (encryption_key->iv.empty()) {
59  if (!AesCryptor::GenerateRandomIv(protection_scheme(),
60  &encryption_key->iv)) {
61  return Status(error::INTERNAL_ERROR, "Failed to generate random iv.");
62  }
63  }
64  set_encryption_key(encryption_key.Pass());
65  prev_crypto_period_index_ = current_crypto_period_index;
66  need_to_refresh_encryptor = true;
67  }
68 
69  DCHECK(encryption_key());
70  const std::vector<ProtectionSystemSpecificInfo>& system_info =
71  encryption_key()->key_system_info;
72  moof_->pssh.resize(system_info.size());
73  for (size_t i = 0; i < system_info.size(); i++) {
74  moof_->pssh[i].raw_box = system_info[i].CreateBox();
75  }
76 
77  if (muxer_listener_) {
78  muxer_listener_->OnEncryptionInfoReady(!kInitialEncryptionInfo,
79  encryption_key()->key_id,
80  encryption_key()->key_system_info);
81  }
82 
83  // Skip the following steps if the current fragment is not going to be
84  // encrypted. 'pssh' box needs to be included in the fragment, which is
85  // performed above, regardless of whether the fragment is encrypted. This is
86  // necessary for two reasons: 1) Requesting keys before reaching encrypted
87  // content avoids playback delay due to license requests; 2) In Chrome, CDM
88  // must be initialized before starting the playback and CDM can only be
89  // initialized with a valid 'pssh'.
90  if (!enable_encryption) {
91  DCHECK(!encryptor());
92  return Status::OK;
93  }
94 
95  if (need_to_refresh_encryptor) {
96  Status status = CreateEncryptor();
97  if (!status.ok())
98  return status;
99  }
100  DCHECK(encryptor());
101 
102  // Key rotation happens in fragment boundary only in this implementation,
103  // i.e. there is at most one key for the fragment. So there should be only
104  // one entry in SampleGroupDescription box and one entry in SampleToGroup box.
105  // Fill in SampleGroupDescription box information.
106  traf()->sample_group_description.grouping_type = FOURCC_seig;
107  traf()->sample_group_description.entries.resize(1);
108  traf()->sample_group_description.entries[0].is_protected = 1;
109  traf()->sample_group_description.entries[0].per_sample_iv_size =
110  encryptor()->iv().size();
111  traf()->sample_group_description.entries[0].key_id = encryption_key()->key_id;
112 
113  // Fill in SampleToGroup box information.
114  traf()->sample_to_group.grouping_type = FOURCC_seig;
115  traf()->sample_to_group.entries.resize(1);
116  // sample_count is adjusted in |FinalizeFragment| later.
117  traf()->sample_to_group.entries[0].group_description_index =
118  SampleToGroupEntry::kTrackFragmentGroupDescriptionIndexBase + 1;
119 
120  return Status::OK;
121 }
122 
125  DCHECK_EQ(1u, traf()->sample_to_group.entries.size());
126  traf()->sample_to_group.entries[0].sample_count =
127  traf()->auxiliary_size.sample_count;
128 }
129 
130 } // namespace mp4
131 } // namespace media
132 } // namespace edash_packager
void FinalizeFragmentForEncryption() override
Finalize current fragment for encryption.
EncryptingFragmenter generates MP4 fragments with sample encrypted.
static bool GenerateRandomIv(FourCC protection_scheme, std::vector< uint8_t > *iv)
Definition: aes_cryptor.cc:58
Status PrepareFragmentForEncryption(bool enable_encryption) override
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, MuxerListener *muxer_listener)
KeySource is responsible for encryption key acquisition.
Definition: key_source.h:31
const std::vector< uint8_t > & iv() const
Definition: aes_cryptor.h:60
virtual void FinalizeFragmentForEncryption()
Finalize current fragment for encryption.
virtual Status GetCryptoPeriodKey(uint32_t crypto_period_index, TrackType track_type, EncryptionKey *key)=0