7 #include "packager/media/formats/mp4/segmenter.h"
11 #include "packager/base/logging.h"
12 #include "packager/base/stl_util.h"
13 #include "packager/media/base/aes_cryptor.h"
14 #include "packager/media/base/buffer_writer.h"
15 #include "packager/media/base/key_source.h"
16 #include "packager/media/base/media_sample.h"
17 #include "packager/media/base/media_stream.h"
18 #include "packager/media/base/muxer_options.h"
19 #include "packager/media/base/muxer_util.h"
20 #include "packager/media/base/video_stream_info.h"
21 #include "packager/media/event/muxer_listener.h"
22 #include "packager/media/event/progress_listener.h"
23 #include "packager/media/formats/mp4/box_definitions.h"
24 #include "packager/media/formats/mp4/key_rotation_fragmenter.h"
25 #include "packager/version/version.h"
32 const size_t kCencKeyIdSize = 16u;
35 const int kCencSchemeVersion = 0x00010000;
38 const uint8_t kKeyRotationDefaultKeyId[] = {
39 0, 0, 0, 0, 0, 0, 0, 0,
40 0, 0, 0, 0, 0, 0, 0, 0
44 struct ProtectionPattern {
45 uint8_t crypt_byte_block;
46 uint8_t skip_byte_block;
49 COMPILE_ASSERT(arraysize(kKeyRotationDefaultKeyId) == kCencKeyIdSize,
50 cenc_key_id_must_be_size_16);
52 uint64_t Rescale(uint64_t time_in_old_scale,
55 return static_cast<double>(time_in_old_scale) / old_scale * new_scale;
58 ProtectionPattern GetProtectionPattern(FourCC protection_scheme,
59 TrackType track_type) {
60 ProtectionPattern pattern;
61 if (protection_scheme != FOURCC_cbcs && protection_scheme != FOURCC_cens) {
63 pattern.crypt_byte_block = 0u;
64 pattern.skip_byte_block = 0u;
65 }
else if (track_type != kVideo) {
73 pattern.crypt_byte_block = 1u;
74 pattern.skip_byte_block = 0u;
77 const uint8_t kCryptByteBlock = 1u;
78 const uint8_t kSkipByteBlock = 9u;
79 pattern.crypt_byte_block = kCryptByteBlock;
80 pattern.skip_byte_block = kSkipByteBlock;
85 void GenerateSinf(
const EncryptionKey& encryption_key,
87 FourCC protection_scheme,
88 ProtectionPattern pattern,
89 ProtectionSchemeInfo* sinf) {
90 sinf->format.format = old_type;
92 DCHECK_NE(protection_scheme, FOURCC_NULL);
93 sinf->type.type = protection_scheme;
94 sinf->type.version = kCencSchemeVersion;
96 auto& track_encryption = sinf->info.track_encryption;
97 track_encryption.default_is_protected = 1;
98 DCHECK(!encryption_key.iv.empty());
99 if (protection_scheme == FOURCC_cbcs) {
102 track_encryption.default_per_sample_iv_size = 0;
103 track_encryption.default_constant_iv = encryption_key.iv;
105 track_encryption.default_per_sample_iv_size =
106 static_cast<uint8_t
>(encryption_key.iv.size());
108 track_encryption.default_crypt_byte_block = pattern.crypt_byte_block;
109 track_encryption.default_skip_byte_block = pattern.skip_byte_block;
110 track_encryption.default_kid = encryption_key.key_id;
113 void GenerateEncryptedSampleEntry(
const EncryptionKey& encryption_key,
114 double clear_lead_in_seconds,
115 FourCC protection_scheme,
116 ProtectionPattern pattern,
117 SampleDescription* description) {
119 if (description->type == kVideo) {
120 DCHECK_EQ(1u, description->video_entries.size());
123 if (clear_lead_in_seconds > 0)
124 description->video_entries.push_back(description->video_entries[0]);
127 VideoSampleEntry& entry = description->video_entries[0];
128 GenerateSinf(encryption_key, entry.format, protection_scheme, pattern,
130 entry.format = FOURCC_encv;
132 DCHECK_EQ(kAudio, description->type);
133 DCHECK_EQ(1u, description->audio_entries.size());
136 if (clear_lead_in_seconds > 0)
137 description->audio_entries.push_back(description->audio_entries[0]);
140 AudioSampleEntry& entry = description->audio_entries[0];
141 GenerateSinf(encryption_key, entry.format, protection_scheme, pattern,
143 entry.format = FOURCC_enca;
149 Segmenter::Segmenter(
const MuxerOptions& options,
150 scoped_ptr<FileType> ftyp,
151 scoped_ptr<Movie> moov)
155 moof_(new MovieFragment()),
156 fragment_buffer_(new BufferWriter()),
157 sidx_(new SegmentIndex()),
158 muxer_listener_(NULL),
159 progress_listener_(NULL),
161 accumulated_progress_(0),
162 sample_duration_(0u) {}
164 Segmenter::~Segmenter() { STLDeleteElements(&fragmenters_); }
170 uint32_t max_sd_pixels,
171 double clear_lead_in_seconds,
172 double crypto_period_duration_in_seconds,
173 FourCC protection_scheme) {
174 DCHECK_LT(0u, streams.size());
175 muxer_listener_ = muxer_listener;
176 progress_listener_ = progress_listener;
177 moof_->header.sequence_number = 0;
179 moof_->tracks.resize(streams.size());
180 segment_durations_.resize(streams.size());
181 fragmenters_.resize(streams.size());
182 const bool key_rotation_enabled = crypto_period_duration_in_seconds != 0;
183 const bool kInitialEncryptionInfo =
true;
185 for (uint32_t i = 0; i < streams.size(); ++i) {
186 stream_map_[streams[i]] = i;
187 moof_->tracks[i].header.track_id = i + 1;
188 if (streams[i]->info()->stream_type() == kStreamVideo) {
190 if (sidx_->reference_id == 0)
191 sidx_->reference_id = i + 1;
193 if (!encryption_key_source) {
194 fragmenters_[i] =
new Fragmenter(streams[i]->info(), &moof_->tracks[i]);
198 KeySource::TrackType track_type =
199 GetTrackTypeForEncryption(*streams[i]->info(), max_sd_pixels);
201 moov_->tracks[i].media.information.sample_table.description;
202 ProtectionPattern pattern =
203 GetProtectionPattern(protection_scheme, description.type);
205 if (key_rotation_enabled) {
208 encryption_key.key_id.assign(
209 kKeyRotationDefaultKeyId,
210 kKeyRotationDefaultKeyId + arraysize(kKeyRotationDefaultKeyId));
212 &encryption_key.iv)) {
213 return Status(error::INTERNAL_ERROR,
"Failed to generate random iv.");
215 GenerateEncryptedSampleEntry(encryption_key, clear_lead_in_seconds,
216 protection_scheme, pattern, &description);
217 if (muxer_listener_) {
218 muxer_listener_->OnEncryptionInfoReady(
219 kInitialEncryptionInfo, protection_scheme, encryption_key.key_id,
220 encryption_key.iv, encryption_key.key_system_info);
224 moof_.get(), streams[i]->info(), &moof_->tracks[i],
225 encryption_key_source, track_type,
226 crypto_period_duration_in_seconds * streams[i]->info()->time_scale(),
227 clear_lead_in_seconds * streams[i]->info()->time_scale(),
228 protection_scheme, pattern.crypt_byte_block, pattern.skip_byte_block,
233 scoped_ptr<EncryptionKey> encryption_key(
new EncryptionKey());
235 encryption_key_source->
GetKey(track_type, encryption_key.get());
238 if (encryption_key->iv.empty()) {
240 &encryption_key->iv)) {
241 return Status(error::INTERNAL_ERROR,
"Failed to generate random iv.");
245 GenerateEncryptedSampleEntry(*encryption_key, clear_lead_in_seconds,
246 protection_scheme, pattern, &description);
248 if (moov_->pssh.empty()) {
249 moov_->pssh.resize(encryption_key->key_system_info.size());
250 for (
size_t i = 0; i < encryption_key->key_system_info.size(); i++) {
251 moov_->pssh[i].raw_box = encryption_key->key_system_info[i].CreateBox();
254 if (muxer_listener_) {
255 muxer_listener_->OnEncryptionInfoReady(
256 kInitialEncryptionInfo, protection_scheme, encryption_key->key_id,
257 encryption_key->iv, encryption_key->key_system_info);
262 streams[i]->info(), &moof_->tracks[i], encryption_key.Pass(),
263 clear_lead_in_seconds * streams[i]->info()->time_scale(),
264 protection_scheme, pattern.crypt_byte_block, pattern.skip_byte_block,
269 for (uint32_t i = 0; i < streams.size(); ++i)
270 fragmenters_[i]->set_use_decoding_timestamp_in_timeline(
true);
274 if (sidx_->reference_id == 0)
275 sidx_->reference_id = 1;
276 sidx_->timescale = streams[GetReferenceStreamId()]->info()->time_scale();
279 progress_target_ = streams[GetReferenceStreamId()]->info()->duration();
282 moov_->header.timescale = sidx_->timescale;
283 moof_->header.sequence_number = 1;
286 const std::string version = GetPackagerVersion();
287 if (!version.empty()) {
288 moov_->metadata.handler.handler_type = FOURCC_ID32;
289 moov_->metadata.id3v2.language.code =
"eng";
290 moov_->metadata.id3v2.private_frame.owner = GetPackagerProjectUrl();
291 moov_->metadata.id3v2.private_frame.value = version;
293 return DoInitialize();
297 for (std::vector<Fragmenter*>::iterator it = fragmenters_.begin();
298 it != fragmenters_.end();
300 Status status = FinalizeFragment(
true, *it);
308 for (std::vector<Track>::iterator track = moov_->tracks.begin();
309 track != moov_->tracks.end();
311 track->header.duration = Rescale(track->media.header.duration,
312 track->media.header.timescale,
313 moov_->header.timescale);
314 if (track->header.duration > moov_->header.duration)
315 moov_->header.duration = track->header.duration;
317 moov_->extends.header.fragment_duration = moov_->header.duration;
323 scoped_refptr<MediaSample> sample) {
326 DCHECK(stream_map_.find(stream) != stream_map_.end());
327 uint32_t stream_id = stream_map_[stream];
328 Fragmenter* fragmenter = fragmenters_[stream_id];
331 if (moov_->extends.tracks[stream_id].default_sample_duration == 0) {
332 moov_->extends.tracks[stream_id].default_sample_duration =
336 if (fragmenter->fragment_finalized()) {
337 return Status(error::FRAGMENT_FINALIZED,
338 "Current fragment is finalized already.");
341 bool finalize_fragment =
false;
342 if (fragmenter->fragment_duration() >=
345 finalize_fragment =
true;
348 bool finalize_segment =
false;
349 if (segment_durations_[stream_id] >=
352 finalize_segment =
true;
353 finalize_fragment =
true;
358 if (finalize_fragment) {
359 status = FinalizeFragment(finalize_segment, fragmenter);
368 if (sample_duration_ == 0)
369 sample_duration_ = sample->duration();
370 moov_->tracks[stream_id].media.header.duration += sample->duration();
371 segment_durations_[stream_id] += sample->duration();
372 DCHECK_GE(segment_durations_[stream_id], fragmenter->fragment_duration());
376 uint32_t Segmenter::GetReferenceTimeScale()
const {
377 return moov_->header.timescale;
381 if (moov_->header.timescale == 0) {
386 return static_cast<double>(moov_->header.duration) / moov_->header.timescale;
390 accumulated_progress_ += progress;
392 if (!progress_listener_)
return;
393 if (progress_target_ == 0)
return;
397 if (accumulated_progress_ >= progress_target_) {
400 progress_listener_->
OnProgress(static_cast<double>(accumulated_progress_) /
405 void Segmenter::SetComplete() {
406 if (!progress_listener_)
return;
410 Status Segmenter::FinalizeSegment() {
411 Status status = DoFinalizeSegment();
414 sidx_->references.clear();
415 std::vector<uint64_t>::iterator it = segment_durations_.begin();
416 for (; it != segment_durations_.end(); ++it)
422 uint32_t Segmenter::GetReferenceStreamId() {
424 return sidx_->reference_id - 1;
427 Status Segmenter::FinalizeFragment(
bool finalize_segment,
428 Fragmenter* fragmenter) {
429 fragmenter->FinalizeFragment();
432 for (std::vector<Fragmenter*>::iterator it = fragmenters_.begin();
433 it != fragmenters_.end();
435 if (!(*it)->fragment_finalized())
442 uint64_t data_offset = moof_->ComputeSize() + mdat.HeaderSize();
444 uint64_t next_traf_position = moof_->HeaderSize() + moof_->header.box_size();
445 for (
size_t i = 0; i < moof_->tracks.size(); ++i) {
446 TrackFragment& traf = moof_->tracks[i];
447 if (traf.auxiliary_offset.offsets.size() > 0) {
448 DCHECK_EQ(traf.auxiliary_offset.offsets.size(), 1u);
449 DCHECK(!traf.sample_encryption.sample_encryption_entries.empty());
451 next_traf_position += traf.box_size();
454 traf.auxiliary_offset.offsets[0] =
455 next_traf_position - traf.sample_encryption.box_size() +
456 traf.sample_encryption.HeaderSize() +
459 traf.runs[0].data_offset = data_offset + mdat.data_size;
460 mdat.data_size += fragmenters_[i]->data()->Size();
464 sidx_->references.resize(sidx_->references.size() + 1);
465 fragmenters_[GetReferenceStreamId()]->GenerateSegmentReference(
466 &sidx_->references[sidx_->references.size() - 1]);
467 sidx_->references[sidx_->references.size() - 1].referenced_size =
468 data_offset + mdat.data_size;
471 moof_->Write(fragment_buffer_.get());
472 mdat.WriteHeader(fragment_buffer_.get());
473 for (Fragmenter* fragmenter : fragmenters_)
474 fragment_buffer_->AppendBuffer(*fragmenter->data());
477 ++moof_->header.sequence_number;
479 if (finalize_segment)
480 return FinalizeSegment();