DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
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/fragmenter.h"
8 
9 #include <limits>
10 
11 #include "packager/media/base/buffer_writer.h"
12 #include "packager/media/base/audio_stream_info.h"
13 #include "packager/media/base/media_sample.h"
14 #include "packager/media/formats/mp4/box_definitions.h"
15 
16 namespace shaka {
17 namespace media {
18 namespace mp4 {
19 
20 namespace {
21 const int64_t kInvalidTime = std::numeric_limits<int64_t>::max();
22 
23 uint64_t GetSeekPreroll(const StreamInfo& stream_info) {
24  if (stream_info.stream_type() != kStreamAudio)
25  return 0;
26  const AudioStreamInfo& audio_stream_info =
27  static_cast<const AudioStreamInfo&>(stream_info);
28  return audio_stream_info.seek_preroll_ns();
29 }
30 } // namespace
31 
32 Fragmenter::Fragmenter(std::shared_ptr<StreamInfo> info, TrackFragment* traf)
33  : use_decoding_timestamp_in_timeline_(false),
34  traf_(traf),
35  seek_preroll_(GetSeekPreroll(*info)),
36  fragment_initialized_(false),
37  fragment_finalized_(false),
38  fragment_duration_(0),
39  earliest_presentation_time_(kInvalidTime),
40  first_sap_time_(kInvalidTime) {
41  DCHECK(traf);
42 }
43 
44 Fragmenter::~Fragmenter() {}
45 
46 Status Fragmenter::AddSample(std::shared_ptr<MediaSample> sample) {
47  DCHECK(sample);
48  if (sample->duration() == 0) {
49  LOG(WARNING) << "Unexpected sample with zero duration @ dts "
50  << sample->dts();
51  }
52 
53  if (!fragment_initialized_) {
54  Status status = InitializeFragment(sample->dts());
55  if (!status.ok())
56  return status;
57  }
58 
59  if (sample->side_data_size() > 0)
60  LOG(WARNING) << "MP4 samples do not support side data. Side data ignored.";
61 
62  // Fill in sample parameters. It will be optimized later.
63  traf_->runs[0].sample_sizes.push_back(
64  static_cast<uint32_t>(sample->data_size()));
65  traf_->runs[0].sample_durations.push_back(sample->duration());
66  traf_->runs[0].sample_flags.push_back(
67  sample->is_key_frame() ? 0 : TrackFragmentHeader::kNonKeySampleMask);
68 
69  data_->AppendArray(sample->data(), sample->data_size());
70  fragment_duration_ += sample->duration();
71 
72  const int64_t pts = sample->pts();
73  const int64_t dts = sample->dts();
74 
75  const int64_t timestamp = use_decoding_timestamp_in_timeline_ ? dts : pts;
76  // Set |earliest_presentation_time_| to |timestamp| if |timestamp| is smaller
77  // or if it is not yet initialized (kInvalidTime > timestamp is always true).
78  if (earliest_presentation_time_ > timestamp)
79  earliest_presentation_time_ = timestamp;
80 
81  traf_->runs[0].sample_composition_time_offsets.push_back(pts - dts);
82  if (pts != dts)
83  traf_->runs[0].flags |= TrackFragmentRun::kSampleCompTimeOffsetsPresentMask;
84 
85  if (sample->is_key_frame()) {
86  if (first_sap_time_ == kInvalidTime)
87  first_sap_time_ = pts;
88  }
89  return Status::OK;
90 }
91 
92 Status Fragmenter::InitializeFragment(int64_t first_sample_dts) {
93  fragment_initialized_ = true;
94  fragment_finalized_ = false;
95  traf_->decode_time.decode_time = first_sample_dts;
96  traf_->runs.clear();
97  traf_->runs.resize(1);
98  traf_->runs[0].flags = TrackFragmentRun::kDataOffsetPresentMask;
99  traf_->sample_group_descriptions.clear();
100  traf_->sample_to_groups.clear();
101  traf_->header.sample_description_index = 1; // 1-based.
102  traf_->header.flags = TrackFragmentHeader::kDefaultBaseIsMoofMask |
103  TrackFragmentHeader::kSampleDescriptionIndexPresentMask;
104  fragment_duration_ = 0;
105  earliest_presentation_time_ = kInvalidTime;
106  first_sap_time_ = kInvalidTime;
107  data_.reset(new BufferWriter());
108  return Status::OK;
109 }
110 
112  // Optimize trun box.
113  traf_->runs[0].sample_count =
114  static_cast<uint32_t>(traf_->runs[0].sample_sizes.size());
115  if (OptimizeSampleEntries(&traf_->runs[0].sample_durations,
116  &traf_->header.default_sample_duration)) {
117  traf_->header.flags |=
118  TrackFragmentHeader::kDefaultSampleDurationPresentMask;
119  } else {
120  traf_->runs[0].flags |= TrackFragmentRun::kSampleDurationPresentMask;
121  }
122  if (OptimizeSampleEntries(&traf_->runs[0].sample_sizes,
123  &traf_->header.default_sample_size)) {
124  traf_->header.flags |= TrackFragmentHeader::kDefaultSampleSizePresentMask;
125  } else {
126  traf_->runs[0].flags |= TrackFragmentRun::kSampleSizePresentMask;
127  }
128  if (OptimizeSampleEntries(&traf_->runs[0].sample_flags,
129  &traf_->header.default_sample_flags)) {
130  traf_->header.flags |= TrackFragmentHeader::kDefaultSampleFlagsPresentMask;
131  } else {
132  traf_->runs[0].flags |= TrackFragmentRun::kSampleFlagsPresentMask;
133  }
134 
135  // Add SampleToGroup boxes. A SampleToGroup box with grouping type of 'roll'
136  // needs to be added if there is seek preroll, referencing sample group
137  // description in track level; Also need to add SampleToGroup boxes
138  // correponding to every SampleGroupDescription boxes, referencing sample
139  // group description in fragment level.
140  DCHECK_EQ(traf_->sample_to_groups.size(), 0u);
141  if (seek_preroll_ > 0) {
142  traf_->sample_to_groups.resize(traf_->sample_to_groups.size() + 1);
143  SampleToGroup& sample_to_group = traf_->sample_to_groups.back();
144  sample_to_group.grouping_type = FOURCC_roll;
145 
146  sample_to_group.entries.resize(1);
147  SampleToGroupEntry& sample_to_group_entry = sample_to_group.entries.back();
148  sample_to_group_entry.sample_count = traf_->runs[0].sample_count;
149  sample_to_group_entry.group_description_index =
150  SampleToGroupEntry::kTrackGroupDescriptionIndexBase + 1;
151  }
152  for (const auto& sample_group_description :
153  traf_->sample_group_descriptions) {
154  traf_->sample_to_groups.resize(traf_->sample_to_groups.size() + 1);
155  SampleToGroup& sample_to_group = traf_->sample_to_groups.back();
156  sample_to_group.grouping_type = sample_group_description.grouping_type;
157 
158  sample_to_group.entries.resize(1);
159  SampleToGroupEntry& sample_to_group_entry = sample_to_group.entries.back();
160  sample_to_group_entry.sample_count = traf_->runs[0].sample_count;
161  sample_to_group_entry.group_description_index =
162  SampleToGroupEntry::kTrackFragmentGroupDescriptionIndexBase + 1;
163  }
164 
165  fragment_finalized_ = true;
166  fragment_initialized_ = false;
167 }
168 
170  // NOTE: Daisy chain is not supported currently.
171  reference->reference_type = false;
172  reference->subsegment_duration = fragment_duration_;
173  reference->starts_with_sap = StartsWithSAP();
174  if (kInvalidTime == first_sap_time_) {
175  reference->sap_type = SegmentReference::TypeUnknown;
176  reference->sap_delta_time = 0;
177  } else {
178  reference->sap_type = SegmentReference::Type1;
179  reference->sap_delta_time = first_sap_time_ - earliest_presentation_time_;
180  }
181  reference->earliest_presentation_time = earliest_presentation_time_;
182 }
183 
184 bool Fragmenter::StartsWithSAP() {
185  DCHECK(!traf_->runs.empty());
186  uint32_t start_sample_flag;
187  if (traf_->runs[0].flags & TrackFragmentRun::kSampleFlagsPresentMask) {
188  DCHECK(!traf_->runs[0].sample_flags.empty());
189  start_sample_flag = traf_->runs[0].sample_flags[0];
190  } else {
191  DCHECK(traf_->header.flags &
192  TrackFragmentHeader::kDefaultSampleFlagsPresentMask);
193  start_sample_flag = traf_->header.default_sample_flags;
194  }
195  return (start_sample_flag & TrackFragmentHeader::kNonKeySampleMask) == 0;
196 }
197 
198 } // namespace mp4
199 } // namespace media
200 } // namespace shaka
virtual Status InitializeFragment(int64_t first_sample_dts)
Definition: fragmenter.cc:92
virtual void FinalizeFragment()
Finalize and optimize the fragment.
Definition: fragmenter.cc:111
Fragmenter(std::shared_ptr< StreamInfo > info, TrackFragment *traf)
Definition: fragmenter.cc:32
virtual Status AddSample(std::shared_ptr< MediaSample > sample)
Definition: fragmenter.cc:46
void GenerateSegmentReference(SegmentReference *reference)
Fill reference with current fragment information.
Definition: fragmenter.cc:169
bool OptimizeSampleEntries(std::vector< T > *entries, T *default_value)
Definition: fragmenter.h:100