2014-02-14 23:21:05 +00:00
|
|
|
// Copyright 2014 Google Inc. All rights reserved.
|
|
|
|
//
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file or at
|
|
|
|
// https://developers.google.com/open-source/licenses/bsd
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2014-04-10 21:42:38 +00:00
|
|
|
#include "media/formats/mp4/fragmenter.h"
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2014-09-30 23:52:58 +00:00
|
|
|
#include <limits>
|
|
|
|
|
2013-11-12 20:37:58 +00:00
|
|
|
#include "media/base/buffer_writer.h"
|
|
|
|
#include "media/base/media_sample.h"
|
2014-04-10 21:42:38 +00:00
|
|
|
#include "media/formats/mp4/box_definitions.h"
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2014-09-19 20:41:13 +00:00
|
|
|
namespace edash_packager {
|
2014-04-18 18:49:49 +00:00
|
|
|
namespace media {
|
|
|
|
namespace mp4 {
|
|
|
|
|
2013-11-12 20:37:58 +00:00
|
|
|
namespace {
|
2014-09-30 23:52:58 +00:00
|
|
|
const int64_t kInvalidTime = std::numeric_limits<int64_t>::max();
|
2013-11-12 20:37:58 +00:00
|
|
|
} // namespace
|
|
|
|
|
2014-07-16 23:41:54 +00:00
|
|
|
Fragmenter::Fragmenter(TrackFragment* traf)
|
2014-04-18 18:49:49 +00:00
|
|
|
: traf_(traf),
|
2014-06-30 16:32:06 +00:00
|
|
|
fragment_initialized_(false),
|
2014-04-18 18:49:49 +00:00
|
|
|
fragment_finalized_(false),
|
|
|
|
fragment_duration_(0),
|
|
|
|
presentation_start_time_(kInvalidTime),
|
|
|
|
earliest_presentation_time_(kInvalidTime),
|
|
|
|
first_sap_time_(kInvalidTime) {
|
|
|
|
DCHECK(traf);
|
|
|
|
}
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2014-04-08 20:21:07 +00:00
|
|
|
Fragmenter::~Fragmenter() {}
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2014-04-08 20:21:07 +00:00
|
|
|
Status Fragmenter::AddSample(scoped_refptr<MediaSample> sample) {
|
2014-05-08 20:53:08 +00:00
|
|
|
DCHECK(sample);
|
2014-01-23 00:13:41 +00:00
|
|
|
CHECK_GT(sample->duration(), 0);
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2014-06-30 16:32:06 +00:00
|
|
|
if (!fragment_initialized_) {
|
|
|
|
Status status = InitializeFragment(sample->dts());
|
|
|
|
if (!status.ok())
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2013-11-12 20:37:58 +00:00
|
|
|
// Fill in sample parameters. It will be optimized later.
|
|
|
|
traf_->runs[0].sample_sizes.push_back(sample->data_size());
|
|
|
|
traf_->runs[0].sample_durations.push_back(sample->duration());
|
|
|
|
traf_->runs[0].sample_flags.push_back(
|
|
|
|
sample->is_key_frame() ? 0 : TrackFragmentHeader::kNonKeySampleMask);
|
|
|
|
|
|
|
|
data_->AppendArray(sample->data(), sample->data_size());
|
|
|
|
fragment_duration_ += sample->duration();
|
|
|
|
|
2014-09-30 21:52:21 +00:00
|
|
|
int64_t pts = sample->pts();
|
2014-01-22 23:51:26 +00:00
|
|
|
|
|
|
|
// Set |earliest_presentation_time_| to |pts| if |pts| is smaller or if it is
|
|
|
|
// not yet initialized (kInvalidTime > pts is always true).
|
|
|
|
if (earliest_presentation_time_ > pts)
|
|
|
|
earliest_presentation_time_ = pts;
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2014-06-30 16:32:06 +00:00
|
|
|
traf_->runs[0].sample_composition_time_offsets.push_back(pts - sample->dts());
|
|
|
|
if (pts != sample->dts())
|
|
|
|
traf_->runs[0].flags |= TrackFragmentRun::kSampleCompTimeOffsetsPresentMask;
|
|
|
|
|
2013-11-12 20:37:58 +00:00
|
|
|
if (sample->is_key_frame()) {
|
2014-01-22 23:51:26 +00:00
|
|
|
if (first_sap_time_ == kInvalidTime)
|
|
|
|
first_sap_time_ = pts;
|
2013-11-12 20:37:58 +00:00
|
|
|
}
|
|
|
|
return Status::OK;
|
|
|
|
}
|
|
|
|
|
2014-09-30 21:52:21 +00:00
|
|
|
Status Fragmenter::InitializeFragment(int64_t first_sample_dts) {
|
2014-06-30 16:32:06 +00:00
|
|
|
fragment_initialized_ = true;
|
2013-11-12 20:37:58 +00:00
|
|
|
fragment_finalized_ = false;
|
2014-06-30 16:32:06 +00:00
|
|
|
traf_->decode_time.decode_time = first_sample_dts;
|
2013-11-12 20:37:58 +00:00
|
|
|
traf_->runs.clear();
|
|
|
|
traf_->runs.resize(1);
|
|
|
|
traf_->runs[0].flags = TrackFragmentRun::kDataOffsetPresentMask;
|
|
|
|
traf_->header.flags = TrackFragmentHeader::kDefaultBaseIsMoofMask;
|
|
|
|
fragment_duration_ = 0;
|
|
|
|
earliest_presentation_time_ = kInvalidTime;
|
|
|
|
first_sap_time_ = kInvalidTime;
|
|
|
|
data_.reset(new BufferWriter());
|
|
|
|
aux_data_.reset(new BufferWriter());
|
2014-04-18 18:49:49 +00:00
|
|
|
return Status::OK;
|
2013-11-12 20:37:58 +00:00
|
|
|
}
|
|
|
|
|
2014-04-08 20:21:07 +00:00
|
|
|
void Fragmenter::FinalizeFragment() {
|
2013-11-12 20:37:58 +00:00
|
|
|
// Optimize trun box.
|
|
|
|
traf_->runs[0].sample_count = traf_->runs[0].sample_sizes.size();
|
|
|
|
if (OptimizeSampleEntries(&traf_->runs[0].sample_durations,
|
|
|
|
&traf_->header.default_sample_duration)) {
|
|
|
|
traf_->header.flags |=
|
|
|
|
TrackFragmentHeader::kDefaultSampleDurationPresentMask;
|
|
|
|
} else {
|
|
|
|
traf_->runs[0].flags |= TrackFragmentRun::kSampleDurationPresentMask;
|
|
|
|
}
|
|
|
|
if (OptimizeSampleEntries(&traf_->runs[0].sample_sizes,
|
|
|
|
&traf_->header.default_sample_size)) {
|
|
|
|
traf_->header.flags |= TrackFragmentHeader::kDefaultSampleSizePresentMask;
|
|
|
|
} else {
|
|
|
|
traf_->runs[0].flags |= TrackFragmentRun::kSampleSizePresentMask;
|
|
|
|
}
|
|
|
|
if (OptimizeSampleEntries(&traf_->runs[0].sample_flags,
|
|
|
|
&traf_->header.default_sample_flags)) {
|
|
|
|
traf_->header.flags |= TrackFragmentHeader::kDefaultSampleFlagsPresentMask;
|
|
|
|
} else {
|
|
|
|
traf_->runs[0].flags |= TrackFragmentRun::kSampleFlagsPresentMask;
|
|
|
|
}
|
|
|
|
|
|
|
|
fragment_finalized_ = true;
|
2014-06-30 16:32:06 +00:00
|
|
|
fragment_initialized_ = false;
|
2013-11-12 20:37:58 +00:00
|
|
|
}
|
|
|
|
|
2014-04-08 20:21:07 +00:00
|
|
|
void Fragmenter::GenerateSegmentReference(SegmentReference* reference) {
|
2014-03-26 22:09:43 +00:00
|
|
|
// NOTE: Daisy chain is not supported currently.
|
2013-11-12 20:37:58 +00:00
|
|
|
reference->reference_type = false;
|
|
|
|
reference->subsegment_duration = fragment_duration_;
|
|
|
|
reference->starts_with_sap = StartsWithSAP();
|
|
|
|
if (kInvalidTime == first_sap_time_) {
|
|
|
|
reference->sap_type = SegmentReference::TypeUnknown;
|
|
|
|
reference->sap_delta_time = 0;
|
|
|
|
} else {
|
|
|
|
reference->sap_type = SegmentReference::Type1;
|
|
|
|
reference->sap_delta_time = first_sap_time_ - earliest_presentation_time_;
|
|
|
|
}
|
|
|
|
reference->earliest_presentation_time = earliest_presentation_time_;
|
|
|
|
}
|
|
|
|
|
2014-04-08 20:21:07 +00:00
|
|
|
bool Fragmenter::StartsWithSAP() {
|
2013-11-12 20:37:58 +00:00
|
|
|
DCHECK(!traf_->runs.empty());
|
2014-09-30 21:52:21 +00:00
|
|
|
uint32_t start_sample_flag;
|
2013-11-12 20:37:58 +00:00
|
|
|
if (traf_->runs[0].flags & TrackFragmentRun::kSampleFlagsPresentMask) {
|
|
|
|
DCHECK(!traf_->runs[0].sample_flags.empty());
|
|
|
|
start_sample_flag = traf_->runs[0].sample_flags[0];
|
|
|
|
} else {
|
|
|
|
DCHECK(traf_->header.flags &
|
|
|
|
TrackFragmentHeader::kDefaultSampleFlagsPresentMask);
|
|
|
|
start_sample_flag = traf_->header.default_sample_flags;
|
|
|
|
}
|
|
|
|
return (start_sample_flag & TrackFragmentHeader::kNonKeySampleMask) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace mp4
|
|
|
|
} // namespace media
|
2014-09-19 20:41:13 +00:00
|
|
|
} // namespace edash_packager
|