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) &&
|
RCHECK(FullBox::ReadWrite(buffer) &&
|
||||||
buffer->ReadWriteUInt32(&track_id));
|
buffer->ReadWriteUInt32(&track_id));
|
||||||
|
|
||||||
// Media Source specific: reject tracks that set 'base-data-offset-present'.
|
if (flags & kBaseDataOffsetPresentMask) {
|
||||||
// Although the Media Source requires that 'default-base-is-moof' (14496-12
|
// MSE requires 'default-base-is-moof' to be set and
|
||||||
// Amendment 2) be set, we omit this check as many otherwise-valid files in
|
// 'base-data-offset-present' not to be set. We omit these checks as some
|
||||||
// the wild don't set it.
|
// valid files in the wild don't follow these rules, though they use moof as
|
||||||
//
|
// base.
|
||||||
// RCHECK((flags & kDefaultBaseIsMoofMask) &&
|
uint64_t base_data_offset;
|
||||||
// !(flags & kBaseDataOffsetPresentMask));
|
RCHECK(buffer->ReadWriteUInt64(&base_data_offset));
|
||||||
if (flags & kDataOffsetPresentMask) {
|
DLOG(WARNING) << "base-data-offset-present is not expected. Assumes "
|
||||||
NOTIMPLEMENTED() << " base-data-offset-present is not supported.";
|
"default-base-is-moof.";
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & kSampleDescriptionIndexPresentMask) {
|
if (flags & kSampleDescriptionIndexPresentMask) {
|
||||||
|
@ -1751,18 +1750,19 @@ uint32_t SampleGroupDescription::ComputeSize() {
|
||||||
return atom_size;
|
return atom_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackFragment::TrackFragment() {}
|
TrackFragment::TrackFragment() : decode_time_absent(false) {}
|
||||||
TrackFragment::~TrackFragment() {}
|
TrackFragment::~TrackFragment() {}
|
||||||
FourCC TrackFragment::BoxType() const { return FOURCC_TRAF; }
|
FourCC TrackFragment::BoxType() const { return FOURCC_TRAF; }
|
||||||
|
|
||||||
bool TrackFragment::ReadWrite(BoxBuffer* buffer) {
|
bool TrackFragment::ReadWrite(BoxBuffer* buffer) {
|
||||||
RCHECK(Box::ReadWrite(buffer) &&
|
RCHECK(Box::ReadWrite(buffer) &&
|
||||||
buffer->PrepareChildren() &&
|
buffer->PrepareChildren() &&
|
||||||
buffer->ReadWriteChild(&header) &&
|
buffer->ReadWriteChild(&header));
|
||||||
// Media Source specific: 'tfdt' required
|
|
||||||
buffer->ReadWriteChild(&decode_time));
|
|
||||||
if (buffer->Reading()) {
|
if (buffer->Reading()) {
|
||||||
DCHECK(buffer->reader());
|
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));
|
RCHECK(buffer->reader()->TryReadChildren(&runs));
|
||||||
|
|
||||||
// There could be multiple SampleGroupDescription and SampleToGroup boxes
|
// There could be multiple SampleGroupDescription and SampleToGroup boxes
|
||||||
|
@ -1778,6 +1778,8 @@ bool TrackFragment::ReadWrite(BoxBuffer* buffer) {
|
||||||
RCHECK(buffer->reader()->ReadChild(&sample_group_description));
|
RCHECK(buffer->reader()->ReadChild(&sample_group_description));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (!decode_time_absent)
|
||||||
|
RCHECK(buffer->ReadWriteChild(&decode_time));
|
||||||
for (uint32_t i = 0; i < runs.size(); ++i)
|
for (uint32_t i = 0; i < runs.size(); ++i)
|
||||||
RCHECK(runs[i].ReadWrite(buffer));
|
RCHECK(runs[i].ReadWrite(buffer));
|
||||||
RCHECK(buffer->TryReadWriteChild(&sample_to_group) &&
|
RCHECK(buffer->TryReadWriteChild(&sample_to_group) &&
|
||||||
|
|
|
@ -445,7 +445,7 @@ struct MovieFragmentHeader : FullBox {
|
||||||
|
|
||||||
struct TrackFragmentHeader : FullBox {
|
struct TrackFragmentHeader : FullBox {
|
||||||
enum TrackFragmentFlagsMasks {
|
enum TrackFragmentFlagsMasks {
|
||||||
kDataOffsetPresentMask = 0x000001,
|
kBaseDataOffsetPresentMask = 0x000001,
|
||||||
kSampleDescriptionIndexPresentMask = 0x000002,
|
kSampleDescriptionIndexPresentMask = 0x000002,
|
||||||
kDefaultSampleDurationPresentMask = 0x000008,
|
kDefaultSampleDurationPresentMask = 0x000008,
|
||||||
kDefaultSampleSizePresentMask = 0x000010,
|
kDefaultSampleSizePresentMask = 0x000010,
|
||||||
|
@ -532,6 +532,7 @@ struct TrackFragment : Box {
|
||||||
|
|
||||||
TrackFragmentHeader header;
|
TrackFragmentHeader header;
|
||||||
std::vector<TrackFragmentRun> runs;
|
std::vector<TrackFragmentRun> runs;
|
||||||
|
bool decode_time_absent;
|
||||||
TrackFragmentDecodeTime decode_time;
|
TrackFragmentDecodeTime decode_time;
|
||||||
SampleToGroup sample_to_group;
|
SampleToGroup sample_to_group;
|
||||||
SampleGroupDescription sample_group_description;
|
SampleGroupDescription sample_group_description;
|
||||||
|
|
|
@ -270,6 +270,7 @@ bool TrackRunIterator::Init() {
|
||||||
bool TrackRunIterator::Init(const MovieFragment& moof) {
|
bool TrackRunIterator::Init(const MovieFragment& moof) {
|
||||||
runs_.clear();
|
runs_.clear();
|
||||||
|
|
||||||
|
next_fragment_start_dts_.resize(moof.tracks.size(), 0);
|
||||||
for (size_t i = 0; i < moof.tracks.size(); i++) {
|
for (size_t i = 0; i < moof.tracks.size(); i++) {
|
||||||
const TrackFragment& traf = moof.tracks[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
|
RCHECK(desc_idx > 0); // Descriptions are one-indexed in the file
|
||||||
desc_idx -= 1;
|
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;
|
int sample_count_sum = 0;
|
||||||
|
|
||||||
for (size_t j = 0; j < traf.runs.size(); j++) {
|
for (size_t j = 0; j < traf.runs.size(); j++) {
|
||||||
|
@ -368,6 +371,7 @@ bool TrackRunIterator::Init(const MovieFragment& moof) {
|
||||||
runs_.push_back(tri);
|
runs_.push_back(tri);
|
||||||
sample_count_sum += trun.sample_count;
|
sample_count_sum += trun.sample_count;
|
||||||
}
|
}
|
||||||
|
next_fragment_start_dts_[i] = run_start_dts;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(runs_.begin(), runs_.end(), CompareMinTrackRunDataOffset());
|
std::sort(runs_.begin(), runs_.end(), CompareMinTrackRunDataOffset());
|
||||||
|
|
|
@ -112,6 +112,9 @@ class TrackRunIterator {
|
||||||
std::vector<SampleInfo>::const_iterator sample_itr_;
|
std::vector<SampleInfo>::const_iterator sample_itr_;
|
||||||
|
|
||||||
std::vector<FrameCENCInfo> cenc_info_;
|
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_dts_;
|
||||||
int64_t sample_offset_;
|
int64_t sample_offset_;
|
||||||
|
|
|
@ -496,8 +496,7 @@ TEST_F(SegmentTemplateTest, OutOfOrder) {
|
||||||
const uint64_t kRepeat = 0;
|
const uint64_t kRepeat = 0;
|
||||||
|
|
||||||
AddSegments(kLaterStartTime, kDuration, kSize, kRepeat);
|
AddSegments(kLaterStartTime, kDuration, kSize, kRepeat);
|
||||||
EXPECT_DEBUG_DEATH(AddSegments(kEarlierStartTime, kDuration, kSize, kRepeat),
|
AddSegments(kEarlierStartTime, kDuration, kSize, kRepeat);
|
||||||
"");
|
|
||||||
|
|
||||||
ASSERT_NO_FATAL_FAILURE(CheckMpdAgainstExpectedResult());
|
ASSERT_NO_FATAL_FAILURE(CheckMpdAgainstExpectedResult());
|
||||||
}
|
}
|
||||||
|
@ -513,8 +512,7 @@ TEST_F(SegmentTemplateTest, OverlappingSegments) {
|
||||||
CHECK_GT(kDuration, kOverlappingSegmentStartTime);
|
CHECK_GT(kDuration, kOverlappingSegmentStartTime);
|
||||||
|
|
||||||
AddSegments(kEarlierStartTime, kDuration, kSize, kRepeat);
|
AddSegments(kEarlierStartTime, kDuration, kSize, kRepeat);
|
||||||
EXPECT_DEBUG_DEATH(
|
AddSegments(kOverlappingSegmentStartTime, kDuration, kSize, kRepeat);
|
||||||
AddSegments(kOverlappingSegmentStartTime, kDuration, kSize, kRepeat), "");
|
|
||||||
|
|
||||||
ASSERT_NO_FATAL_FAILURE(CheckMpdAgainstExpectedResult());
|
ASSERT_NO_FATAL_FAILURE(CheckMpdAgainstExpectedResult());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue