DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs 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/media_sample.h"
13 #include "packager/media/formats/mp4/box_definitions.h"
14 
15 namespace edash_packager {
16 namespace media {
17 namespace mp4 {
18 
19 namespace {
20 const int64_t kInvalidTime = std::numeric_limits<int64_t>::max();
21 } // namespace
22 
24  : traf_(traf),
25  fragment_initialized_(false),
26  fragment_finalized_(false),
27  fragment_duration_(0),
28  presentation_start_time_(kInvalidTime),
29  earliest_presentation_time_(kInvalidTime),
30  first_sap_time_(kInvalidTime) {
31  DCHECK(traf);
32 }
33 
34 Fragmenter::~Fragmenter() {}
35 
36 Status Fragmenter::AddSample(scoped_refptr<MediaSample> sample) {
37  DCHECK(sample);
38  CHECK_GT(sample->duration(), 0);
39 
40  if (!fragment_initialized_) {
41  Status status = InitializeFragment(sample->dts());
42  if (!status.ok())
43  return status;
44  }
45 
46  if (sample->side_data_size() > 0)
47  LOG(WARNING) << "MP4 samples do not support side data. Side data ignored.";
48 
49  // Fill in sample parameters. It will be optimized later.
50  traf_->runs[0].sample_sizes.push_back(sample->data_size());
51  traf_->runs[0].sample_durations.push_back(sample->duration());
52  traf_->runs[0].sample_flags.push_back(
53  sample->is_key_frame() ? 0 : TrackFragmentHeader::kNonKeySampleMask);
54 
55  data_->AppendArray(sample->data(), sample->data_size());
56  fragment_duration_ += sample->duration();
57 
58  int64_t pts = sample->pts();
59 
60  // Set |earliest_presentation_time_| to |pts| if |pts| is smaller or if it is
61  // not yet initialized (kInvalidTime > pts is always true).
62  if (earliest_presentation_time_ > pts)
63  earliest_presentation_time_ = pts;
64 
65  traf_->runs[0].sample_composition_time_offsets.push_back(pts - sample->dts());
66  if (pts != sample->dts())
67  traf_->runs[0].flags |= TrackFragmentRun::kSampleCompTimeOffsetsPresentMask;
68 
69  if (sample->is_key_frame()) {
70  if (first_sap_time_ == kInvalidTime)
71  first_sap_time_ = pts;
72  }
73  return Status::OK;
74 }
75 
76 Status Fragmenter::InitializeFragment(int64_t first_sample_dts) {
77  fragment_initialized_ = true;
78  fragment_finalized_ = false;
79  traf_->decode_time.decode_time = first_sample_dts;
80  traf_->runs.clear();
81  traf_->runs.resize(1);
82  traf_->runs[0].flags = TrackFragmentRun::kDataOffsetPresentMask;
83  traf_->header.sample_description_index = 1; // 1-based.
84  traf_->header.flags = TrackFragmentHeader::kDefaultBaseIsMoofMask |
85  TrackFragmentHeader::kSampleDescriptionIndexPresentMask;
86  fragment_duration_ = 0;
87  earliest_presentation_time_ = kInvalidTime;
88  first_sap_time_ = kInvalidTime;
89  data_.reset(new BufferWriter());
90  return Status::OK;
91 }
92 
94  // Optimize trun box.
95  traf_->runs[0].sample_count = traf_->runs[0].sample_sizes.size();
96  if (OptimizeSampleEntries(&traf_->runs[0].sample_durations,
97  &traf_->header.default_sample_duration)) {
98  traf_->header.flags |=
99  TrackFragmentHeader::kDefaultSampleDurationPresentMask;
100  } else {
101  traf_->runs[0].flags |= TrackFragmentRun::kSampleDurationPresentMask;
102  }
103  if (OptimizeSampleEntries(&traf_->runs[0].sample_sizes,
104  &traf_->header.default_sample_size)) {
105  traf_->header.flags |= TrackFragmentHeader::kDefaultSampleSizePresentMask;
106  } else {
107  traf_->runs[0].flags |= TrackFragmentRun::kSampleSizePresentMask;
108  }
109  if (OptimizeSampleEntries(&traf_->runs[0].sample_flags,
110  &traf_->header.default_sample_flags)) {
111  traf_->header.flags |= TrackFragmentHeader::kDefaultSampleFlagsPresentMask;
112  } else {
113  traf_->runs[0].flags |= TrackFragmentRun::kSampleFlagsPresentMask;
114  }
115 
116  fragment_finalized_ = true;
117  fragment_initialized_ = false;
118 }
119 
121  // NOTE: Daisy chain is not supported currently.
122  reference->reference_type = false;
123  reference->subsegment_duration = fragment_duration_;
124  reference->starts_with_sap = StartsWithSAP();
125  if (kInvalidTime == first_sap_time_) {
126  reference->sap_type = SegmentReference::TypeUnknown;
127  reference->sap_delta_time = 0;
128  } else {
129  reference->sap_type = SegmentReference::Type1;
130  reference->sap_delta_time = first_sap_time_ - earliest_presentation_time_;
131  }
132  reference->earliest_presentation_time = earliest_presentation_time_;
133 }
134 
135 bool Fragmenter::StartsWithSAP() {
136  DCHECK(!traf_->runs.empty());
137  uint32_t start_sample_flag;
138  if (traf_->runs[0].flags & TrackFragmentRun::kSampleFlagsPresentMask) {
139  DCHECK(!traf_->runs[0].sample_flags.empty());
140  start_sample_flag = traf_->runs[0].sample_flags[0];
141  } else {
142  DCHECK(traf_->header.flags &
143  TrackFragmentHeader::kDefaultSampleFlagsPresentMask);
144  start_sample_flag = traf_->header.default_sample_flags;
145  }
146  return (start_sample_flag & TrackFragmentHeader::kNonKeySampleMask) == 0;
147 }
148 
149 } // namespace mp4
150 } // namespace media
151 } // namespace edash_packager
void GenerateSegmentReference(SegmentReference *reference)
Fill reference with current fragment information.
Definition: fragmenter.cc:120
virtual Status InitializeFragment(int64_t first_sample_dts)
Definition: fragmenter.cc:76
virtual Status AddSample(scoped_refptr< MediaSample > sample)
Definition: fragmenter.cc:36
bool OptimizeSampleEntries(std::vector< T > *entries, T *default_value)
Definition: fragmenter.h:89
virtual void FinalizeFragment()
Finalize and optimize the fragment.
Definition: fragmenter.cc:93