From 44f75b205e7bebaa620735df6838f630db09d6ad Mon Sep 17 00:00:00 2001 From: Christophe Beyls Date: Fri, 25 Dec 2020 14:26:39 +0100 Subject: [PATCH] WIP VideoPlayerActivity --- app/build.gradle | 7 ++ app/src/main/AndroidManifest.xml | 1 + .../fosdem/activities/VideoPlayerActivity.kt | 93 +++++++++++++++++++ .../fosdem/fragments/EventDetailsFragment.kt | 10 +- .../fosdem/utils/network/HttpUtils.kt | 5 + .../DrmFreeProgressiveMediaSourceFactory.kt | 39 ++++++++ app/src/main/res/layout/player.xml | 5 + 7 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/be/digitalia/fosdem/activities/VideoPlayerActivity.kt create mode 100644 app/src/main/java/com/google/android/exoplayer2/source/DrmFreeProgressiveMediaSourceFactory.kt create mode 100644 app/src/main/res/layout/player.xml diff --git a/app/build.gradle b/app/build.gradle index f9a9cd1..c77e15c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -31,6 +31,9 @@ android { } buildTypes { + debug { + multiDexEnabled true + } release { minifyEnabled true shrinkResources true @@ -70,6 +73,7 @@ dependencies { def lifecycle_version = "2.2.0" def room_version = "2.2.6" def okhttp_version = "3.12.12" + def exoplayer_version = "2.12.2" implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1' implementation 'androidx.core:core-ktx:1.3.2' @@ -95,4 +99,7 @@ dependencies { implementation 'com.squareup.okio:okio:2.9.0' implementation 'com.squareup.moshi:moshi:1.11.0' implementation 'com.github.chrisbanes:PhotoView:2.3.0' + implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version" + implementation "com.google.android.exoplayer:extension-okhttp:$exoplayer_version" + implementation "com.google.android.exoplayer:exoplayer-ui:$exoplayer_version" } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f998c2a..a15cfa7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -109,6 +109,7 @@ + + arrayOf( + MediaCodecAudioRenderer(context, MediaCodecSelector.DEFAULT, eventHandler, audioRendererEventListener), + MediaCodecVideoRenderer(context, MediaCodecSelector.DEFAULT, + DefaultRenderersFactory.DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS, eventHandler, + videoRendererEventListener, 50) + ) + } + } + + private fun createDataSourceFactory(): DataSource.Factory { + return OkHttpDataSourceFactory(HttpUtils.deferringCallFactory) // Provide support for HTTP data sources only + } + + private fun createExtractorsFactory(): ExtractorsFactory { + return ExtractorsFactory { arrayOf(Mp4Extractor(), OggExtractor(), MatroskaExtractor()) } + } + + private fun createMediaSourceFactory(dataSourceFactory: DataSource.Factory, extractorsFactory: ExtractorsFactory): MediaSourceFactory { + return DrmFreeProgressiveMediaSourceFactory(dataSourceFactory, extractorsFactory) + } + + fun createSimpleExoPlayer(context: Context): SimpleExoPlayer { + return SimpleExoPlayer.Builder(context, + createRenderersFactory(context), + DefaultTrackSelector(context), + createMediaSourceFactory(createDataSourceFactory(), createExtractorsFactory()), + DefaultLoadControl(), + DefaultBandwidthMeter.getSingletonInstance(context), + AnalyticsCollector(Clock.DEFAULT) + ).build() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/be/digitalia/fosdem/fragments/EventDetailsFragment.kt b/app/src/main/java/be/digitalia/fosdem/fragments/EventDetailsFragment.kt index 4681b86..206ce2e 100644 --- a/app/src/main/java/be/digitalia/fosdem/fragments/EventDetailsFragment.kt +++ b/app/src/main/java/be/digitalia/fosdem/fragments/EventDetailsFragment.kt @@ -30,6 +30,7 @@ import androidx.fragment.app.commit import androidx.fragment.app.viewModels import be.digitalia.fosdem.R import be.digitalia.fosdem.activities.PersonInfoActivity +import be.digitalia.fosdem.activities.VideoPlayerActivity import be.digitalia.fosdem.api.FosdemApi import be.digitalia.fosdem.model.Building import be.digitalia.fosdem.model.Event @@ -294,8 +295,15 @@ class EventDetailsFragment : Fragment(R.layout.fragment_event_details) { private class LinkClickListener(private val event: Event, private val link: Link) : View.OnClickListener { override fun onClick(v: View) { + val context = v.context + if (link.url.endsWith(".mp4") || link.url.endsWith(".webm")) { + val intent = Intent(context, VideoPlayerActivity::class.java) + .putExtra(VideoPlayerActivity.EXTRA_URI, link.url) + context.startActivity(intent) + return + } + try { - val context = v.context CustomTabsIntent.Builder() .configureToolbarColors(context, event.track.type.appBarColorResId) .setShowTitle(true) diff --git a/app/src/main/java/be/digitalia/fosdem/utils/network/HttpUtils.kt b/app/src/main/java/be/digitalia/fosdem/utils/network/HttpUtils.kt index cdf4a18..c1f0287 100644 --- a/app/src/main/java/be/digitalia/fosdem/utils/network/HttpUtils.kt +++ b/app/src/main/java/be/digitalia/fosdem/utils/network/HttpUtils.kt @@ -5,6 +5,7 @@ import be.digitalia.fosdem.utils.BackgroundWorkScope import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.suspendCancellableCoroutine import okhttp3.Call import okhttp3.Callback @@ -36,6 +37,10 @@ object HttpUtils { .build() } + val deferringCallFactory = Call.Factory { request -> + runBlocking { deferredClient.await() }.newCall(request) + } + suspend fun get(url: String, bodyParser: (body: ResponseBody, rawResponse: okhttp3.Response) -> T): Response.Success { return when (val response = get(url, null, bodyParser)) { // Can only receive NotModified if lastModified argument is non-null diff --git a/app/src/main/java/com/google/android/exoplayer2/source/DrmFreeProgressiveMediaSourceFactory.kt b/app/src/main/java/com/google/android/exoplayer2/source/DrmFreeProgressiveMediaSourceFactory.kt new file mode 100644 index 0000000..e6f5374 --- /dev/null +++ b/app/src/main/java/com/google/android/exoplayer2/source/DrmFreeProgressiveMediaSourceFactory.kt @@ -0,0 +1,39 @@ +package com.google.android.exoplayer2.source + +import com.google.android.exoplayer2.C +import com.google.android.exoplayer2.MediaItem +import com.google.android.exoplayer2.drm.DrmSessionManager +import com.google.android.exoplayer2.extractor.ExtractorsFactory +import com.google.android.exoplayer2.upstream.DataSource +import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy +import com.google.android.exoplayer2.upstream.HttpDataSource +import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy + +class DrmFreeProgressiveMediaSourceFactory(private val dataSourceFactory: DataSource.Factory, + private val extractorsFactory: ExtractorsFactory) : MediaSourceFactory { + private var loadErrorHandlingPolicy: LoadErrorHandlingPolicy = DefaultLoadErrorHandlingPolicy() + var continueLoadingCheckIntervalBytes: Int = ProgressiveMediaSource.DEFAULT_LOADING_CHECK_INTERVAL_BYTES + + override fun setDrmSessionManager(drmSessionManager: DrmSessionManager?) = this + + override fun setDrmHttpDataSourceFactory(drmHttpDataSourceFactory: HttpDataSource.Factory?) = this + + override fun setDrmUserAgent(userAgent: String?) = this + + override fun setLoadErrorHandlingPolicy(loadErrorHandlingPolicy: LoadErrorHandlingPolicy?): DrmFreeProgressiveMediaSourceFactory { + this.loadErrorHandlingPolicy = loadErrorHandlingPolicy ?: DefaultLoadErrorHandlingPolicy() + return this + } + + override fun getSupportedTypes() = intArrayOf(C.TYPE_OTHER) + + override fun createMediaSource(mediaItem: MediaItem): MediaSource { + return ProgressiveMediaSource( + mediaItem, + dataSourceFactory, + extractorsFactory, + DrmSessionManager.DUMMY, + loadErrorHandlingPolicy, + continueLoadingCheckIntervalBytes) + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/player.xml b/app/src/main/res/layout/player.xml new file mode 100644 index 0000000..d53bcc4 --- /dev/null +++ b/app/src/main/res/layout/player.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file