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
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
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
This also fixes the 'unsuitable output' logic incorrectly overriding
the `@PlayWhenReadyChangeReason` when only the playback **suppression**
state has changed.
PiperOrigin-RevId: 743148739
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
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
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
- 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
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
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
Previous assertion was incorrect. Per-frame initialization
vectors are written to the output stream in
`FragmentedMp4Extractor`
PiperOrigin-RevId: 742203717
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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