1691 Commits

Author SHA1 Message Date
ibaker
fd24449e7e Add param comments to untilPosition calls in ExoPlayerScrubbingTest
Follow-up to 9073c2b28d

PiperOrigin-RevId: 756295111
2025-05-08 07:04:17 -07:00
dancho
5a7d545fd6 Fix flaky clearkeyPlayback_..._dropsInputBuffers test
Increase the input media duration to be sufficiently longer than
OFFSET_FROM_RESET_POSITION_TO_ALLOW_INPUT_BUFFER_DROPPING_US

PiperOrigin-RevId: 756283253
2025-05-08 06:20:48 -07:00
ibaker
9073c2b28d Deflake ExoPlayerScrubbingTest
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
2025-05-08 05:59:20 -07:00
tonihei
38ac6ba711 Fix onAudioPositionAdvancing callback
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
2025-05-07 11:09:34 -07:00
ibaker
1cef4ed9df Log non-square pixel aspect ratio in EventLogger
Also include `w=` and `h=` in video and surface size logging.

PiperOrigin-RevId: 755821356
2025-05-07 06:09:57 -07:00
tonihei
fbee549f74 Improve detection of advancing timestamp in AudioTimestampPoller
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
2025-05-06 08:04:19 -07:00
tonihei
0dc5ed19e2 Improve timestamp smoothing in AudioTrackPositionTracker
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
2025-05-06 06:36:10 -07:00
dancho
e9b2ded810 Rollback of a78d0c3994
PiperOrigin-RevId: 755302920
2025-05-06 03:54:45 -07:00
tonihei
ffb8d3ca66 Refactor AudioTimestampPoller to a smaller API surface
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
2025-05-02 09:44:43 -07:00
claincly
def4794d96 Split initializing CompositionPlayerInternal and setting composition
PiperOrigin-RevId: 753976959
2025-05-02 06:18:20 -07:00
dancho
ef39fc70d9 Disable codec reuse when only crop rect changes
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
2025-05-02 06:16:11 -07:00
michaelkatz
52d9cfdcb7 Add plumbing of ScrubbingModeParameters from ExoPlayer to Renderers
PiperOrigin-RevId: 753959866
2025-05-02 05:09:04 -07:00
ivanbuper
e06e9b4cc9 Detect underruns with AudioTrack#getUnderrunCount() in DefaultAudioSink
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
2025-05-01 05:20:02 -07:00
Copybara-Service
acdc71bb63 Merge pull request #2386 from DolbyLaboratories:dlb/cmcd/nullable-configuration
PiperOrigin-RevId: 753210729
2025-04-30 10:04:01 -07:00
ibaker
8dc8003afc Deprecate Util.compareLong in favour of Long.compare
The `Long` method was only added in API 19, so wasn't previously
usable when ExoPlayer's minSdk was 16.

PiperOrigin-RevId: 753185351
2025-04-30 08:50:22 -07:00
Copybara-Service
df41f6b041 Merge pull request #2387 from DolbyLaboratories:dlb/cmcd/pr-key-not-allowed
PiperOrigin-RevId: 753181724
2025-04-30 08:40:00 -07:00
Mattias Buelens
ec01011374 Fix CMCD sending pr=0.00 even when key is not allowed 2025-04-30 14:28:20 +02:00
Mattias Buelens
a019de887c Allow CmcdConfiguration.Factory to return null to disable CMCD 2025-04-30 14:19:20 +02:00
ibaker
49064c4b82 Stabilize the ExoPlayer.Builder.setSeekForward/BackIncrementMs APIs
The equivalent getters are already stable on `Player`.

Issue: androidx/media#2286
PiperOrigin-RevId: 752686185
2025-04-29 05:02:03 -07:00
kimvde
293c55e062 Adapt InputVideoSink.onInputStreamChanged for CompositionPlayer
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
2025-04-29 03:23:42 -07:00
kimvde
48832cbbc4 Remove unused setter in PlaybackVideoGraphWrapper.Builder
PiperOrigin-RevId: 752639277
2025-04-29 01:57:12 -07:00
ibaker
ecfd9d1e92 Clear TextRenderer.streamError when disabling or changing stream
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
2025-04-29 01:05:21 -07:00
kimvde
0f08c97221 Handle rendering in VideoGraph time
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
2025-04-28 04:59:13 -07:00
kimvde
8968d9fa45 Remove VideoSinkProvider
PiperOrigin-RevId: 752227606
2025-04-28 02:48:06 -07:00
ibaker
8bf658cd79 Remove some hard-coding of file and content URI schemes
PiperOrigin-RevId: 751417429
2025-04-25 08:05:22 -07:00
dancho
910b6ab884 Do not flush c2.mtk decoders when outputting to a videoSink
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
2025-04-24 08:39:46 -07:00
michaelkatz
2e20d35c3d Set static interval as default for dynamic scheduling with audio
Applications providing custom AudioSink implementations should have the dynamic scheduling for audio playback fallback to the static interval if they are not 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
2025-04-24 07:26:04 -07:00
tonihei
6ce9fdee8c Add test and formatting fixes 2025-04-24 12:52:22 +01:00
Colin Kho
25feac7664 Add ForwardingTrackSelection to allow access to the underlying instance 2025-04-24 12:26:31 +01:00
ibaker
4189a7c8bd Add ExoPlayer.isScrubbingModeEnabled
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
2025-04-24 02:35:14 -07:00
kimvde
d9a92e2586 Remove references to defaultVideoSink from inputVideoSink
This makes the chain structure (InputVideoSinks, then VideoGraph, then
DefaultVideoSink) clearer.

PiperOrigin-RevId: 750910247
2025-04-24 02:22:25 -07:00
tonihei
50345b03aa Fix memory leak caused by removing wrong period from List
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
2025-04-23 06:21:48 -07:00
tonihei
a7c897003c Fix bug where a MaskingMediaSource never throws prepare error
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
2025-04-23 04:13:30 -07:00
kimvde
4d68243158 Only join video graph output in playlist mode.
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
2025-04-22 10:15:18 -07:00
kimvde
fe10ca2c9a Start and stop video rendering from CompositionPlayer
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
2025-04-22 08:43:21 -07:00
tonihei
1c855a8abf Remove unneeded SDK checks
PiperOrigin-RevId: 750172684
2025-04-22 06:48:41 -07:00
Copybara-Service
661effcddd Merge pull request #2323 from DolbyLaboratories:dlb/ac4-profile/dev
PiperOrigin-RevId: 750171380
2025-04-22 06:43:36 -07:00
Copybara-Service
4d9f47920a Merge pull request #2285 from MGaetan89:deprecate_util_sdkint
PiperOrigin-RevId: 750142132
2025-04-22 04:53:39 -07:00
tianyifeng
7f6ddef502 Enable DownloadHelper to create DownloadRequest with timeRange
PiperOrigin-RevId: 748722156
2025-04-17 10:14:04 -07:00
tonihei
c4c3e5e0c8 Move getMaximumEncodedRateBytesPerSecond to a shared public util
This makes it more easily reusable.

Issue: androidx/media#2339
PiperOrigin-RevId: 748713531
2025-04-17 09:52:18 -07:00
Gaëtan Muller
9b2e1cfca0 Deprecate Util.SDK_INT in favor of Build.VERSION.SDK_INT
`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.
2025-04-17 15:55:23 +01:00
bachinger
fd8547fc3a Ensure ad playback state and timeline are in sync
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
2025-04-16 07:38:23 -07:00
tonihei
70e7121a51 Make some audio processors public
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
2025-04-15 07:03:04 -07:00
tonihei
9cc7dd0dbe Ensure DefaultAudioSink doesn't store non-application Context
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
2025-04-15 05:40:56 -07:00
tonihei
21514ba8e8 Add missing check for TRACK_TYPE_NONE before accessing selections
The track selections will be null if the track type is NONE even
if the renderer is enabled.

PiperOrigin-RevId: 747818128
2025-04-15 04:38:14 -07:00
bachinger
117db48907 Assert preload looper is not the main looper
Issue: androidx/media#2315
PiperOrigin-RevId: 747809915
2025-04-15 04:08:01 -07:00
shahddaghash
a2265f1dae Replace deprecated ShadowMediaCodecConfig factory methods
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
2025-04-14 07:46:13 -07:00
tonihei
68538029c9 Fix getChildPeriod logic if the child is a TimeOffsetMediaPeriod
The current instanceof check accidentally unpacks the child,
returning the inner period instead of the one passed to the source.

PiperOrigin-RevId: 746556825
2025-04-11 12:45:01 -07:00
tianyifeng
344f249511 Fix issue where ProgressiveMediaPeriod fails assertPrepared
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
2025-04-11 09:34:57 -07:00
ybai001
2500d91848 Add KEY_PROFILE, KEY_LEVEL support for AC-4 2025-04-10 09:39:23 +08:00