androidx / media

Jetpack Media3 support libraries for media use cases, including ExoPlayer, an extensible media player for Android
https://developer.android.com/media/media3
Apache License 2.0
1.69k stars 404 forks source link

Erorr 404 : Issue with Switching Bitrates in Multi-Bitrate HLS Stream Using CMAF on Demo App #1671

Open newtestpage opened 2 months ago

newtestpage commented 2 months ago

Dear Friends

I am experiencing an issue when trying to switch bitrates in a multi-bitrate HLS stream using latest version of demo app. The stream uses CMAF (.m4s segments) instead of the traditional .ts segments. While the master playlist (master.m3u8) and all the variant playlists (master_0.m3u8, master_1.m3u8, master_2.m3u8) are accessible and correctly listed, I encounter a 404 Response Code error when attempting to switch between the bitrates during playback.

Issue: The player correctly accesses and begins playback of the initial stream, but when switching to a different bitrate, it fails with a 404 Response Code. The error appears to be related to the player attempting to load the .m4s segments but being unable to find them or incorrectly handling the CMAF segments.

internalError [eventTime=21.22, mediaPos=40.24, window=0, period=0, loadError
                                                                                                      androidx.media3.datasource.HttpDataSource$InvalidResponseCodeException: Response code: 404
                                                                                                          at androidx.media3.datasource.cronet.CronetDataSource.open(CronetDataSource.java:647)
                                                                                                          at androidx.media3.datasource.DefaultDataSource.open(DefaultDataSource.java:275)
                                                                                                          at androidx.media3.datasource.cache.CacheDataSource.openNextSource(CacheDataSource.java:802)
                                                                                                          at androidx.media3.datasource.cache.CacheDataSource.open(CacheDataSource.java:615)
                                                                                                          at androidx.media3.datasource.StatsDataSource.open(StatsDataSource.java:86)
                                                                                                          at androidx.media3.exoplayer.hls.HlsMediaChunk.prepareExtraction(HlsMediaChunk.java:525)
                                                                                                          at androidx.media3.exoplayer.hls.HlsMediaChunk.feedDataToExtractor(HlsMediaChunk.java:498)
                                                                                                          at androidx.media3.exoplayer.hls.HlsMediaChunk.loadMedia(HlsMediaChunk.java:467)
                                                                                                          at androidx.media3.exoplayer.hls.HlsMediaChunk.load(HlsMediaChunk.java:424)
                                                                                                          at androidx.media3.exoplayer.upstream.Loader$LoadTask.run(Loader.java:421)
                                                                                                          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
                                                                                                          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
                                                                                                          at java.lang.Thread.run(Thread.java:919)

Steps Taken: Verified that all referenced .m4s files in the playlists are accessible directly via a browser and through tools like curl. Confirmed that the master playlist and variant playlists are correctly formatted and accessible. The issue seems specific to the handling of CMAF (.m4s) segments during bitrate switching. Request: Could you please assist in identifying why the player is unable to handle the CMAF segments during bitrate switching? Is there any specific configuration required for the player to correctly support CMAF in HLS streams?

I appreciate your help in resolving this issue.

icbaker commented 2 months ago

I think there are (at least) two possibilities here:

  1. ExoPlayer is incorrectly generating the asset URLs from the HLS playlist(s), and requesting paths that don't exist, hence the 404 error.
  2. ExoPlayer is correctly generating the asset URLs that the server is expecting, but the server doesn't like something about the ExoPlayer request (that is different to your curl and browser requests) and rejecting it with 404.

Given we have no insight into why the server is responding with 404 we can't really debug (2) from the library side.

For (1), can you log the full URL that is generating the 404 error to see if it matches the URL you expect (and that you've tested with curl)? You should be able to find this from the InvalidResponseCodeException.dataSpec field where you catch the exception (inherited from HttpDataSourceException).

newtestpage commented 2 months ago

Thanks for your response . I’m not very experienced with debugging this kind of issue. Would it be possible for you to test the stream URL directly if I send it over to you? I believe this might help in identifying the problem more effectively.

icbaker commented 2 months ago

We can take a look - please send both the HLS playlist URL and the expected asset URLs (that you've tested with curl) to android-media-github@google.com with the subject Issue #1671. Please also update this issue to indicate you’ve done this.

newtestpage commented 2 months ago

Hi,

I’ve sent the HLS playlist URL and asset URLs to android-media-github@google.com as requested.

Thanks

icbaker commented 2 months ago

I'm able to reproduce a 403 error (not 404) in the unmodified demo app when switching bitrate manually in the demo app UI using the "SELECT TRACKS" button at the top.

It seems that when we see the 403 error the URI being requested is missing the query parameters that you included in your email.

You provided:

When ExoPlayer requests the multivariant playlist it includes these parameters: http://your.uri.com/path/to/master.m3u8?username=foo&password=bar

But when making requests for the media playlist the parameters are not propagated, so the requested URI that produces the 403 is http://your.uri.com/path/to/master_0.m3u8

Some of these requests seem to succeed (when playback proceeds "normally"), but later ones fail (when manually switching bitrate).

Assuming the 403 error is due to the missing query parameters (impossible to be sure without access to the server logs), I hacked the demo app to re-append them using ResolvingDataSource. This seemed to resolve the errors when using DefaultHttpDataSourceFactory, but transformed the error into a 404 when using HttpEngineDataSource or CronetDataSource (I hacked the demo app code to switch between these).

The 404 occurs on a segment (not playlist) URI (unlike the 403): http://your.uri.com/path/to/master_chunk_stream0_xyz_123.m4s?username=foo&password=bar

So I think there are multiple issues/questions here:

  1. If you want the ?username=foo&password=bar query parameters to be propagated from the multivariant playlist request to the media playlist request(s), and from the media playlist request to the segment request(s), you need to use the HLS QUERYPARAM config: https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-4.4.2.3
    • However this is currently not supported by ExoPlayer, so we would also need to make changes to support this.
  2. Even with the query parameters appended, playback fails with HttpEngineDataSource and CronetDataSource. My hypothesis is that this is due to the server relying on some auth cookies that are set on the first response, and re-used for later requests. I confirmed this by disabling cookie support with DefaultHttpDataSource and saw the same 404 error when requesting a segment. Lack of cookie support in CronetDataSource is tracked by: https://github.com/google/ExoPlayer/issues/5975.

If you can confirm that you're able to modify the playlists to correctly use the QUERYPARAM config to propagate the query parameters between requests then I can transform this into an enhancement request for QUERYPARAM support in our HLS handling, but I'm afraid we are unlikely to work on this soon.

newtestpage commented 2 months ago

Hi,

Thanks for the detailed response. I don’t have the technical expertise to modify the playlists or implement the QUERYPARAM config myself. I’ve reached out to the server support team to see if they can assist with this.

I’ll keep you updated on their response.

Thanks again for your help.

Best regards,