1266 Commits

Author SHA1 Message Date
tonihei
5e3dcea1bf Ramp up volume after AudioTrack flush to avoid pop sound
AudioTrack doesn't automatically ramp up the volume after a flush
(only when resuming with play after a pause), which causes audible
pop sounds in most cases. The issue can be avoided by manually
applying a short 20ms volume ramp, the same duration used by the
platform for the automatic volume ramping where available.

Together with the already submitted 6147050b90, this fixes the
unwanted pop sounds for most cases in the desired way. It only
leaves two cases that are not handled perfectly:
 - If the media file itself contains a volume ramp at the beginning,
   we wouldn't need this additional ramping. Given the extremely
   short duration, this seems ignorable and we can treat it as a
   future feature request to mark the beginning of media in a special
   way that can then disable the volume ramping.
 - For seamless period transitions where we keep using the same
   AudioTrack, we may still get a pop sound at the transition. To
   solve this, we'd need a dedicated audio processor to either ramp
   the end of media down and the beginning of the next item up, or
   apply a very short cross-fade. Either way, we need new signalling
   to identify cases where the media originates from the same source
   and this effect should not be applied (e.g. when re-concatenating
   clipped audio snippets from the same file).

PiperOrigin-RevId: 676860234
2024-09-20 08:55:29 -07:00
ibaker
0b86f89498 Guard DrmSession.requiresSecureDecoder calls with state checks
This method is documented that it may only be called in `STATE_OPENED`
or `STATE_OPENED_WITH_KEYS`. It's possible for it to be called in other
states (like `STATE_ERROR`) without this guard.

Previously this didn't cause issues, but since 9d62845c45
we assume that the `sessionId` is non-null in this method, which results
in an `IllegalStateException` when the documented state restriction is
ignored.

PiperOrigin-RevId: 675969256
2024-09-18 06:41:32 -07:00
ibaker
3e8ecbf564 Remove @DoNotInline annotations
This is no longer needed now our `compileSdk` implies a new-enough AGP
which does this out-lining automatically via R8. See also
https://issuetracker.google.com/345472586#comment7

There's no plan to remove the `ApiXXX` classes, but no new ones need
to be added.

PiperOrigin-RevId: 675940634
2024-09-18 04:47:39 -07:00
michaelkatz
f0fb386224 Add workaround for Galaxy Tab S7 FE device PerformancePoint issue
The Galaxy Tab S7 FE has a device issue that causes 60fps secure H264 streams to be marked as unsupported. This CL adds a workaround for this issue by checking the CDD required support for secure H264 in addition to the current check on standard H264. If the provided performance points do not cover the CDD requirement of support 720p H264 at 60fps, then it falls back to using legacy methods for checking frame rate and resolution support.

Issue: androidx/media#1619
PiperOrigin-RevId: 675920968
2024-09-18 03:29:10 -07:00
Googler
e1c4ecf2d3 Add suitable output checker tests relevant for API 35+ in ExoPlayerTest
PiperOrigin-RevId: 675547156
2024-09-17 06:45:15 -07:00
rohks
9bc89ae989 Ensure track indices are only added when samples are committed
Previously, track IDs were added to `trackIndicesPerSampleInQueuedOrder`
even when the sample was not committed. This caused issues where attempts
to read samples from the `SampleQueue` returned `C.RESULT_READ_NOTHING`,
which led to an exception being thrown due to the assumption that samples
were available to read.

This fix updates the logic to track sample commits by comparing the write index before and after calling `SampleQueue.sampleMetadata`. Track indices are only added if the sample was committed, ensuring accurate sample handling and avoiding exceptions.

PiperOrigin-RevId: 675526115
2024-09-17 05:27:51 -07:00
Rohit Singh
c8aa122e8a Change from internal review 2024-09-16 13:34:21 +01:00
Rohit Singh
9975175700 Forward default methods 2024-09-16 13:07:36 +01:00
Rohit Singh
3c6f1f1e77 Add copyright text and move test to correct package 2024-09-16 12:36:03 +01:00
Rohit Singh
8ca12338f6 Format with google-java-format 2024-09-16 12:31:48 +01:00
Colin Kho
62aef96b7d Format code using google java format 2024-09-16 12:31:48 +01:00
Colin Kho
72e39c91c4 Denote ForwardingRenderer as subject to change 2024-09-16 12:31:48 +01:00
Colin Kho
72f26d79f6 Added a forwarding class for Renderer to support composing custom behavior on Metadata & Text Renderers 2024-09-16 12:31:48 +01:00
tianyifeng
72ae454f67 Use buffered duration from start position to control preload progress
`PreloadMediaSource` allows to have a `startPositionUs` passed when `preload` is called, then in `PreloadControl.onContinueLoadingRequested`, it can be more intuitive to see the buffered duration rather than the absolute buffered position as the preload progress. Similar in `DefaultPreloadManager`, we haven't allowed the apps to set a custom start position for individual sources though, once we add this support, using the "duration from the start position" than the absolute position will be less error-prone, otherwise, it can run into a case that the position that the apps set is smaller than the start position.

PiperOrigin-RevId: 674251362
2024-09-13 05:05:39 -07:00
claincly
bc8d82355f Block secondary audio processing until primary format is configured
PiperOrigin-RevId: 673961235
2024-09-12 12:42:09 -07:00
rohks
f133e8d1f2 Fix preroll sample handling for non-keyframe media start positions
When processing edit lists in MP4 files, the media start position may be a non-keyframe. To ensure proper playback, the decoder must preroll to the preceding keyframe, as these preroll samples are essential for decoding but are not rendered.

Issue: google/ExoPlayer#1659

#cherrypick

PiperOrigin-RevId: 673457615
2024-09-11 11:02:39 -07:00
kimvde
8271a5f920 Rename CompositingVideoSinkProvider and PreviewAudioPipeline
The components are mirror components for video and audio so they should
have a matching name

PiperOrigin-RevId: 673357081
2024-09-11 05:49:35 -07:00
jbibik
8bfa7e2de1 Make StreamVolumeManager take streamType in constructor
Avoids the dispatch of listener notifications of stream type/device volume change during construction of ExoPlayer. That was problematic because we end up blocking on `constructorFinished.blockUninterruptible()`

Issue: androidx/media#1692
PiperOrigin-RevId: 672965552
2024-09-10 08:05:21 -07:00
sheenachhabra
327b1c8ad8 Move getCodecProfileAndLevel to CodecSpecificDataUtil
`Muxer` module needs to use this method, hence moved to common.

This CL also makes `getHevcProfileAndLevel` public because this is used
in `MediaCodecUtil`.

PiperOrigin-RevId: 671739166
2024-09-06 06:52:29 -07:00
ibaker
0933f561b7 Move MCR CryptoException handling to top-level render() method
Handling for `MediaCodec.CryptoException` was originally added only
around calls to `MediaCodec.queueSecureInputBuffer` and
`queueInputBuffer` (because these are the only methods that can throw
this exception). When asynchronous interaction with `MediaCodec` was
added in <unknown commit>, exceptions from `MediaCodec` started being stored
and bubbled out of **later** interactions with `MediaCodecAdapter`. This
means that `MediaCodecRenderer` can now see `CryptoException` thrown
from a different method, like
`MediaCodecAdapter.dequeueInputBufferIndex()`, and this ends up missing
the `catch (CryptoException)` code in `MediaCodecRenderer`. This results
in an "unexpected runtime error" stack trace like [A].

This change fixes the stack trace to:
1. Make it a "renderer exception" instead of "unexpected runtime error"
2. Include the correct DRM error code -> `@PlaybackException.ErrorCode`
   mapping.

You can see the corrected stack trace below [B].

-----

[A] (synthesized from manually throwing a `CryptoException` from
`AsynchronousMediaCodecBufferEnqueuer#doQueueSecureInputBuffer`)

```
playerFailed [eventTime=11.56, mediaPos=10.35, window=0, period=0, errorCode=ERROR_CODE_UNSPECIFIED
  androidx.media3.exoplayer.ExoPlaybackException: Unexpected runtime error
      at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:729)
      at android.os.Handler.dispatchMessage(Handler.java:103)
      at android.os.Looper.loopOnce(Looper.java:232)
      at android.os.Looper.loop(Looper.java:317)
      at android.os.HandlerThread.run(HandlerThread.java:85)
  Caused by: android.media.MediaCodec$CryptoException: Test error message
      at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecBufferEnqueuer.doQueueSecureInputBuffer(AsynchronousMediaCodecBufferEnqueuer.java:232)
      at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecBufferEnqueuer.doHandleMessage(AsynchronousMediaCodecBufferEnqueuer.java:196)
      at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecBufferEnqueuer.access$000(AsynchronousMediaCodecBufferEnqueuer.java:47)
      at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecBufferEnqueuer$1.handleMessage(AsynchronousMediaCodecBufferEnqueuer.java:93)
      at android.os.Handler.dispatchMessage(Handler.java:107)
      at android.os.Looper.loopOnce(Looper.java:232) 
      at android.os.Looper.loop(Looper.java:317) 
      at android.os.HandlerThread.run(HandlerThread.java:85) 
```

[B]

```
Playback error
  androidx.media3.exoplayer.ExoPlaybackException: MediaCodecAudioRenderer error, index=1, format=Format(0, null, null, audio/mp4a-latm, mp4a.40.2, 134359, en, [-1, -1, -1.0, null], [2, 44100]), format_supported=YES
      at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:649)
      at android.os.Handler.dispatchMessage(Handler.java:103)
      at android.os.Looper.loopOnce(Looper.java:232)
      at android.os.Looper.loop(Looper.java:317)
      at android.os.HandlerThread.run(HandlerThread.java:85)
  Caused by: android.media.MediaCodec$CryptoException: Test error message
      at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecBufferEnqueuer.doQueueSecureInputBuffer(AsynchronousMediaCodecBufferEnqueuer.java:232)
      at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecBufferEnqueuer.doHandleMessage(AsynchronousMediaCodecBufferEnqueuer.java:196)
      at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecBufferEnqueuer.access$000(AsynchronousMediaCodecBufferEnqueuer.java:47)
      at androidx.media3.exoplayer.mediacodec.AsynchronousMediaCodecBufferEnqueuer$1.handleMessage(AsynchronousMediaCodecBufferEnqueuer.java:93)
      at android.os.Handler.dispatchMessage(Handler.java:107)
      at android.os.Looper.loopOnce(Looper.java:232) 
      at android.os.Looper.loop(Looper.java:317) 
      at android.os.HandlerThread.run(HandlerThread.java:85) 
```

PiperOrigin-RevId: 670951229
2024-09-04 06:44:21 -07:00
rohks
6e1bab03bd Add Mp4PlaybackTest for sample with edit list (edts box)
PiperOrigin-RevId: 670572646
2024-09-03 08:43:33 -07:00
dancho
1c61fbadf7 Downscale bitmaps during decoding in Transformer
Limit input image size in Transformer to be less than 4096x4096.
For very large images, this can reduce memory usage substantially,
and stays away from `GL_MAX_TEXTURE_SIZE` - often 4096

PiperOrigin-RevId: 670555939
2024-09-03 07:53:13 -07:00
Copybara-Service
854566dbfe Merge pull request #1371 from v-novaltd:dsparano-exo207
PiperOrigin-RevId: 669352191
2024-08-30 09:35:32 -07:00
microkatz
f1654732a6 Added release note for change 2024-08-30 13:47:43 +00:00
tonihei
41a56daab7 Code formatting 2024-08-29 13:48:41 +01:00
Colin Kho
a509033a5c Correct grammar and format javadoc on DrmUtil.executePost 2024-08-29 13:19:27 +01:00
Colin Kho
4ee34cc00e Refactor HttpMediaDrmCallback's executePost into a shared utility method within DrmUtil 2024-08-29 13:19:27 +01:00
tonihei
e8664dbc8e Report initial discontinuity for DASH periods that require preroll
DASH periods don't have to start at the beginning of a segment. In
these cases, they should report an initial discontinuity to let the
player know it needs to expect preroll data (e.g. to flush renderers)

This information is only available in the ChunkSampleStream after
loading the initialization data, so we need to check the sample
streams and tell them to only report discontinuities at the very
beginning of playback. All other position resets are triggered by
the player itself and don't need this method.

Issue: androidx/media#1440
PiperOrigin-RevId: 668831563
2024-08-29 01:57:15 -07:00
kimvde
8367e420ad Import correct nullable annotation
PiperOrigin-RevId: 668521379
2024-08-28 10:54:29 -07:00
tianyifeng
c2e81052e8 Fix flakiness in ExoPlayerTest
In the flaky test `ExoPlayerTest.loading_withLargeAllocationCausingOom_playsRemainingMediaAndThenThrows`, it is indeterministic that when the message `MSG_IO_EXCEPTION` from the loader thread will arrive on the playback looper. If it arrives after `MSG_PERIOD_PREPARED`, then the period can continue loading and get the three samples written to the `SampleQueue` before the intentional OOM surfacing to the `ExoPlayerImplInternal`, otherwise, the OOM will be detected by `ExoPlayerImplInternal` very early and the player disallows to load three samples, which will cause the assertion to fail.

As we are expecting the three samples to play until the playback fails, we should assume that the `Loader` encounters the OOM after those samples loaded, thus we need to put this trigger a bit later until the `SampleStreamItem`s are handled by the `FakeSampleStream`. This could be checked by the return value of `FakeMediaPeriod.continueLoading` (super class implementation). However, `FakeMediaPeriod.continueLoading` originally always returns `true`, which is not aligned with the javadoc of `MediaPeriod.continueLoading`:

"return `true` if progress was made, meaning that `getNextLoadPositionUs()` will return a different value than prior to the call, `false` otherwise."

then we should also modify that logic.

PiperOrigin-RevId: 668438316
2024-08-28 07:16:29 -07:00
microkatz
0ac26c4004 Format with google-java-format 2024-08-28 12:41:49 +00:00
Daniele Sparano
7473156853 Fix output pixel aspect ratio and add test for it 2024-08-28 12:41:49 +00:00
Daniele Sparano
f0463bff8a Set pixel aspect ratio from output media format if set 2024-08-28 12:41:49 +00:00
tonihei
d0676245b5 Add AnalyticsListener.onRendererReadyChanged
This callback allows listeners to track when individual renderers
allow or prevent playback from being ready. For example, this is useful
to figure out which renderer blocked the playback the longest.

PiperOrigin-RevId: 667970933
2024-08-27 07:08:42 -07:00
kimvde
a4d0735d4c Fix player hanging when seeking at MediaItem transition
Before this CL, the video sink was stuck if a flush was executed:
- after VideoSink.onInputStreamChanged, which is setting
  pendingInputStreamBufferPresentationTimeUs and
- before the previous stream was fully rendered.

This is because pendingInputStreamBufferPresentationTimeUs was not reset
to TIME_UNSET when flushing the sink, so that the sink was still waiting
for the last frame of the previous stream to be rendered in
handleInputFrame/Bitmap.

PiperOrigin-RevId: 667924517
2024-08-27 04:00:46 -07:00
tonihei
6f0cb539d0 Add util method BaseRenderer.getStreamOffsetUs
This simplifies the common pattern of saving this offset in
onStreamChanged to use it at a later point.

PiperOrigin-RevId: 666226263
2024-08-22 00:53:04 -07:00
tianyifeng
410b26fba1 Detect SampleStream error after PreloadMediaPeriod has prepared
Per the javadoc, the method `MediaPeriod.maybeThrowPrepareError` is only allowed to be called before the period has completed preparation. For later errors in loading the streams, `SampleStream.maybeThrowError` will be called instead.

PiperOrigin-RevId: 665831430
2024-08-21 05:16:42 -07:00
tianyifeng
351593a250 Allow playback regardless buffered duration when loading fails
It is possible for playback to be stuck when there is failure in loading further data, while the player is required to load more due to the buffered duration being under `DefaultLoadControl.bufferForPlayback`. Therefore, we check if there is any loading error in `isLoadingPossible`, so that the player will allow the playback of the existing data rather than waiting forever for the data that can never be loaded.

Issue: androidx/media#1571
#cherrypick
PiperOrigin-RevId: 665801674
2024-08-21 03:37:42 -07:00
Copybara-Service
1bb48b1c47 Merge pull request #1616 from colinkho:chmain
PiperOrigin-RevId: 665779059
2024-08-21 02:32:16 -07:00
Copybara-Service
5304f227a7 Merge pull request #1624 from colinkho:comain
PiperOrigin-RevId: 665430514
2024-08-20 10:47:43 -07:00
Ian Baker
9c25845cd7 Restore a couple of blank lines 2024-08-20 17:47:48 +01:00
Ian Baker
a6f5d3daf5 Format with google-java-format 2024-08-20 17:47:48 +01:00
Colin Kho
0a0444b9a5 Use Suppliers.memoize for lazy instantiation of AudioManager 2024-08-20 17:47:47 +01:00
Colin Kho
6af92b0af3 Differ AudioManager retrieval to whenever AudioFocusManagement is required 2024-08-20 17:47:47 +01:00
Copybara-Service
24f3856ea4 Merge pull request #1580 from colinkho:main
PiperOrigin-RevId: 665330328
2024-08-20 06:17:20 -07:00
Ian Baker
41430aaa0c Fix annotation position and clarify javadoc 2024-08-20 13:42:00 +01:00
ibaker
b04b270c2b Use SubtitleExtractor from MediaParserChunkExtractor
This uses a 'bundled' extractor (`SubtitleExtractor`) because
`MediaParser` doesn't support transcoding subtitles to
`application/x-media3-cues`. This transcoding is required to support
non-legacy subtitle handling where they are parsed during extraction,
instead of during rendering.

PiperOrigin-RevId: 665282298
2024-08-20 03:54:17 -07:00
Ian Baker
af5df6e700 Add retryCount parameter to make it clear onLoadStarted is called for retries too 2024-08-20 11:28:18 +01:00
Colin Kho
33d9b78e21 Fix javadoc of onLoadStarted & remove error information as fields 2024-08-20 11:13:41 +01:00
Colin Kho
1cc1bf02ef Added onLoadStarted callback to Loader's callback 2024-08-20 11:13:41 +01:00