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/id3_tag.h" 14 #include "packager/media/base/media_sample.h" 15 #include "packager/media/base/muxer_options.h" 16 #include "packager/media/base/muxer_util.h" 17 #include "packager/media/base/stream_info.h" 18 #include "packager/media/chunking/chunking_handler.h" 19 #include "packager/media/event/progress_listener.h" 20 #include "packager/media/formats/mp4/box_definitions.h" 21 #include "packager/media/formats/mp4/fragmenter.h" 22 #include "packager/media/formats/mp4/key_frame_info.h" 23 #include "packager/version/version.h" 31 uint64_t Rescale(uint64_t time_in_old_scale,
34 return static_cast<double>(time_in_old_scale) / old_scale * new_scale;
39 Segmenter::Segmenter(
const MuxerOptions& options,
40 std::unique_ptr<FileType> ftyp,
41 std::unique_ptr<Movie> moov)
43 ftyp_(
std::move(ftyp)),
44 moov_(
std::move(moov)),
45 moof_(new MovieFragment()),
46 fragment_buffer_(new BufferWriter()),
47 sidx_(new SegmentIndex()) {}
49 Segmenter::~Segmenter() {}
52 const std::vector<std::shared_ptr<const StreamInfo>>& streams,
55 DCHECK_LT(0u, streams.size());
56 muxer_listener_ = muxer_listener;
57 progress_listener_ = progress_listener;
58 moof_->header.sequence_number = 0;
60 moof_->tracks.resize(streams.size());
61 fragmenters_.resize(streams.size());
62 stream_durations_.resize(streams.size());
64 for (uint32_t i = 0; i < streams.size(); ++i) {
65 moof_->tracks[i].header.track_id = i + 1;
66 if (streams[i]->stream_type() == kStreamVideo) {
68 if (sidx_->reference_id == 0)
69 sidx_->reference_id = i + 1;
71 fragmenters_[i].reset(
new Fragmenter(streams[i], &moof_->tracks[i]));
74 if (options_.mp4_params.use_decoding_timestamp_in_timeline) {
75 for (uint32_t i = 0; i < streams.size(); ++i)
76 fragmenters_[i]->set_use_decoding_timestamp_in_timeline(
true);
79 if (options_.output_file_index == 0) {
80 for (uint32_t i = 0; i < streams.size(); ++i)
81 fragmenters_[i]->set_allow_adjust_earliest_presentation_time(
true);
85 if (sidx_->reference_id == 0)
86 sidx_->reference_id = 1;
87 sidx_->timescale = streams[GetReferenceStreamId()]->time_scale();
90 progress_target_ = streams[GetReferenceStreamId()]->duration();
93 moov_->header.timescale = sidx_->timescale;
94 moof_->header.sequence_number = 1;
97 const std::string version = GetPackagerVersion();
98 if (!version.empty()) {
99 moov_->metadata.handler.handler_type = FOURCC_ID32;
100 moov_->metadata.id3v2.language.code =
"eng";
104 CHECK(id3_tag.
WriteToVector(&moov_->metadata.id3v2.id3v2_data));
106 return DoInitialize();
113 moov_->extends.header.fragment_duration = 0;
114 for (
size_t i = 0; i < stream_durations_.size(); ++i) {
116 Rescale(stream_durations_[i], moov_->tracks[i].media.header.timescale,
117 moov_->header.timescale);
118 if (duration > moov_->extends.header.fragment_duration)
119 moov_->extends.header.fragment_duration = duration;
126 if (moov_->extends.tracks[stream_id].default_sample_duration == 0) {
127 moov_->extends.tracks[stream_id].default_sample_duration =
131 DCHECK_LT(stream_id, fragmenters_.size());
132 Fragmenter* fragmenter = fragmenters_[stream_id].get();
133 if (fragmenter->fragment_finalized()) {
134 return Status(error::FRAGMENT_FINALIZED,
135 "Current fragment is finalized already.");
138 Status status = fragmenter->AddSample(sample);
142 if (sample_duration_ == 0)
143 sample_duration_ = sample.duration();
144 stream_durations_[stream_id] += sample.duration();
150 if (segment_info.key_rotation_encryption_config) {
151 FinalizeFragmentForKeyRotation(
152 stream_id, segment_info.is_encrypted,
153 *segment_info.key_rotation_encryption_config);
156 DCHECK_LT(stream_id, fragmenters_.size());
157 Fragmenter* fragmenter = fragmenters_[stream_id].get();
159 Status status = fragmenter->FinalizeFragment();
164 for (
const std::unique_ptr<Fragmenter>& fragmenter : fragmenters_) {
165 if (!fragmenter->fragment_finalized())
174 uint64_t next_traf_position = moof_->HeaderSize() + moof_->header.box_size();
175 for (
size_t i = 0; i < moof_->tracks.size(); ++i) {
177 if (traf.auxiliary_offset.offsets.size() > 0) {
178 DCHECK_EQ(traf.auxiliary_offset.offsets.size(), 1u);
179 DCHECK(!traf.sample_encryption.sample_encryption_entries.empty());
181 next_traf_position += traf.
box_size();
184 traf.auxiliary_offset.offsets[0] =
185 next_traf_position - traf.sample_encryption.
box_size() +
189 traf.runs[0].data_offset = data_offset + mdat.data_size;
190 mdat.data_size +=
static_cast<uint32_t
>(fragmenters_[i]->data()->Size());
194 sidx_->references.resize(sidx_->references.size() + 1);
195 fragmenters_[GetReferenceStreamId()]->GenerateSegmentReference(
196 &sidx_->references[sidx_->references.size() - 1]);
197 sidx_->references[sidx_->references.size() - 1].referenced_size =
198 data_offset + mdat.data_size;
200 const uint64_t moof_start_offset = fragment_buffer_->Size();
203 moof_->Write(fragment_buffer_.get());
206 bool first_key_frame =
true;
207 for (
const std::unique_ptr<Fragmenter>& fragmenter : fragmenters_) {
212 if (!fragmenter->key_frame_infos().empty() && first_key_frame) {
214 fragmenter->key_frame_infos().front();
215 first_key_frame =
false;
216 key_frame_infos_.push_back(
217 {key_frame_info.timestamp, moof_start_offset,
218 fragment_buffer_->Size() - moof_start_offset + key_frame_info.size});
220 fragment_buffer_->AppendBuffer(*fragmenter->data());
224 ++moof_->header.sequence_number;
226 for (std::unique_ptr<Fragmenter>& fragmenter : fragmenters_)
227 fragmenter->ClearFragmentFinalized();
228 if (!segment_info.is_subsegment) {
229 Status status = DoFinalizeSegment();
231 sidx_->references.clear();
232 key_frame_infos_.clear();
238 uint32_t Segmenter::GetReferenceTimeScale()
const {
239 return moov_->header.timescale;
242 double Segmenter::GetDuration()
const {
243 uint64_t duration = moov_->extends.header.fragment_duration;
248 return static_cast<double>(duration) / moov_->header.timescale;
252 accumulated_progress_ += progress;
254 if (!progress_listener_)
return;
255 if (progress_target_ == 0)
return;
259 if (accumulated_progress_ >= progress_target_) {
260 progress_listener_->OnProgress(1.0);
262 progress_listener_->OnProgress(static_cast<double>(accumulated_progress_) /
267 void Segmenter::SetComplete() {
268 if (!progress_listener_)
return;
269 progress_listener_->OnProgress(1.0);
272 uint32_t Segmenter::GetReferenceStreamId() {
274 return sidx_->reference_id - 1;
277 void Segmenter::FinalizeFragmentForKeyRotation(
279 bool fragment_encrypted,
281 if (options_.mp4_params.include_pssh_in_stream) {
282 const std::vector<ProtectionSystemSpecificInfo>& system_info =
283 encryption_config.key_system_info;
284 moof_->pssh.resize(system_info.size());
285 for (
size_t i = 0; i < system_info.size(); i++)
286 moof_->pssh[i].raw_box = system_info[i].psshs;
289 <<
"Key rotation and no pssh in stream may not work well together.";
299 if (!fragment_encrypted)
302 DCHECK_LT(stream_id, moof_->tracks.size());
304 traf.sample_group_descriptions.resize(traf.sample_group_descriptions.size() +
307 traf.sample_group_descriptions.back();
308 sample_group_description.grouping_type = FOURCC_seig;
310 sample_group_description.cenc_sample_encryption_info_entries.resize(1);
312 sample_group_description.cenc_sample_encryption_info_entries.back();
313 sample_group_entry.is_protected = 1;
314 sample_group_entry.per_sample_iv_size = encryption_config.per_sample_iv_size;
315 sample_group_entry.constant_iv = encryption_config.constant_iv;
316 sample_group_entry.crypt_byte_block = encryption_config.crypt_byte_block;
317 sample_group_entry.skip_byte_block = encryption_config.skip_byte_block;
318 sample_group_entry.key_id = encryption_config.key_id;
All the methods that are virtual are virtual for mocking.