mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-04-20 11:35:46 +00:00
add raw dash audio source widevine support
This commit is contained in:
parent
1b8b8f5738
commit
6ec033274f
7 changed files with 120 additions and 46 deletions
|
@ -372,7 +372,7 @@ class VideoUrlWidevineSource extends VideoUrlSource {
|
|||
super(obj);
|
||||
this.plugin_type = "VideoUrlWidevineSource";
|
||||
|
||||
this.licenseUri = obj.licenseUri;
|
||||
this.widevineLicenseUri = obj.licenseUri;
|
||||
if(obj.getLicenseRequestExecutor)
|
||||
this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor;
|
||||
}
|
||||
|
@ -409,7 +409,7 @@ class AudioUrlWidevineSource extends AudioUrlSource {
|
|||
super(obj);
|
||||
this.plugin_type = "AudioUrlWidevineSource";
|
||||
|
||||
this.licenseUri = obj.licenseUri;
|
||||
this.widevineLicenseUri = obj.licenseUri;
|
||||
if(obj.getLicenseRequestExecutor)
|
||||
this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor;
|
||||
|
||||
|
@ -469,6 +469,8 @@ class DashSource {
|
|||
this.language = obj.language;
|
||||
if(obj.requestModifier)
|
||||
this.requestModifier = obj.requestModifier;
|
||||
if(obj.getRequestExecutor)
|
||||
this.getRequestExecutor = obj.getRequestExecutor;
|
||||
}
|
||||
}
|
||||
class DashWidevineSource extends DashSource {
|
||||
|
@ -476,7 +478,7 @@ class DashWidevineSource extends DashSource {
|
|||
super(obj);
|
||||
this.plugin_type = "DashWidevineSource";
|
||||
|
||||
this.licenseUri = obj.licenseUri;
|
||||
this.widevineLicenseUri = obj.licenseUri;
|
||||
if(obj.getLicenseRequestExecutor)
|
||||
this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor;
|
||||
}
|
||||
|
@ -511,6 +513,9 @@ class DashManifestRawAudioSource {
|
|||
this.manifest = obj.manifest ?? null;
|
||||
if(obj.requestModifier)
|
||||
this.requestModifier = obj.requestModifier;
|
||||
this.widevineLicenseUri = obj.widevineLicenseUri;
|
||||
if(obj.getLicenseRequestExecutor)
|
||||
this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ package com.futo.platformplayer.api.media.models.streams.sources
|
|||
import com.futo.platformplayer.api.media.platforms.js.models.JSRequestExecutor
|
||||
|
||||
interface IWidevineSource {
|
||||
val licenseUri: String
|
||||
val widevineLicenseUri: String?
|
||||
val hasLicenseRequestExecutor: Boolean
|
||||
fun getLicenseRequestExecutor(): JSRequestExecutor?
|
||||
}
|
|
@ -8,7 +8,7 @@ import com.futo.platformplayer.engine.V8Plugin
|
|||
import com.futo.platformplayer.getOrThrow
|
||||
|
||||
class JSAudioUrlWidevineSource : JSAudioUrlSource, IAudioUrlWidevineSource {
|
||||
override val licenseUri: String
|
||||
override val widevineLicenseUri: String
|
||||
override val hasLicenseRequestExecutor: Boolean
|
||||
|
||||
@Suppress("ConvertSecondaryConstructorToPrimary")
|
||||
|
@ -16,7 +16,7 @@ class JSAudioUrlWidevineSource : JSAudioUrlSource, IAudioUrlWidevineSource {
|
|||
val contextName = "JSAudioUrlWidevineSource"
|
||||
val config = plugin.config
|
||||
|
||||
licenseUri = _obj.getOrThrow(config, "licenseUri", contextName)
|
||||
widevineLicenseUri = _obj.getOrThrow(config, "widevineLicenseUri", contextName)
|
||||
hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor")
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,6 @@ class JSAudioUrlWidevineSource : JSAudioUrlSource, IAudioUrlWidevineSource {
|
|||
|
||||
override fun toString(): String {
|
||||
val url = getAudioUrl()
|
||||
return "(name=$name, container=$container, bitrate=$bitrate, codec=$codec, url=$url, language=$language, duration=$duration, hasLicenseRequestExecutor=${hasLicenseRequestExecutor}, licenseUri=$licenseUri)"
|
||||
return "(name=$name, container=$container, bitrate=$bitrate, codec=$codec, url=$url, language=$language, duration=$duration, hasLicenseRequestExecutor=${hasLicenseRequestExecutor}, widevineLicenseUri=$widevineLicenseUri)"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,19 +2,17 @@ package com.futo.platformplayer.api.media.platforms.js.models.sources
|
|||
|
||||
import com.caoccao.javet.values.reference.V8ValueObject
|
||||
import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource
|
||||
import com.futo.platformplayer.api.media.models.streams.sources.IDashManifestSource
|
||||
import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlSource
|
||||
import com.futo.platformplayer.api.media.models.streams.sources.IWidevineSource
|
||||
import com.futo.platformplayer.api.media.platforms.js.DevJSClient
|
||||
import com.futo.platformplayer.api.media.platforms.js.JSClient
|
||||
import com.futo.platformplayer.engine.IV8PluginConfig
|
||||
import com.futo.platformplayer.api.media.platforms.js.models.JSRequestExecutor
|
||||
import com.futo.platformplayer.engine.V8Plugin
|
||||
import com.futo.platformplayer.getOrDefault
|
||||
import com.futo.platformplayer.getOrNull
|
||||
import com.futo.platformplayer.getOrThrow
|
||||
import com.futo.platformplayer.others.Language
|
||||
import com.futo.platformplayer.states.StateDeveloper
|
||||
|
||||
class JSDashManifestRawAudioSource : JSSource, IAudioSource, IJSDashManifestRawSource {
|
||||
class JSDashManifestRawAudioSource : JSSource, IAudioSource, IJSDashManifestRawSource, IWidevineSource {
|
||||
override val container : String = "application/dash+xml";
|
||||
override val name : String;
|
||||
override val codec: String;
|
||||
|
@ -29,6 +27,9 @@ class JSDashManifestRawAudioSource : JSSource, IAudioSource, IJSDashManifestRawS
|
|||
|
||||
override val hasGenerate: Boolean;
|
||||
|
||||
override val widevineLicenseUri: String?
|
||||
override val hasLicenseRequestExecutor: Boolean
|
||||
|
||||
constructor(plugin: JSClient, obj: V8ValueObject) : super(TYPE_DASH_RAW, plugin, obj) {
|
||||
val contextName = "DashRawSource";
|
||||
val config = plugin.config;
|
||||
|
@ -41,6 +42,23 @@ class JSDashManifestRawAudioSource : JSSource, IAudioSource, IJSDashManifestRawS
|
|||
priority = _obj.getOrDefault(config, "priority", contextName, false) ?: false;
|
||||
language = _obj.getOrDefault(config, "language", contextName, Language.UNKNOWN) ?: Language.UNKNOWN;
|
||||
hasGenerate = _obj.has("generate");
|
||||
|
||||
widevineLicenseUri = _obj.getOrThrow(config, "widevineLicenseUri", contextName)
|
||||
hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor")
|
||||
}
|
||||
|
||||
override fun getLicenseRequestExecutor(): JSRequestExecutor? {
|
||||
if (!hasLicenseRequestExecutor || _obj.isClosed)
|
||||
return null
|
||||
|
||||
val result = V8Plugin.catchScriptErrors<Any>(_config, "[${_config.name}] JSDashManifestRawAudioSource", "obj.getLicenseRequestExecutor()") {
|
||||
_obj.invoke("getLicenseRequestExecutor", arrayOf<Any>())
|
||||
}
|
||||
|
||||
if (result !is V8ValueObject)
|
||||
return null
|
||||
|
||||
return JSRequestExecutor(_plugin, result)
|
||||
}
|
||||
|
||||
override fun generate(): String? {
|
||||
|
@ -61,4 +79,4 @@ class JSDashManifestRawAudioSource : JSSource, IAudioSource, IJSDashManifestRawS
|
|||
_obj.invokeString("generate");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ class JSDashManifestWidevineSource : IVideoUrlSource, IDashManifestSource,
|
|||
|
||||
override var priority: Boolean = false
|
||||
|
||||
override val licenseUri: String
|
||||
override val widevineLicenseUri: String
|
||||
override val hasLicenseRequestExecutor: Boolean
|
||||
|
||||
@Suppress("ConvertSecondaryConstructorToPrimary")
|
||||
|
@ -36,7 +36,7 @@ class JSDashManifestWidevineSource : IVideoUrlSource, IDashManifestSource,
|
|||
|
||||
priority = obj.getOrNull(config, "priority", contextName) ?: false
|
||||
|
||||
licenseUri = _obj.getOrThrow(config, "licenseUri", contextName)
|
||||
widevineLicenseUri = _obj.getOrThrow(config, "widevineLicenseUri", contextName)
|
||||
hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor")
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import com.futo.platformplayer.engine.V8Plugin
|
|||
import com.futo.platformplayer.getOrThrow
|
||||
|
||||
class JSVideoUrlWidevineSource : JSVideoUrlSource, IVideoUrlWidevineSource {
|
||||
override val licenseUri: String
|
||||
override val widevineLicenseUri: String
|
||||
override val hasLicenseRequestExecutor: Boolean
|
||||
|
||||
@Suppress("ConvertSecondaryConstructorToPrimary")
|
||||
|
@ -16,7 +16,7 @@ class JSVideoUrlWidevineSource : JSVideoUrlSource, IVideoUrlWidevineSource {
|
|||
val contextName = "JSAudioUrlWidevineSource"
|
||||
val config = plugin.config
|
||||
|
||||
licenseUri = _obj.getOrThrow(config, "licenseUri", contextName)
|
||||
widevineLicenseUri = _obj.getOrThrow(config, "widevineLicenseUri", contextName)
|
||||
hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor")
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,6 @@ class JSVideoUrlWidevineSource : JSVideoUrlSource, IVideoUrlWidevineSource {
|
|||
|
||||
override fun toString(): String {
|
||||
val url = getVideoUrl()
|
||||
return "(width=$width, height=$height, container=$container, codec=$codec, name=$name, bitrate=$bitrate, duration=$duration, url=$url, hasLicenseRequestExecutor=$hasLicenseRequestExecutor, licenseUri=$licenseUri)"
|
||||
return "(width=$width, height=$height, container=$container, codec=$codec, name=$name, bitrate=$bitrate, duration=$duration, url=$url, hasLicenseRequestExecutor=$hasLicenseRequestExecutor, widevineLicenseUri=$widevineLicenseUri)"
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package com.futo.platformplayer.views.video
|
||||
|
||||
import android.content.Context
|
||||
import android.media.MediaDrm
|
||||
import android.net.Uri
|
||||
import android.util.AttributeSet
|
||||
import android.widget.RelativeLayout
|
||||
|
@ -57,8 +58,8 @@ import com.futo.platformplayer.helpers.VideoHelper
|
|||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.states.StateApp
|
||||
import com.futo.platformplayer.video.PlayerManager
|
||||
import com.futo.platformplayer.views.video.datasources.PluginMediaDrmCallback
|
||||
import com.futo.platformplayer.views.video.datasources.JSHttpDataSource
|
||||
import com.futo.platformplayer.views.video.datasources.PluginMediaDrmCallback
|
||||
import getHttpDataSourceFactory
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -483,15 +484,20 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
|
|||
@OptIn(UnstableApi::class)
|
||||
private fun swapVideoSourceUrlWidevine(videoSource: IVideoUrlWidevineSource) {
|
||||
Logger.i(TAG, "Loading VideoSource [UrlWidevine]");
|
||||
|
||||
if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) {
|
||||
throw IllegalArgumentException("Device does not support Widevine")
|
||||
}
|
||||
|
||||
val dataSource = if(videoSource is JSSource && videoSource.requiresCustomDatasource)
|
||||
videoSource.getHttpDataSourceFactory()
|
||||
else
|
||||
DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT)
|
||||
|
||||
val baseCallback = HttpMediaDrmCallback(videoSource.licenseUri, dataSource)
|
||||
val baseCallback = HttpMediaDrmCallback(videoSource.widevineLicenseUri, dataSource)
|
||||
|
||||
val callback = if (videoSource.hasLicenseRequestExecutor) {
|
||||
PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.licenseUri)
|
||||
PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.widevineLicenseUri!!)
|
||||
} else {
|
||||
baseCallback
|
||||
}
|
||||
|
@ -519,14 +525,19 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
|
|||
@OptIn(UnstableApi::class)
|
||||
private fun swapVideoSourceDashWidevine(videoSource: IDashManifestWidevineSource) {
|
||||
Logger.i(TAG, "Loading VideoSource [DashWidevine]")
|
||||
|
||||
if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) {
|
||||
throw IllegalArgumentException("Device does not support Widevine")
|
||||
}
|
||||
|
||||
val dataSource =
|
||||
if (videoSource is JSSource && (videoSource.requiresCustomDatasource)) videoSource.getHttpDataSourceFactory()
|
||||
else DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT)
|
||||
|
||||
val baseCallback = HttpMediaDrmCallback(videoSource.licenseUri, dataSource)
|
||||
val baseCallback = HttpMediaDrmCallback(videoSource.widevineLicenseUri, dataSource)
|
||||
|
||||
val callback = if (videoSource.hasLicenseRequestExecutor) {
|
||||
PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.licenseUri)
|
||||
PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.widevineLicenseUri!!)
|
||||
} else {
|
||||
baseCallback
|
||||
}
|
||||
|
@ -651,49 +662,89 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
|
|||
|
||||
@OptIn(UnstableApi::class)
|
||||
private fun swapAudioSourceDashRaw(audioSource: JSDashManifestRawAudioSource, play: Boolean, resume: Boolean): Boolean {
|
||||
Logger.i(TAG, "Loading AudioSource [DashRaw]");
|
||||
val dataSource = if(audioSource is JSSource && (audioSource.requiresCustomDatasource))
|
||||
Logger.i(TAG, "Loading AudioSource [DashRaw]")
|
||||
val dataSource = if (audioSource.requiresCustomDatasource)
|
||||
audioSource.getHttpDataSourceFactory()
|
||||
else
|
||||
DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT);
|
||||
if(audioSource.hasGenerate) {
|
||||
DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT)
|
||||
|
||||
val baseCallback = HttpMediaDrmCallback(audioSource.widevineLicenseUri, dataSource)
|
||||
|
||||
val callback =
|
||||
if (audioSource.hasLicenseRequestExecutor && audioSource.widevineLicenseUri != null) {
|
||||
PluginMediaDrmCallback(baseCallback, audioSource.getLicenseRequestExecutor()!!, audioSource.widevineLicenseUri)
|
||||
} else {
|
||||
baseCallback
|
||||
}
|
||||
|
||||
_lastVideoMediaSource = DashMediaSource.Factory(dataSource).setDrmSessionManagerProvider {
|
||||
DefaultDrmSessionManager.Builder().setMultiSession(true).build(callback)
|
||||
}.createMediaSource(MediaItem.fromUri(audioSource.url))
|
||||
|
||||
if (audioSource.hasGenerate) {
|
||||
findViewTreeLifecycleOwner()?.lifecycle?.coroutineScope?.launch(Dispatchers.IO) {
|
||||
val generated = audioSource.generate();
|
||||
if(generated != null) {
|
||||
val generated = audioSource.generate()
|
||||
if (generated != null) {
|
||||
withContext(Dispatchers.Main) {
|
||||
_lastVideoMediaSource = DashMediaSource.Factory(dataSource)
|
||||
.createMediaSource(DashManifestParser().parse(Uri.parse(audioSource.url),
|
||||
ByteArrayInputStream(generated?.toByteArray() ?: ByteArray(0))));
|
||||
loadSelectedSources(play, resume);
|
||||
val factory = DashMediaSource.Factory(dataSource)
|
||||
if (audioSource.widevineLicenseUri != null) {
|
||||
if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) {
|
||||
throw IllegalArgumentException("Device does not support Widevine")
|
||||
}
|
||||
factory.setDrmSessionManagerProvider {
|
||||
DefaultDrmSessionManager.Builder().setMultiSession(true)
|
||||
.build(callback)
|
||||
}
|
||||
}
|
||||
_lastVideoMediaSource = factory.createMediaSource(
|
||||
DashManifestParser().parse(
|
||||
Uri.parse(audioSource.url),
|
||||
ByteArrayInputStream(generated.toByteArray() ?: ByteArray(0))
|
||||
)
|
||||
)
|
||||
loadSelectedSources(play, resume)
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
_lastVideoMediaSource = DashMediaSource.Factory(dataSource)
|
||||
.createMediaSource(
|
||||
DashManifestParser().parse(
|
||||
Uri.parse(audioSource.url),
|
||||
ByteArrayInputStream(audioSource.manifest?.toByteArray() ?: ByteArray(0))
|
||||
)
|
||||
);
|
||||
return true;
|
||||
return false
|
||||
} else {
|
||||
val factory = DashMediaSource.Factory(dataSource)
|
||||
if (audioSource.widevineLicenseUri != null) {
|
||||
if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) {
|
||||
throw IllegalArgumentException("Device does not support Widevine")
|
||||
}
|
||||
factory.setDrmSessionManagerProvider {
|
||||
DefaultDrmSessionManager.Builder().setMultiSession(true)
|
||||
.build(callback)
|
||||
}
|
||||
}
|
||||
_lastVideoMediaSource = factory.createMediaSource(
|
||||
DashManifestParser().parse(
|
||||
Uri.parse(audioSource.url),
|
||||
ByteArrayInputStream(audioSource.manifest?.toByteArray() ?: ByteArray(0))
|
||||
)
|
||||
)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
private fun swapAudioSourceUrlWidevine(audioSource: IAudioUrlWidevineSource) {
|
||||
Logger.i(TAG, "Loading AudioSource [UrlWidevine]")
|
||||
|
||||
if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) {
|
||||
throw IllegalArgumentException("Device does not support Widevine")
|
||||
}
|
||||
|
||||
val dataSource = if (audioSource is JSSource && audioSource.requiresCustomDatasource)
|
||||
audioSource.getHttpDataSourceFactory()
|
||||
else
|
||||
DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT)
|
||||
|
||||
val baseCallback = HttpMediaDrmCallback(audioSource.licenseUri, dataSource)
|
||||
val baseCallback = HttpMediaDrmCallback(audioSource.widevineLicenseUri, dataSource)
|
||||
|
||||
val callback = if (audioSource.hasLicenseRequestExecutor) {
|
||||
PluginMediaDrmCallback(baseCallback, audioSource.getLicenseRequestExecutor()!!, audioSource.licenseUri)
|
||||
PluginMediaDrmCallback(baseCallback, audioSource.getLicenseRequestExecutor()!!, audioSource.widevineLicenseUri!!)
|
||||
} else {
|
||||
baseCallback
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue