1634 Commits

Author SHA1 Message Date
dancho
036bed3632 Do not drop decoder input buffers close to a reset position
This is a workaround for a bug where the positionUs seen by
MCVR jumps when audio pre-roll samples are discarded.

PiperOrigin-RevId: 743538208
2025-04-03 06:31:32 -07:00
michaelkatz
8327a2a52d Do not enable offload scheduling while preparing next media
ExoPlayer disables sleeping for offload when the reading period advances and re-evaluates turning it back on when the playing period advances. For playlists of short items where the reading period could advance much further than the playing period, sleeping should still be disabled until the playing period advances to match the current reading period.

Issue: androidx/media#1920
PiperOrigin-RevId: 743503063
2025-04-03 04:15:15 -07:00
kimvde
18e9a3fe36 Rename VideoSink.onStarted/Stopped
start/stopRendering better reflects what the method does.

PiperOrigin-RevId: 743493973
2025-04-03 03:42:57 -07:00
tonihei
989e9f9e84 Remove remaining synchronized keywords from EPII
These are needed for the `waitUninterruptibly` handling, which is
really just waiting for a condition to become true on another thread
with a timeout, as well as Clock and interrupt handling.

We already have ConditionVariable that serves this purpose, which
has methods with a timeout and with interrupt handling. Adding
another version of the call with both timeout and interrupt handling
allows to replace the EPII manual code. The ConditionVariable methods
were also missing the clock calls to signal a wait operation.

PiperOrigin-RevId: 743214709
2025-04-02 11:30:04 -07:00
ibaker
a9c0349214 Standardize percentage calculations
This is a follow-up to 72f5df582a

PiperOrigin-RevId: 743173295
2025-04-02 09:46:15 -07:00
tonihei
0dd43b0183 Reduce 'synchronized' usage in EPII by making variable single thread
EPII currently uses 'synchronized' for two purposes:
 1. `waitUninteruptably` to ensure the condition checks and
    `wait` calls are atomic + the calls on the playback thread
    that update these conditions to `notifyAll`.
 2. Access to the `released` field that is used a condition
    for `waitUninterruptibly` but otherwise only accessed on the
    app thread.

We can remove the second usage by making the `released` variable
more clearly single thread on the app thread (including renaming to
make it obvious as this is the only variable in this class accessed
on that thread). The `waitUninterruptly` call for `release` can use
an `AtomicBoolean` like the other two calls to this method.

This also fixes a potential bug where a release timeout would leave
the `released` field as `false`, meaning future calls to these other
methods wouldn't be blocked early.

PiperOrigin-RevId: 743156035
2025-04-02 08:54:29 -07:00
ibaker
0517cea4d2 Add new EPI method for when only the suppression reason has changed
This also fixes the 'unsuitable output' logic incorrectly overriding
the `@PlayWhenReadyChangeReason` when only the playback **suppression**
state has changed.

PiperOrigin-RevId: 743148739
2025-04-02 08:32:08 -07:00
michaelkatz
9e80d6d263 Set static interval as default for dynamic scheduling with audio
Applications providing custom `AudioSink` implementations should have the dynamic scheduling for audio playback fallback to the static interval if they are not implementing `AudioSink#getAudioTrackBufferSizeUs()`.

PiperOrigin-RevId: 743082057
2025-04-02 04:47:32 -07:00
ibaker
d315d90f7a Add scrubbing mode API to ExoPlayer
This initial version prevents incoming seeks from pre-empting
in-progress seeks, allowing more seeks to complete when the scrubber
bar is dragged quickly back and forth.

More scrubbing optimizations will be added in follow-up changes.

PiperOrigin-RevId: 743052527
2025-04-02 03:00:05 -07:00
bachinger
c95544156d Clip live periods that get a duration and end position
When an ad is inserted into a live period with an unset
duration, the live period needs to be wrapped with a
`ClippingMediaPeriod` and then actually be clipped to
the end position when the duration gets known. Without
this the renderers will never see an EOS which prevents
the reading/playing period from advancing.

In the case of a server side inserted ad on the other
hand, the actual clipping needs to be prevented to
keep the current behavior for SSAI streams. In an SSAI
stream, an ad inserted before the current position should
not produce a snap back to the newly inserted ad. This is
currently prevented in both places, when the updated
timeline is handled to not disable the renderers, and when
the `mediaPeriodQueue` updates the queued periods. This
behaviour is preserved to not create side effects of this
change.

PiperOrigin-RevId: 742642715
2025-04-01 04:46:31 -07:00
kimvde
f2d644b7b4 PlaybackVideoGraphWrapper: update listener logic for multi sequence
- Only have the primary sequence renderers listen to
PlaybackVideoGraphWrapper events. These events only need to be
forwarded to a single ExoPlayer instance.
- Set the DefaultVideoSinkListener only once.

PiperOrigin-RevId: 742636455
2025-04-01 04:18:39 -07:00
kimvde
595b75b7d3 Deduplicate some of the calls to DefaultVideoSink methods
Some DefaultVideoSink methods are called once per sequence, but this
doesn't make sense as the DefaultVideoSink is connected to the
VideoGraph output. This CL calls the DefaultVideoSink method only for
the primary sequence.

The other problematic DefaultVideoSink method calls will be moved in
follow-up CLs.

This is part of the effort to prepare PlaybackVideoGraphWrapper for
multi-sequence.

PiperOrigin-RevId: 742625589
2025-04-01 03:42:22 -07:00
kimvde
f8b1dcc33b Move VideoSink config to dedicated method
This is  to improve readability of MediaCodecVideoRenderer.onEnabled

PiperOrigin-RevId: 742246092
2025-03-31 06:40:12 -07:00
claincly
ff6537d69b Fix a bug that video effects are added twice
The tests passed because of an issue in chaining. The chaining listener allows
self-looping, i.e. the producer and the consumer of a frame could be the same
instance. Like an effect chain of `a -> a -> b` This didn't fail any test
before, because the chaining is rectified when connecting a to b, but it should
have failed when connecting a to a.

PiperOrigin-RevId: 742215700
2025-03-31 04:22:18 -07:00
dancho
73fa820828 Skip decoder input buffers for encrypted content
Previous assertion was incorrect. Per-frame initialization
vectors are written to the output stream in
`FragmentedMp4Extractor`

PiperOrigin-RevId: 742203717
2025-03-31 03:34:09 -07:00
kimvde
427daef350 Remove VideoSink.setWakeUpListener
This is the last Renderer reference in VideoSink

PiperOrigin-RevId: 742189332
2025-03-31 02:26:56 -07:00
tianyifeng
72f5df582a Improve the precision of percentDownloaded in Downloaders
We don't require high precision in the calculation of `percentDownloaded` for `Downloader.ProgressListener.onProgress` though, when `byteCached == contentLength`, we hope the `percentDownloaded` to be `100f` (rather than `99.99999f`). The result of `byteCached * 100f` can be less precise as the floating-point numbers are sparser when the value is far from zero. For example, if `byteCached == 812345L`, then the `byteCached * 100f` will become `81234496` (value checked by `BigDecimal`).

PiperOrigin-RevId: 741895445
2025-03-29 16:47:31 -07:00
michaelkatz
a4f5f67d7e Fix media period mismatch during recoverable renderer error processing
If a recoverable renderer error occurred just before playing period transition(aka media item transition) then the player may enter a continuous loop of retrying to play the previous media item.

This was most easily reproduced in an audio offload scenario where init in offload mode always fails. In initializing the following media, the process would fail with recoverable error to try in non-offload mode. The player would try to recover with playing the previous media item. Most times it would skip to the next track but not always.

Issue: androidx/media#2229
PiperOrigin-RevId: 741213293
2025-03-27 11:03:49 -07:00
kimvde
12b4c7d780 Remove unused param from VideoSink
PiperOrigin-RevId: 740739740
2025-03-26 06:15:03 -07:00
kimvde
3d5e650980 Improvements to VideoSink.Listener
- Remove unused VideoSink parameter
- Make methods default so that implementations don't have to override
them all

PiperOrigin-RevId: 740715000
2025-03-26 04:28:07 -07:00
kimvde
d4ea3ad932 PlaybackVideoGraphWrapper: fix inputType discrepancy
PiperOrigin-RevId: 740699944
2025-03-26 03:29:43 -07:00
kimvde
6cd15fb4b0 Remove PlaybackVideoGraphWrapper param from its listener methods
It's unclear why the listeners would need access to the
PlaybackVideoGraphWrapper as there should always be only one. Also,
it's not common practice to pass the parent object to the listener in
media3 (see Player.Listener for example).

PiperOrigin-RevId: 740686007
2025-03-26 02:32:51 -07:00
kimvde
0ad7ceadb3 Remove references to Renderers from VideoSink
Remaining references will be removed in follow-up changes

PiperOrigin-RevId: 740362812
2025-03-25 08:43:44 -07:00
ibaker
4338355422 Use dumper.addIfNonDefault in CapturingAudioSink
If encoded audio is dumped, some of these values may not be set.

Also add a related TODO

PiperOrigin-RevId: 740357230
2025-03-25 08:24:44 -07:00
michaelkatz
6e510c26df Set that any error during pre-warming disables and resets pre-warming
For now, even if a recoverable error occurs during pre-warming, the current process will be that pre-warming is disabled until subsequent media item transition.

PiperOrigin-RevId: 740349517
2025-03-25 08:02:42 -07:00
kimvde
2642d895bd Remove VideoSink.onRendererEnabled
This is part of the effort to make VideoSink independent from renderers.

PiperOrigin-RevId: 740344126
2025-03-25 07:44:50 -07:00
Googler
6034a3c3d6 Tone map in CompositionPlayer if surface can't display HDR
PiperOrigin-RevId: 740290183
2025-03-25 04:17:50 -07:00
tianyifeng
a1738f96f9 Add a Factory for DownloadHelper and deprecate forMediaItem() methods
PiperOrigin-RevId: 739909021
2025-03-24 06:03:24 -07:00
ibaker
75a067a223 Add unsuitable audio output to to-string logic in EventLogger
PiperOrigin-RevId: 739875995
2025-03-24 03:35:09 -07:00
shahddaghash
d5dcbf4a12 Extract CodecInfo from CodecImpl and expose default CodecInfo configs
This is a step towards unifying ShadowMediaCodecConfig structure to accommodate both ExoPlayer and Transcoding codecs configuration.

This change abstracts the codec information to a separate `CodecInfo` class. This allows having codecs with the same information configured with different configurations (passthrough/frame-dropping, decoder/encoder). It also does the following:
* Replaces the map of default codecs with public static final CodecInfo constants for each codec.
* Modifies the ShadowMediaCodecConfig constructor to accept a set of CodecImpls instead of mime types.
* Updates factory methods to reflect the constructor change.
* Updates addSupportedMimeTypes to addDecoder, taking a CodecInfo instead of a mimeType.

This is a non-functional change.

PiperOrigin-RevId: 739857883
2025-03-24 02:17:06 -07:00
tonihei
a472300c7a Use getAchievableFrameRatesFor to find approximate SW codec limits
We currently assume SW codecs are capable of playing all resolutions
and frame rates up to their declared supported maximum values, even
though the are likely not able to keep up playback smoothly for higher
resolutions. For HW codecs we can check PerformancePoints to declare
them as EXCEEDS_CAPABILITIES if they technically support a format but
are not performant enough. We can do the same for SW codecs by
checking getAchievableFrameRatesFor.

PiperOrigin-RevId: 739253653
2025-03-21 11:57:55 -07:00
ibaker
1230573dfb Parameterize ExoPlayerTest and remove sub-class
PiperOrigin-RevId: 739207473
2025-03-21 09:32:04 -07:00
rohks
99f364992a Fix KEY_TRACK_ID in MediaFormat returned by getTrackFormat()
The `KEY_TRACK_ID` was incorrectly set to the track index instead of the track ID from the media file.

PiperOrigin-RevId: 738761146
2025-03-20 05:15:21 -07:00
claincly
8e56810b57 Use VideoFrameMetadataListener for replay notification
PiperOrigin-RevId: 738366305
2025-03-19 06:09:58 -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
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
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
claincly
9ac58fa405 Add frame cache to support replay frames
PiperOrigin-RevId: 737727035
2025-03-17 13:16:23 -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
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
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
800a66a8ca Remove unnecessary @SuppressWarnings("unused")
PiperOrigin-RevId: 736919032
2025-03-14 11:01:03 -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
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
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
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