In general, metrics collection should not lead to Transformer thorwing and crashing the app.
PiperOrigin-RevId: 739099456
(cherry picked from commit 3f5019b9088555e8bbbd492901c272ae47b5fb67)
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
The current instanceof check accidentally unpacks the child,
returning the inner period instead of the one passed to the source.
PiperOrigin-RevId: 746556825
(cherry picked from commit 68538029c926642da42a7ebf40543f480c38146e)
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)
In `PreloadMediaSource` we accesses the `MediaPeriod.getBufferedPositionUs()` when we receive `onContinueLoadingRequested()` from the period. For `ProgressiveMediaPeriod` which requires loading a portion of media file to get it prepared, there is a chance that it needs more than one round of `onContinueLoadingRequested()` -> `continueLoading()` to complete preparation, for example, when the `setContinueLoadingIntervalBytes()` is small enough to not include the full information for preparation. Thus we should avoid `MediaPeriod.getBufferedPositionUs()` being called before period is prepared, as it will fail at `assertPrepared`.
Issue: androidx/media#2315
PiperOrigin-RevId: 746490375
(cherry picked from commit 344f249511ad67a42d8328e79102f02bbbec5201)
Some interactions create a default notification provider if
no custom one is set yet (e.g. setForegroundServiceTimeoutMs).
This means a later call to setMediaNotificationProvider will
silently fail to apply the new provider.
This can be fixed by making the media notification provider
updatable.
Issue: androidx/media#2305
PiperOrigin-RevId: 746428193
(cherry picked from commit 9ca8540f85fba2ff5c8ff151706f36e7b30b46e6)
In `PlayerWrapper.getCurrentTimelineWithCommandCheck()` we
always return `new CurrentMediaItemOnlyTimeline(this)` in
case the wrapped player doesn't have `COMMAND_GET_TIMELINE`
available but has `COMMAND_GET_CURRENT_MEDIA_ITEM`. This is
emulating a single item timeline with a static window count
of 1 which isn't correct when the wrapped player is empty.
Instead, when the wrapped player is empty we need to return
an empty timeline to match the wrapped player.
Issue: androidx/media#2320
PiperOrigin-RevId: 746071237
(cherry picked from commit 5f940af3df5e644b33d45c78cd5103f78566efd0)
Currently, a notification may be recreated even if a user dismissed
it as long as the standard conditions for a notification are true.
To avoid this effect, we plumb the dismissal event to the notification
controller, so that it can override its `shouldShowNotification`
decision. The plumbing sets an extra on the media key intent, which
the session forwards as a custom event to the media notification
controller if connected.
Issue: androidx/media#2302
PiperOrigin-RevId: 745989590
(cherry picked from commit f672590b2deeffb06435eb542cfe0d0630894e92)
The surface must only be used by one player at a time. To ensure
that, we can keep a reference to the previously used player
and clear its surface reference before assigning to a new one.
Note that we do not need to clear the surface in onDispose
of a DisposableEffect because the lifecycle management of the
surface is moved to the Player and the Player takes care of
unregistering its surface reference as soon as the surface is
destroyed (which happens when the AndroidView element is no longer
is the Composable tree).
PiperOrigin-RevId: 745558414
(cherry picked from commit f9617e1f8dade2b957fefd7eaa69da6d5c158eb8)
Previously, encrypted media segments did not have the chunk duration set,
causing an assertion failure during `CmcdData` creation. With this change,
the chunk duration is always set, while `CmcdData` ensures it is applied
only for media chunks.
Issue: androidx/media#2312
PiperOrigin-RevId: 745196718
(cherry picked from commit 9182b413dc6e14ed06817d8ad4ae65ce01d85f1b)
This is a workaround for a bug where the positionUs seen by
MCVR jumps when audio pre-roll samples are discarded.
PiperOrigin-RevId: 743538208
(cherry picked from commit 036bed36326130294f50264659913bdcecb4c9bc)
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
(cherry picked from commit 8327a2a52dd72a98d4abc123f33cfe1250898318)
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)
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
(cherry picked from commit 9e80d6d263d04021e24d4897f415898964a93a05)
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)
The proxy classes Android(Embedded)ExternalSurface just provide a
simple API surface around AndroidView wrapping SurfaceView and
TextureView respectively. However, this prevents accessing the
underlying views directly, which is needed for full lifecycle
tracking by the Player and to access surface size updates (which
are not available when the API is reduced to just `Surface`).
Instead of the proxy classes, we can directly use AndroidView from
PlayerSurface. This allows to call the proper Player APIs to set
SurfaceView or TextureView, so that the Player can keep track of
the view lifecycle and update its internal state and size tracking
accordingly. Because the player keeps tracks of the lifecycle,
none of the callback structure in Android(Embedded)ExternalSurface
is needed, nor are the additional setters for options that are
all default.
PiperOrigin-RevId: 743079058
(cherry picked from commit a1ed0d4ff63fc9e359c8ef1bc53aae43e4b709e3)
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
(cherry picked from commit 6e510c26df0d354312abe480b238afa47abedd3d)
If the `RtspMediaSource.Factory` is provided a `MediaItem` containing a uri with the scheme `rtspt`, then the factory will create its `RtspMediaSource` configured to use TCP.
Issue: androidx/media#1484
PiperOrigin-RevId: 740340604
(cherry picked from commit a220b0cb5e16e6cb8d8719a0e1ffa7e00859abc0)
The `KEY_TRACK_ID` was incorrectly set to the track index instead of the track ID from the media file.
PiperOrigin-RevId: 738761146
(cherry picked from commit 99f364992afa35aa1dba6621ffaa0dc7f1247327)
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)
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)
This field has been used for encoded FLAC data since ba8f55694a
PiperOrigin-RevId: 736811640
(cherry picked from commit fe8163838ed4adead705e2a537973d3c741f5d8e)
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
(cherry picked from commit 2729dbb8a9c9ea29d49efd5ffc30e734b7c86048)
Calling a real method on an interface is not supported by
the Mockito version run by Gradle.
#cherrypick
PiperOrigin-RevId: 738358342
(cherry picked from commit d6b9988eb073d30c7074bae44dba2a48e5d6e687)
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
(cherry picked from commit d0d76f214a3417ec39f86b1003dd0850a88638d9)
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
(cherry picked from commit 06c0f5549e366071ad98050e85ed0e8f1cd36fdf)
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
(cherry picked from commit 6470c97af415d91ad46a1f21c7f2ab5b0716f39c)
The original behaviour of the `handleSetCookieRequests` is preserved.
A bug is addressed, where it woulld set `Set-Cookie` header in the client request (as opposed to the expected `Cookies`).
PiperOrigin-RevId: 732945338
(cherry picked from commit 814d368d9f54f47f6f0372c7905846104c549322)
The original behaviour of the `handleSetCookieRequests` is preserved.
A bug is addressed, where it woulld set `Set-Cookie` header in the client request (as opposed to the expected `Cookies`).
PiperOrigin-RevId: 730857996
(cherry picked from commit 3b38a7a43bc35de1f77338a30bd5dce1d6991e82)
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
(cherry picked from commit dfebe72b6a175ed92420c1946bd06b952d85132d)
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
(cherry picked from commit eef678f26382e74edbbd872173508c8642621160)
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
(cherry picked from commit 0e169ab1bea3a4cd9ff2772d77618c66b5262f3c)
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
(cherry picked from commit 816d5cb86b13629a7ca23dba122f943f175d3bb9)
Calling a real method on an interface is not supported by
the Mockito version run by Gradle.
#cherrypick
PiperOrigin-RevId: 737940266
(cherry picked from commit 4daa43b25727d1d197095d0a9e2cc5a3610d881a)
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
(cherry picked from commit 343a7b054e3e90974c6930f56230b2e96c440d4e)
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
(cherry picked from commit 42b71c29e8bca0369381d100d5cec912e1c1e7ef)
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
(cherry picked from commit 27eb204542dd461a8d77ff58d4ec9599ce336a33)
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)
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
(cherry picked from commit 54c64b41c45397f7cc5892a27c541fdbf6a3cd58)
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
PiperOrigin-RevId: 736564055
(cherry picked from commit d37f05238a2d8b45ea2e5f4ac026084b917f30df)
And improve error message if access to the notification controller
happens without a base context.
#cherrypick
PiperOrigin-RevId: 736545574
(cherry picked from commit 41722be02e34199543dc92c44e12ff95a35cb378)
This allows apps to set a shorter timeout if so desired.
Issue: androidx/media#2206
#cherrypick
PiperOrigin-RevId: 735360459
(cherry picked from commit 222950cfd1bdc942b90e0991e6b96a3f2c86518a)
We currently combine stopping the FGS and optionally removing the
notification in one method, which unnecessarily gates its logic on
checking the desired foreground state again. This causes a bug where
the notification should be removed (because shouldShowNotification
returns false), but stays visible because the service is allowed
to stay in the foreground and the notification removal code is not
triggered.
Issue: androidx/media#2211
PiperOrigin-RevId: 735126704
(cherry picked from commit 91ecc16198bbb48d114a6d581669a9e670c161da)
PlayerSurface exposing the Modifier argument means the gradle dependency needs to be stricter
#cherrypick
PiperOrigin-RevId: 734237616
(cherry picked from commit 8dcfa1afbead8d7af1e11e871df9359052f107c6)
This was requested in Issue: androidx/media#2191 for playback of Opus and Vorbis
files with more than two channels with a float PCM pipeline.
Also, add ChannelMappingAudioProcessorTest.
PiperOrigin-RevId: 733766680
(cherry picked from commit f996a5e3e4b395fe1782392ae90fb088143aa806)
A state holder that handles interaction with a UI component that toggles through a range of playback speeds.
[demo-compose] Use PlaybackSpeedState to create PlaybackSpeedTextButton
Add the button to the bottom extra controls.
PiperOrigin-RevId: 731449526
(cherry picked from commit addf01b9a84bcea945107b3b2993540ec59fbb54)
AudioManager internally assumes the thread is was created on can be
used as a callback thread. Since the AudioManager is only created
once in the lifetime of an app, we need to make sure its obtained
on a thread that stays alive.
#cherrypick
PiperOrigin-RevId: 732072255
(cherry picked from commit 2088697a19ac85feb26ba2521a70647803246571)
On API < 26, the callback thread couldn't be set and the current compat
code assumes it's always the main thread. This isn't true, however,
because AudioManager uses the thread on which it was first instantiated
anywhere in the app.
#cherrypick
PiperOrigin-RevId: 731696188
(cherry picked from commit 1ac82d982460f47589484052f57e27a63b0eb08b)
Without this change, content that contains a PSSH box with only
the ClearKey UUID is not playable on devices with API < 27.
This includes our `sample_fragmented_clearkey.mp4` test content.
PiperOrigin-RevId: 731308444
(cherry picked from commit 275e7d3dbddd04792b472a06ff808f748237f8d5)
When there is both audio and video track, then fragment
creation is driven by video track (a combination of duration
so far + next key frame). But if there is no video track, then
the duration so far drives the fragment creation.
Due to bug, when there is only audio track, only first
fragment was created as expected and then a new fragment is
created for every audio sample.
PiperOrigin-RevId: 731257696
(cherry picked from commit d16fdcb8cc832909b1ff531a00e595c64df5c799)
This ensures all AudioManager calls are moved off the main
thread.
Having the audio focus management on the playback thread
also allows future improvements like requesting audio focus
only just before the player becomes ready (which is recommended
but not currently done by ExoPlayer).
PiperOrigin-RevId: 730962299
(cherry picked from commit 19c7b2127568e05b829efe2d9943be04657cefd1)
This resolves an app crash on devices with Google Play Services
installed but disabled due to `FLAG_MUTABLE` on a `PendingIntent`.
Issue: androidx/media#2178
#cherrypick
PiperOrigin-RevId: 730885329
(cherry picked from commit c4eef6042bbd814cbf25b3bb91ae1433618a290a)
Before API 27, the platform DRM components incorrectly expected
`C.COMMON_PSSH_UUID` instead of `C.CLEARKEY_UUID` in order to perform
ClearKey decryption. `FrameworkMediaDrm` is responsible for doing this
adjustment on these API levels, but this call was missed when
refactoring some DRM code in
c872af4bc0.
This led to `MediaCodec$CryptoException: Operation not supported in this
configuration` errors when doing ClearKey playback on devices with
API < 27. This was because the earlier, clearer error from the
`MediaCrypto` constructor was being swallowed and transformed to
`requiresSecureDecoder = true` by the `catch` logic in
`FrameworkMediaDrm.requiresSecureDecoder`.
This change also makes the error handling in
`FrameworkMediaDrm.requiresSecureDecoder` more robust by assuming
`requiresSecure = false` for ClearKey (and true for all other DRM
schemes), since we know that ClearKey never supports secure decoding.
This will help avoid more ClearKey playback failures if we see other,
unrelated, errors at this point.
Issue: androidx/media#1732
#cherrypick
PiperOrigin-RevId: 730882278
(cherry picked from commit ecb83f3b738db25f503153617ba9db7bb9dc5b4b)
HLS extractors were missing
experimentalSetCodecsToParseWithinGopSampleDependencies prior to this patch.
PiperOrigin-RevId: 730878460
(cherry picked from commit da402cfd64ef3ae60607491730f01138177a077b)
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)
If the deprecated path without a context is used, the capabilities
are set externally and can't recover automatically back to the real
capabilities.
Issue: androidx/media#2168
PiperOrigin-RevId: 730427339
(cherry picked from commit 5610cc846589aafa416c39567f4f5599e98a77ef)
Dropping too many consecutive input buffers reduces the update
frequency of MCVR.shouldDropDecoderInputBuffers and can lead to
dropping too many consecutive input buffers.
Discarding input buffers of type OBU_FRAME_HEADER with
show_existing_frame = 1 saves a smaller amount of resources
than discarding input buffers of type OBU_FRAME.
PiperOrigin-RevId: 730362707
(cherry picked from commit 67e99f46481dbc5fff9ffd04ff13119dac9199bb)
`onConnect_controllerInfo_sameInstanceFromServiceToConnectedControllerManager`
was flaky because `onDestroy()` of `MockMediaSessionService` was cleaning
up the `TestServiceRegistry`. This includes releasing the session of the service
after which no further `MediaSession.Callback` methods are called. This created
a race between `Callback.onDisconnected` and the `Mediasession.release()` being
called.
`onDestroy()` is called unexpectedly early because the controller unbinds as the
last controller from the service that never was started (`onStartCommand` never
called). In such a case the service is immediately terminated by the system after
the last client unbinds from the service, which called `onDestroy()` on the mock
service.
This change making `MockMediaSessionService` optionally not clean up the
registry in `onDestroy()` prevents the session from being released too early.
Alternatively, starting playback and hence starting the service into the
foreground would prevent the problem as well for the purpose of the test.
Another alternative to fix the test would be removing the session from the
service before releasing the controller.
PiperOrigin-RevId: 730361199
(cherry picked from commit fbe186a70ccb588889d0909ccfc07affaf49ec51)
If the name does not match patten, it gets skipped when reporting.
PiperOrigin-RevId: 729463344
(cherry picked from commit 23ebea7ab4afe1cff4b4c3fce222e33639dfd34e)
We currently only catch IOExceptions to close the opened data source.
This means any other type of exception leaves the data source open,
which can caused SimpleCache to be blocked forever when another
data source tries to access the same cache area (which is still
locked by the open data source).
This problem was the cause for flakiness in DownloadManagerDashTest.
#cherrypick
Issue: google/ExoPlayer#9760
PiperOrigin-RevId: 729441817
(cherry picked from commit 72c85aa48393e47642688c8147bdf18d6e3d4bbf)
In some cases, the ExoPlayer immediately transitions to `STATE_IDLE` or `STATE_ENDED` on application thread, while `isLoading` can still remain as `true` before it is finally updated from playback thread.
Issue: androidx/media#2133
#cherrypick
PiperOrigin-RevId: 728724157
(cherry picked from commit daf8f9ff584e52128b94b4b08a1e9cf7ba94dee2)
This is done by getting the session ID for the `EditingSession` and making sure it's unique from the other session ID.
PiperOrigin-RevId: 728680628
(cherry picked from commit ae3eed234382d95bd9187c965c6b949be97fda63)
Add VP9 and APV codecs to the list of supported video mimetypes for Mp4Muxer and Fragmented Mp4Muxer.
PiperOrigin-RevId: 728603222
(cherry picked from commit 1461e9e93a94e2cb27c096dea2c6c2eee934c3df)
This ensures it's easier to handle these State updates in other
helper classes if needed.
Issue: androidx/media#2128
PiperOrigin-RevId: 728264396
(cherry picked from commit f1c62c12394e3c408b24d98ed2472ed88db3e918)
The publish task currently forces to run lint and test
even though there is no technical dependency. If a
process (e.g. releasing a new library) wants to verify
lint and test work, it should run these steps explicitly.
#cherrypick
PiperOrigin-RevId: 728234811
(cherry picked from commit 4b991ad42f3139e7e528a87bf19056bfdb5d9f5a)
This includes creating a new Factory for `MetricsReporter` and adding it to Transformer. This is done as we need to create a new `MetricsReporter` for each export operation, so it makes sense to have a Factory.
PiperOrigin-RevId: 727798528
(cherry picked from commit 6d408c2d31bddacb254bb0cc917e4ecd5d0e4b66)
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)
Otherwise it's impossible to install the androidTest apk
of both lib-datasource and lib-exoplayer on the same device
#cherrypick
PiperOrigin-RevId: 727867871
(cherry picked from commit 527e1d52aedbff53e3ba670d2b6a3cf0b0a84abb)
Following the README, a libflac directory is created, which
needs to be ignored in VCSs
#cherrypick
PiperOrigin-RevId: 727103140
(cherry picked from commit b306b1059772c2e279020f65ac60ae975fca3fbf)
Currently, as soon as the playback is considered disengaged (not
ready and playing), the foreground service is stopped.
This causes problems if the app or the user attempts to restart
playback after a short amount of time, where apps may run into
foreground service start restrictions.
Almost all of these short-term interaction issues can be solved
by keeping the foreground service running for an additional
timeout period, which is chosen to be 10 minutes to match the
behavior of future Android system enforcements. For any longer
term interactions, apps need to implement playback resumption
paths that can restart the service with the previous playback.
One caveat is that we currently use player.pause() as a way to
stop the foreground service in onTaskRemoved() if the app wants
to abandon playback at this point. With the timeout, the service
can no longer be stopped immediately just by calling pause(),
so we need to explicitly disable the timeout in the corresponding
helper method.
Issue: androidx/media#1928
Issue: androidx/media#111
PiperOrigin-RevId: 726942625
(cherry picked from commit 8a888d0d1801ce018b5bca5dbab78be44507286e)
500ms may not be enough to start playback on a slow device
#cherrypick
PiperOrigin-RevId: 726940099
(cherry picked from commit 792a2ae05dbade27d9cd5a8923a1f3cebf083a91)
Controller and browsers are typically obtained with
Futures.addCallback(future, getMainExecutor()), which triggers
the onSuccess callback with a message post. We currently send
the initial media button preferences inline, causing the callback
in MediaController.Listener.onMediaButtonPreferencesChanged to
arrive before the FutureCallback.onSuccess callback.
In the test controller app, which causes crashed when
connecting to existing sessions for example. We can make this
more robust by also posting the initial update of the media button
preferences.
PiperOrigin-RevId: 726923498
(cherry picked from commit d5df227b3ae4d87ec4876cc19ecca814c91c5fd7)
We currently set both actions depending on the playWhenReady state
and we require both actions when converting a platform session to
a Media3 session (if ACTION_PLAY_PAUSE isn't set anyway).
This causes problems in two situations:
- A controller using the platform ACTION_PAUSE/ACTION_PLAY to
determine which button to show in a UI. This needs to be aligned
to the existing Util.shouldShowPlayButton we already use when
setting the PlaybackStateCompat state.
- A session only setting either ACTION_PAUSE or ACTION_PLAY
depending on its state. We should check if the action triggered
by setPlayWhenReady(...) is possible and allow COMMAND_PLAY_PAUSE
accordingly.
PiperOrigin-RevId: 726916720
(cherry picked from commit 28bfb27fb59ceb0cd209ac1eebd803d31f78afa4)
When converting to platform states, STATE_ENDED is mapped to
STATE_STOPPED, but the reverse mapping always assumes STATE_STOPPED
means STATE_IDLE at the moment. We can use the same logic we already
apply for STATE_PAUSED to figure out if we are ended.
PiperOrigin-RevId: 726902064
(cherry picked from commit 982403a0ccab31de1f293fb0b8591e2132e11dd2)
Currently the notification disappears immediately when the player
enters an error or stopped state, but still has its media and
could resume on user request.
This can be fixed by only checking the existence of media and not
the state when deciding to show a notification.
PiperOrigin-RevId: 726901050
(cherry picked from commit f0da364d3fdd8574c8506f0682a7d2ecf8135ad8)
Added tests for APIs `getDrmInitData()`, `getPsshInfo()`, `getLogSessionId()` and `setLogSessionId(LogSessionId)`.
The Widevine encrypted sample was created from already existing `sample_fragmented.mp4` using `mp4encrypt`.
PiperOrigin-RevId: 726881977
(cherry picked from commit e9df85b48d5c8c0727146ace4528293e3f6ecfd5)
This means the volume is available in the internal player,
which is a preparation step to moving the audio focus
handling to the internal player too.
PiperOrigin-RevId: 726880098
(cherry picked from commit ef9b6d212e74c304730161434200244183ae23e6)
This avoids distributing the logic between multiple classes and
keeps ExoPlayerImpl simpler.
PiperOrigin-RevId: 726874038
(cherry picked from commit 1015ef8b565ed04e88a9c596798d294327d05536)
The creation can be moved to the playback thread (to guarantee it
happens in sync other initialization after playback start) and the
potentially blocking calls to the reporting methods can be moved
to the generic shared BackgroundExecutor (it can't use the playback
thread because it no longer exists when the session is ended after
the player is released).
PiperOrigin-RevId: 726872818
(cherry picked from commit d386e002d2b34817178d088f277ced3bf3943ef2)
The mute value usually changes in line with volume == 0.
Also update the test to provide better coverage of the
immediate and delayed state changes.
PiperOrigin-RevId: 726839927
Updating the list of supported codec in Mp4Muxer and
FragmenetdMp4Muxer is often missed when a new codec is added
in Boxes.java.
PiperOrigin-RevId: 726397337
Add a new ByteBufferAllocator interface, with a simple
LinearByteBufferAllocator implementation that supports basic memory
allocations and reuse.
Add an AnnexBToAvccConverter.process override that takes a custom allocator
PiperOrigin-RevId: 726380184
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
When possible, make it the caller's responsibility to release the
GlObjectsProvider. It's good practice that the class creating an object
also releases it. It avoids releasing the same object (here, the
GlObjectsProvider) multiple times, which was causing
DefaultVideoCompositorPixelTest to fail.
PiperOrigin-RevId: 725983417
This ensures that when the input sample rate handled by the encoder differs from the output of the AudioGraph, that output audio will not be broken.
PiperOrigin-RevId: 725610384
The change includes adding a `MetricsReporter` interface with a default implementation to allow testing the `EditingMetricsCollector`.
PiperOrigin-RevId: 725607330
The new asset loader is a wrapper around a provided `MediaProjection` and
`SurfaceAssetLoader`.
The test relies on automating the UI to get a `MediaProjection` instance, which
doesn't work reliably on all devices, so it's restricted to Pixel devices from
API 29 onwards.
For now only video is supported. The plan is to add support for audio playback
capture (also using `MediaProjection`) in a later change(s).
PiperOrigin-RevId: 725241962
In a image sequence, seek to after the image duration should render the final
image frame. But currently it hangs as ConstantRateTimestampIterator doesn't
output any timestamp in this case
PiperOrigin-RevId: 724295475
This test also changes the image seeking behavior to match ExoPlayer: now if
seeking to after the end of the image, the last frame of the image would still
be presented.
PiperOrigin-RevId: 724054371
In the case of replace stream media item transition, it is important that dynamic scheduling does not set the next work task later than the transition boundary.
#cherrypick
PiperOrigin-RevId: 723502204
AV1 input buffers contain multiple compressed pictures.
Enable skipping only the last showable frame, while leaving
any reference pictures to be decoded later, as part of
the next decoder input buffer.
Partial skipping of AV1 input buffer is only applied when:
* fewer than 8 OBUs are delayed
* there's likely to be enough capacity in the decoder input buffer
for the next frame
PiperOrigin-RevId: 723496060
Parsing AV1 bitstreams allows us to identify frames that are
not used as reference, and improve seeking or frame dropping
behavior.
The AV1 bitstream format is relatively quick to parse
PiperOrigin-RevId: 723462680
From the `sampleMimeType`, we can know whether the media item contains video data, image data, and audio data. This is done for input media items, and the output media item.
PiperOrigin-RevId: 723459732
- It's never used and handling multi-threading is costly.
- If the VideoCompositor and the VideoFrameProcessors use separate
threads and the same GlObjectsProvider, the GlObjectsProvider is
accessed from multiple threads. This class doesn't seem designed for
multi-threading.
PiperOrigin-RevId: 723448013
When a timeline change occurs, the `AdTagLoader` will post an adLoad timeout task if currently waiting for an ad to load. Once sdk calls `loadAd`, any pending timeout tasks are removed. If the timeout occurs, the ad group is canceled and content will resume.
If the SDK proceeded to resume content without calling `loadAd`, then any pending timeout tasks should be removed or else a future ad group may error due to a previous timeout task.
PiperOrigin-RevId: 723442852
Seeking will reset media periods following the current playing period. This includes resetting any current pre-warming media periods. Therefore while seeking, any current pre-warming should be disabled and reset.
#cherrypick
PiperOrigin-RevId: 723439145
When sample batching is disabled, copying of the ByteBuffer data
is not necessary as samples are written as they arrive.
Copying of the BufferInfo is necessary because the info is needed
for writing the moov atom.
The input ByteBuffer can be in little endian order, or have its
position set. AnnexBUtils now ensures big endian order before
inspecting bytes, and supports reading from a non-zero position.
This change reduces the amount of memory allocations by Mp4Muxer
in its default configuration
PiperOrigin-RevId: 723401822
Previously, the codec names for the input were collected from `Format.codecs` which return the RFC 6381 string not the codec name used. This was changed to retain the decoder name from `ProcessedInput` instead.
PiperOrigin-RevId: 723129667
This will allow the listeners who are interested in the `SeekMap` to get informed once the period has done the preparation.
PiperOrigin-RevId: 723027718
MediaCodecVideoRenderer is becoming unwieldy with the numerous constructors and optional settings. This refactors MediaCodecVideoRenderer to use a builder pattern for simplicity.
PiperOrigin-RevId: 723022129
It includes entering a custom text and setting the alpha scale. When the effect is applied, it shows the text in the center of the screen. A following change will include changing the color of the text.
PiperOrigin-RevId: 721828892
Also updated DefaultVideoFrameProcessor to create GlShaderPrograms with the working ColorInfo rather than the output ColorInfo.
PiperOrigin-RevId: 721748002
This means we need convert some of the assertions in
ClippingMediaPeriod to contrain the output value to clipped
range instead, because unseekable media will return zero
as a start and seek position in all cases.
PiperOrigin-RevId: 721463824
Most of the values for the output `MediaItemInfo` will be retained from the `ExportResult`, so it's now passed to `onExportSuccess` and `onExportError` directly. For now, the duration of the ouput is recorded for metrics, and more values will be added in the following CLs.
PiperOrigin-RevId: 721324689
This is necessary for prewarming. With prewarming, in a sequence of 2
videos, the second renderer is enabled before the first one is disabled,
and decode-only frames should be skipped before the second renderer is
started. The problem is that the second renderer will forward frames to
a BufferingVideoSink before it is started, which will delay the frame
handling and therefore not skip the frame before the renderer is
started.
PiperOrigin-RevId: 721032049
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
Add an option to GlMatrixTransformation to choose the OpenGL texture
minification filter.
When mipmaps are requested, mipmaps are generated with
`glGenerateMipmap()`.
PiperOrigin-RevId: 720629807
This avoids that these settings have to be resolved inline,
potentially blocking the main thread. They can be resolved at
the time of track selection on a background thread instead.
As a side effect, we can also remove the context parameter from
the Builder. Having the Context in the Builder is also a bad sign
in the first place because it implies the potentially blocking
calls can happen.
PiperOrigin-RevId: 720523139
The calls to Util.isTV and the interactions with the spatializer are
potentially blocking and were triggered from the constructor,
setAudioAttributes and release.
setAudioAttributes and release are both documented to be called by
the Player and should be triggered on the playback thread anyway.
The constructor initialization can be delayed until the spatializer
might be needed to avoid the blocking call.
The threading clean-up also allows to remove the lock from the
audioAttributes and the spatializer fields as they are now
accessed on the playback thread only.
PiperOrigin-RevId: 720488979
Before the change, `SequenceAssetLoader#onTrackAdded` was being called twice, for audio and video. `ExportResult.ProcessedInput` took one format, which was the latest to be written. The change leads to capturing both, the audio and video formats of the input, and prevents the issue of a format overwriting the other.
PiperOrigin-RevId: 720487697
playback_sequencesOfVideos_effectsReceiveCorrectTimestamps is failing
for prewarming. The following is happening:
- For prewarming, there are 2 alternating video renderers per sequence.
- When the first MediaItem ends (for both sequences), signalEndOfInput
is not called on the InputVideoSink (which is expected).
- The DefaultVideoCompositor doesn't receive the end-of-input-source
signal (which is also expected).
- As a result, the DefaultVideoCompositor never outputs the last frame
because it waits for more input frames to be fed.
- The VideoGraph thus doesn't output the last frame either, and the
first video renderer never ends.
- This causes playback to get stuck.
This is similar to the problem of supporting multiple video sequences
with images and videos in CompositionPlayer.
PiperOrigin-RevId: 720106413
Usage:
* call queueInputBuffer() with initialization data or sample data in decode
order - updates the parser state
* call sampleLimitAfterSkippingNonReferenceFrame to identify if the sample
contains a frame without dependencies
PiperOrigin-RevId: 720098835
Previously, the input media item's duration was collected from `ProcessedInput.durationUs`. However, this value turned out to be the duration of the media item after clipping. Getting the duration of the input media item before clipping is tricky, so it will be dropped from Editing Metrics V1.
PiperOrigin-RevId: 719254077
When reading quickly this suggests something 'real' was null (similar to
a `NullPointerException`), but it's actually just the message from the
superclass.
Seen in stack trace in Issue: androidx/media#2074:
```
Caused by: androidx.media3.common.ParserException: null {contentIsMalformed=true, dataType=1}
```
PiperOrigin-RevId: 719240235
The fix is to update `AudioGraphInputAudioSink.lastHandledPositionUs` when a buffer is handled, and end the `AudioGraphInputAudioSink` as the final audio sink plays out further than this position.
PiperOrigin-RevId: 718901825
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
This requires some additional state handling to update the full
state atomically and guess placeholder states while updates are
in progress, using the newly added BackgroundThreadStateHander.
Some tests also needed to be adjusted to account for the fact
that the actual audio system change doesn't happen inline
anymore.
PiperOrigin-RevId: 716702141
This is pre work required to remove `Muxer.java` interface
from the muxer module.
`Mp4Muxer` and `FragmentedMp4Muxer` will no longer implement
the `Muxer` interface.
PiperOrigin-RevId: 716669531
This is a common pattern in media3 libraries where tasks are handled on a
background thread, but the calling thread sees an immediate state update
with a best-guess placeholder. This makes the integration for the caller
very easy as the API surface appears to be synchronous.
This util is a helper class to handle this logic and test it separately.
PiperOrigin-RevId: 716233966
The `DataSpace` contains the Color Standard, Range, and Transfer. These values were mapped as follows:
* Standard: From `@C.ColorSpace` to `@DataSpace.DataSpaceStandard`
* Range: From `@C.ColorRange` to `@DataSpace.DataSpaceRange`
* Transfer: From `@C.ColorTransfer` to `@DataSpace.DataSpaceTransfer`
PiperOrigin-RevId: 716157142
If a format is passed to `ExportResult.ProcessedInput`, the `containerMimeType` and `sampleMimeType` are extracted from the Format and passed inside the `MediaItemInfo` object.
PiperOrigin-RevId: 715840400
To receive multiple schemes of metadata emitted by a stream, multiple
`MetadataRenderer` instances need to be used. This change makes
`DefaultRenderersFactory` add two metadata renderers by default.
PiperOrigin-RevId: 715790821
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
This is to prevent facing errors in apps using Transformer. It will be enabled again once the project is done and comprehensive tests are added.
PiperOrigin-RevId: 715435613
These tests were earlier using `MediaExtractor`, hence
they were in androidTest. Now `MediaExtractor` has been
replaced with `media3 MediaExtractorCompat` so these
test can be robolectric.
PiperOrigin-RevId: 715424470
Some checks in SingleInputVideoGraph were causing CompositionPlayer to
throw for a single media item sequence when repeat mode was enabled. The
reason was that, in this case, no new input stream is registered to the
VideoFrameProcessor.
PiperOrigin-RevId: 715409509
Currently, if a seek occurs when the audio sink was providing back pressure, the audio renderers will provide a durationToProgress based on the last non-writable sample prior to the seek.
Solution is to reset the value used for the `getDurationToProgress` when onPositionReset occurs.
This CL also makes sure to reset the value whenever the audiosink is flushed or reset.
PiperOrigin-RevId: 715361834
In `AudioTrackPositionTracker.hasPendingData()` method, `sourceEnded=false` is always passed. Thus, if the `AudioTimestampPoller` hasn't entered the `STATE_TIMESTAMP_ADVANCING` before the stream ends, then the current position can be inaccurately calculated in the absence of a correct `sourceEnded` value, and `AudioTrackPositionTracker.hasPendingData` will return a wrong result.
We used to avoid calling `getPlayheadPosition()` too often, which involves expensive binder request. However, here we need to adjust a bit back to compare the `writtenFrames` directly with `getPlayheadPosition()` after handling the end of stream, when not being able to declare `sourceEnded=true` can have significant difference.
PiperOrigin-RevId: 715358137
This renaming helps prevent the consumer from including `PlayerSurface` in a Compose tree based on `state.showSurface`. This field intuitively felt like the default would be not to show the surface (correct), but had an unintended consequence of not initialising `AndroidExternal(Embedded)Surface` (since the PlayerSurface Composable would be omitted).
To avoid this confusion, the `PresentationState` should communicate to the consumer when the Surface is not ready and hence should be covered with some overlay (shutter) to prevent poor UX from observing Surface resizing/freezing/flickering.
PiperOrigin-RevId: 714951607
Deprecate BundledChunkExtractor.experimentalParseWithinGopSampleDependencies
in favour of
ChunkExtractor.experimentalSetCodecsToParseWithinGopSampleDependencies
which takes a VideoCodecFlags IntDef flags that represent a set of codecs.
Add a DASH test using the new API with an H.265 video.
PiperOrigin-RevId: 714901602
In this mode there isn't an explicit signal from upstream that an input frame
is going to arrive at the `SurfaceTexture`. This means that when end-of-stream
is signaled we don't know when there won't be any more input frames.
Reject new frames in `onFrameAvailable` after input EOS is handled for the case
of reregistering frames automatically. This avoids those frames entering the
pipeline and causing us to unexpectedly handle frames after EOS.
PiperOrigin-RevId: 714858039
Earlier muxer wrote a different entry for every chunk but as
per the spec (ISO 14496-12) exact same chunks can be combined
and only the first chunk number can be written.
PiperOrigin-RevId: 714154531
It captures the information needed for the UI logic related to rendering of the video track (and later images) to the surface.
The video size will be correct only after the Player decoded the video onto the surface and can't be reliably extracted from MediaItem's metadata. The information about the video's true aspect ratio helps inform the UI elements (such as PlayerSurface Composable) how to customize the Modifiers.
Use this state in demo-compose to show off functionality of changing `PlayerSurface`'s aspectRatio
PiperOrigin-RevId: 714104260
Added the creation of `MediaItemInfo` for each MediaItem and passed the duration of the MediaItem to it. This is done for export operations that complete with success or with error.
PiperOrigin-RevId: 714056270
In some cases encoders include a sample rate in their AudioCapabilities but do not support encoding at that sample rate. This breaks the assumption used to write these tests, so disable them for now until the fallback logic is updated to handle this limitation.
PiperOrigin-RevId: 714055556
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
When the current MediaMetadata is automatically derived from the
MediaItem and Tracks, the result may change when state.buildUpon()
is used and new input data is provided (e.g. new current index).
To avoid reusing the previously derived MediaMetadata, we need to
reset it to null and re-evaluate it on every call to build()
Issue: androidx/media#1940
PiperOrigin-RevId: 714021424
Added reporting 2 values from Transformer:
- `exporterName`: name of the package calling for export. Example: "androidx.media3.transformer".
- `muxerName`: name of the muxer used for the export operation. Example: "androidx.media3.muxer".
PiperOrigin-RevId: 714000672
The initial discontinuity is currently only reported if
the period is prepared at the clip start position. However,
we need the discontinuity whenever we prepare at a non-zero
position (unless we know all samples are sync samples).
PiperOrigin-RevId: 713994155
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
We only care about the duration and don't want to force an initial
discontinuity.
The problem is not currently visible due to a bug in
ClippingMediaPeriod that ignores all dicontinuities if they don't
happen at the clip start position.
PiperOrigin-RevId: 713686333
The previous FragmentedMp4 captions test asset doesn't have captions.
Fix a bug where captions before extractor seek were output after.
PiperOrigin-RevId: 713665817
When CompositionPlayer added repeat modes in d0afb96c40, it
changed the logic in SimpleBasePlayer to workaround the specific
scenario in CompositionPlayer that didn't seem to work correctly.
The workaround is not really generically applicable though. The
source of the original problem was that the position values of
all state objects were connected to the "live" source of the
current player so that the repetition case couldn't be detected
(the position before and after the seek looked the same). The
solution is to use the newly added LivePositionSuppliers and
disconnect them before seeking.
PiperOrigin-RevId: 713659638
In some cases the position is supplied from a "live" source
that keeps changing its value at repeated calls. This typically
happens when forwarding to another backend with unpredictable
position values. The problem is that as soon as the backend
system has a position discontinuity, any previously created
PositionSupplier now returns a position that no longer makes
sense in the context of the State object it belongs to.
ForwardingSimpleBasePlayer already works around this issue by
having a util class to disconnect these live sources. This
change moves the same util to SimpleBasePlayer itself so it
can be reused by other implementations.
PiperOrigin-RevId: 713658046
If `experimentalSetEnableMediaCodecVideoRendererPrewarming` is set with `true`, `DefaultRenderersFactory` will provide `ExoPlayer` with a secondary `MediaCodecVideoRenderer` for use in pre-warming through its `createSecondaryRenderer` and `buildSecondaryVideoRenderer` implementations. `ExoPlayer` will then pre-process video of subsequent media items to reduce media item transition latency.
PiperOrigin-RevId: 713605911
The audio decoder is sometimes failing with error "previous call to
queue exceeded timeout - Codec reported err 0x80000000, actionCode 0,
while in state 6/STARTED". This is probably because the emulator is too
slow.
PiperOrigin-RevId: 713564117
At the point of playing period transition pre-warming has completed and the renderers should receive necessary resources for playback. This CL adds the `Renderer.MessageType` `MSG_TRANSFER_RESOURCES` to direct a renderer to transfer relevant resources to another renderer.
PiperOrigin-RevId: 713372754
We currently force discontinuities for all clipped content periods
that don't start from zero. This shouldn't be done for server-side
ad insertion streams where we are guaranteed to get a continuous
underlying stream.
To enable the right decision, we need to add a flag to
MediaPeriodInfo for isPrecededByTransitionFromSameStream, which
mirrors the existing isFollowedByTransitionToSameStream.
The problem is currently not visible due to a bug in
ClippingMediaPeriod that automatically ignores most discontinuities
that don't match the start of the clip.
PiperOrigin-RevId: 713315398
If an error occurred in the player before the test was calling one of
the waitUntilSomething() methods, a timeout exception was thrown instead
of the actual error.
PiperOrigin-RevId: 713292292
DASH periods can have a duration that is less than the end of the
last chunk in the period. In these cases, the sample data needs to
be clipped to the declared period duration. This already happens
IF the period duration is known at the point where we start loading
the media chunk. However, if the duration becomes known later or is
reduced (e.g. in a live stream), the existing media chunks are not
clipped. This causes unclean transitions across periods where the
player tries to transition to the next period, but renderers struggle
to output all the remaining surplus samples that should have been
clipped.
This can be fixed by asking ChunkSampleStream to discard surplus
samples that were loaded beyond a clipped duration when evaluating
the sample queue between chunk loads.
Issue: androidx/media#1698
PiperOrigin-RevId: 713288221
If a playback exception was thrown before or during awaiting the
frameCountBeforeBlockLatch, a TimeoutException was thrown instead of the
playback exception, hiding the actual cause of the failing test.
PiperOrigin-RevId: 713279627
This method is already quite complex and I will need to add more
complexity, so split it into multiple smaller methods.
This CL is a refactoring. There are no functional changes.
PiperOrigin-RevId: 713266816
The new `currentPlayer` was only used to check the available command. It should also be used for setting and clearing the Surface.
The PlayerSurface was still behaving correctly, perhaps due to the lambda being reevaluated with the new player (since `currentPlayer` is of type MutableState). Which meant it was also using the latest `player` that `PlayerSurface` was recomposed with (in the argument), rather than holding onto the original object.
PiperOrigin-RevId: 713264041
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
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
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
Expose NalUnitUtil.H265SpsData.maxSubLayersMinus1
Required for H.265 non-reference frame identification as
only frames from the highest temporal sub-layer can be
discarded.
PiperOrigin-RevId: 713232825
The change includes setting the final progress percentage when the export completes with error or is cancelled. The value for the progress is collected by calling `Transformer.getProgress()` before `transformerInternal` is set to null.
PiperOrigin-RevId: 713227568
Added the first overlay effect to the Effect demo. It includes an emitter of confetti that drops from the center of the frame.
PiperOrigin-RevId: 712940163
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
This will be useful for recording use cases, including screen recording with
audio queued via `RawAssetLoader`, where the duration is unknown.
PiperOrigin-RevId: 712895577
This change simplifies SpeedChangingAudioProcessor by removing unneeded
heuristics and synchronization added as workarounds to estimate input
and output frame counts.
The synchronization between the video processing and audio processing
threads cannot be completely removed yet because the static methods
depend on the input sample rate for the calculations. However, once
`SpeedChangingAudioProcessor` has been configured, then
`#getSpeedAdjustedTimeAsync()` should invoke the callback immediately.
PiperOrigin-RevId: 712893246
It captures some information needed for the UI logic related to rendering of the video track (and later images) to the surface.
Supporting `EVENT_RENDERED_FIRST_FRAME` helps improve the UX by covering the surface with an overlay (scrim/shutter) until the first frame is ready. This helps avoid sudden flickering during MediaItem transitions.
PiperOrigin-RevId: 712889568
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
If the caller is another asset loader (or another asset loader factory) that is
delegating to a `SurfaceAssetLoader`, it may want to call methods on the
`SurfaceAssetLoader`. Return the concrete type so that a cast isn't necessary
at the call site.
PiperOrigin-RevId: 712881130
This avoids requesting storage permissions for URLs that don't require it.
Also tidy clean-up into `cleanUpExport`, rename `releasePlayer` to
`releasePlayers` as there are players for both input and output, and reduce
live range of `uri` variable.
PiperOrigin-RevId: 712857115
Removed the check for `released` flag to be able to pass the actual progress when the export completes.
Also, removed resetting the `progressState` and `progressValue` to be able to get the actual progress. This block is also not necessary to have at this point.
PiperOrigin-RevId: 712851526
After this change, if the sample rate supported by the encoder differs from the requested sample rate and enableFallback is true, the AudioSampleExporter will convert audio to a sample rate supported by the encoder. This fixes a bug where the audio track is distorted when an unsupported sample rate is requested.
PiperOrigin-RevId: 712822358
This lets us provide a append-only output stream with overridden write() methods - unlocking use cases where we process the muxed data in a streaming fashion, as it's generated by the fragmented muxer.
PiperOrigin-RevId: 712581859
This will ensure that the new `ui-compose` module gets published on Maven
The fix is not necessary for `demo-effect` and `demo-compose` because they are not publishable
PiperOrigin-RevId: 712555702
Take care of releasing the player and re-initialising when returning to the app to prevent memory leaks.
Instead of overriding onStart, onPause, onResume, onStop - use Lifecycle*Effects for a more native compose cleanup. Requires a higher version of the lifecycle library.
PiperOrigin-RevId: 712542884
The latest version of `androidx.compose.foundation:foundation` fixed an issue where `AndroidEmbeddedExternalSurface` would not reset properly. This in turn prevented PlayerSurface Composable with type `SURFACE_TYPE_TEXTURE_VIEW` from being redrawn after returning to a stopped activity.
PiperOrigin-RevId: 712501647
Added reporting 2 values from Transformer:
- elapsed time since creation of the `editingSession` in milliseconds.
- the `ErrorCode` for export errors. The error codes were mapped from `@ExportException.ErrorCode` int to `@EditingEndedEvent.ErrorCode`.
PiperOrigin-RevId: 712472849
For the [0.5; 1) speed range, the combination of having a "slow down"
speed (i.e. more output frames than input frames), and Sonic potentially
needing to copy more input frames that are available in the input buffer
can lead to an unexpected underflow.
Specifically, the underflow happens in Sonic#queueEndOfStream() when the
following conditions are met (skipping some minor ones):
1. `inputFrameCount < remainingInputToCopyFrameCount`
2. `0.5f <= speed < 1`.
3. `outputFrameCount <
(inputFrameCount / remainingInputToCopyFrameCount) / 2`.
This underflow caused `SonicAudioProcessor#isEnded()` to return a false
negative (because `getOutputSize() != 0`), which would stall the
`DefaultAudioSink` waiting for processing to end after EOS.
In practical terms, the underflow is relatively easy to reproduce if we
consume all of Sonic's output and then immediately queue EOS without
queueing any more input in between. This should cause both
`inputFrameCount` and `outputFrameCount` to drop to 0.
PiperOrigin-RevId: 711773565
Added a new `EditingMediaMetrics` class that interacts with the platform's `MediaMetricsManager` through an `EditingSession` created when export starts.
Currently, only the `finalState` of the export event is reported to the `EditingSession`. Future changes will collect additional metrics based on the export operation's output.
PiperOrigin-RevId: 711721801
Some videos include zero length NAL units in the
length-delimited MP4 samples.
Empty NAL units are not spec-compliant (see ISO/IEC 14496-15 section 4.3.3.3),
but other players are able to play these videos (with warnings or errors).
With this change, we check track.sampleTable.sizes[sampleIndex] before
reading a byte from the NAL unit itself.
PiperOrigin-RevId: 711720621
The static method can estimate the number of input frames needed to get
a given number of output frames with a given Sonic configuration.
This CL is prework to remove the dependency of
`SpeedChangingAudioProcessor#getMediaDurationUs()` on non-static output
based heuristics and simplify `SpeedChangingAudioProcessor`.
PiperOrigin-RevId: 711446999
On many devices (for example pixel 7) a dolby vision file can be
decoded (either using dolby vision decoder or H265 decoder)
but they can't be re-encoded to dolby vision.
Allow test to encode to H265.
The test now passes on pixel 7. It was getting skipped earlier.
PiperOrigin-RevId: 711383794
A device (for example pixel 7) might support HDR encoding
but with H265 sample mime type but the existing condition made
assumption false on such devices.
The test still does not pass on pixel 7 because the format
matching condition is incorrect. It will be fixed in a separate CL.
PiperOrigin-RevId: 711368798
Replaced an existing APV file as bitstream syntax has now changed and
previous clip is not a valid bitstream anymore.
This clip was provided by the openAPV team and is under BSD-3 license.
PiperOrigin-RevId: 711318578
After this change if a sample rate is requested that is not supported by the available encoders and enableFallback is true, DefaultEncoderFactory will fall back to the encoder with the closest matching sample rate.
In the case when an encoding profile is included in requestedAudioEncoderSettings, an encoder matching that profile will continue to be preferenced.
PiperOrigin-RevId: 708295869
Added a new `usePlatformDiagnostics` in Transformer. This parameter enables/disables forwarding editing events and performance data to the platform.
This is pre-work for metrics support in Transformer. In the following CLs, metrics collection and forwarding will be implemented.
PiperOrigin-RevId: 707930368
- Added a condition to ensure `requiredIntervalUs > 0` in `DashMediaSource`.
- Resolves an issue where negative `requiredIntervalUs` triggered an infinite loop in `onPlaylistUpdateRequested()`, leading to application/stream freezes.
This fix restores smooth playback for multi-period DASH streams.
AMR-NB and AMR-WB are inherently mono, so channel count is set to 1. Sample rate is also hard-coded to adhere to codec standards.
Also removed unused parameter `hasAdditionalViews` in `StriData`.
#cherrypick
PiperOrigin-RevId: 707606245
The dump file for VP9 mp4 clips varied across SDK versions due to inconsistent CSDs from the platform extractor. By replacing the platform extractor with `MediaExtractorCompat`, the Media3 extractor will provide consistent CSDs across all SDK versions.
PiperOrigin-RevId: 707509473
This enables `AdsMediaSource` to be used with a live media
source that has a growing `AdPlaybackState` to which ad groups
can be appended.
Before this change, `AdsMediaSource` asserted that the number
of ad groups was kept the same, else an exception was thrown.
After this change, the assertion checks the validity of the
update and throws in case the update isn't considered valid.
An update is valid if ad groups are appended to the existing
`AdPlaybackState` or ads are appended to existing ad groups.
Further the `adGroupIndex` and `timeUs`of an existing ad
group can not be changed and once a media item is set for a
given ad, that media item can't be changed either.
PiperOrigin-RevId: 707244455
It seems that changes via Robolectric's `ShadowBuild.setManufacturer()`
and similar methods don't propagate correctly (or quickly?) to these
aliases.
This change resolves a failure caused by different test ordering in
`AudioCapabilitiesTest` in order to unblock the 1.6.0-alpha01 release.
A follow-up change will migrate other usages from `Util.XXX` to
`Build.XXX`.
PiperOrigin-RevId: 707125446
Added a contrast effect and the connection needed to apply the video effects to ExoPlayer.
The effect can be applied to the video by checking the "Contrast" card, and use the slider to change the contrast value. The effects are applied when `Apply effects` button is clicked.
PiperOrigin-RevId: 707092041
Both classes provide utilities widely used by apps that are not
yet available in Media3. This change imports the existing logic as
it is with style adjustments to the Media3 codebase.
PiperOrigin-RevId: 707067512
There are reproducible issues with codec timeouts when using
this API, so we disable it entirely until we know more about
potential fixes and where they are available.
Issue: androidx/media#1641
#cherrypick
PiperOrigin-RevId: 707025950
`MediaCodecVideoRenderer` will skip frames if a surface has not been set and video frame presentation time is early but too close to the current playback position. In the case that the `VideoFrameReleaseControl` says to `FRAME_RELEASE_TRY_AGAIN_LATER`, these frames should not be skipped.
PiperOrigin-RevId: 706711734
`Parcelable` is not safe for IPCs between binaries with potentially
different class definitions (e.g. two apps built from different versions
of media3).
If we get a use case to bundle metadata, then the `Metadata` and
`Metadata.Entry` classes needs to provide a `toBundle()` method.
PiperOrigin-RevId: 706678892
Metadata does not provide a `toBundle` method. It implements
`Parcelable` which is not safe for IPCs between binaries with
potentially different class definitions (e.g. two apps built from
different versions of media3).
If we get a use case to bundle metadata as well, then the `Metadata`
class needs to provide a `toBundle()` method.
PiperOrigin-RevId: 705920231
This change adds a new stable overload of
`SessionToken.createSessionToken` which takes the platform `Token` type
(instead of `Parcelable`). It also stabilises
`MediaController.getCustomLayout` & the corresponding listener.
PiperOrigin-RevId: 705917161
Custom actions are more naturally associated with a user intent
than commands (that are meant to be used for automated inter-app
communication without user interaction).
PiperOrigin-RevId: 705797057
Reads HLS interstitials information from the playlist and
populates the `AdPlaybackState` accordingly to play the ads.
An app can register a `Listener` to be informed about ad
related events.
Only VOD streams are supported and X-ASSET-LIST attibutes
are ignored with this change.
PiperOrigin-RevId: 705604201
When `PlayerSurface` composable gets a new `Player` object, it should initialise a new Android(Embedded)External Surface with it. However, the lambdas used for that are remembered with the reference to the old Player, even if it has been null'd and released properly.
Android(Embedded)ExternalSurface is an interop - `AndroidView` wrapping `SurfaceView` and `TextureView` under the hood. It uses the `onInit` lambda in its factory to create the View and reuses it on later recompositions, making it a longer-lived object than our Player.
`RememberUpdatedState` acts makes a mutable State out of the Player and always gets its latest value. One can think of it as creating a reference to the Player object and telling the lambdas to always resolve that reference in the moment, rather than hold onto the Player than was passed-by-value.
This change is a precursor to a better lifecycle management of Player and Surface in demo-compose.
PiperOrigin-RevId: 705529626
This test was testing a scenario that never happens in production.
Indeed, in this test, a frame was registered to the
ExternalTextureManager but never rendered on the decoder ouput surface.
This never happens in production because both actions are normally
performed in
PlaybackVideoGraphWrapper.InputVideoSink.handleInputFrame().
This test was also failing on API 31 emulator. As the frame was never
rendered, the timeout to release all registered frames in
ExternalTextureManager was always exceeded. This sometimes caused the
decoder to fail on this emulator because there was no interaction with
the decoder for a long time.
PiperOrigin-RevId: 705490910
Moved the `getObjectType` method from `CmcdData.Factory` to `CmcdData` and updated the logic to derive the object type directly within `CmcdData`. This change eliminates the need for chunk source classes to set this value explicitly.
PiperOrigin-RevId: 705457755
The `toBundle()` method is implemented incorrectly as it uses
`parcelable` implementation to bundle `Format.metadata`.
The `parcelable` is not compatible and is likely to cause crashes if
a new field is added or removed.
Moreover, the `fromBundle` method is likely unused as in session
module the exception is [unbundled](df887a9422/libraries/session/src/main/java/androidx/media3/session/PlayerInfo.java (L1021)) as `PlaybackException`.
This is a non breaking change as all the calls to `toBundle()` and
`fromBundle` will now go to the parent class `PlaybackException`.
If this specific bundling is required in future then `Format.Metadata`
and all the `Metadata.Entry` classes need to provide `toBundle()`
and `fromBundle()` method.
PiperOrigin-RevId: 705167002
Currently as there is no formal support for MV-HEVC within Android framework, the profile is not correctly specified by the underlying codec; just assume the profile obtained from the MV-HEVC sample is supported.
PiperOrigin-RevId: 705164738
- Moved static fields for object type, stream type, etc. from `CmcdData.Factory` to `CmcdData`.
- Removed redundant `CmcdData` prefix from `@ObjectType` and `@StreamingFormat` annotations.
#cleanup
PiperOrigin-RevId: 705159876
Before this change, the value of the `dwLength` in the stream header was
interpreted as the number of chunks in the file. Seeking and timestamp
calculation use the media duration and total chunk count. However, in some
files the `dwLength` field appears not to store the number of chunks. For
example, there are CBR MP3 and AC3 files where this field seems to store the
total number of bytes of compressed media instead. That caused seeking and
timestamp calculation to give much smaller values than expected (because the
`dwLength` is very large), which broke seeking.
Work around this using the `idx1` index header if present. We only support
audio formats where every audio sample is a sync sample in AVI, and all chunks
should therefore be listed in this index. Based on testing on many sample AVI
files this gives a reliable total chunk count and fixes seeking.
The test media file is a transcoded version of Big Buck Bunny but manually
edited to overwrite the length, rate and sample size header files to simulate
the error case.
PiperOrigin-RevId: 705103651
Playback was never ending in the case where the video graph rendered
the last frame to the output surface before the end-of-current-input
signal was received. This CL handles this specific case.
PiperOrigin-RevId: 705086366
`AudioTrackPositionTracker.pause` "re-arms" the event, to ensure it
fires again when playback resumes. However the `AudioTrack` position
advances by about 100ms **after** `AudioTrack.pause()`, which
consistently causes the event to fire immediately after pausing (and
then **not** after a subsequent resumption).
This change checks whether the `AudioTrack` is paused before firing
the event, to avoid this spurious trigger.
PiperOrigin-RevId: 704759929
The legacy custom layout doesn't support disabled buttons or buttons
with non-custom actions. These are currently filtered out, but in
inconsistent ways:
- MediaControllerImplBase doesn't filter at all.
- DefaultNotificationProvider filters before converting
mediaButtonPreferences, PlayerWrapper filters after the conversion.
- PlayerWrapper doesn't disable buttons that are unavailable.
To ensure it's consistent, we can add these checks to the existing util
method in CommandButton and also make sure PlayerWrapper disables
unavailable buttons before triggering the util method.
This also means we can simplify some of the tests that rely on the
mediaButtonPreference to customLayout conversion in MediaController.
This change also includes two bug fixes in PlayerWrapper that
became evident in the tests: The extras need to be copied to
avoid modifying a Bundle instance that be used elsewhere and
we need to update the custom layout and potentially the session
extras when the available commands change, as they depend on them.
PiperOrigin-RevId: 704678404
Added functionality to `Choose preset input` button. The picker allows the user to select a preset input from a list of loaded preset playlists. The selected preset input is then used to populate the ExoPlayer with the corresponding media items.
PiperOrigin-RevId: 704626144
`RenderersFactory#createSecondaryRenderer` can be implemented to provide secondary renderers for pre-warming. These renderers must match their primaries in terms of reported track type support and `RendererCapabilities`.
If a secondary renderer is provided, ExoPlayer will enable it for a subsequent media item as soon as its `MediaPeriod` is prepared. This will cause the renderer to start decoding and processing content so that it is ready to play as soon as playback transitions to that media item.
PiperOrigin-RevId: 704326302
AAC is the only format where the codec data buffer is actually used.
Invalid or obscure versions of the relevant syntax can break extraction when we
try to read the codec data, so it's better to read it only when it's required.
PiperOrigin-RevId: 704308925
It's expected that the subtitle load errors are emitted as a non-fatal
error, but it's not defined exactly when they will be emitted. By
consistently ignoring these every time we 'advance' the player, this
de-flakes the test (currently it fails when `untilFullyBuffered()`
triggers a non-fatal error).
PiperOrigin-RevId: 704219317
This is inspired from TestExoPlayerBuilder.
Adding this class has a few advantages:
- It makes testing easier for apps by configuring Transformer for unit
tests (for example, by setting the clock).
- It removes the Transformer setters that apps should not use for unit
testing (for example, the video MIME type should not be set because
it would cause Transformer to transcode.
- It allows us to add additional setters in the future, for example to
build a Transformer that always fails.
PiperOrigin-RevId: 704181927
Add FrameExtraction.setMediaItem() method
Prefer non-vendor software codecs by default because
vendor codecs sometimes fail when we attempt reuse.
PiperOrigin-RevId: 703486235
The test complements the existing E2E test for HLS in `HlsPlaybackTest` by verifying similar functionality for DASH in `DashPlaybackTest`.
PiperOrigin-RevId: 703454388
After removing `Transformer.Builder.setFlattenForSlowMotion()`, there is no need to keep `flattenForSlowMotion` in Transformer since it's now set in `EditedMediaItem`.
The change also includes making `audioProcessors` and `videoEffects` attributes final.
PiperOrigin-RevId: 703076023
The JSON file contains a list of playlists, each with a name and a list of media items. The EffectActivity loads the JSON file and creates a list of PlaylistHolder objects, which contain the playlist name and the list of media items.
PiperOrigin-RevId: 703069411
`equals`, `hashCode`, and `getPeriodByUid` are correctly implemented on
`Timeline`. Overriding these in a way that maintains correctness is
fiddly, so this CL prevents that for the 'simple' case of subclasses of
`ForwardingTimeline`. Implementations of `Timeline` that need to
override these methods for performance should extend `Timeline` or
`AbstractConcatenatedTimeline` instead of `ForwardingTimeline`.
PiperOrigin-RevId: 703035721
* Select an encoder that supports HDR editing.
* Set KEY_PROFILE to an HDR10 option
* Use DecodeOneFrameUtil test util to return the MediaCodec format,
which includes HDR_STATIC_INFO
PiperOrigin-RevId: 702752639
The method previously discarded the cue that was active at `timeUs`,
meaning it had started before but had not ended by `timeUs`.
Issue: androidx/media#1939
#cherrypick
PiperOrigin-RevId: 702707611
With this CL, PlaybackVideoGraphWrapper doesn't call the
VideoFrameRenderControl directly anymore (which is one of the goals of
DefaultVideoSink).
PiperOrigin-RevId: 702673821
This code previously passed null or 'default' for every parameter.
Now it tries to mock non-final types, and recursively constructor final
types if possible, eventually giving up and passing null instead.
The previous null-passing behaviour led to a quite confusing failure in
`ForwardingPlayer.addListener` when writing 25c927e9f3 due to an NPE
when trying to compare parameter equality in `Mockito.verify` [1].
With this change, the failure is much clearer [2].
There's a relatively simple case this code still doesn't handle: A final
type like `PlaybackParameters` where the constructor parameters **have**
to be non-default primitives (greater than zero in that case).
-------
[1]
```
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at androidx.media3.test.utils.TestUtil.assertForwardingClassForwardsAllMethodsExcept(TestUtil.java:687)
at androidx.media3.common.ForwardingPlayerTest.forwardingPlayer_forwardsAllPlayerMethods(ForwardingPlayerTest.java:110)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:588)
at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$2(SandboxTestRunner.java:290)
at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:101)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: java.lang.NullPointerException: Cannot invoke "Object.hashCode()" because "this.listener" is null
at androidx.media3.common.ForwardingPlayer$ForwardingListener.hashCode(ForwardingPlayer.java:1140)
at java.base/java.lang.Object.toString(Object.java:256)
at java.base/java.lang.String.valueOf(String.java:4220)
at org.mockito.internal.verification.argumentmatching.ArgumentMatchingTool.toStringEquals(ArgumentMatchingTool.java:54)
at org.mockito.internal.verification.argumentmatching.ArgumentMatchingTool.getSuspiciouslyNotMatchingArgsIndexes(ArgumentMatchingTool.java:36)
at org.mockito.internal.verification.checkers.MissingInvocationChecker.checkMissingInvocation(MissingInvocationChecker.java:45)
at org.mockito.internal.verification.Times.verify(Times.java:37)
at org.mockito.internal.verification.MockAwareVerificationMode.verify(MockAwareVerificationMode.java:30)
at org.mockito.internal.handler.MockHandlerImpl.handle(MockHandlerImpl.java:75)
at org.mockito.internal.handler.NullResultGuardian.handle(NullResultGuardian.java:29)
at org.mockito.internal.handler.InvocationNotifierHandler.handle(InvocationNotifierHandler.java:34)
at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.doIntercept(MockMethodInterceptor.java:82)
at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.doIntercept(MockMethodInterceptor.java:56)
at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor$DispatcherDefaultingToRealMethod.interceptAbstract(MockMethodInterceptor.java:161)
at androidx.media3.common.Player$MockitoMock$1276619531.addListener(Unknown Source)
... 22 more
```
----
[2]
```
Argument(s) are different! Wanted:
player.addListener(
Mock for Listener, hashCode: 107929032
);
-> at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Actual invocations have different arguments:
player.addListener(
androidx.media3.common.ForwardingPlayer$ForwardingListener@af47cec0
);
-> at androidx.media3.common.ForwardingPlayer.addListener(ForwardingPlayer.java:81)
```
PiperOrigin-RevId: 702378861
This only affects the default SDK level that Robolectric tests run at.
Also upgrade the Robolectric version to 4.14.1 to pick up
4f32042afe
which is needed for async `ShadowMediaCodec` support (the default in
ExoPlayer from API 31+).
Some tests fail on Robolectric at API 31. This change configures them to
continue running on API 30, so the failures can be investigated and
fixed in follow-up changes.
PiperOrigin-RevId: 702357124
Earlier this year, we explored frame extraction built on top of Transformer
or ImageReader.
We decided against these approaches because random-access of frames
is a key requirement. And ImageReader behaviour is unreliable.
PiperOrigin-RevId: 702303490
This means we can complete preparation (and trigger track selection)
before opening a `DataSource`, which then means we only end up loading
the data for a selected subtitle track (instead of all tracks as
currently happens).
By making preparation trivial in this case (with no reasonable cause
of error), we can also remove the `suppressPrepareError` option added in
b3290eff10.
This change also fixes the implementation of
`ProgressiveMediaPeriod.maybeStartDeferredRetry` to only short-circuit
return `false` if the chosen track is not audio or video **and** there
is at least one audio or video track in this period.
Issue: androidx/media#1721
PiperOrigin-RevId: 702275968
This method was taking positionUs and elapsedRealtimeUs parameters and
throwing a VideoSinkException because it was calling render() to make
room for a new input frame. Instead of doing that, this CL makes sure
render() is called before handleInputFrame() in the renderer (even
though it may not make a significant difference).
PiperOrigin-RevId: 702273587
Add missing ones for `ForwardingExtractorInput` and `ForwardingSeekMap`.
`ForwardingTimeline` is a bit more fiddly, so it's left for a follow-up
change.
PiperOrigin-RevId: 701988492
Previously cancelling one FrameExtractor.getFrame
ListenableFuture caused the following requests to fail.
Implement ability to cancel Futures, and correctly issue
next player seek commands after all past requests complete.
Removes uses of SettableFuture, and replaces them with
CallbackToFutureAdapter.
Adds a dependency on androidx.concurrent:concurrent-futures
PiperOrigin-RevId: 701941403
Frame Extractor was getting stuck with SeekParameters.CLOSEST_SYNC.
onPositionDiscontinuity callback was sometimes being called with a
non-adjusted new position.
Fix this by monitoring player state ready.
For the player to become ready, we have to override renderer isReady.
PiperOrigin-RevId: 701924752
When a session sets a custom layout, we currently convert it to the
media button preferences in MediaControllerImplBase and convert it back
to a custom layout for consumers of MediaController.getCustomLayout.
To avoid unnecessary conversions and potential changes, we can
directly use the provided custom layout to get the same logic as
before. This also means we avoid notifying a change to the custom layout
if only the implicit slots changed that weren't relevant before
introducing them (=we can remove some tests for this behavior).
PiperOrigin-RevId: 701903475
The isLastBuffer flag passed to MediaCodecRenderer.processOutputBuffer()
is unreliable. It is true for the last frames (plural) of a video
stream, which makes it possible for the video renderer to end before all
the frames have been rendered to the output surface.
PiperOrigin-RevId: 700941685
This aligns the behavior with `MediaExtractor`, which sets this key in its [`MediaFormat`](https://developer.android.com/reference/android/media/MediaExtractor#getTrackFormat(int)) output.
Additionally, unnecessary `selectTrack` calls have been removed from the existing `getTrackFormat_...` tests, as they are not required to fetch the track format.
PiperOrigin-RevId: 700741326
Currently, `size` is cached in `SampleMetadata` when samples are committed in `SampleQueue`, which worked because we didn't support reading files with `CryptoInfo`. This change prepares for future `CryptoInfo` support, as the size changes when reading samples with encrypted data. Caching the size at commit time could lead to incorrect buffer `size` calculations.
Existing tests verify the correctness of the `getSampleSize()` API.
PiperOrigin-RevId: 700714178
The Android SKD version 30 is stable, allowing us to remove the `@SuppressLint("Override")` annotations from `InputReaderAdapterV30` and `OutputConsumerAdapterV30`.
PiperOrigin-RevId: 700681115
Introduced a `mediaSourceFactory` attribute to CompositionPlayer. This allows for the use of a custom MediaSource.Factory when creating media sources, providing more flexibility and control over media source creation. Previously, the default `MediaSource.Factory` was used in all cases.
PiperOrigin-RevId: 700391911
The previous code assumed that the `VBRI` Table of Contents (ToC)
covers all the MP3 data in the file. In a file with an invalid VBRI ToC
where this isn't the case, this results in playback silently stopping
mid-playback (and either advancing to the next item, or continuing to
count up the playback clock forever). This change considers the `bytes`
field to determine the end of the MP3 data, in addition to deriving it
from the ToC. If they disagree we log a warning and take the max value.
This is because we handle accidentally reading non-MP3 data at the end
(or hitting EoF) better than stopping reading valid MP3 data partway
through.
Issue: androidx/media#1904
#cherrypick
PiperOrigin-RevId: 700319250
The current code assumes that the first Table of Contents segment
includes the `VBRI` frame, but I don't think this is correct and it
should only include real/audible MP3 ata - so this change updates the
logic to assume the first ToC segment starts at the frame **after** the
`VBRI` frame.
Issue: androidx/media#1904
#cherrypick
PiperOrigin-RevId: 700269811
This was hand-crafted with a 4-entry ToC by modifying
`bear-vbr-xing-header.mp3` in a hex editor.
The output difference from 117 samples to 116 samples is due to the
calculation in `VbriSeeker` assuming that the ToC includes the VBRI
frame itself, which I don't think is correct (fix is in a follow-up
change).
Issue: androidx/media#1904
#cherrypick
PiperOrigin-RevId: 700254516
Support extracting frames from HDR input by tone mapping
to SDR (BT.709).
ExperimentalFrameExtractor must be public because HDR tests
live in a different package.
PiperOrigin-RevId: 699994112
Adds a configuration option to Frame Extractor to choose MediaCodecSelector.
Add a MediaCodecSelector that lists software decoders first
PiperOrigin-RevId: 699962365
Renderers join when they can start processing but not produce output.
In CompositionPlayer before this change, the VideoSink will be flushed when
position is reset regardless. This is useful for seeking, as seeking triggers position reset. But with pre-warming, a video renderer can be joining - it is
enabled (which also triggers position reset) before the previous image renderer
is disabled. At this moment, as the image renderer is still producing frames,
we should not flush the video sink just now.
PiperOrigin-RevId: 699943882
We are currently waiting until stream 1 is completely rendered on screen
before registering stream 2 but that is not necessary anymore because
VideoFrameProcessor supports registering stream 2 before stream 1 is
fully processed.
PiperOrigin-RevId: 699929943
Before this CL, the following scenario could happen:
- A new input stream is registered to the DefaultVideoFrameProcessor.
- Before the pipeline is reconfigured, a seek is issued andd the
DefaultVideoFrameProcessor is flushed.
- As a result, the new input stream registration is never taken into
account.
As a result:
- If an input stream is registered after the seek (before queueing any
frame), registerInputStream will block indefinitely because
inputStreamRegisteredCondition will be closed.
- If a frame is queued after the seek, it will be linked to the input
stream information of the previous frames.
This CL makes sure that any pending input stream is registered after a
flush.
PiperOrigin-RevId: 698736866
This call does 2 things:
1. It's used to estimate the frame rate early but this is incorrect as
the frame rate can be changed by effects. I have tested playback on
my device and I don't see any difference.
2. For ExoPlayer.setVideoEffects() only: it allows dropping all the
frames until the next key frame in case the input frame is "very
late". This doesn't seem really necessary though because because we
do the same thing after applying effects.
This change is also a step towards moving all the calls to
VideoFrameRelease/RenderControl to DefaultVideoSink.
PiperOrigin-RevId: 698732161
Changes includes making sure the same `defaultMediaSourceFactory` is used when creating a new media source in `setPrimaryPlayerSequence` and `setSecondaryPlayerSequence`.
This is pre-work for introducing a new attribute `mediaSourceFactory` that can be optionally used instead of the default one. This will allow developers to pass a customized media source factory to CompositionPlayer.
PiperOrigin-RevId: 698721139
This CL also aligns supported color space in `media3 common` and `media3 muxer`.
Earlier `muxer` would take even those values which are considered invalid
in `media3` in general.
Earlier muxer would throw if a given `color standard` is not recognized
but with the new change, it will rather put default `unspecified` value.
#cherrypick
PiperOrigin-RevId: 698683312
Adds a Frame extractor test that verifies decoder
respects rotation metadata from the mp4 container.
Do not rely on the MediaCodec decoder rotate the input.
Rotate via a video effect instead.
PiperOrigin-RevId: 698381282
This non-functional refactor inlines and simplifies the logic of
`BaseAudioProcessor` used by `SpeedChangingAudioProcessor`, and makes
the latter implement `AudioProcessor` directly.
`SpeedChangingAudioProcessor` acts as a wrapper over
`SonicAudioProcessor` and does not actually modify any samples,
so it had very little use for the affordances provided by
`BaseAudioProcessor`.
PiperOrigin-RevId: 698342962
3P app reported it's slow to see the first image frame on the screen, when
`playWhenReady` is false. This is because the player would wake up less
frequently when `playWhenReady` is false. This CL adds a runnable to wake up
the player any time a new frame is made available.
PiperOrigin-RevId: 698066887
SpeedChangingAudioProcessor is redundantly bypassing SonicAudioProcessor
when the speed is set to 1f. SpeedChangingAudioProcessor should not make
assumptions about the underlying audio processing and moreover should
not be bypassing any AudioProcessor based on parameter values. Default
parameter values are a valid state for an active AudioProcessor.
Sonic already handles the "default case" state by just copying the input
buffer onto the output buffer.
This CL also simplifies SonicAudioProcessor, which would mark itself as
inactive when configured with a valid set of default parameters. The API
contract for `isActive()` makes no mention about parameter state, which
makes changes in `isActive()` after applying new valid parameters quite
unintuitive.
PiperOrigin-RevId: 698000500
The following was happening:
- VideoFrameRenderControl.render() was calling
VideoFrameReleaseAction.getFrameReleaseAction().
- VideoFrameReleaseAction.getFrameReleaseAction() was calling
FrameTimingEvaluator.shouldIgnoreFrame(), which is implemented in
MediaCodecVideoRenderer.
- MediaCodecVideoRenderer.shouldIgnoreFrame(), when returning true,
was also flushing the VideoSink, which was flushing the
VideoFrameRenderControl.
- VideoFrameRenderControl.render() was removing the frame from the
presentationTimestampsUs queue, but the frame had already been removed
by the flush operation, causing an exception to be thrown.
This fix removes the last step.
PiperOrigin-RevId: 697915692
To do this, refactor stream start position handling so that
VideoFrameRenderControl is only passed a start position when it should
be applied, and therefore doesn't need to take a timestamp associated
with each start position anymore
PiperOrigin-RevId: 697544416
From [ the last change in `DefaultPreloadManagerTest`](2b54b1ebbe), the preloadManager began to use a separate `preloadThread` in `release_returnZeroCount_sourcesAndRendererCapabilitiesListReleased`, which unveils a bug in `PreloadMediaSource`. When `PreloadMediaSource.releasePreloadMediaSource` is called, `preloadHandler` will post a `Runnable` on the preload looper to release the internal resources. Before this `Runnable` is executed, it is possible that the [`stopPreloading`](https://github.com/androidx/media/blob/main/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/preload/PreloadMediaSource.java#L442) method is executed just as the result of preloading has completed. This is expected to remove the posted `Runnable`s for further preloading, however, the posted `Runnable` for releasing will also be removed from the message queue.
Ideally we should use `postDelayed(runnable, token, delayMillis)` to post the runnables so that the token will be useful to identify which messages to remove in `removeCallbacksAndMessages(token)`, but that `postDelayed` method is only available from API 28. So in this change we are using a separate handler for releasing, and then the call of `preloadHandler.removeCallbacksAndMessages` won't impact the runnable for releasing.
#cherrypick
PiperOrigin-RevId: 696894483
This method returns a `PersistableBundle` containing metrics data for the current media container. The bundle includes attributes and values for the media container, as described in `MediaExtractor.MetricsConstants`.
PiperOrigin-RevId: 696893276
The new callback allows an app to read data from the content
timeline to populate the `AdPlaybackState`. To avoid a deadlock
between the `AdMediaSource` waiting for the `AdPlaybackState` and
the app waiting for the content `Timeline`, a boolean flag
`useLazyContentSourcePreparation` is introduced to tell the
`AdsMediaSource` to prepare the content source immediately
to make the `Timeline` available.
A unit test verifies that in none of the cases (lazy preparation or
immediate preparation) a `Timeline` without ad data is leaked to the
caller. This ensures that in the case of a preroll, the player won't
initially and accidentally read content media data before starting to
load the preroll ad. While the content source is prepared early, no
content media period must be created before the preroll starts.
PiperOrigin-RevId: 696885392
ISO/IEC 23001-8 has been withdrawn. The corresponding definition for channel configuration is available in ISO/IEC 23091-3. Update the comment to reflect this change.
The content in Issue: androidx/media#1863 has every sample incorrectly marked as a
sync sample in the MP4 metadata, which results in flushing the
re-ordering queue on every sample, so nothing gets re-ordered, so the
subtitles are garbled.
There are currently two "uses" for this call on every keyframe:
1. It offers a safety valve if we don't read a `maxNumReorderSamples`
value from the video. Without this, the queue will just keep growing
and end up swallowing all subtitle data (similar to the bug fixed by
39c734963f).
2. When we do read (or infer) a `maxNumReorderSamples` it means we can
emit samples from the queue slightly earlier - but this is pretty
marginal, given i think the max possible value for
`maxNumReorderSamples` is 16, so the most benefit we would get is 16
frames (~0.53s at 30fps) - in most cases we will have more than 0.5s
of buffer ahead of the playback position, so the subtitles will still
get shown at the right time with no problem.
(1) is resolved in this change by setting the queue size to zero (no
reordering) if we don't have a value for `maxNumReorderSamples`.
(2) has minimal impact, so we just accept it.
We may be able to inspect the NAL unit to determine IDR vs non-IDR
instead - we will consider this as a follow-up change, but given the
minimal impact of (2) we may not pursue this.
#cherrypick
PiperOrigin-RevId: 696583702
- Rename a few methods/variable to improve readability.
- Refactor how video size changes are tracked. This will simplify the
upcoming logic to refactor the timestamp logic in
VideoFrameRenderControl because we will use the same logic for
outputVideoSize and for outputStreamStartPositionUs.
PiperOrigin-RevId: 696026515
Earlier watchdog timer was started only after all the tracks are
added. For the cases where export is stuck before adding tracks,
the export would hang forever and will not timeout automatically.
With the changes, watchdog timer is started as soon as export is
started/resumed. Now if the pipeline is stuck before writing any samples,
it will timeout and report error to the caller.
Existing test case: c35a9d62ba/libraries/transformer/src/test/java/androidx/media3/transformer/MediaItemExportTest.java (L996)
PiperOrigin-RevId: 695781654
The behaviour was changed in 1.4.0 with 0f42dd4752,
so that the buffer timestamp is compared to `outputStartTimeUs` when
deciding whether to discard a "decode only" buffer before decoding
(instead of the deprecated/removed `isDecodeOnly` property). This breaks
when the buffer timestamp is `TIME_END_OF_SOURCE` (which is
`Long.MIN_VALUE`), because `TIME_END_OF_SOURCE < outputStartTimeUs` is
always true, so the end-of-stream buffer is never passed to the decoder
and on to `TextRenderer` where it is used to
[set `inputStreamEnded = true`](40f187e4b4/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/text/TextRenderer.java (L434-L436))
and so playback hangs.
#cherrypick
Issue: androidx/media#1863
PiperOrigin-RevId: 695767247
Implemented `getCachedDuration()` to provide an estimate of cached data in memory and `hasCacheReachedEndOfStream()` to indicate if the cache has reached the end of the stream.
Note: The Javadoc for the newly added methods closely follows that of the platform `MediaExtractor`. While the current implementation always uses a cache and therefore never returns `-1` from `getCachedDuration`, this leaves room for future changes should caching behavior or conditions evolve.
PiperOrigin-RevId: 695694460
A skeleton implementation that doesn't actually return decoded frames.
In the current state, we use ExoPlayer to seek to a position, and
ExoPlayer.setVideoEffects to record the presentation time selected.
Seeking and processing frames are synchronized via ListenableFuture
callbacks.
PiperOrigin-RevId: 695691183
In some cases, callers will need to pass in both BitmapLoader and Codec.DecoderFactory without specifying a custom MediaSource.Factory. Omitting the annotation will result in NULL_FOR_NONNULL_TYPE compilation errors in Kotlin.
PiperOrigin-RevId: 695481606
This is because the method is called for each media item, the current name
implies that the method is only called once for all videos in a sequence.
PiperOrigin-RevId: 695332916
This method will replace the current estimation mechanism in place on
`getSpeedAdjustedTimeAsync()`, which relies on heuristics from previous
output rates and depends on the state of the `AudioProcessor`. The new
static method should be considerably more accurate.
PiperOrigin-RevId: 694607264
This ensures it works correctly when there are multiple SEI messages per
sample and the max size is set from e.g. H.264's
`max_num_reorder_frames`.
PiperOrigin-RevId: 694526152
The `RendererCapabilities` and `TrackSelector` objects are accessed on the preload thread during the preloading, when releasing them, they need to be released on the same thread. Otherwise, it is possible that they have already released on the application thread, while the PreloadMediaSource still tries to access them on the preload thread before the source is released.
#cherrypick
PiperOrigin-RevId: 694173131
Note: `androidx.media3.common.DrmInitData` is returned instead of the platform `android.media.DrmInitData` because the platform class has a package-private constructor, making it impossible to implement the abstract class outside the platform.
PiperOrigin-RevId: 694096542
Added the functionality for `Choose local file` button to be able to go and select a local file from the device. The file was then displayed by using ExoPlayer inside PlayerView.
PiperOrigin-RevId: 693756565
Added a basic UI to the effect demo app, including a PlayerView, buttons to choose preset input and choose local file, and a button to apply effects. The buttons are currently not implemented, and the app will show a snackbar message when they are clicked.
PiperOrigin-RevId: 693751272
Changed the dependency of `lib-common` in `lib-ui` from an `implementation` dependency to an `api` dependency. This change ensures that classes and interfaces from `lib-common` used in the public API of `lib-ui` are correctly exposed to consumers of `lib-ui`.
For example, `PlayerView implements AdViewProvider` where the latter is from `androidx.media3.common.AdViewProvider`.
PiperOrigin-RevId: 693734349
Enable transformer to transmux into alternative sample MIME types.
For example, some Dolby Vision profiles have a backwards-compatible
AVC or HEVC layer. MV-HEVC is backwards compatible with HEVC.
This change enables Transformer to transmux into the backwards compatible
format to improve compatibility with legacy APIs such as
MediaMetadataRetriever.
PiperOrigin-RevId: 693667597
All instances of PlaybackVideoGraphWrapper use the same
VIDEO_FRAME_PROCESSOR_FACTORY_SUPPLIER which uses the same
DefaultGlObjectsProvider.
Each call to DefaultGlObjectsProvider.release() releases
all previously created EGLContexts.
Lazily create a new DefaultGlObjectsProvider for each
DefaultVideoFrameProcessor (not one per factory).
PiperOrigin-RevId: 693658458
The tests became more flaky after 76e4abe428, likely because playback
was able to start slightly earlier, exaggerating any existing race
conditions. Fix the flakiness by letting all tests with subtitle
parsing wait until all data is fully loaded before starting to play.
PiperOrigin-RevId: 693380656
When a new media session sets media button preferences, we need to
"translate" them back to a custom layout to ensure the user preferences
are represented as closely as possible when the controller uses the
old button placement rules.
PiperOrigin-RevId: 693306153
The method currently modifies the input Bundle, but it's easier to
reason about it if the method is side-effect free and the places
that need to modify a Bundle do this after calling the method.
PiperOrigin-RevId: 693288031
Implemented `setLogSessionId(LogSessionId)` and `getLogSessionId()` methods.
Note: The `LogSessionId` is currently **not** forwarded to `MediaParser`, but this will be addressed once `MediaParser` can be used to configure `MediaExtractorCompat`.
PiperOrigin-RevId: 692945255
* Provide a helper Composable for remembering the state instance and launching the listening coroutine that observes the changes in the Player
* Add an example to demo-compose of using Shuffle- and Repeat- ButtonStates inside a Shuffle- and RepeatButton Composable.
* Reformat the MainActivity usage of `Shuffle` and `Repeat` buttons to form extra Player Controls and combine Prev/Play-Pause/Next with Shuffle/Repeat (Minimal controls + Extra controls = `PlayerControls`)
PiperOrigin-RevId: 692939825
The test has been moved to an instrumentation test as it relies on APIs that vary by SDK version. Robolectric’s emulation lacks sufficient realism in some cases, which impacts test accuracy. By using an instrumentation test, we ensure that the tests run in a real Android environment, providing reliable results for SDK-dependent APIs.
PiperOrigin-RevId: 692933259
Also move the `lint.xml` config which disables the `NewApi` check from
`lib-session` to the existing top-level file, and limit it to cover all
Robolectric tests by path matching.
Follow-up to 76db936d68
PiperOrigin-RevId: 692913646
This change keeps getSurfaceForCodec and hasSurfaceForCodec in sync.
Before this change when ExoPlayer is configured with setVideoEffects
and no display surface, codecs that need Set Output Surface Workaround
would not be initialized because hasSurfaceForCodec always returns false
PiperOrigin-RevId: 692900899
Restructured sample metadata management in `MediaExtractorCompat` to maintain a queue of `SampleMetadata` objects, each containing `timeUs`, `flags`, `size`, and `trackIndex`, rather than storing only track indices.
Introduced a pooling mechanism for `SampleMetadata` to reduce object allocation and improve memory efficiency. The new `SampleMetaDataQueue` centralizes metadata for easier access and management, eliminating the need to allocate a buffer or peek into the `SampleQueue` to retrieve sample metadata.
This change does not change existing behavior, it optimizes the internal structure, and existing tests already verify the relevant APIs.
PiperOrigin-RevId: 692285581
This CL adds utility methods to obtain sample-aligned timestamps from a
`SpeedProvider` to solve in a unified way the issues arising from
conversions between sample positions and microseconds.
The new utility methods will also help with the implementation of a
static method like `getDurationAfterProcessorApplied()` that will remove
the need for thread synchronization between the video and audio pipeline
for speed changing effects.
PiperOrigin-RevId: 692233318
If audio processors report a drifting position, we currently update
the media position parameters to correct this drift. However, this
means we pass in the wrong value to
audioProcessorChain.getMediaDuration, which reuqires the time since
the last flush.
To fix this problem, we can instead save the drift seperately and
apply it where needed.
PiperOrigin-RevId: 692202219
Also makes muxer shift the first video timestamp to zero, if it's not.
The trim position should respect the media timeline.
For example in a video that is 10s long (without edit list), if an edit list
adds 1_000ms to each video sample, and trimming 100ms, here's the expected:
- The video duration is 10.9s (`10s + 1s edit - 0.1s trim`)
- The first video frame time would be at 0.9s (`1s edit - 0.1s trim`)
PiperOrigin-RevId: 692187399
* Provide a helper Composable for remembering the state instance and launching the listening coroutine that observes the changes in the Player
* Add an example to demo-compose of using Previous- and Next- ButtonStates inside a Previous- and NextButton Composable.
* Reformat the MainActivity usage of `Previous`, `PlayPause`, `Next` buttons to form Minimal Player Controls
PiperOrigin-RevId: 691943147
Provide a helper Composable for remembering the state instance and launching the listening coroutine that observes the changes in the Player
Add an example to demo-compose of using PlayPauseButtonState inside a PlayPauseButton Composable.
The smart State object has been deemed a preferred solution over collecting Flows due to queuing/timing/buffering limitations. Instead, it uses the new `Player.listen` suspending extension function to catch the relevant events.
PiperOrigin-RevId: 691879975
This affects both `AnalyticsListener` and `MediaSourceEventListener`
This was introduced by d051b4b993
Also fix a missing 'load started' event for HLS media playlists (this
was also introduced by d051b4b993).
PiperOrigin-RevId: 691580183
Replaced the custom `LibraryLoader` instance with `OpusLibrary.isAvailable()` to verify the library loading. This simplifies the code by leveraging the existing library loading mechanism.
#cherrypick
PiperOrigin-RevId: 691457871
Using frames instead of bytes helps simplify the processing logic for
the component and will help with the move towards sample-based
`SpeedProvider`s. By using frames, we also abstract away the complexity
related to sample encoding.
This is a non-functional refactor.
PiperOrigin-RevId: 691444106
The overload that takes a `Format` is preferred, because it can detect
SEI NAL units in Dolby Vision tracks too.
Submitting this in a separate change so we can avoid cherry-picking it
into `1.5.0-rc01`, otherwise it would naturally be part of
27371db225.
Issue: androidx/media#1820
PiperOrigin-RevId: 691408725
Previously, `getTrackFormat()` in `MediaExtractorCompat` returned a `MediaFormat` without setting `MediaFormat.KEY_DURATION`. With this change:
- `MediaFormat.KEY_DURATION` is set based on the track's duration, if available.
- If the track duration is unset, the duration from the seek map is used as a fallback.
- When neither duration is set, `MediaFormat.KEY_DURATION` remains unset.
This ensures that `MediaFormat.KEY_DURATION` is populated when possible, enhancing duration information availability.
PiperOrigin-RevId: 691395114
This method will likely be removed in the next release, and is currently
only needed from within the `source` package.
#cherrypick
PiperOrigin-RevId: 691351449
This change ensures that the test uses `assumeTrue` to avoid failures when the `libiamf` library is not pre-built.
#cherrypick
PiperOrigin-RevId: 691333564
The logic in assumeFormatsSupported assumes that portrait videos are
always rotated before encoding but that's not the case when portrait
encoding is enabled.
PiperOrigin-RevId: 691042881
In some cases, the streamOffsetUs was passed to
VideoFrameReleaseControl.getFrameReleaseAction() but it should be the
streamStartPositionUs.
PiperOrigin-RevId: 691040172
When transitioning to the next media position parameter checkpoint
we estimate the position because the audio processor chain no longer
provides access to the actual playout duration.
The estimate using the declared speed and the last checkpoint may
have drifted over time, so we currently estimate relative to the
next checkpoint, which is closer and presumably provides a better
estimate. However, this assumes that these checkpoint are perfectly
aligned without any position jumps.
The current approach has two issues:
- The next checkpoint may include a position jump by design, e.g.
if it was set for a new item in the playlist and the duration of
the current item wasn't perfectly accurate.
- The sudden switch between two estimation methods may cause a jump
in the output position, which is visible when we add new media
position checkpoints to the queue, not when we actually reach the
playback position of the checkpoint.
We can fix both issues by taking a slightly different approach:
- Continuously monitor the estimate using the current checkpoint. If
it starts drifting, we can adjust it directly. This way the estimate
is always aligned with the actual position.
- The change above means we can safely switch to using the estimate
based on the previous checkpoint. This way we don't have to make
assumptions about the next checkpoint and any position jumps will
only happen when we actually reach this checkpoint (which is more
what a user expects to see, e.g. at a playlist item transition).
Issue: androidx/media#1698
PiperOrigin-RevId: 690979859
Removed deprecated `Transformer.PROGRESS_STATE_NO_TRANSFORMATION`, `Transformer.setListener`, and `Transformer.startTransformation` from Transformer.
PiperOrigin-RevId: 690971992
Adjusted logic to accurately calculate sizes and durations for the last valid cue point when cue timestamps are greater than the total duration.
Fixes the issue where the reported duration of the MKV file was greater than the total duration specified by the duration element. Verified this using `mkvinfo` and `mediainfo` tools.
PiperOrigin-RevId: 690961276
A player that is being released may report an error with
null `player.getPlayerError()`. Do not try to read errors
of players that are released.
PiperOrigin-RevId: 690953083
This method allows `Sonic` to statically and accurately report the
expected number of output frames for any given parameter configuration.
This change is required prework for `SpeedChangingAudioProcessor` to
implement a similar static method and allow precise, non-blocking
timestamp adjustments for the experimental speed changing effect.
PiperOrigin-RevId: 690669627
Also, fix incorrectly stretched golden file that was not detected with previous, less sensitive, average pixel error comparison.
PiperOrigin-RevId: 690643520
GLSL 3.00 mediump doesn't require enough precision near zero
to correctly represent PQ colors where the [0, 1] GL range
represents [0, 10_000] nits.
This caused `noEffects_hlg10InputAndHdr10Output_matchesGoldenFile`
to fail on some devices.
PiperOrigin-RevId: 690627069
The old code that uses MediaCodec directly has a race condition
that causes the decoder to incorrectly crop the decoded picture.
PiperOrigin-RevId: 690620868
This is prework for `Sonic` to provide a precise calculation of output
sample counts, and thus allow `SpeedChangingAudioProcessor` to replace
`getSpeedAdjustedTimeAsync()` with an accurate synchronous calculation.
This is a non functional change.
PiperOrigin-RevId: 690608520
This method is already called below in the
`else if (sps.isCompleted())` block which applies when
`hasOutputFormat == true`, but this is only ever entered if we are
parsing SPS and PPS NAL units **after** we've emitted a format, which
is only the case if
`DefaultTsPayloadReaderFactory.FLAG_DETECT_ACCESS_UNITS` is set (which
it isn't by default).
The equivalent call in `H265Reader` is already inside the
`if (!hasOutputFormat)` block, so doesn't need a similar fix.
#cherrypick
PiperOrigin-RevId: 689809529
This ensures that media button preferences with slots for BACK,
FORWARD and OVERFLOW are converted to the legacy custom layout
according to the implicit placement rules. This has to happen
when populating the MediaSessionCompat and when generating the
notification for older APIs. Sending these preferences to older
Media3 controllers can filter them down to the custom layout the
session would have used previously, but there is no need to adjust
the reservation extras because the older Media3 custom layout has
no concept of these extras.
PiperOrigin-RevId: 689761637
This is equivalent to the current logic, but also allows to easily pick
up other buttons that use the BACK, CENTRAL or FORWARD slots for the
compact view by default.
Also fix the test to actually assert the output order.
PiperOrigin-RevId: 689747844
This ensures that the slots are set according to the implicit placement
rules for the legacy custom layouts. This has to be done when receiving
custom actions from a MediaControllerCompat and for Media3 sessions
setting the custom layout field.
PiperOrigin-RevId: 689737951
These methods are marked `default` on the `AnalyticsListener` interface
with an empty implementation, so there's no need to override them just
to re-define the empty implementation.
PiperOrigin-RevId: 689416584
* Use asset without audio for independent video time progress
* Use longer item duration to avoid ExoPlayer STATE_READY workaround
(see https://github.com/google/ExoPlayer/issues/1874)
PiperOrigin-RevId: 689409427
Add `DecoderAudioRenderer.getDurationToProgressUs()` so that `ExoPlayer`, if set with `experimentalSetDynamicSchedulingEnabled()`, will dynamically schedule its main work loop to when the `DecoderAudioRenderer` can make progress.
PiperOrigin-RevId: 689377247
Mp4Muxer caches the samples and then writes them in batches.
The new API allows disabling the batching and writing sample
immediately.
PiperOrigin-RevId: 689352771
- Create `LibiamfAudioRenderer` with `DefaultRenderersFactory` in `ExoPlayerModuleProguard`.
- Remove redundant library availability check from `IamfModuleProguard`.
- Move `proguard-rules.txt` to the root folder.
- Removed unused `cryptoType` parameter from `setLibraries()` method in `IamfLibrary`.
- Added log when `LibiamfAudioRenderer` is loaded in `DefaultRenderersFactory`.
- Annotated missing classes with `@UnstableApi`.
- Check for library availability and throw exception in `IamfDecoder` constructor.
#cherrypick
PiperOrigin-RevId: 689330016
This change:
1. Updates `DataSourceContractTest` to allow multiple "not found"
resources, and to include additional info (e.g. headers) on them.
2. Updates the contract test to assert that `DataSource.getUri()`
returns the expected (non-null) value for "not found" resources
between the failed `open()` call and a subsequent `close()` call.
The `DataSource` is 'open' at this point (since it needs to be
'closed' later), so `getUri()` must return non-null.
* This change also fixes some implementations to comply with this
contract. It also renames some imprecisely named `opened`
booleans that **don't** track whether the `DataSource` is open
or not.
3. Updates the contract test assertions to enforce that
`DataSource.getResponseHeaders()` returns any headers associated
with the 'not found' resource.
4. Configures `HttpDataSourceTestEnv` to provide both 404 and "server
not found" resources, with the former having expected headers
associated with it.
PiperOrigin-RevId: 689316121
The new `media3-ui-compose` module does not have any Material library dependencies, but will rely on androidx.compose + foundation/runtime/ui and other non-theming/opinionated libraries. Surface handling is one such usecase.
PiperOrigin-RevId: 689004504
Also add a test for this to avoid missing any others in future. Also
flesh out the existing test for the deprecated builder, to assert the
return type is correctly updated.
PiperOrigin-RevId: 688948768
The duration is now correctly calculated as the maximum of all track durations, instead of being overwritten by the last track's value. This aligns with how other Extractor implementations handle durations for multiple tracks.
PiperOrigin-RevId: 688896743
`RandomParameterizedSpeedChangingAudioProcessorTest` follows the
structure of `RandomParameterizedSonicAudioProcessorTest` and will help
improve coverage and confidence in the output length of
`SpeedChangingAudioProcessor`.
This CL is prework for removing the synchronization between the video
pipeline and the audio pipeline for speed changing effects.
PiperOrigin-RevId: 688578597
Currently most of the public APIs use `fullscreen` (apart from the deprecated `PlayerControlView.OnFullScreenModeChangedListener` which will have to remain as is). This code changes mostly private variable naming.
PiperOrigin-RevId: 688559509
Frame rate change is currently notified to the release control when the
video frame processor input frame rate changes, but it should be when
the video frame processor output frame rate changes.
PiperOrigin-RevId: 688512300
If not copied, the extras Bundle can be accidentally changed by the
app if it modifies the instance passed into MediaSession. On the flip
side, the Bundle should be modifiable once created so that the session
can amend the extras if needed without crashing.
PiperOrigin-RevId: 688485963
Added start and end time details to the error message for `REASON_START_EXCEEDS_END`, helping to debug cases where the start time exceeds the end time.
PiperOrigin-RevId: 688117440
The method allows extractors to set track duration when available. The `default` implementation does nothing, allowing implementers of `TrackOutput` to override it if they need to handle track duration.
Implemented it in `FakeExtractor` to print track duration in dump files.
PiperOrigin-RevId: 688110288
Treats the media duration as unknown (`C.TIME_UNSET`) when all bytes are `-1` to prevent exceptions during playback.
Issue: androidx/media#1819
#cherrypick
PiperOrigin-RevId: 688103949
Many of the Android TV platforms do not report accurate `SystemClock.elapsedRealtime()`
In addition this drift is not consistant accross multiple boxes, so the time offset
between any pair of boxes will vary over time.
This variance will lead to a drift in the Live Offset calculation.
Fix is simple, inValidate the NTP server query after a period of time (10 minutes)
and re-issue the call
If we handle the "codecs" in HlsPlaylistParser.java rather than in HlsMediaPeriod.java, since the "codecs" property includes both audio and video codec names here, we can't update it directly. Only video part should be updated by Dolby codec string.
method public androidx.media3.common.TrackSelectionParameters.Builder setPreferredAudioMimeTypes(java.lang.String...);
method public androidx.media3.common.TrackSelectionParameters.Builder setPreferredAudioRoleFlags(@androidx.media3.common.C.RoleFlags int);
method public androidx.media3.common.TrackSelectionParameters.Builder setPreferredTextLanguage(@Nullable String);
method public androidx.media3.common.TrackSelectionParameters.Builder setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettings(android.content.Context);
method public androidx.media3.common.TrackSelectionParameters.Builder setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettings();
method @Deprecated public androidx.media3.common.TrackSelectionParameters.Builder setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettings(android.content.Context);
method public androidx.media3.common.TrackSelectionParameters.Builder setPreferredTextLanguages(java.lang.String...);
method public androidx.media3.common.TrackSelectionParameters.Builder setPreferredTextRoleFlags(@androidx.media3.common.C.RoleFlags int);
method public androidx.media3.common.TrackSelectionParameters.Builder setPreferredVideoMimeType(@Nullable String);
method public final androidx.media3.common.Player getPlayer();
method @Nullable public final android.app.PendingIntent getSessionActivity();
method public android.os.Bundle getSessionExtras();
method public final androidx.media3.session.SessionToken getToken();
method public final void release();
method public final com.google.common.util.concurrent.ListenableFuture<androidx.media3.session.SessionResult> sendCustomCommand(androidx.media3.session.MediaSession.ControllerInfo, androidx.media3.session.SessionCommand, android.os.Bundle);
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.