5866 Commits

Author SHA1 Message Date
tonihei
ecad8a5357 Version bump to Media3 1.6.0
PiperOrigin-RevId: 738421167
2025-03-19 09:07:01 -07:00
claincly
9bc088bf2b Remove VisibleForTesting on setVideoGraphFactory
This enables apps to use MultipleInput, or customized VideoGraphFactorys

PiperOrigin-RevId: 738413586
2025-03-19 08:45:26 -07:00
rohks
88da587b0a Parse btrt box in BoxParser to get bitrate information for Mp4 files
PiperOrigin-RevId: 738370142
2025-03-19 06:23:46 -07:00
claincly
8e56810b57 Use VideoFrameMetadataListener for replay notification
PiperOrigin-RevId: 738366305
2025-03-19 06:09:58 -07:00
tonihei
d6b9988eb0 Avoid unsupported mock operation
Calling a real method on an interface is not supported by
the Mockito version run by Gradle.

#cherrypick

PiperOrigin-RevId: 738358342
2025-03-19 05:39:37 -07:00
bachinger
b0bca83811 Add asset list loading methods to HlsInterstitialsAdsLoader.Listener
PiperOrigin-RevId: 738346245
2025-03-19 04:51:16 -07:00
ibaker
71ff9c661c 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
2025-03-19 04:26:35 -07:00
kimvde
14c06eaf8e Remove implementation of DefaultVideoSink.onRendererEnabled
The goal is to get rid of VideoSink.onRendererEnabled so that this
interface becomes renderer-agnostic. Indeed, for multi video sequences,
the DefaultVideoSink won't receive input from a single renderer anymore.

This is a no-op refactoring

PiperOrigin-RevId: 738296515
2025-03-19 01:23:45 -07:00
Googler
d0d76f214a Fix a race condition in HttpEngineDataSource
Pass the temporary CookieHandler as a parameter instead of setting it as a temporary process-default. This avoids a rare race condition, where the player is sending a request with preserveCookies option and runs the `CookieHandler.getDefault()` before a different thread sets a default cookie handler. Over 5 or so lines of code the new default might be reverted to null - this is now fixed.

PiperOrigin-RevId: 738052152
2025-03-18 10:16:08 -07:00
tonihei
06c0f5549e Exclude Xiaomi and OPPO devices from detached surface mode
Ideally, we'd find a more targeted exclusion as it may depend on
specific codecs. The current workaround should help with the
reported issues that are limited to Xiaomi and OPPO.

Issue: androidx/media#2059

#cherrypick

PiperOrigin-RevId: 738017969
2025-03-18 08:37:59 -07:00
tianyifeng
6470c97af4 Consider audio output latency when source has ended
With a [previous change](f05e6a7d6e), we makes `hasPendingData()` return `false` once we've found that the `AudioTrack` has played out all the written frames, to avoid it permanently stays `true` even when the source has ended. However, this is aggressive as the audio output device can still have latency in playing out those frames. So `hasPendingData()` should stay `true` a bit longer (for the duration of `latencyUs`) until finally turn to `false`, as well as the `getCurrentPositionUs()` should increment smoothly without a jump for the duration of `latencyUs`.

PiperOrigin-RevId: 738004292
2025-03-18 07:55:37 -07:00
kimvde
79f29680fc Ignore multi image sequence test
This test is failing in <unknown commit> when the following happens in
PlaybackVideoGraphWrapper:
- Both InputVideoSinks call onInputStreamChanged with startPosition
1000000000000
- Before the first VideoGraph output frame is available, both
InputVideoSinks call onInputStreamChanged with startPosition
1000000200000. This incorrectly erases startPosition
1000000000000 from TimedValueQueue streamStartPositionsUs. Indeed, when
1000000200000 is added for the second time, the whole queue is cleared
because this new value is not strictly greater than the previous one.

This start position logic should only be used for single-sequence
rendering. Disable the test until this is fixed.

PiperOrigin-RevId: 737982504
2025-03-18 06:35:06 -07:00
tonihei
b1068e47d3 Version bump to Media3 1.6.0-rc02
PiperOrigin-RevId: 737948053
2025-03-18 04:11:03 -07:00
tonihei
eef678f263 Wait for first frame when using placeholder surface
We currently pretend to be ready when using a placeholder
surface irrespective of whether the renderer is actually
ready to immediately render when a surface is attached.

This causes issues in two ways:
 - Apps don't know when a player without a surface can be
   connected to a surface and immediately start playing
 - A paused player without a surface will use the 1 second
   default doSomeWork loop, causing any pending decoding
   to be extremely slow (see Issue: androidx/media#1973).

The fix is to let the placeholder surface case use the same
paths as the regular surface and with marking the first
frame as available as soon as the codec output buffer for it
is pending and ready for release.

PiperOrigin-RevId: 737942496
2025-03-18 03:49:52 -07:00
tonihei
0e169ab1be Move decode-only and no surface logic inside VideoFrameReleaseControl
This brings the parts related to video frame release decision making
in a single place and simplifies the calling side in
MediaCodecVideoRenderer.

PiperOrigin-RevId: 737941729
2025-03-18 03:46:13 -07:00
tonihei
4daa43b257 Avoid unsupported mock operation
Calling a real method on an interface is not supported by
the Mockito version run by Gradle.

#cherrypick

PiperOrigin-RevId: 737940266
2025-03-18 03:40:03 -07:00
kimvde
bdc2216492 Skip looping sequences when computing composition duration
This fixes the following issue: in CompositionPlayer, if the
Composition was containing a looping sequence with duration larger than
all the other sequences, the Composition duration was set to the
looping sequence duration. This is incorrect because looping sequences
should be clipped to match the other sequences.

PiperOrigin-RevId: 737927987
2025-03-18 02:46:20 -07:00
claincly
9ac58fa405 Add frame cache to support replay frames
PiperOrigin-RevId: 737727035
2025-03-17 13:16:23 -07:00
bachinger
059cb23f3d Move AssetList to HlsInterstitialsAdsLoader
AssetList is used in the public API of
`HlsInterstitialsAdsLoader.Listener` in a child CL.

PiperOrigin-RevId: 737673293
2025-03-17 10:50:42 -07:00
Googler
0c78bae111 Add API to set resolution that respects orientation
This method allows a single Presentation Effect to resize portrait and landscape videos to a fixed resolution, while maintaining their orientations.

PiperOrigin-RevId: 737652909
2025-03-17 09:58:56 -07:00
shahddaghash
40ab0d40a1 Set LogSessionId on Transformer decoders and encoders
PiperOrigin-RevId: 737636636
2025-03-17 09:14:17 -07:00
michaelkatz
4932300b9a Reduce flakiness for ServerSideAdInsertion±MediaSourceTest past SDK 30
PiperOrigin-RevId: 737631774
2025-03-17 08:56:14 -07:00
tonihei
343a7b054e Clip start time to window duration when clipping
We currently throw an exception if the start time exceeds the
auto-detected end time at the duration even though an app can't
know this in advance in all cases. We should still throw an
exception if app-provided input values are non-sensical, but
auto-adjust the start time to the duration if needed similar to
how we already adjust the end time.

PiperOrigin-RevId: 737585207
2025-03-17 06:04:19 -07:00
tianyifeng
42b71c29e8 Loosen the condition for seeking to sync positions in a HLS stream
Previously we only enable `SeekParameter.*_SYNC` for HLS when `EXT-X-INDEPENDENT-SEGMENTS` is set in the playlist. However, this condition can actually be loosened. To seek in HLS, we need to download the segment in which the resolved seek position locates under any circumstance. If `SeekParameter.PREVIOUS_SYNC` or `SeekParameter.CLOSEST_SYNC` is passed, and that segment happens to start with sync samples, then the seek can be done quicker with that adjusted seek position. And if that segment doesn't start with sync samples, then the behaviour will be the same as we set the adjusted seek position to the exact original position. But we still cannot safely enable `SeekParameter.NEXT_SYNC` as it will potentially cause the seeking to miss more content than seeking to the exact position.

Issue: androidx/media#2209
PiperOrigin-RevId: 737580861
2025-03-17 05:43:45 -07:00
ibaker
75d7d1d71b Release Extractor instances created in ExtractorAsserts
PiperOrigin-RevId: 737576405
2025-03-17 05:21:07 -07:00
ibaker
27eb204542 Indicate MediaCodec FLAC decoder doesn't support 32-bit below API 34
This transforms the reported format support from `supported=YES` to
`supported=NO_EXCEEDS_CAPABILITIES`. Playback is still attempted in the
main demo app, and hangs as described in
https://github.com/androidx/media/issues/2197#issuecomment-2722322954.

PiperOrigin-RevId: 737568955
2025-03-17 04:47:50 -07:00
ivanbuper
cc4ffbe8cf Enforce one non-looping sequence in Composition
Before this change, exporting a Composition with all looping sequences
would result in a runtime exception due to a divide-by-zero exception
in TransformerInternal.

PiperOrigin-RevId: 737568877
2025-03-17 04:45:45 -07:00
ibaker
b47b8ffcd8 Switch lib-decoder-flac FlacExtractorTest to parameterization
The blocking bug has been resolved.

Also delete the now unused methods in `ExtractorAsserts`.

PiperOrigin-RevId: 737568115
2025-03-17 04:41:15 -07:00
ibaker
8837ab2564 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
2025-03-17 04:05:09 -07:00
ibaker
de9216462d Dump per-channel PCM data in CapturingAudioSink
This more clearly shows when a diff is on specific channels, or as a
result of channels being swapped.

PiperOrigin-RevId: 736920754
2025-03-14 11:05:31 -07:00
ibaker
800a66a8ca Remove unnecessary @SuppressWarnings("unused")
PiperOrigin-RevId: 736919032
2025-03-14 11:01:03 -07:00
tonihei
6b1a2aff98 Cleanup some dead code and lint warnings in session compat code
PiperOrigin-RevId: 736861977
2025-03-14 07:54:41 -07:00
ibaker
df489e2f94 Special-case empty and all-zero buffers in CapturingAudioSink dumps
These are common in robolectric playback tests, because our
`ShadowMediaCodecConfig` always returns empty buffers when 'decoding'
audio.

PiperOrigin-RevId: 736836767
2025-03-14 06:05:32 -07:00
Googler
641434ff31 Synthesize CSD data from AV1 sample in Muxer.
Synthesize CSD data from the key frame bit stream if CSD is not available for AV1 in Muxer.

PiperOrigin-RevId: 736815774
2025-03-14 04:16:21 -07:00
ibaker
fe8163838e Update Format.pcmEncoding docs to include lossless compression
This field has been used for encoded FLAC data since ba8f55694a

PiperOrigin-RevId: 736811640
2025-03-14 04:00:30 -07:00
tonihei
54c64b41c4 Add toString to TrackGroup(Array)
These classes are often logged in error messages or tests. The
current output is just the hash code which makes it hard to debug.

PiperOrigin-RevId: 736799086
2025-03-14 02:58:06 -07:00
tonihei
d37f05238a Check language/role flags before merging adaptation sets
The spec technically allows to mark adaptation sets with the switching
property if they allow seamless switching with non-overlapping
segments. This is typically only used for compatible content (e.g.
different codecs), but the spec allows it to be used for other
content as well (e.g. different languages, roles). ExoPlayer's concept
of a TrackGroup only allows formats with the same language and role
flags to be merged, so we should check that before merging.

Issue: androidx/media#2222

#cherrypick

PiperOrigin-RevId: 736564055
2025-03-13 10:54:17 -07:00
ibaker
412ba2e201 Replace links to xiph.org/flac/format.html with RFC 9639
PiperOrigin-RevId: 736564046
2025-03-13 10:52:33 -07:00
ibaker
dfebe72b6a Add 32-bit FLAC test files, and use them in some tests
The matroska file works without further changes. The FLAC container
file works with `lib-flac-decoder` depending on a bundled `libflac`
implementation, but not when using
`androidx.media3.extractor.flac.FlacExtractor` with a `MediaCodec` FLAC
decoder because the media3 extractor doesn't support 32-bit FLAC yet.
The fix for that is in a follow-up change.

`bear_32bit.flac` was generated from `bear.flac` with `ffmpeg`:

```shell
$ ffmpeg \
    -i bear.flac \
    -c:a flac \
    -sample_fmt s32 \
    -strict experimental \
    bear_32bit.flac
```

`bear-flac-32bit.mka` was generated by re-muxing `bear_32bit.flac`,
also with `ffmpeg` (trying to convert `bear-flac-24bit.mka` to 32-bit
didn't work, the resulting file was still 24-bit):

```shell
$ ffmpeg \
    -i ../flac/bear_32bit.flac \
    -c:a copy \
    bear-flac-32bit.mka
```

Issue: androidx/media#2197
PiperOrigin-RevId: 736552251
2025-03-13 10:21:18 -07:00
tonihei
41722be02e Clarify that method can only be called after onCreate
And improve error message if access to the notification controller
happens without a base context.

#cherrypick

PiperOrigin-RevId: 736545574
2025-03-13 10:05:30 -07:00
ivanbuper
d777a11840 Move createCodecProfileLevel() to MediaCodecUtil and simplify usages
This is a non-functional change.

PiperOrigin-RevId: 736534306
2025-03-13 09:34:10 -07:00
tonihei
816d5cb86b Refine logic of when to skip placeholder surface buffers
We want to skip the buffers in sync with playback, which
only makes progress once started. This means we can simplify
the logic to only apply the 30ms threashold when started
(which was indirectly the threashold used already because the
frame release would return TRY_AGAIN_LATER).

This means we can remove the
shouldSkipLateBuffersWhileUsingPlaceholderSurface as it was
only used in tests to prevent skipping while we were not
started.

PiperOrigin-RevId: 736533043
2025-03-13 09:31:17 -07:00
tianyifeng
6edb687aef Do not dump buffers not fully consumed repeatedly in CapturingAudioSink
#cherrypick

PiperOrigin-RevId: 736495022
2025-03-13 07:19:01 -07:00
claincly
4991e623c9 Use the actual render time in VideoFrameMetadataListener
This listener is used by apps to associate render timestamp and presentation
timestamp when using a SurfaceTexture, so this timestamp must match up with
what's set in `eglPresentationTimeANDROID`.

PiperOrigin-RevId: 736494784
2025-03-13 07:17:18 -07:00
ibaker
aa6d8a7666 Set connection & read timeout in HTTP data source contract tests
This timeout can be very low in these tests because we are always
trying to connect to an in-process `MockWebServer`. With the default
timeout value any 'resource not found' tests which use a domain that
can't be connected to take the max timeout (between 8s and 16s depending
on the HTTP stack).

PiperOrigin-RevId: 736466854
2025-03-13 05:16:59 -07:00
ivanbuper
6d00fe58b5 Remove deprecated BaseAudioProcessor in exoplayer module
`BaseAudioProcessor` was moved to `common` over two years ago.

PiperOrigin-RevId: 736179562
2025-03-12 10:27:24 -07:00
kimvde
03892cc1b5 VideoSink: merge setStreamStartPositionUs and onInputStreamChanged
setStreamStartPositionUs and onInputStreamChanged should both be called
when the stream changes.

PiperOrigin-RevId: 736121598
2025-03-12 07:17:41 -07:00
ibaker
99767c6e25 Use info from unseekable Xing frame when falling back to CBR seeking
This change uses the duration and byte count of the Xing frame, if
they're present, to estimate the bitrate of the stream. The seeking
will still be inaccurate (because we're doing CBR seeking in a VBR
stream), but it will be more accurate than basing the bitrate on the
first MP3 frame we read. It will also mean the duration reported is
accurate.

This change also ensures that if the Xing frame contains the number of
audio bytes but no ToC, the audio data length is still propagated into
the `XingSeeker` (and therefore into the `ConstantBitrateSeeker` too).

Issue: androidx/media#2194
PiperOrigin-RevId: 736100104
2025-03-12 05:50:35 -07:00
shahddaghash
1918a256cc Add a test for playing CompositionPlayer again after playback ends
A problem was discovered in Composition demo app where after playing a composition using CompositionPlayer, pressing the "play" button again would not restart the playback. This issue has been resolved, just adding a test to make sure we're not missing any regressions.

PiperOrigin-RevId: 735793488
2025-03-11 09:59:53 -07:00
michaelkatz
2729dbb8a9 Limit dynamic scheduling interval by the audio track buffer size
In certain bluetooth playback scenarios, it was found that the delta of audio duration written by the AudioSink from the current playback position was greater than the size of the audio track buffer, causing underruns.

The solution is to utilize the audio track buffer size as an upper limit for an audio renderer's getDurationToProgress.

PiperOrigin-RevId: 735761604
2025-03-11 08:16:22 -07:00