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  return Status::OK;
88 }
89 
91  // Optimize trun box.
92  traf_->runs[0].sample_count = traf_->runs[0].sample_sizes.size();
93  if (OptimizeSampleEntries(&traf_->runs[0].sample_durations,
94  &traf_->header.default_sample_duration)) {
95  traf_->header.flags |=
96  TrackFragmentHeader::kDefaultSampleDurationPresentMask;
97  } else {
98  traf_->runs[0].flags |= TrackFragmentRun::kSampleDurationPresentMask;
99  }
100  if (OptimizeSampleEntries(&traf_->runs[0].sample_sizes,
101  &traf_->header.default_sample_size)) {
102  traf_->header.flags |= TrackFragmentHeader::kDefaultSampleSizePresentMask;
103  } else {
104  traf_->runs[0].flags |= TrackFragmentRun::kSampleSizePresentMask;
105  }
106  if (OptimizeSampleEntries(&traf_->runs[0].sample_flags,
107  &traf_->header.default_sample_flags)) {
108  traf_->header.flags |= TrackFragmentHeader::kDefaultSampleFlagsPresentMask;
109  } else {
110  traf_->runs[0].flags |= TrackFragmentRun::kSampleFlagsPresentMask;
111  }
112 
113  fragment_finalized_ = true;
114  fragment_initialized_ = false;
115 }
116 
118  // NOTE: Daisy chain is not supported currently.
119  reference->reference_type = false;
120  reference->subsegment_duration = fragment_duration_;
121  reference->starts_with_sap = StartsWithSAP();
122  if (kInvalidTime == first_sap_time_) {
123  reference->sap_type = SegmentReference::TypeUnknown;
124  reference->sap_delta_time = 0;
125  } else {
126  reference->sap_type = SegmentReference::Type1;
127  reference->sap_delta_time = first_sap_time_ - earliest_presentation_time_;
128  }
129  reference->earliest_presentation_time = earliest_presentation_time_;
130 }
131 
132 bool Fragmenter::StartsWithSAP() {
133  DCHECK(!traf_->runs.empty());
134  uint32_t start_sample_flag;
135  if (traf_->runs[0].flags & TrackFragmentRun::kSampleFlagsPresentMask) {
136  DCHECK(!traf_->runs[0].sample_flags.empty());
137  start_sample_flag = traf_->runs[0].sample_flags[0];
138  } else {
139  DCHECK(traf_->header.flags &
140  TrackFragmentHeader::kDefaultSampleFlagsPresentMask);
141  start_sample_flag = traf_->header.default_sample_flags;
142  }
143  return (start_sample_flag & TrackFragmentHeader::kNonKeySampleMask) == 0;
144 }
145 
146 } // namespace mp4
147 } // namespace media
148 } // namespace edash_packager
void GenerateSegmentReference(SegmentReference *reference)
Fill reference with current fragment information.
Definition: fragmenter.cc:117
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:89
virtual void FinalizeFragment()
Finalize and optimize the fragment.
Definition: fragmenter.cc:90