[MP4] Truncate segment references in 'sidx' if necessary

The reference count in 'sidx' box is a uint16 field, which allows at
most 0xFFFF entries, i.e. at most 0xFFFF subsegments, which is roughly
18 hours for one second segments.

Do not fail packaging when it happens. Instead, generate a warning and
truncate the number of references to 0xFFFF instead.

Note that the actual number of mp4 fragments in the mp4 file can still
be more than 0xFFFF. The stream will not play to the end in DASH, but
it will play successfully in HLS.

Workarounds #862.

Change-Id: Ib3930418d1528df1f9ea64cda0d0ebaa78d26abb
This commit is contained in:
KongQun Yang 2020-12-07 00:02:02 -08:00
parent c6b01f90ae
commit 516430bde1
1 changed files with 19 additions and 3 deletions

View File

@ -5,6 +5,7 @@
#include "packager/media/formats/mp4/box_definitions.h"
#include <gflags/gflags.h>
#include <algorithm>
#include <limits>
#include "packager/base/logging.h"
@ -2747,9 +2748,21 @@ bool SegmentIndex::ReadWriteInternal(BoxBuffer* buffer) {
buffer->ReadWriteUInt64NBytes(&earliest_presentation_time, num_bytes) &&
buffer->ReadWriteUInt64NBytes(&first_offset, num_bytes));
uint16_t reference_count = static_cast<uint16_t>(references.size());
uint16_t reference_count;
if (references.size() <= std::numeric_limits<uint16_t>::max()) {
reference_count = static_cast<uint16_t>(references.size());
} else {
reference_count = std::numeric_limits<uint16_t>::max();
LOG(WARNING) << "Seeing " << references.size()
<< " subsegment references, but at most " << reference_count
<< " references can be stored in 'sidx' box."
<< " The extra references are truncated.";
LOG(WARNING) << "The stream will not play to the end in DASH.";
LOG(WARNING) << "A possible workaround is to increase segment duration.";
}
RCHECK(buffer->IgnoreBytes(2) && // reserved.
buffer->ReadWriteUInt16(&reference_count));
if (buffer->Reading())
references.resize(reference_count);
uint32_t reference_type_size;
@ -2782,7 +2795,10 @@ size_t SegmentIndex::ComputeSizeInternal() {
version = IsFitIn32Bits(earliest_presentation_time, first_offset) ? 0 : 1;
return HeaderSize() + sizeof(reference_id) + sizeof(timescale) +
sizeof(uint32_t) * (1 + version) * 2 + 2 * sizeof(uint16_t) +
3 * sizeof(uint32_t) * references.size();
3 * sizeof(uint32_t) *
std::min(
references.size(),
static_cast<size_t>(std::numeric_limits<uint16_t>::max()));
}
MediaData::MediaData() = default;