google / ExoPlayer

This project is deprecated and stale. The latest ExoPlayer code is available in https://github.com/androidx/media
https://developer.android.com/media/media3/exoplayer
Apache License 2.0
21.74k stars 6.03k forks source link

Support cross-protocol redirects in OkHttpDataSource (and possibly CronetDataSource) #5263

Closed needz closed 5 years ago

needz commented 5 years ago

Issue description

The Dailymotion redirect URLs don't work in ExoPlayer, because it's a redirect to a real M3U8. There is also no way to set the allowCrossProtocolRedirects parameter in OkHttpDataSource, although using default DefaultHttpDataSource with allowCrossProtocolRedirects set to true didn't help either.

Reproduction steps

Use OkHttpDataSourceFactory and run the link provided in ExoPlayer 2.9.2

Link to test content

http://tf.umutiptv.cf/dailymotion.php?kanal=tele1

Version of ExoPlayer being used

ExoPlayer 2.9.2

Device(s) and version(s) of Android being used

nVidia Shield Android TV

A full bug report captured from the device

2018-12-16 20:50:18.280 25208-25208/com.google.android.exoplayer2.demo I/DefaultRenderersFactory: Loaded LibvpxVideoRenderer.
2018-12-16 20:50:18.302 25208-25208/com.google.android.exoplayer2.demo I/DefaultRenderersFactory: Loaded LibopusAudioRenderer.
2018-12-16 20:50:18.303 25208-25208/com.google.android.exoplayer2.demo I/DefaultRenderersFactory: Loaded LibflacAudioRenderer.
2018-12-16 20:50:18.305 25208-25208/com.google.android.exoplayer2.demo I/DefaultRenderersFactory: Loaded FfmpegAudioRenderer.
2018-12-16 20:50:18.316 25208-25208/com.google.android.exoplayer2.demo I/ExoPlayerImpl: Init 368fa39 [ExoPlayerLib/2.9.2] [darcy, SHIELD Android TV, NVIDIA, 26]
2018-12-16 20:50:18.360 25208-25208/com.google.android.exoplayer2.demo D/EventLogger: state [0.01, 0.00, window=0, true, BUFFERING]
2018-12-16 20:50:18.396 25208-25251/com.google.android.exoplayer2.demo D/ViewRootImpl: windowFocusChanged true com.google.android.exoplayer2.demo
2018-12-16 20:50:18.420 25208-25208/com.google.android.exoplayer2.demo D/EventLogger: surfaceSizeChanged [0.07, 0.00, window=0, 1920, 1080]
2018-12-16 20:50:18.421 25208-25208/com.google.android.exoplayer2.demo D/EventLogger: timelineChanged [0.08, 0.00, window=0, periodCount=1, windowCount=1, reason=PREPARED
2018-12-16 20:50:18.421 25208-25208/com.google.android.exoplayer2.demo D/EventLogger:   period [?]
2018-12-16 20:50:18.421 25208-25208/com.google.android.exoplayer2.demo D/EventLogger:   window [?, false, false]
2018-12-16 20:50:18.421 25208-25208/com.google.android.exoplayer2.demo D/EventLogger: ]
2018-12-16 20:50:18.489 25208-25208/com.google.android.exoplayer2.demo D/EventLogger: mediaPeriodCreated [0.14, 0.00, window=0, period=0]
2018-12-16 20:50:18.490 25208-25208/com.google.android.exoplayer2.demo D/EventLogger: loading [0.14, 0.00, window=0, period=0, true]
2018-12-16 20:50:18.535 25208-25238/com.google.android.exoplayer2.demo D/OpenGLRenderer: endAllActiveAnimators on 0x21d8931800 (ExpandableListView) with handle 0x21dd4349e0
2018-12-16 20:50:19.102 25208-25208/com.google.android.exoplayer2.demo E/EventLogger: internalError [0.76, 0.00, window=0, period=0, loadError]
    com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 301
        at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.open(DefaultHttpDataSource.java:300)
        at com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:250)
        at com.google.android.exoplayer2.upstream.cache.CacheDataSource.openNextSource(CacheDataSource.java:479)
        at com.google.android.exoplayer2.upstream.cache.CacheDataSource.open(CacheDataSource.java:308)
        at com.google.android.exoplayer2.upstream.StatsDataSource.open(StatsDataSource.java:83)
        at com.google.android.exoplayer2.source.ExtractorMediaPeriod$ExtractingLoadable.load(ExtractorMediaPeriod.java:885)
        at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:381)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)
2018-12-16 20:50:19.849 25208-25208/com.google.android.exoplayer2.demo E/EventLogger: internalError [1.50, 0.00, window=0, period=0, loadError]
    com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 301
        at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.open(DefaultHttpDataSource.java:300)
        at com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:250)
        at com.google.android.exoplayer2.upstream.cache.CacheDataSource.openNextSource(CacheDataSource.java:479)
        at com.google.android.exoplayer2.upstream.cache.CacheDataSource.open(CacheDataSource.java:308)
        at com.google.android.exoplayer2.upstream.StatsDataSource.open(StatsDataSource.java:83)
        at com.google.android.exoplayer2.source.ExtractorMediaPeriod$ExtractingLoadable.load(ExtractorMediaPeriod.java:885)
        at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:381)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)
2018-12-16 20:50:21.624 25208-25208/com.google.android.exoplayer2.demo E/EventLogger: internalError [3.28, 0.00, window=0, period=0, loadError]
    com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 301
        at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.open(DefaultHttpDataSource.java:300)
        at com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:250)
        at com.google.android.exoplayer2.upstream.cache.CacheDataSource.openNextSource(CacheDataSource.java:479)
        at com.google.android.exoplayer2.upstream.cache.CacheDataSource.open(CacheDataSource.java:308)
        at com.google.android.exoplayer2.upstream.StatsDataSource.open(StatsDataSource.java:83)
        at com.google.android.exoplayer2.source.ExtractorMediaPeriod$ExtractingLoadable.load(ExtractorMediaPeriod.java:885)
        at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:381)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)
2018-12-16 20:50:22.438 25208-25217/com.google.android.exoplayer2.demo I/zygote64: Do partial code cache collection, code=124KB, data=105KB
2018-12-16 20:50:22.438 25208-25217/com.google.android.exoplayer2.demo I/zygote64: After code cache collection, code=124KB, data=105KB
2018-12-16 20:50:22.438 25208-25217/com.google.android.exoplayer2.demo I/zygote64: Increasing code cache capacity to 512KB
2018-12-16 20:50:24.333 25208-25208/com.google.android.exoplayer2.demo E/EventLogger: internalError [5.99, 0.00, window=0, period=0, loadError]
    com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 301
        at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.open(DefaultHttpDataSource.java:300)
        at com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:250)
        at com.google.android.exoplayer2.upstream.cache.CacheDataSource.openNextSource(CacheDataSource.java:479)
        at com.google.android.exoplayer2.upstream.cache.CacheDataSource.open(CacheDataSource.java:308)
        at com.google.android.exoplayer2.upstream.StatsDataSource.open(StatsDataSource.java:83)
        at com.google.android.exoplayer2.source.ExtractorMediaPeriod$ExtractingLoadable.load(ExtractorMediaPeriod.java:885)
        at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:381)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)
2018-12-16 20:50:24.336 25208-25264/com.google.android.exoplayer2.demo E/ExoPlayerImplInternal: Source error.
    com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 301
        at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.open(DefaultHttpDataSource.java:300)
        at com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:250)
        at com.google.android.exoplayer2.upstream.cache.CacheDataSource.openNextSource(CacheDataSource.java:479)
        at com.google.android.exoplayer2.upstream.cache.CacheDataSource.open(CacheDataSource.java:308)
        at com.google.android.exoplayer2.upstream.StatsDataSource.open(StatsDataSource.java:83)
        at com.google.android.exoplayer2.source.ExtractorMediaPeriod$ExtractingLoadable.load(ExtractorMediaPeriod.java:885)
        at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:381)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)
2018-12-16 20:50:24.339 25208-25208/com.google.android.exoplayer2.demo D/EventLogger: mediaPeriodReleased [5.99, 0.00, window=0, period=0]
2018-12-16 20:50:24.340 25208-25208/com.google.android.exoplayer2.demo E/EventLogger: playerFailed [5.99, 0.00, window=0]
    com.google.android.exoplayer2.ExoPlaybackException: com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 301
        at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:354)
        at android.os.Handler.dispatchMessage(Handler.java:101)
        at android.os.Looper.loop(Looper.java:164)
        at android.os.HandlerThread.run(HandlerThread.java:65)
     Caused by: com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 301
        at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.open(DefaultHttpDataSource.java:300)
        at com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:250)
        at com.google.android.exoplayer2.upstream.cache.CacheDataSource.openNextSource(CacheDataSource.java:479)
        at com.google.android.exoplayer2.upstream.cache.CacheDataSource.open(CacheDataSource.java:308)
        at com.google.android.exoplayer2.upstream.StatsDataSource.open(StatsDataSource.java:83)
        at com.google.android.exoplayer2.source.ExtractorMediaPeriod$ExtractingLoadable.load(ExtractorMediaPeriod.java:885)
        at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:381)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)
2018-12-16 20:50:24.342 25208-25208/com.google.android.exoplayer2.demo D/EventLogger: loading [6.00, 0.00, window=0, false]
2018-12-16 20:50:24.343 25208-25208/com.google.android.exoplayer2.demo D/EventLogger: state [6.00, 0.00, window=0, true, IDLE]
2018-12-16 20:51:33.556 25208-25217/com.google.android.exoplayer2.demo I/zygote64: Compiler allocated 6MB to compile void android.view.ViewRootImpl.performTraversals()
ojw28 commented 5 years ago

The stream works fine for me with DefaultHttpDataSource and allowCrossProtocolRedirects enabled. Please clarify this part of what you're saying.

For OkHttpDataSource, this is basically a feature request to support cross protocol redirects, right?

needz commented 5 years ago

@ojw28, yes, it would be great if you could include this feature in line with the HttpDataSource for those who use OkHttpDataSource.

Could you please also share your configured allowCrossProtocolRedirects line, so I can implement it on my end? Thanks.

ojw28 commented 5 years ago

I didn't do anything special. I did the minimum possible to enable it in the demo app, which is to change this line in the demo app to:

return new DefaultHttpDataSourceFactory(
        userAgent,
        DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
        DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS,
        /* allowCrossProtocolRedirects= */ true);

and then I added the sample in the demo app's media.exolist.json:

{
  "name": "Test stream",
  "uri": "http://tf.umutiptv.cf/dailymotion.php?kanal=tele1",
  "extension": "m3u8"
},

and that was it.

It should also be noted that you can just use the https URL https://tf.umutiptv.cf/dailymotion.php?kanal=tele1, and everything will work fine without any special configuration (because there wont be a cross protocol redirect).

needz commented 5 years ago

@ojw28, adding the specific extension type "m3u8" worked, but imagine the situation, where a user (or a player) does not know it's an m3u8 stream after adding the original link to the playlist and it fails.

In situation, where there is no extension specified, it still doesn't work, neither adding allowCrossProtocolRedirects, nor adding https:// instead of http:// work, check these variants below.

{
        "name": "Dailymotion HTTP",
        "uri": "http://tf.umutiptv.cf/dailymotion.php?kanal=tele1"
},
{
        "name": "Dailymotion HTTPS",
        "uri": "https://tf.umutiptv.cf/dailymotion.php?kanal=tele1"
}

By the way, adding m3u8 extension definition for the URL worked in OkHttpClient without any changes. Strange.

ojw28 commented 5 years ago

Detecting the stream type is tracked by https://github.com/google/ExoPlayer/issues/3165.

From your response above it sounds like the OkHttp extension already performs cross-protocol redirects by default? In which case we can close this issue.

needz commented 5 years ago

@ojw28, yes, but I guess this issue can be part of "playing PHP video" https://github.com/google/ExoPlayer/issues/5220 issue mentioned in that thread.

ojw28 commented 5 years ago

This issue is just a duplicate of #3165 (as #5220 may well be).