7#include <packager/media/formats/mp4/fragmenter.h>
14#include <absl/log/check.h>
15#include <absl/log/log.h>
17#include <packager/macros/status.h>
18#include <packager/media/base/audio_stream_info.h>
19#include <packager/media/base/buffer_writer.h>
20#include <packager/media/base/decrypt_config.h>
21#include <packager/media/base/fourccs.h>
22#include <packager/media/base/media_sample.h>
23#include <packager/media/base/stream_info.h>
24#include <packager/media/formats/mp4/box_definitions.h>
25#include <packager/status.h>
32const int64_t kInvalidTime = std::numeric_limits<int64_t>::max();
34int64_t GetSeekPreroll(
const StreamInfo& stream_info) {
35 if (stream_info.stream_type() != kStreamAudio)
37 const AudioStreamInfo& audio_stream_info =
38 static_cast<const AudioStreamInfo&
>(stream_info);
39 return audio_stream_info.seek_preroll_ns();
42void NewSampleEncryptionEntry(
const DecryptConfig& decrypt_config,
44 TrackFragment* traf) {
45 SampleEncryption& sample_encryption = traf->sample_encryption;
46 SampleEncryptionEntry sample_encryption_entry;
48 sample_encryption_entry.initialization_vector = decrypt_config.iv();
49 sample_encryption_entry.subsamples = decrypt_config.subsamples();
50 sample_encryption.sample_encryption_entries.push_back(
51 sample_encryption_entry);
52 traf->auxiliary_size.sample_info_sizes.push_back(
53 sample_encryption_entry.ComputeSize());
60 int64_t edit_list_offset)
61 : stream_info_(std::move(stream_info)),
63 edit_list_offset_(edit_list_offset),
64 seek_preroll_(GetSeekPreroll(*stream_info_)),
65 earliest_presentation_time_(kInvalidTime),
66 first_sap_time_(kInvalidTime) {
71Fragmenter::~Fragmenter() {}
74 const int64_t pts = sample.pts();
75 const int64_t dts = sample.dts();
76 const int64_t duration = sample.duration();
78 LOG(WARNING) <<
"Unexpected sample with zero duration @ dts " << dts;
80 if (!fragment_initialized_)
83 if (sample.side_data_size() > 0)
84 LOG(WARNING) <<
"MP4 samples do not support side data. Side data ignored.";
87 traf_->runs[0].sample_sizes.push_back(
88 static_cast<uint32_t
>(sample.data_size()));
89 traf_->runs[0].sample_durations.push_back(duration);
90 traf_->runs[0].sample_flags.push_back(
91 sample.is_key_frame() ? TrackFragmentHeader::kUnset
92 : TrackFragmentHeader::kNonKeySampleMask);
94 if (sample.decrypt_config()) {
95 NewSampleEncryptionEntry(
96 *sample.decrypt_config(),
97 !stream_info_->encryption_config().constant_iv.empty(), traf_);
100 if (stream_info_->stream_type() == StreamType::kStreamVideo &&
101 sample.is_key_frame()) {
102 key_frame_infos_.push_back({pts, data_->Size(), sample.data_size()});
105 data_->AppendArray(sample.data(), sample.data_size());
107 traf_->runs[0].sample_composition_time_offsets.push_back(pts - dts);
109 traf_->runs[0].flags |= TrackFragmentRun::kSampleCompTimeOffsetsPresentMask;
114 const int64_t end_pts = pts + duration;
117 fragment_duration_ += end_pts;
119 earliest_presentation_time_ = 0;
120 if (sample.is_key_frame())
124 fragment_duration_ += duration;
126 if (earliest_presentation_time_ > pts)
127 earliest_presentation_time_ = pts;
129 if (sample.is_key_frame()) {
130 if (first_sap_time_ == kInvalidTime)
131 first_sap_time_ = pts;
138 fragment_initialized_ =
true;
139 fragment_finalized_ =
false;
144 const int64_t dts_before_edit = first_sample_dts + edit_list_offset_;
145 traf_->decode_time.decode_time = dts_before_edit;
148 traf_->runs.resize(1);
149 traf_->runs[0].flags = TrackFragmentRun::kDataOffsetPresentMask;
150 traf_->auxiliary_size.sample_info_sizes.clear();
151 traf_->auxiliary_offset.offsets.clear();
152 traf_->sample_encryption.sample_encryption_entries.clear();
153 traf_->sample_group_descriptions.clear();
154 traf_->sample_to_groups.clear();
155 traf_->header.sample_description_index = 1;
156 traf_->header.flags = TrackFragmentHeader::kDefaultBaseIsMoofMask |
157 TrackFragmentHeader::kSampleDescriptionIndexPresentMask;
159 fragment_duration_ = 0;
160 earliest_presentation_time_ = kInvalidTime;
161 first_sap_time_ = kInvalidTime;
163 key_frame_infos_.clear();
168 if (!fragment_initialized_)
171 if (stream_info_->is_encrypted()) {
172 Status status = FinalizeFragmentForEncryption();
178 traf_->runs[0].sample_count =
179 static_cast<uint32_t
>(traf_->runs[0].sample_sizes.size());
181 &traf_->header.default_sample_duration)) {
182 traf_->header.flags |=
183 TrackFragmentHeader::kDefaultSampleDurationPresentMask;
185 traf_->runs[0].flags |= TrackFragmentRun::kSampleDurationPresentMask;
188 &traf_->header.default_sample_size)) {
189 traf_->header.flags |= TrackFragmentHeader::kDefaultSampleSizePresentMask;
191 traf_->runs[0].flags |= TrackFragmentRun::kSampleSizePresentMask;
194 &traf_->header.default_sample_flags)) {
195 traf_->header.flags |= TrackFragmentHeader::kDefaultSampleFlagsPresentMask;
197 traf_->runs[0].flags |= TrackFragmentRun::kSampleFlagsPresentMask;
205 DCHECK_EQ(traf_->sample_to_groups.size(), 0u);
206 if (seek_preroll_ > 0) {
207 traf_->sample_to_groups.resize(traf_->sample_to_groups.size() + 1);
208 SampleToGroup& sample_to_group = traf_->sample_to_groups.back();
209 sample_to_group.grouping_type = FOURCC_roll;
211 sample_to_group.entries.resize(1);
213 sample_to_group_entry.sample_count = traf_->runs[0].sample_count;
214 sample_to_group_entry.group_description_index =
215 SampleToGroupEntry::kTrackGroupDescriptionIndexBase + 1;
217 for (
const auto& sample_group_description :
218 traf_->sample_group_descriptions) {
219 traf_->sample_to_groups.resize(traf_->sample_to_groups.size() + 1);
220 SampleToGroup& sample_to_group = traf_->sample_to_groups.back();
221 sample_to_group.grouping_type = sample_group_description.grouping_type;
223 sample_to_group.entries.resize(1);
225 sample_to_group_entry.sample_count = traf_->runs[0].sample_count;
226 sample_to_group_entry.group_description_index =
227 SampleToGroupEntry::kTrackFragmentGroupDescriptionIndexBase + 1;
230 fragment_finalized_ =
true;
231 fragment_initialized_ =
false;
237 reference->reference_type =
false;
238 reference->subsegment_duration = fragment_duration_;
239 reference->starts_with_sap = StartsWithSAP();
240 if (kInvalidTime == first_sap_time_) {
241 reference->sap_type = SegmentReference::TypeUnknown;
242 reference->sap_delta_time = 0;
244 reference->sap_type = SegmentReference::Type1;
245 reference->sap_delta_time = first_sap_time_ - earliest_presentation_time_;
247 reference->earliest_presentation_time = earliest_presentation_time_;
250Status Fragmenter::FinalizeFragmentForEncryption() {
252 if (sample_encryption.sample_encryption_entries.empty()) {
256 const uint32_t kClearSampleDescriptionIndex = 2;
257 traf_->header.sample_description_index = kClearSampleDescriptionIndex;
260 if (sample_encryption.sample_encryption_entries.size() !=
261 traf_->runs[0].sample_sizes.size()) {
262 LOG(ERROR) <<
"Partially encrypted segment is not supported";
263 return Status(error::MUXER_FAILURE,
264 "Partially encrypted segment is not supported.");
267 const SampleEncryptionEntry& sample_encryption_entry =
268 sample_encryption.sample_encryption_entries.front();
269 const bool use_subsample_encryption =
270 !sample_encryption_entry.subsamples.empty();
271 if (use_subsample_encryption)
272 traf_->sample_encryption.flags |= SampleEncryption::kUseSubsampleEncryption;
273 traf_->sample_encryption.iv_size =
static_cast<uint8_t
>(
274 sample_encryption_entry.initialization_vector.size());
277 traf_->auxiliary_offset.offsets.push_back(0);
280 SampleAuxiliaryInformationSize& saiz = traf_->auxiliary_size;
281 saiz.sample_count =
static_cast<uint32_t
>(saiz.sample_info_sizes.size());
282 DCHECK_EQ(saiz.sample_info_sizes.size(),
283 traf_->sample_encryption.sample_encryption_entries.size());
285 &saiz.default_sample_info_size)) {
286 saiz.default_sample_info_size = 0;
291 if (saiz.default_sample_info_size == 0 && saiz.sample_info_sizes.empty()) {
292 DCHECK(!use_subsample_encryption);
296 saiz.sample_count = 0;
297 traf_->auxiliary_offset.offsets.clear();
302bool Fragmenter::StartsWithSAP()
const {
303 DCHECK(!traf_->runs.empty());
304 uint32_t start_sample_flag;
305 if (traf_->runs[0].flags & TrackFragmentRun::kSampleFlagsPresentMask) {
306 DCHECK(!traf_->runs[0].sample_flags.empty());
307 start_sample_flag = traf_->runs[0].sample_flags[0];
309 DCHECK(traf_->header.flags &
310 TrackFragmentHeader::kDefaultSampleFlagsPresentMask);
311 start_sample_flag = traf_->header.default_sample_flags;
313 return (start_sample_flag & TrackFragmentHeader::kNonKeySampleMask) == 0;
All the methods that are virtual are virtual for mocking.