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  // Fill in sample parameters. It will be optimized later.
47  traf_->runs[0].sample_sizes.push_back(sample->data_size());
48  traf_->runs[0].sample_durations.push_back(sample->duration());
49  traf_->runs[0].sample_flags.push_back(
50  sample->is_key_frame() ? 0 : TrackFragmentHeader::kNonKeySampleMask);
51 
52  data_->AppendArray(sample->data(), sample->data_size());
53  fragment_duration_ += sample->duration();
54 
55  int64_t pts = sample->pts();
56 
57  // Set |earliest_presentation_time_| to |pts| if |pts| is smaller or if it is
58  // not yet initialized (kInvalidTime > pts is always true).
59  if (earliest_presentation_time_ > pts)
60  earliest_presentation_time_ = pts;
61 
62  traf_->runs[0].sample_composition_time_offsets.push_back(pts - sample->dts());
63  if (pts != sample->dts())
64  traf_->runs[0].flags |= TrackFragmentRun::kSampleCompTimeOffsetsPresentMask;
65 
66  if (sample->is_key_frame()) {
67  if (first_sap_time_ == kInvalidTime)
68  first_sap_time_ = pts;
69  }
70  return Status::OK;
71 }
72 
73 Status Fragmenter::InitializeFragment(int64_t first_sample_dts) {
74  fragment_initialized_ = true;
75  fragment_finalized_ = false;
76  traf_->decode_time.decode_time = first_sample_dts;
77  traf_->runs.clear();
78  traf_->runs.resize(1);
79  traf_->runs[0].flags = TrackFragmentRun::kDataOffsetPresentMask;
80  traf_->header.sample_description_index = 1; // 1-based.
81  traf_->header.flags = TrackFragmentHeader::kDefaultBaseIsMoofMask |
82  TrackFragmentHeader::kSampleDescriptionIndexPresentMask;
83  fragment_duration_ = 0;
84  earliest_presentation_time_ = kInvalidTime;
85  first_sap_time_ = kInvalidTime;
86  data_.reset(new BufferWriter());
87  aux_data_.reset(new BufferWriter());
88  return Status::OK;
89 }
90 
92  // Optimize trun box.
93  traf_->runs[0].sample_count = traf_->runs[0].sample_sizes.size();
94  if (OptimizeSampleEntries(&traf_->runs[0].sample_durations,
95  &traf_->header.default_sample_duration)) {
96  traf_->header.flags |=
97  TrackFragmentHeader::kDefaultSampleDurationPresentMask;
98  } else {
99  traf_->runs[0].flags |= TrackFragmentRun::kSampleDurationPresentMask;
100  }
101  if (OptimizeSampleEntries(&traf_->runs[0].sample_sizes,
102  &traf_->header.default_sample_size)) {
103  traf_->header.flags |= TrackFragmentHeader::kDefaultSampleSizePresentMask;
104  } else {
105  traf_->runs[0].flags |= TrackFragmentRun::kSampleSizePresentMask;
106  }
107  if (OptimizeSampleEntries(&traf_->runs[0].sample_flags,
108  &traf_->header.default_sample_flags)) {
109  traf_->header.flags |= TrackFragmentHeader::kDefaultSampleFlagsPresentMask;
110  } else {
111  traf_->runs[0].flags |= TrackFragmentRun::kSampleFlagsPresentMask;
112  }
113 
114  fragment_finalized_ = true;
115  fragment_initialized_ = false;
116 }
117 
119  // NOTE: Daisy chain is not supported currently.
120  reference->reference_type = false;
121  reference->subsegment_duration = fragment_duration_;
122  reference->starts_with_sap = StartsWithSAP();
123  if (kInvalidTime == first_sap_time_) {
124  reference->sap_type = SegmentReference::TypeUnknown;
125  reference->sap_delta_time = 0;
126  } else {
127  reference->sap_type = SegmentReference::Type1;
128  reference->sap_delta_time = first_sap_time_ - earliest_presentation_time_;
129  }
130  reference->earliest_presentation_time = earliest_presentation_time_;
131 }
132 
133 bool Fragmenter::StartsWithSAP() {
134  DCHECK(!traf_->runs.empty());
135  uint32_t start_sample_flag;
136  if (traf_->runs[0].flags & TrackFragmentRun::kSampleFlagsPresentMask) {
137  DCHECK(!traf_->runs[0].sample_flags.empty());
138  start_sample_flag = traf_->runs[0].sample_flags[0];
139  } else {
140  DCHECK(traf_->header.flags &
141  TrackFragmentHeader::kDefaultSampleFlagsPresentMask);
142  start_sample_flag = traf_->header.default_sample_flags;
143  }
144  return (start_sample_flag & TrackFragmentHeader::kNonKeySampleMask) == 0;
145 }
146 
147 } // namespace mp4
148 } // namespace media
149 } // namespace edash_packager
void GenerateSegmentReference(SegmentReference *reference)
Fill reference with current fragment information.
Definition: fragmenter.cc:118
virtual Status InitializeFragment(int64_t first_sample_dts)
Definition: fragmenter.cc:73
virtual Status AddSample(scoped_refptr< MediaSample > sample)
Definition: fragmenter.cc:36
bool OptimizeSampleEntries(std::vector< T > *entries, T *default_value)
Definition: fragmenter.h:90
virtual void FinalizeFragment()
Finalize and optimize the fragment.
Definition: fragmenter.cc:91