554 Commits

Author SHA1 Message Date
rohks
153974e06c Derive average bitrate from stsz sample size and mdhd duration
Compute a precise average bitrate using total sample size (from `stsz`) and media duration (from `mdhd`), overriding any existing bitrate read from `btrt` or `esds` boxes.

PiperOrigin-RevId: 746497934
(cherry picked from commit 6f5982792aadc9fa795629758015d952323d5654)
2025-04-12 21:12:28 +01:00
bachinger
cb80fe4c7c Make AdPlaybackState.withAdDurationsUs work with removed ad groups
The assertion is changed to check that the number of passed
in arrays of durations is always matching `adGroupCount`
according to the behavior of `withRemoveAdGroupCount(int)`.

Issue: androidx/media#2267
PiperOrigin-RevId: 743185176
(cherry picked from commit d133300627a3d5757c7dd63fc008b2cf9afc70ba)
2025-04-12 21:09:09 +01:00
rohks
2bdf632369 Remove incorrect frame rate calculation using tkhd box duration
Frame rate is correctly determined using the media duration from the `mdhd` box and the sample count from the `stsz` box. The fallback calculation using the edited sample count and `tkhd` box duration is incorrect, as added silence at the beginning can increase the track duration without affecting the sample count.

No-op change, as we never use the fallback calculation for our sample files in the test.

PiperOrigin-RevId: 743081118
(cherry picked from commit c0e518df9709cc858c0610e4694d8753bdb638b7)
2025-04-12 21:08:54 +01:00
ibaker
358e002076 MP4: Parse alternate_group and expose it in Format.metadata
Issue: androidx/media#2242
PiperOrigin-RevId: 740794206
(cherry picked from commit 0d60c5bf25a8725c21affa951409ba148394c526)
2025-04-12 21:08:36 +01:00
rohks
3c4410e967 Add language information for video tracks in BoxParser for Mp4 files
PiperOrigin-RevId: 738777635
(cherry picked from commit 2d4b37dc282dfde1aa8580c0adae45e7fe8d2a28)
2025-04-12 21:02:36 +01:00
rohks
d920cf87a6 Fix parsing of language code in mdhd box
Language codes in the `mdhd` box are stored as three 5-bit values, each representing a letter ('a' to 'z') using an offset of `0x60`. If the decoded characters are not in this range, the language should be treated as undefined.

PiperOrigin-RevId: 738470544
(cherry picked from commit 2a4cbc3be47b54a59aef384b288ea802e34fb2f0)
2025-04-12 21:02:16 +01:00
rohks
dcb67102b9 Parse btrt box in BoxParser to get bitrate information for Mp4 files
PiperOrigin-RevId: 738370142
(cherry picked from commit 88da587b0a5742e31452d5b7609ef96c048095d0)
2025-04-12 21:00:30 +01:00
ibaker
75e28d82e3 Fix FLAC interactions with PBA 'remaining capacity'
The comment sounds like it is worried the next header won't fit after
`limit` and before the end of `data`, but the code was previously only
checking the space between `position` and `limit`. This led to some
unnecessary copies.

Running the Robolectric `FlacExtractorTest.sample()` test in only the
'partial reads' and I/O errors case (worst case for this bug) results
in 57271 copies without this fix, and 19 copies with it.

Sample of the first 10 copies before this fix, showing a copy is made
for every byte read from the input:

```
W/ibaker: Making a copy. input.position=8881, data.length=32768, pos=1, lim=1
W/ibaker: Making a copy. input.position=8882, data.length=32768, pos=1, lim=1
W/ibaker: Making a copy. input.position=8883, data.length=32768, pos=1, lim=1
W/ibaker: Making a copy. input.position=8884, data.length=32768, pos=1, lim=1
W/ibaker: Making a copy. input.position=8885, data.length=32768, pos=1, lim=1
W/ibaker: Making a copy. input.position=8886, data.length=32768, pos=1, lim=1
W/ibaker: Making a copy. input.position=8887, data.length=32768, pos=1, lim=1
W/ibaker: Making a copy. input.position=8888, data.length=32768, pos=1, lim=1
W/ibaker: Making a copy. input.position=8889, data.length=32768, pos=1, lim=1
W/ibaker: Making a copy. input.position=8890, data.length=32768, pos=1, lim=1
```

And the first 10 copies after the fix:

```
W/ibaker: Making a copy. input.position=41648, data.length=32768, pos=32753, lim=32768
W/ibaker: Making a copy. input.position=74401, data.length=32768, pos=32753, lim=32768
W/ibaker: Making a copy. input.position=107154, data.length=32768, pos=32753, lim=32768
W/ibaker: Making a copy. input.position=139907, data.length=32768, pos=32753, lim=32768
W/ibaker: Making a copy. input.position=172660, data.length=32768, pos=32753, lim=32768
W/ibaker: Making a copy. input.position=41648, data.length=32768, pos=32753, lim=32768
W/ibaker: Making a copy. input.position=74401, data.length=32768, pos=32753, lim=32768
W/ibaker: Making a copy. input.position=107154, data.length=32768, pos=32753, lim=32768
W/ibaker: Making a copy. input.position=139907, data.length=32768, pos=32753, lim=32768
W/ibaker: Making a copy. input.position=172660, data.length=32768, pos=32753, lim=32768
```

PiperOrigin-RevId: 738341007
(cherry picked from commit 71ff9c661cccaf2d0c0f9c67008911b4ec5a4397)
2025-04-12 21:00:30 +01:00
ibaker
9a91b2774e Add support for 32-bit FLAC files in the built-in FLAC extractor
Without this, 32-bit files fail to play with `Playback stuck buffering
and not loading`. With this change, playback works on devices where the
`MediaCodec` FLAC decoder supports 32-bit, and crashes on devices with a
`MediaCodec` FLAC decoder that does not support 32-bit.

A follow-up change will aim to transform the 'unsupported' case from a
crash into a report that the track format is not supported.

32-bit support was only fully incorporated into the spec when RFC 9639
was [published in December
2024](https://xiph.org/flac/2024/12/19/rfc-9639-published.html), and
it was been supported by `libflac` (for encode and decode) [since
September 2022](https://xiph.org/flac/2022/09/09/flac-1-4-0-released.html).
The original version of this `FlacExtractor` was written before either
of these, so only supported up to 24-bit.

Issue: androidx/media#2197
PiperOrigin-RevId: 737559285
(cherry picked from commit 8837ab25643bf4ed8a0c973ac637b3221e778f6a)
2025-03-18 11:03:31 +00:00
Copybara-Service
a578d43324 Merge pull request #2115 from MGaetan89:use_objects_equals
PiperOrigin-RevId: 730860597
(cherry picked from commit cc44de8757501cab7e4bb70fd0b090c6dc9799e1)
2025-03-03 16:26:31 +00:00
Copybara-Service
28b70f7e85 Merge pull request #2145 from v-novaltd:dsparano-exo328
PiperOrigin-RevId: 730853667
(cherry picked from commit 85467b9b57ab8ee38cfcb6c9e0f484fd167df372)
2025-03-03 16:26:31 +00:00
ibaker
d755a0477d Fix casting in ParsableByteArray.peekCharacterAndSize
This was introduced in 841bdc6efe.

There's no need to cast the `char` (2 bytes) down to a `byte` in order
to pack it into an `int` (4 bytes) alongside a short (2 bytes).

We also don't need to use `short` to track the character count (max 4
with UTF-8) - a single byte is enough. This change also uses
`Ints.fromBytes` to avoid having to reason about how casting &
bit-shifting interact.

This change introduces a test which reproduces the failure reported in
Issue: androidx/media#2167.

#cherrypick

PiperOrigin-RevId: 730809219
(cherry picked from commit fe19d8c9be94bbf1a1be8d3f49b2de52f0e2f1ae)
2025-03-03 16:26:31 +00:00
Copybara-Service
4d50e8a815 Merge pull request #2170 from wischnow:main
PiperOrigin-RevId: 729558029
(cherry picked from commit 7c2e8c1c4b608bc5da5649d7f2d7f9674dba5d36)
2025-03-03 16:26:30 +00:00
Googler
625ff234e4 Update CSD and apvC box logic
Update the CSD to contain only the APVDecoderConfigurationRecord and the apvC box to be a full box. The apv clip is also updated to be consistent with the new [specification](https://github.com/AcademySoftwareFoundation/openapv/blob/main/readme/apv_isobmff.md#isobmff-binding-for-apv).

The clip is provided by the openAPV team under BSD-3 license.

PiperOrigin-RevId: 727868656
(cherry picked from commit 653470f73be98e01e972513ec80e58c2d36cbb3a)
2025-02-18 09:42:24 +00:00
ibaker
2155c37b08 Switch most intra-lib deps from implementation to api
In all these cases I found at least one public method that takes or
returns a type from the dependency, or a type that inherits from a type
defined in the dependency.

PiperOrigin-RevId: 726130595
2025-02-12 11:29:50 -08:00
ibaker
5e6fb88372 Add missing LINT.If/ThenChange comments
PiperOrigin-RevId: 724291745
2025-02-07 04:10:41 -08:00
rohks
e15438322d Fix ArrayIndexOutOfBoundsException in MP4 edit lists
The exception occurred when an edit list started at a non-sync frame with no preceding sync frame. The fix searches forward for the next sync frame in such cases, preventing the out-of-bounds access.

Issue: androidx/media#2062

#cherrypick

PiperOrigin-RevId: 720642687
2025-01-28 11:13:38 -08:00
ibaker
a7a5d6e92b Suppress (and log) subtitle errors in SubtitleTranscodingTrackOutput
This is equivalent to the error suppression for legacy subtitles in
`TextRenderer`:
76088cd6af/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/text/TextRenderer.java (L357-L359)

This new suppression only affects errors thrown from files with
subtitles muxed together with audio/video. Standalone subtitle
files, and containers containing only text tracks, are handled
by the existing error suppression/reporting added in
49dec5db8b.

Issue: androidx/media#2052
PiperOrigin-RevId: 718930243
2025-01-23 10:49:23 -08:00
ibaker
9bb254f697 Skip SSA cues where end time is before or equal to start time
The file in Issue: androidx/media#2052 contains a cue with the following timecode:

```
0:00:00:00,0:00:00:00
```

The content of this cue seems to be some 'converted by' metadata, i.e.
it's basically a comment and clearly not intended to be shown on
screen (since it has zero duration).

There is some fiddly logic later in `SsaParser` to support overlapping
cues with the old `Subtitle` structure [1], and this logic gets tripped
up by the start and end time being equal, which results in a
**single**, empty `List<Cue>` being added - which trips up another
assumption that every SSA cue line results in at least two `List<Cue>`
entries (one containing the cue text, and another containing an empty
list to signal the end of the cues).

This fiddly logic is no longer required, because overlapping
`CuesWithTiming` objects can now be merged in `TextRenderer`, so there
is a possible future simplification to `SsaParser` which removes a lot
of this complexity.

[1] Added in <unknown commit>

PiperOrigin-RevId: 718380386
2025-01-22 07:41:24 -08:00
Copybara-Service
fda8b8a35d Merge pull request #2023 from DolbyLaboratories:dlb/dovi-format/dev
PiperOrigin-RevId: 716226613
2025-01-16 07:26:46 -08:00
ibaker
736c7528cb Ignore EOS buffer timestamps in CeaDecoder.queueInputBuffer
This is aligned with the documentation of `MediaCodec` which says the
timestamp of a buffer with `BUFFER_FLAG_END_OF_STREAM` should be
ignored:
https://developer.android.com/reference/android/media/MediaCodec#end-of-stream-handling

Add a test that exercises this by clipping off the end of a sample with
CEA-608 captions, because this creates an EOS-flagged buffer with a
non-EOS timestamp.

Also add a straightforward playback test for the
`fragmented_captions.mp4` sample.

PiperOrigin-RevId: 715716036
2025-01-15 02:40:07 -08:00
dancho
1892435fb3 Parse within GOP sample dependencies in ExtractorsFactory
Add helper methods to Mp4Extractor and FragmentedMp4Extractor
to convert between VideoCodecFlags and *ExtractorFlags

PiperOrigin-RevId: 715307495
2025-01-14 03:16:49 -08:00
Copybara-Service
d18ad57e30 Merge pull request #1979 from wischnow:main
PiperOrigin-RevId: 714911017
2025-01-13 04:09:58 -08:00
dancho
93f9e6574c Add missing Mp4Extractor.Flags to IntDef
PiperOrigin-RevId: 714084405
2025-01-10 09:54:19 -08:00
ibaker
e61b521b4a Clear SEI reordering queue when seeking in MPEG-TS files
This avoids outputting spurious samples after the seek.

PiperOrigin-RevId: 714082343
2025-01-10 09:45:21 -08:00
Ian Baker
77790df5a2 Plumb palette through as a method parameter to satisfy nullness checker 2025-01-10 17:17:28 +00:00
Ian Baker
b2f9c1e252 Reformat with google-java-format 2025-01-10 16:02:24 +00:00
Ian Baker
ce0512845f Fix lint/style issues, and log exception 2025-01-10 16:02:24 +00:00
Sven Wischnowsky
47a5166a1d Small fix for an off-by-two error. 2025-01-10 16:02:24 +00:00
Ian Baker
671810235f Assorted nullness and control flow clean-ups 2025-01-10 16:02:24 +00:00
Ian Baker
8520c66fd8 Add some nullness annotations, re-jig some logic and reformat 2025-01-10 16:02:24 +00:00
Sven Wischnowsky
391b72e257 Various cleanup and improvements as suggested by mainainer. 2025-01-10 16:02:24 +00:00
Sven Wischnowsky
f52d98eafd Use Util.maybeInflate() 2025-01-10 16:02:24 +00:00
Sven Wischnowsky
250bc86669 Add comments about needing the size in the IDX file. 2025-01-10 16:02:24 +00:00
Sven Wischnowsky
27a6883768 Another small fix 2025-01-10 16:02:24 +00:00
Sven Wischnowsky
7fbf511d30 Small fix 2025-01-10 16:02:23 +00:00
Sven Wischnowsky
721776c30e Support for Vobsub subtitles 2025-01-10 16:02:23 +00:00
dancho
c26a633d83 Read sample dependencies for H.265 in FragmentedMp4
Add a new flag to FragmentedMp4Extractor
FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES_H265
Read two bytes from H.265 videos to determine NAL unit type and
temporal layer id.

PiperOrigin-RevId: 714046987
2025-01-10 07:39:37 -08:00
ibaker
d0b757886e Fix handling of length-delimited NAL units with 1 or 2 byte length
ExoPlayer assumed 4-bytes for length in two places (by assuming the
length is the same as the 4-byte NAL start code):

1. In `AvcConfig` we transform length-delimited to start-delimited
   before writing into `initializationData`, and then skip
   'nal unit length field' bytes when parsing from `initializationData`
   (when we should skip 'start code length' bytes instead).

2. In `Mp4Extractor.readSample` we modify the local variable
   `sampleSize` to fix the difference between length field length and
   start code length, but **only on the first attempt to read a
   sample**. If we are resuming in the middle of reading a sample (after
   a recoverable I/O error), this fix for `sampleSize` is not done,
   which means we end up missing the last 2-3 bytes of the sample when
   the NAL length is 1-2 bytes.
     * This is fixed by moving the `sampleSize` 'fixing' code to outside
       the `if (sampleCurrentNalBytesRemaining == 0)` block.
     * `FragmentedMp4Extractor` has very similar code, but uses a
       field for `sampleSize`, rather than a local, so doesn't look
       vulnerable to the same problem (though I haven't totally
       tested this).

This change adds a test file with 2-byte NAL lengths, generated by
hacking the media3 muxer to emit 2-byte NAL lengths and transforming
`sample.mp4` using the transformer demo app.

PiperOrigin-RevId: 713709203
2025-01-09 10:06:13 -08:00
dancho
cd511ea60b Add a test file for FragmentedMp4 captions
The previous FragmentedMp4 captions test asset doesn't have captions.
Fix a bug where captions before extractor seek were output after.

PiperOrigin-RevId: 713665817
2025-01-09 07:35:21 -08:00
dancho
0cf52ed45d Read sample dependencies for H.265 in MP4
Add a new Mp4Extractor.FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES_H265
Read two bytes from H.265 videos to determine NAL unit type and
temporal layer id.

PiperOrigin-RevId: 713248154
2025-01-08 04:55:31 -08:00
dancho
b54d8737cf Add number of temporal layers to Format
The number of temporal sub-layers is required for
H.265 non-reference frame identification as
only frames from the highest temporal sub-layer can be
discarded.

PiperOrigin-RevId: 713247354
2025-01-08 04:50:45 -08:00
dancho
281a0e7ac8 Populate HevcConfig with number of temporal layers
The number of temporal sub-layers is required for
H.265 non-reference frame identification as
only frames from the highest temporal sub-layer can be
discarded.

PiperOrigin-RevId: 713242894
2025-01-08 04:31:24 -08:00
ybai001
d16d80ca49 Update Dolby Vision format handling
* Add the missing DV profile 10 handling
* Set DV codec string instead of compatible format codec string in MP4 extractor
2025-01-08 10:40:03 +08:00
dancho
229aadc91b Update javadoc for FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES
Reflects that FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES only parses
H.264 bitstream, and that H.265 parsing will be controlled with
another flag.

PiperOrigin-RevId: 712921990
2025-01-07 08:33:14 -08:00
ibaker
31e5142b72 Restrict SubRip and WebVTT parsing to exactly 3 decimal places
We previously parsed an arbitrary number of decimal places, but assumed
the value was in milliseconds, which doesn't make sense if there is
greater or fewer than 3. This change restricts the parsing to match
exactly 3, meaning the millisecond assumption is always true.

The WebVTT spec requires there to be exactly 3 decimal places:
https://www.w3.org/TR/webvtt1/#webvtt-timestamp

The SubRip spec is less clearly defined, but the Wikipedia article
defines it as having exactly 3 decimal places
(https://en.wikipedia.org/wiki/SubRip#Format) and ExoPlayer has always
assumed 3 decimal places (anything else is already handled incorrectly),
so this change just ensures we don't show subtitles at the wrong time.

Issue: androidx/media#1997
PiperOrigin-RevId: 712885023
2025-01-07 06:13:15 -08:00
Copybara-Service
8fe0b7ac69 Merge pull request #1987 from ojoNetgem:Support_for_origin_and_extent_declared_in_ttml_styles
PiperOrigin-RevId: 712554507
2025-01-06 09:30:15 -08:00
Ian Baker
8d9cb7e5d0 Resolve some TODO comments that are now fixed by the new parsing support 2025-01-06 15:13:32 +00:00
Ian Baker
618c2cf952 Add a release note and format with google-java-format 2025-01-06 15:13:32 +00:00
Olivier Jouvenaux
82bed39140 Add unit tests for TTML region attrs in style, chained styles UT 2025-01-06 15:13:32 +00:00