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
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
The output of CompositionPlayer should be considered as a single clip
(not a playlist) so we should only propagate the first stream change
event in that case.
PiperOrigin-RevId: 752661523
Previously a stream error from one playlist item was incorrectly
preserved when switching to the next one, resulting in playback hanging.
Issue: androidx/media#2328
PiperOrigin-RevId: 752624979
Before this CL, the buffer adjustment (which allows to convert from
ExoPlayer time to VideoGraph time) was added to the frame timestamps
before feeding them to the VideoGraph, and then subtracted at the
VideoGraph output. The playback position and stream start position used
for rendering were in ExoPlayer time.
This doesn't work for multi-sequence though because the adjustment might
be different depending on the player (after a seek for example).
To solve this problem, this CL handles rendering in VideoGraph time
instead of ExoPlayer time. More concretely, the VideoGraph output
timestamps are unchanged, and the playback position and stream start
position are converted to VideoGraph time.
PiperOrigin-RevId: 752260744
Flushing a c2.mtk decoder that outputs to a SurfaceTexture often
fails and leaves the SurfaceTexture's BufferQueue in an unrecoverable
state. Release the codec instead.
PiperOrigin-RevId: 751006875
Applications providing custom AudioSink implementations should have the dynamic scheduling for audio playback fallback to the static interval if they are not supporting AudioSink#getAudioTrackBufferSizeUs().
This CL specifically removes the bypass for the static default for if rendering to end of stream. For scenarios with an intermediary layer between MediaCodecAudioRenderer and DefaultAudioSink, there can be potential underruns even though at the MediaCodecAudioRenderer it has nothing else to write.
PiperOrigin-RevId: 750986145
This helps integration with `PlayerControlView` in a follow-up change,
where we need to reliably know if scrubbing mode is still enabled (in
case someone else disables it after we enable it).
PiperOrigin-RevId: 750913644
MergingMediaSource started keeping references to all MediaPeriods
it ever created since 191bc094a5 as the cleanup step attempted
to remove the outer merged period from the list instead of the
inner period of child source.
Issue: androidx/media#2338
PiperOrigin-RevId: 750566825
We suppressed the direct error throwing ability in <unknown commit>
to avoid throwing errors later in the playlist too early. This
logic got moved to MaskingMediaSource in <unknown commit>, but its
original purpose was no longer needed when the player stopped
calling this method directly in <unknown commit>.
This left a pending bug that any other usage of MaskingMediaSource
(e.g. within AdsMediaSource) no longer forwards source prepare
errors.
Issue: androidx/media#2337
PiperOrigin-RevId: 750537823
DefaultVideoSink.join() was called when join() was called on the
InputVideoSink. This makes sense in playlist mode but we shouldn't
join if the VideoGraph output is considered as a single clip.
This change is no-op. Indeed, for CompositionPlayer, the
allowedJoiningTimeMs is set to 0, so that join doesn't have any effect.
PiperOrigin-RevId: 750238085
Before, we were starting and stopping video rendering when the
renderers were started/stopped. This doesn't work for multi-video
sequences though because we shouldn't stop and start rendering at every
MediaItem transition in any of the input sequences.
PiperOrigin-RevId: 750206410
`Util.SDK_INT` was introduced to be able to simulate any SDK version during tests.
This is possible by using Robolectric's `@Config(sdk)` annotation.
All usages of `Util.SDK_INT` have been replaced by `Build.VERSION.SDK_INT`.
This is a similar change to what was done in #2107.
Before this change a timeline update of a live content
source has produced a timeline refresh before passing
the timeline to the ads loader. When in such a case
the ads loader updates the ad playback state, a
second timeline refresh is trigger that then
includes the updated ad data also. This can result
in a timeline being pulished with stale ad information.
This change prevents this by introducing a boolean
return value that requires the ads loader to signal
whether the ad playback state has been passed back
to the source. This ensures that an update of
timeline and ad playback state produces a single
timeline update and is published in sync.
PiperOrigin-RevId: 748288650
ChannelMappingAudioProcessor, TrimmingAudioProcessor and
ToFloatPcmAudioProcessor are currently package-private even
though they might be useful in custom audio processing chains
or custom version of audio sinks.
Issue: androidx/media#2339
PiperOrigin-RevId: 747857815
The Context is currently passed right down from ExoPlayer.Builder
without ever converting it to the application context. This may
cause memory leaks if a Player is kept across activities/service
lifecycles.
PiperOrigin-RevId: 747835487
This is part of the efforts for adding encoder support for ShadowMediaCodecConfig to use it for ExoPlayer and Transcoding tests.
* Replaced `ShadowMediaCodecConfig#forAllSupportedMimeTypes()` calls with `ShadowMediaCodecConfig#withAllDefaultSupportedCodecs()`
* Replaced `ShadowMediaCodecConfig#withNoDefaultSupportedMimeTypes() calls with `ShadowMediaCodexConfig#withNoDefaultSupportedCodecs()`
PiperOrigin-RevId: 747413859
The current instanceof check accidentally unpacks the child,
returning the inner period instead of the one passed to the source.
PiperOrigin-RevId: 746556825
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
#cherrypick
PiperOrigin-RevId: 746490375
We used to pass `audioTrackConfig.encoding` as the `bufferSize` parameter to `AudioSink.InitializationException`, for which this CL is supposed to correct. But `encoding` is a useful information for logging anyway, thus an `encoding` parameter is also added to `AudioSink.InitializationException` constructor, so now we pass both `encoding` and `bufferSize` parameters.
PiperOrigin-RevId: 745534997