2022-08-26 15:44:59 +00:00
|
|
|
// Copyright 2014 Google LLC. All rights reserved.
|
2014-02-14 23:21:05 +00:00
|
|
|
//
|
|
|
|
// 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
|
|
|
|
2017-12-20 00:56:36 +00:00
|
|
|
#ifndef PACKAGER_MEDIA_FORMATS_MP4_FRAGMENTER_H_
|
|
|
|
#define PACKAGER_MEDIA_FORMATS_MP4_FRAGMENTER_H_
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2016-08-17 17:41:40 +00:00
|
|
|
#include <memory>
|
2013-11-12 20:37:58 +00:00
|
|
|
#include <vector>
|
|
|
|
|
2023-08-31 23:59:46 +00:00
|
|
|
#include <glog/logging.h>
|
2023-10-10 23:51:11 +00:00
|
|
|
#include <packager/macros.h>
|
|
|
|
#include <packager/status/status.h>
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2016-05-20 21:19:33 +00:00
|
|
|
namespace shaka {
|
2013-11-12 20:37:58 +00:00
|
|
|
namespace media {
|
|
|
|
|
|
|
|
class BufferWriter;
|
|
|
|
class MediaSample;
|
2016-05-06 23:56:50 +00:00
|
|
|
class StreamInfo;
|
2013-11-12 20:37:58 +00:00
|
|
|
|
|
|
|
namespace mp4 {
|
|
|
|
|
2018-02-01 20:25:07 +00:00
|
|
|
struct KeyFrameInfo;
|
2014-03-21 17:26:49 +00:00
|
|
|
struct SegmentReference;
|
|
|
|
struct TrackFragment;
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2014-05-08 20:53:08 +00:00
|
|
|
/// Fragmenter is responsible for the generation of MP4 fragments, i.e. 'traf'
|
|
|
|
/// box and corresponding 'mdat' box.
|
2014-04-08 20:21:07 +00:00
|
|
|
class Fragmenter {
|
2013-11-12 20:37:58 +00:00
|
|
|
public:
|
2016-05-06 23:56:50 +00:00
|
|
|
/// @param info contains stream information.
|
2014-01-23 22:34:39 +00:00
|
|
|
/// @param traf points to a TrackFragment box.
|
Add support for EditLists in ISO-BMFF
- EditLists in input files are parsed and applied to sample timestamps.
- An EditList will be inserted in the ISO-BMFF output if
- There is an offset between the initial presentation timestamp (pts)
and decoding timestamp (dts). Chrome, as of M67, still uses dts in
buffered range API [1], which creates various problems when buffered
range by pts does not align with buffered range by dts. There is
another bug in Chrome that applies EditList to pts only [2]. This
means that we can insert an EditList to align pts range and dts range.
- MediaSamples have negative timestamps (e.g. for Audio Priming).
You may notice the below change on some contents:
- Some media duration is reduced by one or two frames. This is because
EditList in the input file was ignored in the previous code, so video
streams start with a zero dts and a non-zero pts; the smaller of dts
and pts was used as the starting timestamp (related to the earlier
workaround for Chrome's dts bug), so the calculated duration was
actually a bit larger than the actual duration. Now with EditList
applied, the initial pts is reduced to zero, so the media duration is
also reduced to reflect the actual and correct media duration.
It may also result in negative timestamps in TS/HLS Packed Audio, which
will be addressed in a follow up CL.
Fixes #112.
Partially address b/110782437.
[1] https://crbug.com/718641, fixed but behind MseBufferByPts.
[2] https://crbug.com/354518. Chrome is planning to enable the fix for
[1] before addressing this bug, so we are safe.
Change-Id: I59317740ad3807ca66fa74b3a18fdf7f32c96aeb
2018-07-03 00:52:25 +00:00
|
|
|
/// @param edit_list_offset is the edit list offset that is encoded in Edit
|
|
|
|
/// List. It should be 0 if there is no EditList.
|
|
|
|
Fragmenter(std::shared_ptr<const StreamInfo> info,
|
|
|
|
TrackFragment* traf,
|
|
|
|
int64_t edit_list_offset);
|
2014-04-18 18:49:49 +00:00
|
|
|
|
2017-03-11 02:49:55 +00:00
|
|
|
~Fragmenter();
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2014-01-23 22:34:39 +00:00
|
|
|
/// Add a sample to the fragmenter.
|
2014-05-08 20:53:08 +00:00
|
|
|
/// @param sample points to the sample to be added.
|
|
|
|
/// @return OK on success, an error status otherwise.
|
2017-09-12 17:24:24 +00:00
|
|
|
Status AddSample(const MediaSample& sample);
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2014-01-23 22:34:39 +00:00
|
|
|
/// Initialize the fragment with default data.
|
2014-06-30 16:32:06 +00:00
|
|
|
/// @param first_sample_dts specifies the decoding timestamp for the first
|
|
|
|
/// sample for this fragment.
|
2014-04-18 18:49:49 +00:00
|
|
|
/// @return OK on success, an error status otherwise.
|
2017-03-11 02:49:55 +00:00
|
|
|
Status InitializeFragment(int64_t first_sample_dts);
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2014-01-23 22:34:39 +00:00
|
|
|
/// Finalize and optimize the fragment.
|
2017-03-11 02:49:55 +00:00
|
|
|
Status FinalizeFragment();
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2014-01-23 22:34:39 +00:00
|
|
|
/// Fill @a reference with current fragment information.
|
2018-03-27 16:27:17 +00:00
|
|
|
void GenerateSegmentReference(SegmentReference* reference) const;
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2017-02-24 01:17:47 +00:00
|
|
|
void ClearFragmentFinalized() { fragment_finalized_ = false; }
|
|
|
|
|
2021-08-04 18:56:44 +00:00
|
|
|
int64_t fragment_duration() const { return fragment_duration_; }
|
|
|
|
int64_t first_sap_time() const { return first_sap_time_; }
|
|
|
|
int64_t earliest_presentation_time() const {
|
2013-11-12 20:37:58 +00:00
|
|
|
return earliest_presentation_time_;
|
|
|
|
}
|
2014-06-30 16:32:06 +00:00
|
|
|
bool fragment_initialized() const { return fragment_initialized_; }
|
2013-11-12 20:37:58 +00:00
|
|
|
bool fragment_finalized() const { return fragment_finalized_; }
|
|
|
|
BufferWriter* data() { return data_.get(); }
|
2018-02-01 20:25:07 +00:00
|
|
|
const std::vector<KeyFrameInfo>& key_frame_infos() const {
|
|
|
|
return key_frame_infos_;
|
|
|
|
}
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2014-04-18 18:49:49 +00:00
|
|
|
protected:
|
|
|
|
TrackFragment* traf() { return traf_; }
|
|
|
|
|
2014-05-08 20:53:08 +00:00
|
|
|
/// Optimize sample entries table. If all values in @a entries are identical,
|
|
|
|
/// then @a entries is cleared and the value is assigned to @a default_value;
|
|
|
|
/// otherwise it is a NOP. Return true if the table is optimized.
|
|
|
|
template <typename T>
|
|
|
|
bool OptimizeSampleEntries(std::vector<T>* entries, T* default_value);
|
2014-04-18 18:49:49 +00:00
|
|
|
|
2013-11-12 20:37:58 +00:00
|
|
|
private:
|
2017-03-11 02:49:55 +00:00
|
|
|
Status FinalizeFragmentForEncryption();
|
2013-11-12 20:37:58 +00:00
|
|
|
// Check if the current fragment starts with SAP.
|
2018-03-27 16:27:17 +00:00
|
|
|
bool StartsWithSAP() const;
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2017-09-12 17:24:24 +00:00
|
|
|
std::shared_ptr<const StreamInfo> stream_info_;
|
Add support for EditLists in ISO-BMFF
- EditLists in input files are parsed and applied to sample timestamps.
- An EditList will be inserted in the ISO-BMFF output if
- There is an offset between the initial presentation timestamp (pts)
and decoding timestamp (dts). Chrome, as of M67, still uses dts in
buffered range API [1], which creates various problems when buffered
range by pts does not align with buffered range by dts. There is
another bug in Chrome that applies EditList to pts only [2]. This
means that we can insert an EditList to align pts range and dts range.
- MediaSamples have negative timestamps (e.g. for Audio Priming).
You may notice the below change on some contents:
- Some media duration is reduced by one or two frames. This is because
EditList in the input file was ignored in the previous code, so video
streams start with a zero dts and a non-zero pts; the smaller of dts
and pts was used as the starting timestamp (related to the earlier
workaround for Chrome's dts bug), so the calculated duration was
actually a bit larger than the actual duration. Now with EditList
applied, the initial pts is reduced to zero, so the media duration is
also reduced to reflect the actual and correct media duration.
It may also result in negative timestamps in TS/HLS Packed Audio, which
will be addressed in a follow up CL.
Fixes #112.
Partially address b/110782437.
[1] https://crbug.com/718641, fixed but behind MseBufferByPts.
[2] https://crbug.com/354518. Chrome is planning to enable the fix for
[1] before addressing this bug, so we are safe.
Change-Id: I59317740ad3807ca66fa74b3a18fdf7f32c96aeb
2018-07-03 00:52:25 +00:00
|
|
|
TrackFragment* traf_ = nullptr;
|
|
|
|
int64_t edit_list_offset_ = 0;
|
|
|
|
int64_t seek_preroll_ = 0;
|
|
|
|
bool fragment_initialized_ = false;
|
|
|
|
bool fragment_finalized_ = false;
|
|
|
|
int64_t fragment_duration_ = 0;
|
|
|
|
int64_t earliest_presentation_time_ = 0;
|
|
|
|
int64_t first_sap_time_ = 0;
|
2016-08-17 17:41:40 +00:00
|
|
|
std::unique_ptr<BufferWriter> data_;
|
2018-02-01 20:25:07 +00:00
|
|
|
// Saves key frames information, for Video.
|
|
|
|
std::vector<KeyFrameInfo> key_frame_infos_;
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2014-04-08 20:21:07 +00:00
|
|
|
DISALLOW_COPY_AND_ASSIGN(Fragmenter);
|
2013-11-12 20:37:58 +00:00
|
|
|
};
|
|
|
|
|
2014-05-08 20:53:08 +00:00
|
|
|
template <typename T>
|
|
|
|
bool Fragmenter::OptimizeSampleEntries(std::vector<T>* entries,
|
|
|
|
T* default_value) {
|
|
|
|
DCHECK(entries);
|
|
|
|
DCHECK(default_value);
|
|
|
|
DCHECK(!entries->empty());
|
|
|
|
|
|
|
|
typename std::vector<T>::const_iterator it = entries->begin();
|
|
|
|
T value = *it;
|
|
|
|
for (; it < entries->end(); ++it)
|
|
|
|
if (value != *it)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Clear |entries| if it contains only one value.
|
|
|
|
entries->clear();
|
|
|
|
*default_value = value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-11-12 20:37:58 +00:00
|
|
|
} // namespace mp4
|
|
|
|
} // namespace media
|
2016-05-20 21:19:33 +00:00
|
|
|
} // namespace shaka
|
2013-11-12 20:37:58 +00:00
|
|
|
|
2017-12-20 00:56:36 +00:00
|
|
|
#endif // PACKAGER_MEDIA_FORMATS_MP4_FRAGMENTER_H_
|