MIME types are case-insensitive, but none of the many existing
comparisons across our code base take this into account. The
code can be made more robust by normalizing all MIME types at the
moment they are first set into a class/builder and adding toLowerCase
as part of the normalization.
Most concretely, this fixes an issue with playing HLS streams via
the IMA SDK where the stream MIME type is indicated with all lower
case "application/x-mpegurl", which failed the MIME type comparison
in DefaultMediaSourceFactory.
PiperOrigin-RevId: 582317261
BundledChunkExtractor creates a JpegExtractor or a PngExtractor if the
chunk's MIME type is JPEG or PNG respectively.
The JpegExtractor is instantiated to load an image track.
PiperOrigin-RevId: 582005828
Instantiate an ImageRenderer and add it to the list returned by
DefaultRenderersFactory.buildRenderers.
Add Renderer.MessageType.MSG_SET_IMAGE_OUTPUT and
ExoPlayer.setImageOutput to enable setting a custom
ImageRenderer.imageOutput.
Add ImageRenderer.handleMessage to process messages sent to the
renderer.
PiperOrigin-RevId: 581962451
Both interfaces are not really needed as the methods can be called
on the respective classes directly. This also avoid error-prone
situations where classes define to/fromBundle methods with parameters
that should be used instead of the parameter-less version.
Also deprecate all existing CREATOR static instances and make the
corresponding fromBundle method public where needed.
PiperOrigin-RevId: 579189766
DefaultTrackSelector now has all logic necessary for selecting an
image track.
If isPrioritizeImageOverVideoEnabled is set to true, image track will
try to be selected first and a video track will only be selected if no
image track is available. If isPrioritizeImageOverVideoEnabled is set
to false, image track will be selected only if video track wasn't
selected.
PiperOrigin-RevId: 578806006
BundleableUtil is the only class that really depends on the type
inheritence from Bundleable. However, it only needs this as a way
to define Function<T, Bundle> and Function<Bundle, T>, which could
just be passed in as parameters as it's already done for some of
these methods.
Also rename the class to BundleCollectionUtil accordingly.
PiperOrigin-RevId: 578791946
This change applies to standalone TTML files linked directly from the manifest.
As a result, we no longer have the flakiness in the DashPlaybackTest which uses sidecar-loaded (standalone file) TTML subtitles. We experimentally opt into parsing subtitles during extraction and use SubtitleExtractor in hybrid mode.
PiperOrigin-RevId: 577457256
This CL adds an isPrioritizeImageOverVideoEnabled flag to
TrackSelectionParameters and an API to set the flag value.
The flag will be used by DefaultTrackSelector to determine whether
to select an image track if both an image track and a video track are available.
PiperOrigin-RevId: 576175162
The events happens in the following order, assuming two media items:
1. First media item is fully decoded, record the last frame's pts
- Note frame processing is still ongoing for this media item
2. Renderer sends `onOutputFormatChanged()` to signal the second media item
3. **Block sending the frames of the second media item to the `VideoSink`**
4. Frame processing finishes on the first media item
5. The last frame of the first media item is released
6. **Reconfigure the `VideoSink` to apply new effects**
7. **Start sending the frames of the second media item to the `VideoSink`**
This CL implements the **events in bold**
PiperOrigin-RevId: 576098798
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
Since DEFAULT_MAX_CHANNEL_COUNT was increased from 8 to 10,
getMaxSupportedChannelCountForPassthrough always throws if its loop
enters its second iteration (channelCount of 9). This is due to
Util.getAudioTrackChannelConfig returning CHANNEL_INVALID when passed a
channelCount of 9, and setting CHANNEL_INVALID as the AudioFormat's
channel mask throws an exception.
This change skips each iteration where CHANNEL_INVALID is returned.
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
The `PreloadMediaSource` has below two new public methods that suppose to be called by the app:
* `preload(long)` allows the apps to preload the source at the passed start position before playback. The preload efforts include preparing the source for a `Timeline`, creating and caching a `MediaPeriod`, preparing the period, selecting tracks on the period and continuing loading the data on the period.
* `releasePreloadMediaSource()` allows the apps to release the preloaded progress.
The `PreloadMediaPeriod` is designed to facilitate the `PreloadMediaSource` for the preloading work. It has a new package-private method `selectTracksForPreloading` which will cache the `SampleStream` that corresponds to the track selection made during the preloading, and when the `PreloadMediaPeriod.selectTracks` is called for playback, it will uses the preloaded streams if the new selection is equal to the selection made during the preloading.
Also add a shortform demo module to demo the usage of `PreloadMediaSource` with the short-form content use case.
PiperOrigin-RevId: 574439529
This change moves the release timestamp adjustment logic out of
MediaCodecVideoRenderer and into a standalone component, the
VideoFrameReleaseControl. The plan for VideoFrameReleaseControl is to use
it:
- from MediaCodecVideoRenderer, when ExoPlayer plays video in standalone
mode.
- from the CompositionPlayer's DefaultVideoSink, when CompositionPlayer
supports multiple sequences.
- (temporarily) from the CompositionPlayer's custom ImageRenderer while
we are implementing single-sequence preview, which is an intermediate
milestone for composition preview.
PiperOrigin-RevId: 574420427
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
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.
#minor-release
PiperOrigin-RevId: 572191308
After 4fad529433, MediaCodecVideoRenderer does not report if frames
are dropped from the VideoSink. This commit fixes this.
#minor-release
PiperOrigin-RevId: 571905721
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
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
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
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
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).
#minor-release
PiperOrigin-RevId: 571021417
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
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
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
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
When seeking, we must first flush the video sink so it stops
using any SurfaceTextures before flushing MediaCodec.
#minor-release
PiperOrigin-RevId: 570015998
It seems likely we will define a new "image decoder" interface that
returns `ListenableFuture<Bitmap>`, and naming that will be
hard/annoying if we need to keep this interface working too.
It's also not really clear what a non-test implementation of this
interface would be expected to do, since `DefaultImageDecoder` is
documented to always decode using `BitmapFactory`.
#minor-release
PiperOrigin-RevId: 569206325
Changes
---
- Added `removeOfflineLicense(byte[])` and `getOfflineLicenseKeySetIds` and consumed them in their implementations
Background
---
- These APIs will help in addressing an increasing amount of `java.lang.IllegalArgumentException: Failed to restore keys: BAD_VALUE` which is our top playback error in our app
- Based on our discussion with Widevine team and [this exoplayer issue](https://github.com/google/ExoPlayer/issues/11202#issuecomment-1708792594)
- TL;DR: The failure occurs on startup if the user has 200+ offline licenses, we would like to add the functionality to remove offline licenses
**Note: Why we want these APIs in ExoMediaDrm and not in OfflineLicenseHelper**
- As per the issue above, we would like to access these 2 public APIs in MediaDrm that don’t exist in `OfflineLicenseHelper` or `ExoMediaDrm`
- APIs interested in:
- [MediaDrm#removeOfflineLicense()](https://developer.android.com/reference/android/media/MediaDrm#removeOfflineLicense(byte%5B%5D)): To remove offline license
- [MediaDrm#getOfflineLicenseKeySetIds()](https://developer.android.com/reference/android/media/MediaDrm#getOfflineLicenseKeySetIds()): To see number of offline licenses on startup
- We use `OfflineLicenseHelper` to download license for L1 and we don't interact with `ExoMediaDrm` directly. But for the alternate Widevine integration, we directly depend on `ExoMediaDrm` APIs to override and call CDM Native APIs.
- We would like to have the functionality of removing offline licenses for both integration which would need access to above APIs in `ExoMediaDrm`.
Links
---
- https://github.com/androidx/media/issues/659
MediaCodecRenderer has already been updated to not rely on the
input stream to mark its samples as decode-only and instead use
a simple time-based comparison to achieve the same effect.
This change makes the same update for all other renderers that
either use the flag directly or forward to a "decoder" instance.
PiperOrigin-RevId: 568232212
The current code only set the videoEffects when CVSP is initialized, which
happens after `player.prepare()`. But it's valid that videoEffects are set
before calling `prepare()`.
PiperOrigin-RevId: 566941216
Move audio offload mode related interfaces and definitions from `TrackSelectionParameters` to a new `AudioOffloadModePreferences` class.
PiperOrigin-RevId: 566905017
This change uses the new incremental overloads of `SubtitleParser` to
avoid introducing the performance regression caused by the original
change requiring all cues to be fully parsed before the first could be
shown on screen.
`TtmlDecoder` which used to be `SimpleSubtitleDecoder` will now be
called `TtmlParser` and implement `SubtitleParser` interface. For
backwards compatibility, we will have the same functionality provided
by `DelegatingSubtitleDecoder` backed-up by a new `TtmlParser`
instance.
PiperOrigin-RevId: 566671398
This change introduces two new types of method to `SubtitleParser`:
1. `parse()` methods that take a `Consumer<CuesWithTiming>` and return `void`
2. `parseToLegacySubtitle` method that returns `Subtitle`
(1) ensures that in the new 'parse before SampleQueue' world we can
write cues to the `SampleQueue` as soon as they're ready - this is
especially important when parsing monolithic text files, e.g. for a
whole movie.
(2) ensures that during the transition, the legacy 'parse after
SampleQueue' behaviour doesn't see any regressions in 'time to first
cue being shown'. Previously we had a single implementation to convert
from `List<CuesWithTiming>` to `Subtitle`, but this relies on the
complete list of cues being available, which can take a long time for
large files in some formats (with ExoPlayer's current parsing logic).
By allowing implementations to customise the way they create a
`Subtitle`, we can directly re-use the existing logic, so that the
'time to first cue being shown' should stay the same.
This change migrates all **usages** to the new methods, but doesn't
migrate any **implementations**. I will migrate the implementations in
follow-up CLs before deleting the old list-returning `parse()` methods.
PiperOrigin-RevId: 565057945
Removed `ExoPlayer.experimentalSetOffloadSchedulingEnabled` as scheduling will be enabled by default when offload is enabled for audio-only playback.
In addition, the `experimental` key word was taken out of the following
method signatures:
* `ExoPlayer.experimentalIsSleepingForOffload`
* `AudioOffloadListener.onExperimentalSleepingForOffloadChanged`
* `AudioOffloadListener.onExperimentalOffloadedPlayback`
PiperOrigin-RevId: 565035289
There is no known use case left that needs to be solved by this
class. All other use cases are better solved by alternative
approaches (Player playlist methods or ConcatenatingMediaSource2).
PiperOrigin-RevId: 563713384
The class currently disallows offsets of periods in their windows
except for the very first window. This is not necessary because
we can use TimeOffsetMediaPeriod to eliminate the offset if needed.
This makes the class more useful for many use cases, in particular
for using it with ClippingMediaSource.
Issue: google/ExoPlayer#11226
PiperOrigin-RevId: 563702120
This callback asks to correct the media time in a composition, but doesn't
provide the MediaPeriodId as the necessary context to do this.
PiperOrigin-RevId: 563699344
We have an existing logic for recovering the `AudioTrack` from the [ERROR_DEAD_OBJECT](https://developer.android.com/reference/android/media/AudioTrack#ERROR_DEAD_OBJECT)
throws. However, this only applies to the situation when the
`writtenEncodedFrames > 0`.
However, we have a case when `ERROR_DEAD_OBJECT` throws while writing
PCM data. When the `tunneling` is turned on, the `AudioTrack` is set the
flag `AUDIO_OUTPUT_FLAG_HW_AV_SYNC`, and further because of this flag,
it is forced the flag `AUDIO_OUTPUT_FLAG_DIRECT`. When the platform
invalidates the `AudioTrack`, the `AudioTrack` won't be restored by the
platform due to `AUDIO_OUTPUT_FLAG_DIRECT` flag, and `ERROR_DEAD_OBJECT`
is thrown.
Issue: androidx/media#431
PiperOrigin-RevId: 562582451
This is so CompositionPlayer can customize the Renderers and figure
out when a transition to a MediaItem is made hence it can configure the
effects pipeline with the effects that are specific to the MediaItem.
PiperOrigin-RevId: 562530774
Created new method `AudioSink#setOffloadDelayPadding` that will set delay and padding data onto an `AudioTrack` using `AudioTrack#setOffloadDelayPadding`. This feature adds support for offloaded, gapless Opus playback as the content requires the capability to set padding data post-`AudioSink#configure`.
PiperOrigin-RevId: 562518193
also improves tests to hash bitmap now that we know the bitmaps are decoded in roboelectic tests,
as well as some minor fixes in the DefaultImageDecoder
PiperOrigin-RevId: 561946073
This wasn't properly documented yet (unlike the longer setMediaItems
method that already includes this documentation).
Issue: androidx/media#607
PiperOrigin-RevId: 561910073
Currently, we only support sending Common Media Client Data (CMCD) data through custom HTTP request headers, added capability to configure and transmit it as HTTP query parameters.
PiperOrigin-RevId: 561591246
At this stage, the image renderer is designed to be able to render one input stream containing one sample. The renderer supports seeking inside that stream, which is a no-op because the stream comprises for exactly one sample.
PiperOrigin-RevId: 561307859
If the loading thread of the second media item progresses slow, then when the playback of the first item approaches to the end before the second item is prepared, the stream will be set "final" and the renderers are disabled during such transition. In this case, `AudioSink.handleDiscontinuity` never gets called, which introduces the flakiness into the `test_bypassOffThenOn`.
Similarly for `test_subtitle`, if the loading thread of extracting the subtitle is slow, then when the renderer attempts to queue the input buffer, the data hasn't been available in the stream. And when the extracting finished, the renderer already advanced to the time after the subtitle end time.
To de-flake the tests, we have to make sure that the period of the second item has fully loaded before starting the playback.
PiperOrigin-RevId: 560080119
The first call to method `registerInputStream` doesn't block.
Later successive calls to the method blocks until the previous register call
finishes.
PiperOrigin-RevId: 559694490
Replace Queue<Long> with LongArrayQueue which provides queue semantics
for long primitives. LongArrayQueue is forked from IntArrayQueue which
in turn was forked from Androidx CircularIntArray.
IntArrayQueue is deleted and we now use CircularIntArray directly from
Androidx Collection.
PiperOrigin-RevId: 559129744
Based on the Common Media Client Data (CMCD) specification key-value pairs should be sequenced in alphabetical order of the key name in order to reduce the fingerprinting surface exposed by the player.
PiperOrigin-RevId: 558296264
Added more comprehensive Javadoc around setting custom data and verification on key format.
Changed adding custom data as a `String` to `List<String>`. This would enable us to sort all keys to reduce the fingerprinting surface.
PiperOrigin-RevId: 558291240
It was moved there temporarily to support another temporary move
of ExoPlaybackException. See <unknown commit>.
Since then, ExoPlaybackException has been moved back to ExoPlayer
and we can do the same with MediaPeriodId, which only makes sense
in the context of the ExoPlayer module.
PiperOrigin-RevId: 557159381
This aligns the bypass code with the MediaCodec logic to not
use buffer.isDecodeOnly and instead rely on a timestamp
comparison with the last reset time. Overall, the change should
not introduce a functional difference and is covered by existing
end-to-end tests with bypass playbacks.
Splitting bypass batch buffers by decoder-only flag is
technically wrong for formats where not every buffer is a
keyframe, and this change also leaves a TODO to explain this
known shortcoming.
PiperOrigin-RevId: 556800038
The method was recently introduced and only searched for matching
samples up to index==length. However, SampleQueue uses a circular
array to index its data and the search should continue until
relativeStartIndex+length, while also handling the overflow
in the circular array.
The tests for seeking didn't cover these overflow cases yet
because they always started writing data in an empty SampleQueue.
This can be fixed by prewarming the queue with placeholder data
to force using the overflow logic in the various seek methods.
PiperOrigin-RevId: 555963011
Use `C.RATE_UNSET_INT` instead of introducing `Long.MIN_VALUE` as the default value for rate parameters. Modifies default behaviour of the `TrackSelection.getLatestBitrateEstimate()` method and the `measuredThroughputInKbps` parameter in `CmcdHeadersFactory.CmcdRequest`.
PiperOrigin-RevId: 555939420
Optimises the construction of Common Media Client Data (CMCD) headers by eliminating the use of trailing commas. Instead of appending values directly to a StringBuilder, it now adds values to a list and joins them using a comma separator. While the primary focus is on enhancing readability and robustness, it's worth noting that in certain instances, removing usages of `formatInvariant`, there are also performance improvements.
PiperOrigin-RevId: 555911498
This is the first iteration for the CompositingVideoSinkProvider which
is basically a copy of MediaCodecVideoRenderer's
VieoFrameProcessorManager.
The MediaCodecVideoRenderer now instantiates a
CompositingVideoSinkProvider instead of a VieoFrameProcessorManager.
PiperOrigin-RevId: 555903928
This adds an effect to change the speed of the video track. The speed
of the audio track can already be changed using a SonicAudioProcessor.
Issue: androidx/media#559
PiperOrigin-RevId: 555155418
Modifies the `ChunkSource.getNextChunk(long, long, List, ChunkHolder)` method in the `ChunkSource` interface to `ChunkSource.getNextChunk(LoadingInfo, long, List, ChunkHolder)`.
LoadingInfo contains additional parameters, including `playbackRate` and `lastRebufferRealtimeMs` in addition to the existing `playbackPositionUs`. The additional parameters will allow us to pass these information to Common Media Client Data (CMCD) logging.
PiperOrigin-RevId: 555148768
Modifies the `SequenceableLoader.continueLoading(long)` method in the `SequenceableLoader` interface to `SequenceableLoader.continueLoading(LoadingInfo)`.
`LoadingInfo` contains additional parameters, including `playbackSpeed` and `lastRebufferRealtimeMs` in addition to the existing `playbackPositionUs`. The additional parameters will allow us to pass these information to Common Media Client Data (CMCD) logging.
By using the `LoadingInfo` object, we ensure future flexibility to add more fields without causing any breaking changes to the API.
PiperOrigin-RevId: 555123961
`asReadOnlyBuffer` doesn't copy the original byte order but always sets it to big-endian. Replace calls to it with a utility method that manually sets the byte order after creating the read-only copy.
This fixes `TeeAudioProcessor` providing a `ByteBuffer` always in big-endian and hence causing `AudioBufferSink` to read wrong data.
PiperOrigin-RevId: 554861402
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))`).
#minor-release
Issue: androidx/media#538
PiperOrigin-RevId: 554481782
If stream is not considered final and `ClippingMediaSource` is read to `endUs`, then `BaseRenderer.readSource` returns `C.RESULT_NOTHING_READ`. In that case, the `lastBufferInStreamPresentationTimeUs` is not set and the last frame is not rendered.
PiperOrigin-RevId: 554418971
This workaround was added for TS streams that do not adjust their
timestamps to start from zero. Over time, the default audio sink
logic has become more robust towards unexpected timestamps and
we no longer need this workaround to jump forward in time.
The workaround also actively caused issues by adjusting the audio
timestamps backwards if the stream starts with large negative
values. See Issue: androidx/media#291. This caused playback to get stuck due
to another bug in the first-frame rendering logic in the video
renderer that is now fixed.
PiperOrigin-RevId: 553493618
This is the same change as 8655429af7, just on the second call site
of readDiscontinuity. The tests didn't cover this case yet because
they never queued more than 2 items in a playlist.
PiperOrigin-RevId: 553485244
setInputFormat calls registerInputStream and will cause VideoFrameProcessor to
reconfigure. We don't need to call it when setting up the VFP
(in `onReadyToInitCodec()`). Rather, we wait until `onOutputFormatChanged()`
called (this output format refers to mediaCodec's outptut format) to register
the input stream.
PiperOrigin-RevId: 553448633
We currently only force the first frame if the frame timestamp is
greater than the stream *offset*.
This is wrong for two reasons:
1. The timestamp and the offset are not comparable and it should be
the stream start position.
2. The check should only be applied at stream transitions where we
need to make sure that a new first frame isn't rendered until we
passed the transition point.
We have to fix both issues together, because fixing just issue (1)
causes seeks to before the start position to no longer render the
frame (and playback will be stuck). A new test covers this case.
We also amend the stream transition test case to actually test what it
promises to test and add a test for prerolling samples at the
beginning, to ensure the first frame is still renderered.
Issue: androidx/media#291
PiperOrigin-RevId: 552858967
We currently use 3 different booleans to track the state of the first
frame rendering, which implies that there are 8 distinct possible
overall states. However, this is actually a staged process and there
are only 3 different overall states in the current code. This means
it's clearer and easier to reason about if the variables are combined
to a single state value. Overall, this should be a complete no-op.
State mapping:
- rFFAReset=false, rFFAEnable=false, mayRenderFFAEINS=false
=> FIRST_FRAME_NOT_RENDERED_ONLY_ALLOWED_IF_STARTED
- rFFAReset=false and/or rFFAEnable=false, mayRenderFFAEINS=any
=> FIRST_FRAME_NOT_RENDERED
- rFFAReset=true, rFFAEnable=true, mayRenderFFAEINS=any
=> FIRST_FRAME_RENDERED
PiperOrigin-RevId: 552857802
Refactored `CmcdLog` to `CmcdHeadersFactory` for improved representation of its purpose and updated implementations.
#minor-change
PiperOrigin-RevId: 552831995
`SubtitleExtractor` used to rely on a `SubtitleDecoder`. However, now all SubtitleDecoders that are used for side-loaded subtitles have been migrated to a `SubtitleParser` interface. We can therefore refactor the extractor.
The `SubtitleExtractor` is only used for side-loaded subtitles which means we do not require the migration of the CEA-608/708 `SubtitleDecoders`.
PiperOrigin-RevId: 552471710
After this change, every queued bitmap is treated as an individual input stream
(like a new MediaItems).
This change merges the FrameDropTest and FrameDropPixelTest into one (while maintaining all the test cases)
- This is accomplished by generating bitmaps with timestamps on it in FrameDropTest and compare them with goldens (one may call this a pixel test, please lmk if you want this to be renamed)
- The most part of the change comes from DefaultVideoFrameProcessorVideoFrameRenderingTest. The overall working is
- We bypass the input manager
- The TestFrameGenerator generates frames based on timestamps. In this case, we generate frames with timestamps on it
- The generated frame is sent to texture output and in turn saved to bitmaps
- We then compare the generated bitmap with the goldens
PiperOrigin-RevId: 551795770
1. For codecs that change timestamps, we need to use greater
or equal instead of just equal for comparison.
2. We should only make this comparison once a value has been
set.
3. The largest queue timestamp isn't updated before using it
for this detection, meaning that we also mark the
second-to-last sample as the last one.
PiperOrigin-RevId: 550901978
We currently pass in the time at which the stream originally started,
but newly enabled renderers should get the current playback position
instead.
PiperOrigin-RevId: 550894630
Instead of `text/x-exoplayer-cues`, we will use `application/x-media3-cues`.
The prefix should be `application` not `text` since the encoded form is arbitrary bytes, not necessarily text. The name should not reference `exoplayer`, since the Media3 Extractors (which are not part of `exoplayer`) produce this format.
PiperOrigin-RevId: 550181852
`TtmlDecoder` which used to be `SimpleSubtitleDecoder` will now be called `TtmlParser` and implement SubtitleParser interface. For backwards compatibility, we will have the same functionality provided by `DelegatingSubtitleDecoder` backed-up by a new `TtmlParser` instance.
PiperOrigin-RevId: 549700490
This tracker aims to replicate the behavior of a specific codec to
ensure MediaCodecRenderer correctly detects stream and output
format transitions. The class was needed because MediaCodecRenderer
made assumptions about codec behavior this codec did not fulfil (in
particular, changing timestamps and number of samples).
Since then, MediaCodecRenderer was made more robust to this kind of
codec behavior in general and currently has no assumptions that
require any special handling of this codec. This means we can remove
the workaround completely.
PiperOrigin-RevId: 549610989
This is no longer flaky because WebVTT subtitles are decoded on the
loading thread (enabled in this test with
`defaultExractorsFactory.setTextTrackTranscodingEnabled(true)` - and
supported for WebVTT since f0f24aa0d4).
PiperOrigin-RevId: 549594291
The class tries to be flexible to support as many different input
and codec behavior combinations as possible. But so far it didn't
spell out its remaining assumptions and explicit non-assumptions,
making it hard to know which behavior to rely on.
PiperOrigin-RevId: 549589347
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.
#minor-release
PiperOrigin-RevId: 549369529
`WebvttDecoder` which used to be `SimpleSubtitleDecoder` will now be called `WebvttParser` and implement `SubtitleParser` interface.
For backwards compatibility, we will have the same functionality provided by `DelegatingSubtitleDecoder` backed-up by a new `WebvttParser` instance. `WebvttSubtitle` will still be used behind the scenes to handle overlapping `Cues`.
PiperOrigin-RevId: 549298733
The end-to-end test output for the overlapping SRT and SSA subtitles
is currently incorrect. They will be fixed in a future change that
updates `TextRenderer` to support this overlap.
The 'extra' samples visible in the extractor test output files are
'empty cue list' samples produced by `SsaParser`. They will go away
when this implementation is updated to remove this behaviour and rely
on `CuesWithTiming.durationUs` instead (the 'empty list' behaviour is
not required by the `SubtitleParser` interface).
PiperOrigin-RevId: 549264593
*** Original commit ***
Rollback of b69b33206e
*** Original commit ***
Mark output sample as decode-only based on start time
We currently do the same check on the input timestamps and
expect the output timestamps to match. Some codecs produce
samples with modified timestamps and the logic is a lot safer
when the comparison with the start time is done on the output
side of the codec.
Issue: google/ExoPlayer#11000
***
***
PiperOrigin-RevId: 549019403
This ensures the DownloadService stays functional on Android 14
where defining this type is required. On Android 14 and above,
the app also needs to define the DATA_SYNC permission, which is
added to the demo app as well. In the future, this service type
will no longer be supported and DownloadService needs to be
rewritten with another background scheduling framework.
Issue: google/ExoPlayer#11239
PiperOrigin-RevId: 548994842
This was done because it was deemed correct to only start at timestamp
zero when the code was originally written. However, in case of
prerolling from a keyframe, many samples will get the same timestamp,
which is not correct and interferes with downstream logic
that deals with timestamps.
PiperOrigin-RevId: 548986160
Reading a discontinuity from a media period indicates that a position
reset is required. As part of this event, the media period may need
further loading (e.g in a MergingMediaPeriod where one stream reported
a discontinuity and the other need to reload from this position).
This currently fails if the media periods was already fully loaded and
we started loading further items in the playlist. As a result, playback
is stuck forever. We can fix this by detecting that further loading is
needed and resetting the loading period to the current one.
The existing MergingPlaylistPlaybackTest already covers this case
reliably, because it combines all the right preconditions (merging
source, clipping to get a discontinuity and a playlist).
PiperOrigin-RevId: 548735177
This is a step towards adding general support for overlapping
subtitles in these formats (and others), both muxed and sideloaded:
* Issue: google/ExoPlayer#10295
* Issue: google/ExoPlayer#4794
This change adds these files to the end-to-end playback tests too, but
the subtitle track is currently disabled because renderer-side subtitle
parsing causes flaky tests (due to an uncontrolled thread in
`SimpleSubtitleDecoder`). The subtitle track will be re-enabled in
a follow-up change when loading-side subtitle parsing is added (so the
tests will no longer be flaky). At this point the overlapping subtitles
**still** won't be supported end-to-end, but a second change will
resolve this will changes in `TextRenderer` - which will change the
end-to-end playback dumps to reflect the overlapping subtitles.
PiperOrigin-RevId: 548705032
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
Also re-use the `CuesWithTimingSubtitle` implementation (previously a
private class inside `DelegatingSubtitleDecoder`) in `ExoPlayerCuesDecoder`.
PiperOrigin-RevId: 548612040
It will act similarly to `SubtitleDecoderFactory`, but return parsers instead of decoders. In turn `SubtitleDecoderFactory.createDecoder()` cab wrap those parsers with `DelegatingSubtitleDecoder`.
PiperOrigin-RevId: 548528054
`PgsDecoder` which used to be `SimpleSubtitleDecoder` will now be called `PgsParser` and implement `SubtitleParser` interface. For backwards compatibility, we will have the same functionality provided by `DelegatingSubtitleDecoder` backed-up by a new `PgsParser` instance.
PiperOrigin-RevId: 548520549
`DvbDecoder` which used to be `SimpleSubtitleDecoder` will now be called `DvbParser` and implement `SubtitleParser` interface. There was, however, already a `DvbParser`, used by `DvbDecoder` behind the scenes. Hence, the refactoring only requires the existing `DvbParser` to adhere to the new `SubtitleParser` interface.
For backwards compatibility, we will have the same functionality as `DvbDecoder` provided by `DelegatingSubtitleDecoder` backed-up by a new `DvbParser` instance, available from the `SubtitleDecoderFactory`.
PiperOrigin-RevId: 548155759
`Tx3gDecoder` which used to be `SimpleSubtitleDecoder` will now be called `Tx3gParser` and implement `SubtitleParser` interface. For backwards compatibility, we will have the same functionality provided by `DelegatingSubtitleDecoder` backed-up by a new `Tx3gParser` instance.
PiperOrigin-RevId: 548144492
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
These tests allow to verify the samples sent for decoding,
when decoders are reset, which samples are dropped as decode-only
for video and which samples are sent to the AudioTrack for playback.
The test exercises all combinations of merges where audio or video
is the primary track and where audio, video or both are clipped.
PiperOrigin-RevId: 548061254
These tests allow to verify the samples sent for decoding,
when decoders are reset, which samples are dropped as decode-only
for video and which samples are sent to the AudioTrack for playback.
The test exercises all combinations of clipping transitions for
sources that are either clipped at the start, the end, or both.
PiperOrigin-RevId: 547730824
When a renderer is pre-enabled (while another playback is still
ongoing), we pass mayRenderStartOfStream=false to Renderer.enable.
This ensures we don't show any first frames while the previous media
is still playing.
Currently, we never tell the renderer when we actually stop playing
the previous media so that it could render the start of the stream,
because we allow this as soon as the renderer is in STATE_STARTED and
we assume that we have to be in STATE_STARTED to make this stream
transition.
While this assumption is true, there are also cases where we can't
start the renderers because they are not ready yet and the video
renderer can't become ready because it didn't render its first frame.
This effectively blocks playback forever.
The most direct way of solving this, is to tell the renderer that
playback has transitioned and that it is now allowed to render the
start of the stream. This means it can never get blocked as described
above.
PiperOrigin-RevId: 547727347
`Mp4WebvttDecoder` which used to be `SimpleSubtitleDecoder` will now be called `Mp4WebvttParser` and implement `SubtitleParser` interface. For backwards compatibility, we will have the same functionality provided by `DelegatingSubtitleDecoder` backed-up by a new `Mp4WebvttParser` instance.
PiperOrigin-RevId: 547248157
For sync-sample-only formats, we have an optimization to drop all buffers
with less than the start time when writing them to the queue.
For the same formats, if we set a new start time (=seek), we only seek
to the buffer at or before the start time. This means the first sample
in the queue is different depending on whether we seek to a start time
or set a start time and then write samples. This is inconsistent and
effectively means the first sample depends on a race condition between
the Loader thread (writing samples) and the playback thread (attempting
an initial seek in the already loaded samples).
The effect of this inconsistency is that we have to decode one sample
we don't need (and could have skipped) and that some tests become flaky
if the test setup runs into the mentioned race condition.
The fix is to change the SampleQueue seek method to also seek to
a sample at or after the specified time, to align the behavior to the
case where we write the same samples to an empty queue.
The change also clarifies the Javadoc of
MimeTypes.allSamplesAreSyncSamples to note that this should really only
return true if the samples have no "duration" that matters. Otherwise,
we could reasonably return true for most subtitle formats although it
would break subtitle display because we'd remove samples that start
before the seek time.
PiperOrigin-RevId: 547189941
Also parse the PCM encoding for lpcm in MP4, and update `MatroskaExtractor`
similarly.
Tested manually in the demo app using an MP4 with 24-bit big endian audio.
PiperOrigin-RevId: 546878505
Some adjustments to the test to make it more correct and prevent it
from becoming flaky:
- Use separate output dump files per test setup. Once we add more data
to these files, they are not guaranteed to be the same anymore.
- Use a seek position that is actually behind the midroll as described
in the test setup.
- Change ad insertion position to ensure the ad group duration doesn't
exceed the underlying media duration.
- Add a wait for isLoading to ensure the late insertion of an ad group
happens consistently at the same processing stage.
PiperOrigin-RevId: 546825183
This changes all MediaSources in our library to allow updates to
their MediaItems (if supported).
Issue: google/ExoPlayer#9978
Issue: androidx/media#33
PiperOrigin-RevId: 546808812
`SubripDecoder` which used to be `SimpleSubtitleDecoder` will now be called `SubripParser` and implement `SubtitleParser` interface. For backwards compatibility, we will have the same functionality provided by `DelegatingSubtitleDecoder` backed-up by a new `SubripParser` instance.
PiperOrigin-RevId: 546538113
`SsaDecoder` which used to be `SimpleSubtitleDecoder` will now be called `SsaParser` and implement `SubtitleParser` interface. For backwards compatibility, we will have the same functionality provided by `DelegatingSubtitleDecoder` backed-up by a new `SsaParser` instance.
PiperOrigin-RevId: 546336035
`DelegatingSubtitleDecoder` is a `SimpleSubtitleDecoder` that delegates to a `SubtitleParser` instance (e.g. future implementations like `WebvttParser`, `SubripParser`, `SsaParser`, `DvbParser` etc)
It will be in the `exoplayer` package, rather than `extractor` and only be used in the decoding flow which happens after SampleQueue (and to be deprecated). When this decoding flow is deprecated and removed, the class can be later deleted.
PiperOrigin-RevId: 546317528
This makes tests more realistic because the returned value matches
the rest of the simulated test time.
It also prevents test flakiness in (yet to be written) tests that
may not correctly advance the playback time in the position tracker.
PiperOrigin-RevId: 546011842
When selecting progressive and HLS tracks, we currently check if
we can either seek in the existing samples or are starting from the
beginning of the stream. In both cases, we don't need to reload the
stream and can continue reading.
Seeking to the beginning isn't side-effect free though because it
also sets the startTimeUs to zero. Whether a seek to the beginning
is successful also depends on whether we already loaded a sample or
not. This mean that the startTimeUs value is set (or not set) based
on the speed of the Loader thread even for the same input starting
from the beginning. This race condition means the actual samples
we write to the stream may differ if the stream has initial samples
with negative timestamps.
We can avoid this race condition by checking if the queue is empty
first, so that we only call seekTo if really needed.
PiperOrigin-RevId: 546010951
Robolectric writes warnings to the log output because the Surfaces
we create are not released and pollute the test environment. This
causes performance issues if tests are run repeatedly.
PiperOrigin-RevId: 545906757
We have the optimization to skip buffers if the release time is
exactly the same as the one for the previous buffer. This makes
sense under the assumption that these buffers get released to
a visible Surface and will be ignored anyway.
However, it's also helpful to provide a customization option to not
do this for cases where the outputting MediaCodecAdapter is not
directly talking to a visible Surface or for tests where we can't
fully control the vsync timing of the Surface and want to ensure
we output all samples that are meant to be shown.
PiperOrigin-RevId: 545906113
This makes tests more realistic because the returned value matches
the rest of the simulated test time.
It also prevents test flakiness in (yet to be written) tests that
may accidentally drop output buffers or calculate the wrong values.
PiperOrigin-RevId: 545690008
Upon track transition of offloaded playback of gapless tracks, the framework will reset the playback head position. The AudioTrackPositionTracker must be made to expect the reset and cache accumulated sum of rawPlaybackHeadPosition.
#minor-release
PiperOrigin-RevId: 545602979