Fix media duration parsing in mdhd box of MP4 files to handle -1 values

Treats the media duration as unknown (`C.TIME_UNSET`) when all bytes are
`-1` to prevent exceptions during playback.

Issue: androidx/media#1819

PiperOrigin-RevId: 688103949
(cherry picked from commit 457bc55a4d)
This commit is contained in:
rohks 2024-10-21 05:51:49 -07:00 committed by Iván Budnik
parent 7da2161a7b
commit cc947dc690
2 changed files with 63 additions and 5 deletions

View file

@ -1,5 +1,44 @@
# Release notes
### Unreleased changes
* Common Library:
* ExoPlayer:
* Transformer:
* Extractors:
* Fix media duration parsing in `mdhd` box of MP4 files to handle `-1`
values ([#1819](https://github.com/androidx/media/issues/1819)).
* DataSource:
* `DataSourceContractTest`: Assert that `DataSource.getUri()` returns the
resolved URI (as documented). Where this is different to the requested
URI, tests can indicate this using the new
`DataSourceContractTest.TestResource.Builder.setResolvedUri()` method.
* Audio:
* Video:
* Text:
* Metadata:
* Image:
* DRM:
* Effect:
* Muxers:
* IMA extension:
* UI:
* Downloads:
* OkHttp Extension:
* Cronet Extension:
* RTMP Extension:
* HLS Extension:
* DASH Extension:
* Smooth Streaming Extension:
* RTSP Extension:
* Decoder Extensions (FFmpeg, VP9, AV1, etc.):
* MIDI extension:
* Leanback extension:
* Cast Extension:
* Test Utilities:
* Demo app:
* Remove deprecated symbols:
## 1.5
### 1.5.0-beta01 (2024-10-30)
@ -122,6 +161,11 @@ This release includes the following changes since the
* Fix `IllegalStateException` from
`DefaultDrmSession.requiresSecureDecoder` after opening a DRM session
failed. This issue was introduced in `1.5.0-alpha01`.
* Effect:
* Moved the functionality of `OverlaySettings` into
`StaticOverlaySettings`. `OverlaySettings` can be subclassed to allow
dynamic overlay settings.
* Muxers:
* IMA extension:
* Fix bug where server-side inserted DAI streams without a preroll can
result in an `ArrayIndexOutOfBoundsException` when playing past the last

View file

@ -958,14 +958,28 @@ public final class BoxParser {
int version = parseFullBoxVersion(fullAtom);
mdhd.skipBytes(version == 0 ? 8 : 16);
long timescale = mdhd.readUnsignedInt();
long mediaDuration = version == 0 ? mdhd.readUnsignedInt() : mdhd.readUnsignedLongToLong();
boolean mediaDurationUnknown = true;
int mediaDurationPosition = mdhd.getPosition();
int mediaDurationByteCount = version == 0 ? 4 : 8;
for (int i = 0; i < mediaDurationByteCount; i++) {
if (mdhd.getData()[mediaDurationPosition + i] != -1) {
mediaDurationUnknown = false;
break;
}
}
long mediaDurationUs;
if (mediaDuration == 0) {
// 0 duration normally indicates that the file is fully fragmented (i.e. all of the media
// samples are in fragments). Treat as unknown.
if (mediaDurationUnknown) {
mdhd.skipBytes(mediaDurationByteCount);
mediaDurationUs = C.TIME_UNSET;
} else {
mediaDurationUs = Util.scaleLargeTimestamp(mediaDuration, C.MICROS_PER_SECOND, timescale);
long mediaDuration = version == 0 ? mdhd.readUnsignedInt() : mdhd.readUnsignedLongToLong();
if (mediaDuration == 0) {
// 0 duration normally indicates that the file is fully fragmented (i.e. all of the media
// samples are in fragments). Treat as unknown.
mediaDurationUs = C.TIME_UNSET;
} else {
mediaDurationUs = Util.scaleLargeTimestamp(mediaDuration, C.MICROS_PER_SECOND, timescale);
}
}
int languageCode = mdhd.readUnsignedShort();
String language =