mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-01-11 20:10:25 +00:00
added header support
This commit is contained in:
parent
767fd2ff87
commit
18fa11fd88
6 changed files with 53 additions and 5 deletions
|
|
@ -22,6 +22,7 @@ class MPVView @JvmOverloads constructor(
|
|||
private var pendingDataSource: String? = null
|
||||
private var isPaused: Boolean = true
|
||||
private var surface: Surface? = null
|
||||
private var httpHeaders: Map<String, String>? = null
|
||||
|
||||
// Event listener for React Native
|
||||
var onLoadCallback: ((duration: Double, width: Int, height: Int) -> Unit)? = null
|
||||
|
|
@ -51,6 +52,7 @@ class MPVView @JvmOverloads constructor(
|
|||
|
||||
// If a data source was set before surface was ready, load it now
|
||||
pendingDataSource?.let { url ->
|
||||
applyHttpHeaders()
|
||||
loadFile(url)
|
||||
pendingDataSource = null
|
||||
}
|
||||
|
|
@ -93,7 +95,7 @@ class MPVView @JvmOverloads constructor(
|
|||
|
||||
// Hardware decoding - use mediacodec-copy to allow subtitle overlay
|
||||
// 'mediacodec-copy' copies frames to CPU memory which enables subtitle blending
|
||||
MPVLib.setOptionString("hwdec", "mediacodec-copy")
|
||||
MPVLib.setOptionString("hwdec", "auto")
|
||||
MPVLib.setOptionString("hwdec-codecs", "all")
|
||||
|
||||
// Audio output
|
||||
|
|
@ -105,6 +107,9 @@ class MPVView @JvmOverloads constructor(
|
|||
MPVLib.setOptionString("cache", "yes")
|
||||
MPVLib.setOptionString("cache-secs", "30")
|
||||
|
||||
// Network options
|
||||
MPVLib.setOptionString("network-timeout", "60") // 60 second timeout
|
||||
|
||||
// Subtitle configuration - CRITICAL for Android
|
||||
MPVLib.setOptionString("sub-auto", "fuzzy") // Auto-load subtitles
|
||||
MPVLib.setOptionString("sub-visibility", "yes") // Make subtitles visible by default
|
||||
|
|
@ -155,7 +160,7 @@ class MPVView @JvmOverloads constructor(
|
|||
val MPV_FORMAT_DOUBLE = 5
|
||||
|
||||
MPVLib.observeProperty("time-pos", MPV_FORMAT_DOUBLE)
|
||||
MPVLib.observeProperty("duration", MPV_FORMAT_DOUBLE)
|
||||
MPVLib.observeProperty("duration/full", MPV_FORMAT_DOUBLE) // Use /full for complete HLS duration
|
||||
MPVLib.observeProperty("pause", MPV_FORMAT_FLAG)
|
||||
MPVLib.observeProperty("paused-for-cache", MPV_FORMAT_FLAG)
|
||||
MPVLib.observeProperty("eof-reached", MPV_FORMAT_FLAG)
|
||||
|
|
@ -179,12 +184,31 @@ class MPVView @JvmOverloads constructor(
|
|||
|
||||
fun setDataSource(url: String) {
|
||||
if (isMpvInitialized) {
|
||||
// Apply headers before loading the file
|
||||
applyHttpHeaders()
|
||||
loadFile(url)
|
||||
} else {
|
||||
pendingDataSource = url
|
||||
}
|
||||
}
|
||||
|
||||
fun setHeaders(headers: Map<String, String>?) {
|
||||
httpHeaders = headers
|
||||
Log.d(TAG, "Headers set: $headers")
|
||||
}
|
||||
|
||||
private fun applyHttpHeaders() {
|
||||
httpHeaders?.let { headers ->
|
||||
if (headers.isNotEmpty()) {
|
||||
// Format headers for MPV: comma-separated "Key: Value" pairs
|
||||
val headerList = headers.map { (key, value) -> "$key: $value" }
|
||||
val headerString = headerList.joinToString(",")
|
||||
Log.d(TAG, "Applying HTTP headers: $headerString")
|
||||
MPVLib.setOptionString("http-header-fields", headerString)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setPaused(paused: Boolean) {
|
||||
isPaused = paused
|
||||
if (isMpvInitialized) {
|
||||
|
|
@ -341,10 +365,10 @@ class MPVView @JvmOverloads constructor(
|
|||
Log.d(TAG, "Property $property = $value (Double)")
|
||||
when (property) {
|
||||
"time-pos" -> {
|
||||
val duration = MPVLib.getPropertyDouble("duration") ?: 0.0
|
||||
val duration = MPVLib.getPropertyDouble("duration/full") ?: MPVLib.getPropertyDouble("duration") ?: 0.0
|
||||
onProgressCallback?.invoke(value, duration)
|
||||
}
|
||||
"duration" -> {
|
||||
"duration/full", "duration" -> {
|
||||
val width = MPVLib.getPropertyInt("width") ?: 0
|
||||
val height = MPVLib.getPropertyInt("height") ?: 0
|
||||
onLoadCallback?.invoke(value, width, height)
|
||||
|
|
@ -384,7 +408,7 @@ class MPVView @JvmOverloads constructor(
|
|||
Log.d(TAG, "MPV_EVENT_END_FILE")
|
||||
|
||||
// Heuristic: If duration is effectively 0 at end of file, it's a load error
|
||||
val duration = MPVLib.getPropertyDouble("duration") ?: 0.0
|
||||
val duration = MPVLib.getPropertyDouble("duration/full") ?: MPVLib.getPropertyDouble("duration") ?: 0.0
|
||||
val timePos = MPVLib.getPropertyDouble("time-pos") ?: 0.0
|
||||
val eofReached = MPVLib.getPropertyBoolean("eof-reached") ?: false
|
||||
|
||||
|
|
|
|||
|
|
@ -163,4 +163,21 @@ class MpvPlayerViewManager(
|
|||
fun setResizeMode(view: MPVView, resizeMode: String?) {
|
||||
view.setResizeMode(resizeMode ?: "contain")
|
||||
}
|
||||
|
||||
@ReactProp(name = "headers")
|
||||
fun setHeaders(view: MPVView, headers: com.facebook.react.bridge.ReadableMap?) {
|
||||
if (headers != null) {
|
||||
val headerMap = mutableMapOf<String, String>()
|
||||
val iterator = headers.keySetIterator()
|
||||
while (iterator.hasNextKey()) {
|
||||
val key = iterator.nextKey()
|
||||
headers.getString(key)?.let { value ->
|
||||
headerMap[key] = value
|
||||
}
|
||||
}
|
||||
view.setHeaders(headerMap)
|
||||
} else {
|
||||
view.setHeaders(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1
mpv-android
Submodule
1
mpv-android
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 118cd1ed3d498265e44230e5dbb015bdd59f9dad
|
||||
|
|
@ -487,6 +487,7 @@ const AndroidVideoPlayer: React.FC = () => {
|
|||
<View style={{ flex: 1, backgroundColor: 'black' }}>
|
||||
<VideoSurface
|
||||
processedStreamUrl={currentStreamUrl}
|
||||
headers={headers}
|
||||
volume={volume}
|
||||
playbackSpeed={speedControl.playbackSpeed}
|
||||
resizeMode={playerState.resizeMode}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export interface MpvPlayerRef {
|
|||
|
||||
export interface MpvPlayerProps {
|
||||
source: string;
|
||||
headers?: { [key: string]: string };
|
||||
paused?: boolean;
|
||||
volume?: number;
|
||||
rate?: number;
|
||||
|
|
@ -92,6 +93,7 @@ const MpvPlayer = forwardRef<MpvPlayerRef, MpvPlayerProps>((props, ref) => {
|
|||
ref={nativeRef}
|
||||
style={[styles.container, props.style]}
|
||||
source={props.source}
|
||||
headers={props.headers}
|
||||
paused={props.paused ?? true}
|
||||
volume={props.volume ?? 1.0}
|
||||
rate={props.rate ?? 1.0}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { ResizeModeType } from '../../utils/playerTypes';
|
|||
|
||||
interface VideoSurfaceProps {
|
||||
processedStreamUrl: string;
|
||||
headers?: { [key: string]: string };
|
||||
volume: number;
|
||||
playbackSpeed: number;
|
||||
resizeMode: ResizeModeType;
|
||||
|
|
@ -35,6 +36,7 @@ interface VideoSurfaceProps {
|
|||
|
||||
export const VideoSurface: React.FC<VideoSurfaceProps> = ({
|
||||
processedStreamUrl,
|
||||
headers,
|
||||
volume,
|
||||
playbackSpeed,
|
||||
resizeMode,
|
||||
|
|
@ -100,6 +102,7 @@ export const VideoSurface: React.FC<VideoSurfaceProps> = ({
|
|||
<MpvPlayer
|
||||
ref={mpvPlayerRef}
|
||||
source={streamUrl}
|
||||
headers={headers}
|
||||
paused={paused}
|
||||
volume={volume}
|
||||
rate={playbackSpeed}
|
||||
|
|
|
|||
Loading…
Reference in a new issue