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