DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerator
encrypting_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/encrypting_fragmenter.h"
8 
9 #include "packager/media/base/aes_encryptor.h"
10 #include "packager/media/base/buffer_reader.h"
11 #include "packager/media/base/key_source.h"
12 #include "packager/media/base/media_sample.h"
13 #include "packager/media/formats/mp4/box_definitions.h"
14 #include "packager/media/formats/mp4/cenc.h"
15 
16 namespace {
17 // Generate 64bit IV by default.
18 const size_t kDefaultIvSize = 8u;
19 } // namespace
20 
21 namespace edash_packager {
22 namespace media {
23 namespace mp4 {
24 
26  TrackFragment* traf,
27  scoped_ptr<EncryptionKey> encryption_key,
28  int64_t clear_time,
29  uint8_t nalu_length_size)
30  : Fragmenter(traf),
31  encryption_key_(encryption_key.Pass()),
32  nalu_length_size_(nalu_length_size),
33  clear_time_(clear_time) {
34  DCHECK(encryption_key_);
35 }
36 EncryptingFragmenter::~EncryptingFragmenter() {}
37 
38 
39 Status EncryptingFragmenter::AddSample(scoped_refptr<MediaSample> sample) {
40  DCHECK(sample);
41  if (!fragment_initialized()) {
42  Status status = InitializeFragment(sample->dts());
43  if (!status.ok())
44  return status;
45  }
46  if (encryptor_) {
47  Status status = EncryptSample(sample);
48  if (!status.ok())
49  return status;
50  }
51  return Fragmenter::AddSample(sample);
52 }
53 
55  Status status = Fragmenter::InitializeFragment(first_sample_dts);
56  if (!status.ok())
57  return status;
58 
59  traf()->auxiliary_size.sample_info_sizes.clear();
60  traf()->auxiliary_offset.offsets.clear();
61 
62  const bool enable_encryption = clear_time_ <= 0;
63  if (!enable_encryption) {
64  // This fragment should be in clear text.
65  // At most two sample description entries, an encrypted entry and a clear
66  // entry, are generated. The 1-based clear entry index is always 2.
67  const uint32_t kClearSampleDescriptionIndex = 2;
68 
69  traf()->header.flags |=
70  TrackFragmentHeader::kSampleDescriptionIndexPresentMask;
71  traf()->header.sample_description_index = kClearSampleDescriptionIndex;
72  }
73  return PrepareFragmentForEncryption(enable_encryption);
74 }
75 
77  if (encryptor_) {
78  DCHECK_LE(clear_time_, 0);
80  } else {
81  DCHECK_GT(clear_time_, 0);
82  clear_time_ -= fragment_duration();
83  }
85 }
86 
88  bool enable_encryption) {
89  return (!enable_encryption || encryptor_) ? Status::OK : CreateEncryptor();
90 }
91 
93  // The offset will be adjusted in Segmenter after knowing moof size.
94  traf()->auxiliary_offset.offsets.push_back(0);
95 
96  // Optimize saiz box.
97  SampleAuxiliaryInformationSize& saiz = traf()->auxiliary_size;
98  saiz.sample_count = traf()->runs[0].sample_sizes.size();
99  if (!saiz.sample_info_sizes.empty()) {
100  if (!OptimizeSampleEntries(&saiz.sample_info_sizes,
101  &saiz.default_sample_info_size)) {
102  saiz.default_sample_info_size = 0;
103  }
104  } else {
105  // |sample_info_sizes| table is filled in only for subsample encryption,
106  // otherwise |sample_info_size| is just the IV size.
107  DCHECK(!IsSubsampleEncryptionRequired());
108  saiz.default_sample_info_size = encryptor_->iv().size();
109  }
110 }
111 
113  DCHECK(encryption_key_);
114 
115  scoped_ptr<AesCtrEncryptor> encryptor(new AesCtrEncryptor());
116  const bool initialized = encryption_key_->iv.empty()
117  ? encryptor->InitializeWithRandomIv(
118  encryption_key_->key, kDefaultIvSize)
119  : encryptor->InitializeWithIv(
120  encryption_key_->key, encryption_key_->iv);
121  if (!initialized)
122  return Status(error::MUXER_FAILURE, "Failed to create the encryptor.");
123  encryptor_ = encryptor.Pass();
124  return Status::OK;
125 }
126 
127 void EncryptingFragmenter::EncryptBytes(uint8_t* data, uint32_t size) {
128  DCHECK(encryptor_);
129  CHECK(encryptor_->Encrypt(data, size, data));
130 }
131 
132 Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {
133  DCHECK(encryptor_);
134 
135  FrameCENCInfo cenc_info(encryptor_->iv());
136  uint8_t* data = sample->writable_data();
137  if (!IsSubsampleEncryptionRequired()) {
138  EncryptBytes(data, sample->data_size());
139  } else {
140  BufferReader reader(data, sample->data_size());
141  while (reader.HasBytes(1)) {
142  uint64_t nalu_length;
143  if (!reader.ReadNBytesInto8(&nalu_length, nalu_length_size_))
144  return Status(error::MUXER_FAILURE, "Fail to read nalu_length.");
145 
146  SubsampleEntry subsample;
147  subsample.clear_bytes = nalu_length_size_ + 1;
148  subsample.cipher_bytes = nalu_length - 1;
149  if (!reader.SkipBytes(nalu_length)) {
150  return Status(error::MUXER_FAILURE,
151  "Sample size does not match nalu_length.");
152  }
153 
154  EncryptBytes(data + subsample.clear_bytes, subsample.cipher_bytes);
155  cenc_info.AddSubsample(subsample);
156  data += nalu_length_size_ + nalu_length;
157  }
158 
159  // The length of per-sample auxiliary datum, defined in CENC ch. 7.
160  traf()->auxiliary_size.sample_info_sizes.push_back(cenc_info.ComputeSize());
161  }
162 
163  cenc_info.Write(aux_data());
164  encryptor_->UpdateIv();
165  return Status::OK;
166 }
167 
168 } // namespace mp4
169 } // namespace media
170 } // namespace edash_packager
Status InitializeFragment(int64_t first_sample_dts) override
virtual Status InitializeFragment(int64_t first_sample_dts)
Definition: fragmenter.cc:73
virtual Status AddSample(scoped_refptr< MediaSample > sample)
Definition: fragmenter.cc:36
bool OptimizeSampleEntries(std::vector< T > *entries, T *default_value)
Definition: fragmenter.h:90
Status AddSample(scoped_refptr< MediaSample > sample) override
void FinalizeFragment() override
Finalize and optimize the fragment.
virtual Status PrepareFragmentForEncryption(bool enable_encryption)
EncryptingFragmenter(TrackFragment *traf, scoped_ptr< EncryptionKey > encryption_key, int64_t clear_time, uint8_t nalu_length_size)
virtual void FinalizeFragmentForEncryption()
Finalize current fragment for encryption.
virtual void FinalizeFragment()
Finalize and optimize the fragment.
Definition: fragmenter.cc:91