Increase the input media duration to be sufficiently longer than
OFFSET_FROM_RESET_POSITION_TO_ALLOW_INPUT_BUFFER_DROPPING_US
PiperOrigin-RevId: 756283253
Instead of waiting for pending commands to complete as a proxy for
'the requested seek(s) completed', we wait until the corresponding
playback position.
PiperOrigin-RevId: 756276867
hasPendingData() should signal whether the final audio sink still
holds unconsumed frames so that the renderer can accurately detect a
buffering state.
Before this change, a media item transition could incorrectly trigger
a buffering state in the internal sequence players and cause
CompositionPlayer to interrupt playback. See Issue: androidx/media#2228.
PiperOrigin-RevId: 756252645
Calls to release() can lead to player errors -> move release()
in the test body instead of tearDown()
The resettable count down latch was error-prone:
* Calling reset() swaps out the CountDownLatch and anything waiting on
the previous latch times out
* Calling unblock() after reset(INT_MAX) hangs the test
Replace the resettable count down latch with a normal CountDownLatch.
PiperOrigin-RevId: 756249512
Prewarming relies on two BufferingVideoSinks controlling the same
underlying video sink. If BufferingVideoSink queues a flush operation
caused by a prewarming renderer, when we transition between renderers
the BufferingVideoSink will flush ongoing playback and will cause
unwanted stuttering.
Flushing the video sink causes a chain reaction of making the video
renderer not ready, triggering a player BUFFERING state, and having
CompositionPlayer disable all renderers and pausing the final audio sink
as a result.
This is a partial fix for Issue: androidx/media#2228. The pending part of the fix is
to implement AudioGraphInputAudioSink#hasPendingData() to report an
accurate value.
PiperOrigin-RevId: 756238558
Added documentation and release notes for using `imageDurationMs` to determine image asset loading in `DefaultAssetLoaderFactory`.
PiperOrigin-RevId: 756228166
Export can be ended twice if an exception is thrown before Transformer
was fully released.
Also add a lock to make sure the released variable doesn't become true
right after its value is checked.
PiperOrigin-RevId: 756196139
The logic has always been broken for multiple different reasons:
- It applied usToMs twice, essentially making all calculations
for the actual start time meaningless.
- It compared against the fist observed timestamp after calling
AudioTrack.play(), which may already include some advanced
position.
- The callback was falsely triggered after speed changes (when
AudioTrack playback params are used).
- It used the potentially smoothed position from different sources
instead of using the latest reliable source
- It did not wait until the getTimestamp source is reliable
before triggering this callback (instead always relying on the
more error-prone getPlaybackHeadPosition).
As a result it has always reported the system time when we first
observed a timestamp that was different from a previous one.
We can make the callback more useful by fixing these points:
- Wait until the getTimestamp source is reliably advancing or
definitely can't be used (by which point we should also have a
more reliable playbackHeadPosition value).
- Calculate the start time using the latest position before
applying any smoothing.
- Save the "from" position in start() before AudioTrack.play()
is called. This also avoid triggering the callback after speed
changes.
- Don't apply usToMs twice.
PiperOrigin-RevId: 755927465
Binder stubs are GC roots and may be accidentally kept long after
the surrounding objects are gone (this is partially outside our
control, e.g. another app keeps a MediaController).
To prevent memory leaks, these binder stubs need to stop referencing
other instances whose data may be kept as well.
- All stubs except one already use a WeakReference for the main
owning class, which is cleared as soon as the class is released.
- This change replace the AtomicReference in ExtraSession with
a WeakReference to make it safer.
- If the stub holds lists of data, these should be all cleared when
released. This wasn't done in all cases yet.
- Some local fields for MediaSessionManager can be removed entirely
by just accessing the static variable on demand.
PiperOrigin-RevId: 755879020
Before, we were using a boolean to wait for the input stream to be
fully registered to the CompositionVideoFrameProcessor before queueing
an input texture. This should instead be done by checking the return
value of queueInputTexture().
Also fix a few small stylistic issues.
PiperOrigin-RevId: 755770940
We currently accept any difference in reported frame position
as an "advancing timestamp". However, we don't check if the
resulting position is actually advancing or was only slightly
corrected, but is not yet advancing reliably.
This results in AV sync issues if the timestamp is used too early
while it's not actually advancing yet, and the potential correction
is only read 10 seconds later when we query the timestamp again.
The fix is to check whether the timestamp is actually advancing
as expected (the resulting position from the previous and the
current snapshot don't differ by more than 1ms). To avoid
permanent polling in 10ms intervals for devices that never report
a reliable timestamp, we introduce another timeout after which we
give up.
PiperOrigin-RevId: 755373666
The position tracker has two different position sources,
getPlaybackHeadPosition and getTimestamp. Whenever we switch
between these sources, we smooth out the position differences
over a period of one second.
This has two problems:
1. The smoothing duration is 1 sec regardless of the actual
position difference. So for small differences, assuming
the new timestamp is more correct, we needlessly keep
the tracker with a position offset for longer. For large
differences, the smoothing may result in an extremely
large speedup (up to 5x in theory, for a max allowed diff
of 5 seconds smoothed over a 1 second real time period).
The solution to this issue is to adjust the smoothing
period to the actual difference by using a maximum
speedup/slowdown set to 10% at the moment. Smaller
differences are corrected faster and larger differences
are corrected in a slightly smoother way without speeding
up drastically. We still need an upper bound though (set
to 1 second difference) where plainly jumping to the correct
position is likely a better user experience than having a lenghty
smoothing.
2. The smoothing is only applied when switching between position
sources. That means any position drift or jump coming from the
same source is always taken as it is without any smoothing. This
is problematic for the getTimstamp-based position in particular
as it is only sampled every 10 seconds.
The solution to this problem is to entirely remove the condition
that smoothing only happens when switching between position
sources. Instead we can always check whether the position drift
compared to the last known position is more than the maximum allowed
speedup/slowdown of 10% and if so, start applying smoothing.
This helps to smooth out the position progress at the start of
playback and after resumption when we switch between the position
sources and both sources are not super reliable yet and it also
helps for unexpected jumps in the position of getTimestamp later
on during playback.
PiperOrigin-RevId: 755348271
This moves the position estimation and plausibility checks inside
the class.
Mostly a no-op change, except that the plausible checks now use
the estimated timestamp from getTimestamp and the playback head
position to make them actually comparable. Before, we were comparing
the last snapshot states which may not necessarily be close together.
Given the large error threshold of 5 seconds, this shouldn't make
a practical difference though, just avoids noise and confusion.
PiperOrigin-RevId: 754035464
Work around a bug where MediaCodec fails to adapt between
formats that have the same decoded picture resolution but
different crop.
Add a playlist of two MP4 files that reproduce the issue.
This CL implements the workaround for H.265 and Mp4
PiperOrigin-RevId: 753976872
This already the case for the platform Queue's MediaDescription, but
we currently use the localConfiguration.uri for the platform
MediaMetadata field even though we intentionally strip locaConfiguration
fields before sharing with other apps.
PiperOrigin-RevId: 753952733
This test previews a composition containing only a single audio asset
sequence. The audio asset is a 1s, stereo, locally available WAV file.
Catching an underrun in this test is a likely indication of something
being seriously wrong with the device's state or a performance
regression on the audio pipeline.
This test is a verification of the fix in 2e20d35c3d. Without this fix
the newly added test fails because MediaCodecAudioRenderer attempts to
use dynamic scheduling with AudioGraphInputAudioSync
(which is unsupported) after EoS is signalled.
PiperOrigin-RevId: 753552825
Prior to this change, DefaultAudioSink (via AudioTrackPositionTracker)
would use best-effort logic to infer underruns in the underlying
AudioTrack. This logic would miss underrun events (e.g. newly added test
fails if run without any changes to AudioTrackPositionTracker).
This change should help more accurately detect regressions in the audio
pipeline.
PiperOrigin-RevId: 753550187
Updated the createAssetLoader method to directly use the `mediaItem.localConfiguration.imageDurationMs` to determine if an ImageAssetLoader should be created for an image. This is specifically used for determining whether a motion photo should be treated as an image or as a video.
PiperOrigin-RevId: 753235616
This change renames the existing `sample_with_ssa_subtitles.mkv` test
file (with `S_TEXT/ASS` codec ID) to `sample_with_ass_subtitles.mkv`
(so the file name matches the codec ID), and forks a new test file
called `sample_with_ssa_subtitles.mkv` with the `S_TEXT/SSA` codec ID.
`MatroskaExtractorTest` then asserts that both these files produce
identical dump files.
Issue: androidx/media#2384
PiperOrigin-RevId: 753164883
PresentationState creation and listener registration are not an atomic operation. This happens because the LaunchedEffect which starts the listen-to-Player-Events coroutine can be pre-empted with other side effects, including the ones that change something in the Player.
rememberPresentationState function creates a PresentationState object and initialises it with the correct fresh values pulled out of the Player. The subscription to Player events with a registration of a Listener (via PresentationState.observe()) is not immediate. It *returns* immediately, but is instead scheduled to happen later, although within the same Handler message. Other LaunchedEffects could have been scheduled earlier and could take place between the button state creation and listener subscription.
This is not a problem if no changes to the player happen, but if we miss the relevant player events, we might end up with a UI that is out of sync with reality. The way to fix this is to pull the latest values out of the Player on demand upon starting to listen to Player events.
PiperOrigin-RevId: 753129489
`PlayerSurface` is just an `AndroidView` composable wrapping `SurfaceView` and `TextureView`. It uses the `Player` passed to it to set the `SurfaceHolder`s from those `SurfaceView`/`TextureView` objects. However, it does not technically need the Player to be created - the result will just be an empty Surface.
Add an optimisation to PlayerSurfaceInternal that avoids preemptive clearing of the Surface on the old Player. This helps avoid a costly creation of a surface placeholder right before (potentially) assigning the new Surface to that player.
PiperOrigin-RevId: 752840145