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/filters/nalu_reader.h"
14 #include "packager/media/filters/vp8_parser.h"
15 #include "packager/media/filters/vp9_parser.h"
16 #include "packager/media/formats/mp4/box_definitions.h"
17 
18 namespace {
19 // Generate 64bit IV by default.
20 const size_t kDefaultIvSize = 8u;
21 const size_t kCencBlockSize = 16u;
22 } // namespace
23 
24 namespace edash_packager {
25 namespace media {
26 namespace mp4 {
27 
29  TrackFragment* traf,
30  scoped_ptr<EncryptionKey> encryption_key,
31  int64_t clear_time,
32  VideoCodec video_codec,
33  uint8_t nalu_length_size)
34  : Fragmenter(traf),
35  encryption_key_(encryption_key.Pass()),
36  video_codec_(video_codec),
37  nalu_length_size_(nalu_length_size),
38  clear_time_(clear_time) {
39  DCHECK(encryption_key_);
40  if (video_codec == kCodecVP8) {
41  vpx_parser_.reset(new VP8Parser);
42  } else if (video_codec == kCodecVP9) {
43  vpx_parser_.reset(new VP9Parser);
44  }
45 }
46 
47 EncryptingFragmenter::~EncryptingFragmenter() {}
48 
49 Status EncryptingFragmenter::AddSample(scoped_refptr<MediaSample> sample) {
50  DCHECK(sample);
51  if (!fragment_initialized()) {
52  Status status = InitializeFragment(sample->dts());
53  if (!status.ok())
54  return status;
55  }
56  if (encryptor_) {
57  Status status = EncryptSample(sample);
58  if (!status.ok())
59  return status;
60  }
61  return Fragmenter::AddSample(sample);
62 }
63 
65  Status status = Fragmenter::InitializeFragment(first_sample_dts);
66  if (!status.ok())
67  return status;
68 
69  traf()->auxiliary_size.sample_info_sizes.clear();
70  traf()->auxiliary_offset.offsets.clear();
71  if (IsSubsampleEncryptionRequired()) {
72  traf()->sample_encryption.flags |=
73  SampleEncryption::kUseSubsampleEncryption;
74  }
75  traf()->sample_encryption.sample_encryption_entries.clear();
76 
77  const bool enable_encryption = clear_time_ <= 0;
78  if (!enable_encryption) {
79  // This fragment should be in clear text.
80  // At most two sample description entries, an encrypted entry and a clear
81  // entry, are generated. The 1-based clear entry index is always 2.
82  const uint32_t kClearSampleDescriptionIndex = 2;
83 
84  traf()->header.flags |=
85  TrackFragmentHeader::kSampleDescriptionIndexPresentMask;
86  traf()->header.sample_description_index = kClearSampleDescriptionIndex;
87  }
88  return PrepareFragmentForEncryption(enable_encryption);
89 }
90 
92  if (encryptor_) {
93  DCHECK_LE(clear_time_, 0);
95  } else {
96  DCHECK_GT(clear_time_, 0);
97  clear_time_ -= fragment_duration();
98  }
100 }
101 
103  bool enable_encryption) {
104  return (!enable_encryption || encryptor_) ? Status::OK : CreateEncryptor();
105 }
106 
108  // The offset will be adjusted in Segmenter after knowing moof size.
109  traf()->auxiliary_offset.offsets.push_back(0);
110 
111  // Optimize saiz box.
112  SampleAuxiliaryInformationSize& saiz = traf()->auxiliary_size;
113  saiz.sample_count = traf()->runs[0].sample_sizes.size();
114  if (!saiz.sample_info_sizes.empty()) {
115  if (!OptimizeSampleEntries(&saiz.sample_info_sizes,
116  &saiz.default_sample_info_size)) {
117  saiz.default_sample_info_size = 0;
118  }
119  } else {
120  // |sample_info_sizes| table is filled in only for subsample encryption,
121  // otherwise |sample_info_size| is just the IV size.
122  DCHECK(!IsSubsampleEncryptionRequired());
123  saiz.default_sample_info_size = encryptor_->iv().size();
124  }
125  traf()->sample_encryption.iv_size = encryptor_->iv().size();
126 }
127 
129  DCHECK(encryption_key_);
130 
131  scoped_ptr<AesCtrEncryptor> encryptor(new AesCtrEncryptor());
132  const bool initialized = encryption_key_->iv.empty()
133  ? encryptor->InitializeWithRandomIv(
134  encryption_key_->key, kDefaultIvSize)
135  : encryptor->InitializeWithIv(
136  encryption_key_->key, encryption_key_->iv);
137  if (!initialized)
138  return Status(error::MUXER_FAILURE, "Failed to create the encryptor.");
139  encryptor_ = encryptor.Pass();
140  return Status::OK;
141 }
142 
143 void EncryptingFragmenter::EncryptBytes(uint8_t* data, uint32_t size) {
144  DCHECK(encryptor_);
145  CHECK(encryptor_->Encrypt(data, size, data));
146 }
147 
148 Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {
149  DCHECK(encryptor_);
150 
151  SampleEncryptionEntry sample_encryption_entry;
152  sample_encryption_entry.initialization_vector = encryptor_->iv();
153  uint8_t* data = sample->writable_data();
154  if (IsSubsampleEncryptionRequired()) {
155  if (vpx_parser_) {
156  std::vector<VPxFrameInfo> vpx_frames;
157  if (!vpx_parser_->Parse(sample->data(), sample->data_size(),
158  &vpx_frames)) {
159  return Status(error::MUXER_FAILURE, "Failed to parse vpx frame.");
160  }
161 
162  const bool is_superframe = vpx_frames.size() > 1;
163  for (const VPxFrameInfo& frame : vpx_frames) {
164  SubsampleEntry subsample;
165  subsample.clear_bytes = frame.uncompressed_header_size;
166  subsample.cipher_bytes =
167  frame.frame_size - frame.uncompressed_header_size;
168 
169  // "VP Codec ISO Media File Format Binding" document requires that the
170  // encrypted bytes of each frame within the superframe must be block
171  // aligned so that the counter state can be computed for each frame
172  // within the superframe.
173  if (is_superframe) {
174  uint16_t misalign_bytes = subsample.cipher_bytes % kCencBlockSize;
175  subsample.clear_bytes += misalign_bytes;
176  subsample.cipher_bytes -= misalign_bytes;
177  }
178 
179  sample_encryption_entry.subsamples.push_back(subsample);
180  if (subsample.cipher_bytes > 0)
181  EncryptBytes(data + subsample.clear_bytes, subsample.cipher_bytes);
182  data += frame.frame_size;
183  }
184  } else {
185  NaluReader reader(nalu_length_size_, data, sample->data_size());
186 
187  Nalu nalu;
188  NaluReader::Result result;
189  while ((result = reader.Advance(&nalu)) == NaluReader::kOk) {
190  SubsampleEntry subsample;
191  subsample.clear_bytes = nalu.header_size();
192  subsample.cipher_bytes = nalu.data_size();
193  sample_encryption_entry.subsamples.push_back(subsample);
194 
195  EncryptBytes(const_cast<uint8_t*>(nalu.data() + nalu.header_size()),
196  subsample.cipher_bytes);
197  }
198  if (result != NaluReader::kEOStream)
199  return Status(error::MUXER_FAILURE, "Failed to parse NAL units.");
200  }
201 
202  // The length of per-sample auxiliary datum, defined in CENC ch. 7.
203  traf()->auxiliary_size.sample_info_sizes.push_back(
204  sample_encryption_entry.ComputeSize());
205  } else {
206  EncryptBytes(data, sample->data_size());
207  }
208 
209  traf()->sample_encryption.sample_encryption_entries.push_back(
210  sample_encryption_entry);
211  encryptor_->UpdateIv();
212  return Status::OK;
213 }
214 
215 } // namespace mp4
216 } // namespace media
217 } // namespace edash_packager
EncryptingFragmenter(TrackFragment *traf, scoped_ptr< EncryptionKey > encryption_key, int64_t clear_time, VideoCodec video_codec, uint8_t nalu_length_size)
Status InitializeFragment(int64_t first_sample_dts) override
virtual Status InitializeFragment(int64_t first_sample_dts)
Definition: fragmenter.cc:76
virtual Status AddSample(scoped_refptr< MediaSample > sample)
Definition: fragmenter.cc:36
Class to parse a vp9 bit stream.
Definition: vp9_parser.h:20
bool OptimizeSampleEntries(std::vector< T > *entries, T *default_value)
Definition: fragmenter.h:89
Status AddSample(scoped_refptr< MediaSample > sample) override
void FinalizeFragment() override
Finalize and optimize the fragment.
virtual Status PrepareFragmentForEncryption(bool enable_encryption)
virtual void FinalizeFragmentForEncryption()
Finalize current fragment for encryption.
virtual void FinalizeFragment()
Finalize and optimize the fragment.
Definition: fragmenter.cc:93