mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-01-11 20:10:25 +00:00
added hw/sw toggle for android
This commit is contained in:
parent
6855a89792
commit
1f3b9413cd
7 changed files with 92 additions and 5 deletions
|
|
@ -23,6 +23,9 @@ class MPVView @JvmOverloads constructor(
|
|||
private var isPaused: Boolean = true
|
||||
private var surface: Surface? = null
|
||||
private var httpHeaders: Map<String, String>? = null
|
||||
|
||||
// Hardware decoding setting (default: false = software decoding)
|
||||
var useHardwareDecoding: Boolean = false
|
||||
|
||||
// Event listener for React Native
|
||||
var onLoadCallback: ((duration: Double, width: Int, height: Int) -> Unit)? = null
|
||||
|
|
@ -94,10 +97,11 @@ class MPVView @JvmOverloads constructor(
|
|||
MPVLib.setOptionString("opengl-es", "yes")
|
||||
|
||||
// Hardware decoding configuration
|
||||
// NOTE: On emulator, mediacodec can cause freezes due to slow GPU translation
|
||||
// Using 'no' for software decoding which is more reliable on emulator
|
||||
// For real devices, use 'mediacodec-copy' for hardware acceleration
|
||||
MPVLib.setOptionString("hwdec", "no")
|
||||
// 'mediacodec-copy' for hardware acceleration (GPU decoding, copies frames to CPU)
|
||||
// 'no' for software decoding (more compatible, especially on emulators)
|
||||
val hwdecValue = if (useHardwareDecoding) "mediacodec-copy" else "no"
|
||||
Log.d(TAG, "Hardware decoding: $useHardwareDecoding, hwdec value: $hwdecValue")
|
||||
MPVLib.setOptionString("hwdec", hwdecValue)
|
||||
MPVLib.setOptionString("hwdec-codecs", "all")
|
||||
|
||||
// Audio output
|
||||
|
|
|
|||
|
|
@ -180,4 +180,9 @@ class MpvPlayerViewManager(
|
|||
view.setHeaders(null)
|
||||
}
|
||||
}
|
||||
|
||||
@ReactProp(name = "useHardwareDecoding")
|
||||
fun setUseHardwareDecoding(view: MPVView, useHardwareDecoding: Boolean) {
|
||||
view.useHardwareDecoding = useHardwareDecoding
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import { useNextEpisode } from './android/hooks/useNextEpisode';
|
|||
import { useTraktAutosync } from '../../hooks/useTraktAutosync';
|
||||
import { useMetadata } from '../../hooks/useMetadata';
|
||||
import { usePlayerGestureControls } from '../../hooks/usePlayerGestureControls';
|
||||
import { useSettings } from '../../hooks/useSettings';
|
||||
|
||||
// Shared Components
|
||||
import { GestureControls, PauseOverlay, SpeedActivatedOverlay } from './components';
|
||||
|
|
@ -69,6 +70,7 @@ const AndroidVideoPlayer: React.FC = () => {
|
|||
const playerState = usePlayerState();
|
||||
const modals = usePlayerModals();
|
||||
const speedControl = useSpeedControl();
|
||||
const { settings } = useSettings();
|
||||
|
||||
const videoRef = useRef<any>(null);
|
||||
const mpvPlayerRef = useRef<MpvPlayerRef>(null);
|
||||
|
|
@ -550,6 +552,7 @@ const AndroidVideoPlayer: React.FC = () => {
|
|||
onPinchGestureEvent={() => { }}
|
||||
onPinchHandlerStateChange={() => { }}
|
||||
screenDimensions={playerState.screenDimensions}
|
||||
useHardwareDecoding={settings.useHardwareDecoding}
|
||||
/>
|
||||
|
||||
{/* Custom Subtitles for addon subtitles */}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export interface MpvPlayerProps {
|
|||
onEnd?: () => void;
|
||||
onError?: (error: { error: string }) => void;
|
||||
onTracksChanged?: (data: { audioTracks: any[]; subtitleTracks: any[] }) => void;
|
||||
useHardwareDecoding?: boolean;
|
||||
}
|
||||
|
||||
const MpvPlayer = forwardRef<MpvPlayerRef, MpvPlayerProps>((props, ref) => {
|
||||
|
|
@ -103,6 +104,7 @@ const MpvPlayer = forwardRef<MpvPlayerRef, MpvPlayerProps>((props, ref) => {
|
|||
onEnd={handleEnd}
|
||||
onError={handleError}
|
||||
onTracksChanged={handleTracksChanged}
|
||||
useHardwareDecoding={props.useHardwareDecoding ?? false}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ interface VideoSurfaceProps {
|
|||
onPinchHandlerStateChange: any;
|
||||
screenDimensions: { width: number, height: number };
|
||||
onTracksChanged?: (data: { audioTracks: any[]; subtitleTracks: any[] }) => void;
|
||||
useHardwareDecoding?: boolean;
|
||||
}
|
||||
|
||||
export const VideoSurface: React.FC<VideoSurfaceProps> = ({
|
||||
|
|
@ -55,6 +56,7 @@ export const VideoSurface: React.FC<VideoSurfaceProps> = ({
|
|||
onPinchHandlerStateChange,
|
||||
screenDimensions,
|
||||
onTracksChanged,
|
||||
useHardwareDecoding,
|
||||
}) => {
|
||||
// Use the actual stream URL
|
||||
const streamUrl = currentStreamUrl || processedStreamUrl;
|
||||
|
|
@ -113,6 +115,7 @@ export const VideoSurface: React.FC<VideoSurfaceProps> = ({
|
|||
onEnd={handleEnd}
|
||||
onError={handleError}
|
||||
onTracksChanged={onTracksChanged}
|
||||
useHardwareDecoding={useHardwareDecoding}
|
||||
/>
|
||||
|
||||
{/* Gesture overlay - transparent, on top of the player */}
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@ export interface AppSettings {
|
|||
streamCacheTTL: number; // Stream cache duration in milliseconds (default: 1 hour)
|
||||
enableStreamsBackdrop: boolean; // Enable blurred backdrop background on StreamsScreen mobile
|
||||
useExternalPlayerForDownloads: boolean; // Enable/disable external player for downloaded content
|
||||
// Android MPV player settings
|
||||
useHardwareDecoding: boolean; // Enable hardware decoding for MPV player on Android (default: false for software decoding)
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: AppSettings = {
|
||||
|
|
@ -149,6 +151,8 @@ export const DEFAULT_SETTINGS: AppSettings = {
|
|||
openMetadataScreenWhenCacheDisabled: true, // Default to StreamsScreen when cache disabled
|
||||
streamCacheTTL: 60 * 60 * 1000, // Default: 1 hour in milliseconds
|
||||
enableStreamsBackdrop: true, // Enable by default (new behavior)
|
||||
// Android MPV player settings
|
||||
useHardwareDecoding: false, // Default to software decoding (more compatible)
|
||||
};
|
||||
|
||||
const SETTINGS_STORAGE_KEY = 'app_settings';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
|
|
@ -14,6 +14,7 @@ import { useNavigation } from '@react-navigation/native';
|
|||
import { useSettings, AppSettings } from '../hooks/useSettings';
|
||||
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
||||
import { useTheme } from '../contexts/ThemeContext';
|
||||
import CustomAlert from '../components/CustomAlert';
|
||||
|
||||
const ANDROID_STATUSBAR_HEIGHT = StatusBar.currentHeight || 0;
|
||||
|
||||
|
|
@ -95,6 +96,17 @@ const PlayerSettingsScreen: React.FC = () => {
|
|||
const { currentTheme } = useTheme();
|
||||
const navigation = useNavigation();
|
||||
|
||||
// CustomAlert state
|
||||
const [alertVisible, setAlertVisible] = useState(false);
|
||||
const [alertTitle, setAlertTitle] = useState('');
|
||||
const [alertMessage, setAlertMessage] = useState('');
|
||||
|
||||
const openAlert = (title: string, message: string) => {
|
||||
setAlertTitle(title);
|
||||
setAlertMessage(message);
|
||||
setAlertVisible(true);
|
||||
};
|
||||
|
||||
const playerOptions = [
|
||||
{
|
||||
id: 'internal',
|
||||
|
|
@ -323,6 +335,53 @@ const PlayerSettingsScreen: React.FC = () => {
|
|||
</View>
|
||||
</View>
|
||||
|
||||
{/* Hardware Decoding for Android Internal Player */}
|
||||
{Platform.OS === 'android' && !settings.useExternalPlayer && (
|
||||
<View style={[styles.settingItem, styles.settingItemBorder, { borderTopColor: 'rgba(255,255,255,0.08)' }]}>
|
||||
<View style={styles.settingContent}>
|
||||
<View style={[
|
||||
styles.settingIconContainer,
|
||||
{ backgroundColor: 'rgba(255,255,255,0.1)' }
|
||||
]}>
|
||||
<MaterialIcons
|
||||
name="memory"
|
||||
size={20}
|
||||
color={currentTheme.colors.primary}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.settingText}>
|
||||
<Text
|
||||
style={[
|
||||
styles.settingTitle,
|
||||
{ color: currentTheme.colors.text },
|
||||
]}
|
||||
>
|
||||
Hardware Decoding
|
||||
</Text>
|
||||
<Text
|
||||
style={[
|
||||
styles.settingDescription,
|
||||
{ color: currentTheme.colors.textMuted },
|
||||
]}
|
||||
>
|
||||
Use GPU for video decoding. May improve performance but can cause issues on some devices.
|
||||
</Text>
|
||||
</View>
|
||||
<Switch
|
||||
value={settings.useHardwareDecoding}
|
||||
onValueChange={(value) => {
|
||||
updateSetting('useHardwareDecoding', value);
|
||||
openAlert(
|
||||
'Restart Required',
|
||||
'Please restart the app for the decoding change to take effect.'
|
||||
);
|
||||
}}
|
||||
thumbColor={settings.useHardwareDecoding ? currentTheme.colors.primary : undefined}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* External Player for Downloads */}
|
||||
{((Platform.OS === 'android' && settings.useExternalPlayer) ||
|
||||
(Platform.OS === 'ios' && settings.preferredPlayer !== 'internal')) && (
|
||||
|
|
@ -367,6 +426,13 @@ const PlayerSettingsScreen: React.FC = () => {
|
|||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
|
||||
<CustomAlert
|
||||
visible={alertVisible}
|
||||
title={alertTitle}
|
||||
message={alertMessage}
|
||||
onClose={() => setAlertVisible(false)}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue