7 #include "packager/media/formats/mp4/segmenter.h"
11 #include "packager/base/logging.h"
12 #include "packager/media/base/buffer_writer.h"
13 #include "packager/media/base/media_sample.h"
14 #include "packager/media/base/muxer_options.h"
15 #include "packager/media/base/muxer_util.h"
16 #include "packager/media/base/stream_info.h"
17 #include "packager/media/chunking/chunking_handler.h"
18 #include "packager/media/event/progress_listener.h"
19 #include "packager/media/formats/mp4/box_definitions.h"
20 #include "packager/media/formats/mp4/fragmenter.h"
21 #include "packager/version/version.h"
29 uint64_t Rescale(uint64_t time_in_old_scale,
32 return static_cast<double>(time_in_old_scale) / old_scale * new_scale;
37 Segmenter::Segmenter(
const MuxerOptions& options,
38 std::unique_ptr<FileType> ftyp,
39 std::unique_ptr<Movie> moov)
41 ftyp_(std::move(ftyp)),
42 moov_(std::move(moov)),
43 moof_(new MovieFragment()),
44 fragment_buffer_(new BufferWriter()),
45 sidx_(new SegmentIndex()),
46 progress_listener_(NULL),
48 accumulated_progress_(0),
49 sample_duration_(0u) {}
51 Segmenter::~Segmenter() {}
54 const std::vector<std::shared_ptr<StreamInfo>>& streams,
57 DCHECK_LT(0u, streams.size());
58 muxer_listener_ = muxer_listener;
59 progress_listener_ = progress_listener;
60 moof_->header.sequence_number = 0;
62 moof_->tracks.resize(streams.size());
63 fragmenters_.resize(streams.size());
65 for (uint32_t i = 0; i < streams.size(); ++i) {
66 moof_->tracks[i].header.track_id = i + 1;
67 if (streams[i]->stream_type() == kStreamVideo) {
69 if (sidx_->reference_id == 0)
70 sidx_->reference_id = i + 1;
72 fragmenters_[i].reset(
new Fragmenter(streams[i], &moof_->tracks[i]));
76 for (uint32_t i = 0; i < streams.size(); ++i)
77 fragmenters_[i]->set_use_decoding_timestamp_in_timeline(
true);
81 if (sidx_->reference_id == 0)
82 sidx_->reference_id = 1;
83 sidx_->timescale = streams[GetReferenceStreamId()]->time_scale();
86 progress_target_ = streams[GetReferenceStreamId()]->duration();
89 moov_->header.timescale = sidx_->timescale;
90 moof_->header.sequence_number = 1;
93 const std::string version = GetPackagerVersion();
94 if (!version.empty()) {
95 moov_->metadata.handler.handler_type = FOURCC_ID32;
96 moov_->metadata.id3v2.language.code =
"eng";
97 moov_->metadata.id3v2.private_frame.owner = GetPackagerProjectUrl();
98 moov_->metadata.id3v2.private_frame.value = version;
100 return DoInitialize();
107 for (std::vector<Track>::iterator track = moov_->tracks.begin();
108 track != moov_->tracks.end();
110 track->header.duration = Rescale(track->media.header.duration,
111 track->media.header.timescale,
112 moov_->header.timescale);
113 if (track->header.duration > moov_->header.duration)
114 moov_->header.duration = track->header.duration;
116 moov_->extends.header.fragment_duration = moov_->header.duration;
122 std::shared_ptr<MediaSample> sample) {
124 if (moov_->extends.tracks[stream_id].default_sample_duration == 0) {
125 moov_->extends.tracks[stream_id].default_sample_duration =
129 DCHECK_LT(stream_id, fragmenters_.size());
130 Fragmenter* fragmenter = fragmenters_[stream_id].get();
131 if (fragmenter->fragment_finalized()) {
132 return Status(error::FRAGMENT_FINALIZED,
133 "Current fragment is finalized already.");
136 Status status = fragmenter->AddSample(sample);
140 if (sample_duration_ == 0)
141 sample_duration_ = sample->duration();
142 moov_->tracks[stream_id].media.header.duration += sample->duration();
147 std::shared_ptr<SegmentInfo> segment_info) {
148 if (segment_info->key_rotation_encryption_config) {
149 FinalizeFragmentForKeyRotation(
150 stream_id, segment_info->is_encrypted,
151 *segment_info->key_rotation_encryption_config);
154 DCHECK_LT(stream_id, fragmenters_.size());
155 Fragmenter* fragmenter = fragmenters_[stream_id].get();
157 Status status = fragmenter->FinalizeFragment();
162 for (
const std::unique_ptr<Fragmenter>& fragmenter : fragmenters_) {
163 if (!fragmenter->fragment_finalized())
172 uint64_t next_traf_position = moof_->HeaderSize() + moof_->header.box_size();
173 for (
size_t i = 0; i < moof_->tracks.size(); ++i) {
175 if (traf.auxiliary_offset.offsets.size() > 0) {
176 DCHECK_EQ(traf.auxiliary_offset.offsets.size(), 1u);
177 DCHECK(!traf.sample_encryption.sample_encryption_entries.empty());
179 next_traf_position += traf.
box_size();
182 traf.auxiliary_offset.offsets[0] =
183 next_traf_position - traf.sample_encryption.
box_size() +
187 traf.runs[0].data_offset = data_offset + mdat.data_size;
188 mdat.data_size +=
static_cast<uint32_t
>(fragmenters_[i]->data()->Size());
192 sidx_->references.resize(sidx_->references.size() + 1);
193 fragmenters_[GetReferenceStreamId()]->GenerateSegmentReference(
194 &sidx_->references[sidx_->references.size() - 1]);
195 sidx_->references[sidx_->references.size() - 1].referenced_size =
196 data_offset + mdat.data_size;
199 moof_->Write(fragment_buffer_.get());
201 for (
const std::unique_ptr<Fragmenter>& fragmenter : fragmenters_)
202 fragment_buffer_->AppendBuffer(*fragmenter->data());
205 ++moof_->header.sequence_number;
207 for (std::unique_ptr<Fragmenter>& fragmenter : fragmenters_)
208 fragmenter->ClearFragmentFinalized();
209 if (!segment_info->is_subsegment) {
210 Status status = DoFinalizeSegment();
212 sidx_->references.clear();
218 uint32_t Segmenter::GetReferenceTimeScale()
const {
219 return moov_->header.timescale;
223 if (moov_->header.timescale == 0) {
228 return static_cast<double>(moov_->header.duration) / moov_->header.timescale;
232 accumulated_progress_ += progress;
234 if (!progress_listener_)
return;
235 if (progress_target_ == 0)
return;
239 if (accumulated_progress_ >= progress_target_) {
242 progress_listener_->
OnProgress(static_cast<double>(accumulated_progress_) /
247 void Segmenter::SetComplete() {
248 if (!progress_listener_)
return;
252 uint32_t Segmenter::GetReferenceStreamId() {
254 return sidx_->reference_id - 1;
257 void Segmenter::FinalizeFragmentForKeyRotation(
259 bool fragment_encrypted,
261 const std::vector<ProtectionSystemSpecificInfo>& system_info =
262 encryption_config.key_system_info;
263 moof_->pssh.resize(system_info.size());
264 for (
size_t i = 0; i < system_info.size(); i++)
265 moof_->pssh[i].raw_box = system_info[i].CreateBox();
274 if (!fragment_encrypted)
277 DCHECK_LT(stream_id, moof_->tracks.size());
278 TrackFragment& traf = moof_->tracks[stream_id];
279 traf.sample_group_descriptions.resize(traf.sample_group_descriptions.size() +
281 SampleGroupDescription& sample_group_description =
282 traf.sample_group_descriptions.back();
283 sample_group_description.grouping_type = FOURCC_seig;
285 sample_group_description.cenc_sample_encryption_info_entries.resize(1);
286 CencSampleEncryptionInfoEntry& sample_group_entry =
287 sample_group_description.cenc_sample_encryption_info_entries.back();
288 sample_group_entry.is_protected = 1;
289 sample_group_entry.per_sample_iv_size = encryption_config.per_sample_iv_size;
290 sample_group_entry.constant_iv = encryption_config.constant_iv;
291 sample_group_entry.crypt_byte_block = encryption_config.crypt_byte_block;
292 sample_group_entry.skip_byte_block = encryption_config.skip_byte_block;
293 sample_group_entry.key_id = encryption_config.key_id;