Handle non-MSE compliant fmp4 properly
MSE requires 'base-data-offset-present' not to be set, but FFmpeg may generate fmp4 files with this flag though it actually uses moof as base. Log a warning instead of failing directly in this case. FFmpeg may also generates fmp4 files without tfdt box (TrackFragmentDecodeTime) box, which is again non-MSE compliant. Handle this scenario properly. Bug: 18613712 Also fixes a test failure in SegmentTemplateTest introduced in an earlier change. Bug: 19235748 Change-Id: I4bcbb675b22a832a88cd33ee64c3e99a1c6e3a63
This commit is contained in:
parent
5462b350ae
commit
80db1c7bbf
|
@ -1485,16 +1485,15 @@ bool TrackFragmentHeader::ReadWrite(BoxBuffer* buffer) {
|
|||
RCHECK(FullBox::ReadWrite(buffer) &&
|
||||
buffer->ReadWriteUInt32(&track_id));
|
||||
|
||||
// Media Source specific: reject tracks that set 'base-data-offset-present'.
|
||||
// Although the Media Source requires that 'default-base-is-moof' (14496-12
|
||||
// Amendment 2) be set, we omit this check as many otherwise-valid files in
|
||||
// the wild don't set it.
|
||||
//
|
||||
// RCHECK((flags & kDefaultBaseIsMoofMask) &&
|
||||
// !(flags & kBaseDataOffsetPresentMask));
|
||||
if (flags & kDataOffsetPresentMask) {
|
||||
NOTIMPLEMENTED() << " base-data-offset-present is not supported.";
|
||||
return false;
|
||||
if (flags & kBaseDataOffsetPresentMask) {
|
||||
// MSE requires 'default-base-is-moof' to be set and
|
||||
// 'base-data-offset-present' not to be set. We omit these checks as some
|
||||
// valid files in the wild don't follow these rules, though they use moof as
|
||||
// base.
|
||||
uint64_t base_data_offset;
|
||||
RCHECK(buffer->ReadWriteUInt64(&base_data_offset));
|
||||
DLOG(WARNING) << "base-data-offset-present is not expected. Assumes "
|
||||
"default-base-is-moof.";
|
||||
}
|
||||
|
||||
if (flags & kSampleDescriptionIndexPresentMask) {
|
||||
|
@ -1751,18 +1750,19 @@ uint32_t SampleGroupDescription::ComputeSize() {
|
|||
return atom_size;
|
||||
}
|
||||
|
||||
TrackFragment::TrackFragment() {}
|
||||
TrackFragment::TrackFragment() : decode_time_absent(false) {}
|
||||
TrackFragment::~TrackFragment() {}
|
||||
FourCC TrackFragment::BoxType() const { return FOURCC_TRAF; }
|
||||
|
||||
bool TrackFragment::ReadWrite(BoxBuffer* buffer) {
|
||||
RCHECK(Box::ReadWrite(buffer) &&
|
||||
buffer->PrepareChildren() &&
|
||||
buffer->ReadWriteChild(&header) &&
|
||||
// Media Source specific: 'tfdt' required
|
||||
buffer->ReadWriteChild(&decode_time));
|
||||
buffer->ReadWriteChild(&header));
|
||||
if (buffer->Reading()) {
|
||||
DCHECK(buffer->reader());
|
||||
decode_time_absent = !buffer->reader()->ChildExist(&decode_time);
|
||||
if (!decode_time_absent)
|
||||
RCHECK(buffer->ReadWriteChild(&decode_time));
|
||||
RCHECK(buffer->reader()->TryReadChildren(&runs));
|
||||
|
||||
// There could be multiple SampleGroupDescription and SampleToGroup boxes
|
||||
|
@ -1778,6 +1778,8 @@ bool TrackFragment::ReadWrite(BoxBuffer* buffer) {
|
|||
RCHECK(buffer->reader()->ReadChild(&sample_group_description));
|
||||
}
|
||||
} else {
|
||||
if (!decode_time_absent)
|
||||
RCHECK(buffer->ReadWriteChild(&decode_time));
|
||||
for (uint32_t i = 0; i < runs.size(); ++i)
|
||||
RCHECK(runs[i].ReadWrite(buffer));
|
||||
RCHECK(buffer->TryReadWriteChild(&sample_to_group) &&
|
||||
|
|
|
@ -445,7 +445,7 @@ struct MovieFragmentHeader : FullBox {
|
|||
|
||||
struct TrackFragmentHeader : FullBox {
|
||||
enum TrackFragmentFlagsMasks {
|
||||
kDataOffsetPresentMask = 0x000001,
|
||||
kBaseDataOffsetPresentMask = 0x000001,
|
||||
kSampleDescriptionIndexPresentMask = 0x000002,
|
||||
kDefaultSampleDurationPresentMask = 0x000008,
|
||||
kDefaultSampleSizePresentMask = 0x000010,
|
||||
|
@ -532,6 +532,7 @@ struct TrackFragment : Box {
|
|||
|
||||
TrackFragmentHeader header;
|
||||
std::vector<TrackFragmentRun> runs;
|
||||
bool decode_time_absent;
|
||||
TrackFragmentDecodeTime decode_time;
|
||||
SampleToGroup sample_to_group;
|
||||
SampleGroupDescription sample_group_description;
|
||||
|
|
|
@ -270,6 +270,7 @@ bool TrackRunIterator::Init() {
|
|||
bool TrackRunIterator::Init(const MovieFragment& moof) {
|
||||
runs_.clear();
|
||||
|
||||
next_fragment_start_dts_.resize(moof.tracks.size(), 0);
|
||||
for (size_t i = 0; i < moof.tracks.size(); i++) {
|
||||
const TrackFragment& traf = moof.tracks[i];
|
||||
|
||||
|
@ -299,7 +300,9 @@ bool TrackRunIterator::Init(const MovieFragment& moof) {
|
|||
RCHECK(desc_idx > 0); // Descriptions are one-indexed in the file
|
||||
desc_idx -= 1;
|
||||
|
||||
int64_t run_start_dts = traf.decode_time.decode_time;
|
||||
int64_t run_start_dts = traf.decode_time_absent
|
||||
? next_fragment_start_dts_[i]
|
||||
: traf.decode_time.decode_time;
|
||||
int sample_count_sum = 0;
|
||||
|
||||
for (size_t j = 0; j < traf.runs.size(); j++) {
|
||||
|
@ -368,6 +371,7 @@ bool TrackRunIterator::Init(const MovieFragment& moof) {
|
|||
runs_.push_back(tri);
|
||||
sample_count_sum += trun.sample_count;
|
||||
}
|
||||
next_fragment_start_dts_[i] = run_start_dts;
|
||||
}
|
||||
|
||||
std::sort(runs_.begin(), runs_.end(), CompareMinTrackRunDataOffset());
|
||||
|
|
|
@ -112,6 +112,9 @@ class TrackRunIterator {
|
|||
std::vector<SampleInfo>::const_iterator sample_itr_;
|
||||
|
||||
std::vector<FrameCENCInfo> cenc_info_;
|
||||
// Track the start dts of the next segment, only useful if decode_time box is
|
||||
// absent.
|
||||
std::vector<int64_t> next_fragment_start_dts_;
|
||||
|
||||
int64_t sample_dts_;
|
||||
int64_t sample_offset_;
|
||||
|
|
|
@ -496,8 +496,7 @@ TEST_F(SegmentTemplateTest, OutOfOrder) {
|
|||
const uint64_t kRepeat = 0;
|
||||
|
||||
AddSegments(kLaterStartTime, kDuration, kSize, kRepeat);
|
||||
EXPECT_DEBUG_DEATH(AddSegments(kEarlierStartTime, kDuration, kSize, kRepeat),
|
||||
"");
|
||||
AddSegments(kEarlierStartTime, kDuration, kSize, kRepeat);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(CheckMpdAgainstExpectedResult());
|
||||
}
|
||||
|
@ -513,8 +512,7 @@ TEST_F(SegmentTemplateTest, OverlappingSegments) {
|
|||
CHECK_GT(kDuration, kOverlappingSegmentStartTime);
|
||||
|
||||
AddSegments(kEarlierStartTime, kDuration, kSize, kRepeat);
|
||||
EXPECT_DEBUG_DEATH(
|
||||
AddSegments(kOverlappingSegmentStartTime, kDuration, kSize, kRepeat), "");
|
||||
AddSegments(kOverlappingSegmentStartTime, kDuration, kSize, kRepeat);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(CheckMpdAgainstExpectedResult());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue