From cc947dc6903cfb01de037bc11ea2b8f2772da005 Mon Sep 17 00:00:00 2001 From: rohks Date: Mon, 21 Oct 2024 05:51:49 -0700 Subject: [PATCH] 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 457bc55a4d37a7762c819db76bd58468ab1ca8b3) --- RELEASENOTES.md | 44 +++++++++++++++++++ .../media3/extractor/mp4/BoxParser.java | 24 +++++++--- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 0113fc293b..e7b383bc6a 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -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 diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParser.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParser.java index 9b51d089d5..8bc285fc2c 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParser.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/BoxParser.java @@ -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 =