Compare commits

...

1460 Commits

Author SHA1 Message Date
tonihei
839c4a90f2 Update release notes for 1.6.1
PiperOrigin-RevId: 747337479
(cherry picked from commit 3205811f239f046062977435ff28a544fa947cfd)
2025-04-14 11:29:27 +01:00
shahddaghash
184416adfc Prevent metricsReporter.reportMetrics() from throwing
In general, metrics collection should not lead to Transformer thorwing and crashing the app.

PiperOrigin-RevId: 739099456
(cherry picked from commit 3f5019b9088555e8bbbd492901c272ae47b5fb67)
2025-04-14 10:12:25 +01:00
michaelkatz
aea0637c95 Fix media period mismatch during recoverable renderer error processing
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
2025-04-14 09:55:23 +01:00
tonihei
f533f55cd6 Add missing type cast
(required due to not cherry-picking 6b1a2aff98)
2025-04-14 09:33:02 +01:00
tonihei
177092d935 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
(cherry picked from commit 68538029c926642da42a7ebf40543f480c38146e)
2025-04-12 21:12:31 +01:00
rohks
153974e06c Derive average bitrate from stsz sample size and mdhd duration
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)
2025-04-12 21:12:28 +01:00
tianyifeng
d7234a6a4e 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

PiperOrigin-RevId: 746490375
(cherry picked from commit 344f249511ad67a42d8328e79102f02bbbec5201)
2025-04-12 21:12:11 +01:00
tonihei
24a8185f4d Ensure media notification provider can be updated
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)
2025-04-12 21:10:54 +01:00
tonihei
d652ba6ae2 Bump version to 1.6.1
PiperOrigin-RevId: 746409221
(cherry picked from commit 45bcf3ff929f0023d4c982c2489214d91ffec29c)
2025-04-12 21:10:54 +01:00
bachinger
75e2522862 Always return empty timeline when wrapped player is empty
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)
2025-04-12 21:10:54 +01:00
tonihei
157fd8a260 Remember explicit notification dismissal
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)
2025-04-12 21:10:54 +01:00
bachinger
ce0c98c4d4 Make sure subtitle is used without display title being set
PiperOrigin-RevId: 745616511
(cherry picked from commit cb0ea7fc95ffb1160cfd7904ee5c548d8f0a68cb)
2025-04-12 21:10:51 +01:00
aquilescanta
b16f9fc4ec Add missing isDeviceMuted to EVENT_DEVICE_VOLUME_CHANGED docs
PiperOrigin-RevId: 745591130
(cherry picked from commit c5b6489d5d6eb206f34b2e11c32ecb34c4ca7d49)
2025-04-12 21:09:13 +01:00
bachinger
5b4ca08ca0 Adjust AGGREGATES_CALLBACKS_WITHIN_TIMEOUT_MS and make it configurable
PiperOrigin-RevId: 745585764
(cherry picked from commit 1b3658e357adad6f12fd7cc864f0b0d64f38fb3c)
2025-04-12 21:09:13 +01:00
tonihei
c0dd97e770 Clear surface from previous player when assigning a new player
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)
2025-04-12 21:09:13 +01:00
rohks
f35c59b176 Ensure chunk duration is set in CmcdData for HLS media
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)
2025-04-12 21:09:13 +01:00
dancho
82d7c628da Do not drop decoder input buffers close to a reset position
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)
2025-04-12 21:09:13 +01:00
michaelkatz
9cfaf78994 Do not enable offload scheduling while preparing next media
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)
2025-04-12 21:09:13 +01:00
bachinger
cb80fe4c7c Make AdPlaybackState.withAdDurationsUs work with removed ad groups
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)
2025-04-12 21:09:09 +01:00
michaelkatz
567ee030b3 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 implementing `AudioSink#getAudioTrackBufferSizeUs()`.

PiperOrigin-RevId: 743082057
(cherry picked from commit 9e80d6d263d04021e24d4897f415898964a93a05)
2025-04-12 21:08:54 +01:00
rohks
2bdf632369 Remove incorrect frame rate calculation using tkhd box duration
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)
2025-04-12 21:08:54 +01:00
tonihei
7c274caa1f Update PlayerSurface to directly use AndroidView
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)
2025-04-12 21:08:54 +01:00
tianyifeng
9d09840bad Add PlaybackParameters.withPitch() method
Issue: androidx/media#2257
PiperOrigin-RevId: 742693410
(cherry picked from commit ce3754a7409562724b5de399cfaab60b96d90da2)
2025-04-12 21:08:54 +01:00
Copybara-Service
9483cbfed4 Merge pull request #2253 from nirb999:main
PiperOrigin-RevId: 741092998
(cherry picked from commit f2fa0f7b2ac998db12722a6a46158474cccfcbc1)
2025-04-12 21:08:39 +01:00
ibaker
358e002076 MP4: Parse alternate_group and expose it in Format.metadata
Issue: androidx/media#2242
PiperOrigin-RevId: 740794206
(cherry picked from commit 0d60c5bf25a8725c21affa951409ba148394c526)
2025-04-12 21:08:36 +01:00
Copybara-Service
1ee030afb1 Merge pull request #2260 from MGaetan89:audiomanagercompat_log
PiperOrigin-RevId: 740752418
(cherry picked from commit 95fbecd0764851a857b7037d76277a9e0725475a)
2025-04-12 21:07:41 +01:00
michaelkatz
ef8f72d684 Set that any error during pre-warming disables and resets pre-warming
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)
2025-04-12 21:07:38 +01:00
michaelkatz
2939bfccbe Add support for RTSPT scheme in RtspMediaSource.Factory
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)
2025-04-12 21:02:40 +01:00
ibaker
1d2019b770 Add unsuitable audio output to to-string logic in EventLogger
PiperOrigin-RevId: 739875995
(cherry picked from commit 75a067a223330d869ecfc87bd170eaf00f55a866)
2025-04-12 21:02:40 +01:00
rohks
3c4410e967 Add language information for video tracks in BoxParser for Mp4 files
PiperOrigin-RevId: 738777635
(cherry picked from commit 2d4b37dc282dfde1aa8580c0adae45e7fe8d2a28)
2025-04-12 21:02:36 +01:00
rohks
d79d6b2b8b Fix KEY_TRACK_ID in MediaFormat returned by getTrackFormat()
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)
2025-04-12 21:02:20 +01:00
rohks
d920cf87a6 Fix parsing of language code in mdhd box
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)
2025-04-12 21:02:16 +01:00
Copybara-Service
963bae9dd8 Merge pull request #2235 from MGaetan89:add_CastPlayer_playlistMetadata
PiperOrigin-RevId: 738455260
(cherry picked from commit 2d1bcc77be3acd0a8297220f7564483c12db32b3)
2025-04-12 21:01:40 +01:00
rohks
dcb67102b9 Parse btrt box in BoxParser to get bitrate information for Mp4 files
PiperOrigin-RevId: 738370142
(cherry picked from commit 88da587b0a5742e31452d5b7609ef96c048095d0)
2025-04-12 21:00:30 +01:00
ibaker
75e28d82e3 Fix FLAC interactions with PBA 'remaining capacity'
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)
2025-04-12 21:00:30 +01:00
ibaker
673da97fde Update Format.pcmEncoding docs to include lossless compression
This field has been used for encoded FLAC data since ba8f55694a

PiperOrigin-RevId: 736811640
(cherry picked from commit fe8163838ed4adead705e2a537973d3c741f5d8e)
2025-04-12 21:00:30 +01:00
michaelkatz
57c82710ea Limit dynamic scheduling interval by the audio track buffer size
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)
2025-04-12 21:00:30 +01:00
tonihei
51efcad672 Merge branch 'release' into release-1.6.0 2025-03-27 12:55:05 +00:00
tonihei
fdbf2a48f7 Add missing 1.6.0 entry to GH bug template
PiperOrigin-RevId: 741120336
(cherry picked from commit f74abed9843dcfc75fe81ac88452e9eef5196f01)
2025-03-27 12:53:29 +00:00
tonihei
df3b138391 Update release notes for 1.6.0
PiperOrigin-RevId: 738443368
(cherry picked from commit a37e906a0a44e166a75a1d75b12c39685b0a5806)
2025-03-19 17:29:46 +00:00
tonihei
7c0fb628ac Version bump to Media3 1.6.0
PiperOrigin-RevId: 738421167
(cherry picked from commit ecad8a53577dc9c843a939e5528b2b41dec23cc4)
2025-03-19 17:29:46 +00:00
tonihei
05827ea5ed Avoid unsupported mock operation
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)
2025-03-19 13:53:29 +00:00
Googler
c558ae43c5 Fix a race condition in HttpEngineDataSource
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)
2025-03-18 18:01:40 +00:00
tonihei
8212b964d1 Exclude Xiaomi and OPPO devices from detached surface mode
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)
2025-03-18 18:01:40 +00:00
tianyifeng
bd104b1cc4 Consider audio output latency when source has ended
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)
2025-03-18 18:01:40 +00:00
tonihei
efb109dd88 Update release notes for 1.6.0-rc02
PiperOrigin-RevId: 737986781
(cherry picked from commit 0991dbcd7dfacc97a191c9053b8bdc59234447bd)
2025-03-18 18:01:37 +00:00
tonihei
dadd970f6e Version bump to Media3 1.6.0-rc02
PiperOrigin-RevId: 737948053
(cherry picked from commit b1068e47d35ac479f111a88fed870d1fdef52376)
2025-03-18 18:00:56 +00:00
Googler
25dc53551d Add CookieHandler support to HttpEngineDataSource.
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)
2025-03-18 18:00:56 +00:00
ibaker
53a3144f96 Rollback of 3b38a7a43b
PiperOrigin-RevId: 731248658
(cherry picked from commit a6debf49048f59544757df880b30a23ed88c277a)
2025-03-18 18:00:56 +00:00
Googler
89cfee6e31 Add CookieHandler support to HttpEngineDataSource.
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)
2025-03-18 18:00:56 +00:00
tonihei
8fa785fc27 Adjust dump files to different dumping logic
In particular, 796df136 and df489e2f are not part of the release branch
2025-03-18 12:27:04 +00:00
ibaker
5c1e0d964a Add 32-bit FLAC test files, and use them in some tests
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)
2025-03-18 11:39:46 +00:00
tonihei
fa71bf229e Wait for first frame when using placeholder surface
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)
2025-03-18 11:20:44 +00:00
tonihei
e2017e35db Move decode-only and no surface logic inside VideoFrameReleaseControl
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)
2025-03-18 11:16:38 +00:00
tonihei
0a284f4927 Refine logic of when to skip placeholder surface buffers
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)
2025-03-18 11:09:27 +00:00
tonihei
8e2ed3bf4d Avoid unsupported mock operation
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)
2025-03-18 11:05:35 +00:00
tonihei
d8914c31e2 Update release notes for 1.6.0-rc02
PiperOrigin-RevId: 737624189
(cherry picked from commit ff0a359e9311b9eadb0346b5e1c38115c0e07082)
2025-03-18 11:05:32 +00:00
tonihei
1512b5b622 Clip start time to window duration when clipping
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)
2025-03-18 11:04:17 +00:00
tianyifeng
f357f0a966 Loosen the condition for seeking to sync positions in a HLS stream
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)
2025-03-18 11:04:14 +00:00
ibaker
5957daadee Indicate MediaCodec FLAC decoder doesn't support 32-bit below API 34
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)
2025-03-18 11:03:35 +00:00
ibaker
9a91b2774e Add support for 32-bit FLAC files in the built-in FLAC extractor
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)
2025-03-18 11:03:31 +00:00
tonihei
a3f4b3dd1f Add toString to TrackGroup(Array)
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)
2025-03-18 11:01:58 +00:00
ivanbuper
f2739302af Add createShortBuffer() to TestUtil
PiperOrigin-RevId: 730875642
(cherry picked from commit 1399e772490b3ee602b298d58f5683ae0a00f688)
2025-03-17 15:00:53 +00:00
tonihei
24b3bf21b8 Check language/role flags before merging adaptation sets
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)
2025-03-17 14:06:03 +00:00
tonihei
23468ed55c Clarify that method can only be called after onCreate
And improve error message if access to the notification controller
happens without a base context.

#cherrypick

PiperOrigin-RevId: 736545574
(cherry picked from commit 41722be02e34199543dc92c44e12ff95a35cb378)
2025-03-17 14:02:19 +00:00
ivanbuper
97606094ca Add float PCM support to TrimmingAudioProcessor
This was requested in Issue: androidx/media#2191.

PiperOrigin-RevId: 735375746
(cherry picked from commit 06163f3dfaf9eb13d84790273179157e762122ed)
2025-03-17 14:02:16 +00:00
tonihei
b215670445 Make foreground service timeout configurable
This allows apps to set a shorter timeout if so desired.

Issue: androidx/media#2206

#cherrypick

PiperOrigin-RevId: 735360459
(cherry picked from commit 222950cfd1bdc942b90e0991e6b96a3f2c86518a)
2025-03-17 14:01:30 +00:00
tonihei
67ec5b76ad Ensure notification is removed when shouldShowNotification==false
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)
2025-03-17 14:01:27 +00:00
jbibik
6b003993a5 [ui-compose] Move ComposeBom from implementation to api
PlayerSurface exposing the Modifier argument means the gradle dependency needs to be stricter

#cherrypick

PiperOrigin-RevId: 734237616
(cherry picked from commit 8dcfa1afbead8d7af1e11e871df9359052f107c6)
2025-03-17 14:00:26 +00:00
ivanbuper
d2703a12cc Add support for FLOAT_PCM in ChannelMappingAudioProcessor
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)
2025-03-17 14:00:22 +00:00
jbibik
fb57e45a58 Align release notes labels spelling
PiperOrigin-RevId: 733717073
(cherry picked from commit bc9a974e07d117c146d2508b363a524c38c0630b)
2025-03-17 13:58:57 +00:00
jbibik
d9deda7b6e [ui-compose] Add PlaybackSpeedState to control playbackParameters.speed
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)
2025-03-17 13:56:51 +00:00
jbibik
5d1e8d1279 Version bump for Media3 1.6.0-rc01
#cherrypick

PiperOrigin-RevId: 733036051
(cherry picked from commit cdb112a85a412d12803d0d3e237f5223b74fba52)
2025-03-03 21:26:19 +00:00
jbibik
3b55f18013 Update release notes for Media3 1.6.0-rc01 release
PiperOrigin-RevId: 732964311
(cherry picked from commit 7419a81aa748ba4210471f28ada9db41c1f3aa65)
2025-03-03 21:26:15 +00:00
Googler
e1d328db11 Fix resizing in debug preview
PiperOrigin-RevId: 732905018
(cherry picked from commit 1e4a10651a931ed9c95898bff1151d8f16a322af)
2025-03-03 16:27:28 +00:00
tonihei
766dbd497e Add util to obtain AudioManager
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)
2025-03-03 16:27:28 +00:00
ibaker
595fd48cd7 Disable subtitlesRespectClipping_multiplePeriods test on API 21
PiperOrigin-RevId: 732065230
(cherry picked from commit f8c3af52e9091db3f683c4661b53e2f92de6fbb4)
2025-03-03 16:27:28 +00:00
jbibik
768f25e163 [ui-compose] Better KDoc formatting
#cherrypick

PiperOrigin-RevId: 731712846
(cherry picked from commit 66ef013cb85e8d7db5679242190202745abf3110)
2025-03-03 16:27:28 +00:00
tonihei
2cb6d4312b Do not assume default callback for Audio focus requests is main looper
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)
2025-03-03 16:27:28 +00:00
jbibik
c7fa2c3de6 [ui-compose] Add KDoc to observe() methods for button states
#cherrypick

PiperOrigin-RevId: 731686021
(cherry picked from commit b465cbc22c61acc07875550d1c1f24aa5d080f13)
2025-03-03 16:27:28 +00:00
Copybara-Service
c66c221b28 Merge pull request #2190 from nift4:main
PiperOrigin-RevId: 731316955
(cherry picked from commit 366e5eccf889be2d88f126846ebc4395f0e5cff7)
2025-03-03 16:27:28 +00:00
ibaker
fd2e874b5d Rewrite ClearKey UUID to Common PSSH UUID in PSSH box on API < 27
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)
2025-03-03 16:27:27 +00:00
simakova
3083a48ecb Add missing links to the effect demo README
PiperOrigin-RevId: 731305090
(cherry picked from commit 5417279982729b8bf5107c48a3cca0904b0c6300)
2025-03-03 16:27:27 +00:00
jbibik
f7479347c0 [ui-compose] Add default value to PlayerSurface's surfaceType
PlayerView's default surface type was also SURFACE_VIEW.

This allows for a simple `PlayerSurface(player)` usage by most developers.

The order of the arguments needs to be changed, because `modifier` should be the first default argument (https://android.googlesource.com/platform/frameworks/support/+/androidx-main/compose/docs/compose-component-api-guidelines.md#parameter)

PiperOrigin-RevId: 731294658
(cherry picked from commit afea6962c254b6621eee2b8f075d6fdb5283602a)
2025-03-03 16:27:27 +00:00
Copybara-Service
4d3f71a0c6 Merge pull request #2180 from nift4:main
PiperOrigin-RevId: 731276598
(cherry picked from commit ac1cf206c89ea656b5a88b807a178f4d3f94d9f0)
2025-03-03 16:27:27 +00:00
sheenachhabra
9ba0a1b470 Reset maxTrackDurationUs when a new fragment is written
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)
2025-03-03 16:27:25 +00:00
ibaker
f739e2d68c Suppress some instrumentation tests on older API levels
PiperOrigin-RevId: 731257575
(cherry picked from commit 20ea05063bcccec8b83c9848fc5b3dbf4edc290c)
2025-03-03 16:26:31 +00:00
tonihei
fc4112beee Move audio focus management to ExoPlayerImplInternal
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)
2025-03-03 16:26:31 +00:00
Copybara-Service
9052313245 Merge pull request #2113 from colinkho:lastrebufferinssp
PiperOrigin-RevId: 730919539
(cherry picked from commit 2c866ce50be132858d9cb4c30c174790577f7560)
2025-03-03 16:26:31 +00:00
Copybara-Service
c4a77475c4 Merge pull request #2135 from bubenheimer:handleMoveMediaItems_docfix
PiperOrigin-RevId: 730886871
(cherry picked from commit 57d4f8354a90960adeb2241683c2b175c03b3ce7)
2025-03-03 16:26:31 +00:00
ibaker
954a1d44e4 Bump play-services-cast-framework cast dependency to 21.5.0
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)
2025-03-03 16:26:31 +00:00
ibaker
8b9e9203a1 Add missing call to adjustUuid in FrameworkMediaDrm
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)
2025-03-03 16:26:31 +00:00
tonihei
317bf3c6c0 Add kotlin-stdlib to aar workaround list
#cherrypick

PiperOrigin-RevId: 730880594
(cherry picked from commit a3f281dff827cbc63482d5e2fbdbedb2427cbb95)
2025-03-03 16:26:31 +00:00
dancho
521c385d4b Add experimentalSetCodecsToParseWithinGopSampleDependencies to HLS
HLS extractors were missing
experimentalSetCodecsToParseWithinGopSampleDependencies prior to this patch.

PiperOrigin-RevId: 730878460
(cherry picked from commit da402cfd64ef3ae60607491730f01138177a077b)
2025-03-03 16:26:31 +00:00
Copybara-Service
a578d43324 Merge pull request #2115 from MGaetan89:use_objects_equals
PiperOrigin-RevId: 730860597
(cherry picked from commit cc44de8757501cab7e4bb70fd0b090c6dc9799e1)
2025-03-03 16:26:31 +00:00
Copybara-Service
28b70f7e85 Merge pull request #2145 from v-novaltd:dsparano-exo328
PiperOrigin-RevId: 730853667
(cherry picked from commit 85467b9b57ab8ee38cfcb6c9e0f484fd167df372)
2025-03-03 16:26:31 +00:00
ibaker
d755a0477d Fix casting in ParsableByteArray.peekCharacterAndSize
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)
2025-03-03 16:26:31 +00:00
tonihei
1f691106f1 Clarify that multiple LibraryParams fields can be set
Issue: androidx/media#2159
PiperOrigin-RevId: 730805485
(cherry picked from commit 3f493eaf9e01909094e99c173cec96b1256f5ca4)
2025-03-03 16:26:31 +00:00
ivanbuper
77c8ddd884 Rollback of 6e9a2cc0cd
PiperOrigin-RevId: 730482824
(cherry picked from commit ee6eb98d4bd4f63270744e25b606208a4a950288)
2025-03-03 16:26:31 +00:00
tonihei
50f6bdd1fd Do not change audio capabilities for error recovery without context
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)
2025-03-03 16:26:31 +00:00
shahddaghash
ff65d7b05b Enable metrics collection by default
PiperOrigin-RevId: 730383523
(cherry picked from commit c90ca4e86ee042f6ce8c6971e075bf0f8d893901)
2025-03-03 16:26:31 +00:00
bachinger
6c143230d7 Avoid rare NPE in MediaSessionServiceTest
PiperOrigin-RevId: 730363453
(cherry picked from commit 76df13d390e57f4462e9e44b20997c6e7dfb8148)
2025-03-03 16:26:31 +00:00
dancho
62ef83b68e MCVR: limit the number of consecutive dropped input frame headers
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)
2025-03-03 16:26:30 +00:00
bachinger
8ee2532db3 Deflake MediaSessionServiceTest
`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)
2025-03-03 16:26:30 +00:00
Copybara-Service
4d50e8a815 Merge pull request #2170 from wischnow:main
PiperOrigin-RevId: 729558029
(cherry picked from commit 7c2e8c1c4b608bc5da5649d7f2d7f9674dba5d36)
2025-03-03 16:26:30 +00:00
Copybara-Service
2c123dedbb Merge pull request #2149 from bubenheimer:util_postorrun_fix
PiperOrigin-RevId: 729495445
(cherry picked from commit 05c8a66dc256b2658bfc4cf43b7e9435dbc75b54)
2025-03-03 16:26:30 +00:00
Copybara-Service
7ed1ebea3a Merge pull request #2139 from bubenheimer:handleReplaceMediaItems_removerangecodefix
PiperOrigin-RevId: 729490370
(cherry picked from commit 2b12a574473c6304511f76325e1927ca50c264bf)
2025-03-03 16:26:30 +00:00
Copybara-Service
b8468bbee3 Merge pull request #2136 from bubenheimer:handleReplaceMediaItems_docfix
PiperOrigin-RevId: 729474558
(cherry picked from commit 378e70e15fe38eae33ab7ed74ea9614ba6ec45cb)
2025-03-03 16:26:30 +00:00
shahddaghash
a5d7be959b Update exporter and muxer name to match expected pattern
If the name does not match patten, it gets skipped when reporting.

PiperOrigin-RevId: 729463344
(cherry picked from commit 23ebea7ab4afe1cff4b4c3fce222e33639dfd34e)
2025-03-03 16:26:30 +00:00
tonihei
073e50a893 Ensure DataSource is closed in CacheWriter at non-IOException
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)
2025-03-03 16:26:30 +00:00
tianyifeng
8e5368a807 Mask ExoPlayer.isLoading when it transitions to IDLE or ENDED states
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)
2025-03-03 16:26:30 +00:00
shahddaghash
816a119617 Verify each export had its own session
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)
2025-03-03 16:26:30 +00:00
Googler
13e14b8e31 Update the list of supported video mimetypes.
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)
2025-03-03 16:26:30 +00:00
jbibik
41062d3910 Fix Shuffle and Repeat references in tests
PiperOrigin-RevId: 728309204
(cherry picked from commit 4045acd13b17c68d7fe532cb7ba746517f83f089)
2025-03-03 16:26:30 +00:00
shahddaghash
e393587787 Add test for usePlatformDiagnostics disabled
PiperOrigin-RevId: 728276994
(cherry picked from commit 90844f11e88ad9dbb26c7fd4bd72d99c577b9c54)
2025-03-03 16:26:30 +00:00
tonihei
d880ab5d4f Make SimpleBasePlayer.State public
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)
2025-03-03 16:26:25 +00:00
tonihei
75da514b7f Decouple gradle publish task from lint and test
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)
2025-03-03 16:25:01 +00:00
shahddaghash
cb2df35a5b Add EditingMetricsCollector test for export cancellation
PiperOrigin-RevId: 727885381
(cherry picked from commit 116fbeaa81b648b6a4bd2f8b202a2140f2450a98)
2025-03-03 16:25:01 +00:00
shahddaghash
ed05bc67c3 Move FrameBlockingMuxer into AndroidTestUtil
This allows it to be reused in upcoming tests.

PiperOrigin-RevId: 727835985
(cherry picked from commit f8d5f5a828d0783725696a27a12b78f577effaa0)
2025-03-03 16:25:01 +00:00
shahddaghash
4a8d28cef8 Add EditingMetricsCollector test for export error
PiperOrigin-RevId: 727835981
(cherry picked from commit 6f60aa2548c556370f1e0bb1aaf33a42c460f33c)
2025-03-03 16:25:00 +00:00
shahddaghash
16add9922d Add EditingMetricsCollector test for export success
PiperOrigin-RevId: 727826326
(cherry picked from commit 3ce6a2e6b8b0b7147a06c5ec38aaf2ee36282720)
2025-03-03 16:25:00 +00:00
shahddaghash
e58d9120bc Create a new MetricsReporter.Factory
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)
2025-03-03 16:25:00 +00:00
bachinger
bb358241b9 Make setSessionActivity accept null
Issue: androidx/media#2109
PiperOrigin-RevId: 728160580
(cherry picked from commit 2b8700beaaabd51365daf9099c42bfa64a2dd4fe)
2025-02-18 14:11:51 +00:00
tonihei
bc872503b9 Ignore .kotlin directory
#cherrypick

PiperOrigin-RevId: 728119609
(cherry picked from commit 0a50741abec718c09e52c5f00cc241a00eeba23d)
2025-02-18 14:09:17 +00:00
tonihei
b49374c8fe Remove unreleased section from RELEASENOTES 2025-02-18 09:51:26 +00:00
tonihei
3f10fa92bb Version bump for Media3 1.6.0-beta01
#cherrypick

PiperOrigin-RevId: 727889651
(cherry picked from commit 78cf53c0b2f604b4d04ab749250f4e4fe88e240f)
2025-02-18 09:42:24 +00:00
Googler
625ff234e4 Update CSD and apvC box logic
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)
2025-02-18 09:42:24 +00:00
tonihei
88e7636ae0 Use different authorities for AssetContentProvider
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)
2025-02-18 09:42:24 +00:00
tonihei
57bbb6c5c6 Update release notes for 1.6.0-beta01
#cherrypick

PiperOrigin-RevId: 727862233
(cherry picked from commit 18f38647732c7fbbafce30d99ab8062da6be2aff)
2025-02-18 09:42:23 +00:00
kimvde
9ad06570b5 Transformer: fix gradle dependency type
PiperOrigin-RevId: 727760498
(cherry picked from commit c1eb381948d5e936bdc9cfb37ca529b816bfcc1b)
2025-02-18 09:42:23 +00:00
tonihei
7db4802f02 Update ignore files for most recent FLAC extension code
Following the README, a libflac directory is created, which
needs to be ignored in VCSs

#cherrypick

PiperOrigin-RevId: 727103140
(cherry picked from commit b306b1059772c2e279020f65ac60ae975fca3fbf)
2025-02-18 09:42:23 +00:00
tonihei
1ceafc7a61 Add timeout to foreground service handling
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)
2025-02-14 18:41:15 +00:00
tonihei
3b897241d2 Increase timeout for AudioPositionAdvancingTest
500ms may not be enough to start playback on a slow device

#cherrypick

PiperOrigin-RevId: 726940099
(cherry picked from commit 792a2ae05dbade27d9cd5a8923a1f3cebf083a91)
2025-02-14 18:41:15 +00:00
tonihei
2a3e733161 Post initial media button preferences update
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)
2025-02-14 18:41:15 +00:00
tonihei
22e5f25648 Refine logic to set and interpret ACTION_PAUSE/ACTION_PLAY
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)
2025-02-14 18:41:15 +00:00
tonihei
71a2b7d72d Refine conversion logic from platform to Media3 state for STATE_ENDED
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)
2025-02-14 18:41:15 +00:00
tonihei
89b5420bc8 Show notification even in STATE_IDLE
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)
2025-02-14 18:41:15 +00:00
rohks
d14807c836 Add contract tests for DRM and logging to MediaExtractorContractTest
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)
2025-02-14 18:41:15 +00:00
tonihei
be76766f95 Add dedicated EPII method to set volume
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)
2025-02-14 18:41:15 +00:00
tonihei
8bd1db5f2c Move DefaultSuitableOutputChecker operations to playback thread
PiperOrigin-RevId: 726879236
(cherry picked from commit e0ef6e51829dd1627d952d2677f532230cb2dbc9)
2025-02-14 18:41:15 +00:00
tonihei
41af00f100 Move unsuitable output path logic <API31 into SuitableOutputChecker
This avoids distributing the logic between multiple classes and
keeps ExoPlayerImpl simpler.

PiperOrigin-RevId: 726874038
(cherry picked from commit 1015ef8b565ed04e88a9c596798d294327d05536)
2025-02-14 18:41:15 +00:00
tonihei
841e27ae5c Move MediaMetricsListener creation and reporting off main thread
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)
2025-02-14 18:41:15 +00:00
tonihei
cd6e61d856 Send renderer settings messages to secondary renderers in ExoPlayer
They are currently only sent to the primary renderer.

PiperOrigin-RevId: 726864595
2025-02-14 04:06:36 -08:00
tonihei
12afdfbaea Improve placeholder value in StreamVolumeManager for muting
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
2025-02-14 02:28:34 -08:00
tonihei
dfd2b75720 Stablize command button icons
These are the preferred replacement for custom icon res ids.

PiperOrigin-RevId: 726821168
2025-02-14 01:24:18 -08:00
tonihei
385498c24e Move audio session id generation to playback thread
PiperOrigin-RevId: 726556015
2025-02-13 10:57:19 -08:00
dancho
22853a5c4c MCVR: fix dropped input buffer count
updateDroppedBufferCountersWithInputBuffers should receive
buffer timestamps before adjusting offset

PiperOrigin-RevId: 726473967
2025-02-13 07:17:41 -08:00
ibaker
12072f7248 Rename TestPlayerRunHelper.run(...) to advance(...)
This avoids a clash with the `run` keyword in Kotlin.

PiperOrigin-RevId: 726461032
2025-02-13 06:37:31 -08:00
andrewlewis
9e22f03718 Add support for screen recording to the Transformer demo
Screen recording continues even if the transformer activity is backgrounded,
to support recording other apps.

PiperOrigin-RevId: 726454538
2025-02-13 06:16:54 -08:00
andrewlewis
04d9a751c6 Add encoder setting to set frame repeat interval
This can be used for screen recording to produce files without large gaps
between frames.

PiperOrigin-RevId: 726451010
2025-02-13 06:05:52 -08:00
kimvde
2a91d47ea9 Add tests for prewarming disabled
PiperOrigin-RevId: 726411904
2025-02-13 03:49:14 -08:00
Googler
f5e583332b Copy the isPlaceholder flag into CurrentMediaItemOnlyTimeline
PiperOrigin-RevId: 726405776
2025-02-13 03:32:08 -08:00
kimvde
cea67e8826 Do not record test skipped for tests skipped on emulator
AndroiTestUtil.recordTestSkipped is useful for MH tests

PiperOrigin-RevId: 726397349
2025-02-13 03:01:18 -08:00
sheenachhabra
56bd32da96 Add Lint.IfChange/ThenChange for muxer codec support logic
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
2025-02-13 02:59:20 -08:00
dancho
38cfd7dc36 Add dropped input buffers to DebugTextViewHelper
The field is more relevant with the
`experimentalSetLateThresholdToDropDecoderInputUs` API.

PiperOrigin-RevId: 726383978
2025-02-13 02:10:57 -08:00
dancho
b9ef0353cf Reduce memory allocations of AnnexBToAvccConverter
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
2025-02-13 01:59:02 -08:00
ibaker
ee4f9d9140 Remove media1 dependency from media3-ui lib
Also remove deprecated
`PlayerNotificationManager.setMediaSessionToken(MediaSessionCompat)`
method.

PiperOrigin-RevId: 726159462
2025-02-12 12:46:27 -08:00
ibaker
2155c37b08 Switch most intra-lib deps from implementation to api
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
2025-02-12 11:29:50 -08:00
kimvde
6e332e9b91 Do not fail the export in case of ExoPlayer release time out
PiperOrigin-RevId: 725996730
2025-02-12 04:13:27 -08:00
bachinger
813973bb58 Explicitly test custom extra entries for legacy conversions
Issue: androidx/media#2127
PiperOrigin-RevId: 725984132
2025-02-12 03:25:22 -08:00
kimvde
be51913b81 Refactor GlObjectsProvider release logic
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
2025-02-12 03:23:49 -08:00
ibaker
5de3ee86e3 Remove the lib-exoplayer dep from lib-common-ktx
This dependency is not used.

PiperOrigin-RevId: 725983258
2025-02-12 03:21:31 -08:00
Googler
1310496809 Revert DefaultEncoderFactory to previous defaults
Also changed encoder factory to not set operating rate or priority if they equal `RATE_UNSET` rather than `NO_VALUE`

PiperOrigin-RevId: 725964682
2025-02-12 02:11:39 -08:00
rohks
75607ac1eb Add tests for setDataSource APIs to MediaExtractorContractTest
Added remaining tests to cover all `setDataSource` APIs in `MediaExtractor`.

PiperOrigin-RevId: 725616816
2025-02-11 07:11:06 -08:00
Googler
a5e5374ba0 Enable ALL_CODECS MediaCodec list when decoding MV-HEVC video.
This is needed since MV-HEVC decoder is marked as a special codec in the media_codecs.xml file.

PiperOrigin-RevId: 725616290
2025-02-11 07:10:08 -08:00
rohks
a5689735a1 Replace assumeTrue with @SdkSuppress for SDK version checks
PiperOrigin-RevId: 725616043
2025-02-11 07:08:16 -08:00
Googler
447d784636 Use encoder input format for sample rate fallback.
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
2025-02-11 06:43:58 -08:00
shahddaghash
1b882fec0c Add unit tests for EditingMetricsCollector
The change includes adding a `MetricsReporter` interface with a default implementation to allow testing the `EditingMetricsCollector`.

PiperOrigin-RevId: 725607330
2025-02-11 06:33:39 -08:00
Googler
fafd12bcfe Rollback of 4ed9abd05b
PiperOrigin-RevId: 725575345
2025-02-11 04:26:50 -08:00
kimvde
9f60eb3825 Fix TODOs formatting in Transformer
PiperOrigin-RevId: 725572106
2025-02-11 04:15:32 -08:00
dancho
5510635620 MCVR Parse AV1 sequence headers in onQueueInputBuffer
AV1 random access points (sync samples) contain updated sequence headers
that are needed for later frame parsing.

PiperOrigin-RevId: 725565810
2025-02-11 03:50:32 -08:00
Googler
50d4e66308 Add getInputFormat to Codec interface
PiperOrigin-RevId: 725552831
2025-02-11 02:58:55 -08:00
jbibik
d022b570f2 Upgrade Kotlin to 2.0.20
This upgrade allows us to use https://developer.android.com/develop/ui/compose/compiler as specified in https://developer.android.com/jetpack/androidx/releases/compose-kotlin#pre-release_kotlin_compatibility

kotlinOptions is considered deprecated in preference of kotlin.compilerOptions (https://kotlinlang.org/docs/gradle-compiler-options.html#how-to-define-options)

PiperOrigin-RevId: 725266131
2025-02-10 10:32:47 -08:00
andrewlewis
1a996d87ca Add MediaProjectionAssetLoader
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
2025-02-10 09:23:34 -08:00
kimvde
faf555e12b MultipleInputVideoGraph: Destroy EGL context on GL thread
PiperOrigin-RevId: 725159572
2025-02-10 04:25:32 -08:00
kimvde
cadecf0219 Add video prewarming to CompositionPlayer
PiperOrigin-RevId: 725153751
2025-02-10 04:04:19 -08:00
Googler
aa6183e883 Update EncoderPerformanceAnalysisTest
PiperOrigin-RevId: 725150395
2025-02-10 03:48:38 -08:00
Googler
0ba3bf66c6 Add raw audio support to Mp4Muxer.
The fourcc used is `sowt` for little endian 16 bit PCM and `twos` for big endian 16 bit PCM.

PiperOrigin-RevId: 724391195
2025-02-07 10:26:48 -08:00
tianyifeng
1190980616 Remove deprecated DownloadHelper constructor and util method
PiperOrigin-RevId: 724300907
2025-02-07 04:50:49 -08:00
dancho
65e7b599d8 AV1 treat show_existing_frame headers as not depended on
PiperOrigin-RevId: 724300793
2025-02-07 04:49:10 -08:00
claincly
babc2dd416 Match with ExoPlayer seeking when using CompositionPlayer
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
2025-02-07 04:26:00 -08:00
ibaker
5e6fb88372 Add missing LINT.If/ThenChange comments
PiperOrigin-RevId: 724291745
2025-02-07 04:10:41 -08:00
claincly
d23d4fc314 Add more test cases to the seek test
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
2025-02-06 13:35:40 -08:00
tianyifeng
d641f6a04c Allow setting byte range for progressive media in DownloadRequest
PiperOrigin-RevId: 723995315
2025-02-06 10:52:10 -08:00
ibaker
097771306d Remove LINT.IfChange comments with no following LINT.ThenChange
PiperOrigin-RevId: 723918659
2025-02-06 06:58:11 -08:00
kimvde
e229f957e6 A few nits
PiperOrigin-RevId: 723859603
2025-02-06 02:57:11 -08:00
dancho
a56a0bd928 MCVR: drop decoder input buffers when the decoder is late
* Add experimentalSetMinEarlyUsToDropDecoderInput to DefaultRenderersFactory
and MediaCodecVideoRenderer
* Enable dropping decoder input buffers inside MCVR.shouldIgnoreFrame
* Track consecutive dropped buffers via priority queue for reordering

PiperOrigin-RevId: 723837356
2025-02-06 01:40:28 -08:00
rohks
baf46d36d9 Bump Media3 version to 1.6.0-alpha03
#cherrypick

PiperOrigin-RevId: 723531635
2025-02-05 09:03:49 -08:00
rohks
6a4aa4515e Update release notes for Media3 1.6.0-alpha03 release
#cherrypick

PiperOrigin-RevId: 723512116
2025-02-05 08:03:50 -08:00
michaelkatz
edc44eefd2 Limit dynamic scheduling by the playing period transition point
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
2025-02-05 07:31:03 -08:00
Googler
85158ec841 Update operating rate adjustment visibility
PiperOrigin-RevId: 723501709
2025-02-05 07:27:57 -08:00
dancho
b90610b95a Force signal encoder end of stream after all output has been processed
Fixes a rare failure on some devices.
Only available when `experimentalSetMaxFramesInEncoder` is enabled.

PiperOrigin-RevId: 723498652
2025-02-05 07:15:23 -08:00
dancho
a80e7be029 MCVR support skipping parts of AV1 input buffers
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
2025-02-05 07:09:20 -08:00
rohks
4f3ed2490a Rollback of 99f2a9f152
PiperOrigin-RevId: 723496012
2025-02-05 07:06:09 -08:00
dancho
2fe92bfca5 Use the AV1 sample dependency parser in MCVR
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
2025-02-05 04:51:02 -08:00
shahddaghash
bcce7b5949 Pass the dataType to MediaItemInfo for Transformer
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
2025-02-05 04:38:06 -08:00
michaelkatz
449b81d510 Fix ordering of MediaCodecRenderer.getDurationToProgressUs parameters
Parameter list should match the base Renderer.getDurationToProgressUs more closely.

#cherrypick

PiperOrigin-RevId: 723449756
2025-02-05 04:03:33 -08:00
kimvde
92a06606b4 Remove ability to run the DefaultVideoCompositor on its own GL thread.
- 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
2025-02-05 03:55:42 -08:00
michaelkatz
4c163553e7 Remove pending adLoad timeout tasks when resuming content
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
2025-02-05 03:31:13 -08:00
michaelkatz
97a1d31b5d Reset prewarming renderers when seek resets prewarming media period
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
2025-02-05 03:14:38 -08:00
dancho
f8f66bdfaa Mp4Muxer: disable sample batching and copying by default.
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
2025-02-05 01:05:22 -08:00
shahddaghash
05e66d9cf6 Fix metrics codec names collection
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
2025-02-04 10:05:37 -08:00
Copybara-Service
a19f68c87e Merge pull request #2107 from MGaetan89:issue_384699964
PiperOrigin-RevId: 723124733
2025-02-04 09:53:43 -08:00
sheenachhabra
ae3f962769 Extract "is last item in sequence" check
This improves readability.

PiperOrigin-RevId: 723116229
2025-02-04 09:27:48 -08:00
Gaëtan Muller
a4cc0f2384
Replace Util.MODEL with Build.MODEL 2025-02-04 15:34:33 +01:00
Gaëtan Muller
2aab921aa2
Replace Util.MANUFACTURER with Build.MANUFACTURER 2025-02-04 15:04:08 +01:00
Gaëtan Muller
d0a3d31e56
Replace Util.DEVICE with Build.DEVICE 2025-02-04 15:00:22 +01:00
tianyifeng
3e56d2a6fb Add ProgressiveMediaSource.Listener interface and onSeekMap event
This will allow the listeners who are interested in the `SeekMap` to get informed once the period has done the preparation.

PiperOrigin-RevId: 723027718
2025-02-04 04:30:29 -08:00
michaelkatz
decfb9b0a9 Refactor MediaCodecVideoRenderer to use a Builder
MediaCodecVideoRenderer is becoming unwieldy with the numerous constructors and optional settings. This refactors MediaCodecVideoRenderer to use a builder pattern for simplicity.

PiperOrigin-RevId: 723022129
2025-02-04 04:08:56 -08:00
shahddaghash
1431497e7f Pass output media item information to MediaItemInfo
PiperOrigin-RevId: 723007882
2025-02-04 03:10:24 -08:00
Googler
6e9a2cc0cd Rollback of 79b61d05a6
PiperOrigin-RevId: 722741988
2025-02-03 11:55:06 -08:00
Googler
aaa7e9e3cb Open visibility to HttpDataSourceTestEnv constants
PiperOrigin-RevId: 722712331
2025-02-03 10:37:43 -08:00
dancho
93c129449a Adjust threshold for analyzeVideo performance test
PiperOrigin-RevId: 722651555
2025-02-03 07:33:53 -08:00
shahddaghash
35d5bd9675 Pass output media items's video size and frame count to MediaItemInfo
PiperOrigin-RevId: 722613631
2025-02-03 05:10:48 -08:00
Googler
4ed9abd05b Rollback of 0fb4e3ba11
PiperOrigin-RevId: 722585306
2025-02-03 03:18:59 -08:00
tonihei
82cb1d8ac7 Move AudioBecomingNoisyManager system calls off main thread
PiperOrigin-RevId: 722569306
2025-02-03 02:18:02 -08:00
shahddaghash
5f4c30c431 Add color changing for Text overlay effect
This includes adding a colors dropdown menu for the text color.

PiperOrigin-RevId: 721830591
2025-01-31 10:59:16 -08:00
shahddaghash
9c0a9c19b7 Add Custom Text Overlay to Effect Demo
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
2025-01-31 10:54:50 -08:00
rohks
99f2a9f152 Remove publishing for media3-ui-compose temporarily
Disabled until we find a way to exclude it from media3 Javadoc prebuilts

PiperOrigin-RevId: 721765815
2025-01-31 07:27:59 -08:00
ivanbuper
79b61d05a6 Rollback of 492574bded
PiperOrigin-RevId: 721758531
2025-01-31 06:56:13 -08:00
Googler
d6844699c5 Recognize QC's secure MV-HEVC decoder.
PiperOrigin-RevId: 721749833
2025-01-31 06:20:49 -08:00
Googler
0fb4e3ba11 Add DebugViewEffect
Also updated DefaultVideoFrameProcessor to create GlShaderPrograms with the working ColorInfo rather than the output ColorInfo.

PiperOrigin-RevId: 721748002
2025-01-31 06:13:57 -08:00
claincly
2b07ece0e5 Allow sequences to have non-matching durations
And only repeat the secondary sequence if `isLooping` is set to true

PiperOrigin-RevId: 721713830
2025-01-31 03:46:15 -08:00
tonihei
39d0881083 Add option to ClippingMediaSource to clip unseekable media
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
2025-01-30 11:40:46 -08:00
tonihei
df575a8d19 Add ClippingMediaSource.Builder
This prevents complicated constructor changes when we add new options.

PiperOrigin-RevId: 721415339
2025-01-30 09:23:49 -08:00
rohks
344214d711 Fix RELEASENOTES based on style guide
PiperOrigin-RevId: 721401564
2025-01-30 08:36:39 -08:00
Copybara-Service
fc1d133454 Merge pull request #1905 from khouzam:placeholderSurface
PiperOrigin-RevId: 721367514
2025-01-30 06:34:26 -08:00
shahddaghash
9f96fe81f3 Pass video data space to output's MediaItemInfo
The DataSpace contains the Color Standard, Range, and Transfer.

PiperOrigin-RevId: 721341719
2025-01-30 04:39:24 -08:00
microkatz
ad18ae9c42 Added release note 2025-01-30 11:40:56 +00:00
Gilles Khouzam
8466a957c3 Make MediaCodecVideoRenderer::shouldUsePlaceholderSurface protected.
This enables a derived renderer to disable the placeholder surface.
2025-01-30 11:35:39 +00:00
rohks
045b8e6a52 Fix lint warnings in RELEASENOTES
PiperOrigin-RevId: 721326280
2025-01-30 03:35:04 -08:00
shahddaghash
3f4e0bdb04 Report output's MediaItemInfo to EditingEndedEvent
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
2025-01-30 03:27:25 -08:00
tonihei
17100259cd Move Util.getCountryCode off main thread in DefaultBandwidthMeter
PiperOrigin-RevId: 721293354
2025-01-30 01:23:56 -08:00
tonihei
6b31b4620c Move NetworkTypeObserver operations off main thread
PiperOrigin-RevId: 721291681
2025-01-30 01:17:22 -08:00
kimvde
9af43c7381 CompositionPlayer: skip decode-only frames upstream of the VideoGraph
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
2025-01-29 10:44:56 -08:00
rohks
3c0e2ee198 Suppress UseSdkSuppress warning in MediaExtractorContractTest
The fix is included in Android Gradle Plugin `8.9.0-alpha05`. Remove this suppression after upgrading.

PiperOrigin-RevId: 721009745
2025-01-29 09:42:37 -08:00
rohks
c9a936e153 Bump Media3 version to 1.6.0-alpha02
#cherrypick

PiperOrigin-RevId: 720990835
2025-01-29 08:43:21 -08:00
ivanbuper
fc6df77831 Remove deprecated androidx.media3.exoplayer.audio.SonicAudioProcessor
Also, make `androidx.media3.common.audio.SonicAudioProcessor` final.

PiperOrigin-RevId: 720987023
2025-01-29 08:30:09 -08:00
rohks
98f52a1dbb Rollback of 5c3c3b91f3
PiperOrigin-RevId: 720968647
2025-01-29 07:33:56 -08:00
rohks
6e53d9b3bd Update release notes for Media3 1.6.0-alpha02 release
#cherrypick

PiperOrigin-RevId: 720963785
2025-01-29 07:16:55 -08:00
rohks
dfef16d5c6 Restrict test to API 24+ in MediaExtractorContractTest
`MediaExtractor.setDataSource(AssetFileDescriptor afd)` requires API 24+.

#cherrypick

PiperOrigin-RevId: 720943416
2025-01-29 06:05:39 -08:00
rohks
e15438322d Fix ArrayIndexOutOfBoundsException in MP4 edit lists
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
2025-01-28 11:13:38 -08:00
dancho
bb37aad170 Add an option to use different texture filtering
Add an option to GlMatrixTransformation to choose the OpenGL texture
minification filter.
When mipmaps are requested, mipmaps are generated with
`glGenerateMipmap()`.

PiperOrigin-RevId: 720629807
2025-01-28 10:44:26 -08:00
shahddaghash
bb9b3bd660 Pass codec names of input media items to MediaItemInfo
PiperOrigin-RevId: 720579315
2025-01-28 08:12:42 -08:00
rohks
8d22482f79 Add MediaExtractor contract test structure with one basic test
Additional tests will be added in future changes.

PiperOrigin-RevId: 720555580
2025-01-28 06:44:40 -08:00
tonihei
ddcf455d03 Convert context dependent TrackSelectionParameters to boolean
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
2025-01-28 04:26:15 -08:00
shahddaghash
c058d97a97 Pass input media items audio information to MediaItemInfo
Audio `sampleMimeType`, `channelCount`, and `sampleRate` were retained from `ExportResult.ProcessedInput`'s audio format.

PiperOrigin-RevId: 720500611
2025-01-28 02:54:32 -08:00
tonihei
706c363104 Remove potentially blocking calls from DefaultTrackSelector UI thread
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
2025-01-28 02:09:28 -08:00
shahddaghash
80e6fa2aa7 Separate ProcessedInput's format into audio and video
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
2025-01-28 02:04:02 -08:00
kimvde
0b9ca1e70b Ignore 1 test in CompositionMultipleSequencePlaybackTest
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
2025-01-27 03:50:32 -08:00
dancho
80a734f4f1 AV1 bitstream parser that identifies frames with no dependencies
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
2025-01-27 03:19:36 -08:00
shahddaghash
c3962d2fe6 Collect clipped duration instead of media item's duration
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
2025-01-24 04:53:35 -08:00
dancho
227a4d76b1 AV1 Frame Header parsing
PiperOrigin-RevId: 719253811
2025-01-24 04:50:11 -08:00
ibaker
1772050ece Remove confusing null from ParserException.getMessage()
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
2025-01-24 03:55:19 -08:00
shahddaghash
382f30616a Rollback of b25d6ef249
PiperOrigin-RevId: 719238418
2025-01-24 03:46:54 -08:00
dancho
dddcdf1613 AV1 sequence header parsing
PiperOrigin-RevId: 719200478
2025-01-24 01:25:58 -08:00
ibaker
a7a5d6e92b Suppress (and log) subtitle errors in SubtitleTranscodingTrackOutput
This is equivalent to the error suppression for legacy subtitles in
`TextRenderer`:
76088cd6af/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/text/TextRenderer.java (L357-L359)

This new suppression only affects errors thrown from files with
subtitles muxed together with audio/video. Standalone subtitle
files, and containers containing only text tracks, are handled
by the existing error suppression/reporting added in
49dec5db8b.

Issue: androidx/media#2052
PiperOrigin-RevId: 718930243
2025-01-23 10:49:23 -08:00
claincly
6b54372df8 Have Sequence Player end as audio sink position is passed
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
2025-01-23 09:38:19 -08:00
Copybara-Service
c1242ffef1 Merge pull request #1235 from DolbyLaboratories:dlb/dovi-transformer/dev
PiperOrigin-RevId: 718856455
2025-01-23 07:26:21 -08:00
dancho
61b7dfd7ba Add ObuParser to split a ByteBuffer into AV1 OBUs
PiperOrigin-RevId: 718813571
2025-01-23 04:46:38 -08:00
Copybara-Service
916018d9fe Merge pull request #1936 from colinkho:eval-buf
PiperOrigin-RevId: 718809019
2025-01-23 04:27:16 -08:00
microkatz
b6d4886887 Reevaluate ongoing chunk loading when pausing 2025-01-22 16:23:55 +00:00
ibaker
9bb254f697 Skip SSA cues where end time is before or equal to start time
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
2025-01-22 07:41:24 -08:00
Colin Kho
8b0cfda178 Move queue reevaluate buffer to only execute when playWhenReady is set to false 2025-01-22 15:18:16 +00:00
Colin Kho
15bdbf735d Reevaluate buffer during a playWhenReady change 2025-01-22 15:18:16 +00:00
sheenachhabra
431efc9c50 Skip exportTranscodeBt2020Sdr test on sm-a325f API 33
The decode over reports its resolution capabilities and
decoder initialization eventually fails.

PiperOrigin-RevId: 718294047
2025-01-22 02:37:15 -08:00
kimvde
635e699965 Various improvements to BufferingVideoSink
PiperOrigin-RevId: 717807436
2025-01-21 01:54:45 -08:00
ibaker
5421a74d06 Tighten two MediaCodecRenderer fields to @MonotonicNonNull
Remove some `checkNotNull` calls that are no longer needed.

PiperOrigin-RevId: 717597046
2025-01-20 12:14:56 -08:00
sheenachhabra
7c10ef03e4 Check full format support in decoder for Transformer
For the case where a hardware decoder does not fully
support the requested format, a software decoder will
be preferred.

PiperOrigin-RevId: 717584768
2025-01-20 11:27:13 -08:00
sheenachhabra
6fe011beb4 Make Mp4Muxers and FragmentedMp4Muxers implement AutoCloseable
PiperOrigin-RevId: 717549236
2025-01-20 09:02:25 -08:00
sheenachhabra
a31c7ad9a8 Move Muxer.java interface into transformer module
Muxer interface is used only in transformer.

PiperOrigin-RevId: 717538306
2025-01-20 08:13:42 -08:00
sheenachhabra
fb58bdfd52 Refactor: Mp4Muxer and FragmentedMp4Muxer no longer implement Muxer
Mp4Muxer and FragmentedMp4Muxer has different contracts
and they can not implement same interface.

PiperOrigin-RevId: 717526288
2025-01-20 07:20:48 -08:00
sheenachhabra
c22798f99c Removing redundant call to setLastSampleDurationBehavior on muxer
The default value is already
LAST_SAMPLE_DURATION_BEHAVIOR_SET_FROM_END_OF_STREAM_BUFFER_OR_DUPLICATE_PREVIOUS

PiperOrigin-RevId: 717497116
2025-01-20 05:14:47 -08:00
kimvde
8abd36fb27 Simplify MediaCodecRenderer.maybeInitializeProcessingPipeline
PiperOrigin-RevId: 717466577
2025-01-20 03:07:59 -08:00
tonihei
190563b8eb Move StreamVolumeManager system calls to playback thread
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
2025-01-17 09:47:33 -08:00
sheenachhabra
c797249998 Move supported sample mime types list in specific muxer
This will reduce the risk of list becoming stale
(its already stale, to be fixed).

PiperOrigin-RevId: 716685242
2025-01-17 08:51:44 -08:00
claincly
a0618eb0ec Adds a test on using composition level effects
Also simplifies the test a bit.

PiperOrigin-RevId: 716683585
2025-01-17 08:46:44 -08:00
sheenachhabra
4ac4f7e2e0 Split InAppMuxer into InApp Mp4Muxer and FragmentedMp4Muxer
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
2025-01-17 08:01:28 -08:00
tonihei
a4d9a3e096 Move Wake/WifiLockManager system calls to playback thread
PiperOrigin-RevId: 716235808
2025-01-16 07:58:32 -08:00
tonihei
297b2b9956 Add util to handle background state updates and placeholder states.
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
2025-01-16 07:53:15 -08:00
Copybara-Service
fda8b8a35d Merge pull request #2023 from DolbyLaboratories:dlb/dovi-format/dev
PiperOrigin-RevId: 716226613
2025-01-16 07:26:46 -08:00
tonihei
4328d29f34 Lazily initialize current audio capabilities in DefaultAudioSink
PiperOrigin-RevId: 716224052
2025-01-16 07:17:26 -08:00
claincly
1732892927 Add tests for multi input video
PiperOrigin-RevId: 716208222
2025-01-16 06:19:47 -08:00
kimvde
b2c31b0743 Small nits in SequenceRenderersFactory
PiperOrigin-RevId: 716187537
2025-01-16 04:56:49 -08:00
claincly
0d8e42238e Stop checking all inputs ended when releasing compositor
This could happen when the player is released before ending so not all input
has ended.

PiperOrigin-RevId: 716173884
2025-01-16 04:11:21 -08:00
shahddaghash
f5f5b63bf7 Pass video data space to MediaItemInfo
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
2025-01-16 03:03:19 -08:00
simakova
22142e0db3 Add keepScreenOn flag in Composition demo
PiperOrigin-RevId: 716139653
2025-01-16 01:57:53 -08:00
Googler
492574bded Rollback of 871381288c
PiperOrigin-RevId: 715891934
2025-01-15 12:08:40 -08:00
shahddaghash
e9b82ee951 Pass video frame rate and video size to MediaItemInfo
The frame rate, height, and width are extracted from the format of processedInput.

PiperOrigin-RevId: 715843086
2025-01-15 10:09:12 -08:00
shahddaghash
04c2d22178 Pass containerMimeType and sampleMimeType to MediaItemInfo
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
2025-01-15 10:03:57 -08:00
bachinger
b49eaf9e87 Add two MetadataRenderer instances by default
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
2025-01-15 07:31:13 -08:00
dancho
0936b549ae Enable non-reference frame skipping in FrameExtractor
Speed up FrameExtractor for videos with non-ref frames

PiperOrigin-RevId: 715789816
2025-01-15 07:27:54 -08:00
kimvde
c5feb28838 Increase FrameExtractorTest timeout
FrameExtractorTest.extractFrame_pastDuration_returnsLastFrame is
sometimes timing out on emulator because it's too slow.

PiperOrigin-RevId: 715771071
2025-01-15 06:18:10 -08:00
michaelkatz
fa4cc7c65c Reduce flakiness for MediaCodecAudioRendererTests past SDK 30
PiperOrigin-RevId: 715770321
2025-01-15 06:15:26 -08:00
michaelkatz
62341f31f9 Reduce flakiness for MediaCodecVideoRendererTests past SDK 30
PiperOrigin-RevId: 715761006
2025-01-15 05:37:40 -08:00
tonihei
a2016f03c6 Remove ExoPlayer components
They have been deprecated since ExoPlayer 2.16.0 and can be easily
replaced by the exact same call in ExoPlayer directly.

PiperOrigin-RevId: 715755105
2025-01-15 05:11:09 -08:00
dancho
ee4a0ea3df Remove deprecated experimentalParseWithinGopSampleDependencies
Remove deprecated API in favor of
experimentalSetCodecsToParseWithinGopSampleDependencies.

PiperOrigin-RevId: 715731718
2025-01-15 03:43:55 -08:00
ibaker
736c7528cb Ignore EOS buffer timestamps in CeaDecoder.queueInputBuffer
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
2025-01-15 02:40:07 -08:00
Googler
2b9c7f8392 Add minimum size for OpusDecoder's streamMap.
PiperOrigin-RevId: 715453498
2025-01-14 11:17:09 -08:00
shahddaghash
465399b57e Disable default collection of platform diagnostics
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
2025-01-14 10:33:50 -08:00
sheenachhabra
1b2e391971 Change muxer instrumentation tests to robolectric
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
2025-01-14 10:09:25 -08:00
kimvde
fbf9be2f00 Fix composition player repeat mode
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
2025-01-14 09:20:14 -08:00
michaelkatz
2361624222 Make MediaCodecAudioRenderer.getDurationToProgressUs protected
This method is not intended to be exposed as 'public' as it was meant
to be internal to the class/subclasses.

PiperOrigin-RevId: 715402007
2025-01-14 09:00:37 -08:00
claincly
e9e0569425 Integrate MultiInputVideoGraph in CompositionPlayer
Currently doesn't support image/video transitions

PiperOrigin-RevId: 715393251
2025-01-14 08:33:39 -08:00
dancho
8f17ab84f8 Add API for sample dependency reading to DefaultMediaSourceFactory
PiperOrigin-RevId: 715372196
2025-01-14 07:28:03 -08:00
michaelkatz
2eb8e53f8c Fix getDurationToProgress for audio renderers to reset after seeking
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
2025-01-14 06:49:43 -08:00
tianyifeng
f05e6a7d6e Accurately determine hasPendingData after handling the end of stream
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
2025-01-14 06:37:02 -08:00
shahddaghash
adb9306e2d Add format of media item to Transformer's ExportResult.ProcessedInput
This will allow us to collect info from the Format for metrics.

PiperOrigin-RevId: 715336943
2025-01-14 05:16:08 -08:00
ibaker
eefad8cbfa Deprecate mutable static MediaParserChunkExtractor.FACTORY
Follow-up to <unknown commit>

PiperOrigin-RevId: 715329316
2025-01-14 04:46:32 -08:00
ibaker
6300a55eb2 Remove usage of mutable static BundledChunkExtractor.FACTORY
PiperOrigin-RevId: 715328246
2025-01-14 04:42:20 -08:00
dancho
1892435fb3 Parse within GOP sample dependencies in ExtractorsFactory
Add helper methods to Mp4Extractor and FragmentedMp4Extractor
to convert between VideoCodecFlags and *ExtractorFlags

PiperOrigin-RevId: 715307495
2025-01-14 03:16:49 -08:00
shahddaghash
b25d6ef249 Rollback of 72a71e8b9c
PiperOrigin-RevId: 714997645
2025-01-13 09:30:39 -08:00
ibaker
a4d28b4f10 Add PGS test file
Transformed from `sample_with_srt.mkv` and provided in
https://github.com/androidx/media/pull/1979#issuecomment-2574007148

PiperOrigin-RevId: 714955725
2025-01-13 07:14:13 -08:00
jbibik
52387bb975 [ui-compose] Rename showSurface to coverSurface in PresentationState
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
2025-01-13 06:59:44 -08:00
Copybara-Service
d18ad57e30 Merge pull request #1979 from wischnow:main
PiperOrigin-RevId: 714911017
2025-01-13 04:09:58 -08:00
dancho
8b33a0a50f Add a ChunkExtractor API to select codecs for sample dependency parsing
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
2025-01-13 03:30:10 -08:00
andrewlewis
0a27e7946f When reregistering frames automatically, drop after signaling EOS
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
2025-01-13 00:43:45 -08:00
kimvde
b183bfb0cb CompositionPlayerTest: use correct video duration
PiperOrigin-RevId: 714847208
2025-01-13 00:01:42 -08:00
sheenachhabra
36be62ee8c Skip duplicate chunks in stsc box writing
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
2025-01-10 13:27:02 -08:00
jbibik
28027c64fd [ui-compose] Add aspect ratio to PresentationState
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
2025-01-10 10:50:53 -08:00
sheenachhabra
33c3d5140e Rollback of 750baf2c05
PiperOrigin-RevId: 714097260
2025-01-10 10:34:56 -08:00
dancho
93f9e6574c Add missing Mp4Extractor.Flags to IntDef
PiperOrigin-RevId: 714084405
2025-01-10 09:54:19 -08:00
ibaker
e61b521b4a Clear SEI reordering queue when seeking in MPEG-TS files
This avoids outputting spurious samples after the seek.

PiperOrigin-RevId: 714082343
2025-01-10 09:45:21 -08:00
Ian Baker
6291cfda86 Fix dump file to match @GraphicsMode(NATIVE) 2025-01-10 17:35:56 +00:00
Ian Baker
77790df5a2 Plumb palette through as a method parameter to satisfy nullness checker 2025-01-10 17:17:28 +00:00
shahddaghash
30c5c66db4 Pass input MediaItemInfo list with duration
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
2025-01-10 08:11:45 -08:00
Googler
d9b61b060f Disable sample rate fallback tests.
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
2025-01-10 08:08:57 -08:00
Ian Baker
4744f082af Add release note 2025-01-10 16:04:04 +00:00
Ian Baker
b2f9c1e252 Reformat with google-java-format 2025-01-10 16:02:24 +00:00
Ian Baker
ce0512845f Fix lint/style issues, and log exception 2025-01-10 16:02:24 +00:00
Ian Baker
6658dc097b Rename new fixed test file to old name, and add output dump 2025-01-10 16:02:24 +00:00
Sven Wischnowsky
90c91fa5d7 Fixed subtitle track length. 2025-01-10 16:02:24 +00:00
Sven Wischnowsky
47a5166a1d Small fix for an off-by-two error. 2025-01-10 16:02:24 +00:00
Ian Baker
671810235f Assorted nullness and control flow clean-ups 2025-01-10 16:02:24 +00:00
Ian Baker
8520c66fd8 Add some nullness annotations, re-jig some logic and reformat 2025-01-10 16:02:24 +00:00
Sven Wischnowsky
391b72e257 Various cleanup and improvements as suggested by mainainer. 2025-01-10 16:02:24 +00:00
Sven Wischnowsky
f52d98eafd Use Util.maybeInflate() 2025-01-10 16:02:24 +00:00
Sven Wischnowsky
3cd0e1ad3d Add maybeInflate() which inflates only if the source buffer starts with the INFLATE_HEADER 2025-01-10 16:02:24 +00:00
Sven Wischnowsky
0254b2d16e Add Vobsub sample file 2025-01-10 16:02:24 +00:00
Sven Wischnowsky
250bc86669 Add comments about needing the size in the IDX file. 2025-01-10 16:02:24 +00:00
Sven Wischnowsky
27a6883768 Another small fix 2025-01-10 16:02:24 +00:00
Sven Wischnowsky
7fbf511d30 Small fix 2025-01-10 16:02:23 +00:00
Sven Wischnowsky
721776c30e Support for Vobsub subtitles 2025-01-10 16:02:23 +00:00
dancho
c26a633d83 Read sample dependencies for H.265 in FragmentedMp4
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
2025-01-10 07:39:37 -08:00
tonihei
71cb246913 Fix bug where changing index does not reevaluate derived metadata
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
2025-01-10 05:59:45 -08:00
tonihei
c3b13a60a3 Mark internal BasePlayer.seekTo method as @ForOverride
This method is not meant to be called directly, it only needs to
be implemented by subclasses.

PiperOrigin-RevId: 714000806
2025-01-10 04:32:32 -08:00
shahddaghash
72a71e8b9c Report exporter and muxer names metrics to EditingEndedEvent
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
2025-01-10 04:29:25 -08:00
tonihei
f6eb2e6dd5 Fix discontinuity reporting in ClippingMediaPeriod
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
2025-01-10 04:04:03 -08:00
ibaker
d0b757886e Fix handling of length-delimited NAL units with 1 or 2 byte length
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
2025-01-09 10:06:13 -08:00
shahddaghash
64462b99fc Add mediaItem durationUs to Transformer's ExportResult.ProcessedInput
This will allow us to access the duration of the input media items and collect them for metrics.

PiperOrigin-RevId: 713686613
2025-01-09 08:51:00 -08:00
tonihei
b225383958 Don't force discontinuity when clipping a merged source duration
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
2025-01-09 08:47:33 -08:00
kimvde
2df50f209e CompositionPlayerTest: increase timeout for emulator tests
Some tests are sometimes timing out because the emulator is too slow.

PiperOrigin-RevId: 713671851
2025-01-09 07:56:55 -08:00
dancho
cd511ea60b Add a test file for FragmentedMp4 captions
The previous FragmentedMp4 captions test asset doesn't have captions.
Fix a bug where captions before extractor seek were output after.

PiperOrigin-RevId: 713665817
2025-01-09 07:35:21 -08:00
tonihei
b9d12837b4 Use live providers in CompositionPlayer to remove workaround
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
2025-01-09 07:10:14 -08:00
tonihei
9608ae4e3d Add LivePositionSupplier util to SimpleBasePlayer
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
2025-01-09 07:05:21 -08:00
Googler
8a709a7d76 Remove setPendingVideoEffects from VideoSink.
VideoSink#onInputStreamChanged(int, Format, List<Effect>) should now be used to set video effects on a new input stream.

PiperOrigin-RevId: 713627389
2025-01-09 04:48:21 -08:00
andrewlewis
e1b57c130d Make auto frame registration test non-flaky
Wait for each frame to be rendered before unblocking queueing the next one.

PiperOrigin-RevId: 713621811
2025-01-09 04:21:39 -08:00
michaelkatz
0e6d39de29 Add DefaultRenderersFactory api for experimental MCVR prewarming
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
2025-01-09 03:08:41 -08:00
kimvde
04ff17d939 CompositionPlayerSeekTest: skip some tests on API 31 emulator
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
2025-01-09 00:24:31 -08:00
jbibik
709d3fd35e [demo-compose] Refactor modifier with better Kotlin syntax
PiperOrigin-RevId: 713476190
2025-01-09 00:22:17 -08:00
michaelkatz
314413365b Implement transfer of resources API for renderer pre-warming
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
2025-01-08 12:12:48 -08:00
tonihei
7d4ddfbb91 Don't force discontinuities for server-side ad insertion transitions
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
2025-01-08 09:23:13 -08:00
kimvde
d9776e74c8 PlayerListener: do not swallow exceptions thrown before waiting
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
2025-01-08 08:03:46 -08:00
tonihei
b321c8d3bd Discard already written sample data for clipped DASH periods
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
2025-01-08 07:47:54 -08:00
kimvde
bb3b85a359 CompositionPlayerSeekTest: don't hide exception while waiting on latch
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
2025-01-08 07:10:09 -08:00
kimvde
30038079c4 Split CompositionPlayerSeekTest.playSequenceAndGetTimestampsUs
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
2025-01-08 06:18:48 -08:00
jbibik
79d41aac7e [ui-compose] Fix PlayerSurface's use of Player
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
2025-01-08 06:07:14 -08:00
kimvde
48e3eaa623 CompositionPlayerSeekTest: increase test timeout for emulators
Some tests are sometimes timing out because the emulator is too slow.

PiperOrigin-RevId: 713259939
2025-01-08 05:48:18 -08:00
kimvde
3a00960831 Remove stale Javadoc
PiperOrigin-RevId: 713253227
2025-01-08 05:16:01 -08:00
dancho
0cf52ed45d Read sample dependencies for H.265 in MP4
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
2025-01-08 04:55:31 -08:00
dancho
b54d8737cf Add number of temporal layers to Format
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
2025-01-08 04:50:45 -08:00
dancho
281a0e7ac8 Populate HevcConfig with number of temporal layers
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
2025-01-08 04:31:24 -08:00
dancho
b3e18729d3 H.265 parse number of temporal layers from SPS
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
2025-01-08 03:48:24 -08:00
shahddaghash
1bea11637b Add setting final progress at export error or cancellation
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
2025-01-08 03:24:18 -08:00
ybai001
d16d80ca49 Update Dolby Vision format handling
* Add the missing DV profile 10 handling
* Set DV codec string instead of compatible format codec string in MP4 extractor
2025-01-08 10:40:03 +08:00
ybai001
39c35b779b
Merge pull request #16 from androidx/main
Merge from androidx/media main branch
2025-01-08 09:52:29 +08:00
shahddaghash
d894217a4e Fix typo for precreateEditingEndedEventBuilder method
PiperOrigin-RevId: 712969879
2025-01-07 10:56:15 -08:00
sheenachhabra
bcae7abde9 Remove TrackToken and replace with int trackId
This is to make API simpler and to have parity with `MediaMuxer`

PiperOrigin-RevId: 712954669
2025-01-07 10:16:31 -08:00
shahddaghash
8dca430e42 Add setting final progress when export success for metrics
Set the progress to 100% for a successful export operation.

PiperOrigin-RevId: 712946218
2025-01-07 09:52:43 -08:00
shahddaghash
6f187a3859 Add confetti overlay to Effect demo
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
2025-01-07 09:33:36 -08:00
dancho
229aadc91b Update javadoc for FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES
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
2025-01-07 08:33:14 -08:00
bachinger
ec50358784 Do not override pending info when masking
PiperOrigin-RevId: 712919739
2025-01-07 08:26:19 -08:00
andrewlewis
e11aabb794 Allow RawAssetLoader media to have unset duration
This will be useful for recording use cases, including screen recording with
audio queued via `RawAssetLoader`, where the duration is unknown.

PiperOrigin-RevId: 712895577
2025-01-07 06:59:21 -08:00
ivanbuper
871381288c Use static methods for getSpeedAdjustedTimeAsync and getMediaDurationUs
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
2025-01-07 06:49:49 -08:00
jbibik
2dc6af1fae [ui-compose] Add PresentationState for first-frame info
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
2025-01-07 06:34:02 -08:00
ibaker
31e5142b72 Restrict SubRip and WebVTT parsing to exactly 3 decimal places
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
2025-01-07 06:13:15 -08:00
andrewlewis
9ac91aaadd Return concrete SurfaceAssetLoader from factory
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
2025-01-07 06:02:24 -08:00
Copybara-Service
38363acc8d Merge pull request #1785 from DolbyLaboratories:dlb/dovi-supplemental-codecs/dev
PiperOrigin-RevId: 712867412
2025-01-07 04:58:21 -08:00
tonihei
a9f9928eb3 Temporarily remove test class to avoid build breakage
PiperOrigin-RevId: 712862960
2025-01-07 04:40:28 -08:00
andrewlewis
5a87aab2f7 Use Util to request permissions in Transformer demo
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
2025-01-07 04:13:36 -08:00
shahddaghash
0074a97333 Remove unnecessary released condition in getProgress
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
2025-01-07 03:53:06 -08:00
andrewlewis
0044d0cebc Fix GLES31 javadoc reference to be unambiguous and link correctly
PiperOrigin-RevId: 712848161
2025-01-07 03:35:30 -08:00
Googler
b2aa8d6d21 Add sample rate fallback to AudioSampleExporter
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
2025-01-07 01:52:57 -08:00
Googler
6c2d25184c Make FragmentedMp4Muxer use OutputStream instead of FileOutputStream.
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
2025-01-06 10:46:00 -08:00
jbibik
575a2ebbd8 [ui-compose] Add gradle version to androidx.compose.foundation
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
2025-01-06 09:34:44 -08:00
Copybara-Service
8fe0b7ac69 Merge pull request #1987 from ojoNetgem:Support_for_origin_and_extent_declared_in_ttml_styles
PiperOrigin-RevId: 712554507
2025-01-06 09:30:15 -08:00
jbibik
ff80ab220f [demo-compose] Add Activity lifecycle methods
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
2025-01-06 08:49:41 -08:00
Ian Baker
8d9cb7e5d0 Resolve some TODO comments that are now fixed by the new parsing support 2025-01-06 15:13:32 +00:00
Ian Baker
618c2cf952 Add a release note and format with google-java-format 2025-01-06 15:13:32 +00:00
Olivier Jouvenaux
82bed39140 Add unit tests for TTML region attrs in style, chained styles UT 2025-01-06 15:13:32 +00:00
Olivier Jouvenaux
026700a9d9 Add unit tests for region attrs in style 2025-01-06 15:13:32 +00:00
Olivier Jouvenaux
fbd6dfa439 Add support for TTML origin and extent attributes defined in style instead of region 2025-01-06 15:13:32 +00:00
jbibik
d8333b37cf Upgrade compose bom to 2024.12.01
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
2025-01-06 06:05:30 -08:00
jbibik
d01d10ce0e [demo-compose] Refactor MediaPlayerScreen() into ComposeDemoApp()
PiperOrigin-RevId: 712495147
2025-01-06 05:33:32 -08:00
Copybara-Service
871c15946b Merge pull request #1947 from totallyunknown:fix/dash-playlist-infinite-loop
PiperOrigin-RevId: 712494399
2025-01-06 05:28:26 -08:00
shahddaghash
115f09dd6d Report ErrorCode and elapsed time metrics for Transformer
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
2025-01-06 03:55:32 -08:00
sheenachhabra
750baf2c05 Rollback of 9cc4532f84
PiperOrigin-RevId: 711804077
2025-01-03 11:18:03 -08:00
ivanbuper
7ecaebe3d6 Fix underflow in Sonic#getOutputSize() after #queueEndOfStream()
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
2025-01-03 09:26:32 -08:00
shahddaghash
cd5d5bde27 Implement basic Metrics Collector in Transformer
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
2025-01-03 05:27:20 -08:00
dancho
9b71f2a3ba Mp4Extractor: allow zero length NAL units
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
2025-01-03 05:21:10 -08:00
ivanbuper
682889f91d Implement Sonic method to get input frame count from output frame count
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
2025-01-02 09:36:12 -08:00
sheenachhabra
01c51d8475 Allow dolby vision transcode test to use alternative output mime type
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
2025-01-02 04:15:27 -08:00
sheenachhabra
9cc4532f84 Use same decoder selection logic is test as in DefaultDecoderFactory
The decoder selection logic in DefaultDecoderFactory is more mature
and can find alternative decoders.

PiperOrigin-RevId: 711378121
2025-01-02 03:49:52 -08:00
sheenachhabra
969c50d60f Fix HDR editing support check in dolby vision test
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
2025-01-02 03:00:08 -08:00
Googler
2caa0d39eb Mp4Extractor: Update APV clip
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
2025-01-01 22:34:31 -08:00
ivanbuper
48e3c6fd75 Rollback of f60d2b4146
PiperOrigin-RevId: 710998501
2024-12-31 10:26:16 -08:00
ivanbuper
d6e4642bcf Rollback of 5ab9a7856f
PiperOrigin-RevId: 710770581
2024-12-30 12:24:05 -08:00
jbibik
afd601f670 Refactor non-ripple Modifier into a separate file
Modifiers.kt will be a place for other extensions on Modifier class

PiperOrigin-RevId: 709416429
2024-12-24 15:27:21 -08:00
jbibik
6da58758a8 Add vertical videos to demo-compose
Useful for future testing of aspect ratio functionality.

PiperOrigin-RevId: 709354104
2024-12-24 08:47:42 -08:00
rohks
3b9737f88a Fix release notes based on Devsite linter warnings
PiperOrigin-RevId: 709329498
2024-12-24 06:17:43 -08:00
sheenachhabra
16617f5a8b Improve javadoc in Mp4LocationData and Mp4OrientationData class
PiperOrigin-RevId: 709061777
2024-12-23 07:57:58 -08:00
claincly
515de89973 Support MediaCodec tonemapping in CompositionPlayer
PiperOrigin-RevId: 708995517
2024-12-23 02:06:08 -08:00
sheenachhabra
f22d91d9e5 Clarify the stream closing responsibility in muxer
PiperOrigin-RevId: 708359779
2024-12-20 10:24:48 -08:00
claincly
8188f7a865 Repect Composition's HDR mode setting using OpenGL
Subsequent CLs will add support for other HDR modes

PiperOrigin-RevId: 708340216
2024-12-20 09:11:00 -08:00
rohks
5c40498054 Fix quotes around parameter name in release notes
PiperOrigin-RevId: 708334464
2024-12-20 08:47:17 -08:00
sheenachhabra
1b0e2fb75e Rename "setSampleCopyEnabled" to "setSampleCopyingEnabled" in muxer
PiperOrigin-RevId: 708322440
2024-12-20 07:57:59 -08:00
sheenachhabra
684c394019 Fix java doc of setSampleBatchingEnabled method
PiperOrigin-RevId: 708310532
2024-12-20 06:58:54 -08:00
Googler
f06bfc2e15 Log errors in BaseGlShaderProgram and QueueingGlShaderProgram.
PiperOrigin-RevId: 708297631
2024-12-20 05:59:18 -08:00
Googler
c12b1768a6 Add sample rate fallback to DefaultEncoderFactory
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
2024-12-20 05:50:25 -08:00
rohks
5c3c3b91f3 Remove publishing for media3-ui-compose temporarily
This is due to a missing version error for the `androidx.compose.foundation` dependency.

PiperOrigin-RevId: 707944220
2024-12-19 09:54:59 -08:00
shahddaghash
915130eb00 Add usePlatformDiagnostics in Transformer.
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
2024-12-19 09:03:19 -08:00
tonihei
cb578c0f37 Additional comments and limit update interval to manifest value 2024-12-19 16:20:44 +00:00
Nils Juenemann
5da67a0033 fix: prevent infinite loop causing stream freeze in DASH multi-period streams
- 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.
2024-12-19 16:18:55 +00:00
ibaker
59789b7209 Fix typo in 1.6.0-alpha01 release notes
#cherrypick

PiperOrigin-RevId: 707907431
2024-12-19 07:31:52 -08:00
rohks
506bc91dd8 Bump Media3 version to 1.6.0-alpha01
PiperOrigin-RevId: 707896534
2024-12-19 06:45:57 -08:00
rohks
9d610894cf Update release notes for Media3 1.6.0-alpha01 release
PiperOrigin-RevId: 707880171
2024-12-19 05:30:04 -08:00
ybai001
1ac847ad60 Update code according to review result 2024-12-19 16:28:33 +08:00
rohks
ca58867816 Hard-code channel count and sample rate for AMR-NB and AMR-WB
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
2024-12-18 11:03:26 -08:00
sheenachhabra
44aa87c832 Extract MuxerException into a separate file
This is to avoid very long name as the FQN earlier
contained muxer 3 times

PiperOrigin-RevId: 707591813
2024-12-18 10:21:51 -08:00
shahddaghash
c3b58f2434 Bump Media3 version to 1.5.1
PiperOrigin-RevId: 707576152
2024-12-18 09:29:43 -08:00
shahddaghash
76088cd6af Bump Media3 version to 1.5.1
PiperOrigin-RevId: 707576152
(cherry picked from commit c3b58f2434b6552498feb6879643ea624676a13a)
2024-12-18 09:26:54 -08:00
shahddaghash
7ae9ddf166 Update release notes for Media3 1.5.1 release
PiperOrigin-RevId: 707558817
(cherry picked from commit 896bd0d330a576d1e76ff39175a754052c2dc92a)
2024-12-19 11:21:58 +00:00
shahddaghash
896bd0d330 Update release notes for Media3 1.5.1 release
PiperOrigin-RevId: 707558817
2024-12-18 08:25:16 -08:00
Copybara-Service
2f507650cc Merge pull request #1871 from colinkho:cmc
PiperOrigin-RevId: 707528211
2024-12-18 06:32:41 -08:00
Googler
2d37823695 Add VP9 Mp4 clip to Mp4MuxerEndToEndParameterizedAndroidTest
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
2024-12-18 05:16:55 -08:00
tonihei
1c044c98ad Formatting fixes 2024-12-18 12:58:32 +00:00
siroberts
16dcf91c1c Reduce log severity to info for unhandled media buttons
PiperOrigin-RevId: 707485315
2024-12-18 03:47:58 -08:00
Googler
6d2331fd13 Add ApvC codec support to Mp4Muxer.
PiperOrigin-RevId: 707482517
2024-12-18 03:38:20 -08:00
Googler
9b628d4542 Update Muxer Test with MediaExtractorCompact
Replace Platform extractor with MediaExtractorCompact in AndroidMuxerTestUtils.

PiperOrigin-RevId: 707469755
2024-12-18 02:50:11 -08:00
bachinger
d4f4a2c1d4 Allow the number of ad groups to grow with AdsMediaSource
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
2024-12-17 14:10:27 -08:00
bachinger
aa2ee8f702 Add client side post roll placeholder
PiperOrigin-RevId: 707142019
2024-12-17 09:59:16 -08:00
ibaker
32ab258c43 Use Build.MANUFACTURER instead of Util alias in AudioCapabilities
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
2024-12-17 09:10:40 -08:00
bachinger
3dede2415d Add AdsMediaSourceFactory for HLS interstitials
PiperOrigin-RevId: 707109323
2024-12-17 08:25:58 -08:00
shahddaghash
acc41cb5f7 Add contrast effect to effect demo
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
2024-12-17 07:33:52 -08:00
Colin Kho
6287a22285 Added getter methods to ContainerMediaChunk & a callback method whenever a load loop is finished 2024-12-17 15:29:59 +00:00
tonihei
2d11a339de Import AudioManagerCompat and AudioFocusRequest from androidx.media
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
2024-12-17 06:14:36 -08:00
rohks
4b26eb2800 Fix lint errors
- Add required mutability flag to `ConnectionStateTest` to fix
  `Missing PendingIntent mutability flag`.
- Suppress `WrongConstant` lint error caused by Kotlin's spread operator
  not propagating the `@IntDef` annotation.

#cherrypick

PiperOrigin-RevId: 707061163
2024-12-17 05:53:19 -08:00
ibaker
601b025b3c Clarify the base of releaseTimeNs in VideoFrameMetadataListener
Also remove docs about API < 21, since the `minSdk` for the library is
now 21.

PiperOrigin-RevId: 707038503
2024-12-17 04:20:44 -08:00
tonihei
71f82df57f Switch default of async crypto mode to disabled
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
2024-12-17 03:25:32 -08:00
tonihei
e4e59cd929 Switch default of async crypto mode to disabled
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
PiperOrigin-RevId: 707025950
(cherry picked from commit 71f82df57f53c69fe34417bbde64847049e27894)
2024-12-17 03:22:51 -08:00
bachinger
12566a50d5 Reorder IMA samples for easier QA testing
PiperOrigin-RevId: 707014618
2024-12-17 02:33:21 -08:00
bachinger
3fe1f2a734 Add adId to AdGroup
PiperOrigin-RevId: 706761644
2024-12-16 10:47:17 -08:00
michaelkatz
d5d85558c1 Skip just-early video frames only if directed to release the frame
`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
2024-12-16 08:05:30 -08:00
sheenachhabra
319ac2e5af Remove Parcelable interface from Metadata and Metadata.Entry
`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
2024-12-16 05:58:02 -08:00
sheenachhabra
1326a92350 Do not bundle metadata when creating Format bundle
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
2024-12-13 10:12:37 -08:00
ibaker
36466cf883 Add some session methods to the stable API
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
2024-12-13 10:03:46 -08:00
dancho
72672b7f87 Implement audioNeedsEncoding based on requested settings
Do not use ForceEncodeFactory in tests

PiperOrigin-RevId: 705835243
2024-12-13 04:23:35 -08:00
bachinger
07b658a6da Ignore invalid interstitials instead of throwing
The HLS spec says so in rfc8216bis (4.4.5.1)

PiperOrigin-RevId: 705829265
2024-12-13 03:58:55 -08:00
dancho
522883bf16 Less granular skipping for HE-AAC support
PiperOrigin-RevId: 705822449
2024-12-13 03:28:51 -08:00
tonihei
3bce3af1a3 Switch play FGS exemption to use custom action instead of commands
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
2024-12-13 01:43:21 -08:00
tonihei
508a4258a3 Switch play FGS exemption to use custom action instead of commands
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
(cherry picked from commit 3bce3af1a39540bd41823b2eaa7e642a668ed34c)
2024-12-13 01:41:20 -08:00
bachinger
83b5eb0040 Add HlsInterstitialsAdsLoader
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
2024-12-12 13:04:10 -08:00
jbibik
e0496ff88d [demo-compose] Initialize the Player outside of Compose
PiperOrigin-RevId: 705533932
2024-12-12 09:39:50 -08:00
jbibik
beda44520a [ui-compose] Fix PlayerSurface's use of Player
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
2024-12-12 09:22:40 -08:00
tonihei
684273e4e1 Add utilities to resolve button preferences to display constraints
PiperOrigin-RevId: 705491402
2024-12-12 07:08:43 -08:00
kimvde
c636d9181b Delete ExoPlayerEffectPlaybackSeekTest
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
2024-12-12 07:05:34 -08:00
jbibik
77a215f39c [ui-compose] Check Player commands in PlayerSurface actions
Setting and destroying the Surface should only happen if the `Player` has the required command

PiperOrigin-RevId: 705488781
2024-12-12 06:57:47 -08:00
rohks
4997ea82fa Refactor CmcdData to handle object type determination internally
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
2024-12-12 04:36:16 -08:00
ibaker
0b0c198f59 Publish some internal tests now we depend on Robolectric 4.14.1
PiperOrigin-RevId: 705411400
2024-12-12 01:28:26 -08:00
sheenachhabra
f587ac2a67 Remove bundle-serialization methods from ExoPlaybackException
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
2024-12-11 11:06:01 -08:00
Googler
3936c27b6d Don't check codec's profile for MV-HEVC video.
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
2024-12-11 10:59:26 -08:00
Googler
52f9761796 Don't check codec's profile for MV-HEVC video.
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
(cherry picked from commit 3936c27b6d0fd5e5795beab029c0216613e3f0ba)
2024-12-11 10:56:06 -08:00
rohks
de31a3745c Make some no-op refactoring in CmcdData
- 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
2024-12-11 10:46:22 -08:00
Copybara-Service
893b3775d4 Merge pull request #1963 from khouzam:codecInitialize
PiperOrigin-RevId: 705123773
2024-12-11 08:56:52 -08:00
Copybara-Service
c222bb8e03 Merge pull request #1968 from colinkho:opus
PiperOrigin-RevId: 705106170
2024-12-11 07:55:46 -08:00
andrewlewis
da05a1a66b Fix handling of CBR audio in some AVI files
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
2024-12-11 07:43:57 -08:00
microkatz
2f880bf051 Added release note 2024-12-11 15:31:00 +00:00
microkatz
55d9626b5a Format with google-java-format 2024-12-11 14:56:25 +00:00
Gilles Khouzam
f149cb28a3 Add MediaCodecInfo to MediaCodecRenderer::onReadyToInitializeCodec 2024-12-11 14:56:25 +00:00
Rohit Singh
b2e8489119 Removed empty line 2024-12-11 14:47:04 +00:00
kimvde
424b43d2eb Fix CompositionPlayerSeekTest timeout
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
2024-12-11 06:39:49 -08:00
dancho
f55e0f3a3f VideoFrameProcessorTestRunner add support for portrait video
Fixes test failures due to differences test util bug that introduced
a crop in external texture sampling

PiperOrigin-RevId: 705061267
2024-12-11 04:45:12 -08:00
Colin Kho
af32e859ed Remove ChannelCount Max Limitation on OpusDecoder 2024-12-11 16:03:42 +08:00
rohks
8d2f531470 Enable sending CmcdData for manifest requests in DASH, HLS and SS
Issue: androidx/media#1951
PiperOrigin-RevId: 704875765
2024-12-10 15:59:39 -08:00
ibaker
c377a34a5a Don't call onAudioPositionAdvancing if AudioTrack is paused
`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
2024-12-10 10:31:46 -08:00
tonihei
3e3cd8e6ac Fix Javadoc reference link for VORBIS mapping
PiperOrigin-RevId: 704737734
2024-12-10 09:27:36 -08:00
tonihei
b34a5b4e5d Align logic to ignore disabled and non-custom buttons in custom layout
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
2024-12-10 06:13:54 -08:00
shahddaghash
dc21f3add2 Add preset input picker functionality
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
2024-12-10 02:51:06 -08:00
michaelkatz
6689fee2b2 Implement error handling support for pre-warming renderers
PiperOrigin-RevId: 704408379
2024-12-09 14:04:00 -08:00
michaelkatz
be63e156bb Implement mediasource list update support for pre-warming renderers
PiperOrigin-RevId: 704381778
2024-12-09 12:41:37 -08:00
michaelkatz
bb62278627 Implement track reselection support for pre-warming renderers
PiperOrigin-RevId: 704371028
2024-12-09 12:07:58 -08:00
ibaker
ef19740c92 Remove Forwarding from assertForwardingClassOverridesAllMethods
And use it in a "non-forwarding" context in
`DefaultAnalyticsCollectorTest`.

PiperOrigin-RevId: 704331859
2024-12-09 10:22:06 -08:00
sheenachhabra
e017213ee8 Fix some MP4-AT file format related naming
Also add spec link in the code.

PiperOrigin-RevId: 704329143
2024-12-09 10:14:34 -08:00
michaelkatz
459162c692 Implement seeking support for pre-warming renderer feature
PiperOrigin-RevId: 704328162
2024-12-09 10:12:11 -08:00
michaelkatz
987869e456 Implement secondary renderer feature for pre-warming
`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
2024-12-09 10:07:33 -08:00
andrewlewis
fc3f096888 Fix handling of 'no chunk readers' in AVI
Before this change the chunk readers array was accessed out of bounds in files
for which no chunk readers are created.

PiperOrigin-RevId: 704323919
2024-12-09 10:01:13 -08:00
andrewlewis
1f6c795407 Read init data for AAC (and not other formats) in AVI files
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
2024-12-09 09:15:29 -08:00
ibaker
12546070ee Add vorbis comment support for track/disc numbering fields, and genre
Only `TRACKNUMBER` and `GENRE` are listed here:
https://xiph.org/vorbis/doc/v-comment.html

The rest are derived from the example in Issue: androidx/media#1958.

It's possible that other formats exist in the wild:
https://hydrogenaud.io/index.php/topic,69292.msg613808.html#msg613808

Issue: androidx/media#1958
PiperOrigin-RevId: 704308788
2024-12-09 09:12:57 -08:00
ibaker
de91ebc6ae Add vorbis comment support for track/disc numbering fields, and genre
Only `TRACKNUMBER` and `GENRE` are listed here:
https://xiph.org/vorbis/doc/v-comment.html

The rest are derived from the example in Issue: androidx/media#1958.

It's possible that other formats exist in the wild:
https://hydrogenaud.io/index.php/topic,69292.msg613808.html#msg613808

Issue: androidx/media#1958
PiperOrigin-RevId: 704308788
(cherry picked from commit 12546070ee6bb8b41dc7c54714592f330d8794ba)
2024-12-09 09:09:53 -08:00
andrewlewis
aa0e7298ca Make some no-op fixes to AVI extraction code
PiperOrigin-RevId: 704292203
2024-12-09 08:16:54 -08:00
ibaker
38d12f25e1 Consistently ignore non-fatal errors in subtitle loading error tests
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
2024-12-09 03:39:57 -08:00
kimvde
1a7da45dd9 Add a TestTransformerBuilder
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
2024-12-09 01:06:51 -08:00
sheenachhabra
0a75447785 Rename terminologies as per the MP4-AT spec
https://developer.android.com/media/platform/mp4-at-file-format

PiperOrigin-RevId: 703531148
2024-12-06 09:58:11 -08:00
dancho
1d2ffcb165 Frame extraction support changing MediaItem
Add FrameExtraction.setMediaItem() method
Prefer non-vendor software codecs by default because
vendor codecs sometimes fail when we attempt reuse.

PiperOrigin-RevId: 703486235
2024-12-06 06:57:21 -08:00
rohks
b816e2f284 Add E2E test for DASH stream with CMCD enabled and init segment
The test complements the existing E2E test for HLS in `HlsPlaybackTest` by verifying similar functionality for DASH in `DashPlaybackTest`.

PiperOrigin-RevId: 703454388
2024-12-06 04:39:14 -08:00
jbibik
038d7c8cb9 Remove kotlin-android plugin from main demo
This fixes the problem with `compileDebugKotlin` gradle task and `Unknown Kotlin JVM target: 21`.

PiperOrigin-RevId: 703427496
2024-12-06 02:46:21 -08:00
shahddaghash
862791f837 Fixes after removing deprecated methods from Transformer.Builder
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
2024-12-05 05:14:59 -08:00
shahddaghash
b6724e2115 Load preset input from JSON file in EffectActivity
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
2024-12-05 04:46:47 -08:00
kimvde
f1a0e4b0b7 Fix timeouts in CompositionPlaybackTest
Some of the tests were timing out because the emulator was too slow.

PiperOrigin-RevId: 703056616
2024-12-05 03:54:49 -08:00
ibaker
b5a1efdbce ForwardingTimeline: Implement & finalize some methods
`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
2024-12-05 02:24:19 -08:00
ibaker
92e0b5978f Add ForwardingTimelineTest
PiperOrigin-RevId: 703029260
2024-12-05 01:59:07 -08:00
Googler
5ab9a7856f Rollback of 646a6352a2
PiperOrigin-RevId: 702960045
2024-12-04 20:36:15 -08:00
Googler
f60d2b4146 Rollback of 66e8b53b43
PiperOrigin-RevId: 702943864
2024-12-04 19:22:54 -08:00
dancho
6193f7c38f Generate static HDR metadata when using DefaultEncoderFactory
* 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
2024-12-04 09:31:13 -08:00
ibaker
3e94bd6125 Enable lint errors in tests for remaining playback modules
Also fix existing violations

This enables the lint for tests in:
* `decoder-iamf`
* `exoplayer-rtsp`
* `test-exoplayer-playback`
* `test-session-current`
* `ui-compose`

PiperOrigin-RevId: 702728438
2024-12-04 08:08:01 -08:00
rohks
fb2d5f905d Fix typo in Javadoc for constructor in SsMediaSource.Factory
PiperOrigin-RevId: 702718127
2024-12-04 07:31:54 -08:00
rohks
e927d7b986 Fix ReplacingCuesResolver.discardCuesBeforeTimeUs to retain active cue
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
2024-12-04 06:51:12 -08:00
rohks
5d9badcb50 Fix ReplacingCuesResolver.discardCuesBeforeTimeUs to retain active cue
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

PiperOrigin-RevId: 702707611
(cherry picked from commit e927d7b986229a89a43d749a0b51cb9d53722d26)
2024-12-04 06:48:43 -08:00
kimvde
06b94f5448 DefaultVideoSink: implement handleInputFrame() and listeners
With this CL, PlaybackVideoGraphWrapper doesn't call the
VideoFrameRenderControl directly anymore (which is one of the goals of
DefaultVideoSink).

PiperOrigin-RevId: 702673821
2024-12-04 04:29:03 -08:00
ibaker
c770a6ab6f Enable lint errors in database tests
Also fix existing violations.

PiperOrigin-RevId: 702665065
2024-12-04 03:55:33 -08:00
tonihei
46ab6cf030 Fix wrong copy-pasted comment
PiperOrigin-RevId: 702647886
2024-12-04 02:38:11 -08:00
Googler
bffa253e3a Add initialization data for VP9 and AV1 codec in MatroskaExtractor
Update `MatroskaExtractor` to populate the CSD information for VP9 and AV1 codecs with their codec private data.

For reference: [CodecPrivate for VP9](https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate), [CSD for AV1](https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox-syntax).

PiperOrigin-RevId: 702631838
2024-12-04 01:39:41 -08:00
ibaker
9828d104b5 Improve reflective instantiation in ForwardingFoo test util
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
2024-12-03 10:10:39 -08:00
ibaker
593899c2b2 Enable lint errors in datasource tests
Fix existing violations

PiperOrigin-RevId: 702377837
2024-12-03 10:07:19 -08:00
ibaker
c870fb7594 Enable lint errors in extractor tests
Fix existing violations.

PiperOrigin-RevId: 702366292
2024-12-03 09:29:30 -08:00
ibaker
876abe315b Increase library target SDK to 31
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
2024-12-03 08:57:53 -08:00
tianyifeng
148641f049 Move BasePreloadManager.Listener to a top level PreloadManagerListener
PiperOrigin-RevId: 702351887
2024-12-03 08:38:35 -08:00
ibaker
d72453a6cd Use ForwardingTrackOutput in MidiExtractor
PiperOrigin-RevId: 702328995
2024-12-03 07:14:58 -08:00
Copybara-Service
9a3dc3f03a Merge pull request #1889 from yschimke:fix_build
PiperOrigin-RevId: 702323944
2024-12-03 06:56:53 -08:00
Yuri Schimke
10ca39a779 Specify androidx.activity:activity-compose as 1.9.0
The Compose BOM doesn't provide this.
https://developer.android.com/develop/ui/compose/bom/bom-mapping
2024-12-03 14:39:08 +00:00
dancho
e8f60d4fec Remove earlier frame extraction prototypes
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
2024-12-03 05:32:09 -08:00
dancho
7821e7702b Frame extractor: explain color accuracy issues
This is only a javadoc change, setting expectations.

PiperOrigin-RevId: 702295210
2024-12-03 04:56:38 -08:00
Copybara-Service
121b79ae96 Merge pull request #1943 from DolbyLaboratories:dlb/ac4-ajoc/dev
PiperOrigin-RevId: 702281314
(cherry picked from commit e4993779db61910aa31c23a6855667e8a6ea91d5)
2024-12-03 04:04:52 -08:00
Copybara-Service
e4993779db Merge pull request #1943 from DolbyLaboratories:dlb/ac4-ajoc/dev
PiperOrigin-RevId: 702281314
2024-12-03 04:04:52 -08:00
ibaker
18d156fe3c Configure ProgressiveMediaSource with a Format for subtitles
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
2024-12-03 03:40:49 -08:00
kimvde
0037388660 Simplify VideoSink.handleInputFrame
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
2024-12-03 03:29:30 -08:00
ybai001
1df0ee2052 Minor change to comment 2024-12-03 15:29:57 +08:00
ybai001
e503535ec2 LFE channel should always be counted for AC-4 A-JOC content on MPEG-4 layer 2024-12-03 13:29:57 +08:00
ybai001
547a164f42
Merge pull request #15 from androidx/main
Merge from androidx/media main branch
2024-12-03 10:14:07 +08:00
claincly
675c1d898a Move interface locations
PiperOrigin-RevId: 702096389
2024-12-02 15:03:37 -08:00
claincly
ecdf7c5df7 Propagate sourceEnded to AudioGraphInputAudioSink
PiperOrigin-RevId: 702076933
2024-12-02 13:59:15 -08:00
claincly
8908d82cac Signal end of stream to VideoFrameProcessor in previewing
This will be used by VideoCompositor

PiperOrigin-RevId: 702031907
2024-12-02 11:30:20 -08:00
ibaker
25c927e9f3 Standardize ForwardingXXX tests
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
2024-12-02 09:12:53 -08:00
dancho
b2ba5da09b Implement cancellation of FrameExtractor.getFrame
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
2024-12-02 06:09:33 -08:00
Googler
19b276d6a7 Allow track selection parameters to be set in ExoPlayerAssetLoader.
PiperOrigin-RevId: 701926949
2024-12-02 05:04:26 -08:00
dancho
d214e90ce4 Fix Frame Extractor getting stuck
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
2024-12-02 04:56:26 -08:00
tonihei
da4376d48d Avoid modifying legacy custom layout in MediaControllerImplBase
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
2024-12-02 03:19:51 -08:00
ibaker
77d33645cc Clarify CommandButton javadoc around iconResId and ICON_UNDEFINED
PiperOrigin-RevId: 701898620
2024-12-02 02:59:32 -08:00
ibaker
fa9689ef9a Clarify CommandButton javadoc around iconResId and ICON_UNDEFINED
PiperOrigin-RevId: 701898620
(cherry picked from commit 77d33645ccae9aef3d9e4def260bc68e9f7024f8)
2024-12-02 02:56:34 -08:00
Copybara-Service
f113a78e0d Merge pull request #1870 from colinkho:fwd-extractor-clz
PiperOrigin-RevId: 701313111
2024-11-29 10:18:34 -08:00
Copybara-Service
e27238666a Merge pull request #1849 from colinkho:stuckwhenready
PiperOrigin-RevId: 701306291
2024-11-29 09:34:56 -08:00
Ian Baker
7f62f74737 Fix review comments 2024-11-29 17:10:45 +00:00
Ian Baker
21e627da1c Fix review comments 2024-11-28 16:54:00 +00:00
Copybara-Service
55c81f6ed6 Merge pull request #1876 from colinkho:extinputgetreader
PiperOrigin-RevId: 701021720
2024-11-28 07:36:28 -08:00
Ian Baker
037a6f3219 Fix nullness errors 2024-11-28 14:47:57 +00:00
Ian Baker
38145b6e89 Tweak javadoc & reformat 2024-11-28 14:20:27 +00:00
Colin Kho
55a1290bfd Add a getter for DataReader on DefaultExtractorInput 2024-11-28 14:20:27 +00:00
Colin Kho
24ea6c4c14 Relax PlaybackStuck criteria to only when playWhenReady is true 2024-11-28 14:06:44 +00:00
Ian Baker
c5af8ba360 Add & fix copyright headers 2024-11-28 14:04:38 +00:00
Ian Baker
2683331299 Add tests and missing overrides to ForwardingExtractor 2024-11-28 14:01:14 +00:00
Ian Baker
01422d8322 Reformat with google-java-format 2024-11-28 11:45:09 +00:00
Colin Kho
6d265476e4 Added Forwarding classes for Extractor and ExtractorOutput 2024-11-28 11:45:09 +00:00
kimvde
4d925bde81 Remove stale TODO
Handling (very) late buffers is already supported.

PiperOrigin-RevId: 700965581
2024-11-28 03:02:59 -08:00
kimvde
852091f2d9 Implement DefaultVideoSink.isEnded
To do that, I had to add VideoFrameRenderControl.signalEndOfInput() and
isEnded() to match the VideoSink interface.

PiperOrigin-RevId: 700957098
2024-11-28 02:27:50 -08:00
kimvde
f3f4646296 Add VideoSink.signalEndOfCurrentInputStream()
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
2024-11-28 01:23:55 -08:00
kimvde
dfe3c90f9a Fix CompositionPlayerTest.imagePreview_imagePlaysForSetDuration
PiperOrigin-RevId: 700931124
2024-11-28 00:36:46 -08:00
rohks
08619bf6fa Add KEY_TRACK_ID to MediaFormat returned by getTrackFormat(int)
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
2024-11-27 10:26:30 -08:00
dancho
6e29b96337 Add support for extracting HDR frames as HLG Bitmaps
* Add GlUtils to create RGB10_A2 textures.
* Add OETF conversion to FrameReadingGlShaderProgram.
* Add FrameExtractor configuration API to request HDR output: API 34+

PiperOrigin-RevId: 700738895
2024-11-27 10:18:57 -08:00
rohks
270543555d Add getSampleCryptoInfo API to MediaExtractorCompat
This method enables handling encrypted samples by providing the necessary decryption details.

PiperOrigin-RevId: 700729949
2024-11-27 09:48:11 -08:00
kimvde
c861947bee Skip failing test on API 31 emulator
PiperOrigin-RevId: 700722123
2024-11-27 09:17:52 -08:00
rohks
52e45e0864 Prepare for CryptoInfo support by removing cached size
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
2024-11-27 08:47:37 -08:00
Copybara-Service
f5bbb39e90 Merge pull request #1823 from MGaetan89:remove_outdated_sdk_check
PiperOrigin-RevId: 700706152
(cherry picked from commit bff5523bb65e90f682df3491f877e06993eee1bc)
2024-11-27 08:16:02 -08:00
Copybara-Service
bff5523bb6 Merge pull request #1823 from MGaetan89:remove_outdated_sdk_check
PiperOrigin-RevId: 700706152
2024-11-27 08:16:02 -08:00
ibaker
60133b0c7e Recommend ForwardingSimpleBasePlayer in ForwardingPlayer javadoc
Also add an explicit warning about how fiddly `ForwardingPlayer` can be
to use correctly.

PiperOrigin-RevId: 700698032
2024-11-27 07:42:24 -08:00
ibaker
fd0c04b3a0 Recommend ForwardingSimpleBasePlayer in ForwardingPlayer javadoc
Also add an explicit warning about how fiddly `ForwardingPlayer` can be
to use correctly.

PiperOrigin-RevId: 700698032
(cherry picked from commit 60133b0c7edccaf350c56193022147bd46509039)
2024-11-27 07:40:13 -08:00
rohks
a371824dbc Remove unnecessary @SuppressLint("Override")
The Android SKD version 30 is stable, allowing us to remove the `@SuppressLint("Override")` annotations from `InputReaderAdapterV30` and `OutputConsumerAdapterV30`.

PiperOrigin-RevId: 700681115
2024-11-27 06:32:24 -08:00
ibaker
6cf3004d62 Bump IMA dependency to 3.35.1
The previous version (3.33.0) is known to have some bugs, and the latest
version (3.36.0) is also known to be buggy.

PiperOrigin-RevId: 700657484
2024-11-27 04:56:28 -08:00
ibaker
8a1e6e59b0 Bump IMA dependency to 3.35.1
The previous version (3.33.0) is known to have some bugs, and the latest
version (3.36.0) is also known to be buggy.

PiperOrigin-RevId: 700657484
(cherry picked from commit 6cf3004d623b9e5fa0e2c1dfc0ba8da1fc4f2cb1)
2024-11-27 04:53:38 -08:00
ibaker
f91d5208b5 MP3: Use bytes field from VBRI frame instead of deriving from ToC
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
(cherry picked from commit 46578ee0a6e8adf4c56b7b45b43713b132e35cca)
2024-12-18 14:19:41 +00:00
shahddaghash
d5d5771cd2 Add custom MediaSource.Factory attribute to CompositionPlayer
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
2024-11-26 10:48:22 -08:00
claincly
96c35966d8 Remove unnecessary parentherses
PiperOrigin-RevId: 700356007
2024-11-26 08:49:20 -08:00
claincly
de76d7932f Add missing test cases in SeekTest
PiperOrigin-RevId: 700354445
2024-11-26 08:43:06 -08:00
ibaker
465873ac28 Add androidx.compose.foundation:foundation to deps with AAR files
Also remove a dependency that is no longer used.

PiperOrigin-RevId: 700341461
2024-11-26 07:55:29 -08:00
ibaker
b19b6ccc60 MP3 VBRI: Use sampleCountToDurationUs() and samplesPerFrame
PiperOrigin-RevId: 700340564
2024-11-26 07:52:18 -08:00
ibaker
46578ee0a6 MP3: Use bytes field from VBRI frame instead of deriving from ToC
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
2024-11-26 06:18:29 -08:00
claincly
2a4bae01ef Add two missing test cases in seeking
PiperOrigin-RevId: 700284751
2024-11-26 03:44:23 -08:00
claincly
e357629400 Make back button pause player instead of quitting app
PiperOrigin-RevId: 700282443
2024-11-26 03:33:45 -08:00
ibaker
f257e5511f MP3: Exclude VBRI frame from ToC position calculations
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
2024-11-26 02:34:33 -08:00
ibaker
989c8f4fdb MP3: Exclude VBRI frame from ToC position calculations
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

PiperOrigin-RevId: 700269811
(cherry picked from commit f257e5511f12f57eb8397ec0801f32361a482f4f)
2024-11-26 02:32:09 -08:00
kimvde
6a3def3ccb Turn off repeat mode on Composition demo app
This is to make debugging easier.

PiperOrigin-RevId: 700265039
2024-11-26 02:14:04 -08:00
Gaëtan Muller
2fc379a61b Fix documentation for Format.Builder.setTileCountHorizontal and Format.Builder.setTileCountVertical 2024-11-26 10:05:16 +00:00
ibaker
3eb36d67bd Add MP3 test asset with VBRI frame
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
2024-11-26 01:33:39 -08:00
ibaker
7abfa764e1 Add MP3 test asset with VBRI frame
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
(cherry picked from commit 3eb36d67bd90d6d962df26dfdf29701a45902b4a)
2024-11-26 01:29:40 -08:00
ibaker
f34abbb29f Add pixel aspect ratio to Format.toLogString
#cherrypick

PiperOrigin-RevId: 698770714
(cherry picked from commit 827966b7a46b48cd17fe27b7b82d01fd9cd4a045)
2024-12-17 18:24:31 +00:00
michaelkatz
8d791fd836 Rollback of 854566dbfe
PiperOrigin-RevId: 698730105
(cherry picked from commit 5282fe3125c0f008d604ae514ee2609708fcb228)
2024-12-17 18:24:29 +00:00
sheenachhabra
05921514b7 Manage all color value conversions in ColorInfo class
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
(cherry picked from commit 407bc4fec9d834ad9ab85c21ad236af6bf6fbc55)
2024-12-17 18:24:14 +00:00
Copybara-Service
6fbd3be9c5 Merge pull request #1277 from consp1racy:patch-1
PiperOrigin-RevId: 694095488
(cherry picked from commit 19d71266ec4a712bfd73404ecda5171071bff295)
2024-12-17 18:24:14 +00:00
sheenachhabra
92166828e1 Make error messages unique in Boxes.java
PiperOrigin-RevId: 692920946
(cherry picked from commit c3e72a87e5d1215402580efc26881b4f65611a68)
2024-12-17 18:24:14 +00:00
sheenachhabra
0ceaa17bf5 Add an API to disable sample batching in Mp4Muxer
Mp4Muxer caches the samples and then writes them in batches.
The new API allows disabling the batching and writing sample
immediately.

PiperOrigin-RevId: 689352771
(cherry picked from commit f181855c5e1577b2df2d61ca49b04e6a202679b0)
2024-12-17 18:24:14 +00:00
dancho
bb20eb4975 Frame Extractor HDR: tone map to SDR
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
2024-11-25 08:41:42 -08:00
Shahd AbuDaghash
df887a9422 Merge branch 'release' into release-1.5.0 2024-11-25 14:47:51 +00:00
dancho
0d8f1d5ab9 Add Frame Extractor configuration for mediacodecselector
Adds a configuration option to Frame Extractor to choose MediaCodecSelector.
Add a MediaCodecSelector that lists software decoders first

PiperOrigin-RevId: 699962365
2024-11-25 06:40:28 -08:00
claincly
7ef1a7ab8b Support renderer joining in CompositionPlayer
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
2024-11-25 05:22:22 -08:00
kimvde
25a782e10a Stop delaying registering input stream on VideoFrameProcessor
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
2024-11-25 04:17:32 -08:00
dancho
c0fb4b7aff Composition demo app: show extended brightness
Request COLOR_MODE_HDR and show HDR content
as brighter-than-SDR.

PiperOrigin-RevId: 699887643
2024-11-25 01:22:54 -08:00
ibaker
827966b7a4 Add pixel aspect ratio to Format.toLogString
#cherrypick

PiperOrigin-RevId: 698770714
2024-11-21 07:21:11 -08:00
shahddaghash
73c4bb6e1f Bump Media3 version to 1.5.0
PiperOrigin-RevId: 698761734
2024-11-21 06:47:36 -08:00
kimvde
52dfe25542 Fix flushing issue in DefaultVideoFrameProcessor
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
2024-11-21 05:00:32 -08:00
kimvde
79effe7b60 Remove call to getFrameReleaseAction prior to applying effects
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
2024-11-21 04:38:54 -08:00
michaelkatz
5282fe3125 Rollback of 854566dbfe
PiperOrigin-RevId: 698730105
2024-11-21 04:29:19 -08:00
shahddaghash
754dfd76c8 Simplify use of defaultMediaSourceFactory in CompositionPlayer
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
2024-11-21 03:52:58 -08:00
shahddaghash
e5110e6442 Merge release notes for media3 1.5.0 stable release
PiperOrigin-RevId: 698713460
2024-11-21 03:16:14 -08:00
sheenachhabra
407bc4fec9 Manage all color value conversions in ColorInfo class
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
2024-11-21 01:09:02 -08:00
Copybara-Service
089eaa1d5d Merge pull request #1898 from DolbyLaboratories:dlb/ac4-level4-dash/dev
PiperOrigin-RevId: 698456089
2024-11-20 11:18:59 -08:00
shahddaghash
cf4488aa1f Move misplaced release note to Unreleased changes section
PiperOrigin-RevId: 698426838
2024-11-20 10:01:03 -08:00
dancho
d92c9aa8a1 Add a Frame Extractor test with rotated input
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
2024-11-20 07:20:50 -08:00
ivanbuper
66e8b53b43 Make SpeedChangingAudioProcessor direct subclass of AudioProcessor
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
2024-11-20 04:27:27 -08:00
claincly
3c01500a4e Use dynamic scheduling to speed up rendering the first image frame
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
2024-11-19 10:33:59 -08:00
dancho
dc7a0ca22f Move SDK == 33 tests to SDK 33+
Ensure tests run on any recent emulator.

PiperOrigin-RevId: 698015529
2024-11-19 07:55:32 -08:00
ivanbuper
646a6352a2 Remove bypass of SonicAudioProcessor in SpeedChangingAudioProcessor
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
2024-11-19 07:02:20 -08:00
rohks
d702e1d496 Add getPsshInfo() API to MediaExtractorCompat
This method retrieves PSSH (Protection System Specific Header) data from the media as a map of UUID-to-bytes.

PiperOrigin-RevId: 697974134
2024-11-19 05:14:55 -08:00
bachinger
b9c9d95b90 Add JSON asset list parser
PiperOrigin-RevId: 697966021
2024-11-19 04:41:17 -08:00
Copybara-Service
98723dc0a8 Merge pull request #1888 from DolbyLaboratories:dlb/dash-parser/dev
PiperOrigin-RevId: 697956473
2024-11-19 04:01:30 -08:00
dancho
ccc7b22ff4 Implement custom Frame Extractor renderer
Render only one frame per seek to reduce the amount of work done

PiperOrigin-RevId: 697946350
2024-11-19 03:14:57 -08:00
dancho
26f10effc2 Add frame extractor tests for decoder counters.
Right now, decoders produce an unspecified (but large)
number of frames. This will be resolved in a follow-up

PiperOrigin-RevId: 697945076
2024-11-19 03:10:17 -08:00
bachinger
c7ca9fbe7d Sanitize duration parsing for HLS interstitials
PiperOrigin-RevId: 697941445
2024-11-19 02:54:53 -08:00
kimvde
b782cdff52 Don't drop frames to ignore in RenderControl
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
2024-11-19 01:15:17 -08:00
claincly
9c6d9e9e47 Reduce test name lengths
Some parametrized names are too long (>255 chars). Remove putting parameter
info in the test name and instead log them.

PiperOrigin-RevId: 697677513
2024-11-18 10:34:06 -08:00
bachinger
9ae136becb Add context as a parameter to shouldStartForegroundService
Issue: androidx/media#1887
PiperOrigin-RevId: 697650546
2024-11-18 09:15:46 -08:00
ivanbuper
fff6e2e169 Fix incorrect Media3 1.5.0-rc01 release notes
PiperOrigin-RevId: 697626185
2024-11-18 07:57:57 -08:00
ibaker
66ec022bf0 Fix broken anchor in 1.5.0-rc02 release notes
PiperOrigin-RevId: 697596494
2024-11-18 05:54:28 -08:00
kimvde
8be2556efd Implement DefaultVideoSink.setStreamTimestampInfo
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
2024-11-18 02:01:52 -08:00
kimvde
2568ff73cb Remove unnecessary checkStateNotNull checks
LongArrayQueue.remove() throws a NoSuchElementException if the queue is
empty.

PiperOrigin-RevId: 697531458
2024-11-18 01:05:34 -08:00
ybai001
7b3effb871 Update test code based on the latest code structure 2024-11-18 10:29:40 +08:00
ibaker
cbb8e2f1e6 Bump media3 version to 1.5.0-rc02
PiperOrigin-RevId: 696912494
2024-11-15 09:33:11 -08:00
tianyifeng
0143884cd7 Deflake the DefaultPreloadManagerTest
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
2024-11-15 08:22:54 -08:00
rohks
ecc5cd889f Add getMetrics() API to MediaExtractorCompat
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
2024-11-15 08:17:26 -08:00
bachinger
1af0b5b432 Add handleContentTimelineChanged to AdsLoader
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
2024-11-15 07:49:41 -08:00
rohks
c3d4a3d683 Set container MIME type for extractors in ts module
PiperOrigin-RevId: 696882489
2024-11-15 07:37:43 -08:00
ibaker
c50867c81d Release notes for 1.5.0-rc01
PiperOrigin-RevId: 696879276
2024-11-15 07:23:51 -08:00
rohks
68c0b8115f Set container MIME type for Flv, Matroska, and image extractors
Image extractors (e.g., `PngExtractor`) use `SingleSampleExtractor`
for extraction.

PiperOrigin-RevId: 696869657
2024-11-15 06:42:12 -08:00
dancho
11fc0871ac Implement video effects for Frame Extraction
Test that downscaled images match MediaMetadataRetriever.

PiperOrigin-RevId: 696862566
2024-11-15 06:09:55 -08:00
ybai001
c503a63878 Update comment for MPEG_CHANNEL_CONFIGURATION_MAPPING
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.
2024-11-15 16:31:52 +08:00
ybai001
3b7d19e94e
Merge pull request #13 from androidx/main
Merge from androidx/media main branch
2024-11-15 15:58:20 +08:00
ibaker
e6448f3498 Don't assume MP4 keyframe metadata is correct for CEA re-ordering
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
2024-11-14 11:05:02 -08:00
rohks
2379d0f18c Set container MIME type for audio-only extractors
PiperOrigin-RevId: 696560053
2024-11-14 10:03:17 -08:00
rohks
93b4c6ef47 Set container MIME type in Mp4Extractor and FragmentedMp4Extractor
PiperOrigin-RevId: 696513199
2024-11-14 07:23:22 -08:00
bachinger
6453054878 Parse interstitials into HLS media playlist
PiperOrigin-RevId: 696454575
2024-11-14 03:09:12 -08:00
dancho
16a15b94ca Add Configration for Frame Extraction for specific SeekParameters
Expose ExoPlayer seek parameters via FrameExtractor API

PiperOrigin-RevId: 696449874
2024-11-14 02:48:05 -08:00
dancho
301ef207f2 Add pixel comparison to FrameExtractorTest
Add PSNR comparison with the output of MedaiMetadataRetriever.

PiperOrigin-RevId: 696190585
2024-11-13 10:43:36 -08:00
Copybara-Service
74611bbdc0 Merge pull request #1265 from DolbyLaboratories:dlb/ac4-level4/dev_new2
PiperOrigin-RevId: 696157037
2024-11-13 09:08:22 -08:00
ibaker
0f96ad247d Fix 'narrowing conversion' warning in FragmentedMp4Extractor
PiperOrigin-RevId: 696119977
2024-11-13 07:08:12 -08:00
tianyifeng
c3d4722197 Resolve the memory leaks in demo short-form app
Issue: androidx/media#1839
#cherrypick
PiperOrigin-RevId: 696080063
2024-11-13 04:42:47 -08:00
kimvde
9db66d6c6b Simplify bufferTimestampAdjustment handling
PiperOrigin-RevId: 696060496
2024-11-13 03:21:52 -08:00
kimvde
8393c2e445 Implement/document trivial methods in DefaultVideoSink
PiperOrigin-RevId: 696047835
2024-11-13 02:33:16 -08:00
dancho
175dca41df Read Bitmap in ExperimentalFrameExtractor
Add a MatrixTransformation GlEffect to flip between
OpenGL and Bitmap coordinates

PiperOrigin-RevId: 696029842
2024-11-13 01:27:02 -08:00
kimvde
64e92cb8e1 Various refactorings in VideoFrameRenderControl
- 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
2024-11-13 01:15:58 -08:00
Googler
838c621d00 Add support to ApvC codec in Mp4Extractor
PiperOrigin-RevId: 695819965
2024-11-12 11:59:56 -08:00
sheenachhabra
59106bba1c Start muxer watchdog timer on export start
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
2024-11-12 10:19:13 -08:00
ibaker
19b38c83b6 Handle C.TIME_END_OF_SOURCE buffer timestamps in CeaDecoder
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
2024-11-12 09:38:44 -08:00
dancho
40f187e4b4 Block calls to FrameExtractor.release
Block calls to release() method, and handle
calls on the player looper or not.

PiperOrigin-RevId: 695697602
2024-11-12 05:49:19 -08:00
rohks
de0e08397e Add caching status APIs to MediaExtractorCompat
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
2024-11-12 05:34:42 -08:00
dancho
ed288fca46 Experimental frame extraction based on ExoPlayer
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
2024-11-12 05:18:01 -08:00
Googler
4acd1b970c Make MediaSource.Factory a nullable parameter.
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
2024-11-11 14:26:14 -08:00
claincly
01c784775e Rename signalEndOfInputStream()
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
2024-11-11 07:44:15 -08:00
bachinger
fa790bd73c Fix supportedCommands in MediaMetadata
#cherrypick

PiperOrigin-RevId: 695304782
2024-11-11 06:07:02 -08:00
michaelkatz
0c982a7994 Fix error where non-enabled renderers were set to final
If the renderer has no stream, then it should not be called with `setCurrentStreamFinal` on it.

PiperOrigin-RevId: 695284225
2024-11-11 04:35:25 -08:00
ivanbuper
f84f44bf6b Implement static method to return estimated output samples
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
2024-11-08 12:54:47 -08:00
ibaker
53953dd377 Re-define 'max size' of SEI queue to operate on unique timestamps
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
2024-11-08 09:20:57 -08:00
michaelkatz
b329806859 Fix unit test that confirms AAC_LC passthrough is unsupported
PiperOrigin-RevId: 694494792
2024-11-08 07:49:11 -08:00
tianyifeng
2b54b1ebbe Release internal components on preload thread in DefaultPreloadManager
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
2024-11-07 10:50:22 -08:00
rohks
91dfaab93f Add getDrmInitData() API to MediaExtractorCompat
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
2024-11-07 06:33:43 -08:00
Copybara-Service
19d71266ec Merge pull request #1277 from consp1racy:patch-1
PiperOrigin-RevId: 694095488
2024-11-07 06:28:45 -08:00
Eugen Pechanec
b956861442 Git: Ignore .cxx intermediate output directory
This is produced by CMake e.g. in FFmpeg extension.
The directory is created in projectDir rather than buildDir.
2024-11-07 10:56:36 +00:00
shahddaghash
f6116a121a Add functionality for Choose local file button
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
2024-11-06 09:36:08 -08:00
shahddaghash
7b9cfd1964 Add basic UI to effect demo app
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
2024-11-06 09:18:44 -08:00
shahddaghash
d164ce221a Change lib-common dependency scope to api in lib-ui
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
2024-11-06 08:21:16 -08:00
rohks
3d51b36e99 Fix wrong class name in error message of MediaExtractorCompatTest
PiperOrigin-RevId: 693685232
2024-11-06 05:08:57 -08:00
dancho
31ae260db4 Support alternative sample MIME types in MuxerWrapper
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
2024-11-06 03:58:02 -08:00
dancho
f9fd8badec Prevent repeated release of the same EGLContext
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
2024-11-06 03:18:42 -08:00
ibaker
ab723fc8ff Mark every media3-cues sample as a keyframe
This format doesn't require any context from previous samples, so every
sample is a keyframe.

PiperOrigin-RevId: 693658370
2024-11-06 03:15:59 -08:00
tonihei
5336d71c22 Add TestPlayerRunHelper run(player).untilFullyBuffered
This simplifies some common test setup steps that rely on
a fully buffered player before making further test progress.

PiperOrigin-RevId: 693651493
2024-11-06 02:45:51 -08:00
Googler
08470140ac Internal
PiperOrigin-RevId: 693418471
2024-11-05 11:24:39 -08:00
tonihei
d38aba92fe Fix flakiness in HlsPlaybackTest and DashPlaybackTest
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
2024-11-05 09:42:53 -08:00
michaelkatz
28b75f7d29 Schedule doSomeWork after setVideoOutput
PiperOrigin-RevId: 693374521
2024-11-05 09:22:17 -08:00
ibaker
286273c10e Enable lint in tests for modules that require no fixes
PiperOrigin-RevId: 693313908
2024-11-05 05:40:03 -08:00
tonihei
12cb803486 Compat logic for MediaController.getCustomLayout
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
2024-11-05 05:06:47 -08:00
tonihei
9fb4ed91b6 Make getCustomLayoutFromMediaButtonPreferences side-effect free
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
2024-11-05 03:54:40 -08:00
tonihei
76e4abe428 Reduce default values for DefaultLoadControl buffer for playback
PiperOrigin-RevId: 693284512
2024-11-05 03:39:16 -08:00
ibaker
6f81b5792b Add 'session extras' and MediaMetadata.durationMs to the stable API
PiperOrigin-RevId: 693279664
2024-11-05 03:17:06 -08:00
ibaker
212bd943f5 Fix lint violations in MediaExtractorCompatTest
I missed these as part of aebf822c3c

PiperOrigin-RevId: 692982120
2024-11-04 08:51:47 -08:00
rohks
278eaf47ad Add log session ID APIs to MediaExtractorCompat
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
2024-11-04 06:38:38 -08:00
jbibik
0270267e08 Add ShuffleButtonState and RepeatButtonState to ui-compose
* 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
2024-11-04 06:12:57 -08:00
rohks
261ca326c5 Move MediaExtractorCompatTest from test/ to androidTest/
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
2024-11-04 05:42:45 -08:00
ibaker
aebf822c3c Enable lint errors in exoplayer tests
Follow-up to 76db936d68

PiperOrigin-RevId: 692925617
2024-11-04 05:08:34 -08:00
sheenachhabra
c3e72a87e5 Make error messages unique in Boxes.java
PiperOrigin-RevId: 692920946
2024-11-04 04:49:27 -08:00
ibaker
af1c13524c Enable lint in lib-common tests
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
2024-11-04 04:16:39 -08:00
shahddaghash
a8ed6494c3 Create an empty module for Effect demo
The new demo module aims to showcase different `Effect` capabilities.

PiperOrigin-RevId: 692912895
2024-11-04 04:12:55 -08:00
dancho
bd90ef38b0 MCVR.hasSurfaceForCodec considers VideoSink
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
2024-11-04 03:17:54 -08:00
Copybara-Service
aebda58314 Merge pull request #1829 from colinkho:ssms-custom-exec-2
PiperOrigin-RevId: 692897382
2024-11-04 03:02:46 -08:00
rohks
d8ad18383d Optimize sample metadata handling in MediaExtractorCompat
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
2024-11-01 14:07:11 -07:00
ivanbuper
7edbaa3f2c Use sample-aligned speed changes in SpeedChangingAudioProcessor
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
2024-11-01 11:09:18 -07:00
ivanbuper
0b1695124b Bump Media3 to 1.5.0-rc01
#cherrypick

PiperOrigin-RevId: 692221696
2024-11-01 10:30:45 -07:00
tonihei
06718c5df3 Fix position tracking bug for inaccurate audio processors
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
2024-11-01 09:28:15 -07:00
claincly
b0c6106882 Fix trim optimization logic when edit lists exist
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
2024-11-01 08:36:08 -07:00
ivanbuper
38e1efafc2 Prepare RELEASENOTES.md for Media3 1.5.0-rc01 release
This change also fixes two notes added incorrectly onto the previous
beta01 release section.

#cherrypick

PiperOrigin-RevId: 692169335
2024-11-01 07:32:10 -07:00
Copybara-Service
4910b2cdc0 Merge pull request #1225 from Kekelic:support-for-parsing-rtsp-packets-with-header-extension
PiperOrigin-RevId: 692156233
2024-11-01 06:35:16 -07:00
tonihei
544d7aa2dc Annotate parameters in RepeatModeUtil
PiperOrigin-RevId: 692129684
2024-11-01 04:33:31 -07:00
jbibik
1b302e879a Add PreviousButtonState and NextButtonState to ui-compose
* 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
2024-10-31 14:52:38 -07:00
jbibik
676a3872a5 Add PlayPauseButtonState to ui-compose
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
2024-10-31 11:42:14 -07:00
ivanbuper
f991e1f023 Move release note in 1.5.0-beta01 to "Unreleased" section
The item was incorrectly added to the beta01 section in 2a49ffcb23.

#cherrypick

PiperOrigin-RevId: 691876672
2024-10-31 11:34:46 -07:00
microkatz
0e020f778c Added release note 2024-10-31 12:42:03 +00:00
microkatz
71bc177e39 Format with google-java-format 2024-10-31 11:57:47 +00:00
Kekelic
47f4dabb98 Fix documentation and improve readability of unit test with rtpDataWithHeaderExtension example 2024-10-31 11:57:47 +00:00
Kekelic
84f8beb884 Remove saving unnecessary header extension data 2024-10-31 11:57:47 +00:00
Kekelic
5a8a250a1a Add reading length of extension payload from header extension in RtpPacket 2024-10-31 11:57:47 +00:00
Kekelic
1ecb7c3fbf Format changes 2024-10-31 11:57:46 +00:00
Kekelic
7dd428534e Change RtpPacket class to parse header extension if exists 2024-10-31 11:57:46 +00:00
ibaker
b5db8a6cbe Fix empty LoadEventInfo.uri passed to onLoadStarted
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
2024-10-30 15:52:48 -07:00
jbibik
6cbf77b3f0 Refactor shouldEnablePlayPauseButton out of PlayerControlView into Util
PiperOrigin-RevId: 691502799
2024-10-30 11:59:25 -07:00
rohks
2b27e33784 Refactor OpusDecoderTest to use OpusLibrary.isAvailable()
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
2024-10-30 10:02:46 -07:00
ivanbuper
2a9963424b Refactor readBytes to readFrames in SpeedChangingAudioProcessor
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
2024-10-30 09:21:54 -07:00
rohks
15583f7c64 Set track duration in AmrExtractor, Mp3Extractor and OggExtractor
PiperOrigin-RevId: 691433024
2024-10-30 08:46:45 -07:00
ibaker
0462349902 Deprecate NalUnitUtil.isNalUnitSei(String, byte)
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
2024-10-30 07:21:26 -07:00
rohks
df07fa35d8 Populate MediaFormat.KEY_DURATION in MediaExtractorCompat
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
2024-10-30 06:29:47 -07:00
rohks
27de9f02e0 Add missing DefaultRenderersFactoryTest for decoder extensions
Added `DefaultRenderersFactoryTest` for `IAMF`, `AV1`, and `MIDI` decoder extensions.

PiperOrigin-RevId: 691381816
2024-10-30 05:33:38 -07:00
ibaker
27371db225 Support CEA-608 subtitles in Dolby Vision
Issue: androidx/media#1820

#cherrypick

PiperOrigin-RevId: 691378476
2024-10-30 05:18:14 -07:00
ibaker
08a141328d Mark ProgressiveMediaSource.setSuppressPrepareError package-private
This method will likely be removed in the next release, and is currently
only needed from within the `source` package.

#cherrypick

PiperOrigin-RevId: 691351449
2024-10-30 03:19:14 -07:00
rohks
129cf8ea72 Use assumeTrue for libiamf availability check in IamfDecoderTest
This change ensures that the test uses `assumeTrue` to avoid failures when the `libiamf` library is not pre-built.

#cherrypick

PiperOrigin-RevId: 691333564
2024-10-30 02:01:05 -07:00
kimvde
96b923b610 Fix failing portrait export test
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
2024-10-29 09:10:59 -07:00
kimvde
14094b5094 Fix offset passed to VideoFrameReleaseControl
In some cases, the streamOffsetUs was passed to
VideoFrameReleaseControl.getFrameReleaseAction() but it should be the
streamStartPositionUs.

PiperOrigin-RevId: 691040172
2024-10-29 09:04:35 -07:00
shahddaghash
7f94aaf49f Remove deprecated SingleFrameGlShaderProgram class.
Class was deprecated in Media3 1.2.0. Use BaseGlShaderProgram class instead.

PiperOrigin-RevId: 691001562
2024-10-29 06:53:45 -07:00
tonihei
7c0cffdca8 Improve position estimate when transitioning to another checkpoint
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
2024-10-29 05:31:25 -07:00
shahddaghash
7a8f05f736 Remove deprecated Transformer methods/variables
Removed deprecated `Transformer.PROGRESS_STATE_NO_TRANSFORMATION`, `Transformer.setListener`, and `Transformer.startTransformation` from Transformer.

PiperOrigin-RevId: 690971992
2024-10-29 05:02:31 -07:00
rohks
b1f2efd218 Fix handling of cues that exceed total duration in MatroskaExtractor
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
2024-10-29 04:18:38 -07:00
shahddaghash
51055d7e79 Remove deprecated TransformationException class.
Class was deprecated in Media3 1.1.0. Use `ExportException` class instead.

PiperOrigin-RevId: 690955853
2024-10-29 03:59:15 -07:00
dancho
b0df3b2da3 DecodeOneFrameUtil: do not access release players
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
2024-10-29 03:48:29 -07:00
shahddaghash
dd6e88889a Remove deprecated TransformationResult class.
Class was deprecated in Media3 1.1.0. Use `ExportResult` class instead.

PiperOrigin-RevId: 690694730
2024-10-28 11:51:02 -07:00
ivanbuper
7e7764de5e Implement getExpectedFrameCountAfterProcessorApplied() in Sonic
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
2024-10-28 10:43:03 -07:00
shahddaghash
772bd20f7d Remove deprecated Transformer.Listener methods
Methods were deprecated between Media3 1.0.0 and Media3 1.1.0.

PiperOrigin-RevId: 690656410
2024-10-28 10:09:20 -07:00
dancho
4601a42aee Use PSNR for comparing equality in one HDR10 test
Also, fix incorrectly stretched golden file that was not detected with previous, less sensitive, average pixel error comparison.

PiperOrigin-RevId: 690643520
2024-10-28 09:38:34 -07:00
dancho
e67660f326 Consistently use highp for HDR colors
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
2024-10-28 08:50:19 -07:00
dancho
fe14525a97 Use ExoPlayer in DecodeOneFrameUtil
The old code that uses MediaCodec directly has a race condition
that causes the decoder to incorrectly crop the decoded picture.

PiperOrigin-RevId: 690620868
2024-10-28 08:32:23 -07:00
shahddaghash
9e088ac2b8 Remove 7 deprecated Transformer.Builder methods
PiperOrigin-RevId: 690617093
2024-10-28 08:19:41 -07:00
dancho
5bb9e1a932 UltraHDR Ovelays: remove texture unit clash
Do not use the same texture unit for two different textures.
This was causing tests to fail on multiple devices.

PiperOrigin-RevId: 690610094
2024-10-28 07:59:09 -07:00
ivanbuper
9653fa64fe Move calculateAccumulatedTruncationErrorForResampling() to Sonic
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
2024-10-28 07:53:44 -07:00
rohks
a913a16db4 Add ignore exclusions for IAMF and MPEG-H decoder extensions
PiperOrigin-RevId: 690537114
2024-10-28 03:12:51 -07:00
rohks
84ab67cca3 Fix .gitignore paths for extensions
#cherrypick

PiperOrigin-RevId: 690534708
2024-10-28 03:03:42 -07:00
ibaker
39c734963f H264Reader: Add missing propagation of max_num_reorder_frames
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
2024-10-25 09:13:53 -07:00
tonihei
a15571c8ee Add logic to convert button preferences to custom layout in sessions
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
2024-10-25 06:09:21 -07:00
tonihei
8811b454bb Use slots to fill in default compact view indices
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
2024-10-25 05:12:07 -07:00
tonihei
0fdc930444 Use media button preferences in session demo app
PiperOrigin-RevId: 689738802
2024-10-25 04:34:21 -07:00
tonihei
aeb9d12a16 Add logic to convert custom layout to button preferences in controller
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
2024-10-25 04:29:05 -07:00
Copybara-Service
d051b4b993 Merge pull request #1768 from colinkho:onloadstarted-retry
PiperOrigin-RevId: 689728139
2024-10-25 03:51:35 -07:00
rohks
e25bc2c1a5 Populate track duration(s) in Avi, Flac and Wav extractors
PiperOrigin-RevId: 689716977
2024-10-25 03:03:08 -07:00
Ian Baker
683a5b8403 Fix review comments 2024-10-25 10:58:48 +01:00
Ian Baker
7d3e6b0f27 Add release note 2024-10-25 10:58:29 +01:00
Ian Baker
37f795ea82 Try removing duplicate calls 2024-10-25 10:58:29 +01:00
Ian Baker
7cf500bc2d Fix compilation of MergingMediaSourceTest 2024-10-25 10:58:29 +01:00
Ian Baker
473a4a7680 Call both old and new onLoadStarted methods in DefaultAnalyticsCollector 2024-10-25 10:58:29 +01:00
Ian Baker
d3298391b2 Fix onLoadStarted event accumulation in DefaultAnalyticsCollectorTest 2024-10-25 10:58:29 +01:00
Ian Baker
b565f47d18 Reformat with google-java-format 2024-10-25 10:58:29 +01:00
Ian Baker
e7f5d4d441 Remove backwards-compat onLoadStarted from MediaSourceEventListener 2024-10-25 10:58:29 +01:00
Colin Kho
5581529bfb Use long as test constant for DefaultAnalyticsCollectorTest 2024-10-25 10:58:28 +01:00
Colin Kho
16f65cee58 Deprecate onLoadStarted w/o retry count on AnalyticsListener 2024-10-25 10:58:28 +01:00
Colin Kho
5dbe1efa9e Treat onLoadStarted with retryCount to be a new method rather than redirect calls 2024-10-25 10:58:28 +01:00
Colin Kho
8adcd35c75 Incorporate MediaSourceEventListener.onLoadStarted with retryCount parameter with backward compatibility 2024-10-25 10:58:25 +01:00
Colin Kho
2d05744333 Add DownloadExecutor to SingleSampleMediaSource 2024-10-24 11:59:35 -07:00
samrobinson
45317394da Implement constant power matrices for channel mixing to mono & stereo.
Calculations are derived from the android platform channel mixing.

PiperOrigin-RevId: 689427658
2024-10-24 10:23:07 -07:00
dancho
d2fb779929 Ignore flaky preview tests
Tests are flaky because shader program creation is slow

PiperOrigin-RevId: 689420905
2024-10-24 10:04:57 -07:00
Rohit Kumar Singh
af1b5b5102 Merge Issue: androidx/media#1826: add extension for MPEG-H decoding
Imported from GitHub PR https://github.com/androidx/media/pull/1826

Merge 6b59a1602b022ebc44411ae3440e274c51c223a7 into b5615d5e919b297def6450b45320a3165c34548c

COPYBARA_INTEGRATE_REVIEW=https://github.com/androidx/media/pull/1826 from androidx:mpegh_extension 6b59a1602b022ebc44411ae3440e274c51c223a7
PiperOrigin-RevId: 689417378
2024-10-24 09:53:45 -07:00
ibaker
757f223d8a Remove // Do nothing overrides from EventLogger
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
2024-10-24 09:50:54 -07:00
dancho
94e37ca7d2 Fix flaky test
* 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
2024-10-24 09:29:35 -07:00
michaelkatz
2f198c4c06 Implement getDurationToProgressUs for DecoderAudioRenderer
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
2024-10-24 07:46:42 -07:00
sheenachhabra
f181855c5e Add an API to disable sample batching in Mp4Muxer
Mp4Muxer caches the samples and then writes them in batches.
The new API allows disabling the batching and writing sample
immediately.

PiperOrigin-RevId: 689352771
2024-10-24 06:15:25 -07:00
ibaker
b36de302f7 Remove some un-needed proguard-rules.txt symlinks
PiperOrigin-RevId: 689344803
2024-10-24 05:43:59 -07:00
rohks
5f99955f31 Make minor improvements for IAMF decoder module
- 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
2024-10-24 04:46:13 -07:00
ibaker
4a406be1bf DataSourceContractTest: Tighten assertions around 'not found' URIs
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
2024-10-24 03:49:27 -07:00
kimvde
d25a423888 Remove unused parameter from VideoFrameRenderControl.FrameRenderer
PiperOrigin-RevId: 689281689
2024-10-24 01:27:20 -07:00
Copybara-Service
b5615d5e91 Merge pull request #1794 from stevemayhew:p-fix-ntp-time-update-main
PiperOrigin-RevId: 689121191
2024-10-23 15:22:22 -07:00
jbibik
7da71f792b Move PlayerSurface from demo-compose to media3-ui-compose
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
2024-10-23 10:00:07 -07:00
tonihei
21526588be Removed unused constructor
PiperOrigin-RevId: 688960856
2024-10-23 07:50:31 -07:00
michaelkatz
f11130d59e Move setVideoOutput message handling to playback thread
PiperOrigin-RevId: 688951964
2024-10-23 07:16:50 -07:00
tonihei
dfb7636138 Suppress not-applicable lint warning
PiperOrigin-RevId: 688948857
2024-10-23 07:11:58 -07:00
ibaker
7b66209bca Add missing overrides in DefaultTrackSelector.Parameters.Builder
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
2024-10-23 07:08:03 -07:00
kimvde
75f29b6997 Implement DefaultVideoSink.render()
PiperOrigin-RevId: 688948682
2024-10-23 07:05:53 -07:00
michaelkatz
e5133e78f5 Abstract EPII renderer logic into holder class
Move EPII calls to renderers to a separate managing class.

PiperOrigin-RevId: 688932712
2024-10-23 06:04:21 -07:00
rohks
e677c8dccd Fix duration calculation for AVI files
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
2024-10-23 03:34:04 -07:00
bachinger
0038dda3c3 Fix flakiness of MediaBrowserListenerWithMediaBrowserServiceCompatTest
PiperOrigin-RevId: 688870397
2024-10-23 01:54:22 -07:00
kimvde
6c932722e4 Set release control frame rate in DefaultVideoSink
All the calls to the VideoFrameReleaseControl and
VideoFrameRenderControl will be moved to the DefaultVideoSink

PiperOrigin-RevId: 688857699
2024-10-23 01:06:04 -07:00
tonihei
e43720b83a Remove deprecated MediaSession.getSessionCompatToken
And also the deprecated override of
ControllerInfo.createTestOnlyControllerInfo using the
androidx.media classes.

PiperOrigin-RevId: 688625484
2024-10-22 11:30:28 -07:00
jbibik
a645f704b8 Create a new media3-ui-compose module
It will be used for UI components built with Jetpack Compose

`implementation("androidx.media3:media3-ui-compose:1.X.Y")`

PiperOrigin-RevId: 688595899
2024-10-22 10:14:26 -07:00
ivanbuper
36a5a83b22 Implement parameterized testing for SpeedChangingAudioProcessor
`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
2024-10-22 09:27:08 -07:00
ibaker
cabc541a6f Use Guava's HttpHeaders consistently in HTTP testing machinery
PiperOrigin-RevId: 688576776
2024-10-22 09:21:09 -07:00
rohks
7545a8929b Add support for identifying h263 box in MP4 files for H.263 video
Issue: androidx/media#1821

#cherrypick

PiperOrigin-RevId: 688570141
2024-10-22 09:02:33 -07:00
jbibik
ee4f0c40bc Align spelling of fullScreen to fullscreen
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
2024-10-22 08:30:10 -07:00
ibaker
219565c15e DataSourceContractTest: Add expected response headers
PiperOrigin-RevId: 688556440
2024-10-22 08:19:10 -07:00
kimvde
8260bb3d2e Refactor frame rate notification to release control
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
2024-10-22 05:44:41 -07:00
sheenachhabra
31ece8cbd2 Fix color info conversion in vpccBox method
The color space should be used to determine the color
primaries and matrix coefficients, not the video range.

PiperOrigin-RevId: 688489212
2024-10-22 04:14:33 -07:00
tonihei
d9ca3c734a Ensure session extras Bundle is copied at least once
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
2024-10-22 04:06:06 -07:00
kimvde
be8c58d51e Use Format object in VideoFrameProcessor
This is to use an existing media3 object rather than creating a new one.

PiperOrigin-RevId: 688481323
2024-10-22 03:46:03 -07:00
claincly
7335754b23 Spell out VFP as VideoFrameProcessor
PiperOrigin-RevId: 688465940
2024-10-22 02:40:22 -07:00
Marc Baechinger
70f2d516a0 Add getter/setter and disable re-initialization by default 2024-10-21 19:18:58 +02:00
tonihei
1780986270 Stabilize ERROR_CODE_DECODING_RESOURCES_RECLAIMED
PiperOrigin-RevId: 688175306
2024-10-21 10:04:22 -07:00
shahddaghash
320cbc09f4 Remove deprecated AudioMixer.create() method
Use `DefaultAudioMixer.Factory().create()` instead.

PiperOrigin-RevId: 688167322
2024-10-21 09:39:34 -07:00
ibaker
b04b37074b Add video language to DefaultTrackSelector
PiperOrigin-RevId: 688155680
2024-10-21 09:02:19 -07:00
rohks
e926b0df1e Populate track duration in Mp4Extractor and FragmentedMp4Extractor
PiperOrigin-RevId: 688125056
2024-10-21 07:16:34 -07:00
claincly
73790cf2a4 Don't optimize for trim if the media is not clipped
PiperOrigin-RevId: 688120868
2024-10-21 06:58:59 -07:00
rohks
0ecd35e24c Improve error logging for IllegalClippingException
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
2024-10-21 06:45:35 -07:00
rohks
847c1252e2 Add default method durationUs(long) in TrackOutput
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
2024-10-21 06:18:00 -07:00
rohks
457bc55a4d Fix media duration parsing in mdhd box of MP4 files to handle -1 values
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
2024-10-21 05:54:44 -07:00
ibaker
40cd64ab19 Test ResolvingDataSource resolveReportedUri functionality
PiperOrigin-RevId: 688102934
2024-10-21 05:49:50 -07:00
shahddaghash
5088e87195 Bump Media3 version to 1.5.0-beta01
PiperOrigin-RevId: 688079507
2024-10-21 04:15:18 -07:00
ibaker
74bbd7727d DataSourceContractTest: Add tests for resolved vs original URI
PiperOrigin-RevId: 688076205
2024-10-21 04:06:37 -07:00
Copybara-Service
f2ecca3b6a Merge pull request #1742 from colinkho:trackselection-playwhenready
PiperOrigin-RevId: 688050467
2024-10-21 02:27:20 -07:00
ibaker
49337d9667 Fix some markdown-in-javadoc
PiperOrigin-RevId: 687354846
2024-10-18 10:48:43 -07:00
tonihei
513ebf67b7 Add initial playWhenReady setting and tests
Also includes a new test for a similar logic that already exists
for speed changes.
2024-10-18 18:00:55 +01:00
Colin Kho
e4b32e4e31 Fix javadoc formatting 2024-10-18 18:00:18 +01:00
Colin Kho
943e165f1f Add variable to track playWhenReady status of a TrackSelection instance 2024-10-18 18:00:18 +01:00
tonihei
ceac959c29 Let FakeTrackSelection extend BaseTrackSelection
This fixes a bug in getIndexInTrackGroup

PiperOrigin-RevId: 687336621
2024-10-18 09:54:50 -07:00
ivanbuper
0108fb938e Make conversions to durationsUs consistent in SpeedProviders
PiperOrigin-RevId: 687334787
2024-10-18 09:47:55 -07:00
ibaker
b64bf88272 Rename playback thread in MediaSourceTestRunner
This makes it more clearly "the playback thread" when logging its name
during tests. The 'real' playback thread used in
`ExoPlayerImplInternal` is [called
`ExoPlayer:Playback`](49dec5db8b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/PlaybackLooperProvider.java (L87)).

PiperOrigin-RevId: 687307440
2024-10-18 08:14:08 -07:00
ibaker
2f01900e83 Release the Surface at the end of every playback test
Without this an error is logged which obfuscates real test failures.

PiperOrigin-RevId: 687302953
2024-10-18 08:01:50 -07:00
claincly
f52c7a1d5c Add an example to integrate android.animation
PiperOrigin-RevId: 687274900
2024-10-18 06:05:26 -07:00
claincly
2a49ffcb23 Make OverlaySettings dynamic
PiperOrigin-RevId: 687269731
2024-10-18 05:43:33 -07:00
shahddaghash
709246ac6a Fix dropped full stop in release notes
PiperOrigin-RevId: 687252101
2024-10-18 04:26:58 -07:00
tonihei
5fffe03312 Remove unneeded @Nullable from PlayerWrapper.legacyExtras
All values passed in via the constructor or setLegacyExtras
are guaranteed to be non-null.

PiperOrigin-RevId: 687245475
2024-10-18 04:04:32 -07:00
shahddaghash
4d711050bb Update release notes for Media3 1.5.0-beta01 release
PiperOrigin-RevId: 687243739
2024-10-18 03:55:16 -07:00
bachinger
3e556a4b53 Accept resource URIs for command buttons
PiperOrigin-RevId: 687239119
2024-10-18 03:35:50 -07:00
ibaker
13d6f37a84 Remove unused Surface from DashPlaybackTest
Follow-up to cb90bb38ee

PiperOrigin-RevId: 687235908
2024-10-18 03:21:07 -07:00
ibaker
3ba2fa6c07 Add @ForOverride annotation to DataSourceContractTest
PiperOrigin-RevId: 687223500
2024-10-18 02:33:14 -07:00
claincly
ba3d2b3fef Add a CanvasOverlay for easier drawing, and an example in demo app
PiperOrigin-RevId: 687223353
2024-10-18 02:29:43 -07:00
bachinger
08e6f30b68 Look for METADATA_KEY_ART_URI for legacy media items
PiperOrigin-RevId: 687222830
2024-10-18 02:26:47 -07:00
Steve Mayhew
621a9aedba SntpClient periodically re-syncs the offset to NTP server
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
2024-10-14 22:03:00 +02:00
ybai001
545d37c104 Fix two bugs in the updated code
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.
2024-10-14 17:25:36 +08:00
ybai001
e8d29dc3d6 Remove redundant blank line
Remove redundant blank line.
2024-10-14 13:55:06 +08:00
ybai001
c18c6b31ef Remove the modification on Format
According to Google's comments, removing the modification on Format.java since it is redundant.
2024-10-14 13:51:40 +08:00
ybai001
79078c390d Add SUPPLEMENTAL-CODECS support in both DASH and HLS 2024-10-08 10:07:43 +08:00
ybai001
1381c92d76 Add AC-4 channel configuration support in DASH 2024-09-25 09:17:50 +08:00
ybai001
e7254b809a
Merge pull request #11 from androidx/main
Merge from androidx/media
2024-09-25 09:11:27 +08:00
ybai001
b650119d4e
Merge pull request #10 from androidx/main
Merge latest code from androidx media main branch
2024-09-20 11:22:08 +08:00
tianyifeng
c35a9d62ba Bump media3 version to 1.4.1
PiperOrigin-RevId: 666347191
(cherry picked from commit 829cad6912c4d99a5676aa3b8beaa258ee417926)
2024-08-22 15:16:35 +00:00
tianyifeng
517762c087 Update release notes for 1.4.1 bug fix release
PiperOrigin-RevId: 666328660
(cherry picked from commit 1994ccdea8bb52c99b8fdf9f35f68043492ab4a9)
2024-08-22 15:13:14 +00:00
tianyifeng
88b640136a 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
PiperOrigin-RevId: 665801674
(cherry picked from commit 351593a2504c9185638637a69f8dd0caf4aa20db)
2024-08-21 11:38:36 +00:00
tianyifeng
9b39e3514f Update translations
#cherrypick

PiperOrigin-RevId: 663705597
(cherry picked from commit 1ffc962fdeb6f62afdaa743c412aeefe8674cd75)
2024-08-21 11:35:55 +00:00
ibaker
b184677b7b Check WV version before relying on MediaDrm.requiresSecureDecoder
This method was added in API 31 (S) but it's non-functional
(incorrectly, silently, returns `false`) on the Widevine plugin version
(`16.0`) from R (API 30), which some devices up to at least API 34 are
still using.

This results in ExoPlayer incorrectly selecting an insecure decoder for
L1 secure content, and subsequently calling
`MediaCodec.queueInputBuffer` instead of `queueSecureInputBuffer`,
which is not supported and generates the following error:
> Operation not supported in this configuration: ERROR_DRM_CANNOT_HANDLE

Issue: androidx/media#1603

#cherrypick

PiperOrigin-RevId: 662852176
(cherry picked from commit ca455ee8583938669179b30a686a894b353820eb)
2024-08-21 11:35:55 +00:00
tianyifeng
f139d709c7 Handle preload callbacks asynchronously in PreloadMediaSource
When there is an exception thrown from the `LoadTask`, the `Loader` will call `Loader.Callback.onLoadError`. Some implementations of `onLoadError` method may call `MediaPeriod.onContinueLoadingRequested`, and in the `PreloadMediaSource`, its `PreloadMediaPeriodCallback` will be triggered and then it can further call `continueLoading` if it finds needed. However the above process is currently done synchronously, which will cause problem. By calling `continueLoading`, the `Loader` is set with a `currentTask`, and when that long sync logic in `Loader.Callback.onLoadError` ends, the `Loader` will immediately retry, and then a non-null `currentTask` will cause the `IllegalStateException`.

Issue: androidx/media#1568

PiperOrigin-RevId: 662550622
(cherry picked from commit cd532c5fb290a6f02906a450b06b8bcff3253eb1)
2024-08-21 11:35:51 +00:00
ibaker
07e9c659d7 Handle HEADSETHOOK as 'play' in MediaButtonReceiver.onReceive
Issue: androidx/media#1581

PiperOrigin-RevId: 662515428
(cherry picked from commit c48c051ce29d50411bbc0aaeeae4973354688574)
2024-08-21 11:30:14 +00:00
ibaker
eebf081528 Pass missing length into SubtitleParser from SubtitleExtractor
If the length of the `ExtractorInput` is not known then the
`subtitleData` field is re-sized by 1kB each time
(`SubtitleExtractor.DEFAULT_BUFFER_SIZE`), so the end of the array is
often not populated. This change ensures that `length` is propagated to
`SubtitleParser`, so that implementations don't try and parse the
garbage/zero bytes at the end of the array.

Discovered while investigating Issue: androidx/media#1516

#cherrypick

PiperOrigin-RevId: 661195634
(cherry picked from commit f37f9690f489dbe83366c93c452faf70b272cae3)
2024-08-21 11:23:53 +00:00
michaelkatz
c773789edb Skip invalid media description in SessionDescriptionParser
Some RTSP servers may provide media descriptions for custom streams that are not supported. ExoPlayer should skip the invalid media description and continues parsing the following media descriptions.

To start, ExoPlayer will still error on malformed SDP lines for media descriptions, but will now skip media descriptions with "non-parsable" formats as described by [RFC 8866 Section 5.14](https://datatracker.ietf.org/doc/html/rfc8866#section-5.14).

Issue: androidx/media#1472
PiperOrigin-RevId: 660826116
(cherry picked from commit 8b33ad581140c8d667bf99c1ad754259be56be33)
2024-08-21 11:23:53 +00:00
ibaker
bf934495df Fix IndexOutOfBoundsException in LegacySubtitleUtil
This is caused when the requested "output start time" is equal to or
larger than the last event time in a `Subtitle` object.

This resolves the error in Issue: androidx/media#1516, but subtitles are still not
renderered (probably because the timestamps aren't what we expect
somewhere, but I need to investigate this part further).

#cherrypick

PiperOrigin-RevId: 660462720
(cherry picked from commit 3763e5bc1da5c5cdb458add2e95eb4e683da5b64)
2024-08-21 11:23:53 +00:00
claincly
cd2a36f705 Add a method to disallow VFP destroying shared eglContext
Previously in MultiInputVideoGraph, each VFP would destroy the shared
eglContext, such that the same eglContext object is destroyed multiple times.

Adding a flag to disallow this.

The alternative being we could add a flag on the VFP constructor, but I think
that is too subscriptive (meaning if we later might want to add another boolean
to control another GL behaviour, multiple booleans would make the class less
reason-able), and would incur a lot of code changes at places.

PiperOrigin-RevId: 660354367
(cherry picked from commit 8f8e48731eeedea8636d4d31be4a0c0b9a574bec)
2024-08-21 11:23:49 +00:00
Googler
efb79472ff Fixes README instructions for depending on modules locally
#cherrypick

PiperOrigin-RevId: 659504142
(cherry picked from commit e7eef0ce346d2567e3f51090bb64ee5fe7b8f727)
2024-08-21 11:22:24 +00:00
ibaker
eb19aefa57 Implement MP3 ConstantBitrateSeeker.getDataEndPosition()
This is needed to correctly handle files with trailing non-MP3 data
(which is indicated by the length in the `Info` frame being shorter than
the overall length of the file).

The test file was generated by appending 150kB of `DEADBEEF` onto the
end of `test-cbr-info-header.mp3`, and the test asserts that the
extracted samples are identical.

Issue: androidx/media#1480

PiperOrigin-RevId: 658727595
(cherry picked from commit b09cea9e3a3f9a039b77c6e6db3ee5f450becc50)
2024-08-21 11:22:20 +00:00
Copybara-Service
3dfe43b498 Merge pull request #1548 from kikoso:chore/fixed_links
PiperOrigin-RevId: 657138513
(cherry picked from commit f1ed195c10a124c52309bc49cc479bf35982e74b)
2024-08-21 11:21:02 +00:00
Googler
692ab33640 Add support for Audio Vorbis codec in Mp4Muxer.
Update esdsBox to support muxing of files encoded with Vorbis audio codec .

PiperOrigin-RevId: 655159074
(cherry picked from commit b77f1d0f99b3e287bc82883054b8ce54bab95fee)
2024-08-21 11:21:02 +00:00
dancho
c2d7417ec8 Destroy EGLSurface immediately by focusing a placeholder surface
eglDestroySurface only destroys the surface when it's made not current.
Pass the placeholder surface in FinalShaderProgramWrapper and use it
when destroying eglSurface.

PiperOrigin-RevId: 655139661
(cherry picked from commit 1797359950fbf1acceddd7f40058cbd003383544)
2024-08-21 11:21:02 +00:00
dancho
b6e78f0b2f Ensure EGLSurface is released on GL thread
Add VideoFrameProcessingTaskExecutor.invoke() method that blocks until
Task has executed on GL thread.
Use that for FinalShaderProgramWrapper.setOutputSurfaceInfo

PiperOrigin-RevId: 655119768
(cherry picked from commit 9c075b692e9e76959e47e9ad3cb018d3071f9154)
2024-08-21 11:21:01 +00:00
bachinger
d44500e0fb Add EXTRAS_KEY_DOWNLOAD_STATUS to MediaContants
This was used in media1 `MediaItemDescription` to indicate the download
status of a media item. When connected to a legacy
`MediaBrowserServiceCompat` the Media3 browsers converts the legacy
media item to a Media3 `MediaItem` and converts the extras of
`MediaDescriptionCompat.extras` to `MediaMetadata.extras`.

#cherrypick

PiperOrigin-RevId: 654625502
(cherry picked from commit 225ad482b13f2c9c661f2bf70300cdf948597fdf)
2024-08-21 11:21:01 +00:00
Googler
818e015e05 Add support for Opus audio codec.
Implement dOpsBox to provide support for Opus audio codec

PiperOrigin-RevId: 653288049
(cherry picked from commit 01dda6d3e5fa1737d7587b08a94c01594ed9711e)
2024-08-21 11:21:01 +00:00
Googler
66e977a810 Add support for 3gpp h263 codec in Mp4Muxer.
Implement d263Box to provide support for muxing video encoded with the h263 codec.

PiperOrigin-RevId: 653188633
(cherry picked from commit 951f2968519090bb2a1a1e3dcb9f5dab80958dfb)
2024-08-21 11:21:01 +00:00
Googler
a153d26d8f Add support for 3gpp amr-nb audio codec.
To support AMR audio codec(audio/3gpp) add `0x81FF` mode to create damrBox.

Add unit test and an Android end to end test.

PiperOrigin-RevId: 652438693
(cherry picked from commit 11ca78761e268044abc85e591fb5a8c2be4d2fe1)
2024-08-21 11:21:01 +00:00
ibaker
4070535ba9 Remove stray parenthesis from MediaSession.ControllerInfo.toString()
#cherrypick

PiperOrigin-RevId: 651760391
(cherry picked from commit 2c7f2686b77d9be213cdca70ee4b709d83f43922)
2024-08-21 11:21:01 +00:00
ibaker
09b6e8fd04 Transform double-tap of HEADSETHOOK to skip-to-next
As reported in Issue: androidx/media#1493 we already use `HEADSETHOOK` to start
waiting for a double-tap, but we don't consider it for the second tap.

Similarly, we previously considered `PLAY` for the second tap, but not the first.
Only `HEADSETHOOK` and `PLAY_PAUSE` are
[documented](https://developer.android.com/reference/androidx/media3/session/MediaSession#media-key-events-mapping)
to transform double-tap to `seekToNext`. So this change removes the
`PLAY` detection from the second tap.

PiperOrigin-RevId: 651017522
(cherry picked from commit c64dacf3df9097dc2c4535674a31dac4f568d344)
2024-08-21 11:20:56 +00:00
Googler
0e75a0a5e1 Add support to MPEG4 codec in Mp4Muxer.
Add support for MPEG4 codec to enable muxing video encoded with the mp4v-es codec. Use esdsBox method to generate esds box required for Mp4v box.

PiperOrigin-RevId: 651000744
(cherry picked from commit 34a802ef38e81389471d08c2574c6019d55d14fa)
2024-08-21 11:20:10 +00:00
Googler
70e8e1bf45 Support for Large CodecSpecificData in ESDS box
Some external media files have CodecSpecificData greater than 128 bytes. Currently, that size
isn't fitting in one byte. Hence, added support to store large CodecSpecificDataSize, as per
ISO standard, by extending to more than one byte as required.

PiperOrigin-RevId: 650972472
(cherry picked from commit cf90d2624d114cdd3cbc8516565409dd8bd48cb7)
2024-08-21 11:20:10 +00:00
dancho
0b6249b8ae Destroy eglSurface as soon as Surface changes
eglDestroySurface now unbinds surface from the GL
thread to ensure quick release of resources.

PiperOrigin-RevId: 650938712
(cherry picked from commit 70a6b5d50d359a6d8288a70758ee2a3c402167f9)
2024-08-21 11:20:10 +00:00
Googler
c4bb43517d Add support for amr-wb audio codec.
Implement damrBox to provide support for amr-wb audio codec.

Add unit test and an Android end to end test.

PiperOrigin-RevId: 650210732
(cherry picked from commit 6e18cb00533b9d66f75d36aa0a9b3c873e6f3b26)
2024-08-21 11:20:10 +00:00
Googler
f2d3072d1a Refactor audioEsdsBox to esdsBox
Since the muxer supported only AAC audio codec, the esdsBox was unconditionally created within the audioSampleEntry. This CL refactors the box creation logic by moving it to the codecSpecificBox method. This is to make adding support for new audio codecs easier.

PiperOrigin-RevId: 650130935
(cherry picked from commit a2693553698bf75a6874f2a5bd7fc8b855232372)
2024-08-21 11:20:10 +00:00
ibaker
ae5a7e54ae Fix TTML handling of inherited percentage tts:fontSize values
The percentage should be interpreted as relative to the size of a parent
node.

This change makes this inheritance work correctly for percentages in
both the parent and child. It does not fix the case of a non-percentage
parent size with a percentage child size.

PiperOrigin-RevId: 649631055
(cherry picked from commit bb2fd002aef583b10eba9c497770c87a3be38839)
2024-08-21 11:20:07 +00:00
bachinger
4dc21fd743 Count down three playback states to match the assertion
PiperOrigin-RevId: 648629427
(cherry picked from commit ec3a58f8dba041b780fe6e84ea7106a7298f9090)
2024-08-21 11:18:57 +00:00
ybai001
62e1383a5b Refine code to match the latest branch 2024-08-08 17:25:06 +08:00
ybai001
0f43554db8
Merge branch 'main' into dlb/dovi-transformer/dev 2024-08-08 14:06:28 +08:00
ybai001
ffecefbec2 Fix a bug in HdrEditingTest.java 2024-08-08 13:33:08 +08:00
ybai001
b8d02d9a43 Update code again based on latest comments 2024-08-08 11:13:12 +08:00
ybai001
fd133459f8 Remove unused imported class 2024-08-06 11:19:42 +08:00
ybai001
d8321cd0fd Replace assumeTrue() with @SdkSupress() 2024-08-06 11:09:15 +08:00
ybai001
2822919df6 Update test code based on Google comments 2024-08-05 16:20:03 +08:00
ybai001
6b6d66c7ce Update code based on Google comments 2024-07-29 16:12:29 +08:00
Tianyi Feng
b01c6ffcb3 Merge branch 'release' into release-1.4.0 2024-07-25 14:42:08 +00:00
tianyifeng
9fb7316696 Fix the release notes for 1.4.0 stable release
#cherrypick

PiperOrigin-RevId: 655558346
(cherry picked from commit d70ff7e4d267a3329ed102167eb60d4c4a8e4544)
2024-07-24 14:45:25 +00:00
tianyifeng
4e6a643d88 Update media3 version for 1.4.0 stable release
PiperOrigin-RevId: 653654999
(cherry picked from commit 3c9332bb480b23abc3bd61b96a5f5d6d29a3b11d)
2024-07-19 13:20:28 +00:00
tianyifeng
18a1582e8c Fix the release notes for 1.4.0 stable release
#cherrypick

PiperOrigin-RevId: 653640574
(cherry picked from commit 1cbcd20851c035b4f268d20cb8fa438d0227f162)
2024-07-19 13:15:34 +00:00
tianyifeng
1dfab4f73a Merge release notes for media3 1.4.0 stable release
#cherrypick

PiperOrigin-RevId: 653261278
(cherry picked from commit 68e8d9cb689fae7b862b3383ad3a80eff8ba85ee)
2024-07-19 13:15:34 +00:00
tianyifeng
567204e986 Version bump to 1.4.0-rc01
#cherrypick

PiperOrigin-RevId: 648982615
(cherry picked from commit b531d93b90cf28b455e1cde8625d6764a6a791ae)
2024-07-03 10:25:39 +00:00
ybai001
5eb064d2d1 Add test cases for Dolby Vision transformer support 2024-07-03 16:22:43 +08:00
tianyifeng
75dadeaa9e Update release notes for 1.4.0-rc01
PiperOrigin-RevId: 648745388
(cherry picked from commit 9277a34253799eb83d338313cb3ae6d6f73b5d4d)
2024-07-02 16:57:58 +00:00
tianyifeng
d97ec132b9 Suppress the lint "WrongConstant" error
Lint somehow complains that the integer resulting from the bit-manipulation shouldn't be passed as an @IntDef parameter.

#cherrypick

PiperOrigin-RevId: 648687698
(cherry picked from commit afe3826d7c4b79acfe0fd165ac1940261a147040)
2024-07-02 14:12:52 +00:00
tianyifeng
6946f49997 Add OptIn annotation to method declaration in demo app file
#cherrypick

PiperOrigin-RevId: 648641357
(cherry picked from commit 0510370bd27f8fe3cd43a18dd254b5d59dc89662)
2024-07-02 14:12:52 +00:00
ibaker
5b60f6c67d Fix index out of bounds exception when a Subtitle is empty
Issue: androidx/media#1516

#cherrypick

PiperOrigin-RevId: 648416119
(cherry picked from commit 711d18de0308d4de40516466d3112c8e99c549dc)
2024-07-02 14:12:52 +00:00
bachinger
035c943219 Improve automatic error replication for legacy browsers
This change extends the error replication to a given set of
error codes (not only authentication error), but only
replicates an error if the caller of the service `Callback`
is a legacy controller. It also makes error replication
configurable so that apps can opt-out and report errors
manually instead, or define the error codes for which
replication is enabled.

The change also removes the restriction of `sendError` only
being available for Media3 controllers. Instead, sending an
error to a legacy controller updates the platform playback
state in the same way as sending the error to the media
notification controller.

#cherrypick

PiperOrigin-RevId: 648399237
(cherry picked from commit 70c063905c0831c072cb9e1fa90bfbc1fd70aa68)
2024-07-02 14:12:52 +00:00
tianyifeng
4a319f19e3 Update translations
#cherrypick

PiperOrigin-RevId: 648385733
(cherry picked from commit 6bf2461f803ffc95c0a40c37099a655abf8448ce)
2024-07-02 14:12:52 +00:00
simakova
0df98407d3 Update the composition README file
PiperOrigin-RevId: 648282532
(cherry picked from commit 16ef63cdfc0f42aa445b2dbc22715bde20ac3226)
2024-07-02 14:12:52 +00:00
michaelkatz
bd1704904e Cache audio timestamp frame position across track transition reset
Upon track transition of offloaded playback of gapless tracks, the framework will reset the audiotrack frame position. The `AudioTrackPositionTracker`'s `AudioTimestampPoller` must be made to expect the reset and cache accumulated sum of `AudioTimestamp.framePosition`.

#cherrypick

PiperOrigin-RevId: 647294360
(cherry picked from commit a58e77a5a63d51c8cb9419fc59a7f0c7459fcafe)
2024-07-02 14:12:52 +00:00
tonihei
adeef60c14 Send pending updates before adding discontinuity for error
When handling a playback error that originates from a future item in
the playlist, we added support for jumping to that item first,
ensuring the errors 'happen' for the right 'current item'.
See 79b688ef30.

However, when we add this new position discontinuity to the
playback state, there may already be other position discontinuities
pending from other parts of the code that executed before the
error. As we can't control that in this case (because it's part
of a generic try/catch block), we need to send any pending
updates first before handling the new change.

Issue: androidx/media#1483
PiperOrigin-RevId: 646968309
(cherry picked from commit 727645179b3c26e495540f4445216fd035cc7654)
2024-07-02 14:12:47 +00:00
Copybara-Service
708dc6cab9 Merge pull request #1487 from colinkho:main
PiperOrigin-RevId: 646917527
(cherry picked from commit 6244d8605f48d1b548201a8a964a9879961b3c68)
2024-07-02 14:11:38 +00:00
rohks
0b87e176fd Use removeKey method instead of setting null for KEY_CODECS_STRING
Setting a `null` value doesn't remove the key as expected per the `MediaFormat` API documentation, using the `removeKey` method instead which is only available starting API level 29.

PiperOrigin-RevId: 646462402
(cherry picked from commit 12c42585d25d4c51bc5d022aa282d4d36b8e1ff2)
2024-07-02 14:11:38 +00:00
ibaker
0f0a20bc1c Use MediaCodec.stop() before release() for surface switching bug
ExoPlayer used to call `stop()` before `release()`. This was removed in
<unknown commit>.

A framework bug introduced in Android 11 (API 30) resulted in some
DRM -> clear transitions failing during `MediaCodec.configure()`. An
investigation in Issue: google/ExoPlayer#8696 and b/191966399 identified that this was
due to `release()` returning 'too early' and the subsequent
`configure()` call was then trying to re-use a `Surface` that hadn't
been fully detached from the previous codec. This was fixed in
Android 13 (API 33) with http://r.android.com/2094347.

ExoPlayer worked around the framework bug by adding an arbitrary 50ms
sleep after a failed codec initialization, followed by retrying. This
was enough to resolve the problem in the test scenario on a OnePlus
AC2003.

Issue: androidx/media#1497 points out that 50ms might not be the appropriate delay
for all devices, so it's an incomplete fix. They suggested re-adding the
`MediaCodec.stop()` call instead. This also reliably resolves the issue
on the OnePlus AC2003 (with neither workaround in place, the problem
repros almost immediately).
PiperOrigin-RevId: 646461943

(cherry picked from commit 5fcc7433a1f188c9644d4430a828a49d06c993cb)
2024-07-02 14:11:38 +00:00
tonihei
a73d32a795 Rename DummyTrackOutput and DummyExtractorOutput
#cherrypick

PiperOrigin-RevId: 646434450
(cherry picked from commit 867410fece006122820e26be4e0bea87309a4f2e)
2024-07-02 14:11:38 +00:00
tonihei
0f18fd87ac Add guard against additional tracks reported by Extractors
Extractors should not report additional tracks once they called
ExtractorOutput.endTracks. This causes thread safety issues in
ProgressiveMediaPeriod where the array of sample queues is
extended while the playback thread accesses the arrays.

Detecting this problem early is beneficial to avoid unexplained
exceptions later one. In most cases where this may happen (namely
TS extractors finding new tracks), it's better to ignore the new
tracks instead of failing completely. So this change adds a
warning log message and assigns a placeholder output.

Note: The same workaround already exists in HlsSampleStreamWrapper
and MediaExtractorCompat.

Issue: androidx/media#1476
#cherrypick
PiperOrigin-RevId: 646427213
(cherry picked from commit 18e631ff790e0e9b3630ea8e36efb468474d0877)
2024-07-02 14:11:38 +00:00
Copybara-Service
aa508b1aaf Merge pull request #1479 from dryganets:sdryanets/fix-handler-usage
PiperOrigin-RevId: 646402268
(cherry picked from commit 04667284975e9fc71c137b4a8c133ca5cc626c19)
2024-07-02 14:11:38 +00:00
Copybara-Service
53bb87b7d6 Merge pull request #1416 from khouzam:customFormat
PiperOrigin-RevId: 646121082
(cherry picked from commit b026271c8438f227f4e15e0eaedd7223b4492037)
2024-07-02 14:11:38 +00:00
tonihei
f49fa99aab Add fail-early checks for TrackSelectorResult correctness
The two arrays need to have the same length and the selection
must match in their nullness (unless for TYPE_NONE
renderers). Clarify this more clearly in the docs and add
new asssertions for it. This avoids that the player is failing
in obscure ways much later.

Issue: androidx/media#1473
#cherrypick
PiperOrigin-RevId: 646086833
(cherry picked from commit 71ef848ec3fa4409f3cdf797226c2a51ecd15da6)
2024-07-02 14:11:38 +00:00
okunhardt
ddf188552e In DemoUtil, don't set cookie handler when using HttpEngineDataSource.
HttpEngine does not support cookie storage.

#cherrypick

PiperOrigin-RevId: 646084702
(cherry picked from commit bb568b5150781457fe22c3d4a877e8c99bddc4a2)
2024-07-02 14:11:38 +00:00
tonihei
3a5e367b93 Fix flakiness in MediaCodecVideoRendererTest
The test is flaky because the decoding process in the renderer
depends on some timing from MediaCodec beyond our control and
the new keyframe added in the test is sometimes 'dropped' when
it arrives too late.

We can fix this by controlling the test progress a bit more
tightly: first rendering with the same current time until the
key frame is processed and then start increasing the time
until we've reached the end.

#cherrypick

PiperOrigin-RevId: 646064352
(cherry picked from commit ada4dc982fac32a57db069341f1f51c6a3bb6cc5)
2024-07-02 14:11:38 +00:00
okunhardt
b433bf928b Use HttpEngineDataSource when supported in demo app.
HttpEngineDataSource is the recommended HttpDataSource when it is available. It uses the [HttpEngine](https://developer.android.com/reference/android/net/http/HttpEngine).

#cherrypick

PiperOrigin-RevId: 646051562
(cherry picked from commit e591c37b1e60d5138a612040efba752b7b7ab8e5)
2024-07-02 14:11:37 +00:00
ibaker
9b713907ce Add null-check to PlayerView to avoid NPE in edit mode
Previously we assumed that `surfaceSyncGroupV34` was always non-null on
API 34, but this isn't true in edit mode. Instead we add an explicit
null-check before accessing it. We don't need to null-check it at the
other usage site because we are already null-checking `surfaceView` (via
`instanceof` check).

Issue: androidx/media#1237

#cherrypick

PiperOrigin-RevId: 645008049
(cherry picked from commit 99803066ea6d375f5527e0953aad4ecd91fbac3c)
2024-07-02 14:11:37 +00:00
ibaker
f645e9ccdc Remove direct AspectRatioFrameLayout usage from session demo
This class is a lower-level UI component that isn't directly needed if
apps are using `PlayerView` to handle their video output (it is used as
an implementation detail of `PlayerView`).

Removing its unecessary usages from this demo avoids developers copying
this as an example when building their own apps.

#cherrypick

PiperOrigin-RevId: 644972454
(cherry picked from commit cb8f87e05e73d72ce7d2c405c4c5899dc31ade5e)
2024-07-02 14:11:37 +00:00
tonihei
c14110cdbf Fix audio focus handling in ExoPlayerImpl
Some cases are not handled correctly at the moment:
 - Pausing during suppressed playback should not clear the
   suppression state.
 - Transient focus loss while paused should be reported as
   a playback suppression.

Issue: androidx/media#1436
#cherrypick
PiperOrigin-RevId: 644971218
(cherry picked from commit e84bb0d21cd114c5b726c6c3d799b194df068a14)
2024-07-02 14:11:37 +00:00
tonihei
05571b3e0d Clarify that onPlayWhenReadyChanged can be called again with new reason
Sometimes the reason for the current state may change. If we don't
report this again, users have no way of knowing that the reason
changed.

Also adjust ExoPlayerImpl and MediaControllerImplBase accordingly.
SimpleBasePlayer already adheres to this logic.

#cherrypick

PiperOrigin-RevId: 644970236
(cherry picked from commit 1d26d1891e6e3cd49a4b479723b8aba7be746c1c)
2024-07-02 14:11:37 +00:00
tonihei
2fd6b60daa Move playWhenReadyChangeReason inside PlaybackInfo
This helps to keep the reason always together with the state it
is referring to, avoiding any side channels and making sure there
are no accidental inconsistencies.

#cherrypick

PiperOrigin-RevId: 644969317
(cherry picked from commit c0abd6f91ec62bc5347561c3f3174b3a660a7ba6)
2024-07-02 14:11:37 +00:00
ibaker
30cb76269a Use SurfaceSyncGroup to ensure resize transaction isn't dropped
This workaround is only applied on API 34, because the problem isn't
present on API 33 and it is fixed in the platform for API 35 onwards.

Issue: androidx/media#1237

#cherrypick

PiperOrigin-RevId: 644729909
(cherry picked from commit 968f72fec6d5452a34976824ac822782eeeb8f45)
2024-07-02 14:11:37 +00:00
bachinger
4330d6a952 Use a localized fallback message for known error codes
In the case of a legacy session app providing an error
code different to `ERROR_UNKNOWN` without an error
message, a localized fallback message is provided
instead of ignoring the error.

#cherrypick

PiperOrigin-RevId: 644704680
(cherry picked from commit 6cc6444dd9be34ea3a40d2bb296247178ee86b1d)
2024-07-02 14:11:37 +00:00
bachinger
56ae85fa3c Allow session activity to be set per controller
PiperOrigin-RevId: 644693533
(cherry picked from commit 856d394c281cabc2b1932b003d752631549e7231)
2024-07-02 14:11:31 +00:00
tonihei
bd5f99cb09 Audio focus player command clean up
The 'player commands' returned to ExoPlayerImpl instruct the
player on how to treat the current audio focus state.

The current return value when playWhenReady==false is misleading
because it implies we are definitely not allowed to play as if
we've lost focus. Instead, we should return the actual player
command corresponding to the focus state we are in.

This has no practical effect in ExoPlayerImpl as we already
ignore the 'player command' completely  when playWhenReady=false.

To facilitate this change, we also introduce a new internal
state for FOCUS_NOT_REQUESTED to distinguish it from the state
in which we lost focus.

#cherrypick

PiperOrigin-RevId: 644416586
(cherry picked from commit 66c19390e2b31106a2a467366f7945c37a273fc6)
2024-07-02 14:10:12 +00:00
tonihei
d76316a1f7 Improve audio focus handling tests with ExoPlayer
There are a lot of tests for AudioFocusManager in isolation,
but almost none for the handling in ExoPlayer.

Add test coverage for all the common cases, including some
currently broken behavior that is indicated by TODOs.

PiperOrigin-RevId: 644319251
(cherry picked from commit e20e94fde277a8e9e9a09e502a5760772e9eb006)
2024-07-02 14:10:12 +00:00
michaelkatz
023e9d1479 Version bump to media3:1.4.0-beta01
PiperOrigin-RevId: 644352776
(cherry picked from commit c07bbd333ca88ec93a9efdfcc037e406e1aa4099)
2024-06-27 09:34:04 +00:00
michaelkatz
cfeee5b34e Update release notes for 1.4.0-beta01
#cherrypick

PiperOrigin-RevId: 644351958
(cherry picked from commit 794731607d2fd267d45f8f587812d11e655e59df)
2024-06-18 13:43:30 +00:00
ybai001
7b09e6c1f2 Merge branch 'dlb/dovi-transformer/dev' of https://github.com/DolbyLaboratories/media into dlb/dovi-transformer/dev 2024-06-18 14:00:08 +08:00
ybai001
6acfa0cc68 Add Dolby Vision Transcoding and Editing Support 2024-06-18 13:56:20 +08:00
michaelkatz
32bedfa93e Fix linter errors in DemoMediaLibrarySessionCallback.kt
PiperOrigin-RevId: 644002147
(cherry picked from commit ed07ac5d7de31a610b63d51242fc383d4bad9ffe)
2024-06-17 14:57:01 +00:00
Copybara-Service
f36395ae66 Merge pull request #1437 from MGaetan89:add_exoplayer_setMaxSeekToPreviousPosition
PiperOrigin-RevId: 643987403
(cherry picked from commit 67a7b41fa7453ac4fa06d4d9c7df68e72fbc58ea)
2024-06-17 14:57:01 +00:00
ybai001
78964d0a90 Move AC-4 Level 4 test case to new location 2024-04-11 12:09:51 +08:00
ybai001
64a006b665 Merge branch 'dlb/ac4-level4/dev' of https://github.com/DolbyLaboratories/media into dlb/ac4-level4/dev 2024-04-11 12:01:59 +08:00
ybai001
e41181d4c3 Merge branch 'dlb/ac4-level4/dev' of https://github.com/DolbyLaboratories/media into dlb/ac4-level4/dev 2024-04-11 12:01:36 +08:00
ybai001
ac94afa4b1 Add AC-4 Level-4 ISO base media file format support 2024-04-11 12:01:11 +08:00
ybai001
29bda3bb5c Add AC-4 Level-4 ISO base media file format support 2024-04-11 12:00:45 +08:00
ybai001
b8c559ed32
Merge pull request #8 from androidx/main
Merge latest code from androidx/media main branch
2024-04-11 11:57:29 +08:00
sheenachhabra
d833d59124 Update Media3 version number
PiperOrigin-RevId: 622211426
(cherry picked from commit 2a5b9afb88965dba7b7138e7c721672360149dbd)
2024-04-05 10:09:43 -07:00
sheenachhabra
1792723be2 Update release notes for 1.3.1 bug fix release
PiperOrigin-RevId: 622189733
(cherry picked from commit 5fc35a604559c0230ef220d96f668820d5b34cc8)
2024-04-08 16:56:58 +00:00
sheenachhabra
1a710b06d0 Import string translations
#minor-release

PiperOrigin-RevId: 621828038
(cherry picked from commit d57229ad15836bafe3a6a351eacc95f21ccd8e8b)
2024-04-04 05:34:46 -07:00
ybai001
a5524c09c5 Add Dolby Vision Transcoding and Editing Support 2024-04-02 12:59:06 +08:00
ibaker
5fe906f1e9 Rollback of e665e2aee8
PiperOrigin-RevId: 619871653
(cherry picked from commit b60cd2c0335960f41c47b4d4bb3fa9729e1e4e7d)
2024-03-28 04:00:11 -07:00
Copybara-Service
7b5522fc58 Merge pull request #1054 from jekopena:main
PiperOrigin-RevId: 619573181
(cherry picked from commit 8fe70332ee68faf8945ddb9cf2c897d809af8e49)
2024-03-27 10:24:32 -07:00
ibaker
4caed3cfb2 Add PlayerView.setControllerAnimationEnabled(boolean)
Issue: androidx/media#1227
PiperOrigin-RevId: 619558900
(cherry picked from commit d684cdb330a162aacc6fad813184abe428a3f647)
2024-03-27 09:36:22 -07:00
ibaker
26ce3f012a Fix javadoc on PlayerView.setControllerVisibilityListener
#minor-release

PiperOrigin-RevId: 619536799
(cherry picked from commit ebfd54081738adec29b43b5add3d83109a397a0b)
2024-03-27 08:17:03 -07:00
tonihei
a5d0cb51bc Don't apply performance point workaround from API 35
The workaround check is now part of CTS and we should be able
to rely on the PerformancePoints values (or at least can be sure
that they cover all CDD requirements)

#minor-release

PiperOrigin-RevId: 619201331
(cherry picked from commit 737bf08314a5d1c27762aa1c501d3e132a138e20)
2024-03-26 08:38:31 -07:00
ibaker
88ebc89da2 Plumb MP3 average bitrate from metadata frames into Format
Issue: androidx/media#1081

PiperOrigin-RevId: 619185083
(cherry picked from commit d00ca1e34368c826879e552524ed3f2ca5a25a1b)
2024-03-26 07:36:46 -07:00
ibaker
dca3c61c5b In-line versions only used by exoplayer-media2 extension
Also remove an unused `androidxTestServicesStorageVersion` version.

Issue: androidx/media#1216
PiperOrigin-RevId: 618990983
(cherry picked from commit 6cb25119fb0b20e3fbc80158b9ebcea55d407780)
2024-03-25 16:18:02 -07:00
tonihei
3657831923 Include nullness of MediaMetadata.extras in equals method
This ensures MediaMetadata with just non-null extras is not
considered equal to MediaMetadata.EMPTY. This makes sure the
contents are bundled when a controller sets the extras in a
new MediaItem

Issue: androidx/media#1176

PiperOrigin-RevId: 618876642
(cherry picked from commit ab0391167c867d2607183cda0b03c762dd5e5c0e)
2024-03-25 10:02:23 -07:00
ibaker
06a4036539 Remove unecessary re-setting of group from session Gradle files
These TODOs precede <unknown commit> when the group was set in the top-level
`build.gradle` file.

Issue: androidx/media#1215
PiperOrigin-RevId: 618835040
(cherry picked from commit fd268eed46baefa59901035470246d07e6048062)
2024-03-25 07:30:24 -07:00
tonihei
5fc9ddab0b Partial revert of 3a7d31a599
The original change did not set the color info in the codec
for standard SDR infos. This was meant to help with consistency
to avoid a situation where the information is partially set and
later the bitstream provides slightly different values (all in
standard SDR though).

We can revert this part because the bitstream may change anyway
and the decoder needs to handle this internally. And more
importantly, it also avoids removing this information when encoding
the format again in Transformer.

PiperOrigin-RevId: 617582066
(cherry picked from commit ed505df2cac9a243a29f4d1e170860fb3c66d4aa)
2024-03-20 11:48:23 -07:00
tonihei
b0adf2fe43 Don't set codec color info for default SDR
Some media can read color info values from the bitstream
and may partially set some of the SDR default values in
Format.ColorInfo. Setting these default values for SDR can
confuse some codecs and may also prevent adaptive ABR
switches if not all ColorInfo values are set in exactly the
same way.

We can avoid any influence of HDR color info handling by
disabling setting the color info MediaFormat keys for SDR
video and also avoid codec reset at format changes if both
formats are SDR with slightly different ColorInfo settings.

To identify "SDR" ColorInfo instances, we need to do some
fuzzy matching as many of the default values are assumed to
match the SDR profile even if not set.

Issue: androidx/media#1158
PiperOrigin-RevId: 617473937
(cherry picked from commit 3a7d31a599fdb9716c95d5cbbb599259bb0464f4)
2024-03-20 04:55:06 -07:00
ybai001
563f4d845a
Merge pull request #4 from androidx/main
Merge the code from androidx/media main branch
2024-03-18 11:11:27 +08:00
ibaker
961d204c2c Fix proguard rule for DefaultVideoFrameProcess.Factory.Builder.build()
Issue: androidx/media#1187

#minor-release

PiperOrigin-RevId: 616112879
(cherry picked from commit 48cffc849a8f0f69ca8741c450c7ccb9fd3a0e44)
2024-03-15 06:46:53 -07:00
ibaker
d195b094b4 Don't emit a CuesWithTiming for zero-duration Subtitle events
It's a bit arguable whether the `Subtitle` implementation supports
zero-duration events, since `getEventTimeCount` is documented as
effectively "the number of times the cues returns by `getCues(long)`
changes", and zero-duration events violate that. However, the current
`WebvttSubtitle` impl **does** produce zero-duration events, so it
seems safer to handle them gracefully here and then, as a possible
follow-up, fix the `WebvttSubtitle` impl (or remove it completely).

Issue: androidx/media#1177

PiperOrigin-RevId: 616095798
(cherry picked from commit e9ed874e51f20460c5a73f811a7cf2c61b7530ec)
2024-03-15 05:22:47 -07:00
Copybara-Service
8a169d104f Merge pull request #1117 from loliball:dev_wav_align_fix
PiperOrigin-RevId: 615820438
(cherry picked from commit e9a28beb446e9dfee509ced0ea3550ede3449c01)
2024-03-14 10:17:49 -07:00
andrewlewis
6f0b70ea78 Add short form content demo to project
#minor-release

PiperOrigin-RevId: 615756117
(cherry picked from commit 9da878956a781e15a6d5abfc7eb185c5a4d9f666)
2024-03-14 06:25:23 -07:00
ibaker
860f18f29c Move test-session-xxx modules from core_settings to settings
This ensures these modules are only configured when directly working
on the library, rather than when depending on it locally. These modules
only contain tests, they shouldn't be depended on by any apps (and are
not published via Maven).

PiperOrigin-RevId: 615004801
(cherry picked from commit c41213c273cc526aaccde5fa99336f1fc623e8ef)
2024-03-12 05:30:06 -07:00
michaelkatz
561dafcdea Start playing period-enabled renderers when setting playWhenReady true
Renderers may be enabled for subsequent media items as soon as the current media item's renderer's isEnded() returns true. Currently, when a player is set to pause, it stops all renderers that are `STATE_STARTED`. When a player is set to play, it starts all renderers that are enabled. This would include renderers that were enabled early for the subsequent media item. The solution is to only start renderers that are enabled by the current playing period.

Issue: androidx/media#1017
PiperOrigin-RevId: 614734437
(cherry picked from commit 8b219b0ae69f80764183b680b44a8b0d6b03ed56)
2024-03-11 11:27:26 -07:00
tonihei
c8ae6d1142 Always set PARAMETER_KEY_TUNNEL_PEEK when tunneling
This should already be the default, but some devices seem
to not adhere to this contract and assume the default is unset.

Issue: androidx/media#1169
PiperOrigin-RevId: 614697283
(cherry picked from commit cbed80ecf36d3ff49ec9d2806670f1fda3551aba)
2024-03-11 09:46:07 -07:00
tonihei
3f3d60eb6a Add device-specific opt-ins for async MediaCodecAdapter
Some devices just don't work very well with the synchronous
model, but are currently still excluded from our approximate
API 31 check. This change allows to include additional devices
or device groups by passing in the Context to the default
adapter.

It also adopts the workaround added in ebceee08c6
for Fire TV Smart devices that exhibit this issue.

PiperOrigin-RevId: 614642545
(cherry picked from commit e4a55844d0c99cdfefb37259a8c3bbe0fb9ddc74)
2024-03-11 06:27:15 -07:00
tonihei
fffbf9ac4e Force external surround sound flag if requested by device
Some FireOS6 devices ask to force the external surround global
flag and ignore any signals from the HDMI connection.

This is the equivalent change of e341944d1e

PiperOrigin-RevId: 614634499
(cherry picked from commit 410c0492cc9c7888df7a5283c5ebf8d99bf9c0cc)
2024-03-11 05:52:52 -07:00
tonihei
a85d9e251c Reorder audio capability checks
Using the more accurate check available on later API versions
first is likely better than falling back to a fallback solution
from older API versions.

PiperOrigin-RevId: 614612628
(cherry picked from commit 18cbbf3850df841f0396abcd2c7e5e8196e85bac)
2024-03-11 04:14:31 -07:00
tonihei
a72a23266b Document MergingMediaSource tag contract
Issue: androidx/media#883

#minor-release

PiperOrigin-RevId: 613970048
(cherry picked from commit eb6f607717ce930036f445511414ef21fea5e174)
2024-03-08 10:11:55 -08:00
ibaker
4db96acee6 Add opt-in flag for the MIDI module for apps with a local dependency
PiperOrigin-RevId: 613938538
(cherry picked from commit 4bca1ac47bda83d43bccc3abd7c38266dcd271a8)
2024-03-08 08:13:55 -08:00
ibaker
e55621496c Add workarounds for NoSuchMethodError from DRM framework exceptions
Issue: androidx/media#1145

PiperOrigin-RevId: 613573868
(cherry picked from commit a604600126e87037056a0d93b76b2d99e89544c4)
2024-03-07 07:13:01 -08:00
tofunmi
2dc2e5daf1 Composition: clarify javadoc to setTransmuxAudio\Video
Document that assoicated effects are ignored if these setters are set

PiperOrigin-RevId: 613518167
(cherry picked from commit 5b7774fcaf1498b7c72448fcd0497fcc44efd7cc)
2024-03-07 02:55:30 -08:00
ibaker
41771d7fa3 Set Format.frameRate for single-frame MP4 tracks
Issue: androidx/media#1051
PiperOrigin-RevId: 613516802
(cherry picked from commit afacf2cdb7d5561ef61b97059cd8bb22d8558c58)
2024-03-07 02:49:59 -08:00
michaelkatz
71bfdd1bce Start early-enabled renderers only after advancing the playing period
Renderers may be enabled for subsequent media items as soon as the current media item's renderer's isEnded() returns true. When a renderer is being enabled and the player is 'playing', that renderer is also started. When playing a mixed playlist of images and content with audio & video, the player may skip some image items because the early-starting of the audio renderer causes a clock update.

A solution is to only start the "early-enabled" renderers at the point of media transition and add a condition on DefaultMediaClock to use the standalone clock when reading-ahead and the renderer clock source is not in a started state.

Issue: androidx/media#1017
PiperOrigin-RevId: 613231227
(cherry picked from commit 638b2a3c86f7362041b09faed7c3c09609e29118)
2024-04-05 13:05:36 +00:00
andrewlewis
3fdd3bdb7a Fix typo
PiperOrigin-RevId: 613156951
(cherry picked from commit a90a7049e8e7c9a283e09cca15f0188954712841)
2024-03-06 03:47:22 -08:00
ibaker
b6cb9c1b90 Fix some invalid javadoc references caught by a new JDK version
PiperOrigin-RevId: 612808322
(cherry picked from commit 3a43bd76875e4f18776f5ec3b0043000a763f9cd)
2024-04-02 18:43:29 +00:00
tonihei
672d149a73 Remove invalid command comparison
The removed check searched for a player command inside a list of
session commands, which is not allowed by the IntDef definition
and only worked because both types map to a Java int.

PiperOrigin-RevId: 612758442
(cherry picked from commit c79ac5ba218c685ea6cf284a634899c8327785c8)
2024-04-02 18:36:27 +00:00
Copybara-Service
e28d772423 Merge pull request #1025 from v-novaltd:dsparano-exo209
PiperOrigin-RevId: 612485043
(cherry picked from commit bbdaf2b092c1cf909502fc49fb7bedf7a5b5b9b8)
2024-04-02 18:36:27 +00:00
tianyifeng
cf9ff4de45 Avoid position jumping back when controller replaces the current item
When the controller replaces the current item, the masking position will be changed to the default position of the new item for a short while, before the correct position comes from the session. This will interrupt the current position fetched from the controller when the playback doesn't interrupted by the item replacing.

Issue: androidx/media#951

PiperOrigin-RevId: 611417539
(cherry picked from commit 1bdc58de0be73c14e1b5fdffab64d69da470ffb3)
2024-04-02 18:36:22 +00:00
ibaker
1d2116c53a Add fps-awareness to DefaultTrackSelector
This change aims to prioritise tracks that have a 'smooth enough for
video' frame rate, without always selecting the track with the highest
frame rate.

In particular MP4 files extracted from motion photos sometimes have two
HEVC tracks, with the higher-res one having a very low frame rate (not
intended for use in video playback). Before this change
`DefaultTrackSelector` would pick the low-fps, high-res track.

This change adds a somewhat arbitrary 10fps threshold for "smooth video
playback", meaning any tracks above this threshold are selected in
preference to tracks below it. Within the tracks above the threshold
other attributes are used to select the preferred track. We deliberately
don't pick the highest-fps track (over pixel count and bitrate), because
most users would prefer to see a 30fps 4k track over a 60fps 720p track.

This change also includes a test MP4 file, extracted from the existing
`jpeg/pixel-motion-photo-2-hevc-tracks.jpg` file by logging
`mp4StartPosition` in
[`MotionPhotoDescription.getMotionPhotoMetadata`](b930b40a16/libraries/extractor/src/main/java/androidx/media3/extractor/jpeg/MotionPhotoDescription.java (L123))
and then using `dd`:

```
mp4StartPosition=2603594

$ dd if=jpeg/pixel-motion-photo-2-hevc-tracks.jpg \
    of=mp4/pixel-motion-photo-2-hevc-tracks.mp4 \
    bs=1 \
    skip=2603594
```

----

This solution is in addition to the `JpegMotionPhotoExtractor` change
made specifically for these two-track motion photos in
5266c71b3a.
We will keep both changes, even though that change is not strictly
needed after this one, because adding the role flags helps to
communicate more clearly the intended usage of these tracks. This
change to consider FPS seems like a generally useful improvement to
`DefaultTrackSelector`, since it seems unlikely we would prefer a 5fps
video track over a 30fps one.

Issue: androidx/media#1051
PiperOrigin-RevId: 611015459
(cherry picked from commit c7e00b12b4b3eff6c478d2f4afc7a48bb05d6e7d)
2024-04-02 18:34:46 +00:00
michaelkatz
3521ccda9b Fallback to legacy sizerate check if CDD H264 PerfPoint check fails
Some devices supporting Performance Points for decoder coverage are missing coverage over the CDD requirements for H264. For these cases ExoPlayer should fall back to legacy resolution and frame rate support checks. If there is a stream evaluated as a PerformancePointCoverageResult of COVERAGE_RESULT_NO, then ExoPlayer checks for coverage of the 720p H264 CDD requirement.

Issue: google/ExoPlayer#10898

Issue: androidx/media#693

Issue: androidx/media#966
PiperOrigin-RevId: 609740128
(cherry picked from commit 23a301fc5d3d14593f32c04634d7267c8a86a1cd)
2024-04-02 18:30:13 +00:00
christosts
3c10b41ffa ExoPlayerImplInternal.releaseInternal(): unblock the app thread
This change makes ExoPlayerImplInternal.releaseInternal() unblock the
app thread if a runtime exception is thrown while releasing components
from the playback thread.

Before this change, if a runtime exception occurred during releasing
components in the playback thread, ExoPlayer.release() would wait for
`releaseTimeoutMs` and then raise a player error. With this change,
the player error is reported only when the playback thread is blocked
but if there is a runtime exception, the application thread is
unblocked.

The impact of this change is potentially fewer ANRs on
ExoPlayer.release() at the expense of less error reporting.

PiperOrigin-RevId: 609702549
(cherry picked from commit 0480eff6a15152ae965129e5357d70507c792658)
2024-04-02 18:27:25 +00:00
christosts
25e8dc5e8b ForwardingAudioSink: add override for release()
We forgot to add it when we added AudioSink.release(). The commit
includes a test that ensures ForwardingAudioSink overrides all the
methods defined in the AudioSink interface.

PiperOrigin-RevId: 609402258
(cherry picked from commit 440d2ab162604a5555ebdaa6d71b2f82120b1e09)
2024-04-02 18:24:37 +00:00
michaelkatz
81e91c25f1 Use playing period TrackSelectorResult in track reselection update
If the reading period has already advanced and a track reselection procs that only affects the reading period media, then ExoPlayer may try and apply the reading period's track selection incorrectly unto the playing period. ExoPlayer should apply the playing period's track selection to the playing period instead.

PiperOrigin-RevId: 609375077
(cherry picked from commit 41929246222e9fdb9aa552db526c1b41d26bdb90)
2024-04-02 18:24:37 +00:00
michaelkatz
ed71172ade Allow renderer retry for audio track offload initialization failure
If render error occurs due to AudioTrack initialization failure in offload mode, then ExoPlayer should allow retry as subsequent attempt will be with DefaultAudioSink disabling offload.

PiperOrigin-RevId: 609304897
(cherry picked from commit 9046f2edb62f3dd9bc735405d2a58a98abd87064)
2024-04-02 18:24:33 +00:00
tianyifeng
2ae79959ef Fix a bug in retaining streams when preload a PreloadMediaPeriod again
The `PreloadMediaPeriod.selectTracksForPreloading` can be called for multiple times at the preloading stage (before the period is being played). For example, when the period resumes preloading. This change fix the assertion failure in `ProgressiveMediaPeriod.selectTracks` caused by the wrong implementation of `PreloadMediaPeriod.selectTracksForPreloading` when it is trying to retain the previously preloaded streams.

Also the `TrackSelectorResult` parameter is changed to a list of `ExoTrackSelection`. We should compare the selections only rather than considering the `RendererConfiguration` in the `TrackSelectorResult` to decide whether to retain the streams, as for preloading case the renderers haven't consumed the samples yet.

PiperOrigin-RevId: 609126868
(cherry picked from commit d952a0621471308b0fb545ce7da5067cead0a0df)
2024-04-02 18:21:05 +00:00
michaelkatz
2f47151131 Allow empty information attributes in RTSP Session Description
Issue: androidx/media#1087
PiperOrigin-RevId: 608534659
(cherry picked from commit 52c1d60d39f690b7f3231095fb193510c93fd1ec)
2024-04-02 17:08:26 +00:00
Googler
04ce83691e Fix failure to write negative PTS sample
Fixes an issue caused by no support for negative audio PTS and edit lists
in FrameworkMuxer, Android versions before 11

PiperOrigin-RevId: 607690507
(cherry picked from commit e43f96687c3c6d13907da1a5c53e90ffa57d624c)
2024-04-02 16:57:22 +00:00
ibaker
b218d910ad Fix docs on playUntilStartOfMediaItem to match playUntilPosition
The behaviour and docs of `playUntilPosition` were changed in
00c7a9bcbb.

This change also affects `playUntilStartOfMediaItem` (since it delegates
to `playUntilPosition`), so the same doc change should also be made
here.

#minor-release

PiperOrigin-RevId: 607364897
(cherry picked from commit fa3212e73e5b5f958e6b0aace459d50232e56de5)
2024-04-02 16:41:12 +00:00
claincly
396ae86fdd Fix forward for 216f3fedb8
The original change missed copying the newly added flag in `buildUpon()`, which
caused some test flakes.

PiperOrigin-RevId: 607232373
(cherry picked from commit ae0da442b1f29b9c8c2b64a99d640fa5b2ce5e0f)
2024-04-02 16:41:12 +00:00
ibaker
61a3127468 Demo app: Clarify that only Widevine DRM content can be downloaded
Issue: androidx/media#1085
PiperOrigin-RevId: 606921440
(cherry picked from commit a0727fe4d774739bc3b7d0ef6396365abcdd44ba)
2024-04-02 16:41:12 +00:00
bachinger
879bcb5d99 Check whether the session activity pending intent is an activity
PiperOrigin-RevId: 606613694
(cherry picked from commit 89571c0a9268469f242586af2b964ccd4daf3dee)
2024-04-02 16:41:11 +00:00
tofunmi
c58adb097a Add release notes for recent transformer features
PiperOrigin-RevId: 606565385
(cherry picked from commit caf584152dee959b3425fd5bc4374e7fa9d27226)
2024-04-02 16:41:03 +00:00
claincly
5fd1f61c84 Loosen the requirement to register every input frame
VideoFrameProcessor requires every input frame to be registered before they are
rendered to its input Surface. This CL adds the option to register the input
frame only once. This is useful for camera inputs where not all input frames
come with changing FrameInfo.

PiperOrigin-RevId: 606294894
(cherry picked from commit 216f3fedb857d9a6e0bf846070784c1cc5b7e705)
2024-04-02 16:14:01 +00:00
michaelkatz
c4688fc557 Fallback to including track language name if display name is not found
Issue: androidx/media#988
PiperOrigin-RevId: 606193299
(cherry picked from commit 0b0c419c73b8a67955c6a5244db3ca87244dc4eb)
2024-04-02 16:13:56 +00:00
huangdarwin
2ec19a5da5 HDR: Add color-space conversion for PQ tone-map.
Previously, we missed the BT2020->BT709 color-space conversion.

A user-visible impact of this is that red and green channels used to be
undersaturated, but now are more correctly saturated.

PiperOrigin-RevId: 605411926
(cherry picked from commit a5e47982f4d98e02469f0f0240b5ee1469bff015)
2024-04-02 16:12:42 +00:00
tofunmi
39f26e6041 DefaultAssetLoaderFactory: Simplify file extension retrival
Change the file extension retrieval back to how it was before 5488d33da8 to reduce the change of false negatives in `isImage()`

PiperOrigin-RevId: 605281186
(cherry picked from commit 4d29d8f012410bdacd5fb3c45c5f082a328f4028)
2024-04-02 16:11:10 +00:00
huangdarwin
9825e21a71 Effect: Remove extra checkStateNotNull by reordering logic.
PiperOrigin-RevId: 603660773
(cherry picked from commit ae85ba9ee9fe55c37ffbbad62e010d318ce199d6)
2024-04-02 16:11:10 +00:00
huangdarwin
ecaff24e46 Effect: Use element instead of peek, when throwing if null.
If nullness should result in an exception, we should throw as soon as possible,
so that stack traces are easier to follow.

Did a quick scan of media3.effect+transformer and this covers all uses of
peek that immediately throw there.

PiperOrigin-RevId: 603393366
(cherry picked from commit dd7846ee1cbeb48ddb5495858a71517858df0554)
2024-04-02 16:11:10 +00:00
huangdarwin
bfa492bf4f HDR: Don't assume that swapping between BT709 and BT601 needs tone-map.
VideoFrameProcessor treats BT601 and BT709 as roughly equivalent now, so we
shouldn't be making checks that assume BT709 <-> requires tone-mapping.

Also, the color transfer is a better determinant for tone-mapping than color range, so use just the transfer to determine if tone-mapping is required.

PiperOrigin-RevId: 603083100
(cherry picked from commit cebe6d8ba573c2a636426b18c01837fbec6b00aa)
2024-04-02 16:11:10 +00:00
Ian Baker
d13a0f4ec6 Merge branch 'release' into release-1.3.0 2024-03-07 09:25:30 +00:00
sheenachhabra
99e7156561 Update media3 version for 1.3.0 stable release
PiperOrigin-RevId: 609745599
(cherry picked from commit 9be7a7ab7f5205feece0d6431bc40e534fe9ac9c)
2024-02-26 12:15:21 +00:00
sheenachhabra
c6a6b81d96 Update release notes section for 1.3.0 stable release
PiperOrigin-RevId: 609407248
(cherry picked from commit 82065e699aec9e0b951ef0ad489c0862c95d288b)
2024-02-26 12:15:05 +00:00
sheenachhabra
ee0eac7e31 Fix nit issues in 1.3.0-rc01 release notes
PiperOrigin-RevId: 608580903
(cherry picked from commit ebcb4e8b21b95991d04acffc0bf38fd7895d3f4d)
2024-02-20 16:31:17 +00:00
sheenachhabra
fbf8ac37c3 Version bump to media3:1.3.0-rc01
PiperOrigin-RevId: 605573991
(cherry picked from commit a31a3843931e6b8535062f06fa8675c158a54d86)
2024-02-09 11:39:45 +00:00
sheenachhabra
43ee291172 Update release notes for media3:1.3.0-rc01
#minor-release

PiperOrigin-RevId: 605561427
(cherry picked from commit c4605b3c90d91becb065af53713f88ee7a22858f)
2024-02-09 11:34:02 +00:00
tianyifeng
38d5635818 Report the skipped silence more deterministically
Issue: androidx/media#1035
#minor-release
PiperOrigin-RevId: 605361126
(cherry picked from commit 9b0cdde7d2fe5ee8cb7a6dcb39d432e877b1a9cd)
2024-02-08 19:09:41 +00:00
tonihei
e492e37baa Move release note to the right section
#minor-release

PiperOrigin-RevId: 605310711
(cherry picked from commit e56e27e725bd90e9b062428a9093424ee3cdd675)
2024-02-08 17:30:17 +00:00
ibaker
dbb99fef19 Rollback of 406c0a15be
PiperOrigin-RevId: 605015994
(cherry picked from commit 3a7a665d5df758817be637d026664838ef1af2ea)
2024-02-08 17:30:17 +00:00
ibaker
1dc4377a4b Stop double-encoding CMCD query parameters
`Uri.appendQueryParameter` is documented to encode its arguments, so
calling `Uri.encode` beforehand results in double-encoding.

Issue: androidx/media#1075

#minor-release

PiperOrigin-RevId: 604995441
(cherry picked from commit 7ebfed505c5ac42cb6e614a3dd9b7755af3e92b2)
2024-02-08 17:30:17 +00:00
tonihei
245e6231d9 Set correct track id when skipping empty tracks in Mp4Extractor
The track id must be the index in the list of published tracks
as it's used as such elsewhere. This is currently not true if we
skip an empty track as all subsequent tracks get a wrong or even
invalid id.

#minor-release

PiperOrigin-RevId: 604929178
(cherry picked from commit 5f9c96ab53c571af90457e9f22bac1fe32209bd5)
2024-02-08 17:30:17 +00:00
bachinger
74d0f93dd4 Fix the regex used for validating custom CMCD key names
Relax the regex to only check for hyphen which is required by the specification.

Issue: androidx/media#1028
#minor-release
PiperOrigin-RevId: 604719300
(cherry picked from commit 138532e3fd158e60d50aa85cc1ac2effa388f4eb)
2024-02-08 17:30:17 +00:00
tianyifeng
9f28e7d81b Improve AudioCapabilities with AudioManager API in Android 13
PiperOrigin-RevId: 604700601
(cherry picked from commit ccd603acb067c560840f7aa1499556733e204c39)
2024-02-08 17:30:17 +00:00
ibaker
bf8b8749fe JpegMotionPhotoExtractor: Don't emit an image track with no metadata
The current implementation of `JpegMotionPhotoExtractor.sniff` returns
`true` for any image with Exif data (not just motion photos). Improving
this is tracked by b/324033919. In the meantime, when we 'extract' a
non-motion photo with `JpegMotionPhotoExtractor`, the result is
currently a single empty image track and no video track (since there's
no video, since this isn't a motion photo). This 'empty' image track
is usually used to transmit metadata about the video parts of the
image file (in the form of `MotionPhotoMetadata`), but this metadata is
also (understandably) absent for non-motion photos. Therefore there's
no need to emit this image track at all, and it's clearer to emit no
tracks at all when extracting a non-motion photo using
`JpegMotionPhotoExtractor`.

This change also removes a `TODO` that is misplaced, since there's no
image bytes being emitted here (and never was).

PiperOrigin-RevId: 604688053
(cherry picked from commit 7ae3d69e001d0a138f3ebe406b050bc06bd24724)
2024-02-08 17:30:16 +00:00
ibaker
7721f387ca Check sampleMimeType rather than containerMimeType for images
These are often the same for image tracks, since we usually drop the
whole image file (both the container and actual encoded image bytes)
into a single sample, but there are cases where we emit a track with
`containerMimeType=image/jpeg` but **no** samples (from
`JpegMotionPhotoExtractor`, to carry some metadata about the image +
video byte offsets).

It's therefore more correct to implement the `supportsFormat` check
based on `sampleMimeType`, so that these 'empty' image tracks are not
considered 'supported' by `ImageRenderer`.

#minor-release

PiperOrigin-RevId: 604672331
(cherry picked from commit eabba49610b8f93ed92450baf55da01e5a8b23b2)
2024-02-08 17:30:16 +00:00
bachinger
dc8d3eaf30 Add constructor that takes only a Context
#minor-release

PiperOrigin-RevId: 604659845
(cherry picked from commit c2273345c51731ba3950298c4f8a8f02957062b7)
2024-02-08 17:30:16 +00:00
tonihei
ca2779e774 Add source prefix to MergingMediaPeriod Format ids
This was already done for the TrackGroup ids in <unknown commit>,
but in some scenarios only the Format instances are known and
it's helpful to be able to identify where they came from.

Issue: androidx/media#883

#minor-release

PiperOrigin-RevId: 604644039
(cherry picked from commit f8f6d80477241a1f2a65e548855f94eeb5389c96)
2024-02-08 17:30:16 +00:00
tonihei
a294dc9bc5 Include nullness of RequestMetadata.extras in equals method
This ensures RequestMetadata with just non-null extras is not
considered equal to RequestMetadata.EMPTY. This makes sure the
contents are bundled when a controller sets the extras in a
new MediaItem.

PiperOrigin-RevId: 604632788
(cherry picked from commit 766a15a51e5e09e6e5f5df5d53bf603e167af3d3)
2024-02-08 17:30:16 +00:00
ibaker
ad57b41da1 Clearly define the consistency requirements for SequenceableLoader
Add a test for this consistency in `CompositeSequenceableLoaderTest`,
and also make the
`CompositeSequenceableLoaderTest.FakeSequenceableLoader` implementation
more realistic.

#minor-release

PiperOrigin-RevId: 604604103
(cherry picked from commit db74bb9609a59b70a6a477f4abb2af61bba19aa2)
2024-02-08 17:30:16 +00:00
Googler
4a952170a2 Fix Kotlin 2.0 compilation error in session demo app
Since Kotlin 2.0 the compiler became better at detecting incorrect
annotation applications. The @OptIn annotation can't be applied to an
expression, so when compiling with Kotlin 2.0 it results in an error.

PiperOrigin-RevId: 604596657
(cherry picked from commit 718cf1299b805339b605bf268fce0ad9158c44f5)
2024-02-08 17:30:16 +00:00
ibaker
4eea69dd46 Merge Cea608Parser back into Cea608Decoder
This reverses 27caeb8038

Due to the re-ordering of packets done in `CeaDecoder`, there's no way
to use the current implementation to correctly parse these subtitle
formats during extraction (the `SubtitleParser` interface), so we have
to keep the `SubtitleDecoder` implementations.

#minor-release

PiperOrigin-RevId: 604594837
(cherry picked from commit 25498b151ba298ef359f245e2ed80718b4adf556)
2024-02-08 17:30:16 +00:00
ibaker
dd2e4a5978 Merge Cea708Parser back into Cea708Decoder
This reverses 94e45eb4ad

Due to the re-ordering of packets done in `CeaDecoder`, there's no way
to use the current implementation to correctly parse these subtitle
formats during extraction (the `SubtitleParser` interface), so we have
to keep the `SubtitleDecoder` implementations.

#minor-release

PiperOrigin-RevId: 604350951
(cherry picked from commit 51b4fa2cc83b60fcb313fd0e6afd2d45fe64e535)
2024-02-08 17:30:16 +00:00
tonihei
548c4ce799 Fix HlsPlaybackTest flakiness
The new test introduced in 45bd5c6f0a is flaky because we only
wait until the media is fully buffered. However, we can't fully
control how much of this data is initially read by the Robolectric
codec and thus the output dump files (containing these codec
interactions) are flaky.

This can be fixed by fully playing the media once and then seeking
back instead.

#minor-release

PiperOrigin-RevId: 603324068
(cherry picked from commit e3e57c9b9943fd160105001b2e8e26782173843e)
2024-02-08 17:30:16 +00:00
michaelkatz
7758e422aa Render last image despite not receiving EoS
If seeking between last image sample and end of the file where the current stream is not final, then EoS sample will not be provided to `ImageRenderer`. ImageRenderer must still produce the last image sample.

PiperOrigin-RevId: 603312090
(cherry picked from commit 62c7ee0fb0f4def17a18233c0fd40958d646c82b)
2024-02-08 17:30:16 +00:00
Copybara-Service
127d0b5f3c Merge pull request #1011 from cedricxperi:dts-lbr-hls-bitrate-unknown-fix
PiperOrigin-RevId: 603302863
(cherry picked from commit f85860c04196875150e24b071f08b193b10f27c9)
2024-02-08 17:30:16 +00:00
Copybara-Service
ad519e2e7e Merge pull request #1015 from kamaroyl:feat/PsshVersion1
PiperOrigin-RevId: 603016920
(cherry picked from commit dfcc2cb41da3a03f027417e8dc26c5dc83b726e5)
2024-02-08 17:30:16 +00:00
Copybara-Service
3d87578779 Merge pull request #1031 from garethfenn:hlschunkseek
PiperOrigin-RevId: 603008793
(cherry picked from commit 45bd5c6f0a24b24282bdb971a3a780a9923eff01)
2024-02-08 17:30:04 +00:00
claincly
a18d96c320 Fix blank video when switching on/off screen
This happens when using `ExoPlayer.setVideoEffects()`.

This CL also fixes the first frame not rendered problem, originally solved in
7e65cce967, but rolled back in 5056dfaa2b because the solution introduces
the flash that is observed in b/292111083.

Before media3 1.1 release, the output size of `VideoFrameProcessor` is not
reported to the app. This was changed later after introducing
`CompositingVideoSinkProvider`, where the video size after processing **is**
reported to the app. After this CL, the size is again, not reported.

PiperOrigin-RevId: 602345087
(cherry picked from commit dcae49a561d3dd0a67a44a913c063b0232bbc445)
2024-02-08 17:29:13 +00:00
tonihei
dfe47219f9 Update skip silence algorithm
The updated algorithm has two main improvements:
 - The silence padding is not constant but a ratio of the original
   silence (up to a defined max) to more naturally represent the
   original gaps.
 - The silence is not instantly going to zero, but uses a ramp down
   and up for a smooth volume transition and also retains a small
   percentage of the original noise for more natural "silences" that
   still contain some background noise.

#minor-release

Issue: google/ExoPlayer#7423
PiperOrigin-RevId: 602322442
(cherry picked from commit bb533332f4b6f46ac9d5ca17cb7943bd1bdb7dd2)
2024-02-08 17:29:12 +00:00
jbibik
826f20dbbd Remove a redundant TODO in Util
PiperOrigin-RevId: 601820851
(cherry picked from commit eb3173aa90a4e7d9438f46ef21a6696ddc0d0129)
2024-02-08 17:29:12 +00:00
tonihei
4560611bd0 Remove misleading @CanIgnoreReturnValue
The return value of onConfigure must not be ignored as it specifies
the output format of the processor, which may be different from the
input format.

#minor-release

PiperOrigin-RevId: 601799440
(cherry picked from commit 2fc5590e7aa5890f22d020778f924e1586a3f3ba)
2024-02-08 17:29:12 +00:00
tonihei
4a7442ef3a Replace or suppress deprecated usages
Many usages are needed to support other deprecations and some
can be replaced by the recommended direct alternative.

Also replace links to deprecated/redirected dev site

PiperOrigin-RevId: 601795998
(cherry picked from commit ed5b7004b435f71c5a37f5db12c3641fbba9be48)
2024-02-08 17:29:12 +00:00
ibaker
0886da450d Add a comment to suggest keeping JUnit version in sync with the Android
source tree - to make importing GTS tests easier.

PiperOrigin-RevId: 601725811
(cherry picked from commit 373822ce45c795b3f12209048b20244e271548a9)
2024-02-08 17:29:12 +00:00
Googler
ddca0116b2 Update IMA README to include link to supported platforms
PiperOrigin-RevId: 601720412
(cherry picked from commit 807d98a3d68447dce72657c8f0b12a9243ef8d86)
2024-02-08 17:29:12 +00:00
sheenachhabra
4570ee9275 Fix link to 1.3.0-alpha01 release
PiperOrigin-RevId: 601469906
(cherry picked from commit 605689a02016eb1594f9fbbeb8c121d5f327a287)
2024-01-26 11:15:09 +00:00
sheenachhabra
7822613cc6 Version bump to media3:1.3.0-beta01
PiperOrigin-RevId: 601441910
(cherry picked from commit 21ab474260714b2ec63c5cdfb8040e45072b19e2)
2024-01-25 16:23:46 +00:00
ibaker
4382aa0b34 Make Cea608Parser and Cea708Parser package-private
It's likely that we will merge these back into their `XXXDecoder`
implementations, but this smaller change allows us to avoid including
these public symbols in the upcoming release.

#minor-release

PiperOrigin-RevId: 601432629
(cherry picked from commit 12157a6b1aba2c59c54e6b7d34bad396008b5f29)
2024-01-25 16:20:26 +00:00
sheenachhabra
e29e775732 Update release notes for Media3 1.3.0-beta01 release
#minor-release

PiperOrigin-RevId: 601408404
(cherry picked from commit 79b0b8090c806f8ee951663f9a85a68f70735f1d)
2024-01-25 16:20:26 +00:00
ibaker
8770286a8e Throw immediately from ExoPlayer.setVideoEffects() if dep not found
This method works by reflectively loading classes from the `lib-effect`
module, in order to avoid a hard dependency on this module for ExoPlayer
users that don't want video effect functionality. This change ensures
that a failure to load the necessary classes fails immediately, instead
of on a later thread inside `MediaCodecVideoRenderer` when the
reflection currently happens.

Also update the javadoc to make the dependency requirement clear.

#minor-release

PiperOrigin-RevId: 601387957
(cherry picked from commit a6812156e6ea5ea2dc45d222f402065c0da46b62)
2024-01-25 11:42:44 +00:00
jbibik
748fec1ac6 Add a setter of SubtitleParser.Factory to MediaSource.Factory
DASH: `DashMediaSource.Factory` would only propagate it to `DashChunkSource.Factory` -> `BundledChunkExtractor.Factory`

SS: `SSMediaSource.Factory` -> `SsChunkSource.Factory`

HLS: `HlsMediaSource.Factory` -> `HlsExtractorFactory`

Remove nullability of SubtitleParser.Factory across the stack

#minor-release

PiperOrigin-RevId: 601250013
(cherry picked from commit f103a2dcf565a311b94171e5714e4ee8ad8c5f65)
2024-01-25 11:42:44 +00:00
christosts
55e3dd77c6 Rollback of e364510937
PiperOrigin-RevId: 601187997
(cherry picked from commit 85db94782a6106f186348a0c35e4423cdda0e07e)
2024-01-25 11:42:44 +00:00
jbibik
0713d56efc Add setters of SubtitleParser.Factory and experimental toggle
The `SubtitleParser.Factory` is no longer @Nullable and the experimenting toggle is used to enable/disable the use of this factory for subtitle parsing during extraction.

The three places that will hold the "truth" for the `SubtitleParser.Factory` are: BundledChunkExtractor.Factory, SsChunkSource.Factory, DefaultHlsExtractorFactory

DASH: `DashMediaSource.Factory` would only propagate it to `DashChunkSource.Factory` -> `BundledChunkExtractor.Factory`

SS: `SSMediaSource.Factory` -> `SsChunkSource.Factory`

HLS: `HlsMediaSource.Factory` -> `HlsExtractorFactory`

#minor-release

PiperOrigin-RevId: 601151615
(cherry picked from commit 4d7b23f0d117a67df33f5cab25d5971a72dc8017)
2024-01-25 11:42:44 +00:00
sheenachhabra
9581af110a Write "stco" box instead of "co64" for fragmented MP4
As per MP4 spec ISO 14496-12: 8.7.5 Chunk Offset Box, Both "stco" and
"co64" can be used to store chunk offsets. While "stco" supports 32-bit
offsets, "co64" supports 64-bit offsets.
In non fragmented MP4, the mdat box can be extremely large, hence muxer
uses "co64" box.
But for fragmented MP4, muxer does not write any data in this chunk offset
box (present in "moov" box) because all sample related info is present in
"moof" box.
Technically, "co64" box should also work in fragmented MP4because
its empty only but QuickTime player fails to play video if "co64"
box is present in fragmented MP4 output file.

Testing: Verified that QuickTime player does not play video when "co64"
box is present but is able to play when "stco" box is present.

#minor-release

PiperOrigin-RevId: 601147046
(cherry picked from commit 0acf6902e57678dc9e6ea8de3a4b3b88b9ec0519)
2024-01-25 11:42:44 +00:00
jbibik
db420350f8 Remove SubtitleParser.Factory references from Hls/Ss/DashMediaPeriod
Those classes only needed to have access to a `SubtitleParser.Factory` to get a potentially updated `Format` for TrackGroups. The `SubtitleParser.Factory` was only used to check the support for the `mimeType` and getting some cue-related behaviour.

This introduced complexity in a way that both Periods and Extractors needed to have the same `SubtitleParser.Factory` in their individual stacks. To ensure that the sample queue would get the same transcoded/original format.

Instead, now we expose `getOutputTextFormat` methods on `ChunkExtractor.Factory`, `SsChunkSource.Factory` and `HlsExtractorFactory`. Those are the dependencies that Hls/Ss/DashMediaPeriod can make use of to delegate the format-updating logic to.

#minor-release

PiperOrigin-RevId: 601130714
(cherry picked from commit 966b7108976706c1b0a1a8a2b82ae8daa747bda3)
2024-01-25 11:42:44 +00:00
rohks
cfb676adaf Add Mp4ExtractorTest for sample with edit list (edts box)
The sample has multiple sync frames for video track.

PiperOrigin-RevId: 601129350
(cherry picked from commit f8dbbc82e2a36c4207b8408bd30d1b37dfd80eca)
2024-01-25 11:42:44 +00:00
sheenachhabra
539a8f9a24 Write sample data offset related fields in tfhd and trun box
This fix makes output playable on VLC player.
The output does not play on QuickTime player which is being fixed in
a separate CL.

#minor-release

PiperOrigin-RevId: 601118813
(cherry picked from commit 806f90922b0d327f1f85e677ac2d9555415d60a4)
2024-01-25 11:42:44 +00:00
michaelkatz
db0262efdb Keep stream offset alive in ImageRenderer until stream transition
Fix modeled after OutputStreamInfo usage for stream offset in `MediaCodecRenderer`

PiperOrigin-RevId: 601109900
(cherry picked from commit 688622eb47ac707affa824d3d68f44755f947380)
2024-01-25 11:42:44 +00:00
tofunmi
a6756c6d40 MuxerWrapper rotation degree fix
Allow setAdditionalRotationDegrees to be called with same rotation after tracks added. This is needed for processes that mux files partially trim optimization so they don't error out after hitting the check state

Manually tested to ensure trim optimization succeeds, automated test added here as well

PiperOrigin-RevId: 601081778
(cherry picked from commit b94c7d08c13210d16725b774f2eda8b1b808e2ab)
2024-01-25 11:42:44 +00:00
ibaker
97b8f1add9 Add proguard keep rules for ExoPlayer.setVideoEffects
These symbols in `lib-effect` are referenced via reflection from
`CompositingVideoSinkProvider` in `lib-exoplayer` in order to avoid
a hard dependency from `lib-exoplayer` to `lib-effect`. Without this
keep rule, the symbols can get renamed by R8 resulting in the
invocations failing.

#minor-release

PiperOrigin-RevId: 601074636
(cherry picked from commit e5621cc70960bf76c5651f6f368f78aeacac82b3)
2024-01-25 11:42:44 +00:00
timpeut
be0d531857 Suppress nullability warnings
PiperOrigin-RevId: 600891113
(cherry picked from commit 9c1aaa7c4341db3de4c59c3068748bd2e4e76959)
2024-01-25 11:42:44 +00:00
tianyifeng
733c982a21 Change the behaviour in MediaMetadata.Builder.populate
Populate both `artworkUri` and `artworkData` in
`MediaMetadata.Builder.populate(MediaMetadata)` when at least one of them is non-null.

Issue: androidx/media#964
PiperOrigin-RevId: 600826103
(cherry picked from commit 35ac46b92e627c16245d8cdec6fd4260b4c0f8ac)
2024-01-25 11:42:44 +00:00
sheenachhabra
426dd77ac0 Suppress lint warning about missing POST_NOTIFICATIONS permission
For media session related notifications, permission is not required.
https://developer.android.com/develop/ui/views/notifications/notification-permission#exemptions-media-sessions

#minor-release

PiperOrigin-RevId: 600819251
(cherry picked from commit b98e5ac0d468770ef1a60fa853ff1463d2fffe93)
2024-01-25 11:42:44 +00:00
sheenachhabra
081baa03b9 Process all tracks before writing fragment in fragmented MP4
Earlier implementation processed each track (pending sample's buffer info)
individually when writing their corresponding "traf" box in a fragment.
The change involves processing all tracks before start writing "traf" boxes.

#minor-release

PiperOrigin-RevId: 600811093
(cherry picked from commit 4c1581a17542f56db9fd85e0c7a6894aef57be52)
2024-01-25 11:42:44 +00:00
tonihei
a1280b1a23 Add setRemotePlaybackInfo to MediaStyle
This method is needed for some system apps to override the
output switcher when MediaRouter2 can't be used.

PiperOrigin-RevId: 600807119
(cherry picked from commit b64d75467010b727d3e201120643becab73fe491)
2024-01-25 11:42:44 +00:00
siroberts
193cb143ff Change type of setCustomLayout in MediaSession.resultBuilder to List
PiperOrigin-RevId: 600801528
(cherry picked from commit 1f78aa5b2a71e468338b489980c5a1375f4dff80)
2024-01-25 11:42:44 +00:00
tonihei
236287a513 Use Media3 MediaStyle instead of legacy one
The default notification provider was still using the legacy
compat MediaStyle instead of our own Media3 one. They are fully
equivalent in their implementation and API and can be swapped out
easily.

PiperOrigin-RevId: 600797920
(cherry picked from commit 9448f939f432d17337e2ecba3a14caa0c322c4eb)
2024-01-25 11:42:43 +00:00
tianyifeng
3a222473e9 Internal change
PiperOrigin-RevId: 600784733
(cherry picked from commit 0c0b19e26e506763af95a53c916fdbf853f81cec)
2024-01-25 11:42:43 +00:00
ibaker
8e97895e9f Test parsing-during-extraction in ClippedPlaybackTest
We keep the previous parsing-during-rendering tests, even though they
can be a bit flaky, because this is an important regression test. The
regression risk is lower for this instrumentation test compared to
robolectric tests with different `ShadowLooper` behaviour.

#minor-release

PiperOrigin-RevId: 600781035
(cherry picked from commit a53f3451ddef819c5b0fb5ff1e9952a98a56bfc3)
2024-01-25 11:42:43 +00:00
tofunmi
b8ff9cd715 Update METADATA to add clang-format requirement for glsl files
also ran clang-format for good measure

PiperOrigin-RevId: 600759938
(cherry picked from commit acc78125d20b3f36859ceb6099c99f0ec251b00d)
2024-01-25 11:42:43 +00:00
tofunmi
eda2080279 BaseGlShaderProgram: Remove redundant NoSuchElementException catching
PiperOrigin-RevId: 600738198
(cherry picked from commit cc62f0556c040e071741690ae31c4982e5efbbfc)
2024-01-25 11:42:43 +00:00
ibaker
dd9f61005e Release MediaSession and ExoPlayer in MediaControllerStubTest
Due to poor isolation between the session tests, in particular the
static state in `MediaSession.SESSION_ID_TO_SESSION_MAP`, an unreleased
session at the end of one test can cause subsequent tests to fail with
obscure errors like `Session ID must be unique`.

#minor-release

PiperOrigin-RevId: 600737697
(cherry picked from commit ca61ac6ca35427a697a6645c90cc8e12889c78f7)
2024-01-25 11:42:43 +00:00
tofunmi
21e6c1c43e Transformer demo: support selecting all media MIME types
It's useful for development and debugging to select a local image
or audio (only) file as well as a video file in the transformer demo
app.

I tested manually that you can select a local video, audio and image
but not e.g. a pdf with the main "choose local file" picker and only
an image with the choose local image picker for the bitmap overlay
demo.

PiperOrigin-RevId: 600722622
(cherry picked from commit 94ce356bc1bea34edeba02181f3793ec7da7c2f4)
2024-01-25 11:42:43 +00:00
tofunmi
fce23d9d4e Trim optimization fix: check if audio is removed when comparing formats
#minor-release

PiperOrigin-RevId: 600493390
(cherry picked from commit 5863ce7dd57e3a90d220bbab9ab1555e9e81b76d)
2024-01-25 11:42:43 +00:00
tonihei
5ac0c8beee Fix cleared metadata when repeating the same item
Issue: androidx/media#1007

#minor-release

PiperOrigin-RevId: 600477540
(cherry picked from commit c6bf380d50d4601ce6ec567ebd56ccf5e36fa8cf)
2024-01-25 11:42:43 +00:00
sheenachhabra
50e0072dac Do not write empty track (with no samples) in a non fragmented MP4
PiperOrigin-RevId: 600453680
(cherry picked from commit 94bf9fa81d836b25cb893cf09e71045b3bbeef8a)
2024-01-25 11:42:43 +00:00
tonihei
6632531c4a Catch exceptions when retrieving current device from audio manager
We can just continue to assume that we don't know the current device.
This case happens on the latest Robolectric release where this method
call isn't implemented yet. As we not generally assume that the
method can throw, this workaround can be removed once Robolectric
is updated again.

#minor-release

PiperOrigin-RevId: 600426851
(cherry picked from commit 81615dd5b56dddc008401a7a8513baf5336c01b6)
2024-01-25 11:42:43 +00:00
christosts
05b8e633e3 SimpleBasePlayer: add protected method for thread verification
Add protected method in SimpleBasePlayer for thread verification to help
subclasses verify thread access for additional methods they define and
still report the same message to the user.

Also, remove the DAC link pointing to the ExoPlayer-specific
documentation from the exception message. Users who extend
SimpleBasePlayer have access to the class' javadoc.

PiperOrigin-RevId: 600426692
(cherry picked from commit 9e9c3cbe5e1576e89ef1f5492b2c14865bc1ddbe)
2024-01-25 11:42:43 +00:00
andrewlewis
18617b8a60 Prevent using high profile on problematic devices
[Android best
practices](https://developer.android.com/media/optimize/sharing#android_8_81_and_9)
recommend disabling B-frames on API 27, but some devices output B-frames anyway
when H.264/AVC High profile is selected. Add a workaround to force these
devices not to use high profile, to prevent B-frames being output.

`MediaMuxer` likely handles B-frames on these specific devices, but this change
allows the migration to default to in-app muxing to take place without
introducing errors, and it's a temporary workaround until B-frames are properly
supported in the in-app muxer.

PiperOrigin-RevId: 600422238
(cherry picked from commit 60295218985952a627764e1c3a6fce919f52ed4c)
2024-01-25 11:42:43 +00:00
tonihei
3e005e62dc Check int and float parameters from external apps for validity
Some player method calls sent from MediaControllers accept int
or float values with a very clear API contract that disallows
some values. Filtering by these values early avoids calling a
Player implementation with invalid values.

PiperOrigin-RevId: 600413993
(cherry picked from commit c64b271f077939abcd33353efb50f1b0b2ca7588)
2024-01-25 11:42:43 +00:00
ibaker
da5e5db3d2 Disable 'skip buffers with identical release times' in GTS tests
This optimization always reports buffers as 'skipped' (i.e. deliberately
not shown), which makes sense for the target case of high FPS content on
a lower refresh rate screen, when lots of the frames will **never** be
shown.

However the optimization also results in reporting buffers as 'skipped'
when decoding is a bit slow, resulting in a frame being released one
vsync late, which then means we have two frames to release in the same
vsync (when the previous vsync was empty). In this case, it would be
more correct to report this as a 'dropped' frame (since it was due to
slow decoding).

Until we can change the logic to distinguish these cases and report them
separately, this CL disables the optimization completely in GTS tests.
This is needed because we often assert there were zero skipped frames,
so slight decoding slowness can cause spurious/flaky test failures (our
threshold for dropped frames is non-zero).

#minor-release

PiperOrigin-RevId: 600406443
(cherry picked from commit 999e154b2aa8cd6845cdbad2a708280f0069dac7)
2024-01-25 11:42:43 +00:00
tonihei
5b7b19cf3c Add TODO about known feature gap in ImageRenderer
PiperOrigin-RevId: 600404546
(cherry picked from commit b84104e7a1479ef31c9c4b02154d0dd3b031b736)
2024-01-25 11:42:43 +00:00
andrewlewis
515d2e2578 Skip 1080p test on Nexus 7, API 21
This device doesn't seem to be capable of simultaneous encode/decode at this
resolution. We don't have a good way to check the capability (we are already
checking separate decode/encode capability) so just skip this test to save time
triaging its failures.

PiperOrigin-RevId: 600399564
(cherry picked from commit e82393ed4108cb34e7b655bad8d098ddafd7652b)
2024-01-25 11:42:43 +00:00
christosts
1dc880cb3b Rollback of e364510937
PiperOrigin-RevId: 600393114
(cherry picked from commit d1d03189ebbb1dd1bb843afd135dadf0d57a2d09)
2024-01-25 11:42:43 +00:00
tonihei
432cde6051 Use routed device in AudioCapabilities
From API 23, we may have a preferred device that is most likely used
as the output device.
From API 24, the AudioTrack tells us the actual routed device that is
used for output and we can listen to changes happening mid-playback.
From API 33, we can directly query the default device that will
be used for audio output for the current attributes.

If the routed device is known by any of the methods above, we can add
more targeted checks in methods like isBluetoothConnected to avoid
iterating over all devices that are not relevant.

The knowledge about the routed device will also be useful to check
advanced output capabilities in the future (e.g. for lossless
playback)

PiperOrigin-RevId: 600384923
(cherry picked from commit b1c954fa844e25f2c65f9f3865dbb62afaee592d)
2024-01-25 11:42:43 +00:00
huangdarwin
dcfa8c60ce Previewing: set VideoFrameReleaseControl after CVSP is created.
This allows us to inject a videoFrameProcessorFactory into
MediaCodecVideoRenderer, without issues about creating the
VideoFrameReleaseControl in the MediaCodecVideoRenderer.

Unfortunately, this does result in more complex CVSP state, where
VideoFrameReleaseControl is no longer final, may be null, and may potentially
change. However, this tries to be careful with assertions to guarantee good
state, and is cleaner than modifying the long-standing MediaCodecVideoRenderer
interface.

Tested that this works on the ExoPlayer demo with setVideoEffects applied, and
using a playlist with SDR->HDR and HDR->SDR items.

PiperOrigin-RevId: 599823412
(cherry picked from commit cb0f5a7fffdf519f5888255be7a5f3aefe5680a7)
2024-01-25 11:42:43 +00:00
samrobinson
4ac9d449d3 Remove thread blocking for TransformerInternal#getProgress.
Thread-safe interactions with state and value.

PiperOrigin-RevId: 599810672
(cherry picked from commit e364510937ac1f3c4eb14fc34d2d772a64645ced)
2024-01-25 11:42:43 +00:00
Michael Katz
b930b40a16
Fix merge error with ffmpeg_jni.cc
Fix merge error with ffmpeg_jni.cc where cherry-pick process included code from nonselected commit.
2024-01-17 17:04:10 +00:00
michaelkatz
0ae7a6bd60 Fix typo of missing closing parentheses in RELEASENOTES
PiperOrigin-RevId: 597496311
2024-01-11 10:48:31 +00:00
michaelkatz
1f79a0ad93 Bump media3 version to 1.2.1 and update RELEASENOTES
PiperOrigin-RevId: 596916027
(cherry picked from commit 324e1beef2402e765b17f8225692245be62972c8)
2024-01-09 14:46:23 +00:00
microkatz
f0d24cbf58 Fix BitmapOverlay to have public constructor 2024-01-09 12:26:11 +00:00
ibaker
d55b33474e Clarify docs on Player.setMediaItem(s) and replaceMediaItem(s)
These methods sound similar, but have different behaviour. This change
tries to make the distinction clearer, and sign-post from one to the
other.

#minor-release

Issue: androidx/media#910
PiperOrigin-RevId: 595701540
(cherry picked from commit 95e742948ca0d7490cb016c1026827b8369fc8ab)
2024-01-09 12:17:49 +00:00
bachinger
141f9b760d Return null if media notification controller Future is not done
When the media notification controller is requested for a session
with `getConnectedControllerForSession` and the `Future` is not null
but not yet completed, the `Future` was returned either way. This was
reported as creating a race condition between the notification
being requested for update the very first time, and the media
notification controller having completed connecting to the session.

Returning null from `getConnectedControllerForSession` when the
`Future` is available but not yet done fixes the problem. This is
safe because for the case when a notification update is dropped,
the media notification controller will trigger the update as soon
as the connection completes.

Issue: androidx/media#917
#minor-release
PiperOrigin-RevId: 595699929
(cherry picked from commit 5c50b27e8fce878bc24852498ae42298613d5ad2)
2024-01-09 12:17:49 +00:00
Copybara-Service
77d220c507 Merge pull request #369 from Tolriq:fix_invalid_frames
PiperOrigin-RevId: 595650068
(cherry picked from commit 8eda9f2ed2cc8d00fbd0bb71090a7a77cc10629b)
2024-01-09 12:17:48 +00:00
bachinger
d1b882ae56 Don't set negative values to setWhen()
When the 'when' timer of the notification is disabled
`DefaultMediaNotificationProvider` may set `C.TIME_UNSET`
as the time. Users reported problems on some devices with
this and the docs ask for an event time that probably
shouldn't be a negative number.

This change sets `0L` instead of `C.TIME_UNSET` when the
timer is disabled.

Issue: androidx/media#903

#minor-release

PiperOrigin-RevId: 594451074
(cherry picked from commit 426bc940905237accf902f42d63b3777c11ff72e)
2024-01-09 12:17:48 +00:00
andrewlewis
b9d205ba0f Expand operating rate workaround to T612 chipset
PiperOrigin-RevId: 592916187
(cherry picked from commit 1845a4ae6908f682cc20df715df4af74d7f79ba6)
2024-01-09 12:17:48 +00:00
Copybara-Service
b68173aae4 Merge pull request #914 from cemrich:366-forward-time-wrong
PiperOrigin-RevId: 592871532
(cherry picked from commit 966b5178b663645aa6b66594e272faa807f6bb83)
2024-01-09 12:17:48 +00:00
ibaker
1da24b2875 Add container to Format.toLogString
While investigating Issue: androidx/media#887 I naively assumed the CEA-608
captions were in a TS file, but they're actually in an MP4 (which is
possibly obvious given DASH only supports MP4). This change includes
container info in the `EventLogger` `tracks` output.

PiperOrigin-RevId: 592192752
(cherry picked from commit 6853ffccae53b0f01c8a818d64ed8dc18d1c60b0)
2024-01-09 12:17:48 +00:00
ibaker
5d7c9142ba Add Widevine license renewal example to demo app
PiperOrigin-RevId: 592182371
(cherry picked from commit 0b8a9a2ca4791f54289706802132138430f51f09)
2024-01-09 12:17:48 +00:00
rohks
6236fd38d0 Fix sending negative bufferedDurationUs to CmcdData.Factory
When track is changed during playback, `playbackPositionUs` may be in middle of a chunk and `loadPositionUs` should be the start of that chunk. In this situation `loadPositionUs` can be less than the current `playbackPositionUs`, resulting into negative `bufferedDurationUs`. It translates to having no buffer and hence we should send `0` for `bufferedDurationUs` when creating new instances of `CmcdData.Factory`.

Issue: androidx/media#888

#minor-release

PiperOrigin-RevId: 591099785
(cherry picked from commit 7f6596bab217847617947b61ded64b7aba58a194)
2024-01-09 12:17:48 +00:00
tonihei
4231a1d183 Use different wraparound assumptions for duration readers
The timestamp adjuster also estimates the number of wraparounds
of the 90Khz TS timestamp. It does that by assuming that a new
timestamp is always close to the previous one (in either direction).

This logic doesn't always work for duration estimates because the
timestamp at the end of the media is not close to the one at the
beginning and it may also never be less than the one at the beginning.

This can be fixed by introducing a new estimation model that assumes
the new timestamp is strictly greater than the previous one without
making the assumption that it has to be close to it.

Issue: androidx/media#855

#minor-release

PiperOrigin-RevId: 590936953
(cherry picked from commit 01578780a6bbd69d206f4f7e815c9f5e9d3c5fa4)
2024-01-09 12:17:48 +00:00
bachinger
09d30a160e Fix broadcasting notifyChildrenChanged for legacy controllers
When broadcasting a notifyChildrenChanged event, the task for legacy
controllers was sent to the broadcasting callback. This would
technically work, but because the subscription list is maintained
with specific controllers, the broadcast controller isn't subscribed
and hence the call wasn't executed.

This change calls the overloaded method for a specific controller
for each connected controller. Making sure (only) subscribed
controllers are notified.

Issue: androidx/media#644
PiperOrigin-RevId: 590904037
(cherry picked from commit 4974f960e7b8a34a37c2206b87973339c0e81cef)
2024-01-09 12:17:48 +00:00
Copybara-Service
c8a403edcf Merge pull request #753 from stevemayhew:p-fix-issue-9347
PiperOrigin-RevId: 590862514
(cherry picked from commit ab296ef686c8132e3d918cd27cd40e4ea02c3f1f)
2024-01-09 12:17:39 +00:00
ibaker
33a51906f9 Combine 'matching' versions in media3 bug template
#minor-release

PiperOrigin-RevId: 590586491
(cherry picked from commit 9a766161ee8a004ed7ca95d0527e416deda1c1a1)
2024-01-09 12:11:49 +00:00
Copybara-Service
7d564f8571 Merge pull request #864 from v-novaltd:dsparano-exo129_2
PiperOrigin-RevId: 590234505
(cherry picked from commit f465efeefd746d3a50fbb9316e6b51a1b7bcec38)
2024-01-09 12:11:49 +00:00
ibaker
5001f70b3d Fix VorbisComment.populateMediaMetadata key comparison to ignore case
Issue: androidx/media#876

#minor-release

PiperOrigin-RevId: 590215918
(cherry picked from commit 5580b78b1367822cc3ef3f35ffeb62ab8c5cb9b8)
2024-01-09 12:11:49 +00:00
Copybara-Service
504bcd804f Merge pull request #867 from equeim:ndk-r26
PiperOrigin-RevId: 590142275
(cherry picked from commit 27f437b65ac8c1f97fa064d04771b412327535fc)
2024-01-09 12:11:49 +00:00
samrobinson
89baa96e32 Fix handling of repeated EOS in SilenceSkippingAudioProcessor.
Issue: androidx/media#712
PiperOrigin-RevId: 589882412
(cherry picked from commit 90a0cbdf3d3c5314915d5fda5eecb93c18bc7bef)
2024-01-09 12:11:49 +00:00
ibaker
e509db273d Fix handling of multiple HEVC tracks in JPEG motion photos
The MP4 data in JPEG motion photos can contain multiple `video/hevc` tracks, but only the first is at a playable frame rate while the others are low-fps, high-res tracks designed for specific use-cases (not direct video playback).

ExoPlayer currently selects the unplayable track by default, because it
has a higher resolution. This change introduces a flag to
`Mp4Extractor` that results in the first video track being marked as
`ROLE_FLAG_MAIN`, and all subsequent video tracks `ROLE_FLAG_ALTERNATE`
- this then results in the playable lower-res track being selected by
default.

PiperOrigin-RevId: 589832072
(cherry picked from commit 5266c71b3a01eda5f3f6ef9449e46887a7f9f4d6)
2024-01-09 12:11:46 +00:00
tofunmi
7df03f381d TransformerEndToEndTest: replace /*testId=*/ with variable
PiperOrigin-RevId: 589765715
(cherry picked from commit 00d5b6ec997408577db7c81517f56ffdb439c90b)
2024-01-09 12:08:20 +00:00
ibaker
482d5d69d5 Add extractor and playback tests for Pixel JPEG motion photo
This image has two video tracks in the MP4 data, one is a 'real' video
which we want to play by default, and the other is a low-fps video track
which isn't intended to be directly played, it's encoded in HEVC for
compression and decoding efficiency.

This test demonstrates ExoPlayer's current behaviour default extraction
and playback, which results in selecting the high-res, low-fps track
(actually single sample in this example), instead of playing the actual
video.

PiperOrigin-RevId: 588068908
(cherry picked from commit 6360082b879e9cba394f169b7b50c8c500173027)
2024-01-09 11:03:33 +00:00
ibaker
ea72856ac8 Add Robolectric e2e test support for HEVC content
PiperOrigin-RevId: 588055594
(cherry picked from commit d4fe3fe318ef5961911b828aa7a42b124acfc186)
2024-01-09 11:03:33 +00:00
Googler
c314123298 Fix nullability issue in MediaControllerImplLegacy
PiperOrigin-RevId: 588035411
(cherry picked from commit e0f1783a54867ee81d6f9fb93ffdcee8451f2118)
2024-01-09 11:03:33 +00:00
michaelkatz
03eae4f9ac Limit processing Opus decode-only frames by seek-preroll in offload
As Opus decoders skip some bytes prior to playback during a seek, the renderer for bypass playback should send samples to the decoder even if they would be decode-only. However, the renderer should not send samples with time preceding that range. This change adds that constraint.

#minor-release

PiperOrigin-RevId: 588014983
(cherry picked from commit d1e38abf93353af1bc3fb2d9a0dfbac01e387f3e)
2024-01-09 10:48:33 +00:00
tonihei
57187aa899 Map VORBIS channel layout to Android layout
Both the extension OPUS decoder and the OMX/C2 MediaCodec
implementations for OPUS and VORBIS decode into the channel
layout defined by VORBIS. See
https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-140001.2.3

While this is technically correct for a stand-alone OPUS or VORBIS
decoder, it doesn't match the channel layout expected by Android.
See https://developer.android.com/reference/android/media/AudioFormat#channelMask

The fix is to apply the channel mapping after decoding if needed.
Also add e2e tests with audio dumps for the extension renderer,
including a new 5.1 channel test file.

Issue: google/ExoPlayer#8396

PiperOrigin-RevId: 588004832
(cherry picked from commit b1541b096f9dc4d1f9ca71b6743c836f6bd4de89)
2024-01-09 10:48:31 +00:00
ibaker
483426ad7b MCR: Ensure mediaCrypto and codec are atomically non-null
`mediaCrypto` is initialized before `codec` in
`maybeInitCodecOrBypass`. Before this change, it was possible for
`maybeInitCodecOrBypass` to complete with `mediaCrypto != null` and
`codec == null`, in particular if it was run as part of clearing the
player surface (since in that case, no video codec is initialized).
This inconsistent state then causes issues during a later invocation of
`maybeInitCodecOrBypass`, when `mediaCrypto` is still non-null, and
`mediaCryptoRequiresSecureDecoder = true`, but the
content has been changed to unencrypted with no associated DRM session.
This results in a playback error, because a secure decoder is
initialized but there's no DRM session available to work with it.

This change ensures that when `maybeInitCodecOrBypass` completes,
either both `mediaCrypto != null` and `codec != null` (i.e. codec
initialization was completed) or `mediaCrypto == null` and
`codec == null` (i.e. codec initialization was not completed). We also
ensure that when nulling out `mediaCrypto` we also set
`maybeInitCodecOrBypass = false`. A later change should be able to
demote `maybeInitCodecOrBypass` from a field to a local in order to
remove any risk of that part of state becoming out of sync. This
resolves the issue, because during the second invocation of
`maybeInitCodecOrBypass` an insecure decoder is now (correctly)
initialized and the unencrypted content is successfully played.

#minor-release

PiperOrigin-RevId: 587713911
(cherry picked from commit 913f6da08305b36798c84d5134d19b2d11affdd2)
2024-01-08 16:40:28 +00:00
ibaker
fa268cf84d Don't include null text or bitmaps in Cue.toBundle()
`fromBundle` doesn't distinguish between `FIELD_BITMAP` and `FIELD_TEXT`
being present with a null value, or being absent, so we might as well
avoid including them when the value is null.

I've separated this from a later change to add
`Cue.toSerializableBundle` which will also skip setting a bitmap value
into the `Bundle` if `this.bitmap == null`. This is partly because it
results in changes to a lot of extractor test dump files, and it's
easier to review that as a separate change.

PiperOrigin-RevId: 586626141
(cherry picked from commit 28c210686f54d52610fe2f9560ad1dfa73753ccd)
2024-01-08 16:16:21 +00:00
christosts
3f3287aba3 Exit early progressive loads if the load task is canceled
Add an check when loading progressive media in case the load
is canceled. If the player is released very early, the progressive
media period may carry on with the initial loading unnecessarily.

PiperOrigin-RevId: 586288385
(cherry picked from commit 3d1d8f4439f194029d1522137b7f428e96bf61b3)
2024-01-08 15:55:36 +00:00
tofunmi
d68c36e082 Update emulator device names
PiperOrigin-RevId: 585682881
(cherry picked from commit b598c96c2f604af731d43e5bd021e5198dab0af1)
2024-01-08 15:55:36 +00:00
Copybara-Service
db648316ed Merge pull request #837 from superjohan:fix/android-14-clearkey
PiperOrigin-RevId: 585639025
(cherry picked from commit 5f27b1821027d4cd086b87242e9e756a301b8e9a)
2024-01-08 15:33:26 +00:00
andrewlewis
19ee78729c Restrict operating rate workaround to SM8550
PiperOrigin-RevId: 585613041
(cherry picked from commit e84a13fb54ab0d325b928bf7ec0d8632ccbc8ca3)
2024-01-08 15:33:26 +00:00
andrewlewis
710c1b9053 Work around codec frame rate issues in Redmi Note 9 Pro
The decoder and encoder won't accept high values for frame rate, so avoid
setting the key when configuring the decoder, and set a default value for the
encoder (where the key is required).

Also skip SSIM calculation for 4k, where the device lacks concurrent decoding
support.

PiperOrigin-RevId: 585604976
(cherry picked from commit 8b38b34b9f02c3648d2988c4cdaca005fbf8f1cd)
2024-01-08 15:33:26 +00:00
andrewlewis
97c9e234d2 Avoid value close to overflow for KEY_OPERATING_RATE
Using `Integer.MAX_VALUE` risks causing arithmetic overflow in the codec
implementation.

Issue: androidx/media#810

PiperOrigin-RevId: 585104621
(cherry picked from commit ad40db448943fef579879c9c2a988f514b254109)
2024-01-08 15:33:24 +00:00
ibaker
36f634d8d1 Fix typo in DashManifestParser
PiperOrigin-RevId: 585017285
(cherry picked from commit 479344d74e1e63d83cd94ed14517e27030c85e6a)
2024-01-08 15:31:29 +00:00
tonihei
4234bc7091 Remove redundant ) in Javadoc
PiperOrigin-RevId: 584910697
(cherry picked from commit 85a54e2e190b705367b0d2dd4d7fcd71900b3fdd)
2024-01-08 15:31:29 +00:00
Copybara-Service
33484b0239 Merge pull request #707 from equeim:ffmpeg-6.0
PiperOrigin-RevId: 584893190
(cherry picked from commit 45b51d8c972f957e02097c5ecff2261ffe23e397)
2024-01-08 15:31:27 +00:00
bachinger
5e86c4c20b Add session extras to the state of the controller
This change adds `MediaController.getSessionExtras()` through
which a controller can access the session extras.

The session extras can be set for the entire session when
building the session. This can be overridden for specific
controllers in `MediaSession.Callback.onConnect`.

PiperOrigin-RevId: 584430419
(cherry picked from commit a063d137b4307348a140ec6a2b6d254db294395e)
2024-01-08 15:26:08 +00:00
christosts
124eb31fd2 MidiExtractor: mark only the first sample as key-frame
This change fixes a bug with seeking forward in MIDI. When seeking forward,
the progressive media period attempts to seek within the sample queue, if a
key-frame exists before the seeking position. With MIDI, however, we can
only skip Note-On and Note-Off samples and all other samples must be sent
to the MIDI decoder.

When seeking outside the sample queue, the MidiExtractor already
instructs the player to start from the beginning of the MIDI input. With
this change, only the first output sample is a key-frame, thus the
progressive media period can no longer seek within the sample queue and
is forced to seek from the MIDI input start always.

Issue: androidx/media#704

PiperOrigin-RevId: 584321443
(cherry picked from commit ec08db458e6cedcb79a42f10eaac7f8da7e7bcdb)
2024-01-08 15:26:03 +00:00
tonihei
c9f6ad0398 Avoid clipping live offset override to min/max offsets
The live offset override is used to replace the media-defined
live offset after user seeks to ensure the live adjustment adjusts
to the new user-provided live offset and doesn't go back to the
original one.

However, the code currently clips the override to the min/max
live offsets defined in LiveConfiguration. This is useful to
clip the default value (in case of inconsistent values in the media),
but the clipping shouldn't be applied to user overrides as
the player will then adjust the position back to the min/max
and doesn't stay at the desired user position.

See 2416d99857 (r132871601)

PiperOrigin-RevId: 584311004
(cherry picked from commit af0282b9db62a8c5de1dbcc49794872d0157c1ab)
2024-01-08 15:21:28 +00:00
bachinger
ea642a41e9 Add test case to test position conversion when POSITION_UNKNOWN
PiperOrigin-RevId: 584261559
(cherry picked from commit ec478138baf58ed5c1a4c5117d5f28e5b40c94eb)
2024-01-08 15:18:39 +00:00
bachinger
5752a09a40 Return empty timeline when media info is null
Issue: androidx/media#708
PiperOrigin-RevId: 584054624
(cherry picked from commit 167f50a9ca8b8cbd80bc5ff4c7afd4c6a1db7dc2)
2024-01-08 15:18:39 +00:00
rohks
0038355590 Use .test top level domain for test URI
PiperOrigin-RevId: 583951327
(cherry picked from commit ffbaa090aa24ef138d38b16b9e6e45560b5c8dd3)
2024-01-08 15:18:38 +00:00
rohks
aab1c9ada1 Populate MediaMetadata.extras to MediaMetadataCompat
Ensures backward compatibility.

Issue: androidx/media#802
PiperOrigin-RevId: 583425114
(cherry picked from commit 6df240877c30aedb271c2bc74c54fc2bab0e4cbf)
2024-01-08 15:18:38 +00:00
tonihei
69884e764e Workaround layout problems with Material Design
In some contexts (e.g. BottomSheetDialogFrament), Material Design
themes will override the default of singleLine=false to true. This
causes layout problems because the forward/rewind buttons are no
longer visible with singleLine=true.

This problem can be avoided by explicitly requesting the default
value of false in our layout files.

Issue: androidx/media#511

#minor-release

PiperOrigin-RevId: 582604131
(cherry picked from commit 310e2edccac75b1ed30eb69520224cb48d1cc190)
2024-01-08 15:18:38 +00:00
ibaker
b9722764ac Update recommended way to suppress @UnstableApi errors in lint.xml
#minor-release

PiperOrigin-RevId: 582599098
(cherry picked from commit bd7615c0b83df8187daaf7e8d91eb1ce9bb35240)
2024-01-08 15:18:38 +00:00
andrewlewis
7901d1cc0a Expand frame drop workaround to Realme C11
Based on on-device testing, this device seems to have the same issue as Moto G (20) where frames are dropped despite configuring the decoder not to drop frames.

PiperOrigin-RevId: 581943805
(cherry picked from commit 330713f687d4ebaec9ee8e9aaf39db503f299ce3)
2024-01-08 15:18:36 +00:00
tianyifeng
21461abc1c Parse "f800" as channel count of 5 for Dolby in DASH manifest
Issue: androidx/media#688
PiperOrigin-RevId: 581908905
(cherry picked from commit 79711ebd3f8626d9ec31f7ac18434625caeac28f)
2024-01-08 15:08:53 +00:00
Googler
2db9da5c1d Don't crash when receiving a bad playback state
PiperOrigin-RevId: 580942377
(cherry picked from commit e79809616cd0ecb6f39cbeffdaaf143c260f64e6)
2024-01-08 14:54:21 +00:00
jbibik
f189af5632 Remove old pre-releases from the github bug template
PiperOrigin-RevId: 580554963
(cherry picked from commit 508582d56c9f8e6219d2e93f0f80ea180b4ad272)
2024-01-08 14:54:21 +00:00
tonihei
d8d552af59 Fix proguard rule to also keep referenced class name
PiperOrigin-RevId: 579234050
(cherry picked from commit bce82bdc752a8da1d7c1f78bdfb417414407849b)
2024-01-08 14:54:17 +00:00
tonihei
40094273ea Fix access to stale ByteBuffer in FfmpegAudioDecoder
The native code can now reallocate the buffer if it needs to grow
its size, so we have to reacquire a reference in the Java code to
avoid accessing a stale instance.

This fixes a bug introduced by 8750ed8de6.

PiperOrigin-RevId: 578799862
(cherry picked from commit ae6f83d298424bd405372803bb8b206fc95a2d0f)
2024-01-08 14:51:05 +00:00
ibaker
2f4d475b5c Split media1/media3 conversion methods out of MediaUtils
Android Studio removed some nested imports, but I think the extra
qualification at the usage site is actually mostly helpful, so I'm
leaving it as-is.

PiperOrigin-RevId: 578518880
(cherry picked from commit 72b7019578f3051e1bec826cf0ac401a86d818dc)
2024-01-08 14:51:05 +00:00
ibaker
07258aa373 Add warning log if DASH manifest contains incomplete ClearKey info
Unfortunately we can't fail any more obviously at this point, because
manifests often contain config for multiple DRM schemes, and when
parsing the manifest we don't know which scheme is going to be used for
playback. It would be unreasonable to fail playback due to incomplete
ClearKey config if playback was otherwise going to succeed using e.g.
Widevine.

* Issue: androidx/media#777
* Issue: androidx/media#563
* Issue: google/ExoPlayer#9169

#minor-release

PiperOrigin-RevId: 578491484
(cherry picked from commit d42c23706b615d1987f988fe219ab0fe61d44ac6)
2024-01-08 14:51:05 +00:00
tianyifeng
2237f4902d Put the custom keys in MediaMetadataCompat to MediaMetadata.extras
PiperOrigin-RevId: 578473874
(cherry picked from commit 84022eacc560b90cf34253b2470aabdf4a4b767d)
2024-01-08 14:51:05 +00:00
ibaker
fe8bbcaa12 Remove stray parentheses from release notes
PiperOrigin-RevId: 577809964
(cherry picked from commit db1ab1dcf37a484370c33b399c52f4e9569c793d)
2024-01-08 14:50:26 +00:00
ibaker
a017080353 Bump okhttp dependency to 4.12
Issue: androidx/media#768
PiperOrigin-RevId: 577208115
(cherry picked from commit e8cca688ad39590a9537c940ed0db4ca805f0fb8)
2024-01-08 13:56:59 +00:00
michaelkatz
79ce4f1c73 Fallback to legacy sizerate check for H264 if CDD PerfPoint check fails
Some devices supporting Performance Points for decoder coverage are missing coverage over the CDD requirements for H264. For these cases ExoPlayer should fall back to legacy resolution and frame rate support checks. If there is an H264 stream evaluated as a `PerformancePointCoverageResult` of `COVERAGE_RESULT_NO`, then ExoPlayer checks for coverage of the [720p CDD requirement](https://source.android.com/docs/compatibility/10/android-10-cdd#5_3_4_h_264).

Issue: google/ExoPlayer#10898

Issue: androidx/media#693
PiperOrigin-RevId: 575768836
(cherry picked from commit 4515a0c3f24706a43b3247b558b14d98f2b0fce2)
2024-01-08 13:56:42 +00:00
ibaker
f6fe90f30b Clean-up multi-line strings in YAML issue templates
* If we don't want any newlines in the result, it's better to use `>`
* If we want newlines (e.g. for markdown) then we should ensure the
  string **only** contains the newlines we want, because GitHub (unlike
  other markdown renderers) preserves single newlines in the output,
  leading to ugly newlines dictated by the source.

Also remove a markdown-style link that isn't renderered as markdown.

PiperOrigin-RevId: 590309749
(cherry picked from commit 6aeaad26addee2d5793a624526d1811b8973c4ce)
2023-12-13 09:49:13 +00:00
Ian Baker
4f5038bc07 Merge branch 'release' into release-1.2.0 2023-11-17 16:13:40 +00:00
ibaker
2cc8afecc6 Remove recommendation to pin annotation-experimental to version 1.2.0
This was intended to avoid bringing in a transitive dependency on the
Kotlin standard library, but Gradle no longer flags lint errors on
`@RequiresOptIn` violations with `annotation-experimental:1.2.0` (1.3.0
is needed), making this recommendation dangerous. See also
https://issuetracker.google.com/310651921.

PiperOrigin-RevId: 582276430
(cherry picked from commit aa1ec981a3eea59f8be9d44104d0573a60816436)
2023-11-17 10:07:23 +00:00
ibaker
1b83c59759 Add @OptIn to fields in demo PlayerActivity now this is supported
This is possible now we use `annotation-experimental:1.3.1`.

#minor-release

PiperOrigin-RevId: 582315579
(cherry picked from commit 8d83d491f198fbe3a21181df235dfff314252929)
2023-11-17 10:07:23 +00:00
jbibik
f90726a78d Merge release notes for media3 1.2.0 stable release
PiperOrigin-RevId: 580923121
(cherry picked from commit 7ee07a5ff583e8d56e34783dc4ecfdb7d9a65ef5)
2023-11-17 10:07:20 +00:00
jbibik
a2679fba54 Bump media3 versions to 1.2.0 (stable)
#minor-release

PiperOrigin-RevId: 580856330
(cherry picked from commit 3918d3620052138f0d7718cd8076e7389222572d)
2023-11-12 20:52:00 +00:00
ibaker
7991838326 Rollback of a19f577976
PiperOrigin-RevId: 577139027
(cherry picked from commit dd6306e1ba5e860d7a267a0ad3a16eb028e8fd7a)
2023-11-06 16:51:08 +00:00
rohks
3d6ac7f6f4 Add com.github.philburk:jsyn to JAR list
#minor-release

PiperOrigin-RevId: 576148893
(cherry picked from commit 00943a0a734e55a1dbdf584c1bc139ed4db67e64)
2023-10-24 17:07:47 +01:00
rohks
1c54c393a0 Reorder RELEASENOTES to move unreleased changes to correct section
PiperOrigin-RevId: 575807109
(cherry picked from commit 105bdf57d80e32d8c0d8c4e2598b9c43c9461870)
2023-10-23 07:03:35 -07:00
rohks
7a2d80d87e Bump Media3 version numbers for 1.2.0-rc01
#minor-release

PiperOrigin-RevId: 575805495
(cherry picked from commit 9d3d7abdc6460bcc6f01145bcb3ce1e854b86a1a)
2023-10-23 06:55:40 -07:00
rohks
c997c71258 Update RELEASENOTES for 1.2.0-rc01 release
PiperOrigin-RevId: 575795800
(cherry picked from commit 7202f5d4de6a51b3fe23994c49ad8c15350d260c)
2023-10-23 06:07:35 -07:00
bachinger
f2cf43ccd5 Use MediaSessionImpl.onMediaButtonEvent() to dispatch key events
This change moves the handling of any media button event into
`MediaSessionImpl.onMediaButtonEvent(intent)`. This includes
the double click handling from `MediaSessionLegacyStub`.

The advantage is that everything is in one place which allows
to offer `MediaSession.Callback.onMediaButtonEvent` with which
an app can override the default implementation and handle media
buttons in a custom way.

Media button events can originate from various places:

- Delivered to `MediaSessionService.onStartCommand(Intent)`
  - A `PendingIntent` from the notification below API 33
  - An `Intent` sent to the `MediaButtonReceiver` by the system dispatched
    to the service
- Delivered to `MediaSessionCompat.Callback.onMediaButtonEvent(Intent)`
  implemented by `MediaSessionLegacyStub` during the session is active
  - Bluetooth (headset/remote control)
  - Apps/system using `AudioManager.dispatchKeyEvent(KeyEvent)`
  - Apps/system using `MediaControllerCompat.dispatchKeyEvent(keyEvent)`

Issue: androidx/media#12
Issue: androidx/media#159
Issue: androidx/media#216
Issue: androidx/media#249

#minor-release

PiperOrigin-RevId: 575231251
(cherry picked from commit a79d44edc5c7fdc81120dbc9b2c89b9799b14031)
2023-10-20 08:52:55 -07:00
rohks
47a451abf7 Update translations in the ui module
#minor-release

PiperOrigin-RevId: 575161190
(cherry picked from commit a8ab9e2c70c98ee65e3b3d71806da6c9fc5c42e3)
2023-10-20 02:49:23 -07:00
simakova
9ac6f89fd7 Remove CompositionPlayer activity from the transformer demo app
The CompositionPlayer is not ready yet.

Issue: androidx/media#741
PiperOrigin-RevId: 574859927
(cherry picked from commit beb1711d4cfad51b88016bbb2b1e0f1a7945ed84)
2023-10-19 07:17:02 -07:00
tonihei
e1ad106453 Add missing command checks to playback resumption flow
Player methods shouldn't be called if they are not available and the
entry point to the playback resumption flow only checks
COMMAND_PLAY_PAUSE.

#minor-release

PiperOrigin-RevId: 574834148
(cherry picked from commit bfd1a2724c660de0df3c13f8394238ac6aa26e68)
2023-10-19 05:36:49 -07:00
Copybara-Service
cb67b16cac Merge pull request #728 from lawadr:audio-capabilities-fix
PiperOrigin-RevId: 574829263
(cherry picked from commit 5f80a4708165ffe977ce37400f7c8eae01142e2d)
2023-10-19 05:18:21 -07:00
bachinger
a8b0bd712a Do not hide System UI when app rejects connection
If an app rejects the connection of the internal media notification manager
the session should behave like without the the media notification controller.
The legacy System UI controller should not be hidden or even rejected to
connect in such a case.

#minor-release

PiperOrigin-RevId: 574807901
(cherry picked from commit 54d5810fc353a9e7133ef929ab2f822d921070b1)
2023-10-19 03:48:16 -07:00
tonihei
2ae6b1e832 Rollback of 64bd3bcad3
PiperOrigin-RevId: 574766164
(cherry picked from commit f0cab4d03ecfa7fbd48262c332d85329736224af)
2023-10-19 01:03:49 -07:00
Googler
4c778edd4d Rollback of eafe2e35f0
PiperOrigin-RevId: 574755143
(cherry picked from commit cf3733765c2ca59ef2261b2e59b21fae5e7546eb)
2023-10-19 00:18:56 -07:00
tonihei
21cb3a6bea Rollback of 4ebe630a80
PiperOrigin-RevId: 574530273
(cherry picked from commit c0759a4e62466bbc0816737e28adf1b4a513016c)
2023-10-23 13:15:17 +01:00
ibaker
5d6fefe410 Add formatting to scheme list in DefaultDataSource javadoc
The current formatting makes the 'scheme' part of the list blend into
the definition, especially when the definition is multi-line.

https://developer.android.com/reference/androidx/media3/datasource/DefaultDataSource

I considered adding another level of nesting, but I think bold will
help distinguish the structure of the list without adding too much HTML
or visual whitespace.

#minor-release

PiperOrigin-RevId: 574514208
(cherry picked from commit aec6db77faba617dc2ab225b72c9bc3350c5b5c3)
2023-10-23 13:15:17 +01:00
michaelkatz
111ac63695 Send decode-only Opus samples in bypass mode for seekPreRoll skip
As Opus decoders skip some bytes prior to playback during a seek, the renderer for bypass playback should send samples to the decoder even if they would be decode-only.

#minor-release

PiperOrigin-RevId: 574494666
(cherry picked from commit 00193e0304a5ea2c20012fabf77f82f29e218372)
2023-10-23 13:15:17 +01:00
tonihei
fe60d0d7b4 Use DataSourceBitmapLoader by default
This replaces the SimpleBitmapLoader that can now be deprecated
as it's fully unused and doesn't provide any additional functionality.

#minor-release

PiperOrigin-RevId: 574454636
(cherry picked from commit db86932781b4a5f377d1f4c1414c3d6a74ede174)
2023-10-23 13:15:17 +01:00
christosts
5a4adc9b25 Fix MIDI decoder build.gradle
Issue: androidx/media#734

#minor-release

PiperOrigin-RevId: 574425269
(cherry picked from commit ff4ff76990b52718f8c1e4acd9075c5c06ebee0e)
2023-10-23 13:15:17 +01:00
Googler
9ace4855e0 Rollback of 4ebe630a80
PiperOrigin-RevId: 574308136
(cherry picked from commit ff330bd8e9e925987396597cfa25f5455e1d4048)
2023-10-23 13:15:17 +01:00
Googler
fcb3315edc Rollback of 64bd3bcad3
PiperOrigin-RevId: 574290408
(cherry picked from commit 1a43aa3602075cc88c902de293cb025ff3d619cc)
2023-10-23 13:15:17 +01:00
christosts
ee83baf92e Publish MIDI decoder module on Maven repository
Issue: androidx/media#734

#minor-release

PiperOrigin-RevId: 574182702
(cherry picked from commit 61770f8a61312cacf596536b614eeb49f6abab6e)
2023-10-23 13:15:17 +01:00
Copybara-Service
29846d0167 Merge pull request #491 from v-novaltd:dsparano-exo128
PiperOrigin-RevId: 574129451
(cherry picked from commit 009d48a75e932c9e8e94a28ca2b92970cf5fe357)
2023-10-23 13:15:17 +01:00
ibaker
f290d0ef86 Move DASH subtitle parsing release note to correct section
#minor-release

PiperOrigin-RevId: 574090381
(cherry picked from commit df19097e220f7b4599830bc2a802b0951bc71cfb)
2023-10-23 13:15:17 +01:00
bachinger
8e48433be3 Send media button events from service directly using MediaSessionImpl
Media button event coming from the `MediaSessionService` are delegated
to the `MediaSessionImpl` and then sent to the session by using the
`MediaSessionStub` directly instead of using the `MediaController`
API.

Splitting the `MediaController.Listener` and `Player.Listener` in
`MediaNotificationManager` got reverted, and both listener are set to the
controller as before. This reverts the change that introduced a
different timing behaviour. It still holds, that a listener
registered on a `MediaController` that calls a method like `play()` is
called immediately and before the call has arrived at the player. This
change works around this behaviour from the library side by calling
`MediaSessionStub` directly with a `ControllerInfo`.

#minor-release

PiperOrigin-RevId: 573918850
(cherry picked from commit 64bd3bcad3fa4b0e433b16d583456920afad3ce2)
2023-10-23 13:15:17 +01:00
bachinger
85167f175a Send ConnectionState as in-process bundle if possible
#minor-release

PiperOrigin-RevId: 573849858
(cherry picked from commit d5f093f43cc2bda763436d4ecf32c38c76b9418e)
2023-10-23 13:15:17 +01:00
bachinger
386d2239eb Only set the queue when COMMAND_GET_TIMELINE is available
Android Auto shows a queue button when the queue is not empty.
Apps were able to remove this queue button with the legacy API
by not setting the queue of the session.

After this change, removing `COMMAND_GET_TIMELINE` from the commands
of the media notification controller or the session player sets the
queue in the platform session to null.

#minor-release
Issue: androidx/media#339
PiperOrigin-RevId: 573813558
(cherry picked from commit f53e1bc6f63caba7774c35aeb663b9178941faf5)
2023-10-23 13:15:17 +01:00
tonihei
e46ee01c00 Expand MediaItems in session demo instead of just replacing them
When MediaItems are added from the controller, we currently completely
replace the item with the one from our database, overriding any
potential additional information the controller may have set.

Also forward the onAddMediaItems/onSetMediaItems callbacks to common
helper methods instead of redirecting them through super methods

#minor-release
Issue: androidx/media#706
PiperOrigin-RevId: 573799351
(cherry picked from commit 00425dbe80dc9da38766f7235052c434d79724d1)
2023-10-23 13:15:17 +01:00
tianyifeng
2a7d85e065 Calculate HLS live playlist refresh interval accurately
Previously, we calculated the next playlist reload time by adding the target duration (or half of it, depending on whether there is a real update in the new playlist snapshot) from the last load completion time, which makes the reload interval as long as `targetDuration(or half of it) + lastLoadDuration`. While still complying to the standard that "the client MUST wait for at least the target duration before attempting to reload the Playlist file again", this could cause buffering when the playback position is close to the end of live window. This change is to calculate the reload interval accurately by not adding the term `lastLoadDuration`.

Issue: androidx/media#663

#minor-release

PiperOrigin-RevId: 573300009
(cherry picked from commit 58a63c82aa0b59e86a656cf6644781a1c4690c82)
2023-10-23 13:15:16 +01:00
Googler
b65136e292 Remove deprecated DownloadNotificationHelper.buildProgressNotification
Use a non deprecated method that takes a `notMetRequirements` parameter
instead.

PiperOrigin-RevId: 573252909
(cherry picked from commit 8b7ebc70320e66b6360df37c36d4cfc2fb71aa98)
2023-10-23 13:15:12 +01:00
ibaker
3244318d28 Test more URI forms in RawResourceDataSourceContractTest
PiperOrigin-RevId: 573220915
(cherry picked from commit 40459f72123cfc3bbead5dd42ce2aa3a824155b2)
2023-10-23 13:14:42 +01:00
ibaker
f77f3dfa1a Migrate SubtitleParser implementations to incremental parse()
All production and test callers of the non-incremental methods are
already migrated, so we can remove them in this change too.

#minor-release

PiperOrigin-RevId: 573207318
(cherry picked from commit ecd24646cb1fd4b06a27cfe87ec0df47e9db87ed)
2023-10-23 13:14:42 +01:00
ibaker
74277b14c8 Remove the 'super speed' SmoothStreaming PlayReady stream from demo
This content is no longer available, the manifest is returning a 404.

Issue: google/ExoPlayer#11309

#minor-release

PiperOrigin-RevId: 573202175
(cherry picked from commit a19f577976fc670c47e837d521c48170ab900ea0)
2023-10-23 13:14:42 +01:00
ibaker
b77a2530af Change LegacySubtitleUtil handling of SubtitleParser.OutputOptions
If the `Subtitle` has 'active' cues at `OutputOptions.startTimeUs`, this
change ensures these are emitted in a `CuesWithTiming` with
`CuesWithTiming.startTimeUs = OutputOptions.startTimeUs`. If
`OutputOptions.outputAllCues` is also set, then another `CuesWithTiming`
is emitted at the end that covers the 'first part' of the active cues,
and  ends at `OutputOptions.startTimeUs`.

As well as adding some more tests to `LegacySubtitleUtilWebvttTest`,
this change also adds more tests for `TtmlParser` handling of
`OutputOptions`, which transitively tests the behaviour of
`LegacySubtitleUtil`.

#minor-release

PiperOrigin-RevId: 573151016
(cherry picked from commit f9ece88a25b449ab1e59ec0f6a67b71d7a2dc8ce)
2023-10-23 13:14:42 +01:00
Copybara-Service
c7186c9400 Merge pull request #650 from cedricxperi:dts-lbr-buffer-underflow-fix
PiperOrigin-RevId: 572864175
(cherry picked from commit 2421ba4d8fec6ef805f2765f522d4bf0027a08c9)
2023-10-23 13:14:42 +01:00
ibaker
24c39b6a78 Migrate SubtitleParser tests to incremental parse() methods
All the production code is already calling these new incremental
methods, migrating the tests allows us to remove the old
`List`-returning methods in a follow-up change.

#minor-release

PiperOrigin-RevId: 572822828
(cherry picked from commit a12bde4f57002a9adf5da6c01b2f601a6edf92e9)
2023-10-23 13:14:42 +01:00
tonihei
d7044c7b83 Avoid bundling PlayerInfo for in-process calls
PlayerInfo bundling is costly and we can add a shortcut for
in-process binder calls where we store the direct object
reference in a live Binder object that can be written to the
Bundle instead of the individual data fields.

#minor-release

PiperOrigin-RevId: 572816784
(cherry picked from commit d1fc15f2075dd5c130a12420889fd83bd6517a08)
2023-10-23 13:14:42 +01:00
tonihei
7d6146170f Split available command filtering and bundling
A few methods in PlayerInfo and related classes combine filtering
information with bundling in one method. This makes it impossible
to use just the filtering for example and it's also easier to reason
about than two dedicated methods. This change splits these methods
into two parts accordingly.

PiperOrigin-RevId: 572592458
(cherry picked from commit 4ebe630a80296cbb4437336a50abccb39da978f7)
2023-10-23 13:14:42 +01:00
bachinger
0255f3be16 Check whether a session is still managed before removing
When the controller of the `MediaNotificationManager` is disconnected,
the session is removed from the service without checking whether the
session hasn't already been removed. This caused flakiness in `MediaSessionServiceTest.addSession()`.

Because there is a public API `MediaSessionService.removeSession()`,
the controller can't make an assumption whether the session is still
contained in the service when being disconnected.

#minor-release

PiperOrigin-RevId: 572568350
(cherry picked from commit 7fdc5b22bac1af6fd074df38bb6b98c921e713a1)
2023-10-23 13:14:42 +01:00
michaelkatz
ec21b9e634 Update release notes to mention AudioOffloadPreference class changes
Issue: androidx/media#721
PiperOrigin-RevId: 572565009
(cherry picked from commit cef85be40f11f129f38bb19438721236c164c9bf)
2023-10-23 13:14:42 +01:00
ibaker
de3eb672a5 Request notification permission when starting session demo app
#minor-release

PiperOrigin-RevId: 572556101
(cherry picked from commit c7a091a97373d3009074dba7ec0eeaaae79b1a12)
2023-10-23 13:14:41 +01:00
bachinger
4b85207621 Add MediaSession.Builder().setPeriodicPositionUpdateEnabled()
This allows to disable periodic position updates when building
the session.

#minor-release

PiperOrigin-RevId: 572531837
(cherry picked from commit 4dc3db4da3da486b9c9ec1780aa595da8de5330c)
2023-10-23 13:14:41 +01:00
ibaker
03a3f77340 Add experimental opt-in to parse DASH subtitles during extraction
This currently only applies to subtitles muxed into mp4 segments, and
not standalone text files linked directly from the manifest.

Issue: androidx/media#288

#minor-release

PiperOrigin-RevId: 572263764
(cherry picked from commit 66fa5919590789b384506a4e604fe02a5a5e0877)
2023-10-23 13:14:41 +01:00
tonihei
7254f5aca5 Do not interrupt controller thread without a good reason
Interrupting the main thread in particular may be dangerous
as the flag is not cleared after handling the current message.

#minor-release

PiperOrigin-RevId: 572259422
(cherry picked from commit 846117399ff87dc025c355639444de2e54430b18)
2023-10-23 13:14:41 +01:00
ibaker
2ec24ac55f Update @UnstableApi docs to include a package-info.java example
#minor-release

PiperOrigin-RevId: 572229092
(cherry picked from commit 7009c53c799171c4f8e418af5fdb31a6a5544ab9)
2023-10-23 13:14:41 +01:00
ibaker
292701ba55 Add SubtitleParser.Factory.getCueReplacementBehavior()
This gives access to the replacement behavior for a particular subtitle
format without needing to instantiate a `SubtitleParser`.

#minor-release

PiperOrigin-RevId: 572226084
(cherry picked from commit e366c3d419f487beb567e360c21400c31add477f)
2023-10-23 13:14:41 +01:00
tonihei
d078baf435 Remove unneccessary method parameter
The value already exists as a class field.

#minor-release

PiperOrigin-RevId: 572200771
(cherry picked from commit e5fa0c2ce98930e4b679576290b5c0bebd37ad21)
2023-10-23 13:14:41 +01:00
tonihei
69749c59cc Align audio adaptive support checks with video
In particular:
 - Add allowAudioNonSeamlessAdaptiveness parameter (default true, same
   as video and as already implemented by default)
 - Forward mixedMimeTypeAdaptation support to AudioTrackScore
   (as for VideoTrackScore) and adapt mixed MIME type adaptive
   support accordingly
 - Check adaptive support when deciding whether a track is allowed for
   adaptation (also same check as for video). This takes the new
   parameter into account.

PiperOrigin-RevId: 572191308
(cherry picked from commit f20d18e6cae136f8109380d69be76178008cdc17)
2023-10-23 13:14:39 +01:00
ibaker
bd24e788b3 Use package-level @OptIn for demo apps
This demonstrates that `@OptIn` can now be used at the package-level
(since [`androidx.annotation:annotation-experimental:1.3.0`](https://developer.android.com/jetpack/androidx/releases/annotation#annotation-experimental-1.3.0)).

PiperOrigin-RevId: 572187729
(cherry picked from commit d60596cfca2926f851881be871117c7772e7096c)
2023-10-23 13:13:46 +01:00
tonihei
77bccf0dd1 Make BundleListRetriever local Binder aware
When used within the same process, we don't have to go via the
onTransact method (which includes marshalling and unmarhsalling
the data), but can directly return the list.

#minor-release

PiperOrigin-RevId: 572179846
(cherry picked from commit 0bddd06938fb5dc97a99a0cb3a444815a47be41c)
2023-10-23 13:13:46 +01:00
tonihei
7d063e9aab Add missing Future cancellation checks
Future.isDone and getDone doesn't imply the Future was successful
and it may have been cancelled or failed.

In case where we handle failure, we should also handle cancellation
to avoid CancellationException to bubble up unchecked.

In demo app code where we use isDone for field initialization, we
want to crash in the failure case (usually security exception where
the connection is disallowed), but we want to gracefully handle
cancellation. Cancellation of these variables usually happens in
Activity.onDestroy/onStop, but methods may be called after this point.

#minor-release

PiperOrigin-RevId: 572178018
(cherry picked from commit fe7c62afe0b39f8d6617cf610dbdccc9e6adcfb4)
2023-10-23 13:13:46 +01:00
Googler
c913237e92 Fix the resumption of playback when suitable device is connected.
With this change the playback will resume as soon as the suitable device is connected and suppression reason is cleared (within set time out).

#minor-release

PiperOrigin-RevId: 572140309
(cherry picked from commit dc859eae82767598c43bbb182e81228be55f030b)
2023-10-23 13:13:46 +01:00
Googler
f799259a14 ...Update metalava library and Reformat api.txt...
PiperOrigin-RevId: 572013340
(cherry picked from commit da49a02b44365d6f85d5191ccb9c6df05d01fd3c)
2023-10-23 13:13:46 +01:00
tonihei
fdaf9b47df Use more targeted listening in session PlayerActivity
The current metadata updates are triggered by item transitions,
but depending on the speed of loading the playlist, the first
metadata may only be known later via metadata-change callbacks.

Slow playlist loading also means the UI stays empty and it's
beneficial to show a placeholder to avoid the impressions the
UI hangs.

Finally, clean-up by removing unused string constants and merging
all listeners into onEvents

#minor-release

PiperOrigin-RevId: 571951529
(cherry picked from commit fd81c904e11c47dcd7694e9b2f610914d4cf2596)
2023-10-23 13:13:46 +01:00
ibaker
99ea703455 Fix the asset and dump file names for the standalone TTML DASH test
#minor-release

PiperOrigin-RevId: 571941997
(cherry picked from commit 33c151eb5b5ce85e554215af0c1d860b66c66fab)
2023-10-23 13:13:46 +01:00
christosts
3ba8459624 Report dropped frames from the VideoSink
After 4fad529433, MediaCodecVideoRenderer does not report if frames
are dropped from the VideoSink. This commit fixes this.

#minor-release

PiperOrigin-RevId: 571905721
(cherry picked from commit 05b17b543060c1f32ae7af212e5e8b33203bdadd)
2023-10-23 13:13:46 +01:00
ibaker
1818d46077 Return true from CuesResolver.addCues if the output changed
This belongs in the resolver, because it depends on the resolution
algorithm (and therefore the logic can't live in `TextRenderer`).

This also fixes a bug in `TextRenderer` where we were doing arithmetic
with `cues.durationUs` without checking if it was `TIME_UNSET` first.

#minor-release

PiperOrigin-RevId: 571332750
(cherry picked from commit 272428734b79ac6857a4333ede2b12563f8b78de)
2023-10-23 13:13:46 +01:00
ibaker
6ad54d72ad Update TextRenderer to handle CuesWithTiming instances directly
The existing `Subtitle` handling code is left intact to support the
legacy post-`SampleQueue` decoding path for now.

This also includes full support for merging overlapping `CuesWithTiming`
instances, which explains the test dump file changes, and which should
resolve the following issues (if used with the
decoder-before-`SampleQueue` subtitle logic added in
5d453fcf37):

* Issue: google/ExoPlayer#10295
* Issue: google/ExoPlayer#4794

It should also help resolve Issue: androidx/media#288, but that will also require
some changes in the DASH module to enable pre-`SampleQueue` subtitle
parsing (which should happen soon).

PiperOrigin-RevId: 571021417
(cherry picked from commit 002ee0555dc35dce9570f1a991b33ec92743db10)
2023-10-23 13:13:42 +01:00
jbibik
c16accb816 Update RELEASENOTES.md for 1.2.0-beta01 release
PiperOrigin-RevId: 571941830
(cherry picked from commit 62ad1dfdf5699b72f5f218c9cabcf73fb1a9f070)
2023-10-17 15:57:14 +01:00
jbibik
ef013c04ab Bump Media3 version numbers for 1.2.0-beta01 release
#minor-release

PiperOrigin-RevId: 572003628
(cherry picked from commit 97645a200d6abcdbacd1805ef149b5f2b02943c0)
2023-10-09 22:47:37 +01:00
michaelkatz
f776021dcc Deflake RTSP keep-alive monitor test
Alters RTSP KeepAlive monitor test to just make sure that keep-alive message is sent.

The test was added in 42c1846984

#minor-release

PiperOrigin-RevId: 571349013
(cherry picked from commit 417970f7132ab9fd539ba692309e29050b7001d5)
2023-10-06 19:20:13 +01:00
jbibik
efb8c70a4b Add multidex Gradle dependency to test-session-current
#minor-release

PiperOrigin-RevId: 571347856
(cherry picked from commit e63be0317f2152398174bb01c3ea134a0883da10)
2023-10-06 19:20:13 +01:00
michaelkatz
f43d0f187a Update cached playbackHeadPosition when pausing after AudioTrack.stop()
In some streaming scenarios, like offload, the sink may finish writing buffers a bit before playback reaches the end of the track. In this case a player may pause while in this 'stopping' state.

The AudioTrackPositionTracker needs to update the cached values it uses to calculate position in the `PLAYSTATE_STOPPED`/`PLAYSTATE_STOPPING` states if pause/play are called during this period.

PiperOrigin-RevId: 571345914
(cherry picked from commit a789db5b41d9d7a671e83a488b3dec372eaa8b3d)
2023-10-06 19:20:13 +01:00
michaelkatz
5d0d30a280 Allow pause if in offload mode after writing all buffers
In offload mode, `AudioTrack#stop()` will put the track in `PLAYSTATE_STOPPING` rather than `PLAYSTATE_STOPPED`. The difference in state means that `AudioTrack` can be paused and played during this 'stopping' period.

Currently, if `AudioTrackPositionTracker#handleEndOfStream()` has been called then `DefaultAudioSink` in `pause()` won't call `AudioTrack#pause()`. `AudioTrack#pause()` should be called in this case if in offload mode.

#minor-release

PiperOrigin-RevId: 571335108
(cherry picked from commit ab42d64d6d5f1859f1c45aebfe26060978b864bd)
2023-10-06 19:20:12 +01:00
bachinger
da5a743175 Add MEDIA_PLAY_FROM_SEARCH to manifest of session demo app
This is required to make GMS send voice commands to the app.

#minor-release

PiperOrigin-RevId: 571326122
(cherry picked from commit 78f403aa7b795e0e3bcd2f4682bef171f545d4fa)
2023-10-06 15:57:25 +01:00
tonihei
7e9ca0bf74 Deprecate decode-only flag.
The flag is no longer used by our components and only set and checked
in a few places to guarantee compatiblity with existing renderers and
decoders that still use it.

The flag will be removed in the future due to its design limitations.

#minor-release

PiperOrigin-RevId: 571291168
(cherry picked from commit 89d01981bc4cf9218e73bcce1b52c7afe29fbecd)
2023-10-06 15:57:25 +01:00
tonihei
03008b966d Remove release notes lines added by merge conflict
#minor-release

PiperOrigin-RevId: 571005643
(cherry picked from commit 49b1e0bbc2a82f3b9c6ba0a1696ee0b1e53673ec)
2023-10-06 15:57:25 +01:00
ibaker
dad362b414 Add tests for CuesWithTiming.endTimeUs
#minor-release

PiperOrigin-RevId: 570988195
(cherry picked from commit 6057b59723ce6e45ec8a68007eff6687956a9a73)
2023-10-06 15:57:25 +01:00
tofunmi
a4582be2c1 Change equalTo check in ImagePlaybackTest to atLeast
The aim of this test is to make sure the image is onscreen for the right amount of time, so to drive down flakes from the decoder taking too long, change this to an atLeast check

#minor-release

PiperOrigin-RevId: 570988044
(cherry picked from commit 9cc75ca52e49792bed43e4d8fbf67b9a0576fdc0)
2023-10-06 15:57:25 +01:00
tonihei
3c414fcde4 Update documentation wrongly referencing the decode-only flag
#minor-release

PiperOrigin-RevId: 570973457
(cherry picked from commit 87f1b4252ec2d342a153e49aac19455cb91655d1)
2023-10-06 15:57:25 +01:00
samrobinson
fbb64e2db2 Remove experimental keepAudioTrackOnSeek.
PiperOrigin-RevId: 570966027
(cherry picked from commit 068d420ba2d27847c5c581d851ff6a5e1ec45611)
2023-10-06 15:57:25 +01:00
michaelkatz
21c714d8d4 Use RTSP Setup response timeout value in KeepAliveMonitor intervalMs
Set KeepAliveMonitor to send a keep-alive message at half the timeout value, if provided, by the RTSP Setup response.

Issue: androidx/media#662
PiperOrigin-RevId: 570946237
(cherry picked from commit 42c1846984fc8ebca5cdbdcf6df8d2dca44eea96)
2023-10-06 15:57:25 +01:00
ibaker
1a0000db1d Add CuesWithTiming.endTimeUs
In most cases this is more useful than `durationUs`.

We will keep `durationUs`, and the constructor will continue to take
`startTimeUs` and `durationUs`, to allow for use-cases where we don't
know the start time but still want to indicate a duration (this will be
used to implement CEA-608 timeout).

#minor-release

PiperOrigin-RevId: 570944449
(cherry picked from commit bf7b91e57e477f71644d5e585e0e999deadf7fa3)
2023-10-06 15:57:25 +01:00
tonihei
df85a996ba Add Decoder.setOutputStartTimeUs and use it in extension decoders
This gets rid of the reliance on the decode only flag that is still
set on input buffers to the decoder if they are less than the start
time.

We still need to set and check the decode-only flag in SimpleDecoder
to ensure compatbility with custom decoders that use the flag while
it's not fully removed.

PiperOrigin-RevId: 570736692
(cherry picked from commit a03e20fe6c423389d54eb08d3b1f1d19499a0d9a)
2023-10-06 15:57:25 +01:00
tonihei
7bfddf9558 Remove wrong Javadoc
The corresponding logic has been removed in 796781d4c3

#minor-release

PiperOrigin-RevId: 570729509
(cherry picked from commit 64fe863f315bbc870b347c4d9ea8009fb7713773)
2023-10-06 15:57:25 +01:00
tonihei
889739d33e Replace ENCODING_DTS_UHD_P2 value by reference to platform constant
#minor-release

PiperOrigin-RevId: 570696505
(cherry picked from commit 9ef1c20e7af4cc483e3ab408218545b182c1a28e)
2023-10-06 15:57:25 +01:00
tofunmi
c99c71b5a4 Update getName of BitmapFactoryImageDecoder
cleanup from 8f5835c51c

#minor-release

PiperOrigin-RevId: 570663437
(cherry picked from commit 572fb4676cd8ce5b40c8ab044aeb2250390f1c17)
2023-10-06 15:57:25 +01:00
tonihei
6d2bf513fb Add onAudioTrackInitialized/Released events
This is useful for analytics and understanding player behavior
during transitions.

#minor-release

PiperOrigin-RevId: 570623227
(cherry picked from commit 8e2bf21011c63e2ca2fc58c4353cd66930b621e3)
2023-10-06 15:57:25 +01:00
rohks
55633658c6 Add nullness annotations to DecoderVideoRenderer
Also fixed a bug where format queue was polled with wrong timestamp value.

#fixit

PiperOrigin-RevId: 570420304
(cherry picked from commit a879bae1ee2c684e8100f50bcff39655d46a2e8d)
2023-10-06 15:57:25 +01:00
rohks
7957554442 Add nullness annotations to MediaCodecRenderer
#fixit

PiperOrigin-RevId: 570403923
(cherry picked from commit 7a91474af9f84595743655b18f4164e193bf2fc1)
2023-10-06 15:57:25 +01:00
tonihei
0480b70f36 Move decode-only handling out of MetadataDecoder interface logic
The interface requires the implementation to return null if the
decode-only flag is set. So instead of setting the flag and returning
null, we can simply not call the method and assume it's null.

The only reason where this wouldn't work is if the metadata format
has keyframe-like logic and requires previous metadata to decode
the next one. This is not something we came across before and it seems
ignorable. If that feature is needed in the future, we should instead
add a method to MetadataDecoder to set the first output timestamp.

#minor-release

PiperOrigin-RevId: 570399838
(cherry picked from commit 796781d4c365e31a196c96e0588e4ff5ff0e3bf0)
2023-10-06 15:57:25 +01:00
michaelkatz
2564c11834 Disable offload scheduling at set up for track transition
While sleeping for offload, position is estimated based on time playing. If asleep and AudioTrack is reused, then the position will keep incrementing as the subsequent item plays. That is until wakeup when playing position is updated to the timestamp of the second item. Offload scheduling should be disabled until track transitions fully.

PiperOrigin-RevId: 570397140
(cherry picked from commit da06bf057a230293c8fb7f06cbfba71df8c4b5b1)
2023-10-06 15:57:24 +01:00
jbibik
e4637d82b7 Add DashPlayback test with sideloaded TTML subtitles
The test is hidden behind the Ignore annotation due to some flakiness just like `webvttInMp4`. However, it will be removed when the subtitle parsing is moved to a pre-sample-queue architecture.

#minor-release

PiperOrigin-RevId: 570376275
(cherry picked from commit bd5a3920b85423f1c1b625369fd606a9f36e1248)
2023-10-06 15:57:24 +01:00
jbibik
484339e3e6 Add Dumper support for outputting multiline strings
PiperOrigin-RevId: 570348425
(cherry picked from commit b83f12c4ba5f7adac388f003596214b03d1d9358)
2023-10-06 15:57:24 +01:00
tonihei
bc3dded868 Explicitly mark DecoderOutputBuffer as shouldBeSkipped if needed
In some cases, SimpleDecoder output needs to be skipped for rendering
because the decoder produces no data. This is one of the remaining
usages of BUFFER_FLAG_DECODE_ONLY at the moment and can be more
directly solved without using the flag. SimpleDecoder still needs to
check the flag though for backwards compatbility with custom decoders
while the flag is not completely removed.

PiperOrigin-RevId: 570345233
(cherry picked from commit c8aac24ffd8bfe708d68a251a9f28b3b48bed50c)
2023-10-06 15:57:24 +01:00
samrobinson
27d6a9bcbd Deprecate experimental keepAudioTrackOnSeek methods.
#minor-release

PiperOrigin-RevId: 570340714
(cherry picked from commit 1bb501ab5046cfb7c9e21302cd3a0d73c176512c)
2023-10-06 15:57:24 +01:00
ibaker
ffe65b358f Fix Util.scaleLargeValue/Timestamp to handle negative numbers
#minor-release

PiperOrigin-RevId: 570337535
(cherry picked from commit 9edbfa974aeab851065655e09e8c1accf51a009c)
2023-10-06 15:57:24 +01:00
Copybara-Service
948491f665 Merge pull request #574 from hugohlln:main
PiperOrigin-RevId: 570037211
(cherry picked from commit b06d82323865870e5c3572e867d3cc165200e497)
2023-10-06 15:57:24 +01:00
christosts
ecfddb9aeb MediaCodeVideoRenderer: flush video sink before codec
When seeking, we must first flush the video sink so it stops
using any SurfaceTextures before flushing MediaCodec.

#minor-release

PiperOrigin-RevId: 570015998
(cherry picked from commit 144bd7223626a2936368cbcb3bf3f7004ebe5e45)
2023-10-06 15:57:24 +01:00
ibaker
1c7b426ccb Mark test_session_current support app as MultiDexApplication
PiperOrigin-RevId: 570015354
(cherry picked from commit e9bf41ca044368f6833984a38b0f7804ce9b1960)
2023-10-06 15:57:24 +01:00
bachinger
4acce9bcae Update playlist UI when playlist is updated
When changing the playlist on Android Auto the UI of the
activity needs to be kept in sync.

PiperOrigin-RevId: 569528785
(cherry picked from commit 52d9fbff73cddd5c0881f6fd53a6ba35220d0ed1)
2023-10-06 15:57:24 +01:00
oceanjules
12332a4afc Remove FfmpegVideoRenderer from Media3 1.2.0 release 2023-10-04 13:13:58 +01:00
tianyifeng
3f366109b7 Fix Media3 1.1.1 release notes
PiperOrigin-RevId: 556735572
(cherry picked from commit dca4f1a9db0bc48b0f28c4e64d55cd54bb33e60c)
2023-08-14 12:05:48 +00:00
tianyifeng
9c7cf224e5 Bump version numbers to Media3 1.1.1 and ExoPlayer 2.19.1
PiperOrigin-RevId: 555987303
(cherry picked from commit 1e2a5cd06a23dcfd854ea813c3c56a2612f45f07)
2023-08-14 10:22:43 +00:00
tianyifeng
a842e62991 Update release notes for Media3 1.1.1
PiperOrigin-RevId: 555951054
(cherry picked from commit b24f7678bb1c13c9e596bfebb95e673aeb26c5e8)
2023-08-14 10:22:38 +00:00
jbibik
2fb3a45b6c Fix Gradle Lint with @RequiresApi and SDK version
Gradle Lint doesn't recognise `checkState` assertion and TargetApi should only ever be used for suppressing a bug in Android Lint. Hence, we keep @RequiresApi and add an if-statement explicitly. Also, fixes >26 to >=26 for the version check.

PiperOrigin-RevId: 555144577
(cherry picked from commit f7c31bd3ef525571f69065e836e350f06ff8d81a)
2023-08-09 13:31:48 +00:00
rohks
4af6fcb838 Bump IMA SDK version to 3.30.3
PiperOrigin-RevId: 555130308
(cherry picked from commit 38eabdc9fc22ff17e53f11cdfe09e7af0dab73d0)
2023-08-09 12:16:14 +00:00
tonihei
bab04ebf2c Verify source is not released before updating ad playback state
Updates to the ad playback state are posted on the main handler,
so they may arrive after the source has already been released
(=the internal MediaSource is null). This can cause NPEs.

PiperOrigin-RevId: 555102426
(cherry picked from commit 20d2ce7ce80c5e29c50438a6d581c1c36c1b0771)
2023-08-09 09:51:56 +00:00
jbibik
136f0876d5 Fix PlayerWrapper's creation of VolumeProviderCompat
When hardware buttons are used to control the volume of the remote device, the call propagates to `MediaSessionCompat.setPlaybackToRemote(volumeProviderCompat)`. However, `volumeProviderCompat` was created incorrectly when the new device volume commands were present (COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS and COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS), i.e. with volumeControlType = `VOLUME_CONTROL_FIXED`. This resulted in `VolumeProviderCompat` which doesn't call `onSetVolumeTo` or `onAdjustVolume` and hence doesn't propagate the calls to the `Player`. Instead, it only worked with the deprecated commands which ensured the volumeControlType was `VOLUME_CONTROL_ABSOLUTE`.

This bug was introduced in c71e4bf1ff (1.0 media 3 release) when `PlayerWrapper`'s call to `createVolumeProviderCompat` was mostly rewritten to handle the new commands, but the two if-statements were not amended. Note: this change fixes the bug only for Android 11 and below. For 12 and above, there is a tracking bug for the regression that was introduced: https://issuetracker.google.com/issues/201546605

http://Issue: androidx/media#554

PiperOrigin-RevId: 554966361
(cherry picked from commit dedccc596eb75f9d3fcf7114e8541f3119a88382)
2023-08-08 22:51:53 +00:00
Tianyi Feng
294fa261b7 Merge pull request #528 from zgzong:patch-2
PiperOrigin-RevId: 554869426
(cherry picked from commit ef543644782798a5c0bbdf1464b29e240f058324)
2023-08-10 12:09:43 +00:00
rohks
57c73d51da Add field object type (ot)
Added this CMCD-Object field to Common Media Client Data (CMCD) logging.

PiperOrigin-RevId: 554843305
(cherry picked from commit 3ec462d1cf8c26c717236a4bb4a7bf9ab1fdc7cd)
2023-08-08 16:09:07 +00:00
ibaker
7e58fde18e Use ceiling divide logic in AudioTrackPositionTracker.hasPendingData
This fixes a bug with playing very short audio files, introduced by
fe710871aa

The existing code using floor integer division results in playback never
transitioning to `STATE_ENDED` because at the end of playback for the
short sample clip provided `currentPositionUs=189937`,
`outputSampleRate=16000` and `(189937 * 16000) / 1000000 = 3038.992`,
while `writtenFrames=3039`. This is fixed by using `Util.ceilDivide`
so we return `3039`, which means
`AudioTrackPositionTracker.hasPendingData()` returns `false` (since
`writtenFrames ==
durationUsToFrames(getCurrentPositionUs(/* sourceEnded= */ false))`).

Issue: androidx/media#538
PiperOrigin-RevId: 554481782
(cherry picked from commit 6e91f0d4c5986af238cc77c1a9daa7f012d98a6c)
2023-08-07 15:17:31 +00:00
kimvde
4b3a4b3395 Check command availability before getting tracks in PlayerView
#minor-release

PiperOrigin-RevId: 554451569
(cherry picked from commit 117b18f54c575bab1f82294cdbf7c0384a3dcd36)
2023-08-07 13:01:49 +00:00
tianyifeng
c0c67dd5e6 Update translations
PiperOrigin-RevId: 554439196
(cherry picked from commit ff3902debb19ff75b68de456f3dc8c687fc7eb3f)
2023-08-07 11:54:19 +00:00
rohks
46c757b008 Simplify and accurately compute chunk duration
Refactored `CmcdLog` to `CmcdHeadersFactory` for improved representation of its purpose and updated implementations.

#minor-change

PiperOrigin-RevId: 552831995
2023-08-01 16:48:19 +00:00
rohks
e8a4894a31 Fix wrong documentation and add missing annotations
#minor-release

PiperOrigin-RevId: 552749407
(cherry picked from commit 267d4164a9e68a1065ea8e5a5da40a57dde76e2a)
2023-08-01 11:21:33 +01:00
andrewlewis
50db5207cb Fix parsing of H.265 sequence parameter sets
Fix short term reference picture list parsing. Before this change, `deltaPocS0`
was derived by adding one to the value of the syntax element
`delta_poc_s0_minus1`, but (maybe surprising) the specification actually says
that `DeltaPocS0[stRpsIdx][i]` should be assigned the negation
`-(delta_poc_s0_minus1[i] + 1)` on the first iteration, then that value added
to the previous value on previous iterations. See equations (7-67) to (7-70) in
the 2021-08 version of the H.265/HEVC specification.

Also read the number of long term reference pictures once rather than on every
loop iteration (subsection 7.3.2.2.1).

PiperOrigin-RevId: 551852999
(cherry picked from commit ddb0f8660489c06ce65d9f4b0256a8b60201920d)
2023-07-28 16:00:13 +01:00
bachinger
ab2505d1a9 Only use result.sendError where supported by legacy media library
`MediaLibraryServiceLegacyStub` handles various edge cases by calling
`result.sendError(null)` with the intention to send back an error to
the legacy browser [1].

`MediaBrowserServiceCompat` of the legacy media1 Compat library has an
inner base class `Result` that has a default implementation of
`onErrorSent` that throws an `UnsupportedOperationException` [2].
However, most anonymous inner classes for `Result` created in
`MediaBrowserServiceCompat` do not override `onErrorSent` [3].

Hence Media3 must not call `sendError` in these cases. Instead we call
`sendResult(null)` according to what the default implementation of
the callbacks in `MediaBrowserServiceCompat` do ([4] as an example).

Issue: androidx/media#78
Issue: androidx/media#334

[1] https://github.com/androidx/media/blob/release/libraries/session/src/main/java/androidx/media3/session/MediaLibraryServiceLegacyStub.java#L200
[2] https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:media/media/src/main/java/androidx/media/MediaBrowserServiceCompat.java;l=872
[3] https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:media/media/src/main/java/androidx/media/MediaBrowserServiceCompat.java;l=578-604?q=MediaBrowserServiceCompat&ss=androidx
[4] https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:media/media/src/main/java/androidx/media/MediaBrowserServiceCompat.java;l=1395

PiperOrigin-RevId: 551210137
(cherry picked from commit 17ee5277d5daf3285e10f5a9bffd1ca027ae51aa)
2023-07-26 16:14:39 +01:00
tonihei
ac175a9c37 Fix ms to us conversion bug in DecoderVideoRenderer
The current code multiplies the value by 1000 twice,
effectively converting to nanoseconds.

#minor-release

PiperOrigin-RevId: 551129750
(cherry picked from commit f7669361407ad0b1fe536a8fb5d78e3f4e77026c)
2023-07-26 09:43:03 +01:00
ibaker
db336d5c74 Add comment about out-of-order timestamps in AtomParsers.parseStbl
PiperOrigin-RevId: 550596173
(cherry picked from commit 449cf55523622bd48c8879a25544f57c50aa75a9)
2023-07-24 18:05:04 +01:00
ibaker
eaf4a2b448 Tighten the demo app's handling of DrmInitData for downloads
This code is Widevine specific. `OfflineLicenseHelper.downloadLicense`
requires the passed `Format` to have a `DrmInitData.SchemeData` with
Widevine UUID and non-null `data` field. The demo app tries to check
this in advance (to avoid an exception later), but its checks are
looser than those made by `OfflineLicenseHelper`. This change tightens
the checks to match.

Issue: androidx/media#512
PiperOrigin-RevId: 549587506
(cherry picked from commit 1ccedf84142bec02ee52e76e714c7fc8dc394eea)
2023-07-20 12:03:36 +01:00
rohks
7352a1be0a Add field measured throughput (mtp)
Updated `ExoTrackSelection` to provide the most recent bitrate estimate, enabling the inclusion of measured throughput (mtp) as a CMCD-Request field in Common Media Client Data (CMCD) logging.

Additionally, made changes to the `checkArgument` methods in `CmcdLog` to prevent the use of default values in certain cases.

PiperOrigin-RevId: 549369529
(cherry picked from commit cdb174c91a0a9e5387f9773ac24f015199a7999e)
2023-07-19 19:10:56 +01:00
rohks
6443614020 Add fields top bitrate(tb) and object duration(d)
Added these CMCD-Object fields to Common Media Client Data (CMCD) logging.

PiperOrigin-RevId: 548950296
(cherry picked from commit 1b2a2fcde00c5bd05573e777c4e8a2bf60db7137)
2023-07-18 11:24:34 +01:00
tonihei
3931c28697 Fix race condition in clipped sample streams
The streams return end-of-input if they read no samples, but know that
they are fully buffered to at least the clipped end time. This helps to
detect the end of stream even if there are no new buffers after the end
of the clip (e.g. for sparse metadata tracks).

The race condition occurs because the buffered position is evaluated
after reading the sample. So between reading "no sample" and checking
the buffered position, the source may have loaded arbitrary amounts
of data. This may lead to a situation where the source has not read
all samples, reads NOTHING_READ (because the queue is empty) and then
immediately returns end-of-stream (because the buffered position
jumped forward), causing all remaining samples in the stream to be
skipped. This can fixed by moving the buffered position check to
before reading the sample, so that it never exceeds the buffered
position at the time of reading "no sample".

#minor-release

PiperOrigin-RevId: 548646464
(cherry picked from commit c64d9fd6da90497547daf3deea536af2007784a5)
2023-07-17 12:17:17 +01:00
tonihei
d4c66e549a Remove duplicated release note entry
Issue: androidx/media#515

#minor-release

PiperOrigin-RevId: 548111465
(cherry picked from commit 42998d6400aaf6ce773383be9ed6386a7c56e125)
2023-07-14 14:36:33 +01:00
michaelkatz
09835006f4 Prepend Ogg ID and Comment Header Pages to offloaded Opus stream
Add Ogg ID Header and Comment Header Pages to the Ogg encapsulated Opus for offload playback. This further matches the RFC 7845 spec and provides initialization data to decoders.

PiperOrigin-RevId: 548080222
(cherry picked from commit 847f6f24d3770b6134a233b62a5fa9413c9bd26c)
2023-07-14 11:41:56 +01:00
rohks
57d0c197cc Add tests for DefaultSsChunkSource
Added tests for Common Media Client Data (CMCD) logging in SmoothStreaming(SS)

PiperOrigin-RevId: 548072725
2023-07-14 11:03:05 +01:00
rohks
88e34017a3 Fix dependencies for UI module
PiperOrigin-RevId: 548063325
(cherry picked from commit 4d40f2e7ddfce700e74f759d3ed8143df7f6b0c8)
2023-07-14 10:12:32 +01:00
rohks
77fb6525b1 Replace Dummy with Placeholder
`Dummy` is a non inclusive language.

PiperOrigin-RevId: 547815680
(cherry picked from commit ca10204b2df316c9524e1986cba272b8c855867e)
2023-07-13 16:55:49 +01:00
rohks
272c844abd Add fields streaming format(sf), stream type(st) and version(v)
Added these CMCD-Session fields to Common Media Client Data (CMCD) logging.

PiperOrigin-RevId: 547435498
(cherry picked from commit 0412a36564a09c0a237b91b4a78fed80336ea6b6)
2023-07-12 10:25:50 +01:00
bachinger
7d35f18732 Add custom layout to the state of the MediaController
This change also marks the buttons of the custom layout as
enabled/disabled according to available commands in the controller.
Accordingly, `CommandButton.Builder.setEnabled(boolean)` is deprecated
because the value is overridden by the library.

Issue: androidx/media#38

PiperOrigin-RevId: 547272588
(cherry picked from commit ea21d27a6974822a970261f38964ec86c305796b)
2023-07-11 20:59:01 +01:00
ibaker
996755c22b Expand @UnstableApi javadoc with how to request stable API additions
Issue: androidx/media#503

#minor-release

PiperOrigin-RevId: 547143885
(cherry picked from commit 2afcf9959124ee906b65569e7e4ae0ffb47e88a3)
2023-07-11 11:57:13 +01:00
ibaker
c1261aa266 Remove javadoc @link from non-javadoc comments
Also update type names to match the current names for these types.

PiperOrigin-RevId: 546884049
(cherry picked from commit eed0e42ff805f54161125bbb6983f30ba0d39e8a)
2023-07-10 16:46:18 +01:00
ibaker
bae387651b Clarify that new ConditionVariable instances are closed
#minor-release

PiperOrigin-RevId: 546803592
(cherry picked from commit a8520bdee63509597c19ecf72d96a5da1ecf4a0b)
2023-07-10 10:10:03 +01:00
andrewlewis
405e5a6e3e Fix incorrect class name for MediaPipe demo
Issue: androidx/media#500

#minor-release

PiperOrigin-RevId: 545942450
(cherry picked from commit bdbf3e29a1a49f1be1fd4ada7c36b4ae80c83510)
2023-07-06 12:07:21 +01:00
tonihei
9de5684d6e Change multidex dependency type to androidTestImplementation
This is only needed for instrumentation tests and should not
be included in regular builds.

Issue: androidx/media#499
PiperOrigin-RevId: 545913113
(cherry picked from commit 2250ffe6c8c5fa6b5bc728cd7a9fa075bcbb04d9)
2023-07-06 09:45:11 +01:00
rohks
0c6cfea048 Replace BitArray.skipBytes() with BitArray.skipBits()
Based on the spec, ETSI TS 102 366 V1.4.1 Annex F, 6 bits should have skipped instead of 6 bytes.

This correction was pointed out in Issue: androidx/media#474.

PiperOrigin-RevId: 545658365
(cherry picked from commit 07d4e5986b06ef6e362fe00fb97187469f42bc25)
2023-07-05 15:04:50 +01:00
ibaker
bcde7e03c2 Include timing info in some SCTE-35 toString implementations
This was helpful in investigating Issue: androidx/media#471

PiperOrigin-RevId: 545393217
(cherry picked from commit 3456382ae7116a8bb57b4212f449dfb50ea490d9)
2023-07-04 10:09:27 +00:00
michaelkatz
cb7b3862c4 Add nanoTime method to Clock to support overriding System.nanoTime()
PiperOrigin-RevId: 545237925
(cherry picked from commit de4575da28ee98a46e284cc8c7f11d34da1df29e)
2023-07-03 16:29:13 +00:00
tonihei
26ee4c35f3 Replace exoplayer.dev@gmail.com with android-media-github@google.com
#minor-release

PiperOrigin-RevId: 545165879
(cherry picked from commit 5e19a33095eeebec0dacbbb7e37c6ff5cb78055f)
2023-07-03 09:34:55 +00:00
ibaker
aa34db41f7 CEA-608: Only truncate to 32 visible characters
We introduced truncation to 32 chars in <unknown commit>
and included indent and offset in the calculation. I think this is
technically correct, but it causes problems with the content in
Issue: google/ExoPlayer#11019 and it doesn't seem a problem to only truncate actual
cue text (i.e. ignore offset and indent).

PiperOrigin-RevId: 544677965
(cherry picked from commit e8fdd83558dcb0a4f886c52c8b32e2c1f3637a48)
2023-06-30 16:35:46 +00:00
tonihei
aefba8a565 Remove dead code in ProgressiveMediaSource.Builder
These fields cannot be set and the logic to handle them can be removed.

PiperOrigin-RevId: 544646460
(cherry picked from commit 2f113c8b8234ca80fd0968f845dd195fcf956c6d)
2023-06-30 14:05:39 +00:00
microkatz
3a66617b9e Merge pull request #487 from vishnuchilakala:allow_unsigned_int_for_adaptation_set_id
PiperOrigin-RevId: 544601945
(cherry picked from commit 9513f2c551e73cdb0ffa27401d7817928b99064e)
2023-07-05 08:53:09 +00:00
tianyifeng
52706b2eb4 Ensure that ShuffleOrder has the same length as the current playlist
Add a fail-fast check in `ExoPlayerImpl` to ensure the equality of the lengths of `ShuffleOrder` and the current playlist. Also improve the documentation of `setShuffleOrder(ShuffleOrder)` with explicit instruction on this.

Issue: androidx/media#480

#minor-release

PiperOrigin-RevId: 544009359
(cherry picked from commit d895a46b280f1f9764f63a5fc1ba16ab2727191e)
2023-06-28 10:41:49 +00:00
tonihei
f768fedaee Clarify MediaPeriod.readDiscontinuity Javadoc
It currently wrongly documents that it is only called before reading
streams (that has never been the case and all MediaPeriods already need
to handle calls after reading samples from the streams).

It was also a bit unclear what a discontinuity implies and the new
Javadoc calls out the main use case for discontinuties and the intended
meaning of returning a discontinuity.

#minor-release

PiperOrigin-RevId: 543989124
(cherry picked from commit b324b8aa72db8853cf28429fa6462acdbf769f21)
2023-06-28 08:55:56 +00:00
tianyifeng
7683ee254a Use different package names in DiagnosticInfo for media3 and exoplayer
Issue: androidx/media#476

#minor-release

PiperOrigin-RevId: 543460075
(cherry picked from commit 140c83ce7ef08ed010b474baf1ea31419df766bb)
2023-06-26 16:28:47 +00:00
tonihei
ec13c42800 Do not trim audio samples by changing their timestamp
MP4 edit lists sometimes ask to start playback between two samples.
If this happens, we currently change the timestamp of the first
sample to zero to trim it (e.g. to display the first frame for a
slightly shorter period of time). However, we can't do this to audio
samples are they have an inherent duration and trimming them this
way is not possible.

PiperOrigin-RevId: 543420218
(cherry picked from commit 232246240415443ff8d3a8cd5930273b4085ddaa)
2023-06-26 13:26:35 +00:00
Googler
bf4561c606 Removing @CallSuper from [add,remove]Listener of ForwardingListener.
PiperOrigin-RevId: 543373503
(cherry picked from commit 1fc49ce288809e7634971f9dcb8121fe13e6a854)
2023-06-26 09:11:27 +00:00
jbibik
b220dfe73c Cleaner unified PlayerInfo update method in MediaControllerImplBase
`MediaControllerImplBase` has 2 methods for updating listeners about `PlayerInfo` changes - `updatePlayerInfo` (for masking the state) and `onPlayerInfoChanged` (when communicating with the session). There is a set number of listener callbacks related to `PlayerInfo` updates and both methods should go through the same control flow (whether we know that masking will ignore most of them or not).

A unified method `notifyPlayerInfoListenersWithReasons` encapsulates only the shared logic of 2 methods - listeners' callbacks. This ensures that both methods call them in the same order and none are missed out.

PiperOrigin-RevId: 542587879
(cherry picked from commit c2d80516628e4f62a4ec88ae1240002e6cc85aef)
2023-06-22 16:49:36 +00:00
jbibik
e008e21b0f Fix missing equals sign in inline-comment parameter names
PiperOrigin-RevId: 542577676
(cherry picked from commit ea0f564c1ea409f717c4cc0277d6c7b82eeb84b9)
2023-06-22 16:09:57 +00:00
jbibik
b4c7e6cb86 Order MediaControllerImplBase listener callbacks as in ExoPlayerImpl
The callbacks for `PlayerInfo` changes are currently in both `MediaControllerImplBase.updatePlayerInfo` (masking) and `MediaControllerImplBase.onPlayerInfoChanged`. But the order was different between them both and `ExoPlayerImpl.updatePlaybackInfo` which they are trying to mimic.

#minor-release

PiperOrigin-RevId: 542519070
(cherry picked from commit b8ac5b42107b7d291162558378c2482bb84576f0)
2023-06-22 11:19:48 +00:00
ibaker
4f5d59b58f Switch to SVG assets hosted on developer.android.com for reference docs
#minor-release

PiperOrigin-RevId: 541970884
(cherry picked from commit 34f23451e66ca85a32a072ad4eada271fd79f898)
2023-06-20 17:23:37 +00:00
bachinger
f6a30f6645 Fix ArrayIndexOutOfBoundIndex when re-preparing after exception
When an app tried to re-prepare a live streeam with server side inserted
ad after a playback exception, the player tried to find the ad group by
its index in the ad playback state of the next timeline when creating
the first period.

If a source that supports server side ad, has removed the ad playback
state when the source has been removed, this causes a crash. For live
streams this is a reasonable thing to do given the exception could be
caused by an invalid ad playback state.

This change removes the ad metadata from the current period for live
streams and the timeline. In case the ad playback state is not reset
by the source, the first timeline refresh would ad the metadata again.

PiperOrigin-RevId: 541959628
(cherry picked from commit 4604f0cde691311d8a1104d66e6eb724766ce4b0)
2023-06-20 16:55:22 +00:00
jbibik
4710b8f03a Fixed spelling across various PlayerInfo *ChangeReason fields
PiperOrigin-RevId: 541892788
(cherry picked from commit b9cc70d9e2d0248a10ad209e362db630a051448c)
2023-06-20 13:06:34 +00:00
tonihei
3561258949 Fix spurious sessions created for events after the playlist is cleared
Some events may arrive after the playlist is cleared (e.g. load
cancellation). In this case, the DefaultPlaybackSessionManager may
create a new session for the already removed item.

We already have checks in place that ignore events with old
windowSequenceNumbers, but these checks only work if the current
session is set (i.e. the playlist is non-empty). The fix is to add
the same check for empty playlists by keeping note of the last
removed window sequence number.

PiperOrigin-RevId: 541870812
(cherry picked from commit e0191ddded1754cc31b025493970240aeb08a46e)
2023-06-20 12:27:23 +01:00
Marc Baechinger
7e0296fa7c Merge pull request #436 from jaeho-lee104:feature/improve_condition
PiperOrigin-RevId: 540875285
(cherry picked from commit af69d5822ae4df4a2a9dec2706a49c15f5112d3d)
2023-06-19 16:25:40 +01:00
rohks
f01ca9d9f1 Refactor method CmcdLog.createInstance to accept bufferedDurationUs
Instead of providing `playbackDurationUs` and `loadPositionUs` individually, which are used to calculate the buffer duration for CMCD logging, we can directly pass the pre-calculated `bufferedDurationUs` available in the `getNextChunk` method of the chunk source classes.

Issue: google/ExoPlayer#8699

#minor-release

PiperOrigin-RevId: 540630112
(cherry picked from commit be9b057dda1a6a2da0e57b3b6f3620b371b7fd6e)
2023-06-15 18:55:30 +01:00
rohks
0aede89586 Add CMCD logging when requesting initialization chunk for DASH and HLS
Additionally, two existing methods to `buildDataSpec` in `DashUtil` have been deprecated, while a new method has been added that allows the inclusion of `httpRequestHeaders`.

Issue: google/ExoPlayer#8699

#minor-release

PiperOrigin-RevId: 540594444
(cherry picked from commit 52878b2aca599d7aee3d87d76d602e81b1946d00)
2023-06-15 16:48:55 +01:00
jbibik
2367e7a9e8 Default RepeatMode for conversion is NONE/OFF
Current behaviour causes an app to crash if it receives an unrecognized repeat mode send over the wire. In order to avoid the crash, a sensible default had to be chosen.

For `Player.RepeatMode`, it is `Player.REPEAT_MODE_OFF`, which is the same value we use as default when unbundling `PlayerInfo`.

For `PlaybackStateCompat.RepeatMode`, it is `PlaybackStateCompat.REPEAT_MODE_NONE`, which is what we use in the no-arg `LegacyPlayerInfo` constructor.

Issue: androidx/media#448

#minor-release

PiperOrigin-RevId: 540563792
(cherry picked from commit 501da109ced14c498eeafcd62d1fbe12e6ecc76e)
2023-06-15 14:31:59 +01:00
ibaker
3c9831fcb4 Remove = from parameter args in call to Constructor.newInstance
These comments reflect the parameter names of the constructor that
we're reflectively calling, but errorprone complains that they don't
match the parameter names of `Constructor.newInstance`.

PiperOrigin-RevId: 540348118
(cherry picked from commit 567890da9ed473b32b6e23c2b499e1e40d835487)
2023-06-14 20:32:01 +01:00
siroberts
648e9943e5 Add missing checkNotNull to bitmapLoader.
#minor-release

PiperOrigin-RevId: 540309118
(cherry picked from commit cf21add916538d3debd51f53ab43710d813e7b02)
2023-06-14 18:22:13 +01:00
bachinger
3cfdd4fdc5 Implement equals/hashCode for CommandButton
#minor-release

PiperOrigin-RevId: 540274932
(cherry picked from commit 3d674fa2f39414824871c88dd73246cbeddb95f8)
2023-06-14 16:13:48 +01:00
ibaker
983d9d57d7 Stop suppressing exceptions in MediaCodec.Callback during flush
Previously `AsynchronousMediaCodecCallback.mediaCodecException` was
cleared when flushing completed. This behaviour was changed in
aeff51c507
so now the exception is not cleared.

The result after that commit was that we would **only** suppress/ignore
the expression if a flush was currently pending, and we would throw it
both before and after the flush. This doesn't really make sense, so this
commit changes the behaviour to also throw the exception during the
flush.

This commit also corrects the assertion in
`flush_withPendingError_resetsError` and deflakes it so that it
consistently passes. The previous version of this test, although the
assertion was incorrect, would often pass because the
`dequeueInputBuffer` call would happen while the `flush` was still
pending, so the exception was suppressed.

#minor-release

PiperOrigin-RevId: 540237228
(cherry picked from commit 248d1d99ecd1f3d57b1acc1cdc6f160b3b8aa495)
2023-06-14 13:07:39 +01:00
tonihei
a9b78318ca Add missing @Override
PiperOrigin-RevId: 540220141
(cherry picked from commit c76680a65c8647c9ce153d116e4bfd94da765daa)
2023-06-14 11:26:38 +01:00
jbibik
9dec0d308b Notify listeners of error changes when masking in MediaControllerImplBase
Currently, the implementation of `MediaControllerImplBase` differs from `ExoPlayerImpl`. The listeners of the former are notified of player error changes only in `onPlayerInfoChanged` and not `updatePlayerInfo` (masking method). Whereas `ExoPlayerImpl` has one unified method - `updatePlaybackInfo` - which sends the events to all the available listeners.

This change fixes the lack of 2 particular callbacks - `onPlayerErrorChanged` and `onPlayerError`, however, there might be more differences. Ideally, there should be a unified method for oldPlayerInfo/newPlayerInfo comparison-update-notify-listeners flow.

Issue: androidx/media#449

#minor-release

PiperOrigin-RevId: 539961618
(cherry picked from commit 4b5a4577905d86ec6e24a92a088a65689c7be901)
2023-06-13 15:46:46 +01:00
ibaker
6615399861 Release ExoPlayer instances in ExoPlayerTest
This was recommended in https://github.com/robolectric/robolectric/issues/8187#issuecomment-1552060094

PiperOrigin-RevId: 539691757
(cherry picked from commit 959e97413887fff5096df65783a895803060d31a)
2023-06-12 18:19:56 +01:00
bachinger
c3a96b2e08 Clean up HLS sample for cast demo
Issue: androidx/media#452
#minor-release
PiperOrigin-RevId: 539613535
(cherry picked from commit c2f78db87e9cd4bcf118d6ab1b7e3a7d86ee55e9)
2023-06-12 11:40:30 +00:00
claincly
0cf3ab31bf Factor out video decoding and fix two minor issues
1. Not treating 0 as valid buffer index
2. Not handling the case the last frame is a comparison frame

PiperOrigin-RevId: 539607482
(cherry picked from commit 4b1ac2f17229a31754440693dc06ef583752070a)
2023-06-12 11:05:08 +00:00
ibaker
8ff61a1430 Stop setting -no-module-directories in ExoPlayer javadoc generation
This flag was introduced to fix links in javadoc search when generating
it with Java 11: <unknown commit>

The flag is no longer supported with Java 17 (which is required for
Gradle 8.0+), and seems to no longer be needed: I generated the javadoc
with it removed and the search links work OK.

PiperOrigin-RevId: 536738686
2023-08-11 15:52:04 +00:00
Tofunmi Adigun-Hameed
5328d6464a
Merge pull request #498 from androidx/release-1.1.0
Release 1.1.0
2023-07-05 08:56:12 +00:00
ibaker
00005cb09d Replace exoplayer.dev@gmail.com with android-media-github@google.com
#minor-release

PiperOrigin-RevId: 544596686
(cherry picked from commit f2c0eab468fa683e03323cc7164f450a123d773a)
2023-06-30 10:57:51 +01:00
tofunmi
1d73c68465 Fix version bump for media3:1.1.0
#minor-release

PiperOrigin-RevId: 543376501
(cherry picked from commit 10cf06386dfdaf63ffbb361c094a3f3e834deaf4)
2023-06-26 10:04:55 +00:00
tofunmi
5fdeabbed8 Version bump for exoplayer 2.19.0 continued
#minor-release

PiperOrigin-RevId: 543369900
(cherry picked from commit 81dfe9d4b44099bbc5c2f4e8a925339e719fbfbe)
2023-06-26 10:04:55 +00:00
tofunmi
ece76c4b61 Version bump to media3-1.1.0 and exoplayer 2.19.0
#minor-release

PiperOrigin-RevId: 542881427
(cherry picked from commit 114364897b42a71cac7d012c2c0b764c6866eb7a)
2023-06-23 18:11:57 +00:00
tofunmi
69c6038e32 Merge release notes for media3 1.1.0 stable release
Merged during cherry-pick

PiperOrigin-RevId: 542539300
(cherry picked from commit 7e475146dd08a444da30eee6dc75246384bf163a)
2023-06-23 12:20:40 +00:00
ibaker
b1522b4069 Add a section to CONTRIBUTING.md about push access to PR forks
#minor-release

PiperOrigin-RevId: 542294607
(cherry picked from commit 3f7599e9c3be199ca55e053894571d46c1f86b98)
2023-06-23 12:13:32 +00:00
ibaker
bcdadbfdf5 Fix two more unresolved SVGs in Timeline.Window and Timeline.Period
These were missed in 10342507f7

#minor-release

PiperOrigin-RevId: 541860649
(cherry picked from commit 71f73229dd37f001bbec2e909c606ccfa1decfd6)
2023-06-23 12:13:31 +00:00
bachinger
1ae8ddd0fd Document how to use a custom receiver app with the cast demo
#minor-release
Issue: androidx/media#452
PiperOrigin-RevId: 539915277
(cherry picked from commit 5afe7552fea22f7d6e600a3c2ef7ff14962f4c77)
2023-06-23 12:13:31 +00:00
bachinger
e53796fc25 Fix bug where PlayerView distorts video when video size is unknown
PiperOrigin-RevId: 541640959
(cherry picked from commit 8d8c514d1220904a8d2df3f9bc3176877df9f553)
2023-06-19 17:03:25 +01:00
tofunmi
3631e1c6f3 Version bump to media3:1.1.0-rc01
#minor-release

PiperOrigin-RevId: 539632164
(cherry picked from commit 4bceb64dee2e143016bdd8cb355c160890df8bc2)
2023-06-12 13:23:56 +00:00
tofunmi
66b59ec3a7 Update RELEASENOTES.md for media3-1.1.0-rc01 release
Removed unreleased changes in this cherry-pick.

PiperOrigin-RevId: 539606230
(cherry picked from commit 49b893f6f375b44d310e0b720cbea7197061625b)
2023-06-12 16:15:31 +00:00
Googler
2ee0900659 Rollback of a66f08ba97
*** Original commit ***

Add a timer to end a video stream prematurely in ExtTexMgr

***

This has been submitting for more than 1.5hrs. "This presubmit is running slowly because you have been throttled by Build Queue due to using too much of your Product Area's quota."

adding NO_SQ as this is a pure rollback

PiperOrigin-RevId: 539135970
(cherry picked from commit 5c29abbbf4d2fb7c7770bcc79a1027c532f7b96e)
2023-06-12 09:15:55 +00:00
tianyifeng
23e92805a1 Throw exception when TimestampAdjuster initialization hits timeout
Add `HlsMediaSource.Factory.setTimestampAdjusterInitializationTimeoutMs(long)` to set the timeout for the loading thread to wait for the `TimestampAdjuster` to initialize. If the initialization doesn't complete before the timeout, a `PlaybackException` is thrown to avoid the playback endless stalling. The timeout is set to zero by default.

This can avoid HLS playback endlessly stalls when manifest has missing discontinuities. According to the HLS spec, all variants and renditions have discontinuities at the same points in time. If not, the one with discontinuities will have a new `TimestampAdjuster` not shared by the others. When the loading thread of that variant is waiting for the other threads to initialize the timestamp and hits the timeout, the playback will stall.

Issue: androidx/media#323

#minor-release

PiperOrigin-RevId: 539108886
(cherry picked from commit db3e662bdc17945acbe835120806b6aa597dee8a)
2023-06-12 09:15:54 +00:00
bachinger
21fb8c9942 Fix splitting ad playback state for partial ad group when joining
This change addresses the case when the user joins the live stream
on an ad period but the metadata for the ad period is not emitted.
This results in inserting a partial ad group.

In this case the ad group duration is longer than the partial ad
group. If now the partial ad group ends at the period before the
last period of the window (unknown duration), the splitting algorithm
didn't recognize that the ad group already ended and made the last
period wrongly an ad period.

This change handles this edge case by counting the mapped ads in
the partial ad group to detect this situation and stops splitting.

#minor-release

PiperOrigin-RevId: 539102785
(cherry picked from commit cd604e7ead3e4393dd6bf7b615df00b1b6da5d4a)
2023-06-12 09:15:54 +00:00
claincly
4dae1a1679 Add missing empty lines
PiperOrigin-RevId: 539100987
(cherry picked from commit edf30433b6780788a3410c8bc98f527d9a01444b)
2023-06-12 09:15:54 +00:00
bachinger
56c62d1ab1 Make current period a placeholder when a live stream is reset
In case the player is reset while a live stream is playing, the current
period needs to be a placeholder. This makes sure that the default start
position is used when the first live timeline arrives after re-preparing.

#minor-release

PiperOrigin-RevId: 539044360
(cherry picked from commit 71153a43a8e55380076af97450414f9142dc636b)
2023-06-12 09:15:54 +00:00
claincly
50f4caacd6 Add a timer to end a video stream prematurely in ExtTexMgr
PiperOrigin-RevId: 539036285
(cherry picked from commit a66f08ba978c2bd146242eec86dd69d8a85b5408)
2023-06-12 09:15:54 +00:00
bachinger
1c8c563263 Do not reset period uid when DashMediaSource is released
When the source is prepared again after stop, the period uid
is calculated by subtracting the `firstPeriodId` from the
period uid that is passed in to `createPeriod`. When this
happens after stop, the uid from the old period uid that
is still stored and has the value of the last played uid.

Hence the `firstPeriodId` must not be reset when released.

Issue: google/ExoPlayer#10838
PiperOrigin-RevId: 539028570
(cherry picked from commit 319854d624a95d3f71a26c96ecb4e5827d4a7f4e)
2023-06-12 09:15:54 +00:00
rohks
f1529d63a1 Implement logging support for Common Media Client Data (CMCD)
Add support for including Common Media Client Data (CMCD) in the outgoing requests of adaptive streaming formats DASH, HLS, and SmoothStreaming.

API structure and API methods:
   *   CMCD logging is disabled by default, use `MediaSource.Factory.setCmcdConfigurationFactory(CmcdConfiguration.Factory cmcdConfigurationFactory)` to enable it.
   *   All keys are enabled by default, override `CmcdConfiguration.RequestConfig.isKeyAllowed(String key)` to filter out which keys are logged.
   *  Override `CmcdConfiguration.RequestConfig.getCustomData()` to enable custom key logging.

NOTE: Only the following fields have been implemented: `br`, `bl`, `cid`, `rtp`, and `sid`.

Issue: google/ExoPlayer#8699

#minor-release

PiperOrigin-RevId: 539021056
(cherry picked from commit b55ddf12b4536b457b8ad843047f559fa8ed5c33)
2023-06-12 09:15:54 +00:00
bachinger
ec3446fe8b Enable re-preparing the ImaSSAIMediaSource
#minor-release

PiperOrigin-RevId: 538927855
(cherry picked from commit a67ce066df228f789549350f2e92af12003c0220)
2023-06-12 09:15:53 +00:00
jbibik
f18ec2e0c5 Make StreamKey Bundleable and remove deprecated trackIndex
#minor-release

PiperOrigin-RevId: 538809105
(cherry picked from commit 28b8fb706a016e7771313e0f3dea73a0c27833f8)
2023-06-12 09:15:53 +00:00
tofunmi
39b98fe5ad Add 'Keep every nth frame' frame dropping strategy.
#minor-release

PiperOrigin-RevId: 538804347
(cherry picked from commit 276f2f1fe65402dbfd9d9f273d1c4da8eb08865b)
2023-06-12 09:15:53 +00:00
tianyifeng
78f23c0c9b Add seekPrev and seekNext buttons on the default compact notification
This change is for Android 12 and below, where the buttons are derived from the actions added with the notification. From Android 13 (https://developer.android.com/about/versions/13/behavior-changes-13#playback-controls), the system derives media controls from `PlaybackState` actions.

When adding the actions onto the notification, the logic will iterate all the command buttons. The `COMMAND_KEY_CONPACT_VIEW_INDEX` extra will be checked for each button. If that extra is set for the three buttons on the compact view, then the customized buttons and their order will be used. Otherwise, the compact view will be "seekPrev" (if any), "play/pause" (if any), "seekNext" (if any) buttons (in such order).

Issue: androidx/media#410
PiperOrigin-RevId: 538797874
(cherry picked from commit 2e2f19351f751a084889fc3b1d8dfbfa1eb757d7)
2023-06-12 09:15:53 +00:00
claincly
f1b942150c Fix calling extra registerInputStream and not handling EOS
PiperOrigin-RevId: 538796466
(cherry picked from commit a7cff4e0e300e971035cf23f3840a80b387d0d65)
2023-06-12 09:15:53 +00:00
sheenachhabra
ebfb9cf402 Add support for passing custom metadata via transformer
Changes included:
1. Enable MP4 extractor to read all types of metadata.
2. Allow passing String and Float metadata via Transformer.

Reference to QuickTime spec: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW21

PiperOrigin-RevId: 538783982
(cherry picked from commit 53c174f047ac759e6ff3c44776d7d46fc0aed755)
2023-06-12 09:15:53 +00:00
sheenachhabra
f2c0d7e13c Enable nullness checker for Muxer module androidTest library
PiperOrigin-RevId: 538742957
(cherry picked from commit 2753fb0e3e05616ed096db31675f3eeaa25ec5b1)
2023-06-12 09:15:53 +00:00
huangdarwin
6dcfe44b89 Test: Add no-op effect test for GL tone mapping.
To ensure no regressions for the potentially confusing pipeline of:
* HDR electrical -> SDR linear EOTF+OOTF, and
* SDR linear -> SDR electrical OETF

PiperOrigin-RevId: 538741079
(cherry picked from commit 0c924fcb4072d7485e0e5b61097c2e7c37eb6b6a)
2023-06-12 09:15:53 +00:00
tofunmi
5afc256eba DefaultVideoFrameProcessorMultipleTextureOutputPixelTest fixes & cleanup
PiperOrigin-RevId: 538495675
(cherry picked from commit ce203ccfede1b7762ca5b5ea0924fb9bef13a8a3)
2023-06-12 09:15:52 +00:00
huangdarwin
797ee99baf Test: Move duplicated GL tone mapping logic into helper methods.
PiperOrigin-RevId: 538491957
(cherry picked from commit 9dad207603ed778bbdd428b1ebe501a94747a088)
2023-06-12 09:15:52 +00:00
kimvde
71c2d7ba92 Remove unnecessary thread in AssetLoader tests
Also queue textures from a different thread in TextureAssetLoader, to
have a behaviour closer to reality.

PiperOrigin-RevId: 538473089
(cherry picked from commit 3ba8f6dd8fe57c2b1edde75630f568d374c1b69f)
2023-06-12 09:15:52 +00:00
jbibik
ade2990503 Fix 1 ErrorProneStyle finding
PiperOrigin-RevId: 538469993
(cherry picked from commit e7f7e86f3e2f242dd9bdd1a9ffaeefb1e1693320)
2023-06-12 09:15:52 +00:00
tofunmi
f7245a5ff2 Tests for disabled color transfers
#minor-release

PiperOrigin-RevId: 538466615
(cherry picked from commit c3b9328d74e21a05ff463ea8250510663233b79c)
2023-06-12 09:15:52 +00:00
huangdarwin
295eb06145 Effect: Add multiple texture output test.
Confirms that multiple textures can be output, and that timestamps and pixels
are as expected.

PiperOrigin-RevId: 538459296
(cherry picked from commit adf53b4d508320e8b60bcfd2d5366ff9a5065736)
2023-06-12 09:15:52 +00:00
andrewlewis
752a49c8d0 Log additional information on test runner timeout
PiperOrigin-RevId: 538437142
(cherry picked from commit 828a05e0fa1385ae3f645e471ef24c8a161268c7)
2023-06-12 09:15:52 +00:00
Tofunmi Adigun-Hameed
9b136d3368 Merge pull request #371 from tatsuyafujisaki:simplify-loadJSONFromAsset
PiperOrigin-RevId: 538423581
(cherry picked from commit 9aa519f1eef66592c85e35ebd38912ec301df9fb)
2023-06-12 09:15:52 +00:00
Tofunmi Adigun-Hameed
9db3769fac Merge pull request #439 from kaidokert:pick_workaround
PiperOrigin-RevId: 538209925
(cherry picked from commit 886717e3fe08a89d3e3400c6bd51b9aa15d5aa7a)
2023-06-12 09:15:51 +00:00
sheenachhabra
f1d285ed6f Add support for passing creation time via InAppMuxer
PiperOrigin-RevId: 538175466
(cherry picked from commit 7e14811e255b6a5da4e9c3f5bdf7c0f4e783840a)
2023-06-12 09:15:51 +00:00
Tofunmi Adigun-Hameed
d4e0a8d13d Merge pull request #425 from vishnuchilakala:set_min_live_position
PiperOrigin-RevId: 538173603
(cherry picked from commit 9ca6e5d90dfda78a74609721a9a4e6a901bd7a92)
2023-06-12 09:15:51 +00:00
tianyifeng
1c1ca3edaf Defer outputting the metadata sample when TimestampAdjuster isn't initialized
The sample timestamp carried by the emsg box can have a significant delta when comparing to the earliest presentation timestamp of the segment. Using this timestamp to intialize the timestamp offset in TimestampAdjuster will cause the media sample to have a wrong adjusted timestamp. So we should defer adjusting the metadata sample timestamp until the TimestampAdjuster is initialized with a real media sample.

PiperOrigin-RevId: 538172841
(cherry picked from commit f4bf376e891bb0326b4c569cecec825e870aec92)
2023-06-12 09:15:51 +00:00
claincly
70a25b01bf Add utility to create ScheduledExecutorService
PiperOrigin-RevId: 538129792
(cherry picked from commit 08e7158be51324752c4ae0f3b4f723b6fae7e7a8)
2023-06-12 09:15:51 +00:00
jbibik
a5949d8806 Allow playback of MediaItems with LocalConfiguration
When initiated by MediaController, it should be possible for `MediaSession` to pass `MediaItems` to the `Player` if they have `LocalConfiguration`. In such case, it is not required to override `MediaSession.Callback.onAddMediaItems`, because the new current default implementation will handle it.

However, in other cases, MediaItem.toBundle() will continue to strip the LocalConfiguration information.

Issue: androidx/media#282

RELEASENOTES.md modified in cherrypick

PiperOrigin-RevId: 537993460
(cherry picked from commit d9764c18adbc8b1fe23d983f92c68a582394b33a)
2023-06-12 09:15:01 +00:00
Googler
4a90efaf10 Override ParserException#getMessage
PiperOrigin-RevId: 537908595
(cherry picked from commit 83e9080b718d1d063d8efcd9d35c58d5f7bfaac5)
2023-06-12 09:13:53 +00:00
ibaker
5792b9299e Add a 'more version details' box to the GitHub bug issue template
#minor-release

PiperOrigin-RevId: 537893360
(cherry picked from commit d328e62f69a9f5b4c40867139c4fcb35262df3b5)
2023-06-12 09:13:53 +00:00
claincly
39ec69fe66 Fix recreation of DefaultShaderProgram in FinalWrapper
`outputSurfaceInfoChanged` is not reset when `defaultShaderProgram` is null.
That is, on the first time `ensureConfigured()` is called with output size
changed, `outputSurfaceInfoChanged` is not set to false after creating the
`defaultShaderProgram`, and `defaultShaderProgram` will be created again on the
second time `ensureConfigured()` is called.

PiperOrigin-RevId: 537870404
(cherry picked from commit 133943a63520fbc872c3960647144fde8a918df8)
2023-06-12 09:13:53 +00:00
tofunmi
a8dbea74ce Revert AndroidTestUtil.canDecode to use EncoderUtil.findCodecForFormat
208eefc0fd introduced using `DefaultDecoderFactory.getDecoderInfo(format) != null` caused certain tests not to be skipped when they were expected to be, creating more mh failures.

PiperOrigin-RevId: 537820370
(cherry picked from commit 2af57527853beb7ee40e5b70efde74e72f8d60f1)
2023-06-12 09:13:53 +00:00
sheenachhabra
83957eb67f Ignore ByteBuffer position when writing samples in Mp4Muxer
PiperOrigin-RevId: 537814319
(cherry picked from commit 997f2be5e58d020c918050fb6e3559ffc1e33969)
2023-06-12 09:13:53 +00:00
andrewlewis
3ef7bc291c Tidy color info checking tests
ExoPlayer extractors (backing `MetadataRetriever`) now parse the color format
from the bitstream so using `MetadataRetriever` should be an equivalent but
more lightweight way to verify the color info.

Also remove try/catch blocks in test code calling into these methods, and add
skipping based on decoder capabilities in the cases where it was missing.

PiperOrigin-RevId: 537789483
(cherry picked from commit 74478f2478b420f9264c33e74a4544a8cef60cb8)
2023-06-12 09:13:53 +00:00
huangdarwin
4bb00d5e2e Test: Add special effects for forcing transcode.
Previously, we would apply a general effect to signal wanting to transcode.

PiperOrigin-RevId: 537034455
(cherry picked from commit c52130a2124b7dfcdff3eac02167795b772f3a6b)
2023-06-12 09:13:52 +00:00
Tofunmi Adigun-Hameed
568327ff2e Merge pull request #420 from changxiangzhong:fix/cp-missing
PiperOrigin-RevId: 537014587
(cherry picked from commit a739f6062e37df48db395ce8eb8f0aafb4856b0d)
2023-06-12 09:13:52 +00:00
claincly
1238a5f328 Use the designated UNSET value for aspect ratio
PiperOrigin-RevId: 536770380
(cherry picked from commit f6dbe99c7922b73abacfb71b763072843848eb87)
2023-06-12 09:13:52 +00:00
kimvde
55a2e7ff9e Add TransformationRequest toString method
PiperOrigin-RevId: 536727079
(cherry picked from commit 108000834be230d3f265d77b96b131cc9fc03e99)
2023-06-12 09:13:52 +00:00
ibaker
89c5e16d2f Soften MediaCodecRenderer's assumptions about using framework DRM
#minor-release

PiperOrigin-RevId: 536724725
(cherry picked from commit 0ddc024c697dff1eca028c752d8bb9d90f37ea5b)
2023-06-12 09:13:52 +00:00
claincly
ba84de02f6 Fix codec's MIME type is not used
In some cases the codec selected for decoding has a different MIME type than
the media. In thoses cases Transformer continued to use the media's MIME type
and that caused codec configuration failures.

Removed `EncoderUtil.findCodecForFormat()` as we stopped using the method it
uses for finding a codec. Plus, the method is only used in the test.

See also `MediaCodecUtil.getALternativeCodecMimeType()`.

PiperOrigin-RevId: 536683663
(cherry picked from commit 208eefc0fdf7b5320f5468aa9da864fefba3cfbe)
2023-06-12 09:13:52 +00:00
huangdarwin
db1b5f148d Exoplayer: Suppress check to allow video to run ahead of Audio.
Otherwise, texture output errors out if video decoding decodes faster than audio,
hitting the end of the file, while audio is still in the middle of the file.

PiperOrigin-RevId: 536679568
(cherry picked from commit e2821f10f5ad9d88ab30c7ea50b815cb8854801f)
2023-06-12 09:13:52 +00:00
huangdarwin
2713f81fd0 Effect: Remove extra wait on taskExecutor release()
This future.get() duplicates the wait done in
singleThreadExecutorService.awaitTermination(). If awaitTermination times out, this future.get() would also result in unnecessary blocking.

PiperOrigin-RevId: 536442153
(cherry picked from commit 1c172e0bed7937282fca630efde497319f2ae82a)
2023-06-12 09:13:51 +00:00
sheenachhabra
6e74b1770c Add only supported MdtaMetadataEntry
PiperOrigin-RevId: 536351494
(cherry picked from commit 99d2cf67137310cbcd50f6553b1e455a1f33cb5c)
2023-06-12 09:13:51 +00:00
jbibik
629ab59b5f Remove previously deprecated MediaItem.PlaybackProperties in favour of LocalConfiguration.
Deprecated field `MediaItem.playbackProperties` remains for backwards compatibility, but its type is changed from `MediaItem.PlaybackProperties` to `MediaItem.LocalConfiguration`. The private `MediaItem` constructor will now also take in a `LocalConfiguration` argument instead.

PiperOrigin-RevId: 535648420
(cherry picked from commit 25bf0c6738b6bf58e153a1ddbb0cb29c40501e13)
2023-06-12 09:13:51 +00:00
tofunmi
75ad65f14c Image transcoding: Add support for bmp image format.
With this change we will now support loading bitmaps from all the formats documented [here](https://developer.android.com/guide/topics/media/media-formats#image-formats) except for gifs (because they are animated). Java doc is added to express this.

PiperOrigin-RevId: 535610152
(cherry picked from commit 94d29f35fcae157b43ff43d89dcd4ff38fd88cb2)
2023-06-12 09:13:51 +00:00
kimvde
2ed784f156 Transmux video if rotation is only effect applied
PiperOrigin-RevId: 535554628
(cherry picked from commit f4d1a6c453d701504a865a4dc9d50a2f87d77968)
2023-06-12 09:13:51 +00:00
Tofunmi Adigun-Hameed
b79ee36661 Removing unreleased Audio Offload changes from git 2023-06-07 09:05:51 +00:00
tofunmi
723424a852 Version bump to media3:1.1.0-beta01
#minor-release

PiperOrigin-RevId: 536464412
(cherry picked from commit 49ea280bb8a8bdd3db7d5e7ea4336dab752e9402)
2023-05-30 19:42:29 +00:00
Tofunmi Adigun-Hameed
6e0156766b Merge branch 'release' into release-1.1.0-beta01 2023-05-30 16:12:11 +00:00
huangdarwin
4d4f61b772 Rollback of 438ae0ed6a
*** Original commit ***

ExoPlayer: Add setVideoFrameProcessorFactory().

This allows apps to use a custom VideoFrameProcessor implementation for video
playback. This may be useful, for example, when outputting to a texture.
***

PiperOrigin-RevId: 536391597
(cherry picked from commit 06908e1a865c4c5ae9a9f52986255756bb20cd07)
2023-05-30 14:57:40 +00:00
tofunmi
a442919246 Update release notes for 1.1.0-beta01 release
PiperOrigin-RevId: 536383299
(cherry picked from commit ebbbcf9ac9c2622f9889b057fcfa3d425bfa0244)
Merged in cherry-pick
2023-05-30 14:57:05 +00:00
Tofunmi Adigun-Hameed
bd29a3553d Merge pull request #335 from cedricxperi:dts-direct-passthrough-support
Resolved Merge Conflict during cherrypicking

PiperOrigin-RevId: 535255453
(cherry picked from commit c3dd88d715a0ff92d912d1f4145fbfaea86184d5)
2023-05-26 13:58:36 +00:00
ibaker
75a9de6c21 Add sections for each minor release to RELEASENOTES.md
#minor-release

PiperOrigin-RevId: 535240816
(cherry picked from commit 41b19df5fa85366ca0ac61c430c4ab04d3ea4309)
2023-05-26 13:34:52 +00:00
Googler
d7e5c1bb0b Show the file path of the exported output video.
PiperOrigin-RevId: 535233266
(cherry picked from commit 86515f8683fe3b035aff175b5dbb7898922da716)
2023-05-26 13:34:52 +00:00
tofunmi
7047f44564 Move OnInputFrameProcessedListener into it's own file
PiperOrigin-RevId: 535183521
(cherry picked from commit a19e07c4d284c4d14e61849fa921dfc544406324)
2023-05-26 13:34:52 +00:00
tonihei
f2edc0bed1 Implement Player.replaceMediaItem(s)
This change moves the default logic into the actual Player
implementations, but does not introduce any behavior changes compared
to addMediaItems+removeMediaItems except to make the updates "atomic"
in ExoPlayerImpl, SimpleBasePlayer and MediaController. It also
provides backwards compatbility for cases where Players don't support
the operation.

Issue: google/ExoPlayer#8046

#minor-release

PiperOrigin-RevId: 534945089
(cherry picked from commit 2c07468908fdba9918d33d0f02c6ff872b87fefc)
2023-05-26 13:25:10 +00:00
tonihei
638dee44a9 Merge pull request #386 from yschimke:icon
PiperOrigin-RevId: 534927167
(cherry picked from commit cf0334d7935a9ec5f36e102f39737e4fe296cfec)
2023-05-26 13:25:10 +00:00
michaelkatz
df4803028f Use base Uri from the RTSP DESCRIBE response header for relative paths
Issue: google/ExoPlayer#11160

#minor-release

PiperOrigin-RevId: 534896789
(cherry picked from commit 85f83b1208c1c21f0fe8c0eea3cf04e0a6bef9c8)
2023-05-26 13:25:10 +00:00
huangdarwin
74a032d462 Effects: Have VFP texture output disable surface output.
Also, document that texture output disables manual frame release.

In the past, texture output would lead to surface output methods throwing. Now,
they're simply no-ops instead.

PiperOrigin-RevId: 534894168
(cherry picked from commit abf649cdfa367976517ee07f83ea805b60ed88a5)
2023-05-26 13:25:10 +00:00
andrewlewis
f59dac9d7d Clarify color transfers for internal textures
PiperOrigin-RevId: 534869452
(cherry picked from commit b988cce62c804b1ec3e9fb3ec305ffa5c2047445)
2023-05-26 13:25:10 +00:00
bachinger
5c498c3eca Keep aspect ratio of PlayerView when IDLE
When the video renderer is disabled, the video size is set to 0/0
and sent to listeners. The `PlayerView` potentially still has the last frame
displayed when the player is stopped or an error occurs. This may have the
effect that the frame is displayed distorted.

Not changing the aspect ratio when the video size arrives when the player is IDLE
avoids the problem. In the case when playback starts again and the renderes is
enabled, another video size is sent to the listener.

#minor-release

PiperOrigin-RevId: 534860889
(cherry picked from commit 6469fffd8fe4ffc404f4bc1e405c362ff7020827)
2023-05-26 13:25:10 +00:00
andrewlewis
a7501f4aaf Tidy TextureManager javadoc
Fix `@param`s and clarify wording.

PiperOrigin-RevId: 534857204
(cherry picked from commit 749c64c74ffed281baf51e7ce0c1f0ea9003bbbf)
2023-05-26 13:25:10 +00:00
jbibik
171f48fccc Make MediaItem.AdsConfiguration bundleable
PiperOrigin-RevId: 534848363
(cherry picked from commit 3cc4e44fe30f99be578cf5f817c9b3195d853e66)
2023-05-26 13:25:09 +00:00
tonihei
8573a4ba85 Add clarifiying note to Player.replaceMediaItem
This helps to highlight that the replaced range doesn't need to have
the same size as before.

#minor-release

PiperOrigin-RevId: 534834917
(cherry picked from commit acb567d5a723102a82afff2eb36f953f203deddf)
2023-05-26 13:25:09 +00:00
sheenachhabra
c38f094b32 Add support for adding capture FPS via transformer
PiperOrigin-RevId: 534814892
(cherry picked from commit a944ffecb94844e6a2f0b8af96dd4b6a5e473e1e)
2023-05-26 13:25:09 +00:00
sheenachhabra
fb952145fc Add support for adding XMP data via transformer
PiperOrigin-RevId: 534801202
(cherry picked from commit 71facd825e41029238c3afebfba9d7bf4f22fa87)
2023-05-26 13:25:09 +00:00
ibaker
6b19e5781c Clean up release notes (again)
I undid my last clean-up (b762ca993e) in 5a5c3ce3bd

#minor-release

PiperOrigin-RevId: 534763770
(cherry picked from commit 41492b6e299b4069324dd74ae03ad896992ae970)
2023-05-26 13:25:09 +00:00
ibaker
c2d6c27d0b Remove deprecated onSeekProcessed
This change removes it from `Player.Listener` and `AnalyticsListener`,
use `onPositionDiscontinuity` with `DISCONTINUITY_REASON_SEEK` instead.

#minor-release

PiperOrigin-RevId: 534757426
(cherry picked from commit 5c713feb60bafbf8534cc30c525572bc4c96222b)
2023-05-26 13:25:09 +00:00
huangdarwin
9e19c60907 Codec: Reduce limit for max decoder pending output frames.
Tentative/experimental value to reduce codec timeouts. We will reconsider using a larger limit after seeing whether this really does reduce error rate.

PiperOrigin-RevId: 534491615
(cherry picked from commit 66554b9b686843d4f503833d59717a7717dd4959)
2023-05-26 13:25:09 +00:00
claincly
38a341a458 Add logging for ExtTexMgr
- Number of frames from SurfaceTexture that is sent downstream
- Times ExtTexMgr signaled end of current input stream

PiperOrigin-RevId: 534487842
(cherry picked from commit d584a772e3dbc0ba6df7e4d7073e735e1918c6c4)
2023-05-26 13:25:09 +00:00
sheenachhabra
d3f88a434b Add support for updating Metadata entries via InAppMuxer
Mp4Muxer already supports writing Mp4LocationData so added that
as supported Metadata entry.
Support for more Metadata entries will be added in upcoming CLs.

PiperOrigin-RevId: 534473866
(cherry picked from commit 7c477589e5f25b1fffa51e8961ed26f4615066a5)
2023-05-26 13:25:09 +00:00
ibaker
4d17a05b2b Ensure rootProject.name is only set from settings.gradle
I moved this assignment in 0888dfbd05
in order to provide a single source-of-truth for `publish.gradle`,
but as pointed out in Issue: androidx/media#416 this breaks apps that are depending
on our project locally using the instructions we publish. Instead we can
remove the `rootProject.name` check from `publish.gradle`, and check an
explicit boolean value instead to indicate if the root project is 'ours'
(with this boolean only set from `settings.gradle`, so it doesn't get
picked up by apps depending on us locally).

#minor-release

PiperOrigin-RevId: 534459085
(cherry picked from commit 9a795712843aa8907a3087fc6003e000960db5ad)
2023-05-26 13:25:09 +00:00
tonihei
88cdbe52d7 Improve MediaSource threading constraints documentation
And fix violation of this in AdsMediaSource.

#minor-release

PiperOrigin-RevId: 534441648
(cherry picked from commit c73955a4cd75a2b8b7393d5a44067d0eaeb3981a)
2023-05-26 13:25:09 +00:00
ibaker
6621287c86 Remove four deprecated AnalyticsListener decoder methods
Use the audio or video specific variants instead.

#minor-release

PiperOrigin-RevId: 534436644
(cherry picked from commit 5a5c3ce3bd4a6b906e8ddc6cbdbfcf2d7f4ee71f)
2023-05-26 13:25:09 +00:00
ibaker
48c58cefc2 Remove deprecated OfflineLicenseHelper constructor
Use the non-deprecated constructor instead.

#minor-release

PiperOrigin-RevId: 534426655
(cherry picked from commit 48348df58ad7ebbe13b842a3daa9db21a67c75ad)
2023-05-26 13:25:09 +00:00
ibaker
c650a10256 Remove deprecated Cue constructors, use Cue.Builder instead
#minor-release

PiperOrigin-RevId: 534412494
(cherry picked from commit e6f5f58e471b4e93a6cbb2ba34963b59602dbd33)
2023-05-26 13:25:09 +00:00
jbibik
16b09f6d63 Make MediaItem.SubtitleConfiguration bundleable
PiperOrigin-RevId: 534390168
(cherry picked from commit b7edc9e416225e03c3afea573e47c8f3a68cd1d4)
2023-05-26 13:25:09 +00:00
ibaker
22ac971bbc Remove deprecated DownloadManager constructor
Use the constructor that takes an `Executor` instead.

#minor-release

PiperOrigin-RevId: 534370613
(cherry picked from commit ff0f1c4e9c41ae9c0e087988f1e5d82cbe4c1324)
2023-05-26 13:25:08 +00:00
bachinger
f8ef386065 Use artwork display mode in demo app
- Use artwork display mode `fill` to improve visual apperance
- Some minor cleanup

#minor-release

PiperOrigin-RevId: 534366246
(cherry picked from commit 230921e4ab999f3f9af40688cedaf02631052a95)
2023-05-26 13:25:08 +00:00
ibaker
e8bcbd5249 Clean up release notes
This change merges some duplicate sections, moves some items to more
appropriate sections and removes unnecessary items (deprecations are
self-documenting, so don't need to be included here).

#minor-release

PiperOrigin-RevId: 534363065
(cherry picked from commit b762ca993ef2c8afc2e840cebdf86bba2778b798)
2023-05-26 13:25:08 +00:00
ibaker
ead2c0682a Remove deprecated DefaultLoadControl.Builder.createDefaultLoadControl()
Use `build()` instead.

#minor-release

PiperOrigin-RevId: 534348979
(cherry picked from commit 594e9ac50d0c901dca6d69691111c98ac4d2d3cd)
2023-05-26 13:25:08 +00:00
ibaker
12ca8903ce Remove deprecated ExoPlayer.setHandleWakeLock(boolean)
Use `setWakeMode(int)` instead.

#minor-release

PiperOrigin-RevId: 534344010
(cherry picked from commit cad1ac2eb58e693194c165839843977bcccc3a8d)
2023-05-26 13:25:08 +00:00
bachinger
f372440882 Add artwork display mode to PlayerView
This change deprecates `PlayerView.setUseArtwork(boolean)` and
introduces `setArtworkDisplayMode(mode)` and
`artworkDisplayMode="off|fit|fill"` instead.

- off: no artwork is displayed (like deprecated useArtwork=false)
- fit: letterbox like media (like deprecated useArtwork=true)
- fill: scales the artwork to fill the entire width/weight of the player view

#minor-release

PiperOrigin-RevId: 534167226
(cherry picked from commit 46fb454b3ffc4b2ad97ceccb4dc798e1c9a4c774)
2023-05-26 13:25:08 +00:00
bachinger
5f3cb861fc Minor session demo app improvements
Basically this change removes a bug that makes video playback stuck when
a video is playing and the user taps the UMO notification to get to
the player activity.

- Use `launchMode="singleTop"` for `PlayerActivity`
- Change session activity to a back stacked activity on service `onDestroy`.

Using a back stacked activity `onDestroy()` will be useful once this demo
app implements playback resumption.

The rest of the changes are aesthetic:

- clean up and optimize screen space usage in UI of `PlayerActivity`
- changed some colors, paddings and spacings
- adds a default artwork for the `PlayerView`

PiperOrigin-RevId: 534152052
(cherry picked from commit 96a4ae7e40732dccd2fdded4cb8d0cc7f25f8cdd)
2023-05-26 13:25:08 +00:00
christosts
fbd0bae265 Fix seeking bug in opus
Fix a bug when seeking in an opus container. The calculations inside
DefaultOggSeeker may overflow a long primitive.

Issue: androidx/media#391

#minor-release

PiperOrigin-RevId: 534128513
(cherry picked from commit b9a4e614f7cfe863e72dec779b7beb1a8c1e4e2d)
2023-05-26 13:25:08 +00:00
sheenachhabra
cebdb17134 Write metadata to Mp4Muxer in the release() method
Earlier metadata was written multiple times as it came.
With new changes, all the distinct metadata entries will
get collected and will be written at once in the end.

PiperOrigin-RevId: 534088401
(cherry picked from commit a9e3f5def4fa17aa82f47a8d3a1f1452c2e6f245)
2023-05-26 13:25:08 +00:00
huangdarwin
9d04b11d49 Effect: Add GlTextureInfo release() and accessor methods.
This allows us to disallow access after release.

PiperOrigin-RevId: 534046475
(cherry picked from commit a6897aedaa540dd10ba3be72b4e871ef0f241fd8)
2023-05-26 13:25:08 +00:00
huangdarwin
3d231cce05 ExoPlayer: Add setVideoFrameProcessorFactory().
This allows apps to use a custom VideoFrameProcessor implementation for video
playback. This may be useful, for example, when outputting to a texture.

PiperOrigin-RevId: 534044831
(cherry picked from commit 438ae0ed6ac1059e8aaa9380f476c1403f24a986)
2023-05-26 13:25:08 +00:00
tonihei
5cdbd59756 Improve handling of adding items to empty playlist in MediaController
This is a follow-up to 99dac0be0f where we made the same change in
ExoPlayerImpl and SimpleBasePlayer, but for consistency it makes
sense to also update the masking code in MediaControllerImplBase to
assume the same logic.

Note: MediaControllerImplLegacy already handles this case via
setMediaItems and doesn't need to be updated further.

#minor-release

PiperOrigin-RevId: 534038759
(cherry picked from commit 33af245465ac9a8441a58a6fd6bf75c34e2efa26)
2023-05-26 13:25:08 +00:00
tonihei
1b007deca0 Untangle PlayerInfo/PlaybackInfo updates
The methods in ExoPlayerImpl and MediaControllerImplBase that determine
the new PlayerInfo/PlaybackInfo currently have a hard-to-reason-about
setup where the method generating the new info accesses other methods
that rely on the existing class field instead of working with the
passed in PlayerInfo/PlaybackInfo. This prevents reuse of the util
methods (e.g. for replaceMediaItems) because they access potentially
stale state.

This change untangles these methods a bit by making the util methods
either static or at least ensure that they don't rely on existing
class fields of PlayerInfo/PlaybackInfo. Overall, the change is a
complete no-op.

#minor-release

PiperOrigin-RevId: 534036633
(cherry picked from commit 1fa790348e7e90c987d3385a79a2c7c150cd6824)
2023-05-26 13:25:08 +00:00
tonihei
44ffea2477 Keep pending initial position when setting empty playlist
MediaControllerImplBase currently drops the pending initial seek
position when a user sets an empty playlist.

When seeking in empty playlists and setting new empty playlists,
the class also drops the the period index (and wrongly assigns zero
instead of the windowIndex).

#minor-release

PiperOrigin-RevId: 534035046
(cherry picked from commit caf1c77af1822d0268d7f028f358374bbe2ba1c8)
2023-05-26 13:25:08 +00:00
tonihei
3704c7fc8d Extend main Player Javadoc
The main interface documentation hasn't been updated substantially
since 2017 and is missing notes for many of its current features and
requirements.

Also change the recommendation for implementors from BasePlayer to
SimpleBasePlayer to ensure new classes are more likely to cover all
of the interface requirements.

#minor-release

PiperOrigin-RevId: 534027117
(cherry picked from commit 6de6bd9c4f23b87427b7d2c4cb2c330aef5fba49)
2023-05-26 13:25:08 +00:00
andrewlewis
8df047108c Remove unnecessary volatile
This field is always accessed with the mutex held.

PiperOrigin-RevId: 534027096
(cherry picked from commit ea0b94c0eb165f6673a5dd693009ae0b1a76c66d)
2023-05-26 13:25:07 +00:00
andrewlewis
8a9503c01a Use Ascii for conversion to lower case
PiperOrigin-RevId: 534016337
(cherry picked from commit b0418f1a2ad04add963aab0c98477dc729cbe86d)
2023-05-26 13:25:07 +00:00
andrewlewis
aa4f84d89a Run clang-format on GLSL
PiperOrigin-RevId: 534015933
(cherry picked from commit 2cbc2c6176128bd70aa1595ec5c461e1a849e915)
2023-05-26 13:25:07 +00:00
ibaker
5c42c25ad3 Remove deprecated zero-arg DefaultTrackSelector constructor
Use `DefaultTrackSelector(Context)` instead.

#minor-release

PiperOrigin-RevId: 533985937
(cherry picked from commit 2b409da881750328bffd276e53b027a6b1a96d06)
2023-05-26 13:25:07 +00:00
jbibik
992c9aa470 Make DrmConfiguration Bundleable
PiperOrigin-RevId: 533721679
(cherry picked from commit 5008417c8cd12680a3945945e00399cca05915c5)
2023-05-26 13:25:07 +00:00
sheenachhabra
d40f37158a Move MdtaMetadataEntry class into container module
This class is to be shared between extractor, transformer
and muxer module.

PiperOrigin-RevId: 533490888
(cherry picked from commit b382a7c2da1452e15d5829113fb39ebc98b87a17)
2023-05-26 13:25:07 +00:00
bachinger
b066a0912e Set video size to 0/0 when video render is disabled
In terms of MCVR with a `VideoRendererEventListener`, the video size is set to
0/0 right after `onVideoDisabled()` is called and is set to the actual size as
soon as the video size is known after 'onVideoEnabled()`.

For ExoPlayer and in terms of the `Player` interface, `Player.getVideoSize()`
returns a video size of 0/0 when `Player.getCurrentTracks()` does not support
`C.TRACK_TYPE_VIDEO`. This is ensured by the masking behavior of
`ExoPlayerImpl` that sets an empty track selection result when the playing
period changes due to a seek or timeline removal.

When transitioning playback from a video media item to the next, or when
seeking within the same video media item, the renderer is not disabled.

#minor-release

PiperOrigin-RevId: 533479600
(cherry picked from commit 2a6f893fba763077cae85b0255d6bd05f0887709)
2023-05-26 13:25:07 +00:00
bachinger
ef6772b946 Return full media item when SystemUI calls service on device boot time
#minor-release

PiperOrigin-RevId: 533465595
(cherry picked from commit 3fa666c687c62b0a1d8b0b0fca31d008aba378de)
2023-05-25 10:44:07 +00:00
ibaker
41de418c3d Remove deprecated ExoPlayer.retry(), use prepare() instead.
#minor-release

PiperOrigin-RevId: 533463348
(cherry picked from commit 50112c685b093964be1da3a513bba5e0c86f3882)
2023-05-25 10:44:07 +00:00
ibaker
7934eaf882 Add logging where we were swallowing failed futures in media3.session
This may not be completely exhaustive, but it's better than before!

#minor-release

PiperOrigin-RevId: 533457167
(cherry picked from commit fe19dc421decccf283e503aab9375a04f5dcdeb7)
2023-05-25 10:44:07 +00:00
ibaker
c26659184c Add empty headings to the 'unreleased changes' section of release notes
PiperOrigin-RevId: 533403520
(cherry picked from commit 0e09c0041f109b08b247c286f853f2e79519bcb7)
2023-05-25 10:44:07 +00:00
claincly
1f8caa508f Add a getter method for texture manager
PiperOrigin-RevId: 533402277
(cherry picked from commit d7ad431cfc892a3f1d2fab51f7af7bda19065642)
2023-05-25 10:44:07 +00:00
tonihei
5e98c938c0 Add FilteringMediaSource that only provides tracks of given types
This is useful for cases where only certain types (e.g. only video)
from a source are needed and other tracks should be filtered out
completely to avoid later track selection issues.

#minor-release

PiperOrigin-RevId: 533394658
(cherry picked from commit c44b3828caed79351955b761a84db804da8691c5)
2023-05-25 10:44:07 +00:00
huangdarwin
3ac01d43dd Effect: Use callback to release texture
This allows us to avoid needing a reference to the VideoFrameProcessor, which
can be especially difficult if an App only has a reference to the
VideoFrameProcessor.Factory it passes into Transformer/ExoPlayer.

PiperOrigin-RevId: 533205983
(cherry picked from commit 25fa2df2dedf45e8a060ee28324460429b9bb279)
2023-05-25 10:44:07 +00:00
ibaker
2b53139c5f Allow mock(Random.class) to work with Java 17
https://stackoverflow.com/questions/70993863/mockito-can-not-mock-random-in-java-17

#minor-release

PiperOrigin-RevId: 533161221
(cherry picked from commit 04106da932fd9fb64ae4792f5cffce04f78c7a89)
2023-05-25 10:44:07 +00:00
jbibik
9c1a80082f Use TestUtil.getPublicMethods instead of getDeclaredMethods
JaCoCo introduces private synthetic methods (even on interfaces) which
have to be skipped when checking that a 'forwarding' implementation does
forward everything. Instead we can use the existing `getPublicMethods()`
method which implicitly skips these (since they're private).

PiperOrigin-RevId: 533130932
(cherry picked from commit 620b9e15403b5138e7b3f44194b10e5ae7f72a8c)
2023-05-25 10:44:07 +00:00
sheenachhabra
400218c018 Add argument validation in Mp4LocationData
PiperOrigin-RevId: 533121451
(cherry picked from commit 209783bdf24e946356c4cfd48a76a195762bbe71)
2023-05-25 10:44:07 +00:00
claincly
dd425d53c9 Always use sRGB/BT.709 for bitmap inputs
PiperOrigin-RevId: 533117700
(cherry picked from commit 24a43969908dc7823a497ec193b544ea7783cc7a)
2023-05-25 10:44:07 +00:00
Tofunmi Adigun-Hameed
cd9ff24086 Remove FfmpegVideoRenderer from 1.1.0 release 2023-05-18 18:04:45 +00:00
tofunmi
431b985a04 HDR texture asset loading
PiperOrigin-RevId: 532846248
(cherry picked from commit 5fe10d76520137d860fe9f847f467cb4926427e0)
2023-05-18 16:07:52 +00:00
rohks
633c339dc1 Remove deprecated methods Format.copyWithXXX
Use `Format.buildUpon()` and `setXXX` instead.

#minor-release

PiperOrigin-RevId: 532840625
(cherry picked from commit 538524e579496aa75469ddd8fea76a963236da42)
2023-05-18 16:07:52 +00:00
sheenachhabra
b97ec5edfc Add default constructor for InAppMuxer.Factory
PiperOrigin-RevId: 532838813
(cherry picked from commit 410840c9e19836fe1fc5c38001a6150fefe29027)
2023-05-18 16:07:52 +00:00
rohks
61a5dd76e3 Remove deprecated methods that create an instance of Format
Use `Format.Builder` instead.

#minor-release

PiperOrigin-RevId: 532808478
(cherry picked from commit 18aa664cb8574d1bad4aca24917ffeb74181309a)
2023-05-18 16:07:52 +00:00
huangdarwin
55c9d10022 HDR: Blocklist Galaxy Z Fold 4 for HLG tone mapping.
This device failed on HdrEditingTest's exportAndTranscode_hlg10File_whenHdrEditingUnsupported_toneMapsOrThrows
before this CL, and succeeds on that test after this CL.

PiperOrigin-RevId: 532796897
(cherry picked from commit 83190a0fe9b7f0cd30398ecc6d1246412ec555d7)
2023-05-18 16:07:52 +00:00
sheenachhabra
7adca46e4b Move Mp4LocationData from extractor module to container module
This class will be shared between extractor and muxer module.

PiperOrigin-RevId: 532784415
(cherry picked from commit 7b62b33127a617cc3b7b23f21c385f2329e402a3)
2023-05-18 16:07:52 +00:00
ibaker
514f032afc Add main/dev-v2 branch options to bug.yml template
#minor-release

PiperOrigin-RevId: 532766676
(cherry picked from commit 84d0206c767526802aa3798dad7742ea807d5bc6)
2023-05-18 16:07:51 +00:00
ibaker
962499c9d8 Add Media3 1.0.2 and ExoPlayer 2.18.7 to bug.yml template
#minor-release

PiperOrigin-RevId: 532765549
(cherry picked from commit 4ede3d600718969e6c62e855fcdf73805352a323)
2023-05-18 16:07:51 +00:00
huangdarwin
ce5b57e03c Effect: Make TexturePool and use in FinalWrapper.
Have the FinalShaderProgramWrapper / VideoFrameProcessor texture
output access textures provided through a texture pool, that
recycles used textures.

Also, add the TexturePool interface to generally re-use textures.

PiperOrigin-RevId: 532754377
(cherry picked from commit 94efcd7917ad5c175aac52280ee82f054d24a953)
2023-05-18 16:07:51 +00:00
sheenachhabra
f5ec1bb6f9 Move NAL unit related methods from common to container module
PiperOrigin-RevId: 532750099
(cherry picked from commit e0d6f67dd90acbe8f1c41ffd9550d18eea2ca129)
2023-05-18 16:07:51 +00:00
kimvde
6abc1a7155 Simplify FrameConsumptionManager onReadyToAcceptInputFrame logic
Propagate the "end of current stream" signal directly after queueing the
last frame, instead of waiting for the next onReadyToAcceptInputFrame()
call.

PiperOrigin-RevId: 532739462
(cherry picked from commit 028b3a73120b755733f58f8c8d9764146c470437)
2023-05-18 16:07:51 +00:00
tianyifeng
a5031a688b Avoid using @see in the summary fragment in C.java
PiperOrigin-RevId: 532536037
(cherry picked from commit 5d4c73eee55ce40548dd89265d56755b9ef169c8)
2023-05-18 16:07:51 +00:00
rohks
7773c88404 Remove deprecated WorkManagerScheduler constructor
Use a non deprecated constructor that includes the option to provide a `Context` parameter instead.

#minor-release

PiperOrigin-RevId: 532535770
(cherry picked from commit df52864420da49e97405c905c7e218e4112573df)
2023-05-18 16:07:51 +00:00
rohks
fa152ddc80 Remove deprecated String constants for Charsets
Use Kotlin Charsets from the `kotlin.text` package, the `java.nio.charset.StandardCharsets` or the `com.google.common.base.Charsets` instead.

#minor-release

PiperOrigin-RevId: 532469103
(cherry picked from commit 1061135cfd68dec4d2e073c1ca9e08d57b5c6875)
2023-05-18 16:07:51 +00:00
tofunmi
7fdae1ad0d Adjust image input ForPixelWidthHeightRatio
PiperOrigin-RevId: 532463400
(cherry picked from commit 63ee5ccb286727445542b11d99a455162cee49f6)
2023-05-18 16:07:51 +00:00
rohks
5a72333554 Remove deprecated DownloadService constructor
Use a non deprecated constructor that includes the option to provide a `channelDescriptionResourceId` parameter.

#minor-release

PiperOrigin-RevId: 532450975
(cherry picked from commit 022a05c376918eec0628c0eed32251882fc6f767)
2023-05-18 16:07:51 +00:00
ibaker
06c8433ce8 Remove deprecated DownloadHelper format-specific methods
Use `forMediaItem` instead.

PiperOrigin-RevId: 532414060
(cherry picked from commit 57479dd397f25fc38d4cb32cf44b63536bcdb094)
2023-05-18 16:07:51 +00:00
bachinger
1510710c46 Enable live DASH stream for IMA DAI
This change enables the IMA extension to play live DASH streams
with DAI support. Samples streams can be found and played in the
main demo app.

Issue: google/ExoPlayer#10912
#minor-release
PiperOrigin-RevId: 532407708
(cherry picked from commit dab1353aadd4a093d29e1d418f012d42964e9d50)
2023-05-17 16:59:56 +00:00
ibaker
3633ad15cc Update release notes for Media3 1.0.2
#minor-release

PiperOrigin-RevId: 532404001
(cherry picked from commit 1a38a0c41ebad512e9baab14d562f06de934177f)
2023-05-17 16:59:56 +00:00
tofunmi
43f8d080df Update mixed input test to include images of different aspect ratios
Makes this test a little more thorough.

PiperOrigin-RevId: 532386515
(cherry picked from commit 88642587ac9faa4ba0d7ea9870fa1898ef90277e)
2023-05-17 16:59:55 +00:00
huangdarwin
04a00c7ac4 Test: Suppress SSIM timeouts on galaxy fold/flip.
This is a failure only in SSIM, so it seems unlikely we'll prioritize this over
other work or bugs soon. Suppress test failures to reduce triage burden.

PiperOrigin-RevId: 532200729
(cherry picked from commit 62afbe87bb05890bbbb60ff4e3f0b2fd65aea433)
2023-05-17 16:59:55 +00:00
rohks
fc6429b2d4 Remove two deprecated InvalidResponseCodeException constructors
Use a non-deprecated constructor that accepts additional fields(`cause`, `responseBody`) to enhance error logging.

#minor-release

PiperOrigin-RevId: 532190896
(cherry picked from commit b120ef65ed6425c3193bb4d68a11ce9ac2372347)
2023-05-17 16:59:55 +00:00
tonihei
a8c56f2c60 Add Player.replaceMediaItem(s)
This methods allows to replace single items or a range of items directly
without using separate operations for add and remove. The advantage is
more readable code for apps and the potential for player
implementations to optimize this process (e.g. only replace values
without interrupting playback).

The current change just introduces the API with its default behavior.
The default logic will be removed again in the future in favor of
better logic in the Player implementations.

Issue: google/ExoPlayer#8046
PiperOrigin-RevId: 532151471
(cherry picked from commit b1cfeb04a0e9a1e0f08917e621bd40968db68c01)
2023-05-17 16:59:55 +00:00
jbibik
27becc028d Allow ExoPlayer to opt into volume device control, forbidden by default
PiperOrigin-RevId: 532136692
(cherry picked from commit 1c6b894e8880480918babaf0a6f6b2038faf2e81)
2023-05-17 16:59:55 +00:00
tonihei
7f1c1185e7 Remove unnecessary warning suppression
PiperOrigin-RevId: 532114601
(cherry picked from commit 79657692e41d168c559a8a5412aa3cfd4040d80b)
2023-05-17 16:59:55 +00:00
ibaker
7ac9cf0ec7 Remove deprecated DefaultDrmSessionManager constructors
Use `DefaultDrmSessionManager.Builder` instead.

#minor-release

PiperOrigin-RevId: 532102375
(cherry picked from commit 8a5cebb54dd17e40f0d10700645659450dd7d934)
2023-05-17 16:59:55 +00:00
huangdarwin
a1fbb12ade Effect: Multiple Texture output
Allow the VideoFrameProcessor to output multiple textures at a time, so that
lifetime of textures is up to the consumer calling VFP.releaseOutputFrame.

The FinalShaderProgramWrapper also has a new maxCapacity limit added, to ensure
the a reasonable amount of textures is used and avoid using up memory.

PiperOrigin-RevId: 532094256
(cherry picked from commit 07ec1eaa480146942e8019a1db25661201a2f3e0)
2023-05-17 16:59:55 +00:00
tonihei
c7004d43af Add consistency check to sending and receiving position updates
The periodic updates are only meant to happen while we are in the
same period or ad. This was already guaranteed except for two cases:
1. The Player in a session has updated its state without yet calling
   its listeners
2. The session scheduled a PlayerInfo update that hasn't been sent yet

... and in both cases, the following happened:
 - The change updated the mediaItemIndex to an index that didn't exist
   in a previous Timeline known to the Controller
 - One of the period position updates happened to be sent at exactly
   this time

This problem can be avoided by only scheduling the update if we are
still in the same period/ad and haven't scheduled a normal PlayerInfo
update already.

Since new MediaControllers may still connect to old sessons with this
bug, we need an equivalent change on the controller side to ignore such
buggy updates.

PiperOrigin-RevId: 532089328
(cherry picked from commit 96dd0ae5837a5fd82d7407623bedb5fd4d1e9252)
2023-05-17 16:59:55 +00:00
andrewlewis
5722e6472a Fix lost shader input capacity after end-of-stream
When exporting compositions with multiple images in a row, transformation could
get stuck if a shader was ready to accept input when end-of-stream was already
signaled and queued from upstream. Fix accounting for the downstream capacity.

Manually tested on concatenations with several images and several videos in a
row, by adding logging and verifying the capacity updates as expected across
edited media item transitions.

PiperOrigin-RevId: 532088793
(cherry picked from commit 6850391e45ed571f0190643189661b0920292084)
2023-05-17 16:59:55 +00:00
ibaker
1ebf5c2a6a Delete deprecated zero-arg DefaultBandwidthMeter constructor
Use `DefaultBandwidthMeter.Builder` instead.

#minor-release

PiperOrigin-RevId: 532069549
(cherry picked from commit 8f29a5eba9d1cd67e4eef2ef6f13d91fd8846668)
2023-05-17 16:59:55 +00:00
kimvde
5e926cdce5 Refactor SequenceAssetLoader release
In the past, the SequenceAssetLoader was released in TransformerInternal
when the export ended.

fc539da061 was made to release the SequenceAssetLoader earlier, when
loading ended. This was causing player release timeouts because the last
AssetLoader in the sequence was released before the SamplePipelines (see
0b40bc37ab for more information).

The code that was releasing the SequenceAssetLoader was first commented
out because we didn't have an understanding of what was happening.

This change removes the early SequenceAssetLoader release all together.
It doesn't have any effect as this code was already commented out.

PiperOrigin-RevId: 532065673
(cherry picked from commit 6dfb387117b2a12d5141014dd49fe32afcec3886)
2023-05-17 16:59:55 +00:00
andrewlewis
b0f8a8f316 Signal end-of-stream after creating latch
The output end-of-stream notification from the last shader could theoretically
arrive before the latch for detecting it is created, which might cause waiting
on the latch indefinitely. Create the latch before signaling end of stream so
that it's guaranteed to be set before the end-of-stream signal arrives.

PiperOrigin-RevId: 532056472
(cherry picked from commit 857e6ebee814cb1a92875dc055dd5aff0ef07453)
2023-05-17 16:59:55 +00:00
ibaker
7e30091196 Remove two deprecated SimpleCache constructors
Use a non-deprecated constructor that takes a `DatabaseProvider`
instead for better performance.

#minor-release

PiperOrigin-RevId: 532046598
(cherry picked from commit 0a86790be25527c45b0070cd0d4a1089b2069108)
2023-05-17 16:59:55 +00:00
ibaker
07ca741eb1 Rollback of 509830f38f
*** Original commit ***

Rollback of 221a56da38

*** Original commit ***

Rollback of 749d77b1d9

*** Original commit ***

PiperOrigin-RevId: 531530885
(cherry picked from commit 9366b4e50a0dbb1d8a59940944dd732b3f3c3f9b)
2023-05-17 16:59:54 +00:00
huangdarwin
2ab9c0c556 Transformer: Add latest input format to DebugTraceUtil
This can provide more information to help debug muxer errors

PiperOrigin-RevId: 531521974
(cherry picked from commit 2736b118458c1ead0cbac2457700c1333f7c86c7)
2023-05-17 16:59:54 +00:00
bachinger
932bed1f79 Implement SystemUI contract for media resumption
When a `MediaButtonReceiver` is found in the manifest, the library
can implement the contract of SystemUI to signal that the app wants
a playback resumption notification to be displayed.

And, vice versa, if no `MediaButtonReceiver` is in the manifest, the
library will signal to not show the notification after the app has been
terminated.

#minor-release

PiperOrigin-RevId: 531516023
(cherry picked from commit 9bf6b7ea2062435970cea132c295659b48508b4e)
2023-05-17 16:59:54 +00:00
sheenachhabra
f15e5733ce Add container module
This module will contain functionalities common to extractor and muxer.

PiperOrigin-RevId: 531501602
(cherry picked from commit eb8ec87a5cbf26998ee17d9d6b1d4979ee0c28f6)
2023-05-17 16:59:54 +00:00
sheenachhabra
80aac22cf9 Add test file with metadata track
Mp4Muxer supports adding Metadata track.
Added test file to cover this scenario.

PiperOrigin-RevId: 531496409
(cherry picked from commit b3fd202e113949146f6155984665a411164da9e3)
2023-05-17 16:59:54 +00:00
sheenachhabra
2478b48997 Rollback of 925aa34e13
*** Original commit ***

Rollback of 65d5132f76

*** Original commit ***

Create InAppMuxer in transformer

To use the InAppMuxer, the client needs to pass InAppMuxer Factory.

***

***

PiperOrigin-RevId: 531470081
(cherry picked from commit 867355fdc55722a5fde9f22cd207c5fb57ba067d)
2023-05-17 16:59:54 +00:00
2293 changed files with 103067 additions and 18599 deletions

View File

@ -19,6 +19,9 @@ body:
options:
- Media3 main branch
- Media3 pre-release (alpha, beta or RC not in this list)
- Media3 1.6.1
- Media3 1.6.0
- Media3 1.5.1
- Media3 1.5.0
- Media3 1.4.1
- Media3 1.4.0
@ -42,9 +45,6 @@ body:
- ExoPlayer 2.16.0
- ExoPlayer 2.15.1
- ExoPlayer 2.15.0
- ExoPlayer 2.14.2
- ExoPlayer 2.14.1
- ExoPlayer 2.14.0
- ExoPlayer dev-v2 branch
- Older (unsupported)
validations:

9
.gitignore vendored
View File

@ -4,6 +4,7 @@ gen
libs
obj
lint.xml
.kotlin
# IntelliJ IDEA
.idea
@ -52,6 +53,7 @@ tmp
# External native builds
.externalNativeBuild
.cxx
# VP9 decoder extension
libraries/decoder_vp9/src/main/jni/libvpx
@ -67,6 +69,7 @@ libraries/decoder_opus/src/main/jni/libopus
# FLAC decoder extension
libraries/decoder_flac/src/main/jni/flac
libraries/decoder_flac/src/main/jni/libflac
# FFmpeg decoder extension
libraries/decoder_ffmpeg/src/main/jni/ffmpeg
@ -79,3 +82,9 @@ libraries/datasource_cronet/libs/*
# MIDI decoder extension
libraries/decoder_midi/lib
# IAMF decoder extension
libraries/decoder_iamf/src/main/jni/libiamf
# MPEG-H decoder extension
libraries/decoder_mpegh/src/main/jni/libmpegh

View File

@ -1,7 +1,466 @@
# Release notes
## 1.6
### 1.6.1 (2025-04-14)
This release includes the following changes since the
[1.6.0 release](#160-2025-03-26):
* Common Library:
* Add `PlaybackParameters.withPitch(float)` method for easily copying a
`PlaybackParameters` with a new `pitch` value
([#2257](https://github.com/androidx/media/issues/2257)).
* ExoPlayer:
* Fix issue where media item transition fails due to recoverable renderer
error during initialization of the next media item
([#2229](https://github.com/androidx/media/issues/2229)).
* Fix issue where `ProgressiveMediaPeriod` throws an
`IllegalStateException` as `PreloadMediaSource` attempts to call its
`getBufferedDurationUs()` before it is prepared
([#2315](https://github.com/androidx/media/issues/2315)).
* Fix sending `CmcdData` in manifest requests for DASH, HLS, and
SmoothStreaming ([#2253](https://github.com/androidx/media/pull/2253)).
* Ensure `AdPlaybackState.withAdDurationsUs(long[][])` can be used after
ad groups have been removed. The user still needs to pass in an array of
durations for removed ad groups which can be empty or null
([#2267](https://github.com/androidx/media/issues/2267)).
* Extractors:
* MP4: Parse `alternate_group` from the `tkhd` box and expose it as an
`Mp4AlternateGroupData` entry in each track's `Format.metadata`
([#2242](https://github.com/androidx/media/issues/2242)).
* Audio:
* Fix offload issue where the position might get stuck when playing a
playlist of short content
([#1920](https://github.com/androidx/media/issues/1920)).
* Session:
* Lower aggregation timeout for platform `MediaSession` callbacks from 500
to 100 milliseconds and add an experimental setter to allow apps to
configure this value.
* Fix issue where notifications reappear after they have been dismissed by
the user ([#2302](https://github.com/androidx/media/issues/2302)).
* Fix a bug where the session returned a single-item timeline when the
wrapped player is actually empty. This happened when the wrapped player
doesn't have `COMMAND_GET_TIMELINE` available while
`COMMAND_GET_CURRENT_MEDIA_ITEM` is available and the wrapped player is
empty ([#2320](https://github.com/androidx/media/issues/2320)).
* Fix a bug where calling
`MediaSessionService.setMediaNotificationProvider` is silently ignored
after other interactions with the service like
`setForegroundServiceTimeoutMs`
([#2305](https://github.com/androidx/media/issues/2305)).
* UI:
* Enable `PlayerSurface` to work with `ExoPlayer.setVideoEffects` and
`CompositionPlayer`.
* Fix bug where `PlayerSurface` can't be recomposed with a new `Player`.
* HLS extension:
* Fix issue where chunk duration wasn't set in `CmcdData` for HLS media,
causing an assertion failure when processing encrypted media segments
([#2312](https://github.com/androidx/media/issues/2312)).
* RTSP extension:
* Add support for URI with RTSPT scheme as a way to configure the RTSP
session to use TCP
([#1484](https://github.com/androidx/media/issues/1484)).
* Cast extension:
* Add support for playlist metadata
([#2235](https://github.com/androidx/media/pull/2235)).
### 1.6.0 (2025-03-26)
This release includes the following changes since the
[1.5.1 release](#151-2024-12-19):
* Common Library:
* Add `AudioManagerCompat` and `AudioFocusRequestCompat` to replace the
equivalent classes in `androidx.media`.
* Upgrade Kotlin from 1.9.20 to 2.0.20 and use Compose Compiler Gradle
plugin. Upgrade KotlinX Coroutines library from 1.8.1 to 1.9.0.
* Remove `Format.toBundle(boolean excludeMetadata)` method, use
`Format.toBundle()` instead.
* Fix bug in `SimpleBasePlayer` where setting a new
`currentMediaItemIndex` in `State` after `setPlaylist` with `null`
`MediaMetadata` does not reevaluate the metadata
([#1940](https://github.com/androidx/media/issues/1940)).
* Change `SimpleBasePlayer.State` access from protected to public to make
it easier to handle updates in other classes
([#2128](https://github.com/androidx/media/issues/2128)).
* ExoPlayer:
* Add `MediaExtractorCompat`, a new class that provides equivalent
features to platform `MediaExtractor`.
* Add experimental 'ExoPlayer' pre-warming support for playback using
`MediaCodecVideoRenderer`. You can configure `DefaultRenderersFactory`
through `experimentalSetEnableMediaCodecVideoRendererPrewarming` to
provide a secondary `MediaCodecVideoRenderer` to `ExoPlayer`. If
enabled, `ExoPlayer` pre-processes the video of consecutive media items
during playback to reduce media item transition latency.
* Reduce default values for `bufferForPlaybackMs` and
`bufferForPlaybackAfterRebufferMs` in `DefaultLoadControl` to 1000 and
2000 ms respectively.
* Initialize `DeviceInfo` and device volume asynchronously (if enabled
using `setDeviceVolumeControlEnabled`). These values aren't available
instantly after `ExoPlayer.Builder.build()`, and `Player.Listener`
notifies changes through `onDeviceInfoChanged` and
`onDeviceVolumeChanged`.
* Initial audio session id is no longer immediately available after
creating the player. You can use
`AnalyticsListener.onAudioSessionIdChanged` to listen to the initial
update if required.
* Consider language when selecting a video track. By default, select a
'main' video track that matches the language of the selected audio
track, if available. Explicit video language preferences can be
expressed with
`TrackSelectionParameters.Builder.setPreferredVideoLanguage(s)`.
* Add `selectedAudioLanguage` parameter to
`DefaultTrackSelector.selectVideoTrack()` method.
* Add `retryCount` parameter to `MediaSourceEventListener.onLoadStarted`
and corresponding `MediaSourceEventListener.EventDispatcher` methods.
* Fix bug where playlist items or periods in multi-period DASH streams
with durations that don't match the actual content could cause frame
freezes at the end of the item
([#1698](https://github.com/androidx/media/issues/1698)).
* Move `BasePreloadManager.Listener` to a top-level
`PreloadManagerListener`.
* `RenderersFactory.createSecondaryRenderer` can be implemented to provide
secondary renderers for pre-warming. Pre-warming enables quicker media
item transitions during playback.
* Enable sending `CmcdData` for manifest requests in adaptive streaming
formats DASH, HLS, and SmoothStreaming
([#1951](https://github.com/androidx/media/issues/1951)).
* Provide `MediaCodecInfo` of the codec that will be initialized in
`MediaCodecRenderer.onReadyToInitializeCodec`
([#1963](https://github.com/androidx/media/pull/1963)).
* Change `AdsMediaSource` to allow the `AdPlaybackStates` to grow by
appending ad groups. Invalid modifications are detected and throw an
exception.
* Fix issue where additional decode-only frames may be displayed in quick
succession when transitioning to content media after a mid-roll ad.
* Make `DefaultRenderersFactory` add two `MetadataRenderer` instances to
enable apps to receive two different schemes of metadata by default.
* Reevaluate whether the ongoing load of a chunk should be cancelled when
playback is paused
([#1785](https://github.com/androidx/media/pull/1785)).
* Add option to `ClippingMediaSource` to allow clipping in unseekable
media.
* Fix bug where seeking with pre-warming could block following media item
transition.
* Fix a bug where `ExoPlayer.isLoading()` remains `true` while it has
transitioned to `STATE_IDLE` or `STATE_ENDED`
([#2133](https://github.com/androidx/media/issues/2133)).
* Add `lastRebufferRealtimeMs` to `LoadControl.Parameter`
([#2113](https://github.com/androidx/media/pull/2113)).
* Transformer:
* Add support for transmuxing into alternative backward compatible
formats.
* Add support for transcoding and transmuxing Dolby Vision (profile 8)
format.
* Update parameters of `VideoFrameProcessor.registerInputStream` and
`VideoFrameProcessor.Listener.onInputStreamRegistered` to use `Format`.
* Generate HDR static metadata when using `DefaultEncoderFactory`.
* Enable support for Android platform diagnostics using
`MediaMetricsManager`. Transformer forwards editing events and
performance data to the platform, which helps to provide system
performance and debugging information on the device. This data may also
be collected by Google
[if sharing usage and diagnostics data is enabled](https://support.google.com/accounts/answer/6078260)
by the user of the device. Apps can opt-out of contributing to platform
diagnostics for Transformer with
`Transformer.Builder.setUsePlatformDiagnostics(false)`.
* Split `InAppMuxer` into `InAppMp4Muxer` and `InAppFragmentedMp4Muxer`.
You use `InAppMp4Muxer` to produce a non-fragmented MP4 file, while
`InAppFragmentedMp4Muxer` is for producing a fragmented MP4 file.
* Move `Muxer` interface from `media3-muxer` to `media3-transformer`.
* Add `MediaProjectionAssetLoader`, which provides media from a
`MediaProjection` for screen recording, and add support for screen
recording to the Transformer demo app.
* Add `#getInputFormat()` to `Codec` interface.
* Shift the responsibility to release the `GlObjectsProvider` onto the
caller in `DefaultVideoFrameProcessor` and `DefaultVideoCompositor` when
possible.
* Extractors:
* AVI: Fix handling of files with constant bitrate compressed audio where
the stream header stores the number of bytes instead of the number of
chunks.
* Fix handling of NAL units with lengths expressed in 1 or 2 bytes (rather
than 4).
* Fix `ArrayIndexOutOfBoundsException` in MP4 edit lists when the edit
list starts at a non-sync frame with no preceding sync frame
([#2062](https://github.com/androidx/media/issues/2062)).
* Fix issue where TS streams can get stuck on some devices
([#2069](https://github.com/androidx/media/issues/2069)).
* FLAC: Add support for 32-bit FLAC files. Previously these would fail to
play with `IllegalStateException: Playback stuck buffering and not
loading` ([#2197](https://github.com/androidx/media/issues/2197)).
* Audio:
* Fix `onAudioPositionAdvancing` to be called when playback resumes
(previously it was called when playback was paused).
* Don't bypass `SonicAudioProcessor` when `SpeedChangingAudioProcessor` is
configured with default parameters.
* Fix underflow in `Sonic#getOutputSize()` that could cause
`DefaultAudioSink` to stall.
* Fix `MediaCodecAudioRenderer.getDurationToProgressUs()` and
`DecoderAudioRenderer.getDurationToProgressUs()` so that seeks correctly
reset the provided durations.
* Make `androidx.media3.common.audio.SonicAudioProcessor` final.
* Add support for float PCM to `ChannelMappingAudioProcessor` and
`TrimmingAudioProcessor`.
* Video:
* Change `MediaCodecVideoRenderer.shouldUsePlaceholderSurface` to
protected so that applications can override to block usage of
placeholder surfaces
([#1905](https://github.com/androidx/media/pull/1905)).
* Add experimental `ExoPlayer` AV1 sample dependency parsing to speed up
seeking. Enable it with the new
`DefaultRenderersFactory.experimentalSetParseAv1SampleDependencies` API.
* Add experimental `ExoPlayer` API to drop late `MediaCodecVideoRenderer`
decoder input buffers that are not depended on. Enable it with
`DefaultRenderersFactory.experimentalSetLateThresholdToDropDecoderInputUs`.
* Fix issue where a player without a surface was ready immediately and
very slow decoding any pending frames
([#1973](https://github.com/androidx/media/issues/1973)).
* Exclude Xiaomi and OPPO devices from detached surface mode to avoid
screen flickering
([#2059](https://github.com/androidx/media/issues/2059)).
* Text:
* Add support for VobSub subtitles
([#8260](https://github.com/google/ExoPlayer/issues/8260)).
* Stop eagerly loading all subtitle files configured with
`MediaItem.Builder.setSubtitleConfigurations`, and instead only load one
if it is selected by track selection
([#1721](https://github.com/androidx/media/issues/1721)).
* TTML: Add support for referencing `tts:origin` and `tts:extent` using
`style` ([#2953](https://github.com/google/ExoPlayer/issues/2953)).
* Restrict WebVTT and SubRip timestamps to exactly 3 decimal places.
Previously we incorrectly parsed any number of decimal places but always
assumed the value was in milliseconds, leading to incorrect timestamps
([#1997](https://github.com/androidx/media/issues/1997)).
* Fix playback hanging when a playlist contains clipped items with CEA-608
or CEA-708 captions.
* Fix `IllegalStateException` when an SSA file contains a cue with zero
duration (start and end time equal)
([#2052](https://github.com/androidx/media/issues/2052)).
* Suppress (and log) subtitle parsing errors when subtitles are muxed into
the same container as audio and video
([#2052](https://github.com/androidx/media/issues/2052)).
* Fix handling of multi-byte UTF-8 characters in WebVTT files using CR
line endings ([#2167](https://github.com/androidx/media/issues/2167)).
* DRM:
* Fix `MediaCodec$CryptoException: Operation not supported in this
configuration` error when playing ClearKey content on API < 27 devices
([#1732](https://github.com/androidx/media/issues/1732)).
* Effect:
* Moved the functionality of `OverlaySettings` into
`StaticOverlaySettings`. `OverlaySettings` can be subclassed to allow
dynamic overlay settings.
* Muxers:
* Moved `MuxerException` out of `Muxer` interface to avoid a very long
fully qualified name.
* Renamed `setSampleCopyEnabled()` method to `setSampleCopyingEnabled()`
in both `Mp4Muxer.Builder` and `FragmentedMp4Muxer.Builder`.
* `Mp4Muxer.addTrack()` and `FragmentedMp4Muxer.addTrack()` now return an
`int` track ID instead of a `TrackToken`.
* `Mp4Muxer` and `FragmentedMp4Muxer` no longer implement `Muxer`
interface.
* Disable `Mp4Muxer` sample batching and copying by default.
* Fix a bug in `FragmentedMp4Muxer` that creates a lot of fragments when
only audio track is written.
* Session:
* Keep foreground service state for an additional 10 minutes when playback
pauses, stops or fails. This allows users to resume playback within this
timeout without risking foreground service restrictions on various
devices. Note that simply calling `player.pause()` can no longer be used
to stop the foreground service before `stopSelf()` when overriding
`onTaskRemoved`, use `MediaSessionService.pauseAllPlayersAndStopSelf()`
instead.
* Keep notification visible when playback enters an error or stopped
state. The notification is only removed if the playlist is cleared or
the player is released.
* Improve handling of Android platform MediaSession actions ACTION_PLAY
and ACTION_PAUSE to only set one of them according to the available
commands and also accept if only one of them is set.
* Add `Context` as a parameter to
`MediaButtonReceiver.shouldStartForegroundService`
([#1887](https://github.com/androidx/media/issues/1887)).
* Fix bug where calling a `Player` method on a `MediaController` connected
to a legacy session dropped changes from a pending update.
* Make `MediaSession.setSessionActivity(PendingIntent)` accept null
([#2109](https://github.com/androidx/media/issues/2109)).
* Fix bug where a stale notification stays visible when the playlist is
cleared ([#2211](https://github.com/androidx/media/issues/2211)).
* UI:
* Add state holders and composables to the `media3-ui-compose` module for
`PlayerSurface`, `PresentationState`, `PlayPauseButtonState`,
`NextButtonState`, `PreviousButtonState`, `RepeatButtonState`,
`ShuffleButtonState` and `PlaybackSpeedState`.
* Downloads:
* Fix bug in `CacheWriter` that leaves data sources open and cache areas
locked in case the data source throws an `Exception` other than
`IOException`
([#9760](https://github.com/google/ExoPlayer/issues/9760)).
* HLS extension:
* Add a first version of `HlsInterstitialsAdsLoader`. The ads loader reads
the HLS interstitials of an HLS media playlist and maps them to the
`AdPlaybackState` that is passed to the `AdsMediaSource`. This initial
version only supports HLS VOD streams with `X-ASSET-URI` attributes.
* Add `HlsInterstitialsAdsLoader.AdsMediaSourceFactory`. Apps can use it
to create `AdsMediaSource` instances that use an
`HlsInterstitialsAdsLoader` in a convenient and safe way.
* Parse `SUPPLEMENTAL-CODECS` tag from HLS playlist to detect Dolby Vision
formats ([#1785](https://github.com/androidx/media/pull/1785)).
* Loosen the condition for seeking to sync positions in an HLS stream
([#2209](https://github.com/androidx/media/issues/2209)).
* DASH extension:
* Add AC-4 Level-4 format support for DASH
([#1898](https://github.com/androidx/media/pull/1898)).
* Fix issue when calculating the update interval for ad insertion in
multi-period live streams
([#1698](https://github.com/androidx/media/issues/1698)).
* Parse `scte214:supplementalCodecs` attribute from DASH manifest to
detect Dolby Vision formats
([#1785](https://github.com/androidx/media/pull/1785)).
* Improve handling of period transitions in live streams where the period
contains media samples beyond the declared period duration
([#1698](https://github.com/androidx/media/issues/1698)).
* Fix issue where adaptation sets marked with `adaptation-set-switching`
but different languages or role flags are merged together
([#2222](https://github.com/androidx/media/issues/2222)).
* Decoder extensions (FFmpeg, VP9, AV1, etc.):
* Add the MPEG-H decoder module which uses the native MPEG-H decoder
module to decode MPEG-H audio
([#1826](https://github.com/androidx/media/pull/1826)).
* MIDI extension:
* Plumb custom `AudioSink` and `AudioRendererEventListener` instances into
`MidiRenderer`.
* Cast extension:
* Bump the `play-services-cast-framework` dependency to 21.5.0 to fix a
`FLAG_MUTABLE` crash in apps targeting API 34+ on devices with Google
Play services installed but disabled
([#2178](https://github.com/androidx/media/issues/2178)).
* Demo app:
* Extend `demo-compose` with additional buttons and enhance
`PlayerSurface` integration with scaling and shutter support.
* Remove deprecated symbols:
* Remove deprecated `AudioMixer.create()` method. Use
`DefaultAudioMixer.Factory().create()` instead.
* Remove the following deprecated `Transformer.Builder` methods:
* `setTransformationRequest()`, use `setAudioMimeType()`,
`setVideoMimeType()`, and `setHdrMode()` instead.
* `setAudioProcessors()`, set the audio processor in an
`EditedMediaItem.Builder.setEffects()`, and pass it to
`Transformer.start()` instead.
* `setVideoEffects()`, set video effect in an
`EditedMediaItem.Builder.setEffects()`, and pass it to
`Transformer.start()` instead.
* `setRemoveAudio()`, use `EditedMediaItem.Builder.setRemoveAudio()`
to remove the audio from the `EditedMediaItem` passed to
`Transformer.start()` instead.
* `setRemoveVideo()`, use `EditedMediaItem.Builder.setRemoveVideo()`
to remove the video from the `EditedMediaItem` passed to
`Transformer.start()` instead.
* `setFlattenForSlowMotion()`, use
`EditedMediaItem.Builder.setFlattenForSlowMotion()` to flatten the
`EditedMediaItem` passed to `Transformer.start()` instead.
* `setListener()`, use `addListener()`, `removeListener()` or
`removeAllListeners()` instead.
* Remove the following deprecated `Transformer.Listener` methods:
* `onTransformationCompleted(MediaItem)`, use
`onCompleted(Composition, ExportResult)` instead.
* `onTransformationCompleted(MediaItem, TransformationResult)`, use
`onCompleted(Composition, ExportResult)` instead.
* `onTransformationError(MediaItem, Exception)`, use
`onError(Composition, ExportResult, ExportException)` instead.
* `onTransformationError(MediaItem, TransformationException)`, use
`onError(Composition, ExportResult, ExportException)` instead.
* `onTransformationError(MediaItem, TransformationResult,
TransformationException)`, use `onError(Composition, ExportResult,
ExportException)` instead.
* `onFallbackApplied(MediaItem, TransformationRequest,
TransformationRequest)`, use `onFallbackApplied(Composition,
TransformationRequest, TransformationRequest)` instead.
* Remove deprecated `TransformationResult` class. Use `ExportResult`
instead.
* Remove deprecated `TransformationException` class. Use `ExportException`
instead.
* Remove deprecated `Transformer.PROGRESS_STATE_NO_TRANSFORMATION`. Use
`Transformer.PROGRESS_STATE_NOT_STARTED` instead.
* Remove deprecated `Transformer.setListener()`. Use
`Transformer.addListener()`, `Transformer.removeListener()` or
`Transformer.removeAllListeners()` instead.
* Remove deprecated `Transformer.startTransformation()`. Use
`Transformer.start(MediaItem, String)` instead.
* Remove deprecated `SingleFrameGlShaderProgram`. Use
`BaseGlShaderProgram` instead.
* Remove `Transformer.flattenForSlowMotion`. Use
`EditedMediaItem.flattenForSlowMotion` instead.
* Removed `ExoPlayer.VideoComponent`, `ExoPlayer.AudioComponent`,
`ExoPlayer.TextComponent` and `ExoPlayer.DeviceComponent`.
* Removed `androidx.media3.exoplayer.audio.SonicAudioProcessor`.
* Removed the following deprecated `DownloadHelper` methods:
* Constructor `DownloadHelper(MediaItem, @Nullable MediaSource,
TrackSelectionParameters, RendererCapabilities[])`, use
`DownloadHelper(MediaItem, @Nullable MediaSource,
TrackSelectionParameters, RendererCapabilitiesList)` instead.
* `getRendererCapabilities(RenderersFactory)`, equivalent
functionality can be achieved by creating a
`DefaultRendererCapabilitiesList` with a `RenderersFactory`, and
calling `DefaultRendererCapabilitiesList.getRendererCapabilities()`.
* Removed
`PlayerNotificationManager.setMediaSessionToken(MediaSessionCompat)`
method. Use
`PlayerNotificationManager.setMediaSessionToken(MediaSession.Token)` and
pass in `(MediaSession.Token) compatToken.getToken()` instead.
### 1.6.0-rc02 (2025-03-18)
Use the 1.6.0 [stable version](#160-2025-03-26).
### 1.6.0-rc01 (2025-03-12)
Use the 1.6.0 [stable version](#160-2025-03-26).
### 1.6.0-beta01 (2025-02-26)
Use the 1.6.0 [stable version](#160-2025-03-26).
### 1.6.0-alpha03 (2025-02-06)
Use the 1.6.0 [stable version](#160-2025-03-26).
### 1.6.0-alpha02 (2025-01-30)
Use the 1.6.0 [stable version](#160-2025-03-26).
### 1.6.0-alpha01 (2024-12-20)
Use the 1.6.0 [stable version](#160-2025-03-26).
## 1.5
### 1.5.1 (2024-12-19)
This release includes the following changes since the
[1.5.0 release](#150-2024-11-27):
* ExoPlayer:
* Disable use of asynchronous decryption in MediaCodec to avoid reported
codec timeout issues with this platform API
([#1641](https://github.com/androidx/media/issues/1641)).
* Extractors:
* MP3: Don't stop playback early when a `VBRI` frame's table of contents
doesn't cover all the MP3 data in a file
([#1904](https://github.com/androidx/media/issues/1904)).
* Video:
* Rollback of using `MediaCodecAdapter` supplied pixel aspect ratio values
when provided while processing `onOutputFormatChanged`
([#1371](https://github.com/androidx/media/pull/1371)).
* Text:
* Fix bug in `ReplacingCuesResolver.discardCuesBeforeTimeUs` where the cue
active at `timeUs` (started before but not yet ended) was incorrectly
discarded ([#1939](https://github.com/androidx/media/issues/1939)).
* Metadata:
* Extract disc/track numbering and genre from Vorbis comments into
`MediaMetadata`
([#1958](https://github.com/androidx/media/issues/1958)).
### 1.5.0 (2024-11-27)
This release includes the following changes since the
@ -286,19 +745,19 @@ This release includes the following changes since the
[#184](https://github.com/androidx/media/issues/184)).
* Fix bug where the "None" choice in the text selection is not working if
there are app-defined text track selection preferences.
* DASH Extension:
* DASH extension:
* Add support for periods starting in the middle of a segment
([#1440](https://github.com/androidx/media/issues/1440)).
* Smooth Streaming Extension:
* Smooth Streaming extension:
* Fix a `Bad magic number for Bundle` error when playing SmoothStreaming
streams with text tracks
([#1779](https://github.com/androidx/media/issues/1779)).
* RTSP Extension:
* RTSP extension:
* Fix user info removal for URLs that contain encoded @ characters
([#1138](https://github.com/androidx/media/pull/1138)).
* Fix crashing when parsing of RTP packets with header extensions
([#1225](https://github.com/androidx/media/pull/1225)).
* Decoder Extensions (FFmpeg, VP9, AV1, etc.):
* Decoder extensions (FFmpeg, VP9, AV1, etc.):
* Add the IAMF decoder module, which provides support for playback of MP4
files containing IAMF tracks using the libiamf native library to
synthesize audio.
@ -307,7 +766,7 @@ This release includes the following changes since the
binaural playback support is currently not available.
* Add 16 KB page support for decoder extensions on Android 15
([#1685](https://github.com/androidx/media/issues/1685)).
* Cast Extension:
* Cast extension:
* Stop cleaning the timeline after the CastSession disconnects, which
enables the sender app to resume playback locally after a disconnection.
* Populate CastPlayer's `DeviceInfo` when a `Context` is provided. This
@ -388,7 +847,7 @@ This release includes the following changes since the
`MediaButtonReceiver` when deciding whether to ignore it to avoid a
`ForegroundServiceDidNotStartInTimeException`
([#1581](https://github.com/androidx/media/issues/1581)).
* RTSP Extension:
* RTSP extension:
* Skip invalid Media Descriptions in SDP parsing
([#1087](https://github.com/androidx/media/issues/1472)).
@ -733,12 +1192,12 @@ This release includes the following changes since the
instances, which can eventually result in an app crashing with
`IllegalStateException: Too many receivers, total of 1000, registered
for pid` ([#1224](https://github.com/androidx/media/issues/1224)).
* Cronet Extension:
* Cronet extension:
* Fix `SocketTimeoutException` in `CronetDataSource`. In some versions of
Cronet, the request provided by the callback is not always the same.
This leads to callback not completing and request timing out
(https://issuetracker.google.com/328442628).
* HLS Extension:
* HLS extension:
* Fix bug where pending EMSG samples waiting for a discontinuity were
delegated in `HlsSampleStreamWrapper` with an incorrect offset causing
an `IndexOutOfBoundsException` or an `IllegalArgumentException`
@ -752,13 +1211,13 @@ This release includes the following changes since the
* Fix bug where enabling CMCD for HLS live streams causes
`ArrayIndexOutOfBoundsException`
([#1395](https://github.com/androidx/media/issues/1395)).
* DASH Extension:
* DASH extension:
* Fix bug where re-preparing a multi-period live stream can throw an
`IndexOutOfBoundsException`
([#1329](https://github.com/androidx/media/issues/1329)).
* Add support for `dashif:Laurl` license urls
([#1345](https://github.com/androidx/media/issues/1345)).
* Cast Extension:
* Cast extension:
* Fix bug that converted the album title of the `MediaQueueItem` to the
artist in the Media3 media item
([#1255](https://github.com/androidx/media/pull/1255)).
@ -906,13 +1365,13 @@ This release includes the following changes since the
* Fallback to include audio track language name if `Locale` cannot
identify a display name
([#988](https://github.com/androidx/media/issues/988)).
* DASH Extension:
* DASH extension:
* Populate all `Label` elements from the manifest into `Format.labels`
([#1054](https://github.com/androidx/media/pull/1054)).
* RTSP Extension:
* RTSP extension:
* Skip empty session information values (i-tags) in SDP parsing
([#1087](https://github.com/androidx/media/issues/1087)).
* Decoder Extensions (FFmpeg, VP9, AV1, MIDI, etc.):
* Decoder extensions (FFmpeg, VP9, AV1, MIDI, etc.):
* Disable the MIDI extension as a local dependency by default because it
requires an additional Maven repository to be configured. Users who need
this module from a local dependency
@ -1065,12 +1524,12 @@ This release includes the following changes since the
not transmitted between media controllers and sessions.
* Add constructor to `MediaLibrarySession.Builder` that only takes a
`Context` instead of a `MediaLibraryService`.
* HLS Extension:
* HLS extension:
* Reduce `HlsMediaPeriod` to package-private visibility. This type
shouldn't be directly depended on from outside the HLS package.
* Resolve seeks to beginning of a segment more efficiently
([#1031](https://github.com/androidx/media/pull/1031)).
* Decoder Extensions (FFmpeg, VP9, AV1, MIDI, etc.):
* Decoder extensions (FFmpeg, VP9, AV1, MIDI, etc.):
* MIDI decoder: Ignore SysEx event messages
([#710](https://github.com/androidx/media/pull/710)).
* Test Utilities:
@ -1168,16 +1627,16 @@ This release includes the following changes since the
* Fix issue where the numbers in the fast forward button of the
`PlayerControlView` were misaligned
([#547](https://github.com/androidx/media/issues/547)).
* DASH Extension:
* DASH extension:
* Parse "f800" as channel count of 5 for Dolby in DASH manifest
([#688](https://github.com/androidx/media/issues/688)).
* Decoder Extensions (FFmpeg, VP9, AV1, MIDI, etc.):
* Decoder extensions (FFmpeg, VP9, AV1, MIDI, etc.):
* MIDI: Fix issue where seeking forward skips the Program Change events
([#704](https://github.com/androidx/media/issues/704)).
* Migrate to FFmpeg 6.0 and update supported NDK to `r26b`
([#707](https://github.com/androidx/media/pull/707),
[#867](https://github.com/androidx/media/pull/867)).
* Cast Extension:
* Cast extension:
* Sanitize creation of a `Timeline` to not crash the app when loading
media fails on the cast device
([#708](https://github.com/androidx/media/issues/708)).
@ -1415,11 +1874,11 @@ This release includes the following changes since the
add `dataSync` as `foregroundServiceType` in the manifest and add the
`FOREGROUND_SERVICE_DATA_SYNC` permission
([#11239](https://github.com/google/ExoPlayer/issues/11239)).
* HLS Extension:
* HLS extension:
* Refresh the HLS live playlist with an interval calculated from the last
load start time rather than the last load completed time
([#663](https://github.com/androidx/media/issues/663)).
* DASH Extension:
* DASH extension:
* Allow multiple of the same DASH identifier in segment template url.
* Add experimental support for parsing subtitles during extraction. This
has better support for merging overlapping subtitles, including
@ -1427,7 +1886,7 @@ This release includes the following changes since the
can enable this using
`DashMediaSource.Factory.experimentalParseSubtitlesDuringExtraction()`
([#288](https://github.com/androidx/media/issues/288)).
* RTSP Extension:
* RTSP extension:
* Fix a race condition that could lead to `IndexOutOfBoundsException` when
falling back to TCP, or playback hanging in some situations.
* Check state in RTSP setup when returning loading state of
@ -1438,7 +1897,7 @@ This release includes the following changes since the
* Use RTSP Setup Response timeout value in time interval of sending
keep-alive RTSP Options requests
([#662](https://github.com/androidx/media/issues/662)).
* Decoder Extensions (FFmpeg, VP9, AV1, MIDI, etc.):
* Decoder extensions (FFmpeg, VP9, AV1, MIDI, etc.):
* Release the MIDI decoder module, which provides support for playback of
standard MIDI files using the Jsyn library to synthesize audio.
* Add `DecoderOutputBuffer.shouldBeSkipped` to directly mark output
@ -1715,20 +2174,20 @@ This release contains the following changes since the
* Add Util methods `shouldShowPlayButton` and
`handlePlayPauseButtonAction` to write custom UI elements with a
play/pause button.
* RTSP Extension:
* RTSP extension:
* For MPEG4-LATM, use default profile-level-id value if absent in Describe
Response SDP message
([#302](https://github.com/androidx/media/issues/302)).
* Use base Uri for relative path resolution from the RTSP session if
present in DESCRIBE response header
([#11160](https://github.com/google/ExoPlayer/issues/11160)).
* DASH Extension:
* DASH extension:
* Remove the media time offset from `MediaLoadData.startTimeMs` and
`MediaLoadData.endTimeMs` for multi period DASH streams.
* Fix a bug where re-preparing a multi-period live Dash media source
produced a `IndexOutOfBoundsException`
([#10838](https://github.com/google/ExoPlayer/issues/10838)).
* HLS Extension:
* HLS extension:
* Add
`HlsMediaSource.Factory.setTimestampAdjusterInitializationTimeoutMs(long)`
to set a timeout for the loading thread to wait for the

108
api.txt
View File

@ -464,6 +464,7 @@ package androidx.media3.common {
field @Nullable public final CharSequence description;
field @Nullable public final Integer discNumber;
field @Nullable public final CharSequence displayTitle;
field @Nullable public final Long durationMs;
field @Nullable public final android.os.Bundle extras;
field @Deprecated @Nullable @androidx.media3.common.MediaMetadata.FolderType public final Integer folderType;
field @Nullable public final CharSequence genre;
@ -502,6 +503,7 @@ package androidx.media3.common {
method public androidx.media3.common.MediaMetadata.Builder setDescription(@Nullable CharSequence);
method public androidx.media3.common.MediaMetadata.Builder setDiscNumber(@Nullable Integer);
method public androidx.media3.common.MediaMetadata.Builder setDisplayTitle(@Nullable CharSequence);
method public androidx.media3.common.MediaMetadata.Builder setDurationMs(@Nullable Long);
method public androidx.media3.common.MediaMetadata.Builder setExtras(@Nullable android.os.Bundle);
method @Deprecated public androidx.media3.common.MediaMetadata.Builder setFolderType(@Nullable @androidx.media3.common.MediaMetadata.FolderType Integer);
method public androidx.media3.common.MediaMetadata.Builder setGenre(@Nullable CharSequence);
@ -636,6 +638,7 @@ package androidx.media3.common {
field public static final int ERROR_CODE_DECODING_FAILED = 4003; // 0xfa3
field public static final int ERROR_CODE_DECODING_FORMAT_EXCEEDS_CAPABILITIES = 4004; // 0xfa4
field public static final int ERROR_CODE_DECODING_FORMAT_UNSUPPORTED = 4005; // 0xfa5
field public static final int ERROR_CODE_DECODING_RESOURCES_RECLAIMED = 4006; // 0xfa6
field public static final int ERROR_CODE_DISCONNECTED = -100; // 0xffffff9c
field public static final int ERROR_CODE_DRM_CONTENT_ERROR = 6003; // 0x1773
field public static final int ERROR_CODE_DRM_DEVICE_REVOKED = 6007; // 0x1777
@ -676,7 +679,7 @@ package androidx.media3.common {
field public final long timestampMs;
}
@IntDef(open=true, value={androidx.media3.common.PlaybackException.ERROR_CODE_INVALID_STATE, androidx.media3.common.PlaybackException.ERROR_CODE_BAD_VALUE, androidx.media3.common.PlaybackException.ERROR_CODE_PERMISSION_DENIED, androidx.media3.common.PlaybackException.ERROR_CODE_NOT_SUPPORTED, androidx.media3.common.PlaybackException.ERROR_CODE_DISCONNECTED, androidx.media3.common.PlaybackException.ERROR_CODE_AUTHENTICATION_EXPIRED, androidx.media3.common.PlaybackException.ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED, androidx.media3.common.PlaybackException.ERROR_CODE_CONCURRENT_STREAM_LIMIT, androidx.media3.common.PlaybackException.ERROR_CODE_PARENTAL_CONTROL_RESTRICTED, androidx.media3.common.PlaybackException.ERROR_CODE_NOT_AVAILABLE_IN_REGION, androidx.media3.common.PlaybackException.ERROR_CODE_SKIP_LIMIT_REACHED, androidx.media3.common.PlaybackException.ERROR_CODE_SETUP_REQUIRED, androidx.media3.common.PlaybackException.ERROR_CODE_END_OF_PLAYLIST, androidx.media3.common.PlaybackException.ERROR_CODE_CONTENT_ALREADY_PLAYING, androidx.media3.common.PlaybackException.ERROR_CODE_UNSPECIFIED, androidx.media3.common.PlaybackException.ERROR_CODE_REMOTE_ERROR, androidx.media3.common.PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW, androidx.media3.common.PlaybackException.ERROR_CODE_TIMEOUT, androidx.media3.common.PlaybackException.ERROR_CODE_FAILED_RUNTIME_CHECK, androidx.media3.common.PlaybackException.ERROR_CODE_IO_UNSPECIFIED, androidx.media3.common.PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT, androidx.media3.common.PlaybackException.ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE, androidx.media3.common.PlaybackException.ERROR_CODE_IO_BAD_HTTP_STATUS, androidx.media3.common.PlaybackException.ERROR_CODE_IO_FILE_NOT_FOUND, androidx.media3.common.PlaybackException.ERROR_CODE_IO_NO_PERMISSION, androidx.media3.common.PlaybackException.ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED, androidx.media3.common.PlaybackException.ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE, androidx.media3.common.PlaybackException.ERROR_CODE_PARSING_CONTAINER_MALFORMED, androidx.media3.common.PlaybackException.ERROR_CODE_PARSING_MANIFEST_MALFORMED, androidx.media3.common.PlaybackException.ERROR_CODE_PARSING_CONTAINER_UNSUPPORTED, androidx.media3.common.PlaybackException.ERROR_CODE_PARSING_MANIFEST_UNSUPPORTED, androidx.media3.common.PlaybackException.ERROR_CODE_DECODER_INIT_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_DECODER_QUERY_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_DECODING_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_DECODING_FORMAT_EXCEEDS_CAPABILITIES, androidx.media3.common.PlaybackException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED, androidx.media3.common.PlaybackException.ERROR_CODE_AUDIO_TRACK_INIT_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_AUDIO_TRACK_WRITE_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_AUDIO_TRACK_OFFLOAD_INIT_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_AUDIO_TRACK_OFFLOAD_WRITE_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_UNSPECIFIED, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_SCHEME_UNSUPPORTED, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_PROVISIONING_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_CONTENT_ERROR, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_LICENSE_ACQUISITION_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_DISALLOWED_OPERATION, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_DEVICE_REVOKED, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_LICENSE_EXPIRED}) @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.LOCAL_VARIABLE, java.lang.annotation.ElementType.TYPE_USE}) public static @interface PlaybackException.ErrorCode {
@IntDef(open=true, value={androidx.media3.common.PlaybackException.ERROR_CODE_INVALID_STATE, androidx.media3.common.PlaybackException.ERROR_CODE_BAD_VALUE, androidx.media3.common.PlaybackException.ERROR_CODE_PERMISSION_DENIED, androidx.media3.common.PlaybackException.ERROR_CODE_NOT_SUPPORTED, androidx.media3.common.PlaybackException.ERROR_CODE_DISCONNECTED, androidx.media3.common.PlaybackException.ERROR_CODE_AUTHENTICATION_EXPIRED, androidx.media3.common.PlaybackException.ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED, androidx.media3.common.PlaybackException.ERROR_CODE_CONCURRENT_STREAM_LIMIT, androidx.media3.common.PlaybackException.ERROR_CODE_PARENTAL_CONTROL_RESTRICTED, androidx.media3.common.PlaybackException.ERROR_CODE_NOT_AVAILABLE_IN_REGION, androidx.media3.common.PlaybackException.ERROR_CODE_SKIP_LIMIT_REACHED, androidx.media3.common.PlaybackException.ERROR_CODE_SETUP_REQUIRED, androidx.media3.common.PlaybackException.ERROR_CODE_END_OF_PLAYLIST, androidx.media3.common.PlaybackException.ERROR_CODE_CONTENT_ALREADY_PLAYING, androidx.media3.common.PlaybackException.ERROR_CODE_UNSPECIFIED, androidx.media3.common.PlaybackException.ERROR_CODE_REMOTE_ERROR, androidx.media3.common.PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW, androidx.media3.common.PlaybackException.ERROR_CODE_TIMEOUT, androidx.media3.common.PlaybackException.ERROR_CODE_FAILED_RUNTIME_CHECK, androidx.media3.common.PlaybackException.ERROR_CODE_IO_UNSPECIFIED, androidx.media3.common.PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT, androidx.media3.common.PlaybackException.ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE, androidx.media3.common.PlaybackException.ERROR_CODE_IO_BAD_HTTP_STATUS, androidx.media3.common.PlaybackException.ERROR_CODE_IO_FILE_NOT_FOUND, androidx.media3.common.PlaybackException.ERROR_CODE_IO_NO_PERMISSION, androidx.media3.common.PlaybackException.ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED, androidx.media3.common.PlaybackException.ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE, androidx.media3.common.PlaybackException.ERROR_CODE_PARSING_CONTAINER_MALFORMED, androidx.media3.common.PlaybackException.ERROR_CODE_PARSING_MANIFEST_MALFORMED, androidx.media3.common.PlaybackException.ERROR_CODE_PARSING_CONTAINER_UNSUPPORTED, androidx.media3.common.PlaybackException.ERROR_CODE_PARSING_MANIFEST_UNSUPPORTED, androidx.media3.common.PlaybackException.ERROR_CODE_DECODER_INIT_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_DECODER_QUERY_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_DECODING_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_DECODING_FORMAT_EXCEEDS_CAPABILITIES, androidx.media3.common.PlaybackException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED, androidx.media3.common.PlaybackException.ERROR_CODE_DECODING_RESOURCES_RECLAIMED, androidx.media3.common.PlaybackException.ERROR_CODE_AUDIO_TRACK_INIT_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_AUDIO_TRACK_WRITE_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_AUDIO_TRACK_OFFLOAD_INIT_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_AUDIO_TRACK_OFFLOAD_WRITE_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_UNSPECIFIED, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_SCHEME_UNSUPPORTED, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_PROVISIONING_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_CONTENT_ERROR, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_LICENSE_ACQUISITION_FAILED, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_DISALLOWED_OPERATION, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_DEVICE_REVOKED, androidx.media3.common.PlaybackException.ERROR_CODE_DRM_LICENSE_EXPIRED}) @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.LOCAL_VARIABLE, java.lang.annotation.ElementType.TYPE_USE}) public static @interface PlaybackException.ErrorCode {
}
public final class PlaybackParameters {
@ -1093,12 +1096,13 @@ package androidx.media3.common {
public class TrackSelectionParameters {
method public androidx.media3.common.TrackSelectionParameters.Builder buildUpon();
method public static androidx.media3.common.TrackSelectionParameters fromBundle(android.os.Bundle);
method public static androidx.media3.common.TrackSelectionParameters getDefaults(android.content.Context);
method @Deprecated public static androidx.media3.common.TrackSelectionParameters getDefaults(android.content.Context);
method @CallSuper public android.os.Bundle toBundle();
field public final com.google.common.collect.ImmutableSet<java.lang.Integer> disabledTrackTypes;
field public final boolean forceHighestSupportedBitrate;
field public final boolean forceLowestBitrate;
field @androidx.media3.common.C.SelectionFlags public final int ignoredTextSelectionFlags;
field public final boolean isViewportSizeLimitedByPhysicalDisplaySize;
field public final int maxAudioBitrate;
field public final int maxAudioChannelCount;
field public final int maxVideoBitrate;
@ -1118,13 +1122,15 @@ package androidx.media3.common {
field public final com.google.common.collect.ImmutableList<java.lang.String> preferredVideoMimeTypes;
field @androidx.media3.common.C.RoleFlags public final int preferredVideoRoleFlags;
field public final boolean selectUndeterminedTextLanguage;
field public final boolean usePreferredTextLanguagesAndRoleFlagsFromCaptioningManager;
field public final int viewportHeight;
field public final boolean viewportOrientationMayChange;
field public final int viewportWidth;
}
public static class TrackSelectionParameters.Builder {
ctor public TrackSelectionParameters.Builder(android.content.Context);
ctor public TrackSelectionParameters.Builder();
ctor @Deprecated @com.google.errorprone.annotations.InlineMe(replacement="this()") public TrackSelectionParameters.Builder(android.content.Context);
method public androidx.media3.common.TrackSelectionParameters.Builder addOverride(androidx.media3.common.TrackSelectionOverride);
method public androidx.media3.common.TrackSelectionParameters build();
method public androidx.media3.common.TrackSelectionParameters.Builder clearOverride(androidx.media3.common.TrackGroup);
@ -1151,7 +1157,8 @@ package androidx.media3.common {
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);
@ -1160,7 +1167,8 @@ package androidx.media3.common {
method public androidx.media3.common.TrackSelectionParameters.Builder setSelectUndeterminedTextLanguage(boolean);
method public androidx.media3.common.TrackSelectionParameters.Builder setTrackTypeDisabled(@androidx.media3.common.C.TrackType int, boolean);
method public androidx.media3.common.TrackSelectionParameters.Builder setViewportSize(int, int, boolean);
method public androidx.media3.common.TrackSelectionParameters.Builder setViewportSizeToPhysicalDisplaySize(android.content.Context, boolean);
method @Deprecated public androidx.media3.common.TrackSelectionParameters.Builder setViewportSizeToPhysicalDisplaySize(android.content.Context, boolean);
method public androidx.media3.common.TrackSelectionParameters.Builder setViewportSizeToPhysicalDisplaySize(boolean);
}
public final class Tracks {
@ -1480,7 +1488,82 @@ package androidx.media3.exoplayer.util {
package androidx.media3.session {
public final class CommandButton {
field public static final int ICON_ALBUM = 57369; // 0xe019
field public static final int ICON_ARTIST = 57370; // 0xe01a
field public static final int ICON_BLOCK = 57675; // 0xe14b
field public static final int ICON_BOOKMARK_FILLED = 1042534; // 0xfe866
field public static final int ICON_BOOKMARK_UNFILLED = 59494; // 0xe866
field public static final int ICON_CHECK_CIRCLE_FILLED = 1042540; // 0xfe86c
field public static final int ICON_CHECK_CIRCLE_UNFILLED = 59500; // 0xe86c
field public static final int ICON_CLOSED_CAPTIONS = 57372; // 0xe01c
field public static final int ICON_CLOSED_CAPTIONS_OFF = 61916; // 0xf1dc
field public static final int ICON_FAST_FORWARD = 57375; // 0xe01f
field public static final int ICON_FEED = 57573; // 0xe0e5
field public static final int ICON_FLAG_FILLED = 1040723; // 0xfe153
field public static final int ICON_FLAG_UNFILLED = 57683; // 0xe153
field public static final int ICON_HEART_FILLED = 1042557; // 0xfe87d
field public static final int ICON_HEART_UNFILLED = 59517; // 0xe87d
field public static final int ICON_MINUS = 57691; // 0xe15b
field public static final int ICON_MINUS_CIRCLE_FILLED = 1040712; // 0xfe148
field public static final int ICON_MINUS_CIRCLE_UNFILLED = 1040713; // 0xfe149
field public static final int ICON_NEXT = 57412; // 0xe044
field public static final int ICON_PAUSE = 57396; // 0xe034
field public static final int ICON_PLAY = 57399; // 0xe037
field public static final int ICON_PLAYBACK_SPEED = 57448; // 0xe068
field public static final int ICON_PLAYBACK_SPEED_0_5 = 62690; // 0xf4e2
field public static final int ICON_PLAYBACK_SPEED_0_8 = 1045730; // 0xff4e2
field public static final int ICON_PLAYBACK_SPEED_1_0 = 61389; // 0xefcd
field public static final int ICON_PLAYBACK_SPEED_1_2 = 62689; // 0xf4e1
field public static final int ICON_PLAYBACK_SPEED_1_5 = 62688; // 0xf4e0
field public static final int ICON_PLAYBACK_SPEED_1_8 = 1045728; // 0xff4e0
field public static final int ICON_PLAYBACK_SPEED_2_0 = 62699; // 0xf4eb
field public static final int ICON_PLAYLIST_ADD = 57403; // 0xe03b
field public static final int ICON_PLAYLIST_REMOVE = 60288; // 0xeb80
field public static final int ICON_PLUS = 57669; // 0xe145
field public static final int ICON_PLUS_CIRCLE_FILLED = 1040711; // 0xfe147
field public static final int ICON_PLUS_CIRCLE_UNFILLED = 57671; // 0xe147
field public static final int ICON_PREVIOUS = 57413; // 0xe045
field public static final int ICON_QUALITY = 58409; // 0xe429
field public static final int ICON_QUEUE_ADD = 57436; // 0xe05c
field public static final int ICON_QUEUE_NEXT = 57446; // 0xe066
field public static final int ICON_QUEUE_REMOVE = 57447; // 0xe067
field public static final int ICON_RADIO = 58654; // 0xe51e
field public static final int ICON_REPEAT_ALL = 57408; // 0xe040
field public static final int ICON_REPEAT_OFF = 1040448; // 0xfe040
field public static final int ICON_REPEAT_ONE = 57409; // 0xe041
field public static final int ICON_REWIND = 57376; // 0xe020
field public static final int ICON_SETTINGS = 59576; // 0xe8b8
field public static final int ICON_SHARE = 59405; // 0xe80d
field public static final int ICON_SHUFFLE_OFF = 1040452; // 0xfe044
field public static final int ICON_SHUFFLE_ON = 57411; // 0xe043
field public static final int ICON_SHUFFLE_STAR = 1040451; // 0xfe043
field public static final int ICON_SIGNAL = 61512; // 0xf048
field public static final int ICON_SKIP_BACK = 57410; // 0xe042
field public static final int ICON_SKIP_BACK_10 = 57433; // 0xe059
field public static final int ICON_SKIP_BACK_15 = 1040473; // 0xfe059
field public static final int ICON_SKIP_BACK_30 = 57434; // 0xe05a
field public static final int ICON_SKIP_BACK_5 = 57435; // 0xe05b
field public static final int ICON_SKIP_FORWARD = 63220; // 0xf6f4
field public static final int ICON_SKIP_FORWARD_10 = 57430; // 0xe056
field public static final int ICON_SKIP_FORWARD_15 = 1040470; // 0xfe056
field public static final int ICON_SKIP_FORWARD_30 = 57431; // 0xe057
field public static final int ICON_SKIP_FORWARD_5 = 57432; // 0xe058
field public static final int ICON_STAR_FILLED = 1042488; // 0xfe838
field public static final int ICON_STAR_UNFILLED = 59448; // 0xe838
field public static final int ICON_STOP = 57415; // 0xe047
field public static final int ICON_SUBTITLES = 57416; // 0xe048
field public static final int ICON_SUBTITLES_OFF = 61298; // 0xef72
field public static final int ICON_SYNC = 58919; // 0xe627
field public static final int ICON_THUMB_DOWN_FILLED = 1042651; // 0xfe8db
field public static final int ICON_THUMB_DOWN_UNFILLED = 59611; // 0xe8db
field public static final int ICON_THUMB_UP_FILLED = 1042652; // 0xfe8dc
field public static final int ICON_THUMB_UP_UNFILLED = 59612; // 0xe8dc
field public static final int ICON_UNDEFINED = 0; // 0x0
field public static final int ICON_VOLUME_DOWN = 57421; // 0xe04d
field public static final int ICON_VOLUME_OFF = 57423; // 0xe04f
field public static final int ICON_VOLUME_UP = 57424; // 0xe050
field public final CharSequence displayName;
field @androidx.media3.session.CommandButton.Icon public final int icon;
field @DrawableRes public final int iconResId;
field public final boolean isEnabled;
field @androidx.media3.common.Player.Command public final int playerCommand;
@ -1488,16 +1571,21 @@ package androidx.media3.session {
}
public static final class CommandButton.Builder {
ctor public CommandButton.Builder();
ctor @Deprecated public CommandButton.Builder();
ctor public CommandButton.Builder(@androidx.media3.session.CommandButton.Icon int);
method public androidx.media3.session.CommandButton build();
method public androidx.media3.session.CommandButton.Builder setCustomIconResId(@DrawableRes int);
method public androidx.media3.session.CommandButton.Builder setDisplayName(CharSequence);
method public androidx.media3.session.CommandButton.Builder setEnabled(boolean);
method public androidx.media3.session.CommandButton.Builder setExtras(android.os.Bundle);
method public androidx.media3.session.CommandButton.Builder setIconResId(@DrawableRes int);
method @Deprecated public androidx.media3.session.CommandButton.Builder setIconResId(@DrawableRes int);
method public androidx.media3.session.CommandButton.Builder setPlayerCommand(@androidx.media3.common.Player.Command int);
method public androidx.media3.session.CommandButton.Builder setSessionCommand(androidx.media3.session.SessionCommand);
}
@IntDef({androidx.media3.session.CommandButton.ICON_UNDEFINED, androidx.media3.session.CommandButton.ICON_PLAY, androidx.media3.session.CommandButton.ICON_PAUSE, androidx.media3.session.CommandButton.ICON_STOP, androidx.media3.session.CommandButton.ICON_NEXT, androidx.media3.session.CommandButton.ICON_PREVIOUS, androidx.media3.session.CommandButton.ICON_SKIP_FORWARD, androidx.media3.session.CommandButton.ICON_SKIP_FORWARD_5, androidx.media3.session.CommandButton.ICON_SKIP_FORWARD_10, androidx.media3.session.CommandButton.ICON_SKIP_FORWARD_15, androidx.media3.session.CommandButton.ICON_SKIP_FORWARD_30, androidx.media3.session.CommandButton.ICON_SKIP_BACK, androidx.media3.session.CommandButton.ICON_SKIP_BACK_5, androidx.media3.session.CommandButton.ICON_SKIP_BACK_10, androidx.media3.session.CommandButton.ICON_SKIP_BACK_15, androidx.media3.session.CommandButton.ICON_SKIP_BACK_30, androidx.media3.session.CommandButton.ICON_FAST_FORWARD, androidx.media3.session.CommandButton.ICON_REWIND, androidx.media3.session.CommandButton.ICON_REPEAT_ALL, androidx.media3.session.CommandButton.ICON_REPEAT_ONE, androidx.media3.session.CommandButton.ICON_REPEAT_OFF, androidx.media3.session.CommandButton.ICON_SHUFFLE_ON, androidx.media3.session.CommandButton.ICON_SHUFFLE_OFF, androidx.media3.session.CommandButton.ICON_SHUFFLE_STAR, androidx.media3.session.CommandButton.ICON_HEART_FILLED, androidx.media3.session.CommandButton.ICON_HEART_UNFILLED, androidx.media3.session.CommandButton.ICON_STAR_FILLED, androidx.media3.session.CommandButton.ICON_STAR_UNFILLED, androidx.media3.session.CommandButton.ICON_BOOKMARK_FILLED, androidx.media3.session.CommandButton.ICON_BOOKMARK_UNFILLED, androidx.media3.session.CommandButton.ICON_THUMB_UP_FILLED, androidx.media3.session.CommandButton.ICON_THUMB_UP_UNFILLED, androidx.media3.session.CommandButton.ICON_THUMB_DOWN_FILLED, androidx.media3.session.CommandButton.ICON_THUMB_DOWN_UNFILLED, androidx.media3.session.CommandButton.ICON_FLAG_FILLED, androidx.media3.session.CommandButton.ICON_FLAG_UNFILLED, androidx.media3.session.CommandButton.ICON_PLUS, androidx.media3.session.CommandButton.ICON_MINUS, androidx.media3.session.CommandButton.ICON_PLAYLIST_ADD, androidx.media3.session.CommandButton.ICON_PLAYLIST_REMOVE, androidx.media3.session.CommandButton.ICON_QUEUE_ADD, androidx.media3.session.CommandButton.ICON_QUEUE_NEXT, androidx.media3.session.CommandButton.ICON_QUEUE_REMOVE, androidx.media3.session.CommandButton.ICON_BLOCK, androidx.media3.session.CommandButton.ICON_PLUS_CIRCLE_FILLED, androidx.media3.session.CommandButton.ICON_PLUS_CIRCLE_UNFILLED, androidx.media3.session.CommandButton.ICON_MINUS_CIRCLE_FILLED, androidx.media3.session.CommandButton.ICON_MINUS_CIRCLE_UNFILLED, androidx.media3.session.CommandButton.ICON_CHECK_CIRCLE_FILLED, androidx.media3.session.CommandButton.ICON_CHECK_CIRCLE_UNFILLED, androidx.media3.session.CommandButton.ICON_PLAYBACK_SPEED, androidx.media3.session.CommandButton.ICON_PLAYBACK_SPEED_0_5, androidx.media3.session.CommandButton.ICON_PLAYBACK_SPEED_0_8, androidx.media3.session.CommandButton.ICON_PLAYBACK_SPEED_1_0, androidx.media3.session.CommandButton.ICON_PLAYBACK_SPEED_1_2, androidx.media3.session.CommandButton.ICON_PLAYBACK_SPEED_1_5, androidx.media3.session.CommandButton.ICON_PLAYBACK_SPEED_1_8, androidx.media3.session.CommandButton.ICON_PLAYBACK_SPEED_2_0, androidx.media3.session.CommandButton.ICON_SETTINGS, androidx.media3.session.CommandButton.ICON_QUALITY, androidx.media3.session.CommandButton.ICON_SUBTITLES, androidx.media3.session.CommandButton.ICON_SUBTITLES_OFF, androidx.media3.session.CommandButton.ICON_CLOSED_CAPTIONS, androidx.media3.session.CommandButton.ICON_CLOSED_CAPTIONS_OFF, androidx.media3.session.CommandButton.ICON_SYNC, androidx.media3.session.CommandButton.ICON_SHARE, androidx.media3.session.CommandButton.ICON_VOLUME_UP, androidx.media3.session.CommandButton.ICON_VOLUME_DOWN, androidx.media3.session.CommandButton.ICON_VOLUME_OFF, androidx.media3.session.CommandButton.ICON_ARTIST, androidx.media3.session.CommandButton.ICON_ALBUM, androidx.media3.session.CommandButton.ICON_RADIO, androidx.media3.session.CommandButton.ICON_SIGNAL, androidx.media3.session.CommandButton.ICON_FEED}) @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE_USE) public static @interface CommandButton.Icon {
}
public final class LibraryResult<V> {
method public static <V> androidx.media3.session.LibraryResult<V> ofError(@androidx.media3.session.LibraryResult.Code int);
method public static <V> androidx.media3.session.LibraryResult<V> ofError(@androidx.media3.session.LibraryResult.Code int, @Nullable androidx.media3.session.MediaLibraryService.LibraryParams);
@ -1596,6 +1684,7 @@ package androidx.media3.session {
method public final long getCurrentPosition();
method public final androidx.media3.common.Timeline getCurrentTimeline();
method public final androidx.media3.common.Tracks getCurrentTracks();
method public final com.google.common.collect.ImmutableList<androidx.media3.session.CommandButton> getCustomLayout();
method public final androidx.media3.common.DeviceInfo getDeviceInfo();
method @IntRange(from=0) public final int getDeviceVolume();
method public final long getDuration();
@ -1615,6 +1704,7 @@ package androidx.media3.session {
method public final long getSeekBackIncrement();
method public final long getSeekForwardIncrement();
method @Nullable public final android.app.PendingIntent getSessionActivity();
method public final android.os.Bundle getSessionExtras();
method public final boolean getShuffleModeEnabled();
method public final long getTotalBufferedDuration();
method public final androidx.media3.common.TrackSelectionParameters getTrackSelectionParameters();
@ -1697,6 +1787,7 @@ package androidx.media3.session {
public static interface MediaController.Listener {
method public default void onAvailableSessionCommandsChanged(androidx.media3.session.MediaController, androidx.media3.session.SessionCommands);
method public default com.google.common.util.concurrent.ListenableFuture<androidx.media3.session.SessionResult> onCustomCommand(androidx.media3.session.MediaController, androidx.media3.session.SessionCommand, android.os.Bundle);
method public default void onCustomLayoutChanged(androidx.media3.session.MediaController, java.util.List<androidx.media3.session.CommandButton>);
method public default void onDisconnected(androidx.media3.session.MediaController);
method public default void onExtrasChanged(androidx.media3.session.MediaController, android.os.Bundle);
method public default com.google.common.util.concurrent.ListenableFuture<androidx.media3.session.SessionResult> onSetCustomLayout(androidx.media3.session.MediaController, java.util.List<androidx.media3.session.CommandButton>);
@ -1759,6 +1850,7 @@ package androidx.media3.session {
method public final String getId();
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);
@ -1777,6 +1869,7 @@ package androidx.media3.session {
method public androidx.media3.session.MediaSession.Builder setExtras(android.os.Bundle);
method public androidx.media3.session.MediaSession.Builder setId(String);
method public androidx.media3.session.MediaSession.Builder setSessionActivity(android.app.PendingIntent);
method public androidx.media3.session.MediaSession.Builder setSessionExtras(android.os.Bundle);
}
public static interface MediaSession.Callback {
@ -1887,6 +1980,7 @@ package androidx.media3.session {
public final class SessionToken {
ctor public SessionToken(android.content.Context, android.content.ComponentName);
method public static com.google.common.util.concurrent.ListenableFuture<androidx.media3.session.SessionToken> createSessionToken(android.content.Context, android.media.session.MediaSession.Token);
method public static com.google.common.collect.ImmutableSet<androidx.media3.session.SessionToken> getAllServiceTokens(android.content.Context);
method public android.os.Bundle getExtras();
method public String getPackageName();

View File

@ -19,7 +19,8 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:8.3.2'
classpath 'com.google.android.gms:strict-version-matcher-plugin:1.2.4'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.10'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.20'
classpath 'org.jetbrains.kotlin:compose-compiler-gradle-plugin:2.0.20'
}
}
allprojects {

View File

@ -29,6 +29,10 @@ android {
}
}
lintOptions {
checkTestSources true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8

View File

@ -12,15 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
project.ext {
releaseVersion = '1.5.0'
releaseVersionCode = 1_005_000_3_00
releaseVersion = '1.6.1'
releaseVersionCode = 1_006_001_3_00
minSdkVersion = 21
// See https://developer.android.com/training/cars/media/automotive-os#automotive-module
automotiveMinSdkVersion = 28
appTargetSdkVersion = 34
// Upgrading this requires [Internal ref: b/193254928] to be fixed, or some
// additional robolectric config.
targetSdkVersion = 30
targetSdkVersion = 31
compileSdkVersion = 35
dexmakerVersion = '2.28.3'
// Use the same JUnit version as the Android repo:
@ -30,10 +30,11 @@ project.ext {
// https://cs.android.com/android/platform/superproject/main/+/main:external/guava/METADATA
guavaVersion = '33.3.1-android'
glideVersion = '4.14.2'
kotlinxCoroutinesVersion = '1.8.1'
// Not the same as kotlin version, https://github.com/Kotlin/kotlinx.coroutines/releases
kotlinxCoroutinesVersion = '1.9.0'
leakCanaryVersion = '2.10'
mockitoVersion = '3.12.4'
robolectricVersion = '4.11'
robolectricVersion = '4.14.1'
// Keep this in sync with Google's internal Checker Framework version.
checkerframeworkVersion = '3.13.0'
errorProneVersion = '2.18.0'
@ -46,11 +47,13 @@ project.ext {
androidxConstraintLayoutVersion = '2.1.4'
androidxCoreVersion = '1.8.0'
androidxExifInterfaceVersion = '1.3.6'
androidxLifecycleVersion = '2.6.0'
androidxLifecycleVersion = '2.8.7'
androidxMediaVersion = '1.7.0'
androidxRecyclerViewVersion = '1.3.0'
androidxMaterialVersion = '1.8.0'
androidxTestCoreVersion = '1.5.0'
androidxTestUiAutomatorVersion = '2.3.0'
androidxWindowVersion = '1.3.0'
androidxTestEspressoVersion = '3.5.1'
androidxTestJUnitVersion = '1.1.5'
androidxTestRunnerVersion = '1.5.2'

View File

@ -52,6 +52,8 @@ include modulePrefix + 'lib-ui'
project(modulePrefix + 'lib-ui').projectDir = new File(rootDir, 'libraries/ui')
include modulePrefix + 'lib-ui-leanback'
project(modulePrefix + 'lib-ui-leanback').projectDir = new File(rootDir, 'libraries/ui_leanback')
include modulePrefix + 'lib-ui-compose'
project(modulePrefix + 'lib-ui-compose').projectDir = new File(rootDir, 'libraries/ui_compose')
include modulePrefix + 'lib-database'
project(modulePrefix + 'lib-database').projectDir = new File(rootDir, 'libraries/database')
@ -81,6 +83,8 @@ if (gradle.ext.has('androidxMediaEnableMidiModule') && gradle.ext.androidxMediaE
include modulePrefix + 'lib-decoder-midi'
project(modulePrefix + 'lib-decoder-midi').projectDir = new File(rootDir, 'libraries/decoder_midi')
}
include modulePrefix + 'lib-decoder-mpegh'
project(modulePrefix + 'lib-decoder-mpegh').projectDir = new File(rootDir, 'libraries/decoder_mpegh')
include modulePrefix + 'lib-decoder-opus'
project(modulePrefix + 'lib-decoder-opus').projectDir = new File(rootDir, 'libraries/decoder_opus')
include modulePrefix + 'lib-decoder-vp9'

View File

@ -14,6 +14,7 @@
apply from: '../../constants.gradle'
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'org.jetbrains.kotlin.plugin.compose'
android {
namespace 'androidx.media3.demo.compose'
@ -52,12 +53,8 @@ android {
disable 'GoogleAppIndexingWarning','MissingTranslation'
}
buildFeatures {
viewBinding true
compose true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.3"
}
testOptions {
unitTests {
@ -67,21 +64,21 @@ android {
}
dependencies {
def composeBom = platform('androidx.compose:compose-bom:2024.05.00')
def composeBom = platform('androidx.compose:compose-bom:2024.12.01')
implementation composeBom
implementation 'androidx.activity:activity-compose:1.9.0'
implementation 'androidx.compose.foundation:foundation-android:1.6.7'
implementation 'androidx.compose.material3:material3-android:1.2.1'
implementation 'androidx.compose.foundation:foundation'
implementation 'androidx.compose.material3:material3'
implementation 'androidx.compose.material:material-icons-extended'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.lifecycle:lifecycle-runtime-compose:' + androidxLifecycleVersion
implementation 'com.google.android.material:material:' + androidxMaterialVersion
implementation project(modulePrefix + 'lib-exoplayer')
implementation project(modulePrefix + 'lib-ui-compose')
debugImplementation 'androidx.compose.ui:ui-tooling'
// For detecting and debugging leaks only. LeakCanary is not needed for demo app to work.
debugImplementation 'com.squareup.leakcanary:leakcanary-android:' + leakCanaryVersion
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:' + kotlinxCoroutinesVersion
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
testImplementation project(modulePrefix + 'test-utils')
}

20
demos/compose/lint.xml Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<lint>
<issue id="UnsafeOptInUsageError">
<option name="opt-in" value="androidx.media3.common.util.UnstableApi" />
</issue>
</lint>

View File

@ -15,49 +15,139 @@
*/
package androidx.media3.demo.compose
import android.content.Context
import android.os.Build
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Surface
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.lifecycle.compose.LifecycleStartEffect
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
import androidx.media3.demo.compose.buttons.ExtraControls
import androidx.media3.demo.compose.buttons.MinimalControls
import androidx.media3.demo.compose.data.videos
import androidx.media3.demo.compose.layout.CONTENT_SCALES
import androidx.media3.demo.compose.layout.noRippleClickable
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.compose.PlayerSurface
import androidx.media3.ui.compose.SURFACE_TYPE_SURFACE_VIEW
import androidx.media3.ui.compose.modifiers.resizeWithContentScale
import androidx.media3.ui.compose.state.rememberPresentationState
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
Surface {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
val context = LocalContext.current
val exoPlayer = remember {
ExoPlayer.Builder(context).build().apply {
setMediaItem(MediaItem.fromUri(videos[0]))
prepare()
playWhenReady = true
repeatMode = Player.REPEAT_MODE_ONE
}
}
PlayerSurface(
player = exoPlayer,
surfaceType = SURFACE_TYPE_SURFACE_VIEW,
modifier = Modifier.align(Alignment.CenterHorizontally),
)
}
setContent { ComposeDemoApp() }
}
}
@Composable
fun ComposeDemoApp(modifier: Modifier = Modifier) {
val context = LocalContext.current
var player by remember { mutableStateOf<Player?>(null) }
// See the following resources
// https://developer.android.com/topic/libraries/architecture/lifecycle#onStop-and-savedState
// https://developer.android.com/develop/ui/views/layout/support-multi-window-mode#multi-window_mode_configuration
// https://developer.android.com/develop/ui/compose/layouts/adaptive/support-multi-window-mode#android_9
if (Build.VERSION.SDK_INT > 23) {
// Initialize/release in onStart()/onStop() only because in a multi-window environment multiple
// apps can be visible at the same time. The apps that are out-of-focus are paused, but video
// playback should continue.
LifecycleStartEffect(Unit) {
player = initializePlayer(context)
onStopOrDispose {
player?.apply { release() }
player = null
}
}
} else {
// Call to onStop() is not guaranteed, hence we release the Player in onPause() instead
LifecycleResumeEffect(Unit) {
player = initializePlayer(context)
onPauseOrDispose {
player?.apply { release() }
player = null
}
}
}
player?.let { MediaPlayerScreen(player = it, modifier = modifier.fillMaxSize()) }
}
private fun initializePlayer(context: Context): Player =
ExoPlayer.Builder(context).build().apply {
setMediaItems(videos.map(MediaItem::fromUri))
prepare()
}
@Composable
private fun MediaPlayerScreen(player: Player, modifier: Modifier = Modifier) {
var showControls by remember { mutableStateOf(true) }
var currentContentScaleIndex by remember { mutableIntStateOf(0) }
val contentScale = CONTENT_SCALES[currentContentScaleIndex].second
val presentationState = rememberPresentationState(player)
val scaledModifier = Modifier.resizeWithContentScale(contentScale, presentationState.videoSizeDp)
// Only use MediaPlayerScreen's modifier once for the top level Composable
Box(modifier) {
// Always leave PlayerSurface to be part of the Compose tree because it will be initialised in
// the process. If this composable is guarded by some condition, it might never become visible
// because the Player will not emit the relevant event, e.g. the first frame being ready.
PlayerSurface(
player = player,
surfaceType = SURFACE_TYPE_SURFACE_VIEW,
modifier = scaledModifier.noRippleClickable { showControls = !showControls },
)
if (presentationState.coverSurface) {
// Cover the surface that is being prepared with a shutter
// Do not use scaledModifier here, makes the Box be measured at 0x0
Box(Modifier.matchParentSize().background(Color.Black))
}
if (showControls) {
// drawn on top of a potential shutter
MinimalControls(player, Modifier.align(Alignment.Center))
ExtraControls(
player,
Modifier.fillMaxWidth()
.align(Alignment.BottomCenter)
.background(Color.Gray.copy(alpha = 0.4f))
.navigationBarsPadding(),
)
}
Button(
onClick = { currentContentScaleIndex = currentContentScaleIndex.inc() % CONTENT_SCALES.size },
modifier = Modifier.align(Alignment.TopCenter).padding(top = 48.dp),
) {
Text("ContentScale is ${CONTENT_SCALES[currentContentScaleIndex].first}")
}
}
}

View File

@ -1,76 +0,0 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.demo.compose
import android.view.Surface
import android.view.SurfaceView
import android.view.TextureView
import androidx.annotation.IntDef
import androidx.compose.foundation.AndroidEmbeddedExternalSurface
import androidx.compose.foundation.AndroidExternalSurface
import androidx.compose.foundation.AndroidExternalSurfaceScope
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.media3.common.Player
/**
* Provides a dedicated drawing [Surface] for media playbacks using a [Player].
*
* The player's video output is displayed with either a [SurfaceView]/[AndroidExternalSurface] or a
* [TextureView]/[AndroidEmbeddedExternalSurface].
*
* [Player] takes care of attaching the rendered output to the [Surface] and clearing it, when it is
* destroyed.
*
* See
* [Choosing a surface type](https://developer.android.com/media/media3/ui/playerview#surfacetype)
* for more information.
*/
@Composable
fun PlayerSurface(player: Player, surfaceType: @SurfaceType Int, modifier: Modifier = Modifier) {
val onSurfaceCreated: (Surface) -> Unit = { surface -> player.setVideoSurface(surface) }
val onSurfaceDestroyed: () -> Unit = { player.setVideoSurface(null) }
val onSurfaceInitialized: AndroidExternalSurfaceScope.() -> Unit = {
onSurface { surface, _, _ ->
onSurfaceCreated(surface)
surface.onDestroyed { onSurfaceDestroyed() }
}
}
when (surfaceType) {
SURFACE_TYPE_SURFACE_VIEW ->
AndroidExternalSurface(modifier = modifier, onInit = onSurfaceInitialized)
SURFACE_TYPE_TEXTURE_VIEW ->
AndroidEmbeddedExternalSurface(modifier = modifier, onInit = onSurfaceInitialized)
else -> throw IllegalArgumentException("Unrecognized surface type: $surfaceType")
}
}
/**
* The type of surface view used for media playbacks. One of [SURFACE_TYPE_SURFACE_VIEW] or
* [SURFACE_TYPE_TEXTURE_VIEW].
*/
@MustBeDocumented
@Retention(AnnotationRetention.SOURCE)
@Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE, AnnotationTarget.TYPE_PARAMETER)
@IntDef(SURFACE_TYPE_SURFACE_VIEW, SURFACE_TYPE_TEXTURE_VIEW)
annotation class SurfaceType
/** Surface type equivalent to [SurfaceView] . */
const val SURFACE_TYPE_SURFACE_VIEW = 1
/** Surface type equivalent to [TextureView]. */
const val SURFACE_TYPE_TEXTURE_VIEW = 2

View File

@ -0,0 +1,37 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.demo.compose.buttons
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.media3.common.Player
@Composable
internal fun ExtraControls(player: Player, modifier: Modifier = Modifier) {
Row(
modifier = modifier,
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
) {
PlaybackSpeedPopUpButton(player)
ShuffleButton(player)
RepeatButton(player)
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.demo.compose.buttons
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.media3.common.Player
/**
* Minimal playback controls for a [Player].
*
* Includes buttons for seeking to a previous/next items or playing/pausing the playback.
*/
@Composable
internal fun MinimalControls(player: Player, modifier: Modifier = Modifier) {
val graySemiTransparentBackground = Color.Gray.copy(alpha = 0.1f)
val modifierForIconButton =
modifier.size(80.dp).background(graySemiTransparentBackground, CircleShape)
Row(
modifier = modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically,
) {
PreviousButton(player, modifierForIconButton)
PlayPauseButton(player, modifierForIconButton)
NextButton(player, modifierForIconButton)
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.demo.compose.buttons
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.SkipNext
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.media3.common.Player
import androidx.media3.demo.compose.R
import androidx.media3.ui.compose.state.rememberNextButtonState
@Composable
internal fun NextButton(player: Player, modifier: Modifier = Modifier) {
val state = rememberNextButtonState(player)
IconButton(onClick = state::onClick, modifier = modifier, enabled = state.isEnabled) {
Icon(
Icons.Default.SkipNext,
contentDescription = stringResource(R.string.next_button),
modifier = modifier,
)
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.demo.compose.buttons
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Pause
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.media3.common.Player
import androidx.media3.demo.compose.R
import androidx.media3.ui.compose.state.rememberPlayPauseButtonState
@Composable
internal fun PlayPauseButton(player: Player, modifier: Modifier = Modifier) {
val state = rememberPlayPauseButtonState(player)
val icon = if (state.showPlay) Icons.Default.PlayArrow else Icons.Default.Pause
val contentDescription =
if (state.showPlay) stringResource(R.string.playpause_button_play)
else stringResource(R.string.playpause_button_pause)
IconButton(onClick = state::onClick, modifier = modifier, enabled = state.isEnabled) {
Icon(icon, contentDescription = contentDescription, modifier = modifier)
}
}

View File

@ -0,0 +1,108 @@
/*
* Copyright 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.demo.compose.buttons
import android.view.Gravity
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.text.BasicText
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.compose.ui.window.DialogWindowProvider
import androidx.media3.common.Player
import androidx.media3.ui.compose.state.rememberPlaybackSpeedState
@Composable
internal fun PlaybackSpeedPopUpButton(
player: Player,
modifier: Modifier = Modifier,
speedSelection: List<Float> = listOf(0.5f, 0.75f, 1.0f, 1.25f, 1.5f, 1.75f, 2.0f),
) {
val state = rememberPlaybackSpeedState(player)
var openDialog by remember { mutableStateOf(false) }
TextButton(onClick = { openDialog = true }, modifier = modifier, enabled = state.isEnabled) {
// TODO: look into TextMeasurer to ensure 1.1 and 2.2 occupy the same space
BasicText("%.1fx".format(state.playbackSpeed))
}
if (openDialog) {
BottomDialogOfChoices(
currentSpeed = state.playbackSpeed,
choices = speedSelection,
onDismissRequest = { openDialog = false },
onSelectChoice = state::updatePlaybackSpeed,
)
}
}
@Composable
private fun BottomDialogOfChoices(
currentSpeed: Float,
choices: List<Float>,
onDismissRequest: () -> Unit,
onSelectChoice: (Float) -> Unit,
) {
Dialog(
onDismissRequest = onDismissRequest,
properties = DialogProperties(usePlatformDefaultWidth = false),
) {
val dialogWindowProvider = LocalView.current.parent as? DialogWindowProvider
dialogWindowProvider?.window?.let { window ->
window.setGravity(Gravity.BOTTOM) // Move down, by default dialogs are in the centre
window.setDimAmount(0f) // Remove dimmed background of ongoing playback
}
Box(modifier = Modifier.wrapContentSize().background(Color.LightGray)) {
Column(
modifier = Modifier.fillMaxWidth().wrapContentWidth(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
choices.forEach { speed ->
TextButton(
onClick = {
onSelectChoice(speed)
onDismissRequest()
}
) {
var fontWeight = FontWeight(400)
if (speed == currentSpeed) {
fontWeight = FontWeight(1000)
}
Text("%.1fx".format(speed), fontWeight = fontWeight)
}
}
}
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.demo.compose.buttons
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.SkipPrevious
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.media3.common.Player
import androidx.media3.demo.compose.R
import androidx.media3.ui.compose.state.rememberPreviousButtonState
@Composable
internal fun PreviousButton(player: Player, modifier: Modifier = Modifier) {
val state = rememberPreviousButtonState(player)
IconButton(onClick = state::onClick, modifier = modifier, enabled = state.isEnabled) {
Icon(
Icons.Default.SkipPrevious,
contentDescription = stringResource(R.string.previous_button),
modifier = modifier,
)
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.demo.compose.buttons
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Repeat
import androidx.compose.material.icons.filled.RepeatOn
import androidx.compose.material.icons.filled.RepeatOneOn
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.media3.common.Player
import androidx.media3.demo.compose.R
import androidx.media3.ui.compose.state.rememberRepeatButtonState
@Composable
internal fun RepeatButton(player: Player, modifier: Modifier = Modifier) {
val state = rememberRepeatButtonState(player)
val icon = repeatModeIcon(state.repeatModeState)
val contentDescription = repeatModeContentDescription(state.repeatModeState)
IconButton(onClick = state::onClick, modifier = modifier, enabled = state.isEnabled) {
Icon(icon, contentDescription = contentDescription, modifier = modifier)
}
}
private fun repeatModeIcon(repeatMode: @Player.RepeatMode Int): ImageVector {
return when (repeatMode) {
Player.REPEAT_MODE_OFF -> Icons.Default.Repeat
Player.REPEAT_MODE_ONE -> Icons.Default.RepeatOneOn
else -> Icons.Default.RepeatOn
}
}
@Composable
private fun repeatModeContentDescription(repeatMode: @Player.RepeatMode Int): String {
return when (repeatMode) {
Player.REPEAT_MODE_OFF -> stringResource(R.string.repeat_button_repeat_off_description)
Player.REPEAT_MODE_ONE -> stringResource(R.string.repeat_button_repeat_one_description)
else -> stringResource(R.string.repeat_button_repeat_all_description)
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.demo.compose.buttons
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Shuffle
import androidx.compose.material.icons.filled.ShuffleOn
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.media3.common.Player
import androidx.media3.demo.compose.R
import androidx.media3.ui.compose.state.rememberShuffleButtonState
@Composable
internal fun ShuffleButton(player: Player, modifier: Modifier = Modifier) {
val state = rememberShuffleButtonState(player)
val icon = if (state.shuffleOn) Icons.Default.ShuffleOn else Icons.Default.Shuffle
val contentDescription =
if (state.shuffleOn) {
stringResource(R.string.shuffle_button_shuffle_on_description)
} else {
stringResource(R.string.shuffle_button_shuffle_off_description)
}
IconButton(onClick = state::onClick, modifier = modifier, enabled = state.isEnabled) {
Icon(icon, contentDescription = contentDescription, modifier = modifier)
}
}

View File

@ -18,6 +18,7 @@ package androidx.media3.demo.compose.data
val videos =
listOf(
"https://html5demos.com/assets/dizzy.mp4",
"https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_4x3/gear0/fileSequence0.aac",
"https://storage.googleapis.com/exoplayer-test-media-0/shortform_2.mp4",
"https://storage.googleapis.com/exoplayer-test-media-1/gen-3/screens/dash-vod-single-segment/video-vp9-360.webm",
"https://storage.googleapis.com/exoplayer-test-media-0/shortform_3.mp4",
)

View File

@ -0,0 +1,32 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.demo.compose.layout
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
@Composable
internal fun Modifier.noRippleClickable(onClick: () -> Unit): Modifier =
clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null, // to prevent the ripple from the tap
) {
onClick()
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.demo.compose.layout
import androidx.compose.ui.layout.ContentScale
val CONTENT_SCALES =
listOf(
"Fit" to ContentScale.Fit,
"Crop" to ContentScale.Crop,
"None" to ContentScale.None,
"Inside" to ContentScale.Inside,
"FillBounds" to ContentScale.FillBounds,
"FillHeight" to ContentScale.FillHeight,
"FillWidth" to ContentScale.FillWidth,
)

View File

@ -15,12 +15,13 @@
-->
<resources>
<string name="app_name">Media3 Compose Demo</string>
<string name="current_playlist_name">Current playlist</string>
<string name="open_player_content_description">Click to view your play list</string>
<string name="added_media_item_format">Added %1$s to playlist</string>
<string name="shuffle">Shuffle</string>
<string name="play_button">Play</string>
<string name="waiting_for_metadata">Waiting for playlist to load…</string>
<string name="notification_permission_denied">
"Without notification access the app can't warn about failed background operations"</string>
<string name="playpause_button_play">Play</string>
<string name="playpause_button_pause">Pause</string>
<string name="next_button">Next</string>
<string name="previous_button">Previous</string>
<string name="repeat_button_repeat_off_description">Current mode: Repeat none. Toggle repeat mode.</string>
<string name="repeat_button_repeat_one_description">Current mode: Repeat one. Toggle repeat mode.</string>
<string name="repeat_button_repeat_all_description">Current mode: Repeat all. Toggle repeat mode.</string>
<string name="shuffle_button_shuffle_on_description">Disable shuffle mode.</string>
<string name="shuffle_button_shuffle_off_description">Enable shuffle mode</string>
</resources>

View File

@ -15,6 +15,8 @@
*/
package androidx.media3.demo.composition;
import static android.content.pm.ActivityInfo.COLOR_MODE_HDR;
import static androidx.media3.common.util.Util.SDK_INT;
import static androidx.media3.transformer.Composition.HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR;
import static androidx.media3.transformer.Composition.HDR_MODE_KEEP_HDR;
import static androidx.media3.transformer.Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC;
@ -55,7 +57,8 @@ import androidx.media3.transformer.EditedMediaItemSequence;
import androidx.media3.transformer.Effects;
import androidx.media3.transformer.ExportException;
import androidx.media3.transformer.ExportResult;
import androidx.media3.transformer.InAppMuxer;
import androidx.media3.transformer.InAppFragmentedMp4Muxer;
import androidx.media3.transformer.InAppMp4Muxer;
import androidx.media3.transformer.JsonUtil;
import androidx.media3.transformer.Transformer;
import androidx.media3.ui.PlayerView;
@ -111,6 +114,9 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (SDK_INT >= 26) {
getWindow().setColorMode(COLOR_MODE_HDR);
}
setContentView(R.layout.composition_preview_activity);
playerView = findViewById(R.id.composition_player_view);
@ -186,6 +192,18 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
exportStopwatch.reset();
}
@SuppressWarnings("MissingSuperCall")
@Override
public void onBackPressed() {
if (compositionPlayer != null) {
compositionPlayer.pause();
}
if (exportStopwatch.isRunning()) {
cancelExport();
exportStopwatch.reset();
}
}
private Composition prepareComposition() {
String[] presetUris = getResources().getStringArray(/* id= */ R.array.preset_uris);
int[] presetDurationsUs = getResources().getIntArray(/* id= */ R.array.preset_durations);
@ -279,7 +297,6 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
Log.e(TAG, "Preview error", error);
}
});
player.setRepeatMode(Player.REPEAT_MODE_ALL);
player.setComposition(composition);
player.prepare();
player.play();
@ -346,21 +363,20 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
enableDebugTracingCheckBox.setOnCheckedChangeListener(
(buttonView, isChecked) -> DebugTraceUtil.enableTracing = isChecked);
// Connect producing fragmented MP4 to using Media3 Muxer
CheckBox useMedia3MuxerCheckBox =
exportSettingsDialogView.findViewById(R.id.use_media3_muxer_checkbox);
CheckBox produceFragmentedMp4CheckBox =
exportSettingsDialogView.findViewById(R.id.produce_fragmented_mp4_checkbox);
useMedia3MuxerCheckBox.setOnCheckedChangeListener(
(buttonView, isChecked) -> {
if (!isChecked) {
produceFragmentedMp4CheckBox.setChecked(false);
}
});
produceFragmentedMp4CheckBox.setOnCheckedChangeListener(
CheckBox useMedia3Mp4MuxerCheckBox =
exportSettingsDialogView.findViewById(R.id.use_media3_mp4_muxer_checkbox);
CheckBox useMedia3FragmentedMp4MuxerCheckBox =
exportSettingsDialogView.findViewById(R.id.use_media3_fragmented_mp4_muxer_checkbox);
useMedia3Mp4MuxerCheckBox.setOnCheckedChangeListener(
(buttonView, isChecked) -> {
if (isChecked) {
useMedia3MuxerCheckBox.setChecked(true);
useMedia3FragmentedMp4MuxerCheckBox.setChecked(false);
}
});
useMedia3FragmentedMp4MuxerCheckBox.setOnCheckedChangeListener(
(buttonView, isChecked) -> {
if (isChecked) {
useMedia3Mp4MuxerCheckBox.setChecked(false);
}
});
@ -403,15 +419,15 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
transformerBuilder.setVideoMimeType(selectedVideoMimeType);
}
CheckBox useMedia3MuxerCheckBox =
exportSettingsDialogView.findViewById(R.id.use_media3_muxer_checkbox);
CheckBox produceFragmentedMp4CheckBox =
exportSettingsDialogView.findViewById(R.id.produce_fragmented_mp4_checkbox);
if (useMedia3MuxerCheckBox.isChecked()) {
transformerBuilder.setMuxerFactory(
new InAppMuxer.Factory.Builder()
.setOutputFragmentedMp4(produceFragmentedMp4CheckBox.isChecked())
.build());
CheckBox useMedia3Mp4MuxerCheckBox =
exportSettingsDialogView.findViewById(R.id.use_media3_mp4_muxer_checkbox);
CheckBox useMedia3FragmentedMp4MuxerCheckBox =
exportSettingsDialogView.findViewById(R.id.use_media3_fragmented_mp4_muxer_checkbox);
if (useMedia3Mp4MuxerCheckBox.isChecked()) {
transformerBuilder.setMuxerFactory(new InAppMp4Muxer.Factory());
}
if (useMedia3FragmentedMp4MuxerCheckBox.isChecked()) {
transformerBuilder.setMuxerFactory(new InAppFragmentedMp4Muxer.Factory());
}
transformer =

View File

@ -18,6 +18,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true"
android:padding="16dp">
<com.google.android.material.card.MaterialCardView

View File

@ -79,12 +79,12 @@
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:text="@string/use_media3_muxer"
android:text="@string/use_media3_mp4_muxer"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1" />
<CheckBox
android:id="@+id/use_media3_muxer_checkbox"
android:id="@+id/use_media3_mp4_muxer_checkbox"
android:layout_gravity="end"
android:checked="false"
android:layout_height="wrap_content"
@ -96,12 +96,12 @@
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:text="@string/produce_fragmented_mp4"
android:text="@string/use_media3_fragmented_mp4_muxer"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1" />
<CheckBox
android:id="@+id/produce_fragmented_mp4_checkbox"
android:id="@+id/use_media3_fragmented_mp4_muxer_checkbox"
android:layout_gravity="end"
android:checked="false"
android:layout_height="wrap_content"

View File

@ -34,6 +34,6 @@
<string name="output_audio_mime_type" translatable="false">Output audio MIME type</string>
<string name="output_video_mime_type" translatable="false">Output video MIME type</string>
<string name="enable_debug_tracing" translatable="false">Enable debug tracing</string>
<string name="use_media3_muxer" translatable="false">Use Media3 muxer</string>
<string name="produce_fragmented_mp4" translatable="false">Produce fragmented MP4</string>
<string name="use_media3_mp4_muxer" translatable="false">Use Media3 Mp4Muxer</string>
<string name="use_media3_fragmented_mp4_muxer" translatable="false">Use Media3 FragmentedMp4Muxer</string>
</resources>

10
demos/effect/README.md Normal file
View File

@ -0,0 +1,10 @@
# Effect demo
This app demonstrates how to use the [Effect][] API to modify videos. It uses
`setVideoEffects` method to add different effects to [ExoPlayer][].
See the [demos README](../README.md) for instructions on how to build and run
this demo.
[Effect]: https://github.com/androidx/media/tree/release/libraries/effect
[ExoPlayer]: https://github.com/androidx/media/tree/release/libraries/exoplayer

80
demos/effect/build.gradle Normal file
View File

@ -0,0 +1,80 @@
// Copyright 2024 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
apply from: '../../constants.gradle'
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'org.jetbrains.kotlin.plugin.compose'
android {
namespace 'androidx.media3.demo.effect'
compileSdk project.ext.compileSdkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
defaultConfig {
versionName project.ext.releaseVersion
versionCode project.ext.releaseVersionCode
minSdkVersion project.ext.minSdkVersion
targetSdkVersion project.ext.appTargetSdkVersion
}
buildTypes {
release {
shrinkResources true
minifyEnabled true
signingConfig signingConfigs.debug
}
debug {
jniDebuggable = true
}
}
lintOptions {
// The demo app isn't indexed, and doesn't have translations.
disable 'GoogleAppIndexingWarning','MissingTranslation'
}
buildFeatures {
compose true
}
testOptions {
unitTests {
includeAndroidResources = true
}
}
}
dependencies {
def composeBom = platform('androidx.compose:compose-bom:2024.10.00')
implementation composeBom
implementation 'androidx.activity:activity-compose:1.9.0'
implementation 'androidx.compose.foundation:foundation'
implementation 'androidx.compose.material3:material3'
implementation 'com.google.android.material:material:' + androidxMaterialVersion
implementation project(modulePrefix + 'lib-exoplayer')
implementation project(modulePrefix + 'lib-ui')
implementation project(modulePrefix + 'lib-effect')
// For detecting and debugging leaks only. LeakCanary is not needed for demo app to work.
debugImplementation 'com.squareup.leakcanary:leakcanary-android:' + leakCanaryVersion
}

20
demos/effect/lint.xml Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<lint>
<issue id="UnsafeOptInUsageError">
<option name="opt-in" value="androidx.media3.common.util.UnstableApi" />
</issue>
</lint>

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="androidx.media3.demo.effect">
<uses-sdk/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
<application
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.Media3EffectDemo">
<activity
android:name="androidx.media3.demo.effect.EffectActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,27 @@
[
{
"name": "Cats -> Dogs",
"playlist": [
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
},
{
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv"
}
]
},
{
"name": "Android Block -> Dogs -> BigBuckBunny",
"playlist": [
{
"uri": "https://storage.googleapis.com/exoplayer-test-media-0/android-block-1080-hevc.mp4"
},
{
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv"
},
{
"uri": "https://storage.googleapis.com/exoplayer-test-media-0/BigBuckBunny_320x180.mp4"
}
]
}
]

View File

@ -0,0 +1,140 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.demo.effect
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.PorterDuff
import android.os.Handler
import androidx.media3.common.VideoFrameProcessingException
import androidx.media3.common.util.Size
import androidx.media3.common.util.Util
import androidx.media3.effect.CanvasOverlay
import kotlin.math.abs
import kotlin.random.Random
/** Mimics an emitter of confetti, dropping from the center of the frame. */
internal class ConfettiOverlay : CanvasOverlay(/* useInputFrameSize= */ true) {
private val confettiList = mutableListOf<Confetti>()
private val paint = Paint()
private val handler = Handler(Util.getCurrentOrMainLooper())
private var addConfettiTask: (() -> Unit)? = null
private var width = 0f
private var height = 0f
private var started = false
override fun configure(videoSize: Size) {
super.configure(videoSize)
this.width = videoSize.width.toFloat()
this.height = videoSize.height.toFloat()
}
@Synchronized
override fun onDraw(canvas: Canvas, presentationTimeUs: Long) {
if (!started) {
start()
}
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
confettiList.removeAll { confetti ->
confetti.y > height / 2 || confetti.x <= 0 || confetti.x > width
}
for (confetti in confettiList) {
confetti.draw(canvas, paint)
confetti.update()
}
}
@Throws(VideoFrameProcessingException::class)
override fun release() {
super.release()
handler.post(this::stop)
}
/** Starts the confetti. */
fun start() {
addConfettiTask = this::addConfetti
handler.post(checkNotNull(addConfettiTask))
started = true
}
/** Stops the confetti. */
fun stop() {
handler.removeCallbacks(checkNotNull(addConfettiTask))
confettiList.clear()
started = false
addConfettiTask = null
}
@Synchronized
fun addConfetti() {
repeat(5) {
confettiList.add(
Confetti(
text = CONFETTI_TEXTS[abs(Random.nextInt()) % CONFETTI_TEXTS.size],
x = width / 2f,
y = EMITTER_POSITION_Y.toFloat(),
size = CONFETTI_BASE_SIZE + Random.nextInt(CONFETTI_SIZE_VARIATION),
color = Color.HSVToColor(floatArrayOf(Random.nextInt(360).toFloat(), 0.6f, 0.8f)),
)
)
}
handler.postDelayed(this::addConfetti, /* delayMillis= */ 100)
}
private class Confetti(
private val text: String,
private val size: Int,
private val color: Int,
var x: Float,
var y: Float,
) {
private val speedX = 4 * (Random.nextFloat() * 2 - 1) // Random speed in x direction
private val speedY = 4 * Random.nextFloat() // Random speed in y direction
private val rotationSpeed = (Random.nextFloat() - 0.5f) * 4f // Random rotation speed
private var rotation = Random.nextFloat() * 360f
/** Draws the [Confetti] on the [Canvas]. */
fun draw(canvas: Canvas, paint: Paint) {
canvas.save()
paint.color = color
canvas.translate(x, y)
canvas.rotate(rotation)
paint.textSize = size.toFloat()
canvas.drawText(text, /* x= */ 0f, /* y= */ 0f, paint) // Only draw text
canvas.restore()
}
/** Updates the [Confetti]. */
fun update() {
x += speedX
y += speedY
rotation += rotationSpeed
}
}
private companion object {
val CONFETTI_TEXTS = listOf("", "", "", "✦︎", "♥︎", "☕︎")
const val EMITTER_POSITION_Y = -50
const val CONFETTI_BASE_SIZE = 30
const val CONFETTI_SIZE_VARIATION = 10
}
}

View File

@ -0,0 +1,588 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.demo.effect
import android.Manifest
import android.net.Uri
import android.os.Bundle
import android.text.Spannable
import android.text.SpannableString
import android.text.style.ForegroundColorSpan
import androidx.activity.ComponentActivity
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.OptIn
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.Checkbox
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuAnchorType
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Slider
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import androidx.media3.common.Effect
import androidx.media3.common.MediaItem
import androidx.media3.common.util.UnstableApi
import androidx.media3.common.util.Util.SDK_INT
import androidx.media3.effect.Contrast
import androidx.media3.effect.OverlayEffect
import androidx.media3.effect.StaticOverlaySettings
import androidx.media3.effect.TextOverlay
import androidx.media3.effect.TextureOverlay
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.PlayerView
import com.google.common.collect.ImmutableList
import kotlinx.coroutines.launch
class EffectActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val playlistHolderList = mutableStateOf<List<PlaylistHolder>>(emptyList())
lifecycleScope.launch {
playlistHolderList.value =
loadPlaylistsFromJson(JSON_FILENAME, this@EffectActivity, "EffectActivity")
}
setContent { EffectDemo(playlistHolderList.value) }
}
@OptIn(UnstableApi::class)
@Composable
private fun EffectDemo(playlistHolderList: List<PlaylistHolder>) {
val snackbarHostState = remember { SnackbarHostState() }
val coroutineScope = rememberCoroutineScope()
val context = LocalContext.current
val exoPlayer by remember {
mutableStateOf(ExoPlayer.Builder(context).build().apply { playWhenReady = true })
}
var effectsEnabled by remember { mutableStateOf(false) }
Scaffold(
modifier = Modifier.fillMaxSize(),
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
) { paddingValues ->
Column(
modifier = Modifier.fillMaxWidth().padding(paddingValues),
verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.CenterHorizontally,
) {
InputChooser(
playlistHolderList,
onException = { message ->
coroutineScope.launch { snackbarHostState.showSnackbar(message) }
},
) { mediaItems ->
effectsEnabled = true
exoPlayer.apply {
setMediaItems(mediaItems)
setVideoEffects(emptyList())
prepare()
}
}
PlayerScreen(exoPlayer)
EffectControls(
effectsEnabled,
onApplyEffectsClicked = { videoEffects ->
exoPlayer.apply {
setVideoEffects(videoEffects)
prepare()
}
},
)
}
}
}
@Composable
private fun InputChooser(
playlistHolderList: List<PlaylistHolder>,
onException: (String) -> Unit,
onNewMediaItems: (List<MediaItem>) -> Unit,
) {
var showPresetInputChooser by remember { mutableStateOf(false) }
var showLocalFileChooser by remember { mutableStateOf(false) }
Row(
Modifier.padding(vertical = dimensionResource(id = R.dimen.regular_padding)),
horizontalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.regular_padding)),
) {
Button(onClick = { showPresetInputChooser = true }) {
Text(text = stringResource(id = R.string.choose_preset_input))
}
Button(onClick = { showLocalFileChooser = true }) {
Text(text = stringResource(id = R.string.choose_local_file))
}
}
if (showPresetInputChooser) {
if (playlistHolderList.isNotEmpty()) {
PresetInputChooser(
playlistHolderList,
onDismissRequest = { showPresetInputChooser = false },
) { mediaItems ->
onNewMediaItems(mediaItems)
showPresetInputChooser = false
}
} else {
onException(stringResource(id = R.string.no_loaded_playlists_error))
showPresetInputChooser = false
}
}
if (showLocalFileChooser) {
LocalFileChooser(
onException = { message ->
onException(message)
showLocalFileChooser = false
}
) { mediaItems ->
onNewMediaItems(mediaItems)
showLocalFileChooser = false
}
}
}
@Composable
private fun PresetInputChooser(
playlistHolderList: List<PlaylistHolder>,
onDismissRequest: () -> Unit,
onInputSelected: (List<MediaItem>) -> Unit,
) {
var selectedOption by remember { mutableStateOf(playlistHolderList.first()) }
AlertDialog(
onDismissRequest = onDismissRequest,
title = { Text(stringResource(id = R.string.choose_preset_input)) },
confirmButton = {
Button(onClick = { onInputSelected(selectedOption.mediaItems) }) {
Text(text = stringResource(id = R.string.ok))
}
},
text = {
Column {
playlistHolderList.forEach { playlistHolder ->
Row(
Modifier.fillMaxWidth()
.selectable(
(playlistHolder == selectedOption),
onClick = { selectedOption = playlistHolder },
),
verticalAlignment = Alignment.CenterVertically,
) {
RadioButton(
selected = (playlistHolder == selectedOption),
onClick = { selectedOption = playlistHolder },
)
Text(playlistHolder.title)
}
}
}
},
)
}
@OptIn(UnstableApi::class)
@Composable
private fun LocalFileChooser(
onException: (String) -> Unit,
onFileSelected: (List<MediaItem>) -> Unit,
) {
val context = LocalContext.current
val localFileChooserLauncher =
rememberLauncherForActivityResult(
contract = ActivityResultContracts.OpenDocument(),
onResult = { uri: Uri? ->
if (uri != null) {
onFileSelected(listOf(MediaItem.fromUri(uri)))
} else {
onException(getString(R.string.can_not_open_file_error))
}
},
)
val permissionLauncher =
rememberLauncherForActivityResult(
contract = ActivityResultContracts.RequestPermission(),
onResult = { isGranted: Boolean ->
if (isGranted) {
localFileChooserLauncher.launch(arrayOf("video/*"))
} else {
onException(getString(R.string.permission_not_granted_error))
}
},
)
LaunchedEffect(Unit) {
val permission =
if (SDK_INT >= 33) Manifest.permission.READ_MEDIA_VIDEO
else Manifest.permission.READ_EXTERNAL_STORAGE
val permissionCheck = ContextCompat.checkSelfPermission(context, permission)
if (permissionCheck == android.content.pm.PackageManager.PERMISSION_GRANTED) {
localFileChooserLauncher.launch(arrayOf("video/*"))
} else {
permissionLauncher.launch(permission)
}
}
}
@Composable
private fun PlayerScreen(exoPlayer: ExoPlayer) {
val context = LocalContext.current
AndroidView(
factory = { PlayerView(context).apply { player = exoPlayer } },
modifier =
Modifier.height(dimensionResource(id = R.dimen.android_view_height))
.padding(all = dimensionResource(id = R.dimen.regular_padding)),
)
}
@OptIn(UnstableApi::class)
@Composable
private fun EffectControls(enabled: Boolean, onApplyEffectsClicked: (List<Effect>) -> Unit) {
var effectControlsState by remember { mutableStateOf(EffectControlsState()) }
Button(
enabled = enabled && effectControlsState.effectsChanged,
onClick = {
val effectsList = mutableListOf<Effect>()
if (effectControlsState.contrastValue != 0f) {
effectsList += Contrast(effectControlsState.contrastValue)
}
val overlaysBuilder = ImmutableList.builder<TextureOverlay>()
if (effectControlsState.confettiOverlayChecked) {
overlaysBuilder.add(ConfettiOverlay())
}
val textOverlayText = effectControlsState.textOverlayText
if (effectControlsState.textOverlayChecked && textOverlayText != null) {
val spannableOverlayText = SpannableString(textOverlayText)
spannableOverlayText.setSpan(
ForegroundColorSpan(effectControlsState.textOverlayColor.toArgb()),
/* start= */ 0,
textOverlayText.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE,
)
val staticOverlaySettings =
StaticOverlaySettings.Builder()
.setAlphaScale(effectControlsState.textOverlayAlpha)
.build()
overlaysBuilder.add(
TextOverlay.createStaticTextOverlay(spannableOverlayText, staticOverlaySettings)
)
}
effectsList += OverlayEffect(overlaysBuilder.build())
onApplyEffectsClicked(effectsList)
effectControlsState = effectControlsState.copy(effectsChanged = false)
},
) {
Text(text = stringResource(id = R.string.apply_effects))
}
EffectControlsList(enabled, effectControlsState) { newEffectControlsState ->
effectControlsState = newEffectControlsState
}
}
@Composable
private fun EffectControlsList(
enabled: Boolean,
effectControlsState: EffectControlsState,
onEffectControlsStateChange: (EffectControlsState) -> Unit,
) {
LazyColumn(Modifier.padding(vertical = dimensionResource(id = R.dimen.small_padding))) {
item {
EffectItem(
name = stringResource(id = R.string.contrast),
enabled = enabled,
onCheckedChange = {
onEffectControlsStateChange(
effectControlsState.copy(effectsChanged = true, contrastValue = 0f)
)
},
) {
Row {
Text(
text = "%.2f".format(effectControlsState.contrastValue),
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.padding(dimensionResource(id = R.dimen.large_padding)).weight(1f),
)
Slider(
value = effectControlsState.contrastValue,
onValueChange = { newContrastValue ->
val newRoundedContrastValue = "%.2f".format(newContrastValue).toFloat()
onEffectControlsStateChange(
effectControlsState.copy(
effectsChanged = true,
contrastValue = newRoundedContrastValue,
)
)
},
valueRange = -1f..1f,
modifier = Modifier.weight(4f),
)
}
}
}
item {
EffectItem(
name = stringResource(R.string.confetti_overlay),
enabled = enabled,
onCheckedChange = { checked ->
onEffectControlsStateChange(
effectControlsState.copy(effectsChanged = true, confettiOverlayChecked = checked)
)
},
)
}
item {
EffectItem(
name = stringResource(R.string.custom_text_overlay),
enabled = enabled,
onCheckedChange = { checked ->
onEffectControlsStateChange(
effectControlsState.copy(effectsChanged = !checked, textOverlayChecked = checked)
)
},
) {
Column {
OutlinedTextField(
value = effectControlsState.textOverlayText ?: "",
onValueChange = { newTextOverlayText ->
onEffectControlsStateChange(
effectControlsState.copy(
effectsChanged = true,
textOverlayText = newTextOverlayText.ifEmpty { null },
)
)
},
label = { Text(stringResource(R.string.text)) },
singleLine = true,
modifier =
Modifier.fillMaxWidth().padding(bottom = dimensionResource(R.dimen.large_padding)),
)
Row {
ColorsDropDownMenu(effectControlsState.textOverlayColor) { color ->
onEffectControlsStateChange(
effectControlsState.copy(
effectsChanged = effectControlsState.textOverlayText != null,
textOverlayColor = color,
)
)
}
}
Row {
Text(
text =
stringResource(R.string.alpha) +
" = %.2f".format(effectControlsState.textOverlayAlpha),
style = MaterialTheme.typography.bodyLarge,
modifier =
Modifier.padding(dimensionResource(id = R.dimen.large_padding)).weight(1f),
)
Slider(
value = effectControlsState.textOverlayAlpha,
onValueChange = { newAlphaValue ->
val newRoundedAlphaValue = "%.2f".format(newAlphaValue).toFloat()
onEffectControlsStateChange(
effectControlsState.copy(
effectsChanged = effectControlsState.textOverlayText != null,
textOverlayAlpha = newRoundedAlphaValue,
)
)
},
valueRange = 0f..1f,
modifier = Modifier.weight(2f),
)
}
}
}
}
}
}
@kotlin.OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ColorsDropDownMenu(color: Color, onItemSelected: (Color) -> Unit) {
var expanded by remember { mutableStateOf(false) }
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = it },
modifier = Modifier.fillMaxWidth().padding(bottom = dimensionResource(R.dimen.large_padding)),
) {
OutlinedTextField(
modifier = Modifier.fillMaxWidth().menuAnchor(MenuAnchorType.PrimaryNotEditable),
value = COLOR_NAMES[color] ?: stringResource(R.string.unknown_color),
onValueChange = {},
readOnly = true,
singleLine = true,
label = { Text(stringResource(R.string.text_color)) },
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
colors = ExposedDropdownMenuDefaults.textFieldColors(),
)
ExposedDropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
for (color in COLORS) {
DropdownMenuItem(
text = {
Text(
COLOR_NAMES[color] ?: stringResource(R.string.unknown_color),
style = MaterialTheme.typography.bodyLarge,
)
},
onClick = {
onItemSelected(color)
expanded = false
},
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
leadingIcon = {
Box(
modifier =
Modifier.size(dimensionResource(R.dimen.color_circle_size))
.background(color, CircleShape)
)
},
)
}
}
}
}
@Composable
fun EffectItem(
name: String,
enabled: Boolean,
onCheckedChange: (Boolean) -> Unit = {},
content: @Composable () -> Unit = {},
) {
var checked by rememberSaveable { mutableStateOf(false) }
Card(
modifier =
Modifier.padding(
vertical = dimensionResource(id = R.dimen.small_padding),
horizontal = dimensionResource(id = R.dimen.regular_padding),
)
.clickable(enabled = enabled && !checked) {
checked = !checked
onCheckedChange(checked)
}
) {
Column(
Modifier.padding(dimensionResource(id = R.dimen.large_padding))
.animateContentSize(animationSpec = tween(durationMillis = 200, easing = LinearEasing))
) {
Row {
Column(Modifier.weight(1f).padding(dimensionResource(id = R.dimen.large_padding))) {
Text(text = name, style = MaterialTheme.typography.bodyLarge)
}
Checkbox(
enabled = enabled,
checked = checked,
onCheckedChange = {
checked = !checked
onCheckedChange(checked)
},
)
}
if (checked) {
content()
}
}
}
}
private data class EffectControlsState(
val effectsChanged: Boolean = false,
val contrastValue: Float = 0f,
val confettiOverlayChecked: Boolean = false,
val textOverlayChecked: Boolean = false,
val textOverlayText: String? = null,
val textOverlayColor: Color = COLORS[0],
val textOverlayAlpha: Float = 1f,
)
private companion object {
const val JSON_FILENAME = "media.playlist.json"
val COLORS =
listOf(
Color.Black,
Color.DarkGray,
Color.Gray,
Color.LightGray,
Color.White,
Color.Red,
Color.Green,
Color.Blue,
Color.Yellow,
Color.Cyan,
Color.Magenta,
)
val COLOR_NAMES =
mapOf(
Color.Black to "Black",
Color.DarkGray to "Dark Gray",
Color.Gray to "Gray",
Color.LightGray to "Light Gray",
Color.White to "White",
Color.Red to "Red",
Color.Green to "Green",
Color.Blue to "Blue",
Color.Yellow to "Yellow",
Color.Cyan to "Cyan",
Color.Magenta to "Magenta",
)
}
}

View File

@ -0,0 +1,78 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.demo.effect
import android.content.Context
import android.net.Uri
import android.util.JsonReader
import android.util.Log
import androidx.media3.common.MediaItem
import java.io.IOException
import java.io.InputStreamReader
import java.nio.charset.StandardCharsets
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
internal suspend fun loadPlaylistsFromJson(
jsonFilename: String,
context: Context,
tag: String,
): List<PlaylistHolder> =
withContext(Dispatchers.IO) {
try {
context.assets.open(jsonFilename).use { inputStream ->
val reader = JsonReader(InputStreamReader(inputStream, StandardCharsets.UTF_8))
val playlistHolders = buildList {
reader.beginArray()
while (reader.hasNext()) {
readPlaylist(reader)?.let { add(it) }
}
reader.endArray()
}
playlistHolders
}
} catch (e: IOException) {
Log.e(tag, context.getString(R.string.playlist_loading_error, jsonFilename, e))
emptyList()
}
}
private fun readPlaylist(reader: JsonReader): PlaylistHolder? {
val playlistHolder = PlaylistHolder("", emptyList())
reader.beginObject()
while (reader.hasNext()) {
val name = reader.nextName()
if (name.equals("name")) {
playlistHolder.title = reader.nextString()
} else if (name.equals("playlist")) {
playlistHolder.mediaItems = buildList {
reader.beginArray()
while (reader.hasNext()) {
reader.beginObject()
reader.nextName()
add(MediaItem.fromUri(Uri.parse(reader.nextString())))
reader.endObject()
}
reader.endArray()
}
}
}
reader.endObject()
// Only return the playlistHolder object if it has media items
return if (playlistHolder.mediaItems.isNotEmpty()) playlistHolder else null
}
internal data class PlaylistHolder(var title: String, var mediaItems: List<MediaItem>)

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<!-- Base application theme. -->
<style name="Theme.Media3EffectDemo" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<dimen name="small_padding">4dp</dimen>
<dimen name="regular_padding">8dp</dimen>
<dimen name="large_padding">12dp</dimen>
<dimen name="android_view_height">256dp</dimen>
<dimen name="color_circle_size">40dp</dimen>
</resources>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="app_name">Effect Demo</string>
<string name="choose_preset_input">Choose preset input</string>
<string name="choose_local_file">Choose local file</string>
<string name="apply_effects">Apply effects</string>
<string name="ok">OK</string>
<string name="playlist_loading_error">Error loading playlist from %1$s: %2$s</string>
<string name="no_loaded_playlists_error">There are no loaded preset inputs.</string>
<string name="can_not_open_file_error">"File couldn't be opened. Please try again."</string>
<string name="permission_not_granted_error">"Permission was not granted."</string>
<string name="contrast">Contrast</string>
<string name="confetti_overlay">Confetti Overlay</string>
<string name="custom_text_overlay">Custom Text Overlay</string>
<string name="text">Text</string>
<string name="text_color">Text color</string>
<string name="unknown_color">Unknown color</string>
<string name="alpha">Alpha</string>
</resources>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<!-- Base application theme. -->
<style name="Theme.Media3EffectDemo" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@ -14,7 +14,6 @@
apply from: '../../constants.gradle'
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
android {
namespace 'androidx.media3.demo.main'
@ -90,6 +89,7 @@ dependencies {
withDecoderExtensionsImplementation project(modulePrefix + 'lib-decoder-iamf')
withDecoderExtensionsImplementation project(modulePrefix + 'lib-decoder-vp9')
withDecoderExtensionsImplementation project(modulePrefix + 'lib-decoder-midi')
withDecoderExtensionsImplementation project(modulePrefix + 'lib-decoder-mpegh')
withDecoderExtensionsImplementation project(modulePrefix + 'lib-datasource-rtmp')
}

View File

@ -257,6 +257,10 @@
{
"name": "Apple media playlist (AAC)",
"uri": "https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_4x3/gear0/prog_index.m3u8"
},
{
"name": "Bitmovin (FMP4)",
"uri": "https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s-fmp4/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8"
}
]
},
@ -280,15 +284,25 @@
"name": "IMA sample ad tags",
"samples": [
{
"name": "Single inline linear",
"name": "VMAP pre-roll single ad, mid-roll standard pods with 5 ads every 10 seconds for 1:40, post-roll single ad",
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv",
"ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinear&correlator="
"ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostlongpod&cmsid=496&vid=short_tencue&correlator="
},
{
"name": "VMAP empty midroll",
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv",
"ad_tag_uri": "https://vastsynthesizer.appspot.com/empty-midroll"
},
{
"name": "Single skippable inline",
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv",
"ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dskippablelinear&correlator="
},
{
"name": "Single inline linear",
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv",
"ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinear&correlator="
},
{
"name": "Single redirect linear",
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv",
@ -349,16 +363,6 @@
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv",
"ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostoptimizedpodbumper&cmsid=496&vid=short_onecue&correlator="
},
{
"name": "VMAP pre-roll single ad, mid-roll standard pods with 5 ads every 10 seconds for 1:40, post-roll single ad",
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv",
"ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostlongpod&cmsid=496&vid=short_tencue&correlator="
},
{
"name": "VMAP empty midroll",
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv",
"ad_tag_uri": "https://vastsynthesizer.appspot.com/empty-midroll"
},
{
"name": "VMAP full, empty, full midrolls",
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv",
@ -396,6 +400,10 @@
{
"name": "IMA DAI streams",
"samples": [
{
"name": "DASH VOD: Tears of Steel (11 periods, pre/mid/post), 2/5/2 ads [5/10s]",
"uri": "ssai://dai.google.com/?contentSourceId=2559737&videoId=tos-dash&format=0&adsId=1"
},
{
"name": "HLS VOD: Demo (skippable pre/post), single ads [30 s]",
"uri": "ssai://dai.google.com/?contentSourceId=2483977&videoId=ima-vod-skippable-test&format=2&adsId=1"
@ -408,10 +416,6 @@
"name": "HLS Live: Big Buck Bunny (mid), 3 ads [10/10/10s]",
"uri": "ssai://dai.google.com/?assetKey=sN_IYUG8STe1ZzhIIE_ksA&format=2&adsId=3"
},
{
"name": "DASH VOD: Tears of Steel (11 periods, pre/mid/post), 2/5/2 ads [5/10s]",
"uri": "ssai://dai.google.com/?contentSourceId=2559737&videoId=tos-dash&format=0&adsId=1"
},
{
"name": "DASH live: Tears of Steel (mid), 3 ads each [10 s]",
"uri": "ssai://dai.google.com/?assetKey=jNVjPZwzSkyeGiaNQTPqiQ&format=0&adsId=1"
@ -420,6 +424,34 @@
"name": "DASH live: New Tears of Steel (mid), 3 ads each [10 s]",
"uri": "ssai://dai.google.com/?assetKey=PSzZMzAkSXCmlJOWDmRj8Q&format=0&adsId=12"
},
{
"name": "Playlist: No ads - HLS live: Big Buck Bunny - No ads",
"playlist": [
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
},
{
"uri": "ssai://dai.google.com/?assetKey=sN_IYUG8STe1ZzhIIE_ksA&format=2&adsId=3"
},
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
}
]
},
{
"name": "Playlist: No ads - DASH live: Tears of Steel (mid) - No ads",
"playlist": [
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
},
{
"uri": "ssai://dai.google.com/?assetKey=PSzZMzAkSXCmlJOWDmRj8Q&format=0&adsId=1"
},
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
}
]
},
{
"name": "DASH live: Unencrypted stream with 30s ad breaks every minute",
"uri": "ssai://dai.google.com/?assetKey=0ndl1dJcRmKDUPxTRjvdog&format=0&adsId=21"
@ -480,34 +512,6 @@
"uri": "https://html5demos.com/assets/dizzy.mp4"
}
]
},
{
"name": "Playlist: No ads - DASH live: Tears of Steel (mid) - No ads",
"playlist": [
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
},
{
"uri": "ssai://dai.google.com/?assetKey=PSzZMzAkSXCmlJOWDmRj8Q&format=0&adsId=1"
},
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
}
]
},
{
"name": "Playlist: No ads - HLS live: Big Buck Bunny - No ads",
"playlist": [
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
},
{
"uri": "ssai://dai.google.com/?assetKey=sN_IYUG8STe1ZzhIIE_ksA&format=2&adsId=3"
},
{
"uri": "https://html5demos.com/assets/dizzy.mp4"
}
]
}
]
},
@ -762,6 +766,10 @@
{
"name": "Immersive Audio Format Sample (MP4, IAMF)",
"uri": "https://github.com/AOMediaCodec/libiamf/raw/main/tests/test_000036_s.mp4"
},
{
"name": "MPEG-H HD (MP4, H265)",
"uri": "https://media.githubusercontent.com/media/Fraunhofer-IIS/mpegh-test-content/main/TRI_Fileset_17_514H_D1_D2_D3_O1_24bit1080p50.mp4"
}
]
},

View File

@ -315,7 +315,7 @@ public class DownloadTracker {
TrackSelectionDialog.createForTracksAndParameters(
/* titleId= */ R.string.exo_download_description,
tracks,
DownloadHelper.getDefaultTrackSelectorParameters(context),
DownloadHelper.DEFAULT_TRACK_SELECTOR_PARAMETERS,
/* allowAdaptiveSelections= */ false,
/* allowMultipleOverrides= */ true,
/* onTracksSelectedListener= */ this,

View File

@ -61,7 +61,6 @@ import androidx.media3.datasource.DataSourceUtil;
import androidx.media3.datasource.DataSpec;
import androidx.media3.exoplayer.RenderersFactory;
import androidx.media3.exoplayer.offline.DownloadService;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.io.IOException;
@ -74,6 +73,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -524,7 +524,7 @@ public class SampleChooserActivity extends AppCompatActivity
private PlaylistGroup getGroup(String groupName, List<PlaylistGroup> groups) {
for (int i = 0; i < groups.size(); i++) {
if (Objects.equal(groupName, groups.get(i).title)) {
if (Objects.equals(groupName, groups.get(i).title)) {
return groups.get(i);
}
}

View File

@ -41,8 +41,7 @@ open class DemoMediaLibrarySessionCallback(context: Context) :
MediaItemTree.initialize(context.assets)
}
@OptIn(UnstableApi::class) // TODO: b/328238954 - Remove once new CommandButton icons are stable.
private val customLayoutCommandButtons: List<CommandButton> =
private val commandButtons: List<CommandButton> =
listOf(
CommandButton.Builder(CommandButton.ICON_SHUFFLE_OFF)
.setDisplayName(context.getString(R.string.exo_controls_shuffle_on_description))
@ -59,7 +58,7 @@ open class DemoMediaLibrarySessionCallback(context: Context) :
MediaSession.ConnectionResult.DEFAULT_SESSION_AND_LIBRARY_COMMANDS.buildUpon()
.also { builder ->
// Put all custom session commands in the list that may be used by the notification.
customLayoutCommandButtons.forEach { commandButton ->
commandButtons.forEach { commandButton ->
commandButton.sessionCommand?.let { builder.add(it) }
}
}
@ -78,13 +77,13 @@ open class DemoMediaLibrarySessionCallback(context: Context) :
session.isAutoCompanionController(controller)
) {
// Select the button to display.
val customLayout = customLayoutCommandButtons[if (session.player.shuffleModeEnabled) 1 else 0]
val customButton = commandButtons[if (session.player.shuffleModeEnabled) 1 else 0]
return MediaSession.ConnectionResult.AcceptedResultBuilder(session)
.setAvailableSessionCommands(mediaNotificationSessionCommands)
.setCustomLayout(ImmutableList.of(customLayout))
.setMediaButtonPreferences(ImmutableList.of(customButton))
.build()
}
// Default commands without custom layout for common controllers.
// Default commands without media button preferences for common controllers.
return MediaSession.ConnectionResult.AcceptedResultBuilder(session).build()
}
@ -98,19 +97,19 @@ open class DemoMediaLibrarySessionCallback(context: Context) :
if (CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_ON == customCommand.customAction) {
// Enable shuffling.
session.player.shuffleModeEnabled = true
// Change the custom layout to contain the `Disable shuffling` command.
session.setCustomLayout(
// Change the media button preferences to contain the `Disable shuffling` button.
session.setMediaButtonPreferences(
session.mediaNotificationControllerInfo!!,
ImmutableList.of(customLayoutCommandButtons[1]),
ImmutableList.of(commandButtons[1]),
)
return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS))
} else if (CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_OFF == customCommand.customAction) {
// Disable shuffling.
session.player.shuffleModeEnabled = false
// Change the custom layout to contain the `Enable shuffling` command.
session.setCustomLayout(
// Change the media button preferences to contain the `Enable shuffling` button.
session.setMediaButtonPreferences(
session.mediaNotificationControllerInfo!!,
ImmutableList.of(customLayoutCommandButtons[0]),
ImmutableList.of(commandButtons[0]),
)
return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS))
}

View File

@ -76,6 +76,7 @@ dependencies {
implementation 'androidx.appcompat:appcompat:' + androidxAppCompatVersion
implementation 'androidx.constraintlayout:constraintlayout:' + androidxConstraintLayoutVersion
implementation 'androidx.recyclerview:recyclerview:' + androidxRecyclerViewVersion
implementation 'androidx.window:window:' + androidxWindowVersion
implementation 'com.google.android.material:material:' + androidxMaterialVersion
implementation project(modulePrefix + 'lib-effect')
implementation project(modulePrefix + 'lib-exoplayer')

View File

@ -24,6 +24,10 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
<!-- For media projection. -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION"/>
<application
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
@ -64,5 +68,9 @@
android:label="@string/app_name"
android:exported="true"
android:theme="@style/Theme.MaterialComponents.DayNight.NoActionBar"/>
<service
android:name=".TransformerActivity$DemoMediaProjectionService"
android:foregroundServiceType="mediaProjection"
android:exported="false"/>
</application>
</manifest>

View File

@ -0,0 +1,188 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.demo.transformer;
import android.animation.FloatEvaluator;
import android.animation.Keyframe;
import android.animation.PropertyValuesHolder;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.Pair;
import android.view.animation.LinearInterpolator;
import androidx.media3.common.OverlaySettings;
import androidx.media3.common.VideoFrameProcessingException;
import androidx.media3.common.util.Util;
import androidx.media3.effect.DrawableOverlay;
import androidx.media3.effect.TextureOverlay;
import java.util.concurrent.CountDownLatch;
/**
* An animated {@link TextureOverlay} using {@link android.animation}.
*
* <p>The rotation is controlled by a simple {@link ValueAnimator}, while the position is controlled
* by key frames.
*/
public class AnimatedLogoOverlay extends DrawableOverlay {
private static final long ROTATION_PERIOD_MS = 2_000;
private static final long POSITION_PERIOD_MS = 5_000;
private static final float POSITION_X_BOUND = 0.8f;
private static final float POSITION_Y_BOUND = 0.7f;
private final Drawable logo;
private final AnimatedOverlaySettings overlaySettings;
public AnimatedLogoOverlay(Context context) {
try {
logo = context.getPackageManager().getApplicationIcon(context.getPackageName());
} catch (PackageManager.NameNotFoundException e) {
throw new IllegalStateException(e);
}
logo.setBounds(
/* left= */ 0, /* top= */ 0, logo.getIntrinsicWidth(), logo.getIntrinsicHeight());
ValueAnimator rotationAnimator = ValueAnimator.ofFloat(0, 360);
rotationAnimator.setRepeatMode(ValueAnimator.RESTART);
rotationAnimator.setRepeatCount(ValueAnimator.INFINITE);
rotationAnimator.setDuration(ROTATION_PERIOD_MS);
// Rotate the logo with a constant angular velocity.
rotationAnimator.setInterpolator(new LinearInterpolator());
Keyframe[] keyFrames = new Keyframe[5];
keyFrames[0] =
Keyframe.ofObject(/* fraction= */ 0f, Pair.create(-POSITION_X_BOUND, -POSITION_Y_BOUND));
keyFrames[2] =
Keyframe.ofObject(/* fraction= */ 0.5f, Pair.create(POSITION_X_BOUND, POSITION_Y_BOUND));
keyFrames[1] =
Keyframe.ofObject(/* fraction= */ 0.25f, Pair.create(-POSITION_X_BOUND, POSITION_Y_BOUND));
keyFrames[3] =
Keyframe.ofObject(/* fraction= */ 0.75f, Pair.create(POSITION_X_BOUND, -POSITION_Y_BOUND));
keyFrames[4] =
Keyframe.ofObject(/* fraction= */ 1f, Pair.create(-POSITION_X_BOUND, -POSITION_Y_BOUND));
PropertyValuesHolder positionValuesHolder =
PropertyValuesHolder.ofKeyframe("position", keyFrames);
ValueAnimator positionAnimator = ValueAnimator.ofPropertyValuesHolder(positionValuesHolder);
// The position can also be animated using separate animators for x and y, the purpose of
// PairEvaluator is to use one animator for both x and y.
positionAnimator.setEvaluator(new AnimatedOverlaySettings.PairEvaluator());
positionAnimator.setRepeatMode(ValueAnimator.RESTART);
positionAnimator.setRepeatCount(ValueAnimator.INFINITE);
positionAnimator.setDuration(POSITION_PERIOD_MS);
overlaySettings = new AnimatedOverlaySettings(rotationAnimator, positionAnimator);
}
@Override
public Drawable getDrawable(long presentationTimeUs) {
return logo;
}
@Override
public OverlaySettings getOverlaySettings(long presentationTimeUs) {
overlaySettings.setCurrentPresentationTimeUs(presentationTimeUs);
return overlaySettings;
}
@Override
public void release() throws VideoFrameProcessingException {
super.release();
overlaySettings.stopAnimation();
}
private static class AnimatedOverlaySettings implements OverlaySettings {
private final ValueAnimator rotationAnimator;
private final ValueAnimator positionAnimator;
private final Handler mainThreadHandler;
private boolean started;
public AnimatedOverlaySettings(ValueAnimator rotationAnimator, ValueAnimator positionAnimator) {
this.rotationAnimator = rotationAnimator;
this.positionAnimator = positionAnimator;
mainThreadHandler = new Handler(Util.getCurrentOrMainLooper());
}
public void setCurrentPresentationTimeUs(long presentationTimeUs) {
// Sets the animation time to the video presentation time, so the animation is presentation
// time based.
rotationAnimator.setCurrentPlayTime(presentationTimeUs / 1000);
positionAnimator.setCurrentPlayTime(presentationTimeUs / 1000);
}
@Override
public float getRotationDegrees() {
maybeStartAnimator();
return (float) rotationAnimator.getAnimatedValue();
}
@Override
public Pair<Float, Float> getBackgroundFrameAnchor() {
maybeStartAnimator();
return (Pair<Float, Float>) positionAnimator.getAnimatedValue();
}
public void stopAnimation() {
mainThreadHandler.post(
() -> {
rotationAnimator.cancel();
positionAnimator.cancel();
});
}
private void maybeStartAnimator() {
if (!started) {
CountDownLatch latch = new CountDownLatch(1);
mainThreadHandler.post(
() -> {
rotationAnimator.start();
positionAnimator.start();
latch.countDown();
});
try {
// Block until the animators are actually started, or they'll return null values.
latch.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException(e);
}
started = true;
}
}
/** An {@link TypeEvaluator} to animate position in the form of {@link Pair} of floats. */
private static class PairEvaluator implements TypeEvaluator<Pair<Float, Float>> {
private final FloatEvaluator floatEvaluator;
private PairEvaluator() {
floatEvaluator = new FloatEvaluator();
}
@Override
public Pair<Float, Float> evaluate(
float fraction, Pair<Float, Float> startValue, Pair<Float, Float> endValue) {
return Pair.create(
floatEvaluator.evaluate(fraction, startValue.first, endValue.first),
floatEvaluator.evaluate(fraction, startValue.second, endValue.second));
}
}
}
}

View File

@ -0,0 +1,106 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.demo.transformer;
import static java.lang.Math.toRadians;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.RectF;
import androidx.media3.common.OverlaySettings;
import androidx.media3.effect.CanvasOverlay;
import androidx.media3.effect.StaticOverlaySettings;
/* package */ final class ClockOverlay extends CanvasOverlay {
private static final int CLOCK_COLOR = Color.WHITE;
private static final int DIAL_SIZE = 200;
private static final float DIAL_WIDTH = 3.f;
private static final float NEEDLE_WIDTH = 3.f;
private static final int NEEDLE_LENGTH = DIAL_SIZE / 2 - 20;
private static final int CENTRE_X = DIAL_SIZE / 2;
private static final int CENTRE_Y = DIAL_SIZE / 2;
private static final int DIAL_INSET = 5;
private static final RectF DIAL_BOUND =
new RectF(
/* left= */ DIAL_INSET,
/* top= */ DIAL_INSET,
/* right= */ DIAL_SIZE - DIAL_INSET,
/* bottom= */ DIAL_SIZE - DIAL_INSET);
private static final int HUB_SIZE = 5;
private static final float BOTTOM_RIGHT_ANCHOR_X = 1.f;
private static final float BOTTOM_RIGHT_ANCHOR_Y = -1.f;
private static final float ANCHOR_INSET_X = 0.1f;
private static final float ANCHOR_INSET_Y = -0.1f;
private final Paint dialPaint;
private final Paint needlePaint;
private final Paint hubPaint;
public ClockOverlay() {
super(/* useInputFrameSize= */ false);
setCanvasSize(/* width= */ DIAL_SIZE, /* height= */ DIAL_SIZE);
dialPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
dialPaint.setStyle(Paint.Style.STROKE);
dialPaint.setStrokeWidth(DIAL_WIDTH);
dialPaint.setColor(CLOCK_COLOR);
needlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
needlePaint.setStrokeWidth(NEEDLE_WIDTH);
needlePaint.setColor(CLOCK_COLOR);
hubPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
hubPaint.setColor(CLOCK_COLOR);
}
@Override
public void onDraw(Canvas canvas, long presentationTimeUs) {
// Clears the canvas
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
// Draw the dial
canvas.drawArc(
DIAL_BOUND, /* startAngle= */ 0, /* sweepAngle= */ 360, /* useCenter= */ false, dialPaint);
// Draw the needle
float angle = 6 * presentationTimeUs / 1_000_000.f - 90;
double radians = toRadians(angle);
float startX = CENTRE_X - (float) (10 * Math.cos(radians));
float startY = CENTRE_Y - (float) (10 * Math.sin(radians));
float endX = CENTRE_X + (float) (NEEDLE_LENGTH * Math.cos(radians));
float endY = CENTRE_Y + (float) (NEEDLE_LENGTH * Math.sin(radians));
canvas.drawLine(startX, startY, endX, endY, needlePaint);
// Draw a small hub at the center
canvas.drawCircle(CENTRE_X, CENTRE_Y, HUB_SIZE, hubPaint);
}
@Override
public OverlaySettings getOverlaySettings(long presentationTimeUs) {
return new StaticOverlaySettings.Builder()
.setBackgroundFrameAnchor(
BOTTOM_RIGHT_ANCHOR_X - ANCHOR_INSET_X, BOTTOM_RIGHT_ANCHOR_Y - ANCHOR_INSET_Y)
.setOverlayFrameAnchor(BOTTOM_RIGHT_ANCHOR_X, BOTTOM_RIGHT_ANCHOR_Y)
.build();
}
}

View File

@ -0,0 +1,162 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.demo.transformer;
import static androidx.media3.common.util.Assertions.checkStateNotNull;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.os.Handler;
import androidx.annotation.Nullable;
import androidx.media3.common.VideoFrameProcessingException;
import androidx.media3.common.util.Size;
import androidx.media3.common.util.Util;
import androidx.media3.effect.CanvasOverlay;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/** Mimics an emitter of confetti, dropping from the center of the frame. */
/* package */ final class ConfettiOverlay extends CanvasOverlay {
private static final ImmutableList<String> CONFETTI_TEXTS =
ImmutableList.of("", "", "", "✦︎", "♥︎", "☕︎");
private static final int EMITTER_POSITION_Y = -50;
private static final int CONFETTI_BASE_SIZE = 30;
private static final int CONFETTI_SIZE_VARIATION = 10;
private final List<Confetti> confettiList;
private final Random random;
private final Paint paint;
private final Handler handler;
@Nullable private Runnable runnable;
private int width;
private int height;
private boolean started;
public ConfettiOverlay() {
super(/* useInputFrameSize= */ true);
confettiList = new ArrayList<>();
random = new Random();
paint = new Paint();
paint.setAntiAlias(true);
handler = new Handler(Util.getCurrentOrMainLooper());
}
@Override
public void configure(Size videoSize) {
super.configure(videoSize);
this.width = videoSize.getWidth();
this.height = videoSize.getHeight();
}
@Override
public synchronized void onDraw(Canvas canvas, long presentationTimeUs) {
if (!started) {
start();
}
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
for (int i = 0; i < confettiList.size(); i++) {
Confetti confetti = confettiList.get(i);
if (confetti.y > (float) height / 2 || confetti.x <= 0 || confetti.x > width) {
confettiList.remove(confetti);
continue;
}
confetti.draw(canvas, paint);
confetti.update();
}
}
/** Starts the confetti. */
public void start() {
runnable = this::addConfetti;
handler.post(runnable);
started = true;
}
/** Stops the confetti. */
public void stop() {
checkStateNotNull(runnable);
handler.removeCallbacks(runnable);
confettiList.clear();
started = false;
runnable = null;
}
@Override
public void release() throws VideoFrameProcessingException {
super.release();
handler.post(this::stop);
}
private synchronized void addConfetti() {
for (int i = 0; i < 5; i++) {
confettiList.add(
new Confetti(
CONFETTI_TEXTS.get(Math.abs(random.nextInt()) % CONFETTI_TEXTS.size()),
random,
/* x= */ (float) width / 2,
/* y= */ EMITTER_POSITION_Y,
/* size= */ CONFETTI_BASE_SIZE + random.nextInt(CONFETTI_SIZE_VARIATION),
/* color= */ Color.HSVToColor(
new float[] {
/* hue= */ random.nextInt(360), /* saturation= */ 0.6f, /* value= */ 0.8f
})));
}
handler.postDelayed(this::addConfetti, /* delayMillis= */ 100);
}
private static final class Confetti {
private final String text;
private final float speedX;
private final float speedY;
private final int size;
private final int color;
private float x;
private float y;
public Confetti(String text, Random random, float x, float y, int size, int color) {
this.text = text;
this.x = x;
this.y = y;
this.size = size;
this.color = color;
speedX = 4 * (random.nextFloat() * 2 - 1); // Random speed in x direction
speedY = 4 * random.nextFloat(); // Random downward speed
}
/** Draws the {@code Confetti} on the {@link Canvas}. */
public void draw(Canvas canvas, Paint paint) {
canvas.save();
paint.setColor(color);
paint.setTextSize(size);
canvas.drawText(text, x, y, paint);
canvas.restore();
}
/** Updates the {@code Confetti}. */
public void update() {
x += speedX;
y += speedY;
}
}
}

View File

@ -77,8 +77,8 @@ public final class ConfigurationActivity extends AppCompatActivity {
public static final String ENABLE_ANALYZER_MODE = "enable_analyzer_mode";
public static final String ENABLE_DEBUG_PREVIEW = "enable_debug_preview";
public static final String ABORT_SLOW_EXPORT = "abort_slow_export";
public static final String USE_MEDIA3_MUXER = "use_media3_muxer";
public static final String PRODUCE_FRAGMENTED_MP4 = "produce_fragmented_mp4";
public static final String USE_MEDIA3_MP4_MUXER = "use_media3_mp4_muxer";
public static final String USE_MEDIA3_FRAGMENTED_MP4_MUXER = "use_media3_fragmented_mp4_muxer";
public static final String HDR_MODE = "hdr_mode";
public static final String AUDIO_EFFECTS_SELECTIONS = "audio_effects_selections";
public static final String VIDEO_EFFECTS_SELECTIONS = "video_effects_selections";
@ -114,13 +114,17 @@ public final class ConfigurationActivity extends AppCompatActivity {
public static final int OVERLAY_LOGO_AND_TIMER_INDEX = 10;
public static final int BITMAP_OVERLAY_INDEX = 11;
public static final int TEXT_OVERLAY_INDEX = 12;
public static final int CLOCK_OVERLAY_INDEX = 13;
public static final int CONFETTI_OVERLAY_INDEX = 14;
public static final int ANIMATING_LOGO_OVERLAY = 15;
// Audio effect selections.
public static final int HIGH_PITCHED_INDEX = 0;
public static final int SAMPLE_RATE_INDEX = 1;
public static final int SKIP_SILENCE_INDEX = 2;
public static final int CHANNEL_MIXING_INDEX = 3;
public static final int VOLUME_SCALING_INDEX = 4;
public static final int SAMPLE_RATE_48K_INDEX = 1;
public static final int SAMPLE_RATE_96K_INDEX = 2;
public static final int SKIP_SILENCE_INDEX = 3;
public static final int CHANNEL_MIXING_INDEX = 4;
public static final int VOLUME_SCALING_INDEX = 5;
// Color filter options.
public static final int COLOR_FILTER_GRAYSCALE = 0;
@ -173,8 +177,8 @@ public final class ConfigurationActivity extends AppCompatActivity {
private CheckBox enableDebugPreviewCheckBox;
private CheckBox enableDebugTracingCheckBox;
private CheckBox abortSlowExportCheckBox;
private CheckBox useMedia3Muxer;
private CheckBox produceFragmentedMp4CheckBox;
private CheckBox useMedia3Mp4Muxer;
private CheckBox useMedia3FragmentedMp4Muxer;
private Spinner hdrModeSpinner;
private Button selectAudioEffectsButton;
private Button selectVideoEffectsButton;
@ -262,7 +266,8 @@ public final class ConfigurationActivity extends AppCompatActivity {
MimeTypes.VIDEO_H264,
MimeTypes.VIDEO_H265,
MimeTypes.VIDEO_MP4V,
MimeTypes.VIDEO_AV1);
MimeTypes.VIDEO_AV1,
MimeTypes.VIDEO_DOLBY_VISION);
ArrayAdapter<String> resolutionHeightAdapter =
new ArrayAdapter<>(/* context= */ this, R.layout.spinner_item);
@ -299,18 +304,18 @@ public final class ConfigurationActivity extends AppCompatActivity {
(buttonView, isChecked) -> DebugTraceUtil.enableTracing = isChecked);
abortSlowExportCheckBox = findViewById(R.id.abort_slow_export_checkbox);
useMedia3Muxer = findViewById(R.id.use_media3_muxer_checkbox);
produceFragmentedMp4CheckBox = findViewById(R.id.produce_fragmented_mp4_checkbox);
useMedia3Muxer.setOnCheckedChangeListener(
(buttonView, isChecked) -> {
if (!isChecked) {
produceFragmentedMp4CheckBox.setChecked(false);
}
});
produceFragmentedMp4CheckBox.setOnCheckedChangeListener(
useMedia3Mp4Muxer = findViewById(R.id.use_media3_mp4_muxer_checkbox);
useMedia3FragmentedMp4Muxer = findViewById(R.id.use_media3_fragmented_mp4_muxer_checkbox);
useMedia3Mp4Muxer.setOnCheckedChangeListener(
(buttonView, isChecked) -> {
if (isChecked) {
useMedia3Muxer.setChecked(true);
useMedia3FragmentedMp4Muxer.setChecked(false);
}
});
useMedia3FragmentedMp4Muxer.setOnCheckedChangeListener(
(buttonView, isChecked) -> {
if (isChecked) {
useMedia3Mp4Muxer.setChecked(false);
}
});
@ -403,8 +408,8 @@ public final class ConfigurationActivity extends AppCompatActivity {
bundle.putBoolean(ENABLE_ANALYZER_MODE, enableAnalyzerModeCheckBox.isChecked());
bundle.putBoolean(ENABLE_DEBUG_PREVIEW, enableDebugPreviewCheckBox.isChecked());
bundle.putBoolean(ABORT_SLOW_EXPORT, abortSlowExportCheckBox.isChecked());
bundle.putBoolean(USE_MEDIA3_MUXER, useMedia3Muxer.isChecked());
bundle.putBoolean(PRODUCE_FRAGMENTED_MP4, produceFragmentedMp4CheckBox.isChecked());
bundle.putBoolean(USE_MEDIA3_MP4_MUXER, useMedia3Mp4Muxer.isChecked());
bundle.putBoolean(USE_MEDIA3_FRAGMENTED_MP4_MUXER, useMedia3FragmentedMp4Muxer.isChecked());
String selectedHdrMode = String.valueOf(hdrModeSpinner.getSelectedItem());
bundle.putInt(HDR_MODE, HDR_MODE_DESCRIPTIONS.get(selectedHdrMode));
bundle.putBooleanArray(AUDIO_EFFECTS_SELECTIONS, audioEffectsSelections);

View File

@ -20,7 +20,8 @@ import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import androidx.media3.common.C;
import androidx.media3.effect.OverlaySettings;
import androidx.media3.common.OverlaySettings;
import androidx.media3.effect.StaticOverlaySettings;
import androidx.media3.effect.TextOverlay;
import androidx.media3.effect.TextureOverlay;
import java.util.Locale;
@ -31,11 +32,11 @@ import java.util.Locale;
*/
/* package */ final class TimerOverlay extends TextOverlay {
private final OverlaySettings overlaySettings;
private final StaticOverlaySettings overlaySettings;
public TimerOverlay() {
overlaySettings =
new OverlaySettings.Builder()
new StaticOverlaySettings.Builder()
// Place the timer in the bottom left corner of the screen with some padding from the
// edges.
.setOverlayFrameAnchor(/* x= */ -1f, /* y= */ -1f)

View File

@ -15,25 +15,33 @@
*/
package androidx.media3.demo.transformer;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.READ_MEDIA_VIDEO;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Util.SDK_INT;
import static androidx.media3.exoplayer.DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS;
import static androidx.media3.exoplayer.DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS;
import static androidx.media3.transformer.Transformer.PROGRESS_STATE_NOT_STARTED;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
@ -45,10 +53,13 @@ import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.media3.common.C;
import androidx.media3.common.DebugViewProvider;
import androidx.media3.common.Effect;
@ -71,13 +82,13 @@ import androidx.media3.effect.GlShaderProgram;
import androidx.media3.effect.HslAdjustment;
import androidx.media3.effect.LanczosResample;
import androidx.media3.effect.OverlayEffect;
import androidx.media3.effect.OverlaySettings;
import androidx.media3.effect.Presentation;
import androidx.media3.effect.RgbAdjustment;
import androidx.media3.effect.RgbFilter;
import androidx.media3.effect.RgbMatrix;
import androidx.media3.effect.ScaleAndRotateTransformation;
import androidx.media3.effect.SingleColorLut;
import androidx.media3.effect.StaticOverlaySettings;
import androidx.media3.effect.TextOverlay;
import androidx.media3.effect.TextureOverlay;
import androidx.media3.exoplayer.DefaultLoadControl;
@ -92,12 +103,16 @@ import androidx.media3.transformer.Effects;
import androidx.media3.transformer.ExperimentalAnalyzerModeFactory;
import androidx.media3.transformer.ExportException;
import androidx.media3.transformer.ExportResult;
import androidx.media3.transformer.InAppMuxer;
import androidx.media3.transformer.InAppFragmentedMp4Muxer;
import androidx.media3.transformer.InAppMp4Muxer;
import androidx.media3.transformer.JsonUtil;
import androidx.media3.transformer.MediaProjectionAssetLoader;
import androidx.media3.transformer.ProgressHolder;
import androidx.media3.transformer.Transformer;
import androidx.media3.transformer.VideoEncoderSettings;
import androidx.media3.ui.AspectRatioFrameLayout;
import androidx.media3.ui.PlayerView;
import androidx.window.layout.WindowMetricsCalculator;
import com.google.android.material.card.MaterialCardView;
import com.google.android.material.progressindicator.LinearProgressIndicator;
import com.google.common.base.Stopwatch;
@ -109,7 +124,6 @@ import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@ -120,12 +134,13 @@ import org.json.JSONObject;
public final class TransformerActivity extends AppCompatActivity {
private static final String TAG = "TransformerActivity";
private static final int IMAGE_DURATION_MS = 5_000;
private static final int IMAGE_FRAME_RATE_FPS = 30;
private static final int DEFAULT_FRAME_RATE_FPS = 30;
private static int LOAD_CONTROL_MIN_BUFFER_MS = 5_000;
private static int LOAD_CONTROL_MAX_BUFFER_MS = 5_000;
private Button displayInputButton;
private MaterialCardView inputCardView;
private MaterialCardView outputCardView;
private TextView inputTextView;
private ImageView inputImageView;
private PlayerView inputPlayerView;
@ -137,10 +152,13 @@ public final class TransformerActivity extends AppCompatActivity {
private LinearProgressIndicator progressIndicator;
private Button pauseButton;
private Button resumeButton;
private Button stopCaptureButton;
private Stopwatch exportStopwatch;
private AspectRatioFrameLayout debugFrame;
@Nullable private DebugTextViewHelper debugTextViewHelper;
@Nullable private Intent screenCaptureToken;
@Nullable private MediaProjection mediaProjection;
@Nullable private ExoPlayer inputPlayer;
@Nullable private ExoPlayer outputPlayer;
@Nullable private Transformer transformer;
@ -153,6 +171,7 @@ public final class TransformerActivity extends AppCompatActivity {
setContentView(R.layout.transformer_activity);
inputCardView = findViewById(R.id.input_card_view);
outputCardView = findViewById(R.id.output_card_view);
inputTextView = findViewById(R.id.input_text_view);
inputImageView = findViewById(R.id.input_image_view);
inputPlayerView = findViewById(R.id.input_player_view);
@ -166,6 +185,8 @@ public final class TransformerActivity extends AppCompatActivity {
pauseButton.setOnClickListener(view -> pauseExport());
resumeButton = findViewById(R.id.resume_button);
resumeButton.setOnClickListener(view -> startExport());
stopCaptureButton = findViewById(R.id.stop_capture_button);
stopCaptureButton.setOnClickListener(view -> mediaProjection.stop());
debugFrame = findViewById(R.id.debug_aspect_ratio_frame_layout);
displayInputButton = findViewById(R.id.display_input_button);
displayInputButton.setOnClickListener(view -> toggleInputVideoDisplay());
@ -184,7 +205,10 @@ public final class TransformerActivity extends AppCompatActivity {
protected void onStart() {
super.onStart();
startExport();
// Restart exporting, unless this is a capture session which can run in the background.
if (!isUsingMediaProjection()) {
startExport();
}
inputPlayerView.onResume();
outputPlayerView.onResume();
@ -194,32 +218,72 @@ public final class TransformerActivity extends AppCompatActivity {
protected void onStop() {
super.onStop();
if (transformer != null) {
transformer.cancel();
transformer = null;
}
// The stop watch is reset after cancelling the export, in case cancelling causes the stop watch
// to be stopped in a transformer callback.
exportStopwatch.reset();
inputPlayerView.onPause();
outputPlayerView.onPause();
releasePlayer();
outputFile.delete();
outputFile = null;
if (oldOutputFile != null) {
oldOutputFile.delete();
oldOutputFile = null;
// Keep the capture session going to allow capturing other apps while backgrounded.
if (!isUsingMediaProjection()) {
releasePlayers();
cleanUpExport();
}
}
private void startExport() {
requestReadVideoPermission(/* activity= */ this);
@Override
protected void onDestroy() {
super.onDestroy();
if (isUsingMediaProjection()) {
releasePlayers();
mediaProjection.stop();
mediaProjection = null;
screenCaptureToken = null;
}
cleanUpExport();
}
private void startExport() {
Intent intent = getIntent();
Uri inputUri = checkNotNull(intent.getData());
if (inputUri.toString().equals("transformer_surface_asset:media_projection")
&& screenCaptureToken == null) {
// MediaProjection can only start once the foreground service is running.
MediaProjectionManager mediaProjectionManager =
(MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
Context context = this;
LocalBroadcastManager.getInstance(context)
.registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = checkNotNull(intent.getAction());
if (action.equals(DemoMediaProjectionService.ACTION_EVENT_STARTED)) {
LocalBroadcastManager.getInstance(context)
.unregisterReceiver(/* receiver= */ this);
// The service has started so media projection can start.
startExport();
}
}
},
new IntentFilter(DemoMediaProjectionService.ACTION_EVENT_STARTED));
registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
activityResult -> {
int resultCode = activityResult.getResultCode();
if (resultCode == RESULT_OK) {
screenCaptureToken = activityResult.getData();
Intent startServiceIntent = new Intent(context, DemoMediaProjectionService.class);
ContextCompat.startForegroundService(context, startServiceIntent);
} else if (resultCode == RESULT_CANCELED) {
finish();
}
})
.launch(mediaProjectionManager.createScreenCaptureIntent());
inputCardView.setVisibility(View.GONE);
outputCardView.setVisibility(View.GONE);
return;
}
try {
outputFile =
createExternalCacheFile("transformer-output-" + Clock.DEFAULT.elapsedRealtime() + ".mp4");
@ -229,6 +293,7 @@ public final class TransformerActivity extends AppCompatActivity {
String outputFilePath = outputFile.getAbsolutePath();
@Nullable Bundle bundle = intent.getExtras();
MediaItem mediaItem = createMediaItem(bundle, inputUri);
Util.maybeRequestReadStoragePermission(/* activity= */ this, mediaItem);
Transformer transformer = createTransformer(bundle, inputUri, outputFilePath);
Composition composition = createComposition(mediaItem, bundle);
exportStopwatch.reset();
@ -245,10 +310,20 @@ public final class TransformerActivity extends AppCompatActivity {
outputVideoTextView.setVisibility(View.GONE);
debugTextView.setVisibility(View.GONE);
informationTextView.setText(R.string.export_started);
outputCardView.setVisibility(View.VISIBLE);
progressViewGroup.setVisibility(View.VISIBLE);
pauseButton.setVisibility(View.VISIBLE);
resumeButton.setVisibility(View.GONE);
progressIndicator.setProgress(0);
if (isUsingMediaProjection()) {
pauseButton.setVisibility(View.GONE);
resumeButton.setVisibility(View.GONE);
stopCaptureButton.setVisibility(View.VISIBLE);
} else {
pauseButton.setVisibility(View.VISIBLE);
resumeButton.setVisibility(View.GONE);
stopCaptureButton.setVisibility(View.GONE);
}
Handler mainHandler = new Handler(getMainLooper());
ProgressHolder progressHolder = new ProgressHolder();
mainHandler.post(
@ -314,21 +389,16 @@ public final class TransformerActivity extends AppCompatActivity {
transformerBuilder.setVideoMimeType(videoMimeType);
}
transformerBuilder.setEncoderFactory(
new DefaultEncoderFactory.Builder(this.getApplicationContext())
.setEnableFallback(bundle.getBoolean(ConfigurationActivity.ENABLE_FALLBACK))
.build());
if (!bundle.getBoolean(ConfigurationActivity.ABORT_SLOW_EXPORT)) {
transformerBuilder.setMaxDelayBetweenMuxerSamplesMs(C.TIME_UNSET);
}
if (bundle.getBoolean(ConfigurationActivity.USE_MEDIA3_MUXER)) {
transformerBuilder.setMuxerFactory(
new InAppMuxer.Factory.Builder()
.setOutputFragmentedMp4(
bundle.getBoolean(ConfigurationActivity.PRODUCE_FRAGMENTED_MP4))
.build());
if (bundle.getBoolean(ConfigurationActivity.USE_MEDIA3_MP4_MUXER)) {
transformerBuilder.setMuxerFactory(new InAppMp4Muxer.Factory());
}
if (bundle.getBoolean(ConfigurationActivity.USE_MEDIA3_FRAGMENTED_MP4_MUXER)) {
transformerBuilder.setMuxerFactory(new InAppFragmentedMp4Muxer.Factory());
}
if (bundle.getBoolean(ConfigurationActivity.ENABLE_DEBUG_PREVIEW)) {
@ -341,6 +411,32 @@ public final class TransformerActivity extends AppCompatActivity {
}
}
VideoEncoderSettings videoEncoderSettings = VideoEncoderSettings.DEFAULT;
if (screenCaptureToken != null) {
MediaProjectionManager mediaProjectionManager =
(MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
MediaProjection mediaProjection =
mediaProjectionManager.getMediaProjection(RESULT_OK, checkNotNull(screenCaptureToken));
Rect bounds =
WindowMetricsCalculator.getOrCreate()
.computeCurrentWindowMetrics(/* activity= */ this)
.getBounds();
int densityDpi = getResources().getConfiguration().densityDpi;
transformerBuilder.setAssetLoaderFactory(
new MediaProjectionAssetLoader.Factory(mediaProjection, bounds, densityDpi));
this.mediaProjection = mediaProjection;
videoEncoderSettings =
videoEncoderSettings
.buildUpon()
.setRepeatPreviousFrameIntervalUs(C.MICROS_PER_SECOND / DEFAULT_FRAME_RATE_FPS)
.build();
}
transformerBuilder.setEncoderFactory(
new DefaultEncoderFactory.Builder(this.getApplicationContext())
.setEnableFallback(bundle.getBoolean(ConfigurationActivity.ENABLE_FALLBACK))
.setRequestedVideoEncoderSettings(videoEncoderSettings)
.build());
return transformerBuilder.build();
}
@ -359,7 +455,7 @@ public final class TransformerActivity extends AppCompatActivity {
private Composition createComposition(MediaItem mediaItem, @Nullable Bundle bundle) {
EditedMediaItem.Builder editedMediaItemBuilder = new EditedMediaItem.Builder(mediaItem);
// For image inputs. Automatically ignored if input is audio/video.
editedMediaItemBuilder.setFrameRate(IMAGE_FRAME_RATE_FPS);
editedMediaItemBuilder.setFrameRate(DEFAULT_FRAME_RATE_FPS);
if (bundle != null) {
ImmutableList<AudioProcessor> audioProcessors = createAudioProcessorsFromBundle(bundle);
ImmutableList<Effect> videoEffects = createVideoEffectsFromBundle(bundle);
@ -394,14 +490,18 @@ public final class TransformerActivity extends AppCompatActivity {
ImmutableList.Builder<AudioProcessor> processors = new ImmutableList.Builder<>();
if (selectedAudioEffects[ConfigurationActivity.HIGH_PITCHED_INDEX]
|| selectedAudioEffects[ConfigurationActivity.SAMPLE_RATE_INDEX]) {
|| selectedAudioEffects[ConfigurationActivity.SAMPLE_RATE_48K_INDEX]
|| selectedAudioEffects[ConfigurationActivity.SAMPLE_RATE_96K_INDEX]) {
SonicAudioProcessor sonicAudioProcessor = new SonicAudioProcessor();
if (selectedAudioEffects[ConfigurationActivity.HIGH_PITCHED_INDEX]) {
sonicAudioProcessor.setPitch(2f);
}
if (selectedAudioEffects[ConfigurationActivity.SAMPLE_RATE_INDEX]) {
if (selectedAudioEffects[ConfigurationActivity.SAMPLE_RATE_48K_INDEX]) {
sonicAudioProcessor.setOutputSampleRateHz(48_000);
}
if (selectedAudioEffects[ConfigurationActivity.SAMPLE_RATE_96K_INDEX]) {
sonicAudioProcessor.setOutputSampleRateHz(96_000);
}
processors.add(sonicAudioProcessor);
}
@ -417,20 +517,9 @@ public final class TransformerActivity extends AppCompatActivity {
if (mixToMono || scaleVolumeToHalf) {
ChannelMixingAudioProcessor mixingAudioProcessor = new ChannelMixingAudioProcessor();
for (int inputChannelCount = 1; inputChannelCount <= 6; inputChannelCount++) {
ChannelMixingMatrix matrix;
if (mixToMono) {
float[] mixingCoefficients = new float[inputChannelCount];
// Each channel is equally weighted in the mix to mono.
Arrays.fill(mixingCoefficients, 1f / inputChannelCount);
matrix =
new ChannelMixingMatrix(
inputChannelCount, /* outputChannelCount= */ 1, mixingCoefficients);
} else {
// Identity matrix.
matrix =
ChannelMixingMatrix.create(
inputChannelCount, /* outputChannelCount= */ inputChannelCount);
}
ChannelMixingMatrix matrix =
ChannelMixingMatrix.createForConstantPower(
inputChannelCount, /* outputChannelCount= */ mixToMono ? 1 : inputChannelCount);
// Apply the volume adjustment.
mixingAudioProcessor.putChannelMixingMatrix(
@ -599,8 +688,8 @@ public final class TransformerActivity extends AppCompatActivity {
private OverlayEffect createOverlayEffectFromBundle(Bundle bundle, boolean[] selectedEffects) {
ImmutableList.Builder<TextureOverlay> overlaysBuilder = new ImmutableList.Builder<>();
if (selectedEffects[ConfigurationActivity.OVERLAY_LOGO_AND_TIMER_INDEX]) {
OverlaySettings logoSettings =
new OverlaySettings.Builder()
StaticOverlaySettings logoSettings =
new StaticOverlaySettings.Builder()
// Place the logo in the bottom left corner of the screen with some padding from the
// edges.
.setOverlayFrameAnchor(/* x= */ -1f, /* y= */ -1f)
@ -619,8 +708,8 @@ public final class TransformerActivity extends AppCompatActivity {
overlaysBuilder.add(logoOverlay, timerOverlay);
}
if (selectedEffects[ConfigurationActivity.BITMAP_OVERLAY_INDEX]) {
OverlaySettings overlaySettings =
new OverlaySettings.Builder()
StaticOverlaySettings overlaySettings =
new StaticOverlaySettings.Builder()
.setAlphaScale(
bundle.getFloat(
ConfigurationActivity.BITMAP_OVERLAY_ALPHA, /* defaultValue= */ 1))
@ -633,8 +722,8 @@ public final class TransformerActivity extends AppCompatActivity {
overlaysBuilder.add(bitmapOverlay);
}
if (selectedEffects[ConfigurationActivity.TEXT_OVERLAY_INDEX]) {
OverlaySettings overlaySettings =
new OverlaySettings.Builder()
StaticOverlaySettings overlaySettings =
new StaticOverlaySettings.Builder()
.setAlphaScale(
bundle.getFloat(ConfigurationActivity.TEXT_OVERLAY_ALPHA, /* defaultValue= */ 1))
.build();
@ -648,6 +737,15 @@ public final class TransformerActivity extends AppCompatActivity {
TextOverlay textOverlay = TextOverlay.createStaticTextOverlay(overlayText, overlaySettings);
overlaysBuilder.add(textOverlay);
}
if (selectedEffects[ConfigurationActivity.CLOCK_OVERLAY_INDEX]) {
overlaysBuilder.add(new ClockOverlay());
}
if (selectedEffects[ConfigurationActivity.CONFETTI_OVERLAY_INDEX]) {
overlaysBuilder.add(new ConfettiOverlay());
}
if (selectedEffects[ConfigurationActivity.ANIMATING_LOGO_OVERLAY]) {
overlaysBuilder.add(new AnimatedLogoOverlay(this.getApplicationContext()));
}
ImmutableList<TextureOverlay> overlays = overlaysBuilder.build();
return overlays.isEmpty() ? null : new OverlayEffect(overlays);
@ -658,6 +756,9 @@ public final class TransformerActivity extends AppCompatActivity {
informationTextView.setText(R.string.export_error);
progressViewGroup.setVisibility(View.GONE);
debugFrame.removeAllViews();
if (isUsingMediaProjection()) {
mediaProjection.stop();
}
Toast.makeText(getApplicationContext(), "Export error: " + exportException, Toast.LENGTH_LONG)
.show();
Log.e(TAG, "Export error", exportException);
@ -701,9 +802,8 @@ public final class TransformerActivity extends AppCompatActivity {
private void playMediaItems(MediaItem inputMediaItem, MediaItem outputMediaItem) {
inputPlayerView.setPlayer(null);
outputPlayerView.setPlayer(null);
releasePlayer();
releasePlayers();
Uri uri = checkNotNull(inputMediaItem.localConfiguration).uri;
ExoPlayer outputPlayer =
new ExoPlayer.Builder(/* context= */ this)
.setLoadControl(
@ -722,6 +822,7 @@ public final class TransformerActivity extends AppCompatActivity {
this.outputPlayer = outputPlayer;
// Only support showing jpg images.
Uri uri = checkNotNull(inputMediaItem.localConfiguration).uri;
if (uri.toString().endsWith("jpg")) {
inputPlayerView.setVisibility(View.GONE);
inputImageView.setVisibility(View.VISIBLE);
@ -735,6 +836,12 @@ public final class TransformerActivity extends AppCompatActivity {
} catch (ExecutionException | InterruptedException e) {
throw new IllegalArgumentException("Failed to load bitmap.", e);
}
} else if (isUsingMediaProjection()) {
inputCardView.setVisibility(View.GONE);
displayInputButton.setVisibility(View.GONE);
Intent stopIntent = new Intent(/* context= */ this, DemoMediaProjectionService.class);
stopIntent.setAction(DemoMediaProjectionService.ACTION_STOP);
ContextCompat.startForegroundService(/* context= */ this, stopIntent);
} else {
inputPlayerView.setVisibility(View.VISIBLE);
inputImageView.setVisibility(View.GONE);
@ -785,7 +892,7 @@ public final class TransformerActivity extends AppCompatActivity {
}
}
private void releasePlayer() {
private void releasePlayers() {
if (debugTextViewHelper != null) {
debugTextViewHelper.stop();
debugTextViewHelper = null;
@ -800,12 +907,22 @@ public final class TransformerActivity extends AppCompatActivity {
}
}
private static void requestReadVideoPermission(AppCompatActivity activity) {
String permission = SDK_INT >= 33 ? READ_MEDIA_VIDEO : READ_EXTERNAL_STORAGE;
if (ActivityCompat.checkSelfPermission(activity, permission)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity, new String[] {permission}, /* requestCode= */ 0);
private void cleanUpExport() {
if (transformer != null) {
transformer.cancel();
transformer = null;
}
if (outputFile != null) {
outputFile.delete();
outputFile = null;
}
if (oldOutputFile != null) {
oldOutputFile.delete();
oldOutputFile = null;
}
// The stop watch is reset after cancelling the export, in case cancelling causes the stop watch
// to be stopped in a transformer callback.
exportStopwatch.reset();
}
private void showToast(@StringRes int messageResource) {
@ -837,6 +954,54 @@ public final class TransformerActivity extends AppCompatActivity {
oldOutputFile = outputFile;
}
private boolean isUsingMediaProjection() {
return mediaProjection != null;
}
/** Foreground service that's required by the media projection APIs. */
public static final class DemoMediaProjectionService extends Service {
private static final String CHANNEL_ID = "DemoMediaProjectionServiceChannel";
private static final String CHANNEL_NAME = "Media projection";
private static final int NOTIFICATION_ID = 1;
private static final String ACTION_EVENT_STARTED = "started";
private static final String ACTION_STOP = "stop";
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (ACTION_STOP.equals(intent.getAction())) {
stopSelf();
} else {
Context context = this;
Notification notification =
new NotificationCompat.Builder(context, CHANNEL_ID)
.setOngoing(true)
.setSmallIcon(R.drawable.exo_icon_play)
.build();
if (Util.SDK_INT >= 26) {
NotificationChannel channel =
new NotificationChannel(
CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel);
}
if (Util.SDK_INT >= 29) {
startForeground(NOTIFICATION_ID, notification, FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION);
} else {
startForeground(NOTIFICATION_ID, notification);
}
// Notify that the service is started (and it's now safe to set up media projection).
LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent(ACTION_EVENT_STARTED));
}
return START_STICKY;
}
}
private final class DemoDebugViewProvider implements DebugViewProvider {
@Nullable private SurfaceView surfaceView;

View File

@ -239,18 +239,18 @@
android:layout_weight="1">
<TextView
android:layout_gravity="center_vertical"
android:text="@string/use_media3_muxer" />
android:text="@string/use_media3_mp4_muxer" />
<CheckBox
android:id="@+id/use_media3_muxer_checkbox"
android:id="@+id/use_media3_mp4_muxer_checkbox"
android:layout_gravity="end"/>
</TableRow>
<TableRow
android:layout_weight="1">
<TextView
android:layout_gravity="center_vertical"
android:text="@string/produce_fragmented_mp4" />
android:text="@string/use_media3_fragmented_mp4_muxer" />
<CheckBox
android:id="@+id/produce_fragmented_mp4_checkbox"
android:id="@+id/use_media3_fragmented_mp4_muxer_checkbox"
android:layout_gravity="end"/>
</TableRow>
<TableRow

View File

@ -165,6 +165,12 @@
android:layout_width="match_parent"
android:text="@string/resume"/>
<Button
android:id="@+id/stop_capture_button"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/stop_capture"/>
<androidx.media3.ui.AspectRatioFrameLayout
android:id="@+id/debug_aspect_ratio_frame_layout"
android:layout_width="match_parent"

View File

@ -28,10 +28,14 @@
<item>Overlay logo and timer</item>
<item>Custom Bitmap Overlay</item>
<item>Custom Text Overlay</item>
<item>Clock Overlay</item>
<item>Confetti Overlay</item>
<item>Animated logo</item>
</string-array>
<string-array name="audio_effects_names">
<item>High pitched</item>
<item>Sample rate of 48000Hz</item>
<item>Sample rate of 96000Hz</item>
<item>Skip silence</item>
<item>Mix channels into mono</item>
<item>Scale volume to 50%</item>
@ -54,6 +58,7 @@
<item>HDR (HDR10+) H265 limited range video (encoding may fail)</item>
<item>HDR (HLG) H265 limited range video (encoding may fail)</item>
<item>720p H264 video with no audio (B-frames)</item>
<item>Record screen</item>
</string-array>
<string-array name="preset_uris">
<item>https://storage.googleapis.com/exoplayer-test-media-1/mp4/android-screens-10s.mp4</item>
@ -73,5 +78,6 @@
<item>https://storage.googleapis.com/exoplayer-test-media-1/mp4/samsung-s21-hdr-hdr10.mp4</item>
<item>https://storage.googleapis.com/exoplayer-test-media-1/mp4/Pixel7Pro_HLG_1080P.mp4</item>
<item>https://storage.googleapis.com/exoplayer-test-media-1/mp4/sample_video_track_only.mp4</item>
<item>transformer_surface_asset:media_projection</item>
</string-array>
</resources>

View File

@ -32,8 +32,8 @@
<string name="enable_debug_preview" translatable="false">Enable debug preview</string>
<string name="enable_debug_tracing" translatable="false">Enable debug tracing</string>
<string name="abort_slow_export" translatable="false">Abort slow export</string>
<string name="use_media3_muxer" translatable="false">Use Media3 muxer</string>
<string name="produce_fragmented_mp4" translatable="false">Produce fragmented MP4</string>
<string name="use_media3_mp4_muxer" translatable="false">Use Media3 Mp4Muxer</string>
<string name="use_media3_fragmented_mp4_muxer" translatable="false">Use Media3 FragmentedMp4Muxer</string>
<string name="trim" translatable="false">Trim</string>
<string name="hdr_mode" translatable="false">HDR mode</string>
<string name="select_audio_effects" translatable="false">Add audio effects</string>
@ -44,6 +44,7 @@
<string name="debug_preview" translatable="false">Debug preview:</string>
<string name="pause" translatable="false">Pause</string>
<string name="resume" translatable="false">Resume</string>
<string name="stop_capture" translatable="false">Stop capture</string>
<string name="debug_preview_not_available" translatable="false">No debug preview available.</string>
<string name="export_started" translatable="false">Export started</string>
<string name="export_timer" translatable="false">Export started %d seconds ago.</string>

View File

@ -24,9 +24,9 @@ android {
}
dependencies {
api 'com.google.android.gms:play-services-cast-framework:21.3.0'
api 'com.google.android.gms:play-services-cast-framework:21.5.0'
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
implementation project(modulePrefix + 'lib-common')
api project(modulePrefix + 'lib-common')
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
compileOnly 'org.jetbrains.kotlin:kotlin-annotations-jvm:' + kotlinAnnotationsVersion
testImplementation project(modulePrefix + 'test-utils')

View File

@ -15,8 +15,8 @@
*/
package androidx.media3.cast;
import static androidx.annotation.VisibleForTesting.PROTECTED;
import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Util.SDK_INT;
import static androidx.media3.common.util.Util.castNonNull;
import static java.lang.Math.min;
@ -74,6 +74,7 @@ import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.Objects;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/**
@ -166,6 +167,7 @@ public final class CastPlayer extends BasePlayer {
private long pendingSeekPositionMs;
@Nullable private PositionInfo pendingMediaItemRemovalPosition;
private MediaMetadata mediaMetadata;
private MediaMetadata playlistMetadata;
private DeviceInfo deviceInfo;
/**
@ -268,6 +270,7 @@ public final class CastPlayer extends BasePlayer {
playbackState = STATE_IDLE;
currentTimeline = CastTimeline.EMPTY_CAST_TIMELINE;
mediaMetadata = MediaMetadata.EMPTY;
playlistMetadata = MediaMetadata.EMPTY;
currentTracks = Tracks.EMPTY;
availableCommands = new Commands.Builder().addAll(PERMANENT_AVAILABLE_COMMANDS).build();
pendingSeekWindowIndex = C.INDEX_UNSET;
@ -467,8 +470,7 @@ public final class CastPlayer extends BasePlayer {
// onPositionDiscontinuity(PositionInfo, PositionInfo, @DiscontinuityReason int).
@SuppressWarnings("deprecation")
@Override
@VisibleForTesting(otherwise = PROTECTED)
public void seekTo(
protected void seekTo(
int mediaItemIndex,
long positionMs,
@Player.Command int seekCommand,
@ -639,7 +641,7 @@ public final class CastPlayer extends BasePlayer {
@Override
public TrackSelectionParameters getTrackSelectionParameters() {
return TrackSelectionParameters.DEFAULT_WITHOUT_CONTEXT;
return TrackSelectionParameters.DEFAULT;
}
@Override
@ -657,14 +659,19 @@ public final class CastPlayer extends BasePlayer {
@Override
public MediaMetadata getPlaylistMetadata() {
// CastPlayer does not currently support metadata.
return MediaMetadata.EMPTY;
return playlistMetadata;
}
/** This method is not supported and does nothing. */
@Override
public void setPlaylistMetadata(MediaMetadata mediaMetadata) {
// CastPlayer does not currently support metadata.
public void setPlaylistMetadata(MediaMetadata playlistMetadata) {
checkNotNull(playlistMetadata);
if (playlistMetadata.equals(this.playlistMetadata)) {
return;
}
this.playlistMetadata = playlistMetadata;
listeners.sendEvent(
EVENT_PLAYLIST_METADATA_CHANGED,
listener -> listener.onPlaylistMetadataChanged(this.playlistMetadata));
}
@Override
@ -911,7 +918,7 @@ public final class CastPlayer extends BasePlayer {
? currentTimeline.getPeriod(currentWindowIndex, period, /* setIds= */ true).uid
: null;
if (!playingPeriodChangedByTimelineChange
&& !Util.areEqual(oldPeriodUid, currentPeriodUid)
&& !Objects.equals(oldPeriodUid, currentPeriodUid)
&& pendingSeekCount == 0) {
// Report discontinuity and media item auto transition.
currentTimeline.getPeriod(oldWindowIndex, period, /* setIds= */ true);

View File

@ -1800,7 +1800,7 @@ public class CastPlayerTest {
}
@Test
public void setMediaItems_doesNotifyOnMetadataChanged() {
public void setMediaItems_doesNotifyOnMediaMetadataChanged() {
when(mockRemoteMediaClient.queueJumpToItem(anyInt(), anyLong(), eq(null)))
.thenReturn(mockPendingResult);
ArgumentCaptor<MediaMetadata> metadataCaptor = ArgumentCaptor.forClass(MediaMetadata.class);
@ -1827,7 +1827,7 @@ public class CastPlayerTest {
.build());
castPlayer.addListener(mockListener);
MediaMetadata intitalMetadata = castPlayer.getMediaMetadata();
MediaMetadata initialMetadata = castPlayer.getMediaMetadata();
castPlayer.setMediaItems(firstPlaylist, /* startIndex= */ 0, /* startPositionMs= */ 2000L);
updateTimeLine(firstPlaylist, /* mediaQueueItemIds= */ new int[] {1}, /* currentItemId= */ 1);
MediaMetadata firstMetadata = castPlayer.getMediaMetadata();
@ -1850,7 +1850,7 @@ public class CastPlayerTest {
secondPlaylist.get(1).mediaMetadata,
secondPlaylist.get(0).mediaMetadata)
.inOrder();
assertThat(intitalMetadata).isEqualTo(MediaMetadata.EMPTY);
assertThat(initialMetadata).isEqualTo(MediaMetadata.EMPTY);
assertThat(ImmutableList.of(firstMetadata, secondMetadata, thirdMetadata))
.containsExactly(
firstPlaylist.get(0).mediaMetadata,
@ -1898,6 +1898,35 @@ public class CastPlayerTest {
verify(mockListener, never()).onMediaMetadataChanged(any());
}
@Test
public void setPlaylistMetadata_doesNotifyOnPlaylistMetadataChanged() {
castPlayer.addListener(mockListener);
MediaMetadata metadata = new MediaMetadata.Builder().setArtist("foo").build();
assertThat(castPlayer.getPlaylistMetadata()).isEqualTo(MediaMetadata.EMPTY);
castPlayer.setPlaylistMetadata(metadata);
assertThat(castPlayer.getPlaylistMetadata()).isEqualTo(metadata);
verify(mockListener).onPlaylistMetadataChanged(metadata);
}
@Test
public void setPlaylistMetadata_equalMetadata_doesNotNotifyOnPlaylistMetadataChanged() {
castPlayer.addListener(mockListener);
MediaMetadata metadata = new MediaMetadata.Builder().setArtist("foo").build();
castPlayer.setPlaylistMetadata(metadata);
castPlayer.setPlaylistMetadata(metadata);
assertThat(castPlayer.getPlaylistMetadata()).isEqualTo(metadata);
verify(mockListener, times(1)).onPlaylistMetadataChanged(metadata);
}
@Test
public void getDeviceInfo_returnsCorrectDeviceInfoWithPlaybackTypeRemote() {
DeviceInfo deviceInfo = castPlayer.getDeviceInfo();

View File

@ -35,12 +35,14 @@ import androidx.annotation.VisibleForTesting;
import androidx.media3.common.util.NullableType;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.errorprone.annotations.InlineMe;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
/**
* Represents ad group times and information on the state and URIs of ads within each ad group.
@ -70,7 +72,7 @@ public final class AdPlaybackState {
/**
* The original number of ads in the ad group in case the ad group is only partially available,
* or {@link C#LENGTH_UNSET} if unknown. An ad can be partially available when a server side
* or {@link C#LENGTH_UNSET} if unknown. An ad can be partially available when a server-side
* inserted ad live stream is joined while an ad is already playing and some ad information is
* missing.
*/
@ -90,6 +92,9 @@ public final class AdPlaybackState {
/** The durations of each ad in the ad group, in microseconds. */
public final long[] durationsUs;
/** The optional IDs of the ads. */
public final @NullableType String[] ids;
/**
* The offset in microseconds which should be added to the content stream when resuming playback
* after the ad group.
@ -99,6 +104,9 @@ public final class AdPlaybackState {
/** Whether this ad group is server-side inserted and part of the content stream. */
public final boolean isServerSideInserted;
/** Whether this is an ignorable placeholder that must not be attempted to be played. */
public final boolean isPlaceholder;
/**
* Creates a new ad group with an unspecified number of ads.
*
@ -114,7 +122,9 @@ public final class AdPlaybackState {
/* mediaItems= */ new MediaItem[0],
/* durationsUs= */ new long[0],
/* contentResumeOffsetUs= */ 0,
/* isServerSideInserted= */ false);
/* isServerSideInserted= */ false,
/* ids= */ new String[0],
/* isPlaceholder= */ false);
}
@SuppressWarnings("deprecation") // Intentionally assigning deprecated field
@ -126,7 +136,9 @@ public final class AdPlaybackState {
@NullableType MediaItem[] mediaItems,
long[] durationsUs,
long contentResumeOffsetUs,
boolean isServerSideInserted) {
boolean isServerSideInserted,
@NullableType String[] ids,
boolean isPlaceholder) {
checkArgument(states.length == mediaItems.length);
this.timeUs = timeUs;
this.count = count;
@ -140,6 +152,8 @@ public final class AdPlaybackState {
for (int i = 0; i < uris.length; i++) {
uris[i] = mediaItems[i] == null ? null : checkNotNull(mediaItems[i].localConfiguration).uri;
}
this.ids = ids;
this.isPlaceholder = isPlaceholder;
}
/**
@ -155,7 +169,7 @@ public final class AdPlaybackState {
* lastPlayedAdIndex}, or {@link #count} if no later ads should be played. If no ads have been
* played, pass -1 to get the index of the first ad to play.
*
* <p>Note: {@linkplain #isServerSideInserted Server side inserted ads} are always considered
* <p>Note: {@linkplain #isServerSideInserted server-side inserted ads} are always considered
* playable.
*/
public int getNextAdIndexToPlay(@IntRange(from = -1) int lastPlayedAdIndex) {
@ -191,8 +205,24 @@ public final class AdPlaybackState {
return false;
}
private boolean isLivePostrollPlaceholder() {
return isServerSideInserted && timeUs == C.TIME_END_OF_SOURCE && count == C.LENGTH_UNSET;
/**
* Returns whether this is a is a placeholder ad group.
*
* @param isServerSideInserted Whether the postroll placeholder must be server-side inserted.
* @return true only if this ad group has a matching {@link #isServerSideInserted} flag.
*/
public boolean isLivePostrollPlaceholder(boolean isServerSideInserted) {
return (this.isServerSideInserted == isServerSideInserted) && isLivePostrollPlaceholder();
}
/**
* Returns whether this is a placeholder ad group. It can be server-side inserted or not. Use
* {@link #isLivePostrollPlaceholder(boolean)} if you want to differentiate.
*
* @return true only if this is a live postroll placeholder.
*/
public boolean isLivePostrollPlaceholder() {
return isPlaceholder && timeUs == C.TIME_END_OF_SOURCE && count == C.LENGTH_UNSET;
}
@Override
@ -211,7 +241,9 @@ public final class AdPlaybackState {
&& Arrays.equals(states, adGroup.states)
&& Arrays.equals(durationsUs, adGroup.durationsUs)
&& contentResumeOffsetUs == adGroup.contentResumeOffsetUs
&& isServerSideInserted == adGroup.isServerSideInserted;
&& isServerSideInserted == adGroup.isServerSideInserted
&& Arrays.equals(ids, adGroup.ids)
&& isPlaceholder == adGroup.isPlaceholder;
}
@Override
@ -224,6 +256,8 @@ public final class AdPlaybackState {
result = 31 * result + Arrays.hashCode(durationsUs);
result = 31 * result + (int) (contentResumeOffsetUs ^ (contentResumeOffsetUs >>> 32));
result = 31 * result + (isServerSideInserted ? 1 : 0);
result = 31 * result + Arrays.hashCode(ids);
result = 31 * result + (isPlaceholder ? 1 : 0);
return result;
}
@ -238,7 +272,9 @@ public final class AdPlaybackState {
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
isServerSideInserted,
ids,
isPlaceholder);
}
/** Returns a new instance with the ad count set to {@code count}. */
@ -247,6 +283,7 @@ public final class AdPlaybackState {
@AdState int[] states = copyStatesWithSpaceForAdCount(this.states, count);
long[] durationsUs = copyDurationsUsWithSpaceForAdCount(this.durationsUs, count);
@NullableType MediaItem[] mediaItems = Arrays.copyOf(this.mediaItems, count);
@NullableType String[] ids = Arrays.copyOf(this.ids, count);
return new AdGroup(
timeUs,
count,
@ -255,7 +292,9 @@ public final class AdPlaybackState {
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
isServerSideInserted,
ids,
isPlaceholder);
}
/**
@ -281,6 +320,9 @@ public final class AdPlaybackState {
@NullableType MediaItem[] mediaItems = Arrays.copyOf(this.mediaItems, states.length);
mediaItems[index] = mediaItem;
states[index] = AD_STATE_AVAILABLE;
@NullableType
String[] ids =
this.ids.length == states.length ? this.ids : Arrays.copyOf(this.ids, states.length);
return new AdGroup(
timeUs,
count,
@ -289,7 +331,9 @@ public final class AdPlaybackState {
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
isServerSideInserted,
ids,
isPlaceholder);
}
/**
@ -317,6 +361,9 @@ public final class AdPlaybackState {
this.mediaItems.length == states.length
? this.mediaItems
: Arrays.copyOf(this.mediaItems, states.length);
@NullableType
String[] ids =
this.ids.length == states.length ? this.ids : Arrays.copyOf(this.ids, states.length);
states[index] = state;
return new AdGroup(
timeUs,
@ -326,7 +373,9 @@ public final class AdPlaybackState {
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
isServerSideInserted,
ids,
isPlaceholder);
}
/** Returns a new instance with the specified ad durations, in microseconds. */
@ -345,7 +394,39 @@ public final class AdPlaybackState {
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
isServerSideInserted,
ids,
isPlaceholder);
}
/** Returns a new instance with the specified ID for the given ad index. */
@CheckResult
public AdGroup withAdId(String adId, @IntRange(from = 0) int index) {
@AdState int[] states = copyStatesWithSpaceForAdCount(this.states, index + 1);
long[] durationsUs =
this.durationsUs.length == states.length
? this.durationsUs
: copyDurationsUsWithSpaceForAdCount(this.durationsUs, states.length);
@NullableType
MediaItem[] mediaItems =
this.mediaItems.length == states.length
? this.mediaItems
: Arrays.copyOf(this.mediaItems, states.length);
@NullableType
String[] ids =
this.ids.length == states.length ? this.ids : Arrays.copyOf(this.ids, states.length);
ids[index] = adId;
return new AdGroup(
timeUs,
count,
originalCount,
states,
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted,
ids,
isPlaceholder);
}
/** Returns an instance with the specified {@link #contentResumeOffsetUs}. */
@ -359,7 +440,9 @@ public final class AdPlaybackState {
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
isServerSideInserted,
ids,
isPlaceholder);
}
/** Returns an instance with the specified value for {@link #isServerSideInserted}. */
@ -373,7 +456,9 @@ public final class AdPlaybackState {
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
isServerSideInserted,
ids,
isPlaceholder);
}
/** Returns an instance with the specified value for {@link #originalCount}. */
@ -386,7 +471,9 @@ public final class AdPlaybackState {
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
isServerSideInserted,
ids,
isPlaceholder);
}
/** Removes the last ad from the ad group. */
@ -398,6 +485,7 @@ public final class AdPlaybackState {
if (durationsUs.length > newCount) {
newDurationsUs = Arrays.copyOf(durationsUs, newCount);
}
@NullableType String[] newIds = Arrays.copyOf(ids, newCount);
return new AdGroup(
timeUs,
newCount,
@ -406,7 +494,9 @@ public final class AdPlaybackState {
newMediaItems,
newDurationsUs,
/* contentResumeOffsetUs= */ Util.sum(newDurationsUs),
isServerSideInserted);
isServerSideInserted,
newIds,
isPlaceholder);
}
/**
@ -424,7 +514,9 @@ public final class AdPlaybackState {
/* mediaItems= */ new MediaItem[0],
/* durationsUs= */ new long[0],
contentResumeOffsetUs,
isServerSideInserted);
isServerSideInserted,
ids,
isPlaceholder);
}
int count = this.states.length;
@AdState int[] states = Arrays.copyOf(this.states, count);
@ -441,7 +533,9 @@ public final class AdPlaybackState {
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
isServerSideInserted,
ids,
isPlaceholder);
}
/**
@ -470,7 +564,36 @@ public final class AdPlaybackState {
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
isServerSideInserted,
ids,
isPlaceholder);
}
private AdGroup withIsPlaceholder(boolean isPlaceholder, boolean isServerSideInserted) {
return new AdGroup(
timeUs,
count,
originalCount,
states,
mediaItems,
durationsUs,
contentResumeOffsetUs,
isServerSideInserted,
ids,
isPlaceholder);
}
/**
* Returns the index of the ad with the given ad ID, or {@link C#INDEX_UNSET} if the ad ID can't
* be found.
*/
public int getIndexOfAdId(String adId) {
for (int i = 0; i < ids.length; i++) {
if (Objects.equals(ids[i], adId)) {
return i;
}
}
return C.INDEX_UNSET;
}
@CheckResult
@ -500,6 +623,8 @@ public final class AdPlaybackState {
private static final String FIELD_IS_SERVER_SIDE_INSERTED = Util.intToStringMaxRadix(6);
private static final String FIELD_ORIGINAL_COUNT = Util.intToStringMaxRadix(7);
@VisibleForTesting static final String FIELD_MEDIA_ITEMS = Util.intToStringMaxRadix(8);
static final String FIELD_IDS = Util.intToStringMaxRadix(9);
static final String FIELD_IS_PLACEHOLDER = Util.intToStringMaxRadix(10);
// Intentionally assigning deprecated field.
// putParcelableArrayList actually supports null elements.
@ -516,6 +641,8 @@ public final class AdPlaybackState {
bundle.putLongArray(FIELD_DURATIONS_US, durationsUs);
bundle.putLong(FIELD_CONTENT_RESUME_OFFSET_US, contentResumeOffsetUs);
bundle.putBoolean(FIELD_IS_SERVER_SIDE_INSERTED, isServerSideInserted);
bundle.putStringArrayList(FIELD_IDS, new ArrayList<>(Arrays.asList(ids)));
bundle.putBoolean(FIELD_IS_PLACEHOLDER, isPlaceholder);
return bundle;
}
@ -536,6 +663,8 @@ public final class AdPlaybackState {
@Nullable long[] durationsUs = bundle.getLongArray(FIELD_DURATIONS_US);
long contentResumeOffsetUs = bundle.getLong(FIELD_CONTENT_RESUME_OFFSET_US);
boolean isServerSideInserted = bundle.getBoolean(FIELD_IS_SERVER_SIDE_INSERTED);
@Nullable ArrayList<String> ids = bundle.getStringArrayList(FIELD_IDS);
boolean isPlaceholder = bundle.getBoolean(FIELD_IS_PLACEHOLDER);
return new AdGroup(
timeUs,
count,
@ -544,7 +673,9 @@ public final class AdPlaybackState {
getMediaItemsFromBundleArrays(mediaItemBundleList, uriList),
durationsUs == null ? new long[0] : durationsUs,
contentResumeOffsetUs,
isServerSideInserted);
isServerSideInserted,
ids == null ? new String[0] : ids.toArray(new String[0]),
isPlaceholder);
}
private ArrayList<@NullableType Bundle> getMediaItemsArrayBundles() {
@ -844,14 +975,21 @@ public final class AdPlaybackState {
adsId, adGroups, adResumePositionUs, contentDurationUs, removedAdGroupCount);
}
/** Returns an instance with the specified value for {@link #adsId}. */
@CheckResult
public AdPlaybackState withAdsId(Object adsId) {
return new AdPlaybackState(
adsId, adGroups, adResumePositionUs, contentDurationUs, removedAdGroupCount);
}
/**
* Returns an instance with the specified ad marked as {@linkplain #AD_STATE_AVAILABLE available}.
*
* <p>Must not be called with client side inserted ad groups. Client side inserted ads should use
* <p>Must not be called with client-side inserted ad groups. Client-side inserted ads should use
* {@link #withAvailableAdMediaItem}.
*
* @throws IllegalStateException in case this methods is called on an ad group that {@linkplain
* AdGroup#isServerSideInserted is not server side inserted}.
* AdGroup#isServerSideInserted is not server-side inserted}.
*/
@CheckResult
public AdPlaybackState withAvailableAd(
@ -907,6 +1045,17 @@ public final class AdPlaybackState {
adsId, adGroups, adResumePositionUs, contentDurationUs, removedAdGroupCount);
}
/** Returns an instance with the specified ad ID for the given ad. */
@CheckResult
public AdPlaybackState withAdId(
@IntRange(from = 0) int adGroupIndex, @IntRange(from = 0) int adIndexInAdGroup, String adId) {
int adjustedIndex = adGroupIndex - removedAdGroupCount;
AdGroup[] adGroups = Util.nullSafeArrayCopy(this.adGroups, this.adGroups.length);
adGroups[adjustedIndex] = adGroups[adjustedIndex].withAdId(adId, adIndexInAdGroup);
return new AdPlaybackState(
adsId, adGroups, adResumePositionUs, contentDurationUs, removedAdGroupCount);
}
/**
* Returns an instance with all ads in the specified ad group skipped (except for those already
* marked as played or in the error state).
@ -923,14 +1072,23 @@ public final class AdPlaybackState {
/**
* Returns an instance with the specified ad durations, in microseconds.
*
* <p>Must only be used if {@link #removedAdGroupCount} is 0.
* <p>The number of arrays of durations ({@code adDurations.length}) must always be equal to
* {@link #adGroupCount}. This is required even on an instance created with {@link
* #withRemovedAdGroupCount(int)}. The array of durations at the index of a removed ad group can
* be null or empty.
*
* @throws IllegalArgumentException if {@code adDurations.length != adGroupCount}.
*/
@CheckResult
public AdPlaybackState withAdDurationsUs(long[][] adDurationUs) {
checkState(removedAdGroupCount == 0);
checkArgument(adDurationUs.length == adGroupCount);
AdGroup[] adGroups = Util.nullSafeArrayCopy(this.adGroups, this.adGroups.length);
for (int adGroupIndex = 0; adGroupIndex < adGroupCount; adGroupIndex++) {
adGroups[adGroupIndex] = adGroups[adGroupIndex].withAdDurationsUs(adDurationUs[adGroupIndex]);
for (int correctedAdGroupIndex = 0;
correctedAdGroupIndex < adGroupCount - removedAdGroupCount;
correctedAdGroupIndex++) {
adGroups[correctedAdGroupIndex] =
adGroups[correctedAdGroupIndex].withAdDurationsUs(
adDurationUs[removedAdGroupCount + correctedAdGroupIndex]);
}
return new AdPlaybackState(
adsId, adGroups, adResumePositionUs, contentDurationUs, removedAdGroupCount);
@ -1066,25 +1224,56 @@ public final class AdPlaybackState {
adsId, adGroups, adResumePositionUs, contentDurationUs, removedAdGroupCount);
}
/**
* @deprecated Use {@link #withLivePostrollPlaceholderAppended(boolean)} and pass {@code true}
* instead.
*/
@InlineMe(replacement = "this.withLivePostrollPlaceholderAppended(true)")
@Deprecated
public AdPlaybackState withLivePostrollPlaceholderAppended() {
return withLivePostrollPlaceholderAppended(/* isServerSideInserted= */ true);
}
/**
* Appends a live postroll placeholder ad group to the ad playback state.
*
* <p>Adding such a placeholder is only required for periods of server side ad insertion live
* streams. A player is not expected to play this placeholder. It is only used to indicate that
* another ad group with this ad group index will be inserted in the future.
* <p>Adding such a placeholder is only required for periods of live streams. A player is not
* expected to play this placeholder. It is only used to indicate that another ad group with this
* ad group index will be inserted in the future.
*
* <p>See {@link #endsWithLivePostrollPlaceHolder()} also.
* <p>See {@link #endsWithLivePostrollPlaceHolder()} and {@link
* #endsWithLivePostrollPlaceHolder(boolean)} also.
*
* @param isServerSideInserted Whether this is a server-side inserted ad (single stream).
* @return The new ad playback state instance ending with a live postroll placeholder.
*/
public AdPlaybackState withLivePostrollPlaceholderAppended() {
public AdPlaybackState withLivePostrollPlaceholderAppended(boolean isServerSideInserted) {
return withNewAdGroup(adGroupCount, /* adGroupTimeUs= */ C.TIME_END_OF_SOURCE)
.withIsServerSideInserted(adGroupCount, true);
.withIsPlaceholder(adGroupCount, /* isPlaceholder= */ true, isServerSideInserted);
}
@VisibleForTesting
/* package */ AdPlaybackState withIsPlaceholder(
int adGroupIndex, boolean isPlaceholder, boolean isServerSideInserted) {
int adjustedIndex = adGroupIndex - removedAdGroupCount;
if (adGroups[adjustedIndex].isPlaceholder == isPlaceholder
&& adGroups[adjustedIndex].isServerSideInserted == isServerSideInserted) {
return this;
}
AdGroup[] adGroups = Util.nullSafeArrayCopy(this.adGroups, this.adGroups.length);
adGroups[adjustedIndex] =
adGroups[adjustedIndex].withIsPlaceholder(isPlaceholder, isServerSideInserted);
return new AdPlaybackState(
adsId, adGroups, adResumePositionUs, contentDurationUs, removedAdGroupCount);
}
/**
* Returns whether the last ad group is a live postroll placeholder as inserted by {@link
* #withLivePostrollPlaceholderAppended()}.
* #withLivePostrollPlaceholderAppended(boolean)}.
*
* <p>Note: That either server-side or client-side inserted placeholders are considered. Use
* {@link #endsWithLivePostrollPlaceHolder(boolean)} if you want to test for one or the other
* only.
*
* @return Whether the ad playback state ends with a live postroll placeholder.
*/
@ -1094,7 +1283,22 @@ public final class AdPlaybackState {
}
/**
* Whether the {@link AdGroup} at the given ad group index is a live postroll placeholder.
* Returns whether the last ad group is a live postroll placeholder as inserted by {@link
* #withLivePostrollPlaceholderAppended(boolean)} .
*
* @param isServerSideInserted Whether the trailing placeholder is server-side inserted.
* @return Whether the ad playback state ends with a live postroll placeholder.
*/
public boolean endsWithLivePostrollPlaceHolder(boolean isServerSideInserted) {
int adGroupIndex = adGroupCount - 1;
return adGroupIndex >= 0 && isLivePostrollPlaceholder(adGroupIndex, isServerSideInserted);
}
/**
* Returns whether the {@link AdGroup} at the given ad group index is a live postroll placeholder.
*
* <p>Note: That either server-side or client-side inserted placeholders return true. Use {@link
* #isLivePostrollPlaceholder(int, boolean)} if you want to test for one or the other only.
*
* @param adGroupIndex The ad group index.
* @return True if the ad group at the given index is a live postroll placeholder, false if not.
@ -1103,6 +1307,31 @@ public final class AdPlaybackState {
return adGroupIndex == adGroupCount - 1 && getAdGroup(adGroupIndex).isLivePostrollPlaceholder();
}
/**
* Returns whether the {@link AdGroup} at the given ad group index is a live postroll placeholder
* and either server or client-side inserted.
*
* @param adGroupIndex The ad group index.
* @param isServerSideInserted Whether the placeholder is server-side inserted.
* @return True if the ad group at the given index is a live postroll placeholder, false if not.
*/
public boolean isLivePostrollPlaceholder(int adGroupIndex, boolean isServerSideInserted) {
return adGroupIndex == adGroupCount - 1
&& getAdGroup(adGroupIndex).isLivePostrollPlaceholder(isServerSideInserted);
}
/**
* Returns the index of the ad with the given ad ID in the given ad group, or {@link
* C#INDEX_UNSET} if the ad ID can't be found.
*
* @param adGroupIndex The ad group index.
* @param adId The ad ID.
* @return The ad index in the ad group, or {@link C#INDEX_UNSET} if the ad ID is not found.
*/
public int getAdIndexOfAdId(int adGroupIndex, String adId) {
return getAdGroup(adGroupIndex).getIndexOfAdId(adId);
}
/**
* Returns a copy of the ad playback state with the given ads ID.
*
@ -1124,7 +1353,9 @@ public final class AdPlaybackState {
Arrays.copyOf(adGroup.mediaItems, adGroup.mediaItems.length),
Arrays.copyOf(adGroup.durationsUs, adGroup.durationsUs.length),
adGroup.contentResumeOffsetUs,
adGroup.isServerSideInserted);
adGroup.isServerSideInserted,
adGroup.ids,
adGroup.isPlaceholder);
}
return new AdPlaybackState(
adsId,
@ -1143,7 +1374,7 @@ public final class AdPlaybackState {
return false;
}
AdPlaybackState that = (AdPlaybackState) o;
return Util.areEqual(adsId, that.adsId)
return Objects.equals(adsId, that.adsId)
&& adGroupCount == that.adGroupCount
&& adResumePositionUs == that.adResumePositionUs
&& contentDurationUs == that.contentDurationUs
@ -1226,7 +1457,7 @@ public final class AdPlaybackState {
// placeholder in a period of a multi-period live window, or when c) the position actually is
// before the given period duration.
return periodDurationUs == C.TIME_UNSET
|| (adGroup.isServerSideInserted && adGroup.count == C.LENGTH_UNSET)
|| adGroup.isLivePostrollPlaceholder()
|| positionUs < periodDurationUs;
}
return positionUs < adGroupPositionUs;

View File

@ -170,6 +170,43 @@ public final class AudioAttributes {
return audioAttributesV21;
}
/** Returns the {@link C.StreamType} corresponding to these audio attributes. */
@UnstableApi
public @C.StreamType int getStreamType() {
// Flags to stream type mapping
if ((flags & C.FLAG_AUDIBILITY_ENFORCED) == C.FLAG_AUDIBILITY_ENFORCED) {
return C.STREAM_TYPE_SYSTEM;
}
// Usage to stream type mapping
switch (usage) {
case C.USAGE_ASSISTANCE_SONIFICATION:
return C.STREAM_TYPE_SYSTEM;
case C.USAGE_VOICE_COMMUNICATION:
return C.STREAM_TYPE_VOICE_CALL;
case C.USAGE_VOICE_COMMUNICATION_SIGNALLING:
return C.STREAM_TYPE_DTMF;
case C.USAGE_ALARM:
return C.STREAM_TYPE_ALARM;
case C.USAGE_NOTIFICATION_RINGTONE:
return C.STREAM_TYPE_RING;
case C.USAGE_NOTIFICATION:
case C.USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
case C.USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
case C.USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
case C.USAGE_NOTIFICATION_EVENT:
return C.STREAM_TYPE_NOTIFICATION;
case C.USAGE_ASSISTANCE_ACCESSIBILITY:
return C.STREAM_TYPE_ACCESSIBILITY;
case C.USAGE_MEDIA:
case C.USAGE_GAME:
case C.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
case C.USAGE_ASSISTANT:
case C.USAGE_UNKNOWN:
default:
return C.STREAM_TYPE_MUSIC;
}
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {

View File

@ -15,15 +15,14 @@
*/
package androidx.media3.common;
import static androidx.annotation.VisibleForTesting.PROTECTED;
import static java.lang.Math.max;
import static java.lang.Math.min;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.ForOverride;
import java.util.List;
/** Abstract base {@link Player} which implements common implementation independent methods. */
@ -276,8 +275,8 @@ public abstract class BasePlayer implements Player {
* @param seekCommand The {@link Player.Command} used to trigger the seek.
* @param isRepeatingCurrentItem Whether this seeks repeats the current item.
*/
@VisibleForTesting(otherwise = PROTECTED)
public abstract void seekTo(
@ForOverride
protected abstract void seekTo(
int mediaItemIndex,
long positionMs,
@Player.Command int seekCommand,

View File

@ -29,7 +29,6 @@ import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableList;
import java.util.List;
// LINT.IfChange(javadoc)
/**
* A {@link Binder} to transfer a list of {@link Bundle Bundles} across processes by splitting the
* list into multiple transactions.

View File

@ -30,6 +30,7 @@ import android.media.MediaCodec;
import android.media.MediaCrypto;
import android.media.MediaFormat;
import android.net.Uri;
import android.opengl.GLES20;
import android.view.Surface;
import androidx.annotation.IntDef;
import androidx.media3.common.util.UnstableApi;
@ -327,8 +328,8 @@ public final class C {
/**
* Stream types for an {@link android.media.AudioTrack}. One of {@link #STREAM_TYPE_ALARM}, {@link
* #STREAM_TYPE_DTMF}, {@link #STREAM_TYPE_MUSIC}, {@link #STREAM_TYPE_NOTIFICATION}, {@link
* #STREAM_TYPE_RING}, {@link #STREAM_TYPE_SYSTEM}, {@link #STREAM_TYPE_VOICE_CALL} or {@link
* #STREAM_TYPE_DEFAULT}.
* #STREAM_TYPE_RING}, {@link #STREAM_TYPE_SYSTEM}, {@link #STREAM_TYPE_VOICE_CALL}, {@link
* #STREAM_TYPE_ACCESSIBILITY} or {@link #STREAM_TYPE_DEFAULT}.
*/
// @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
// with Kotlin usages from before TYPE_USE was added.
@ -345,6 +346,7 @@ public final class C {
STREAM_TYPE_RING,
STREAM_TYPE_SYSTEM,
STREAM_TYPE_VOICE_CALL,
STREAM_TYPE_ACCESSIBILITY,
STREAM_TYPE_DEFAULT
})
public @interface StreamType {}
@ -370,6 +372,10 @@ public final class C {
/** See {@link AudioManager#STREAM_VOICE_CALL}. */
@UnstableApi public static final int STREAM_TYPE_VOICE_CALL = AudioManager.STREAM_VOICE_CALL;
/** See {@link AudioManager#STREAM_ACCESSIBILITY}. */
@UnstableApi
public static final int STREAM_TYPE_ACCESSIBILITY = AudioManager.STREAM_ACCESSIBILITY;
/** The default stream type used by audio renderers. Equal to {@link #STREAM_TYPE_MUSIC}. */
@UnstableApi public static final int STREAM_TYPE_DEFAULT = STREAM_TYPE_MUSIC;
@ -611,6 +617,28 @@ public final class C {
/** See {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}. */
public static final int ALLOW_CAPTURE_BY_SYSTEM = AudioAttributes.ALLOW_CAPTURE_BY_SYSTEM;
/**
* Flags which represent a set of video codecs.
*
* <p>Possible flag values are:
*
* <ul>
* <li>{@link #VIDEO_CODEC_FLAG_H264}
* <li>{@link #VIDEO_CODEC_FLAG_H265}
* </ul>
*/
@UnstableApi
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef(
flag = true,
value = {VIDEO_CODEC_FLAG_H264, VIDEO_CODEC_FLAG_H265})
public @interface VideoCodecFlags {}
@UnstableApi public static final int VIDEO_CODEC_FLAG_H264 = 1;
@UnstableApi public static final int VIDEO_CODEC_FLAG_H265 = 2;
/**
* Flags which can apply to a buffer containing a media sample.
*
@ -670,6 +698,7 @@ public final class C {
/** A non-realtime (as fast as possible) {@linkplain MediaFormat#KEY_PRIORITY codec priority}. */
@UnstableApi public static final int MEDIA_CODEC_PRIORITY_NON_REALTIME = 1;
// LINT.IfChange
/**
* Video decoder output modes. Possible modes are {@link #VIDEO_OUTPUT_MODE_NONE}, {@link
* #VIDEO_OUTPUT_MODE_YUV} and {@link #VIDEO_OUTPUT_MODE_SURFACE_YUV}.
@ -690,6 +719,11 @@ public final class C {
/** Video decoder output mode that renders 4:2:0 YUV planes directly to a surface. */
@UnstableApi public static final int VIDEO_OUTPUT_MODE_SURFACE_YUV = 1;
// LINT.ThenChange(
// ../../../../../../../decoder_av1/src/main/jni/gav1_jni.cc,
// ../../../../../../../decoder_vp9/src/main/jni/vpx_jni.cc
// )
/**
* Video scaling modes for {@link MediaCodec}-based renderers. One of {@link
* #VIDEO_SCALING_MODE_SCALE_TO_FIT}, {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING} or
@ -781,6 +815,8 @@ public final class C {
*/
public static final int SELECTION_FLAG_AUTOSELECT = 1 << 2; // 4
// LINT.ThenChange("util/Util.java:selection_flags")
/** Represents an undetermined language as an ISO 639-2 language code. */
public static final String LANGUAGE_UNDETERMINED = "und";
@ -1162,6 +1198,11 @@ public final class C {
/** See {@link MediaFormat#COLOR_STANDARD_BT2020}. */
@UnstableApi public static final int COLOR_SPACE_BT2020 = MediaFormat.COLOR_STANDARD_BT2020;
// LINT.ThenChange(
// util/MediaFormatUtil.java:color_space,
// ColorInfo.java:color_space,
// )
// LINT.IfChange(color_transfer)
/**
* Video/image color transfer characteristics. One of {@link Format#NO_VALUE}, {@link
@ -1209,6 +1250,14 @@ public final class C {
/** See {@link MediaFormat#COLOR_TRANSFER_HLG}. */
@UnstableApi public static final int COLOR_TRANSFER_HLG = MediaFormat.COLOR_TRANSFER_HLG;
// LINT.ThenChange(
// util/MediaFormatUtil.java:color_transfer,
// ColorInfo.java:color_transfer,
// ../../../../../../../effect/src/main/assets/shaders/fragment_shader_transformation_sdr_external_es2.glsl:color_transfer,
// ../../../../../../../effect/src/main/assets/shaders/fragment_shader_transformation_external_yuv_es3.glsl:color_transfer,
// ../../../../../../../effect/src/main/assets/shaders/fragment_shader_oetf_es3.glsl:color_transfer,
// )
// LINT.IfChange(color_range)
/**
* Video color range. One of {@link Format#NO_VALUE}, {@link #COLOR_RANGE_LIMITED} or {@link
@ -1227,6 +1276,11 @@ public final class C {
/** See {@link MediaFormat#COLOR_RANGE_FULL}. */
@UnstableApi public static final int COLOR_RANGE_FULL = MediaFormat.COLOR_RANGE_FULL;
// LINT.ThenChange(
// util/MediaFormatUtil.java:color_range,
// ColorInfo.java:color_range,
// )
/** Video projection types. */
@UnstableApi
@Documented
@ -1520,6 +1574,8 @@ public final class C {
*/
public static final int ROLE_FLAG_AUXILIARY = 1 << 15;
// LINT.ThenChange("util/Util.java:role_flags")
/**
* {@linkplain #ROLE_FLAG_AUXILIARY Auxiliary track types}. One of {@link
* #AUXILIARY_TRACK_TYPE_UNDEFINED}, {@link #AUXILIARY_TRACK_TYPE_ORIGINAL}, {@link
@ -1565,6 +1621,8 @@ public final class C {
/** A timed metadata of depth video track. */
@UnstableApi public static final int AUXILIARY_TRACK_TYPE_DEPTH_METADATA = 4;
// LINT.ThenChange("util/Util.java:auxiliary_track_type")
/**
* Level of support for a format. One of {@link #FORMAT_HANDLED}, {@link
* #FORMAT_EXCEEDS_CAPABILITIES}, {@link #FORMAT_UNSUPPORTED_DRM}, {@link
@ -1666,6 +1724,40 @@ public final class C {
/** The first frame was rendered. */
@UnstableApi public static final int FIRST_FRAME_RENDERED = 3;
/**
* Texture filtering algorithm for minification.
*
* <p>Possible values are:
*
* <ul>
* <li>{@link #TEXTURE_MIN_FILTER_LINEAR}
* <li>{@link #TEXTURE_MIN_FILTER_LINEAR_MIPMAP_LINEAR}
* </ul>
*
* <p>The algorithms are ordered by increasing visual quality and computational cost.
*/
@UnstableApi
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({TEXTURE_MIN_FILTER_LINEAR, TEXTURE_MIN_FILTER_LINEAR_MIPMAP_LINEAR})
public @interface TextureMinFilter {}
/**
* Returns the weighted average of the four texture elements that are closest to the specified
* texture coordinates.
*/
@UnstableApi public static final int TEXTURE_MIN_FILTER_LINEAR = GLES20.GL_LINEAR;
/**
* Chooses the two mipmaps that most closely match the size of the pixel being textured and uses
* the {@link C#TEXTURE_MIN_FILTER_LINEAR} criterion (a weighted average of the texture elements
* that are closest to the specified texture coordinates) to produce a texture value from each
* mipmap. The final texture value is a weighted average of those two values.
*/
@UnstableApi
public static final int TEXTURE_MIN_FILTER_LINEAR_MIPMAP_LINEAR = GLES20.GL_LINEAR_MIPMAP_LINEAR;
/**
* @deprecated Use {@link Util#usToMs(long)}.
*/

View File

@ -203,7 +203,7 @@ public final class ColorInfo {
/**
* Returns the {@link C.ColorSpace} corresponding to the given ISO color primary code, as per
* table A.7.21.1 in Rec. ITU-T T.832 (03/2009), or {@link Format#NO_VALUE} if no mapping can be
* table A.7.21.1 in Rec. ITU-T T.832 (06/2019), or {@link Format#NO_VALUE} if no mapping can be
* made.
*/
@Pure
@ -219,13 +219,52 @@ public final class ColorInfo {
case 9:
return C.COLOR_SPACE_BT2020;
default:
// Remaining color primaries are either reserved or unspecified.
return Format.NO_VALUE;
}
}
/**
* Returns the ISO color primary code corresponding to the given {@link C.ColorSpace}, as per
* table A.7.21.1 in Rec. ITU-T T.832 (06/2019). made.
*/
public static int colorSpaceToIsoColorPrimaries(@C.ColorSpace int colorSpace) {
switch (colorSpace) {
// Default to BT.709 SDR as per the <a
// href="https://www.webmproject.org/vp9/mp4/#optional-fields">recommendation</a>.
case Format.NO_VALUE:
case C.COLOR_SPACE_BT709:
return 1;
case C.COLOR_SPACE_BT601:
return 5;
case C.COLOR_SPACE_BT2020:
return 9;
}
return 1;
}
/**
* Returns the ISO matrix coefficients code corresponding to the given {@link C.ColorSpace}, as
* per table A.7.21.3 in Rec. ITU-T T.832 (06/2019).
*/
public static int colorSpaceToIsoMatrixCoefficients(@C.ColorSpace int colorSpace) {
switch (colorSpace) {
// Default to BT.709 SDR as per the <a
// href="https://www.webmproject.org/vp9/mp4/#optional-fields">recommendation</a>.
case Format.NO_VALUE:
case C.COLOR_SPACE_BT709:
return 1;
case C.COLOR_SPACE_BT601:
return 6;
case C.COLOR_SPACE_BT2020:
return 9;
}
return 1;
}
/**
* Returns the {@link C.ColorTransfer} corresponding to the given ISO transfer characteristics
* code, as per table A.7.21.2 in Rec. ITU-T T.832 (03/2009), or {@link Format#NO_VALUE} if no
* code, as per table A.7.21.2 in Rec. ITU-T T.832 (06/2019), or {@link Format#NO_VALUE} if no
* mapping can be made.
*/
@Pure
@ -249,6 +288,31 @@ public final class ColorInfo {
}
}
/**
* Returns the ISO transfer characteristics code corresponding to the given {@link
* C.ColorTransfer}, as per table A.7.21.2 in Rec. ITU-T T.832 (06/2019).
*/
public static int colorTransferToIsoTransferCharacteristics(@C.ColorTransfer int colorTransfer) {
switch (colorTransfer) {
// Default to BT.709 SDR as per the <a
// href="https://www.webmproject.org/vp9/mp4/#optional-fields">recommendation</a>.
case C.COLOR_TRANSFER_LINEAR:
return 8;
case C.COLOR_TRANSFER_SRGB:
return 13;
case Format.NO_VALUE:
case C.COLOR_TRANSFER_SDR:
return 1;
case C.COLOR_TRANSFER_ST2084:
return 16;
case C.COLOR_TRANSFER_HLG:
return 18;
case C.COLOR_TRANSFER_GAMMA_2_2:
return 4;
}
return 1;
}
/**
* Returns whether the {@code ColorInfo} uses an HDR {@link C.ColorTransfer}.
*
@ -423,6 +487,7 @@ public final class ColorInfo {
default:
return "Undefined color space " + colorSpace;
}
// LINT.ThenChange(C.java:color_space)
}
private static String colorTransferToString(@C.ColorTransfer int colorTransfer) {
@ -445,6 +510,7 @@ public final class ColorInfo {
default:
return "Undefined color transfer " + colorTransfer;
}
// LINT.ThenChange(C.java:color_transfer)
}
private static String colorRangeToString(@C.ColorRange int colorRange) {
@ -459,6 +525,7 @@ public final class ColorInfo {
default:
return "Undefined color range " + colorRange;
}
// LINT.ThenChange(C.java:color_range)
}
private static final String FIELD_COLOR_SPACE = Util.intToStringMaxRadix(0);

View File

@ -30,6 +30,7 @@ import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Objects;
/** Information about the playback device. */
public final class DeviceInfo {
@ -178,7 +179,7 @@ public final class DeviceInfo {
return playbackType == other.playbackType
&& minVolume == other.minVolume
&& maxVolume == other.maxVolume
&& Util.areEqual(routingControllerId, other.routingControllerId);
&& Objects.equals(routingControllerId, other.routingControllerId);
}
@Override
@ -227,5 +228,4 @@ public final class DeviceInfo {
.setRoutingControllerId(routingControllerId)
.build();
}
;
}

View File

@ -28,6 +28,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
/** Initialization data for one or more DRM schemes. */
@ -160,7 +161,7 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
*/
@CheckResult
public DrmInitData copyWithSchemeType(@Nullable String schemeType) {
if (Util.areEqual(this.schemeType, schemeType)) {
if (Objects.equals(this.schemeType, schemeType)) {
return this;
}
return new DrmInitData(schemeType, false, schemeDatas);
@ -204,7 +205,7 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
return false;
}
DrmInitData other = (DrmInitData) obj;
return Util.areEqual(schemeType, other.schemeType)
return Objects.equals(schemeType, other.schemeType)
&& Arrays.equals(schemeDatas, other.schemeDatas);
}
@ -352,9 +353,9 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
return true;
}
SchemeData other = (SchemeData) obj;
return Util.areEqual(licenseServerUrl, other.licenseServerUrl)
&& Util.areEqual(mimeType, other.mimeType)
&& Util.areEqual(uuid, other.uuid)
return Objects.equals(licenseServerUrl, other.licenseServerUrl)
&& Objects.equals(mimeType, other.mimeType)
&& Objects.equals(uuid, other.uuid)
&& Arrays.equals(data, other.data);
}

View File

@ -16,6 +16,7 @@
package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkState;
import static com.google.common.math.DoubleMath.fuzzyEquals;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle;
@ -102,6 +103,7 @@ import java.util.UUID;
* <li>{@link #projectionData}
* <li>{@link #stereoMode}
* <li>{@link #colorInfo}
* <li>{@link #maxSubLayers}
* </ul>
*
* <h2 id="audio-formats">Fields relevant to audio formats</h2>
@ -178,6 +180,7 @@ public final class Format {
@Nullable private byte[] projectionData;
private @C.StereoMode int stereoMode;
@Nullable private ColorInfo colorInfo;
private int maxSubLayers;
// Audio specific.
@ -216,6 +219,7 @@ public final class Format {
frameRate = NO_VALUE;
pixelWidthHeightRatio = 1.0f;
stereoMode = NO_VALUE;
maxSubLayers = NO_VALUE;
// Audio specific.
channelCount = NO_VALUE;
sampleRate = NO_VALUE;
@ -267,6 +271,7 @@ public final class Format {
this.projectionData = format.projectionData;
this.stereoMode = format.stereoMode;
this.colorInfo = format.colorInfo;
this.maxSubLayers = format.maxSubLayers;
// Audio specific.
this.channelCount = format.channelCount;
this.sampleRate = format.sampleRate;
@ -655,6 +660,18 @@ public final class Format {
return this;
}
/**
* Sets {@link Format#maxSubLayers}. The default value is {@link #NO_VALUE}.
*
* @param maxSubLayers The {@link Format#maxSubLayers}.
* @return The builder.
*/
@CanIgnoreReturnValue
public Builder setMaxSubLayers(int maxSubLayers) {
this.maxSubLayers = maxSubLayers;
return this;
}
// Audio specific.
/**
@ -749,7 +766,7 @@ public final class Format {
/**
* Sets {@link Format#tileCountHorizontal}. The default value is {@link #NO_VALUE}.
*
* @param tileCountHorizontal The {@link Format#accessibilityChannel}.
* @param tileCountHorizontal The {@link Format#tileCountHorizontal}.
* @return The builder.
*/
@CanIgnoreReturnValue
@ -761,7 +778,7 @@ public final class Format {
/**
* Sets {@link Format#tileCountVertical}. The default value is {@link #NO_VALUE}.
*
* @param tileCountVertical The {@link Format#accessibilityChannel}.
* @param tileCountVertical The {@link Format#tileCountVertical}.
* @return The builder.
*/
@CanIgnoreReturnValue
@ -1008,6 +1025,12 @@ public final class Format {
/** The color metadata associated with the video, or null if not applicable. */
@UnstableApi @Nullable public final ColorInfo colorInfo;
/**
* The maximum number of temporal scalable sub-layers in the video bitstream, or {@link #NO_VALUE}
* if not applicable.
*/
@UnstableApi public final int maxSubLayers;
// Audio specific.
/** The number of audio channels, or {@link #NO_VALUE} if unknown or not applicable. */
@ -1016,7 +1039,10 @@ public final class Format {
/** The audio sampling rate in Hz, or {@link #NO_VALUE} if unknown or not applicable. */
public final int sampleRate;
/** The {@link C.PcmEncoding} for PCM audio. Set to {@link #NO_VALUE} for other media types. */
/**
* The {@link C.PcmEncoding} for PCM or losslessly compressed audio. Set to {@link #NO_VALUE} for
* other media types.
*/
@UnstableApi public final @C.PcmEncoding int pcmEncoding;
/**
@ -1126,6 +1152,7 @@ public final class Format {
projectionData = builder.projectionData;
stereoMode = builder.stereoMode;
colorInfo = builder.colorInfo;
maxSubLayers = builder.maxSubLayers;
// Audio specific.
channelCount = builder.channelCount;
sampleRate = builder.sampleRate;
@ -1308,6 +1335,7 @@ public final class Format {
// [Omitted] projectionData.
result = 31 * result + stereoMode;
// [Omitted] colorInfo.
result = 31 * result + maxSubLayers;
// Audio specific.
result = 31 * result + channelCount;
result = 31 * result + sampleRate;
@ -1350,6 +1378,7 @@ public final class Format {
&& height == other.height
&& rotationDegrees == other.rotationDegrees
&& stereoMode == other.stereoMode
&& maxSubLayers == other.maxSubLayers
&& channelCount == other.channelCount
&& sampleRate == other.sampleRate
&& pcmEncoding == other.pcmEncoding
@ -1442,12 +1471,18 @@ public final class Format {
if (format.width != NO_VALUE && format.height != NO_VALUE) {
builder.append(", res=").append(format.width).append("x").append(format.height);
}
if (!fuzzyEquals(format.pixelWidthHeightRatio, 1, 0.001)) {
builder.append(", par=").append(Util.formatInvariant("%.3f", format.pixelWidthHeightRatio));
}
if (format.colorInfo != null && format.colorInfo.isValid()) {
builder.append(", color=").append(format.colorInfo.toLogString());
}
if (format.frameRate != NO_VALUE) {
builder.append(", fps=").append(format.frameRate);
}
if (format.maxSubLayers != NO_VALUE) {
builder.append(", maxSubLayers=").append(format.maxSubLayers);
}
if (format.channelCount != NO_VALUE) {
builder.append(", channels=").append(format.channelCount);
}
@ -1492,7 +1527,8 @@ public final class Format {
private static final String FIELD_AVERAGE_BITRATE = Util.intToStringMaxRadix(5);
private static final String FIELD_PEAK_BITRATE = Util.intToStringMaxRadix(6);
private static final String FIELD_CODECS = Util.intToStringMaxRadix(7);
private static final String FIELD_METADATA = Util.intToStringMaxRadix(8);
// Do not reuse this key.
private static final String UNUSED_FIELD_METADATA = Util.intToStringMaxRadix(8);
private static final String FIELD_CONTAINER_MIME_TYPE = Util.intToStringMaxRadix(9);
private static final String FIELD_SAMPLE_MIME_TYPE = Util.intToStringMaxRadix(10);
private static final String FIELD_MAX_INPUT_SIZE = Util.intToStringMaxRadix(11);
@ -1518,22 +1554,14 @@ public final class Format {
private static final String FIELD_TILE_COUNT_VERTICAL = Util.intToStringMaxRadix(31);
private static final String FIELD_LABELS = Util.intToStringMaxRadix(32);
private static final String FIELD_AUXILIARY_TRACK_TYPE = Util.intToStringMaxRadix(33);
/**
* @deprecated Use {@link #toBundle(boolean)} instead.
*/
@UnstableApi
@Deprecated
public Bundle toBundle() {
return toBundle(/* excludeMetadata= */ false);
}
private static final String FIELD_MAX_SUB_LAYERS = Util.intToStringMaxRadix(34);
/**
* Returns a {@link Bundle} representing the information stored in this object. If {@code
* excludeMetadata} is true, {@linkplain Format#metadata metadata} is excluded.
*/
@UnstableApi
public Bundle toBundle(boolean excludeMetadata) {
public Bundle toBundle() {
Bundle bundle = new Bundle();
bundle.putString(FIELD_ID, id);
bundle.putString(FIELD_LABEL, label);
@ -1548,10 +1576,7 @@ public final class Format {
bundle.putInt(FIELD_AVERAGE_BITRATE, averageBitrate);
bundle.putInt(FIELD_PEAK_BITRATE, peakBitrate);
bundle.putString(FIELD_CODECS, codecs);
if (!excludeMetadata) {
// TODO (internal ref: b/239701618)
bundle.putParcelable(FIELD_METADATA, metadata);
}
// The metadata does not implement toBundle() method, hence can not be added.
// Container specific.
bundle.putString(FIELD_CONTAINER_MIME_TYPE, containerMimeType);
// Sample specific.
@ -1575,6 +1600,7 @@ public final class Format {
if (colorInfo != null) {
bundle.putBundle(FIELD_COLOR_INFO, colorInfo.toBundle());
}
bundle.putInt(FIELD_MAX_SUB_LAYERS, maxSubLayers);
// Audio specific.
bundle.putInt(FIELD_CHANNEL_COUNT, channelCount);
bundle.putInt(FIELD_SAMPLE_RATE, sampleRate);
@ -1614,7 +1640,6 @@ public final class Format {
.setAverageBitrate(bundle.getInt(FIELD_AVERAGE_BITRATE, DEFAULT.averageBitrate))
.setPeakBitrate(bundle.getInt(FIELD_PEAK_BITRATE, DEFAULT.peakBitrate))
.setCodecs(defaultIfNull(bundle.getString(FIELD_CODECS), DEFAULT.codecs))
.setMetadata(defaultIfNull(bundle.getParcelable(FIELD_METADATA), DEFAULT.metadata))
// Container specific.
.setContainerMimeType(
defaultIfNull(bundle.getString(FIELD_CONTAINER_MIME_TYPE), DEFAULT.containerMimeType))
@ -1643,7 +1668,8 @@ public final class Format {
.setPixelWidthHeightRatio(
bundle.getFloat(FIELD_PIXEL_WIDTH_HEIGHT_RATIO, DEFAULT.pixelWidthHeightRatio))
.setProjectionData(bundle.getByteArray(FIELD_PROJECTION_DATA))
.setStereoMode(bundle.getInt(FIELD_STEREO_MODE, DEFAULT.stereoMode));
.setStereoMode(bundle.getInt(FIELD_STEREO_MODE, DEFAULT.stereoMode))
.setMaxSubLayers(bundle.getInt(FIELD_MAX_SUB_LAYERS, DEFAULT.maxSubLayers));
Bundle colorInfoBundle = bundle.getBundle(FIELD_COLOR_INFO);
if (colorInfoBundle != null) {
builder.setColorInfo(ColorInfo.fromBundle(colorInfoBundle));

View File

@ -30,6 +30,25 @@ import java.util.List;
/**
* A {@link Player} that forwards method calls to another {@link Player}. Applications can use this
* class to suppress or modify specific operations, by overriding the respective methods.
*
* <p>Subclasses must ensure they maintain consistency with the {@link Player} interface, including
* interactions with {@link Player.Listener}, which can be quite fiddly. For example, if removing an
* available {@link Player.Command} and disabling the corresponding method, subclasses need to:
*
* <ul>
* <li>Override {@link #isCommandAvailable(int)} and {@link #getAvailableCommands()}
* <li>Override and no-op the method itself
* <li>Override {@link #addListener(Listener)} and wrap the provided {@link Player.Listener} with
* an implementation that drops calls to {@link
* Player.Listener#onAvailableCommandsChanged(Commands)} and {@link
* Player.Listener#onEvents(Player, Events)} if they were only triggered by a change in
* command availability that is 'invisible' after the command removal.
* </ul>
*
* <p>Many customization use-cases are instead better served by {@link ForwardingSimpleBasePlayer},
* which allows subclasses to more concisely modify the behavior of an operation, or disallow a
* {@link Player.Command}. In many cases {@link ForwardingSimpleBasePlayer} should be used in
* preference to {@code ForwardingPlayer}.
*/
@UnstableApi
public class ForwardingPlayer implements Player {

View File

@ -25,7 +25,6 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.List;
// LINT.IfChange(javadoc)
/**
* A {@link SimpleBasePlayer} that forwards all calls to another {@link Player} instance.
*
@ -60,7 +59,7 @@ public class ForwardingSimpleBasePlayer extends SimpleBasePlayer {
private final Player player;
private ForwardingPositionSupplier currentPositionSupplier;
private LivePositionSuppliers livePositionSuppliers;
private Metadata lastTimedMetadata;
private @Player.PlayWhenReadyChangeReason int playWhenReadyChangeReason;
private @Player.DiscontinuityReason int pendingDiscontinuityReason;
@ -78,7 +77,7 @@ public class ForwardingSimpleBasePlayer extends SimpleBasePlayer {
this.lastTimedMetadata = new Metadata(/* presentationTimeUs= */ C.TIME_UNSET);
this.playWhenReadyChangeReason = Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST;
this.pendingDiscontinuityReason = Player.DISCONTINUITY_REASON_INTERNAL;
this.currentPositionSupplier = new ForwardingPositionSupplier(player);
this.livePositionSuppliers = new LivePositionSuppliers(player);
player.addListener(
new Listener() {
@Override
@ -99,15 +98,8 @@ public class ForwardingSimpleBasePlayer extends SimpleBasePlayer {
@Player.DiscontinuityReason int reason) {
pendingDiscontinuityReason = reason;
pendingPositionDiscontinuityNewPositionMs = newPosition.positionMs;
// Any previously created State will directly call through to player.getCurrentPosition
// via the existing position supplier. From this point onwards, this is wrong as the
// player had a discontinuity and will now return a new position unrelated to the old
// State. We can disconnect these old State objects from the underlying Player by fixing
// the position to the one before the discontinuity and using a new (live) position
// supplier for future State objects.
currentPositionSupplier.setConstant(
oldPosition.positionMs, oldPosition.contentPositionMs);
currentPositionSupplier = new ForwardingPositionSupplier(player);
livePositionSuppliers.disconnect(oldPosition.positionMs, oldPosition.contentPositionMs);
livePositionSuppliers = new LivePositionSuppliers(player);
}
@Override
@ -132,18 +124,18 @@ public class ForwardingSimpleBasePlayer extends SimpleBasePlayer {
protected State getState() {
// Ordered alphabetically by State.Builder setters.
State.Builder state = new State.Builder();
ForwardingPositionSupplier positionSupplier = currentPositionSupplier;
LivePositionSuppliers positionSuppliers = livePositionSuppliers;
if (player.isCommandAvailable(Player.COMMAND_GET_CURRENT_MEDIA_ITEM)) {
state.setAdBufferedPositionMs(positionSupplier::getBufferedPositionMs);
state.setAdPositionMs(positionSupplier::getCurrentPositionMs);
state.setAdBufferedPositionMs(positionSuppliers.bufferedPositionSupplier);
state.setAdPositionMs(positionSuppliers.currentPositionSupplier);
}
if (player.isCommandAvailable(Player.COMMAND_GET_AUDIO_ATTRIBUTES)) {
state.setAudioAttributes(player.getAudioAttributes());
}
state.setAvailableCommands(player.getAvailableCommands());
if (player.isCommandAvailable(Player.COMMAND_GET_CURRENT_MEDIA_ITEM)) {
state.setContentBufferedPositionMs(positionSupplier::getContentBufferedPositionMs);
state.setContentPositionMs(positionSupplier::getContentPositionMs);
state.setContentBufferedPositionMs(positionSuppliers.contentBufferedPositionSupplier);
state.setContentPositionMs(positionSuppliers.contentPositionSupplier);
if (player.isCommandAvailable(Player.COMMAND_GET_TIMELINE)) {
state.setCurrentAd(player.getCurrentAdGroupIndex(), player.getCurrentAdIndexInAdGroup());
}
@ -194,7 +186,7 @@ public class ForwardingSimpleBasePlayer extends SimpleBasePlayer {
state.setSurfaceSize(player.getSurfaceSize());
state.setTimedMetadata(lastTimedMetadata);
if (player.isCommandAvailable(Player.COMMAND_GET_CURRENT_MEDIA_ITEM)) {
state.setTotalBufferedDurationMs(positionSupplier::getTotalBufferedDurationMs);
state.setTotalBufferedDurationMs(positionSuppliers.totalBufferedPositionSupplier);
}
state.setTrackSelectionParameters(player.getTrackSelectionParameters());
state.setVideoSize(player.getVideoSize());
@ -456,44 +448,29 @@ public class ForwardingSimpleBasePlayer extends SimpleBasePlayer {
* Forwards to the changing position values of the wrapped player until the forwarding is
* deactivated with constant values.
*/
private static final class ForwardingPositionSupplier {
private static final class LivePositionSuppliers {
private final Player player;
public final LivePositionSupplier currentPositionSupplier;
public final LivePositionSupplier bufferedPositionSupplier;
public final LivePositionSupplier contentPositionSupplier;
public final LivePositionSupplier contentBufferedPositionSupplier;
public final LivePositionSupplier totalBufferedPositionSupplier;
private long positionsMs;
private long contentPositionMs;
public ForwardingPositionSupplier(Player player) {
this.player = player;
this.positionsMs = C.TIME_UNSET;
this.contentPositionMs = C.TIME_UNSET;
public LivePositionSuppliers(Player player) {
currentPositionSupplier = new LivePositionSupplier(player::getCurrentPosition);
bufferedPositionSupplier = new LivePositionSupplier(player::getBufferedPosition);
contentPositionSupplier = new LivePositionSupplier(player::getContentPosition);
contentBufferedPositionSupplier =
new LivePositionSupplier(player::getContentBufferedPosition);
totalBufferedPositionSupplier = new LivePositionSupplier(player::getTotalBufferedDuration);
}
public void setConstant(long positionMs, long contentPositionMs) {
this.positionsMs = positionMs;
this.contentPositionMs = contentPositionMs;
}
public long getCurrentPositionMs() {
return positionsMs == C.TIME_UNSET ? player.getCurrentPosition() : positionsMs;
}
public long getBufferedPositionMs() {
return positionsMs == C.TIME_UNSET ? player.getBufferedPosition() : positionsMs;
}
public long getContentPositionMs() {
return contentPositionMs == C.TIME_UNSET ? player.getContentPosition() : contentPositionMs;
}
public long getContentBufferedPositionMs() {
return contentPositionMs == C.TIME_UNSET
? player.getContentBufferedPosition()
: contentPositionMs;
}
public long getTotalBufferedDurationMs() {
return positionsMs == C.TIME_UNSET ? player.getTotalBufferedDuration() : 0;
public void disconnect(long positionMs, long contentPositionMs) {
currentPositionSupplier.disconnect(positionMs);
bufferedPositionSupplier.disconnect(positionMs);
contentPositionSupplier.disconnect(contentPositionMs);
contentBufferedPositionSupplier.disconnect(contentPositionMs);
totalBufferedPositionSupplier.disconnect(/* finalValue= */ 0);
}
}
}

View File

@ -18,123 +18,34 @@ package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkArgument;
import androidx.media3.common.util.UnstableApi;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
/** Value class specifying information about a decoded video frame. */
@UnstableApi
public class FrameInfo {
/** A builder for {@link FrameInfo} instances. */
public static final class Builder {
private ColorInfo colorInfo;
private int width;
private int height;
private float pixelWidthHeightRatio;
private long offsetToAddUs;
/**
* Creates an instance with default values.
*
* @param colorInfo The {@link ColorInfo}.
* @param width The frame width, in pixels.
* @param height The frame height, in pixels.
*/
public Builder(ColorInfo colorInfo, int width, int height) {
this.colorInfo = colorInfo;
this.width = width;
this.height = height;
pixelWidthHeightRatio = 1;
}
/** Creates an instance with the values of the provided {@link FrameInfo}. */
public Builder(FrameInfo frameInfo) {
colorInfo = frameInfo.colorInfo;
width = frameInfo.width;
height = frameInfo.height;
pixelWidthHeightRatio = frameInfo.pixelWidthHeightRatio;
offsetToAddUs = frameInfo.offsetToAddUs;
}
/** Sets the {@link ColorInfo}. */
@CanIgnoreReturnValue
public Builder setColorInfo(ColorInfo colorInfo) {
this.colorInfo = colorInfo;
return this;
}
/** Sets the frame width, in pixels. */
@CanIgnoreReturnValue
public Builder setWidth(int width) {
this.width = width;
return this;
}
/** Sets the frame height, in pixels. */
@CanIgnoreReturnValue
public Builder setHeight(int height) {
this.height = height;
return this;
}
/**
* Sets the ratio of width over height for each pixel.
*
* <p>The default value is {@code 1}.
*/
@CanIgnoreReturnValue
public Builder setPixelWidthHeightRatio(float pixelWidthHeightRatio) {
this.pixelWidthHeightRatio = pixelWidthHeightRatio;
return this;
}
/**
* Sets the {@linkplain FrameInfo#offsetToAddUs offset to add} to the frame presentation
* timestamp, in microseconds.
*
* <p>The default value is {@code 0}.
*/
@CanIgnoreReturnValue
public Builder setOffsetToAddUs(long offsetToAddUs) {
this.offsetToAddUs = offsetToAddUs;
return this;
}
/** Builds a {@link FrameInfo} instance. */
public FrameInfo build() {
return new FrameInfo(colorInfo, width, height, pixelWidthHeightRatio, offsetToAddUs);
}
}
/** The {@link ColorInfo} of the frame. */
public final ColorInfo colorInfo;
/** The width of the frame, in pixels. */
public final int width;
/** The height of the frame, in pixels. */
public final int height;
/** The ratio of width over height for each pixel. */
public final float pixelWidthHeightRatio;
/**
* The offset that must be added to the frame presentation timestamp, in microseconds.
* The {@link Format} of the frame.
*
* <p>This offset is not part of the input timestamps. It is added to the frame timestamps before
* processing, and is retained in the output timestamps.
* <p>The {@link Format#colorInfo} must be set, and the {@link Format#width} and {@link
* Format#height} must be greater than 0.
*/
public final Format format;
/** The offset that must be added to the frame presentation timestamp, in microseconds. */
public final long offsetToAddUs;
private FrameInfo(
ColorInfo colorInfo, int width, int height, float pixelWidthHeightRatio, long offsetToAddUs) {
checkArgument(width > 0, "width must be positive, but is: " + width);
checkArgument(height > 0, "height must be positive, but is: " + height);
/**
* Creates an instance.
*
* @param format See {@link #format}.
* @param offsetToAddUs See {@link #offsetToAddUs}.
*/
public FrameInfo(Format format, long offsetToAddUs) {
checkArgument(format.colorInfo != null, "format colorInfo must be set");
checkArgument(format.width > 0, "format width must be positive, but is: " + format.width);
checkArgument(format.height > 0, "format height must be positive, but is: " + format.height);
this.colorInfo = colorInfo;
this.width = width;
this.height = height;
this.pixelWidthHeightRatio = pixelWidthHeightRatio;
this.format = format;
this.offsetToAddUs = offsetToAddUs;
}
}

View File

@ -21,7 +21,7 @@ import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.base.Objects;
import java.util.Objects;
/**
* A rating expressed as "heart" or "no heart". It can be used to indicate whether the content is a
@ -60,7 +60,7 @@ public final class HeartRating extends Rating {
@Override
public int hashCode() {
return Objects.hashCode(rated, isHeart);
return Objects.hash(rated, isHeart);
}
@Override

View File

@ -21,6 +21,7 @@ import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import java.util.Objects;
/** A label for a {@link Format}. */
@UnstableApi
@ -55,7 +56,7 @@ public class Label {
return false;
}
Label label = (Label) o;
return Util.areEqual(language, label.language) && Util.areEqual(value, label.value);
return Objects.equals(language, label.language) && Objects.equals(value, label.value);
}
@Override

View File

@ -39,6 +39,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
/** Representation of a media item. */
@ -915,8 +916,8 @@ public final class MediaItem {
DrmConfiguration other = (DrmConfiguration) obj;
return scheme.equals(other.scheme)
&& Util.areEqual(licenseUri, other.licenseUri)
&& Util.areEqual(licenseRequestHeaders, other.licenseRequestHeaders)
&& Objects.equals(licenseUri, other.licenseUri)
&& Objects.equals(licenseRequestHeaders, other.licenseRequestHeaders)
&& multiSession == other.multiSession
&& forceDefaultLicenseUri == other.forceDefaultLicenseUri
&& playClearContentWithoutKey == other.playClearContentWithoutKey
@ -1090,7 +1091,7 @@ public final class MediaItem {
}
AdsConfiguration other = (AdsConfiguration) obj;
return adTagUri.equals(other.adTagUri) && Util.areEqual(adsId, other.adsId);
return adTagUri.equals(other.adTagUri) && Objects.equals(adsId, other.adsId);
}
@Override
@ -1209,14 +1210,14 @@ public final class MediaItem {
LocalConfiguration other = (LocalConfiguration) obj;
return uri.equals(other.uri)
&& Util.areEqual(mimeType, other.mimeType)
&& Util.areEqual(drmConfiguration, other.drmConfiguration)
&& Util.areEqual(adsConfiguration, other.adsConfiguration)
&& Objects.equals(mimeType, other.mimeType)
&& Objects.equals(drmConfiguration, other.drmConfiguration)
&& Objects.equals(adsConfiguration, other.adsConfiguration)
&& streamKeys.equals(other.streamKeys)
&& Util.areEqual(customCacheKey, other.customCacheKey)
&& Objects.equals(customCacheKey, other.customCacheKey)
&& subtitleConfigurations.equals(other.subtitleConfigurations)
&& Util.areEqual(tag, other.tag)
&& Util.areEqual(imageDurationMs, other.imageDurationMs);
&& Objects.equals(tag, other.tag)
&& imageDurationMs == other.imageDurationMs;
}
@Override
@ -1714,12 +1715,12 @@ public final class MediaItem {
SubtitleConfiguration other = (SubtitleConfiguration) obj;
return uri.equals(other.uri)
&& Util.areEqual(mimeType, other.mimeType)
&& Util.areEqual(language, other.language)
&& Objects.equals(mimeType, other.mimeType)
&& Objects.equals(language, other.language)
&& selectionFlags == other.selectionFlags
&& roleFlags == other.roleFlags
&& Util.areEqual(label, other.label)
&& Util.areEqual(id, other.id);
&& Objects.equals(label, other.label)
&& Objects.equals(id, other.id);
}
@Override
@ -2216,8 +2217,8 @@ public final class MediaItem {
return false;
}
RequestMetadata that = (RequestMetadata) o;
return Util.areEqual(mediaUri, that.mediaUri)
&& Util.areEqual(searchQuery, that.searchQuery)
return Objects.equals(mediaUri, that.mediaUri)
&& Objects.equals(searchQuery, that.searchQuery)
&& ((extras == null) == (that.extras == null));
}
@ -2337,12 +2338,12 @@ public final class MediaItem {
MediaItem other = (MediaItem) obj;
return Util.areEqual(mediaId, other.mediaId)
return Objects.equals(mediaId, other.mediaId)
&& clippingConfiguration.equals(other.clippingConfiguration)
&& Util.areEqual(localConfiguration, other.localConfiguration)
&& Util.areEqual(liveConfiguration, other.liveConfiguration)
&& Util.areEqual(mediaMetadata, other.mediaMetadata)
&& Util.areEqual(requestMetadata, other.requestMetadata);
&& Objects.equals(localConfiguration, other.localConfiguration)
&& Objects.equals(liveConfiguration, other.liveConfiguration)
&& Objects.equals(mediaMetadata, other.mediaMetadata)
&& Objects.equals(requestMetadata, other.requestMetadata);
}
@Override

View File

@ -29,11 +29,11 @@ public final class MediaLibraryInfo {
/** The version of the library expressed as a string, for example "1.2.3" or "1.2.0-beta01". */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa.
public static final String VERSION = "1.5.0";
public static final String VERSION = "1.6.1";
/** The version of the library expressed as {@code TAG + "/" + VERSION}. */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public static final String VERSION_SLASHY = "AndroidXMedia3/1.5.0";
public static final String VERSION_SLASHY = "AndroidXMedia3/1.6.1";
/**
* The version of the library expressed as an integer, for example 1002003300.
@ -47,7 +47,7 @@ public final class MediaLibraryInfo {
* (123-045-006-3-00).
*/
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public static final int VERSION_INT = 1_005_000_3_00;
public static final int VERSION_INT = 1_006_001_3_00;
/** Whether the library was compiled with {@link Assertions} checks enabled. */
public static final boolean ASSERTIONS_ENABLED = true;

View File

@ -29,7 +29,6 @@ import androidx.annotation.IntRange;
import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.lang.annotation.Documented;
@ -39,6 +38,7 @@ import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
* Metadata of a {@link MediaItem}, playlist, or a combination of multiple sources of {@link
@ -194,7 +194,6 @@ public final class MediaMetadata {
*
* @throws IllegalArgumentException if the duration is negative.
*/
@UnstableApi
@CanIgnoreReturnValue
public Builder setDurationMs(@Nullable Long durationMs) {
checkArgument(durationMs == null || durationMs >= 0);
@ -250,8 +249,8 @@ public final class MediaMetadata {
@CanIgnoreReturnValue
public Builder maybeSetArtworkData(byte[] artworkData, @PictureType int artworkDataType) {
if (this.artworkData == null
|| Util.areEqual(artworkDataType, PICTURE_TYPE_FRONT_COVER)
|| !Util.areEqual(this.artworkDataType, PICTURE_TYPE_FRONT_COVER)) {
|| artworkDataType == PICTURE_TYPE_FRONT_COVER
|| !Objects.equals(this.artworkDataType, PICTURE_TYPE_FRONT_COVER)) {
this.artworkData = artworkData.clone();
this.artworkDataType = artworkDataType;
}
@ -1029,7 +1028,7 @@ public final class MediaMetadata {
* informational purpose only. For retrieving the duration of the media item currently being
* played, use {@link Player#getDuration()} instead.
*/
@UnstableApi @Nullable public final Long durationMs;
@Nullable public final Long durationMs;
/** Optional user {@link Rating}. */
@Nullable public final Rating userRating;
@ -1222,47 +1221,47 @@ public final class MediaMetadata {
return false;
}
MediaMetadata that = (MediaMetadata) obj;
return Util.areEqual(title, that.title)
&& Util.areEqual(artist, that.artist)
&& Util.areEqual(albumTitle, that.albumTitle)
&& Util.areEqual(albumArtist, that.albumArtist)
&& Util.areEqual(displayTitle, that.displayTitle)
&& Util.areEqual(subtitle, that.subtitle)
&& Util.areEqual(description, that.description)
&& Util.areEqual(durationMs, that.durationMs)
&& Util.areEqual(userRating, that.userRating)
&& Util.areEqual(overallRating, that.overallRating)
return Objects.equals(title, that.title)
&& Objects.equals(artist, that.artist)
&& Objects.equals(albumTitle, that.albumTitle)
&& Objects.equals(albumArtist, that.albumArtist)
&& Objects.equals(displayTitle, that.displayTitle)
&& Objects.equals(subtitle, that.subtitle)
&& Objects.equals(description, that.description)
&& Objects.equals(durationMs, that.durationMs)
&& Objects.equals(userRating, that.userRating)
&& Objects.equals(overallRating, that.overallRating)
&& Arrays.equals(artworkData, that.artworkData)
&& Util.areEqual(artworkDataType, that.artworkDataType)
&& Util.areEqual(artworkUri, that.artworkUri)
&& Util.areEqual(trackNumber, that.trackNumber)
&& Util.areEqual(totalTrackCount, that.totalTrackCount)
&& Util.areEqual(folderType, that.folderType)
&& Util.areEqual(isBrowsable, that.isBrowsable)
&& Util.areEqual(isPlayable, that.isPlayable)
&& Util.areEqual(recordingYear, that.recordingYear)
&& Util.areEqual(recordingMonth, that.recordingMonth)
&& Util.areEqual(recordingDay, that.recordingDay)
&& Util.areEqual(releaseYear, that.releaseYear)
&& Util.areEqual(releaseMonth, that.releaseMonth)
&& Util.areEqual(releaseDay, that.releaseDay)
&& Util.areEqual(writer, that.writer)
&& Util.areEqual(composer, that.composer)
&& Util.areEqual(conductor, that.conductor)
&& Util.areEqual(discNumber, that.discNumber)
&& Util.areEqual(totalDiscCount, that.totalDiscCount)
&& Util.areEqual(genre, that.genre)
&& Util.areEqual(compilation, that.compilation)
&& Util.areEqual(station, that.station)
&& Util.areEqual(mediaType, that.mediaType)
&& Util.areEqual(supportedCommands, that.supportedCommands)
&& Objects.equals(artworkDataType, that.artworkDataType)
&& Objects.equals(artworkUri, that.artworkUri)
&& Objects.equals(trackNumber, that.trackNumber)
&& Objects.equals(totalTrackCount, that.totalTrackCount)
&& Objects.equals(folderType, that.folderType)
&& Objects.equals(isBrowsable, that.isBrowsable)
&& Objects.equals(isPlayable, that.isPlayable)
&& Objects.equals(recordingYear, that.recordingYear)
&& Objects.equals(recordingMonth, that.recordingMonth)
&& Objects.equals(recordingDay, that.recordingDay)
&& Objects.equals(releaseYear, that.releaseYear)
&& Objects.equals(releaseMonth, that.releaseMonth)
&& Objects.equals(releaseDay, that.releaseDay)
&& Objects.equals(writer, that.writer)
&& Objects.equals(composer, that.composer)
&& Objects.equals(conductor, that.conductor)
&& Objects.equals(discNumber, that.discNumber)
&& Objects.equals(totalDiscCount, that.totalDiscCount)
&& Objects.equals(genre, that.genre)
&& Objects.equals(compilation, that.compilation)
&& Objects.equals(station, that.station)
&& Objects.equals(mediaType, that.mediaType)
&& Objects.equals(supportedCommands, that.supportedCommands)
&& ((extras == null) == (that.extras == null));
}
@SuppressWarnings("deprecation") // Hashing deprecated fields.
@Override
public int hashCode() {
return Objects.hashCode(
return Objects.hash(
title,
artist,
albumTitle,

View File

@ -15,8 +15,6 @@
*/
package androidx.media3.common;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
@ -26,10 +24,10 @@ import java.util.List;
/** A collection of metadata entries. */
@UnstableApi
public final class Metadata implements Parcelable {
public final class Metadata {
/** A metadata entry. */
public interface Entry extends Parcelable {
public interface Entry {
/**
* Returns the {@link Format} that can be used to decode the wrapped metadata in {@link
@ -100,14 +98,6 @@ public final class Metadata implements Parcelable {
this(presentationTimeUs, entries.toArray(new Entry[0]));
}
/* package */ Metadata(Parcel in) {
entries = new Metadata.Entry[in.readInt()];
for (int i = 0; i < entries.length; i++) {
entries[i] = in.readParcelable(Entry.class.getClassLoader());
}
presentationTimeUs = in.readLong();
}
/** Returns the number of metadata entries. */
public int length() {
return entries.length;
@ -190,33 +180,4 @@ public final class Metadata implements Parcelable {
+ Arrays.toString(entries)
+ (presentationTimeUs == C.TIME_UNSET ? "" : ", presentationTimeUs=" + presentationTimeUs);
}
// Parcelable implementation.
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(entries.length);
for (Entry entry : entries) {
dest.writeParcelable(entry, 0);
}
dest.writeLong(presentationTimeUs);
}
public static final Parcelable.Creator<Metadata> CREATOR =
new Parcelable.Creator<Metadata>() {
@Override
public Metadata createFromParcel(Parcel in) {
return new Metadata(in);
}
@Override
public Metadata[] newArray(int size) {
return new Metadata[size];
}
};
}

View File

@ -44,6 +44,7 @@ public final class MimeTypes {
public static final String VIDEO_WEBM = BASE_TYPE_VIDEO + "/webm";
public static final String VIDEO_H263 = BASE_TYPE_VIDEO + "/3gpp";
public static final String VIDEO_H264 = BASE_TYPE_VIDEO + "/avc";
@UnstableApi public static final String VIDEO_APV = BASE_TYPE_VIDEO + "/apv";
public static final String VIDEO_H265 = BASE_TYPE_VIDEO + "/hevc";
@UnstableApi public static final String VIDEO_VP8 = BASE_TYPE_VIDEO + "/x-vnd.on2.vp8";
@UnstableApi public static final String VIDEO_VP9 = BASE_TYPE_VIDEO + "/x-vnd.on2.vp9";
@ -579,6 +580,36 @@ public final class MimeTypes {
}
}
/**
* Returns whether the given {@code codecs} and {@code supplementalCodecs} correspond to a valid
* Dolby Vision codec.
*
* @param codecs An RFC 6381 codecs string for the base codec. may be null.
* @param supplementalCodecs An optional RFC 6381 codecs string for supplemental codecs.
* @return Whether the given {@code codecs} and {@code supplementalCodecs} correspond to a valid
* Dolby Vision codec.
*/
@UnstableApi
public static boolean isDolbyVisionCodec(
@Nullable String codecs, @Nullable String supplementalCodecs) {
if (codecs == null) {
return false;
}
if (codecs.startsWith("dvhe") || codecs.startsWith("dvh1")) {
// profile 5
return true;
}
if (supplementalCodecs == null) {
return false;
}
// profiles 8, 9 and 10
return (supplementalCodecs.startsWith("dvhe") && codecs.startsWith("hev1"))
|| (supplementalCodecs.startsWith("dvh1") && codecs.startsWith("hvc1"))
|| (supplementalCodecs.startsWith("dvav") && codecs.startsWith("avc3"))
|| (supplementalCodecs.startsWith("dva1") && codecs.startsWith("avc1"))
|| (supplementalCodecs.startsWith("dav1") && codecs.startsWith("av01"));
}
/**
* Returns the {@link C.TrackType track type} constant corresponding to a specified MIME type,
* which may be {@link C#TRACK_TYPE_UNKNOWN} if it could not be determined.
@ -685,6 +716,9 @@ public final class MimeTypes {
}
mimeType = Ascii.toLowerCase(mimeType);
switch (mimeType) {
// Normalize uncommon versions of some video MIME types to their standard equivalent.
case BASE_TYPE_VIDEO + "/x-mvhevc":
return VIDEO_MV_HEVC;
// Normalize uncommon versions of some audio MIME types to their standard equivalent.
case BASE_TYPE_AUDIO + "/x-flac":
return AUDIO_FLAC;

View File

@ -0,0 +1,133 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.common;
import android.util.Pair;
import androidx.media3.common.util.UnstableApi;
/**
* Provides information of how an input texture (for example, a {@code TextureOverlay} or in {@code
* VideoCompositor}) is presented.
*/
@UnstableApi
public interface OverlaySettings {
/** The default alpha scale value of the overlay. */
float DEFAULT_ALPHA_SCALE = 1f;
/** The default coordinates for the anchor point of the overlay within the background frame. */
Pair<Float, Float> DEFAULT_BACKGROUND_FRAME_ANCHOR = Pair.create(0f, 0f);
/** The default coordinates for the anchor point of the overlay frame. */
Pair<Float, Float> DEFAULT_OVERLAY_FRAME_ANCHOR = Pair.create(0f, 0f);
/** The default scaling of the overlay. */
Pair<Float, Float> DEFAULT_SCALE = Pair.create(1f, 1f);
/** The default rotation of the overlay, counter-clockwise. */
float DEFAULT_ROTATION_DEGREES = 0f;
/** The default luminance multiplier of an SDR overlay when overlaid on a HDR frame. */
float DEFAULT_HDR_LUMINANCE_MULTIPLIER = 1f;
/**
* Returns the alpha scale value of the overlay, altering its translucency.
*
* <p>An {@code alphaScale} value of {@code 1} means no change is applied. A value below {@code 1}
* increases translucency, and a value above {@code 1} reduces translucency.
*
* <p>The default value is {@link #DEFAULT_ALPHA_SCALE}.
*/
default float getAlphaScale() {
return DEFAULT_ALPHA_SCALE;
}
/**
* Returns the coordinates for the anchor point of the overlay within the background frame.
*
* <p>The coordinates are specified in Normalised Device Coordinates (NDCs) relative to the
* background frame. The ranges for x and y are from {@code -1} to {@code 1}. The default value is
* {@code (0,0)}, the center of the background frame.
*
* <p>The overlay's {@linkplain #getOverlayFrameAnchor anchor point} will be positioned at the
* anchor point returned from this method. For example, a value of {@code (1,1)} will move the
* {@linkplain #getOverlayFrameAnchor overlay's anchor} to the top right corner. That is, if the
* overlay's anchor is at {@code (1,1)} (the top right corner), the overlay's top right corner
* will be aligned with that of the background frame; whereas if the overlay's anchor is at {@code
* (0,0)} (the center), the overlay's center will be positioned at the top right corner of the
* background frame.
*
* <p>The default value is {@link #DEFAULT_BACKGROUND_FRAME_ANCHOR}.
*/
default Pair<Float, Float> getBackgroundFrameAnchor() {
return DEFAULT_BACKGROUND_FRAME_ANCHOR;
}
/**
* Returns the coordinates for the anchor point within the overlay.
*
* <p>The anchor point is the point inside the overlay that is placed on the {@linkplain
* #getBackgroundFrameAnchor background frame anchor}
*
* <p>The coordinates are specified in Normalised Device Coordinates (NDCs) relative to the
* overlay. The ranges for x and y are from {@code -1} to {@code 1}. The default value is {@code
* (0,0)}, the center of the overlay.
*
* <p>See {@link #getBackgroundFrameAnchor} for examples of how to position an overlay.
*
* <p>The default value is {@link #DEFAULT_OVERLAY_FRAME_ANCHOR}.
*/
default Pair<Float, Float> getOverlayFrameAnchor() {
return DEFAULT_OVERLAY_FRAME_ANCHOR;
}
/**
* Returns the scaling of the overlay.
*
* <p>The default value is {@link #DEFAULT_SCALE}.
*/
default Pair<Float, Float> getScale() {
return DEFAULT_SCALE;
}
/**
* Returns the rotation of the overlay, counter-clockwise.
*
* <p>The overlay is rotated at the center of its frame.
*
* <p>The default value is {@link #DEFAULT_ROTATION_DEGREES}.
*/
default float getRotationDegrees() {
return DEFAULT_ROTATION_DEGREES;
}
/**
* Returns the luminance multiplier of an SDR overlay when overlaid on a HDR frame.
*
* <p>Scales the luminance of the overlay to adjust the output brightness of the overlay on the
* frame. The default value is 1, which scales the overlay colors into the standard HDR luminance
* within the processing pipeline. Use 0.5 to scale the luminance of the overlay to SDR range, so
* that no extra luminance is added.
*
* <p>Currently only supported on text overlays
*
* <p>The default value is {@link #DEFAULT_HDR_LUMINANCE_MULTIPLIER}.
*/
default float getHdrLuminanceMultiplier() {
return DEFAULT_HDR_LUMINANCE_MULTIPLIER;
}
}

View File

@ -109,11 +109,11 @@ public class ParserException extends IOException {
this.dataType = dataType;
}
@Nullable
@Override
public String getMessage() {
return super.getMessage()
+ " {contentIsMalformed="
String superMessage = super.getMessage();
return (superMessage != null ? superMessage + " " : "")
+ "{contentIsMalformed="
+ contentIsMalformed
+ ", dataType="
+ dataType

View File

@ -22,7 +22,7 @@ import androidx.annotation.FloatRange;
import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.base.Objects;
import java.util.Objects;
/** A rating expressed as a percentage. */
public final class PercentageRating extends Rating {
@ -59,7 +59,7 @@ public final class PercentageRating extends Rating {
@Override
public int hashCode() {
return Objects.hashCode(percent);
return Objects.hash(percent);
}
@Override

View File

@ -36,6 +36,7 @@ import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Objects;
/** Thrown when a non locally recoverable playback failure occurs. */
public class PlaybackException extends Exception {
@ -91,6 +92,7 @@ public class PlaybackException extends Exception {
ERROR_CODE_DECODING_FAILED,
ERROR_CODE_DECODING_FORMAT_EXCEEDS_CAPABILITIES,
ERROR_CODE_DECODING_FORMAT_UNSUPPORTED,
ERROR_CODE_DECODING_RESOURCES_RECLAIMED,
ERROR_CODE_AUDIO_TRACK_INIT_FAILED,
ERROR_CODE_AUDIO_TRACK_WRITE_FAILED,
ERROR_CODE_AUDIO_TRACK_OFFLOAD_INIT_FAILED,
@ -272,9 +274,8 @@ public class PlaybackException extends Exception {
/** Caused by trying to decode content whose format is not supported. */
public static final int ERROR_CODE_DECODING_FORMAT_UNSUPPORTED = 4005;
// TODO: b/322943860 - Stabilize error code and add to IntDef
/** Caused by higher priority task reclaiming resources needed for decoding. */
@UnstableApi public static final int ERROR_CODE_DECODING_RESOURCES_RECLAIMED = 4006;
public static final int ERROR_CODE_DECODING_RESOURCES_RECLAIMED = 4006;
// AudioTrack errors (5xxx).
@ -553,17 +554,17 @@ public class PlaybackException extends Exception {
@Nullable Throwable thisCause = getCause();
@Nullable Throwable thatCause = other.getCause();
if (thisCause != null && thatCause != null) {
if (!Util.areEqual(thisCause.getMessage(), thatCause.getMessage())) {
if (!Objects.equals(thisCause.getMessage(), thatCause.getMessage())) {
return false;
}
if (!Util.areEqual(thisCause.getClass(), thatCause.getClass())) {
if (!Objects.equals(thisCause.getClass(), thatCause.getClass())) {
return false;
}
} else if (thisCause != null || thatCause != null) {
return false;
}
return errorCode == other.errorCode
&& Util.areEqual(getMessage(), other.getMessage())
&& Objects.equals(getMessage(), other.getMessage())
&& timestampMs == other.timestampMs;
}

View File

@ -88,6 +88,18 @@ public final class PlaybackParameters {
return new PlaybackParameters(speed, pitch);
}
/**
* Returns a copy with the given pitch.
*
* @param pitch The new pitch. Must be greater than zero.
* @return The copied playback parameters.
*/
@UnstableApi
@CheckResult
public PlaybackParameters withPitch(@FloatRange(from = 0, fromInclusive = false) float pitch) {
return new PlaybackParameters(speed, pitch);
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {

View File

@ -37,7 +37,6 @@ import androidx.media3.common.text.CueGroup;
import androidx.media3.common.util.Size;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.base.Objects;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
@ -45,6 +44,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* A media player interface defining high-level functionality, such as the ability to play, pause,
@ -352,13 +352,13 @@ public interface Player {
}
PositionInfo that = (PositionInfo) o;
return equalsForBundling(that)
&& Objects.equal(windowUid, that.windowUid)
&& Objects.equal(periodUid, that.periodUid);
&& Objects.equals(windowUid, that.windowUid)
&& Objects.equals(periodUid, that.periodUid);
}
@Override
public int hashCode() {
return Objects.hashCode(
return Objects.hash(
windowUid,
mediaItemIndex,
mediaItem,
@ -382,7 +382,7 @@ public interface Player {
&& contentPositionMs == other.contentPositionMs
&& adGroupIndex == other.adGroupIndex
&& adIndexInAdGroup == other.adIndexInAdGroup
&& Objects.equal(mediaItem, other.mediaItem);
&& Objects.equals(mediaItem, other.mediaItem);
}
@VisibleForTesting static final String FIELD_MEDIA_ITEM_INDEX = Util.intToStringMaxRadix(0);
@ -1613,7 +1613,7 @@ public interface Player {
/** {@link #getDeviceInfo()} changed. */
int EVENT_DEVICE_INFO_CHANGED = 29;
/** {@link #getDeviceVolume()} changed. */
/** {@link #getDeviceVolume()} or {@link #isDeviceMuted()} changed. */
int EVENT_DEVICE_VOLUME_CHANGED = 30;
/**
@ -2855,7 +2855,6 @@ public interface Player {
*/
TrackSelectionParameters getTrackSelectionParameters();
// LINT.IfChange(set_track_selection_parameters)
/**
* Sets the parameters constraining the track selection.
*
@ -3384,8 +3383,7 @@ public interface Player {
*
* <p>For devices with {@link DeviceInfo#PLAYBACK_TYPE_LOCAL local playback}, the volume returned
* by this method varies according to the current {@link C.StreamType stream type}. The stream
* type is determined by {@link AudioAttributes#usage} which can be converted to stream type with
* {@link Util#getStreamTypeForAudioUsage(int)}.
* type is determined by {@link AudioAttributes#getStreamType()}.
*
* <p>For devices with {@link DeviceInfo#PLAYBACK_TYPE_REMOTE remote playback}, the volume of the
* remote device is returned.
@ -3508,10 +3506,6 @@ public interface Player {
* <p>If tunneling is enabled by the track selector, the specified audio attributes will be
* ignored, but they will take effect if audio is later played without tunneling.
*
* <p>If the device is running a build before platform API version 21, audio attributes cannot be
* set directly on the underlying audio track. In this case, the usage will be mapped onto an
* equivalent stream type using {@link Util#getStreamTypeForAudioUsage(int)}.
*
* <p>If audio focus should be handled, the {@link AudioAttributes#usage} must be {@link
* C#USAGE_MEDIA} or {@link C#USAGE_GAME}. Other usages will throw an {@link
* IllegalArgumentException}.

View File

@ -35,6 +35,7 @@ public interface PreviewingVideoGraph extends VideoGraph {
* @param debugViewProvider A {@link DebugViewProvider}.
* @param listener A {@link Listener}.
* @param listenerExecutor The {@link Executor} on which the {@code listener} is invoked.
* @param videoCompositorSettings The {@link VideoCompositorSettings}.
* @param compositionEffects A list of {@linkplain Effect effects} to apply to the composition.
* @param initialTimestampOffsetUs The timestamp offset for the first frame, in microseconds.
* @return A new instance.
@ -47,9 +48,16 @@ public interface PreviewingVideoGraph extends VideoGraph {
DebugViewProvider debugViewProvider,
Listener listener,
Executor listenerExecutor,
VideoCompositorSettings videoCompositorSettings,
List<Effect> compositionEffects,
long initialTimestampOffsetUs)
throws VideoFrameProcessingException;
/**
* Returns whether the {@link VideoGraph} implementation supports {@linkplain #registerInput
* registering} multiple inputs.
*/
boolean supportsMultipleInputs();
}
/**

View File

@ -15,7 +15,6 @@
*/
package androidx.media3.common;
import static androidx.annotation.VisibleForTesting.PROTECTED;
import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Util.castNonNull;
@ -35,7 +34,6 @@ import android.view.TextureView;
import androidx.annotation.FloatRange;
import androidx.annotation.IntRange;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.media3.common.text.CueGroup;
import androidx.media3.common.util.Clock;
import androidx.media3.common.util.HandlerWrapper;
@ -98,7 +96,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
public abstract class SimpleBasePlayer extends BasePlayer {
/** An immutable state description of the player. */
protected static final class State {
public static final class State {
/** A builder for {@link State} objects. */
public static final class Builder {
@ -161,7 +159,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
seekForwardIncrementMs = C.DEFAULT_SEEK_FORWARD_INCREMENT_MS;
maxSeekToPreviousPositionMs = C.DEFAULT_MAX_SEEK_TO_PREVIOUS_POSITION_MS;
playbackParameters = PlaybackParameters.DEFAULT;
trackSelectionParameters = TrackSelectionParameters.DEFAULT_WITHOUT_CONTEXT;
trackSelectionParameters = TrackSelectionParameters.DEFAULT;
audioAttributes = AudioAttributes.DEFAULT;
volume = 1f;
videoSize = VideoSize.UNKNOWN;
@ -222,7 +220,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
this.playlist = ((PlaylistTimeline) state.timeline).playlist;
} else {
this.currentTracks = state.currentTracks;
this.currentMetadata = state.currentMetadata;
this.currentMetadata = state.usesDerivedMediaMetadata ? null : state.currentMetadata;
}
this.playlistMetadata = state.playlistMetadata;
this.currentMediaItemIndex = state.currentMediaItemIndex;
@ -958,9 +956,12 @@ public abstract class SimpleBasePlayer extends BasePlayer {
*/
public final long discontinuityPositionMs;
private final boolean usesDerivedMediaMetadata;
private State(Builder builder) {
Tracks currentTracks = builder.currentTracks;
MediaMetadata currentMetadata = builder.currentMetadata;
boolean usesDerivedMediaMetadata = false;
if (builder.timeline.isEmpty()) {
checkArgument(
builder.playbackState == Player.STATE_IDLE
@ -1016,6 +1017,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
getCombinedMediaMetadata(
builder.timeline.getWindow(mediaItemIndex, new Timeline.Window()).mediaItem,
checkNotNull(currentTracks));
usesDerivedMediaMetadata = true;
}
}
if (builder.playerError != null) {
@ -1092,6 +1094,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
this.hasPositionDiscontinuity = builder.hasPositionDiscontinuity;
this.positionDiscontinuityReason = builder.positionDiscontinuityReason;
this.discontinuityPositionMs = builder.discontinuityPositionMs;
this.usesDerivedMediaMetadata = usesDerivedMediaMetadata;
}
/** Returns a {@link Builder} pre-populated with the current state values. */
@ -1790,9 +1793,9 @@ public abstract class SimpleBasePlayer extends BasePlayer {
return this.uid.equals(mediaItemData.uid)
&& this.tracks.equals(mediaItemData.tracks)
&& this.mediaItem.equals(mediaItemData.mediaItem)
&& Util.areEqual(this.mediaMetadata, mediaItemData.mediaMetadata)
&& Util.areEqual(this.manifest, mediaItemData.manifest)
&& Util.areEqual(this.liveConfiguration, mediaItemData.liveConfiguration)
&& Objects.equals(this.mediaMetadata, mediaItemData.mediaMetadata)
&& Objects.equals(this.manifest, mediaItemData.manifest)
&& Objects.equals(this.liveConfiguration, mediaItemData.liveConfiguration)
&& this.presentationStartTimeMs == mediaItemData.presentationStartTimeMs
&& this.windowStartTimeMs == mediaItemData.windowStartTimeMs
&& this.elapsedRealtimeEpochOffsetMs == mediaItemData.elapsedRealtimeEpochOffsetMs
@ -2069,7 +2072,21 @@ public abstract class SimpleBasePlayer extends BasePlayer {
}
}
/** A supplier for a position. */
/**
* A supplier for a position.
*
* <p>Convenience methods and classes for creating position suppliers:
*
* <ul>
* <li>Use {@link #getConstant} for constant or non-moving positions.
* <li>Use {@link #getExtrapolating} for positions advancing with the system clock from a
* provided start time.
* <li>Use {@link LivePositionSupplier} for positions that can be directly obtained from a live
* system. Note that these suppliers should be {@linkplain LivePositionSupplier#disconnect
* disconnected} from the live source as soon as the position is no longer valid, for
* example after a position discontinuity.
* </ul>
*/
protected interface PositionSupplier {
/** An instance returning a constant position of zero. */
@ -2102,6 +2119,48 @@ public abstract class SimpleBasePlayer extends BasePlayer {
long get();
}
/**
* A {@link PositionSupplier} connected to a live provider that returns a new value on each
* invocation until it is {@linkplain #disconnect disconnected} from the live source.
*
* <p>The recommended usage of this class is to create a new instance connected to the live source
* and keep returning this instance as long as the position source is still valid. As soon as the
* position source becomes invalid, for example when handling a position discontinuity, call
* {@link #disconnect} with the final position that will be returned for all future invocations.
*/
protected static final class LivePositionSupplier implements PositionSupplier {
private final PositionSupplier livePosition;
private long finalValue;
/**
* Creates the live position supplier.
*
* @param livePosition The function returning the live position.
*/
public LivePositionSupplier(PositionSupplier livePosition) {
this.livePosition = livePosition;
this.finalValue = C.TIME_UNSET;
}
/**
* Disconnects the position supplier from the live source.
*
* <p>All future invocations of {@link #get()} will return the provided final position.
*
* @param finalValue The final position value.
*/
public void disconnect(long finalValue) {
this.finalValue = finalValue;
}
@Override
public long get() {
return finalValue != C.TIME_UNSET ? finalValue : livePosition.get();
}
}
/**
* Position difference threshold below which we do not automatically report a position
* discontinuity, in milliseconds.
@ -2450,8 +2509,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
}
@Override
@VisibleForTesting(otherwise = PROTECTED)
public final void seekTo(
protected final void seekTo(
int mediaItemIndex,
long positionMs,
@Player.Command int seekCommand,
@ -3402,7 +3460,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
* index is in the range {@code fromIndex} &lt; {@code toIndex} &lt;= {@link
* #getMediaItemCount()}.
* @param newIndex The new index of the first moved item. The index is in the range {@code 0}
* &lt;= {@code newIndex} &lt; {@link #getMediaItemCount() - (toIndex - fromIndex)}.
* &lt;= {@code newIndex} &lt;= {@link #getMediaItemCount() - (toIndex - fromIndex)}.
* @return A {@link ListenableFuture} indicating the completion of all immediate {@link State}
* changes caused by this call.
*/
@ -3417,9 +3475,9 @@ public abstract class SimpleBasePlayer extends BasePlayer {
* <p>Will only be called if {@link Player#COMMAND_CHANGE_MEDIA_ITEMS} is available.
*
* @param fromIndex The start index of the items to replace. The index is in the range 0 &lt;=
* {@code fromIndex} &lt; {@link #getMediaItemCount()}.
* {@code fromIndex} &lt;= {@link #getMediaItemCount()}.
* @param toIndex The index of the first item not to be replaced (exclusive). The index is in the
* range {@code fromIndex} &lt; {@code toIndex} &lt;= {@link #getMediaItemCount()}.
* range {@code fromIndex} &lt;= {@code toIndex} &lt;= {@link #getMediaItemCount()}.
* @param mediaItems The media items to replace the specified range with.
* @return A {@link ListenableFuture} indicating the completion of all immediate {@link State}
* changes caused by this call.
@ -3428,6 +3486,9 @@ public abstract class SimpleBasePlayer extends BasePlayer {
protected ListenableFuture<?> handleReplaceMediaItems(
int fromIndex, int toIndex, List<MediaItem> mediaItems) {
ListenableFuture<?> addFuture = handleAddMediaItems(toIndex, mediaItems);
if (fromIndex == toIndex) {
return addFuture;
}
ListenableFuture<?> removeFuture = handleRemoveMediaItems(fromIndex, toIndex);
return Util.transformFutureAsync(addFuture, unused -> removeFuture);
}
@ -3561,7 +3622,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
Player.EVENT_MEDIA_ITEM_TRANSITION,
listener -> listener.onMediaItemTransition(mediaItem, mediaItemTransitionReason));
}
if (!Util.areEqual(previousState.playerError, newState.playerError)) {
if (!Objects.equals(previousState.playerError, newState.playerError)) {
listeners.queueEvent(
Player.EVENT_PLAYER_ERROR,
listener -> listener.onPlayerErrorChanged(newState.playerError));
@ -4008,14 +4069,10 @@ public abstract class SimpleBasePlayer extends BasePlayer {
}
// Only mark changes within the current item as a transition if we are repeating automatically
// or via a seek to next/previous.
if (positionDiscontinuityReason == DISCONTINUITY_REASON_AUTO_TRANSITION) {
if ((getContentPositionMsInternal(previousState, window)
> getContentPositionMsInternal(newState, window))
|| (newState.hasPositionDiscontinuity
&& newState.discontinuityPositionMs == C.TIME_UNSET
&& isRepeatingCurrentItem)) {
return MEDIA_ITEM_TRANSITION_REASON_REPEAT;
}
if (positionDiscontinuityReason == DISCONTINUITY_REASON_AUTO_TRANSITION
&& getContentPositionMsInternal(previousState, window)
> getContentPositionMsInternal(newState, window)) {
return MEDIA_ITEM_TRANSITION_REASON_REPEAT;
}
if (positionDiscontinuityReason == DISCONTINUITY_REASON_SEEK && isRepeatingCurrentItem) {
return MEDIA_ITEM_TRANSITION_REASON_SEEK;

View File

@ -23,7 +23,7 @@ import androidx.annotation.IntRange;
import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.base.Objects;
import java.util.Objects;
/** A rating expressed as a fractional number of stars. */
public final class StarRating extends Rating {
@ -84,7 +84,7 @@ public final class StarRating extends Rating {
@Override
public int hashCode() {
return Objects.hashCode(maxStars, starRating);
return Objects.hash(maxStars, starRating);
}
@Override

View File

@ -21,7 +21,7 @@ import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.base.Objects;
import java.util.Objects;
/** A rating expressed as "thumbs up" or "thumbs down". */
public final class ThumbRating extends Rating {
@ -57,7 +57,7 @@ public final class ThumbRating extends Rating {
@Override
public int hashCode() {
return Objects.hashCode(rated, isThumbsUp);
return Objects.hash(rated, isThumbsUp);
}
@Override

View File

@ -36,6 +36,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.InlineMe;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
@ -371,10 +372,10 @@ public abstract class Timeline {
return false;
}
Window that = (Window) obj;
return Util.areEqual(uid, that.uid)
&& Util.areEqual(mediaItem, that.mediaItem)
&& Util.areEqual(manifest, that.manifest)
&& Util.areEqual(liveConfiguration, that.liveConfiguration)
return Objects.equals(uid, that.uid)
&& Objects.equals(mediaItem, that.mediaItem)
&& Objects.equals(manifest, that.manifest)
&& Objects.equals(liveConfiguration, that.liveConfiguration)
&& presentationStartTimeMs == that.presentationStartTimeMs
&& windowStartTimeMs == that.windowStartTimeMs
&& elapsedRealtimeEpochOffsetMs == that.elapsedRealtimeEpochOffsetMs
@ -871,13 +872,13 @@ public abstract class Timeline {
return false;
}
Period that = (Period) obj;
return Util.areEqual(id, that.id)
&& Util.areEqual(uid, that.uid)
return Objects.equals(id, that.id)
&& Objects.equals(uid, that.uid)
&& windowIndex == that.windowIndex
&& durationUs == that.durationUs
&& positionInWindowUs == that.positionInWindowUs
&& isPlaceholder == that.isPlaceholder
&& Util.areEqual(adPlaybackState, that.adPlaybackState);
&& Objects.equals(adPlaybackState, that.adPlaybackState);
}
@Override

View File

@ -161,6 +161,11 @@ public final class TrackGroup {
return id.equals(other.id) && Arrays.equals(formats, other.formats);
}
@Override
public String toString() {
return id + ": " + Arrays.toString(formats);
}
private static final String FIELD_FORMATS = Util.intToStringMaxRadix(0);
private static final String FIELD_ID = Util.intToStringMaxRadix(1);
@ -169,7 +174,7 @@ public final class TrackGroup {
Bundle bundle = new Bundle();
ArrayList<Bundle> arrayList = new ArrayList<>(formats.length);
for (Format format : formats) {
arrayList.add(format.toBundle(/* excludeMetadata= */ true));
arrayList.add(format.toBundle());
}
bundle.putParcelableArrayList(FIELD_FORMATS, arrayList);
bundle.putString(FIELD_ID, id);

View File

@ -22,9 +22,7 @@ import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.content.Context;
import android.graphics.Point;
import android.os.Bundle;
import android.os.Looper;
import android.view.accessibility.CaptioningManager;
import androidx.annotation.CallSuper;
import androidx.annotation.IntDef;
@ -37,6 +35,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.Ints;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.InlineMe;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@ -44,12 +43,10 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.checkerframework.checker.initialization.qual.UnknownInitialization;
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
// LINT.IfChange(javadoc)
/**
* Parameters for controlling track selection.
*
@ -88,8 +85,10 @@ public class TrackSelectionParameters {
private int minVideoBitrate;
private int viewportWidth;
private int viewportHeight;
private boolean isViewportSizeLimitedByPhysicalDisplaySize;
private boolean viewportOrientationMayChange;
private ImmutableList<String> preferredVideoMimeTypes;
private ImmutableList<String> preferredVideoLanguages;
private @C.RoleFlags int preferredVideoRoleFlags;
// Audio
private ImmutableList<String> preferredAudioLanguages;
@ -101,6 +100,7 @@ public class TrackSelectionParameters {
// Text
private ImmutableList<String> preferredTextLanguages;
private @C.RoleFlags int preferredTextRoleFlags;
private boolean usePreferredTextLanguagesAndRoleFlagsFromCaptioningManager;
private @C.SelectionFlags int ignoredTextSelectionFlags;
private boolean selectUndeterminedTextLanguage;
// Image
@ -111,12 +111,7 @@ public class TrackSelectionParameters {
private HashMap<TrackGroup, TrackSelectionOverride> overrides;
private HashSet<@C.TrackType Integer> disabledTrackTypes;
/**
* @deprecated {@link Context} constraints will not be set using this constructor. Use {@link
* #Builder(Context)} instead.
*/
@UnstableApi
@Deprecated
/** Creates a builder with default initial values. */
public Builder() {
// Video
maxVideoWidth = Integer.MAX_VALUE;
@ -125,8 +120,10 @@ public class TrackSelectionParameters {
maxVideoBitrate = Integer.MAX_VALUE;
viewportWidth = Integer.MAX_VALUE;
viewportHeight = Integer.MAX_VALUE;
isViewportSizeLimitedByPhysicalDisplaySize = true;
viewportOrientationMayChange = true;
preferredVideoMimeTypes = ImmutableList.of();
preferredVideoLanguages = ImmutableList.of();
preferredVideoRoleFlags = 0;
// Audio
preferredAudioLanguages = ImmutableList.of();
@ -138,6 +135,7 @@ public class TrackSelectionParameters {
// Text
preferredTextLanguages = ImmutableList.of();
preferredTextRoleFlags = 0;
usePreferredTextLanguagesAndRoleFlagsFromCaptioningManager = true;
ignoredTextSelectionFlags = 0;
selectUndeterminedTextLanguage = false;
// Image
@ -150,15 +148,12 @@ public class TrackSelectionParameters {
}
/**
* Creates a builder with default initial values.
*
* @param context Any context.
* @deprecated Use {@link #Builder()} instead.
*/
@SuppressWarnings({"deprecation", "method.invocation"}) // Methods invoked are setter only.
@Deprecated
@InlineMe(replacement = "this()")
public Builder(Context context) {
this();
setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettings(context);
setViewportSizeToPhysicalDisplaySize(context, /* viewportOrientationMayChange= */ true);
}
/** Creates a builder with the initial values specified in {@code initialValues}. */
@ -171,44 +166,42 @@ public class TrackSelectionParameters {
@UnstableApi
protected Builder(Bundle bundle) {
// Video
maxVideoWidth = bundle.getInt(FIELD_MAX_VIDEO_WIDTH, DEFAULT_WITHOUT_CONTEXT.maxVideoWidth);
maxVideoHeight =
bundle.getInt(FIELD_MAX_VIDEO_HEIGHT, DEFAULT_WITHOUT_CONTEXT.maxVideoHeight);
maxVideoFrameRate =
bundle.getInt(FIELD_MAX_VIDEO_FRAMERATE, DEFAULT_WITHOUT_CONTEXT.maxVideoFrameRate);
maxVideoBitrate =
bundle.getInt(FIELD_MAX_VIDEO_BITRATE, DEFAULT_WITHOUT_CONTEXT.maxVideoBitrate);
minVideoWidth = bundle.getInt(FIELD_MIN_VIDEO_WIDTH, DEFAULT_WITHOUT_CONTEXT.minVideoWidth);
minVideoHeight =
bundle.getInt(FIELD_MIN_VIDEO_HEIGHT, DEFAULT_WITHOUT_CONTEXT.minVideoHeight);
minVideoFrameRate =
bundle.getInt(FIELD_MIN_VIDEO_FRAMERATE, DEFAULT_WITHOUT_CONTEXT.minVideoFrameRate);
minVideoBitrate =
bundle.getInt(FIELD_MIN_VIDEO_BITRATE, DEFAULT_WITHOUT_CONTEXT.minVideoBitrate);
viewportWidth = bundle.getInt(FIELD_VIEWPORT_WIDTH, DEFAULT_WITHOUT_CONTEXT.viewportWidth);
viewportHeight = bundle.getInt(FIELD_VIEWPORT_HEIGHT, DEFAULT_WITHOUT_CONTEXT.viewportHeight);
maxVideoWidth = bundle.getInt(FIELD_MAX_VIDEO_WIDTH, DEFAULT.maxVideoWidth);
maxVideoHeight = bundle.getInt(FIELD_MAX_VIDEO_HEIGHT, DEFAULT.maxVideoHeight);
maxVideoFrameRate = bundle.getInt(FIELD_MAX_VIDEO_FRAMERATE, DEFAULT.maxVideoFrameRate);
maxVideoBitrate = bundle.getInt(FIELD_MAX_VIDEO_BITRATE, DEFAULT.maxVideoBitrate);
minVideoWidth = bundle.getInt(FIELD_MIN_VIDEO_WIDTH, DEFAULT.minVideoWidth);
minVideoHeight = bundle.getInt(FIELD_MIN_VIDEO_HEIGHT, DEFAULT.minVideoHeight);
minVideoFrameRate = bundle.getInt(FIELD_MIN_VIDEO_FRAMERATE, DEFAULT.minVideoFrameRate);
minVideoBitrate = bundle.getInt(FIELD_MIN_VIDEO_BITRATE, DEFAULT.minVideoBitrate);
viewportWidth = bundle.getInt(FIELD_VIEWPORT_WIDTH, DEFAULT.viewportWidth);
viewportHeight = bundle.getInt(FIELD_VIEWPORT_HEIGHT, DEFAULT.viewportHeight);
isViewportSizeLimitedByPhysicalDisplaySize =
viewportWidth == Integer.MAX_VALUE
&& viewportHeight == Integer.MAX_VALUE
&& bundle.getBoolean(
FIELD_IS_VIEWPORT_SIZE_LIMITED_BY_PHYSICAL_DISPLAY_SIZE,
DEFAULT.isViewportSizeLimitedByPhysicalDisplaySize);
viewportOrientationMayChange =
bundle.getBoolean(
FIELD_VIEWPORT_ORIENTATION_MAY_CHANGE,
DEFAULT_WITHOUT_CONTEXT.viewportOrientationMayChange);
FIELD_VIEWPORT_ORIENTATION_MAY_CHANGE, DEFAULT.viewportOrientationMayChange);
preferredVideoMimeTypes =
ImmutableList.copyOf(
firstNonNull(bundle.getStringArray(FIELD_PREFERRED_VIDEO_MIMETYPES), new String[0]));
preferredVideoLanguages =
ImmutableList.copyOf(
firstNonNull(bundle.getStringArray(FIELD_PREFERRED_VIDEO_LANGUAGES), new String[0]));
preferredVideoRoleFlags =
bundle.getInt(
FIELD_PREFERRED_VIDEO_ROLE_FLAGS, DEFAULT_WITHOUT_CONTEXT.preferredVideoRoleFlags);
bundle.getInt(FIELD_PREFERRED_VIDEO_ROLE_FLAGS, DEFAULT.preferredVideoRoleFlags);
// Audio
String[] preferredAudioLanguages1 =
firstNonNull(bundle.getStringArray(FIELD_PREFERRED_AUDIO_LANGUAGES), new String[0]);
preferredAudioLanguages = normalizeLanguageCodes(preferredAudioLanguages1);
preferredAudioRoleFlags =
bundle.getInt(
FIELD_PREFERRED_AUDIO_ROLE_FLAGS, DEFAULT_WITHOUT_CONTEXT.preferredAudioRoleFlags);
bundle.getInt(FIELD_PREFERRED_AUDIO_ROLE_FLAGS, DEFAULT.preferredAudioRoleFlags);
maxAudioChannelCount =
bundle.getInt(
FIELD_MAX_AUDIO_CHANNEL_COUNT, DEFAULT_WITHOUT_CONTEXT.maxAudioChannelCount);
maxAudioBitrate =
bundle.getInt(FIELD_MAX_AUDIO_BITRATE, DEFAULT_WITHOUT_CONTEXT.maxAudioBitrate);
bundle.getInt(FIELD_MAX_AUDIO_CHANNEL_COUNT, DEFAULT.maxAudioChannelCount);
maxAudioBitrate = bundle.getInt(FIELD_MAX_AUDIO_BITRATE, DEFAULT.maxAudioBitrate);
preferredAudioMimeTypes =
ImmutableList.copyOf(
firstNonNull(bundle.getStringArray(FIELD_PREFERRED_AUDIO_MIME_TYPES), new String[0]));
@ -218,29 +211,29 @@ public class TrackSelectionParameters {
normalizeLanguageCodes(
firstNonNull(bundle.getStringArray(FIELD_PREFERRED_TEXT_LANGUAGES), new String[0]));
preferredTextRoleFlags =
bundle.getInt(
FIELD_PREFERRED_TEXT_ROLE_FLAGS, DEFAULT_WITHOUT_CONTEXT.preferredTextRoleFlags);
bundle.getInt(FIELD_PREFERRED_TEXT_ROLE_FLAGS, DEFAULT.preferredTextRoleFlags);
usePreferredTextLanguagesAndRoleFlagsFromCaptioningManager =
preferredTextLanguages.isEmpty()
&& preferredTextRoleFlags == 0
&& bundle.getBoolean(
FIELD_USE_PREFERRED_TEXT_LANGUAGES_AND_ROLE_FLAGS_FROM_CAPTIONING_MANAGER,
DEFAULT.usePreferredTextLanguagesAndRoleFlagsFromCaptioningManager);
ignoredTextSelectionFlags =
bundle.getInt(
FIELD_IGNORED_TEXT_SELECTION_FLAGS,
DEFAULT_WITHOUT_CONTEXT.ignoredTextSelectionFlags);
bundle.getInt(FIELD_IGNORED_TEXT_SELECTION_FLAGS, DEFAULT.ignoredTextSelectionFlags);
selectUndeterminedTextLanguage =
bundle.getBoolean(
FIELD_SELECT_UNDETERMINED_TEXT_LANGUAGE,
DEFAULT_WITHOUT_CONTEXT.selectUndeterminedTextLanguage);
FIELD_SELECT_UNDETERMINED_TEXT_LANGUAGE, DEFAULT.selectUndeterminedTextLanguage);
// Image
isPrioritizeImageOverVideoEnabled =
bundle.getBoolean(
FIELD_IS_PREFER_IMAGE_OVER_VIDEO_ENABLED,
DEFAULT_WITHOUT_CONTEXT.isPrioritizeImageOverVideoEnabled);
FIELD_IS_PREFER_IMAGE_OVER_VIDEO_ENABLED, DEFAULT.isPrioritizeImageOverVideoEnabled);
// General
forceLowestBitrate =
bundle.getBoolean(FIELD_FORCE_LOWEST_BITRATE, DEFAULT_WITHOUT_CONTEXT.forceLowestBitrate);
bundle.getBoolean(FIELD_FORCE_LOWEST_BITRATE, DEFAULT.forceLowestBitrate);
forceHighestSupportedBitrate =
bundle.getBoolean(
FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE,
DEFAULT_WITHOUT_CONTEXT.forceHighestSupportedBitrate);
FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE, DEFAULT.forceHighestSupportedBitrate);
@Nullable
List<Bundle> overrideBundleList = bundle.getParcelableArrayList(FIELD_SELECTION_OVERRIDES);
List<TrackSelectionOverride> overrideList =
@ -284,6 +277,7 @@ public class TrackSelectionParameters {
/** Overrides the value of the builder with the value of {@link TrackSelectionParameters}. */
@EnsuresNonNull({
"preferredVideoMimeTypes",
"preferredVideoLanguages",
"preferredAudioLanguages",
"preferredAudioMimeTypes",
"audioOffloadPreferences",
@ -303,8 +297,11 @@ public class TrackSelectionParameters {
minVideoBitrate = parameters.minVideoBitrate;
viewportWidth = parameters.viewportWidth;
viewportHeight = parameters.viewportHeight;
isViewportSizeLimitedByPhysicalDisplaySize =
parameters.isViewportSizeLimitedByPhysicalDisplaySize;
viewportOrientationMayChange = parameters.viewportOrientationMayChange;
preferredVideoMimeTypes = parameters.preferredVideoMimeTypes;
preferredVideoLanguages = parameters.preferredVideoLanguages;
preferredVideoRoleFlags = parameters.preferredVideoRoleFlags;
// Audio
preferredAudioLanguages = parameters.preferredAudioLanguages;
@ -316,6 +313,8 @@ public class TrackSelectionParameters {
// Text
preferredTextLanguages = parameters.preferredTextLanguages;
preferredTextRoleFlags = parameters.preferredTextRoleFlags;
usePreferredTextLanguagesAndRoleFlagsFromCaptioningManager =
parameters.usePreferredTextLanguagesAndRoleFlagsFromCaptioningManager;
ignoredTextSelectionFlags = parameters.ignoredTextSelectionFlags;
selectUndeterminedTextLanguage = parameters.selectUndeterminedTextLanguage;
// Image
@ -434,20 +433,31 @@ public class TrackSelectionParameters {
}
/**
* Equivalent to calling {@link #setViewportSize(int, int, boolean)} with the viewport size
* obtained from {@link Util#getCurrentDisplayModeSize(Context)}.
* Sets whether the viewport size should be assumed to the physical display size if no other
* specific viewport size constraint is specified. Constrains video track selections for
* adaptive content so that only tracks suitable for the viewport are selected.
*
* @param context Any context.
* @param viewportOrientationMayChange Whether the viewport orientation may change during
* playback.
* @return This builder.
*/
@CanIgnoreReturnValue
public Builder setViewportSizeToPhysicalDisplaySize(boolean viewportOrientationMayChange) {
this.isViewportSizeLimitedByPhysicalDisplaySize = true;
this.viewportOrientationMayChange = viewportOrientationMayChange;
this.viewportHeight = Integer.MAX_VALUE;
this.viewportWidth = Integer.MAX_VALUE;
return this;
}
/**
* @deprecated Use {@link #setViewportSizeToPhysicalDisplaySize(boolean)} instead.
*/
@Deprecated
@CanIgnoreReturnValue
public Builder setViewportSizeToPhysicalDisplaySize(
Context context, boolean viewportOrientationMayChange) {
// Assume the viewport is fullscreen.
Point viewportSize = Util.getCurrentDisplayModeSize(context);
return setViewportSize(viewportSize.x, viewportSize.y, viewportOrientationMayChange);
return setViewportSizeToPhysicalDisplaySize(viewportOrientationMayChange);
}
/**
@ -477,6 +487,7 @@ public class TrackSelectionParameters {
this.viewportWidth = viewportWidth;
this.viewportHeight = viewportHeight;
this.viewportOrientationMayChange = viewportOrientationMayChange;
this.isViewportSizeLimitedByPhysicalDisplaySize = false;
return this;
}
@ -504,6 +515,36 @@ public class TrackSelectionParameters {
return this;
}
/**
* Sets the preferred language for video tracks.
*
* @param preferredVideoLanguage Preferred video language as an IETF BCP 47 conformant tag, or
* {@code null} to express no language preference for video track selection.
* @return This builder.
*/
@UnstableApi
@CanIgnoreReturnValue
public Builder setPreferredVideoLanguage(@Nullable String preferredVideoLanguage) {
return preferredVideoLanguage == null
? setPreferredVideoLanguages()
: setPreferredVideoLanguages(preferredVideoLanguage);
}
/**
* Sets the preferred languages for video tracks.
*
* @param preferredVideoLanguages Preferred video languages as IETF BCP 47 conformant tags in
* order of preference, or an empty array to express no language preference for video track
* selection.
* @return This builder.
*/
@UnstableApi
@CanIgnoreReturnValue
public Builder setPreferredVideoLanguages(String... preferredVideoLanguages) {
this.preferredVideoLanguages = normalizeLanguageCodes(preferredVideoLanguages);
return this;
}
/**
* Sets the preferred {@link C.RoleFlags} for video tracks.
*
@ -620,33 +661,29 @@ public class TrackSelectionParameters {
// Text
/**
* Sets the preferred language and role flags for text tracks based on the accessibility
* settings of {@link CaptioningManager}.
* Sets whether the preferred languages and the preferred role flags for text tracks should be
* set according the {@link CaptioningManager} preferences, if enabled in the system settings
* and no other explicit language or role flag preferences are specified.
*
* <p>Does nothing when the {@link CaptioningManager} is disabled.
*
* @param context A {@link Context}.
* @return This builder.
*/
@CanIgnoreReturnValue
public Builder setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettings() {
usePreferredTextLanguagesAndRoleFlagsFromCaptioningManager = true;
preferredTextLanguages = ImmutableList.of();
preferredTextRoleFlags = 0;
return this;
}
/**
* @deprecated Use {@link #setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettings()}
* instead.
*/
@Deprecated
@CanIgnoreReturnValue
public Builder setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettings(
Context context) {
if (Util.SDK_INT < 23 && Looper.myLooper() == null) {
// Android platform bug (pre-Marshmallow) that causes RuntimeExceptions when
// CaptioningService is instantiated from a non-Looper thread. See [internal: b/143779904].
return this;
}
CaptioningManager captioningManager =
(CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
if (captioningManager == null || !captioningManager.isEnabled()) {
return this;
}
preferredTextRoleFlags = C.ROLE_FLAG_CAPTION | C.ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND;
Locale preferredLocale = captioningManager.getLocale();
if (preferredLocale != null) {
preferredTextLanguages = ImmutableList.of(Util.getLocaleLanguageTag(preferredLocale));
}
return this;
return setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettings();
}
/**
@ -673,6 +710,7 @@ public class TrackSelectionParameters {
@CanIgnoreReturnValue
public Builder setPreferredTextLanguages(String... preferredTextLanguages) {
this.preferredTextLanguages = normalizeLanguageCodes(preferredTextLanguages);
this.usePreferredTextLanguagesAndRoleFlagsFromCaptioningManager = false;
return this;
}
@ -685,6 +723,7 @@ public class TrackSelectionParameters {
@CanIgnoreReturnValue
public Builder setPreferredTextRoleFlags(@C.RoleFlags int preferredTextRoleFlags) {
this.preferredTextRoleFlags = preferredTextRoleFlags;
this.usePreferredTextLanguagesAndRoleFlagsFromCaptioningManager = false;
return this;
}
@ -1043,35 +1082,21 @@ public class TrackSelectionParameters {
}
}
/**
* An instance with default values, except those obtained from the {@link Context}.
*
* <p>If possible, use {@link #getDefaults(Context)} instead.
*
* <p>This instance will not have the following settings:
*
* <ul>
* <li>{@link Builder#setViewportSizeToPhysicalDisplaySize(Context, boolean) Viewport
* constraints} configured for the primary display.
* <li>{@link Builder#setPreferredTextLanguageAndRoleFlagsToCaptioningManagerSettings(Context)
* Preferred text language and role flags} configured to the accessibility settings of
* {@link CaptioningManager}.
* </ul>
*/
@UnstableApi
@SuppressWarnings("deprecation")
public static final TrackSelectionParameters DEFAULT_WITHOUT_CONTEXT = new Builder().build();
/** An instance with default parameters. */
@UnstableApi public static final TrackSelectionParameters DEFAULT = new Builder().build();
/**
* @deprecated This instance is not configured using {@link Context} constraints. Use {@link
* #getDefaults(Context)} instead.
* @deprecated Use {@link #DEFAULT} instead.
*/
@UnstableApi @Deprecated
public static final TrackSelectionParameters DEFAULT = DEFAULT_WITHOUT_CONTEXT;
public static final TrackSelectionParameters DEFAULT_WITHOUT_CONTEXT = DEFAULT;
/** Returns an instance configured with default values. */
/**
* @deprecated Use {@link #DEFAULT} instead.
*/
@Deprecated
public static TrackSelectionParameters getDefaults(Context context) {
return new Builder(context).build();
return DEFAULT;
}
// Video
@ -1135,6 +1160,13 @@ public class TrackSelectionParameters {
*/
public final int viewportHeight;
/**
* Whether the viewport size should be assumed to the physical display size if no other specific
* viewport size constraint is specified. Constrains video track selections for adaptive content
* so that only tracks suitable for the viewport are selected. The default value is {@code true}.
*/
public final boolean isViewportSizeLimitedByPhysicalDisplaySize;
/**
* Whether the viewport orientation may change during playback. Constrains video track selections
* for adaptive content so that only tracks suitable for the viewport are selected. The default
@ -1148,6 +1180,11 @@ public class TrackSelectionParameters {
*/
public final ImmutableList<String> preferredVideoMimeTypes;
/**
* The preferred languages for video tracks as IETF BCP 47 conformant tags in order of preference.
*/
@UnstableApi public final ImmutableList<String> preferredVideoLanguages;
/**
* The preferred {@link C.RoleFlags} for video tracks. {@code 0} selects the default track if
* there is one, or the first track if there's no default. The default value is {@code 0}.
@ -1196,19 +1233,24 @@ public class TrackSelectionParameters {
/**
* The preferred languages for text tracks as IETF BCP 47 conformant tags in order of preference.
* An empty list selects the default track if there is one, or no track otherwise. The default
* value is an empty list, or the language of the accessibility {@link CaptioningManager} if
* enabled.
* value is an empty list.
*/
public final ImmutableList<String> preferredTextLanguages;
/**
* The preferred {@link C.RoleFlags} for text tracks. {@code 0} selects the default track if there
* is one, or no track otherwise. The default value is {@code 0}, or {@link C#ROLE_FLAG_SUBTITLE}
* | {@link C#ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND} if the accessibility {@link CaptioningManager}
* is enabled.
* is one, or no track otherwise. The default value is {@code 0}.
*/
public final @C.RoleFlags int preferredTextRoleFlags;
/**
* Whether the preferred languages and the preferred role flags for text tracks should be set
* according the {@link CaptioningManager} preferences, if enabled in the system settings and no
* other explicit language or role flag preferences are specified. The default value is {@code
* true}.
*/
public final boolean usePreferredTextLanguagesAndRoleFlagsFromCaptioningManager;
/**
* Bitmask of selection flags that are ignored for text track selections. See {@link
* C.SelectionFlags}. The default value is {@code 0} (i.e., no flags are ignored).
@ -1265,8 +1307,11 @@ public class TrackSelectionParameters {
this.minVideoBitrate = builder.minVideoBitrate;
this.viewportWidth = builder.viewportWidth;
this.viewportHeight = builder.viewportHeight;
this.isViewportSizeLimitedByPhysicalDisplaySize =
builder.isViewportSizeLimitedByPhysicalDisplaySize;
this.viewportOrientationMayChange = builder.viewportOrientationMayChange;
this.preferredVideoMimeTypes = builder.preferredVideoMimeTypes;
this.preferredVideoLanguages = builder.preferredVideoLanguages;
this.preferredVideoRoleFlags = builder.preferredVideoRoleFlags;
// Audio
this.preferredAudioLanguages = builder.preferredAudioLanguages;
@ -1278,6 +1323,8 @@ public class TrackSelectionParameters {
// Text
this.preferredTextLanguages = builder.preferredTextLanguages;
this.preferredTextRoleFlags = builder.preferredTextRoleFlags;
this.usePreferredTextLanguagesAndRoleFlagsFromCaptioningManager =
builder.usePreferredTextLanguagesAndRoleFlagsFromCaptioningManager;
this.ignoredTextSelectionFlags = builder.ignoredTextSelectionFlags;
this.selectUndeterminedTextLanguage = builder.selectUndeterminedTextLanguage;
// Image
@ -1316,7 +1363,10 @@ public class TrackSelectionParameters {
&& viewportOrientationMayChange == other.viewportOrientationMayChange
&& viewportWidth == other.viewportWidth
&& viewportHeight == other.viewportHeight
&& isViewportSizeLimitedByPhysicalDisplaySize
== other.isViewportSizeLimitedByPhysicalDisplaySize
&& preferredVideoMimeTypes.equals(other.preferredVideoMimeTypes)
&& preferredVideoLanguages.equals(other.preferredVideoLanguages)
&& preferredVideoRoleFlags == other.preferredVideoRoleFlags
// Audio
&& preferredAudioLanguages.equals(other.preferredAudioLanguages)
@ -1328,6 +1378,8 @@ public class TrackSelectionParameters {
// Text
&& preferredTextLanguages.equals(other.preferredTextLanguages)
&& preferredTextRoleFlags == other.preferredTextRoleFlags
&& usePreferredTextLanguagesAndRoleFlagsFromCaptioningManager
== other.usePreferredTextLanguagesAndRoleFlagsFromCaptioningManager
&& ignoredTextSelectionFlags == other.ignoredTextSelectionFlags
&& selectUndeterminedTextLanguage == other.selectUndeterminedTextLanguage
// Image
@ -1354,7 +1406,9 @@ public class TrackSelectionParameters {
result = 31 * result + (viewportOrientationMayChange ? 1 : 0);
result = 31 * result + viewportWidth;
result = 31 * result + viewportHeight;
result = 31 * result + (isViewportSizeLimitedByPhysicalDisplaySize ? 1 : 0);
result = 31 * result + preferredVideoMimeTypes.hashCode();
result = 31 * result + preferredVideoLanguages.hashCode();
result = 31 * result + preferredVideoRoleFlags;
// Audio
result = 31 * result + preferredAudioLanguages.hashCode();
@ -1366,6 +1420,7 @@ public class TrackSelectionParameters {
// Text
result = 31 * result + preferredTextLanguages.hashCode();
result = 31 * result + preferredTextRoleFlags;
result = 31 * result + (usePreferredTextLanguagesAndRoleFlagsFromCaptioningManager ? 1 : 0);
result = 31 * result + ignoredTextSelectionFlags;
result = 31 * result + (selectUndeterminedTextLanguage ? 1 : 0);
// Image
@ -1410,6 +1465,12 @@ public class TrackSelectionParameters {
private static final String FIELD_AUDIO_OFFLOAD_PREFERENCES = Util.intToStringMaxRadix(30);
private static final String FIELD_IS_PREFER_IMAGE_OVER_VIDEO_ENABLED =
Util.intToStringMaxRadix(31);
private static final String FIELD_PREFERRED_VIDEO_LANGUAGES = Util.intToStringMaxRadix(32);
private static final String FIELD_IS_VIEWPORT_SIZE_LIMITED_BY_PHYSICAL_DISPLAY_SIZE =
Util.intToStringMaxRadix(33);
private static final String
FIELD_USE_PREFERRED_TEXT_LANGUAGES_AND_ROLE_FLAGS_FROM_CAPTIONING_MANAGER =
Util.intToStringMaxRadix(34);
/**
* Defines a minimum field ID value for subclasses to use when implementing {@link #toBundle()}
@ -1436,9 +1497,14 @@ public class TrackSelectionParameters {
bundle.putInt(FIELD_MIN_VIDEO_BITRATE, minVideoBitrate);
bundle.putInt(FIELD_VIEWPORT_WIDTH, viewportWidth);
bundle.putInt(FIELD_VIEWPORT_HEIGHT, viewportHeight);
bundle.putBoolean(
FIELD_IS_VIEWPORT_SIZE_LIMITED_BY_PHYSICAL_DISPLAY_SIZE,
isViewportSizeLimitedByPhysicalDisplaySize);
bundle.putBoolean(FIELD_VIEWPORT_ORIENTATION_MAY_CHANGE, viewportOrientationMayChange);
bundle.putStringArray(
FIELD_PREFERRED_VIDEO_MIMETYPES, preferredVideoMimeTypes.toArray(new String[0]));
bundle.putStringArray(
FIELD_PREFERRED_VIDEO_LANGUAGES, preferredVideoLanguages.toArray(new String[0]));
bundle.putInt(FIELD_PREFERRED_VIDEO_ROLE_FLAGS, preferredVideoRoleFlags);
// Audio
bundle.putStringArray(
@ -1452,6 +1518,9 @@ public class TrackSelectionParameters {
bundle.putStringArray(
FIELD_PREFERRED_TEXT_LANGUAGES, preferredTextLanguages.toArray(new String[0]));
bundle.putInt(FIELD_PREFERRED_TEXT_ROLE_FLAGS, preferredTextRoleFlags);
bundle.putBoolean(
FIELD_USE_PREFERRED_TEXT_LANGUAGES_AND_ROLE_FLAGS_FROM_CAPTIONING_MANAGER,
usePreferredTextLanguagesAndRoleFlagsFromCaptioningManager);
bundle.putInt(FIELD_IGNORED_TEXT_SELECTION_FLAGS, ignoredTextSelectionFlags);
bundle.putBoolean(FIELD_SELECT_UNDETERMINED_TEXT_LANGUAGE, selectUndeterminedTextLanguage);
bundle.putInt(FIELD_AUDIO_OFFLOAD_MODE_PREFERENCE, audioOffloadPreferences.audioOffloadMode);

View File

@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.effect;
package androidx.media3.common;
import androidx.media3.common.util.Size;
import androidx.media3.common.util.UnstableApi;
import java.util.List;
/** Settings for the {@link VideoCompositor}. */
/** Settings for the {@code VideoCompositor}. */
@UnstableApi
public interface VideoCompositorSettings {
// TODO: b/262694346 - Consider adding more features, like selecting a:
@ -45,7 +45,7 @@ public interface VideoCompositorSettings {
*/
@Override
public OverlaySettings getOverlaySettings(int inputId, long presentationTimeUs) {
return new OverlaySettings.Builder().build();
return new OverlaySettings() {};
}
};

View File

@ -84,8 +84,8 @@ public interface VideoFrameProcessor {
* Input frames come from the {@linkplain #getInputSurface input surface} and don't need to be
* {@linkplain #registerInputFrame registered} (unlike with {@link #INPUT_TYPE_SURFACE}).
*
* <p>Every frame must use the {@linkplain #registerInputStream(int, List, FrameInfo) input
* stream's registered} frame info. Also sets the surface's {@linkplain
* <p>Every frame must use the {@linkplain #registerInputStream input stream's registered} frame
* format. Also sets the surface's {@linkplain
* android.graphics.SurfaceTexture#setDefaultBufferSize(int, int) default buffer size}.
*/
int INPUT_TYPE_SURFACE_AUTOMATIC_FRAME_REGISTRATION = 4;
@ -131,8 +131,8 @@ public interface VideoFrameProcessor {
interface Listener {
/**
* Called when the {@link VideoFrameProcessor} finishes {@linkplain #registerInputStream(int,
* List, FrameInfo) registering an input stream}.
* Called when the {@link VideoFrameProcessor} finishes {@linkplain #registerInputStream
* registering an input stream}.
*
* <p>The {@link VideoFrameProcessor} is now ready to accept new input {@linkplain
* VideoFrameProcessor#registerInputFrame frames}, {@linkplain
@ -140,11 +140,11 @@ public interface VideoFrameProcessor {
* VideoFrameProcessor#queueInputTexture(int, long) textures}.
*
* @param inputType The {@link InputType} of the new input stream.
* @param format The {@link Format} of the new input stream.
* @param effects The list of {@link Effect effects} to apply to the new input stream.
* @param frameInfo The {@link FrameInfo} of the new input stream.
*/
default void onInputStreamRegistered(
@InputType int inputType, List<Effect> effects, FrameInfo frameInfo) {}
@InputType int inputType, Format format, List<Effect> effects) {}
/**
* Called when the output size changes.
@ -157,6 +157,14 @@ public interface VideoFrameProcessor {
*/
default void onOutputSizeChanged(int width, int height) {}
/**
* Called when the output frame rate changes.
*
* @param frameRate The output frame rate in frames per second, or {@link Format#NO_VALUE} if
* unknown.
*/
default void onOutputFrameRateChanged(float frameRate) {}
/**
* Called when an output frame with the given {@code presentationTimeUs} becomes available for
* rendering.
@ -196,8 +204,8 @@ public interface VideoFrameProcessor {
/**
* Provides an input {@link Bitmap} to the {@link VideoFrameProcessor}.
*
* <p>Can be called many times after {@link #registerInputStream(int, List, FrameInfo) registering
* the input stream} to put multiple frames in the same input stream.
* <p>Can be called many times after {@link #registerInputStream registering the input stream} to
* put multiple frames in the same input stream.
*
* @param inputBitmap The {@link Bitmap} queued to the {@code VideoFrameProcessor}.
* @param timestampIterator A {@link TimestampIterator} generating the exact timestamps that the
@ -271,14 +279,20 @@ public interface VideoFrameProcessor {
* #queueInputTexture queued}.
*
* <p>This method blocks the calling thread until the previous calls to this method finish, that
* is when {@link Listener#onInputStreamRegistered(int, List, FrameInfo)} is called after the
* is when {@link Listener#onInputStreamRegistered(int, Format, List)} is called after the
* underlying processing pipeline has been adapted to the registered input stream.
*
* @param inputType The {@link InputType} of the new input stream.
* @param format The {@link Format} of the new input stream. The {@link Format#colorInfo}, the
* {@link Format#width}, the {@link Format#height} and the {@link
* Format#pixelWidthHeightRatio} must be set.
* @param effects The list of {@link Effect effects} to apply to the new input stream.
* @param frameInfo The {@link FrameInfo} of the new input stream.
* @param offsetToAddUs The offset that must be added to the frame presentation timestamps, in
* microseconds. This offset is not part of the input timestamps. It is added to the frame
* timestamps before processing, and is retained in the output timestamps.
*/
void registerInputStream(@InputType int inputType, List<Effect> effects, FrameInfo frameInfo);
void registerInputStream(
@InputType int inputType, Format format, List<Effect> effects, long offsetToAddUs);
/**
* Informs the {@code VideoFrameProcessor} that a frame will be queued to its {@linkplain
@ -287,11 +301,10 @@ public interface VideoFrameProcessor {
* <p>Must be called before rendering a frame to the input surface. The caller must not render
* frames to the {@linkplain #getInputSurface input surface} when {@code false} is returned.
*
* @return Whether the input frame was successfully registered. If {@link
* #registerInputStream(int, List, FrameInfo)} is called, this method returns {@code false}
* until {@link Listener#onInputStreamRegistered(int, List, FrameInfo)} is called. Otherwise,
* a return value of {@code false} indicates the {@code VideoFrameProcessor} is not ready to
* accept input.
* @return Whether the input frame was successfully registered. If {@link #registerInputStream} is
* called, this method returns {@code false} until {@link
* Listener#onInputStreamRegistered(int, Format, List)} is called. Otherwise, a return value
* of {@code false} indicates the {@code VideoFrameProcessor} is not ready to accept input.
* @throws UnsupportedOperationException If the {@code VideoFrameProcessor} does not accept
* {@linkplain #INPUT_TYPE_SURFACE surface input}.
* @throws IllegalStateException If called after {@link #signalEndOfInput()} or before {@link

Some files were not shown because too many files have changed in this diff Show More