feat: implement hardware and software upscaling
This commit is contained in:
@@ -4148,6 +4148,12 @@ kbd {
|
||||
/* Green for Direct */
|
||||
}
|
||||
|
||||
.transcode-status.upscaling {
|
||||
background: rgba(156, 39, 176, 0.8);
|
||||
/* Purple for Upscaling */
|
||||
box-shadow: 0 0 10px rgba(156, 39, 176, 0.4);
|
||||
}
|
||||
|
||||
.transcode-status.hidden {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
|
||||
@@ -587,6 +587,41 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<h3>Upscaling</h3>
|
||||
<div class="setting-item">
|
||||
<label class="setting-toggle">
|
||||
<input type="checkbox" id="setting-upscale-enabled">
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
<div class="setting-info">
|
||||
<span class="setting-label">Enable Upscaling</span>
|
||||
<span class="setting-hint">Upscale lower-resolution content to a higher resolution during transcoding.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item" id="upscale-method-container" style="display: none;">
|
||||
<div class="setting-info" style="flex: 1;">
|
||||
<span class="setting-label">Upscale Method</span>
|
||||
<span class="setting-hint">Hardware is faster; Software (Lanczos) is higher quality.</span>
|
||||
</div>
|
||||
<select id="setting-upscale-method" class="source-select" style="width: auto; min-width: 200px;">
|
||||
<option value="hardware">Hardware (GPU)</option>
|
||||
<option value="software">Software (Lanczos)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="setting-item" id="upscale-target-container" style="display: none;">
|
||||
<div class="setting-info" style="flex: 1;">
|
||||
<span class="setting-label">Upscale Target</span>
|
||||
<span class="setting-hint">Target resolution for upscaled output.</span>
|
||||
</div>
|
||||
<select id="setting-upscale-target" class="source-select" style="width: auto; min-width: 200px;">
|
||||
<option value="720p">720p (HD)</option>
|
||||
<option value="1080p" selected>1080p (Full HD)</option>
|
||||
<option value="4k">4K (2160p)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<h3>Stream Processing</h3>
|
||||
<div class="setting-item">
|
||||
|
||||
@@ -814,16 +814,17 @@ class VideoPlayer {
|
||||
}
|
||||
}
|
||||
|
||||
if (info.needsTranscode) {
|
||||
// Incompatible audio (AC3/EAC3/DTS) - use transcode session
|
||||
console.log('[Player] Auto: Using HLS transcode session');
|
||||
if (info.needsTranscode || this.settings.upscaleEnabled) {
|
||||
// Incompatible audio (AC3/EAC3/DTS) or Upscaling enabled - use transcode session
|
||||
console.log(`[Player] Auto: Using HLS transcode session (${this.settings.upscaleEnabled ? 'Upscaling' : 'Incompatible audio/video'})`);
|
||||
|
||||
// Heuristic: If video is h264, it's likely compatible, so only copy video (audio transcode only)
|
||||
// If video is hevc/other, we need full transcode
|
||||
const videoMode = (info.video && info.video.includes('h264')) ? 'copy' : 'encode';
|
||||
const statusText = videoMode === 'copy' ? 'Transcoding (Audio)' : 'Transcoding (Video)';
|
||||
// BUT: If upscaling is enabled, we MUST encode.
|
||||
const videoMode = (info.video && info.video.includes('h264') && !this.settings.upscaleEnabled) ? 'copy' : 'encode';
|
||||
const statusText = videoMode === 'copy' ? 'Transcoding (Audio)' : (this.settings.upscaleEnabled ? 'Upscaling' : 'Transcoding (Video)');
|
||||
const statusMode = this.settings.upscaleEnabled ? 'upscaling' : 'transcoding';
|
||||
|
||||
this.updateTranscodeStatus('transcoding', statusText);
|
||||
this.updateTranscodeStatus(statusMode, statusText);
|
||||
const playlistUrl = await this.startTranscodeSession(streamUrl, {
|
||||
videoMode,
|
||||
videoCodec: info.video,
|
||||
@@ -863,10 +864,12 @@ class VideoPlayer {
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: Force Video Transcode (Full)
|
||||
if (this.settings.forceVideoTranscode) {
|
||||
console.log('[Player] Force Video Transcode enabled. Starting session (encode)...');
|
||||
this.updateTranscodeStatus('transcoding', 'Transcoding (Video)');
|
||||
// CHECK: Force Video Transcode (Full) or Upscaling
|
||||
if (this.settings.forceVideoTranscode || this.settings.upscaleEnabled) {
|
||||
const statusText = this.settings.upscaleEnabled ? 'Upscaling' : 'Transcoding (Video)';
|
||||
const statusMode = this.settings.upscaleEnabled ? 'upscaling' : 'transcoding';
|
||||
console.log(`[Player] ${statusText} enabled. Starting session (encode)...`);
|
||||
this.updateTranscodeStatus(statusMode, statusText);
|
||||
const playlistUrl = await this.startTranscodeSession(streamUrl, { videoMode: 'encode' });
|
||||
this.currentUrl = playlistUrl;
|
||||
|
||||
|
||||
@@ -163,6 +163,44 @@ class SettingsPage {
|
||||
});
|
||||
}
|
||||
|
||||
// Upscaling Settings
|
||||
const upscaleEnabledToggle = document.getElementById('setting-upscale-enabled');
|
||||
const upscaleMethodSelect = document.getElementById('setting-upscale-method');
|
||||
const upscaleTargetSelect = document.getElementById('setting-upscale-target');
|
||||
const upscaleMethodContainer = document.getElementById('upscale-method-container');
|
||||
const upscaleTargetContainer = document.getElementById('upscale-target-container');
|
||||
|
||||
// Helper to toggle upscale options visibility
|
||||
const toggleUpscaleOptions = (enabled) => {
|
||||
if (upscaleMethodContainer) upscaleMethodContainer.style.display = enabled ? 'flex' : 'none';
|
||||
if (upscaleTargetContainer) upscaleTargetContainer.style.display = enabled ? 'flex' : 'none';
|
||||
};
|
||||
|
||||
// Load upscaling settings
|
||||
if (upscaleEnabledToggle) {
|
||||
upscaleEnabledToggle.checked = s.upscaleEnabled || false;
|
||||
toggleUpscaleOptions(upscaleEnabledToggle.checked);
|
||||
}
|
||||
if (upscaleMethodSelect) upscaleMethodSelect.value = s.upscaleMethod || 'hardware';
|
||||
if (upscaleTargetSelect) upscaleTargetSelect.value = s.upscaleTarget || '1080p';
|
||||
|
||||
// Upscaling event handlers
|
||||
upscaleEnabledToggle?.addEventListener('change', () => {
|
||||
this.app.player.settings.upscaleEnabled = upscaleEnabledToggle.checked;
|
||||
this.app.player.saveSettings();
|
||||
toggleUpscaleOptions(upscaleEnabledToggle.checked);
|
||||
});
|
||||
|
||||
upscaleMethodSelect?.addEventListener('change', () => {
|
||||
this.app.player.settings.upscaleMethod = upscaleMethodSelect.value;
|
||||
this.app.player.saveSettings();
|
||||
});
|
||||
|
||||
upscaleTargetSelect?.addEventListener('change', () => {
|
||||
this.app.player.settings.upscaleTarget = upscaleTargetSelect.value;
|
||||
this.app.player.saveSettings();
|
||||
});
|
||||
|
||||
// Stream processing toggles
|
||||
forceProxyToggle?.addEventListener('change', () => {
|
||||
this.app.player.settings.forceProxy = forceProxyToggle.checked;
|
||||
|
||||
@@ -395,14 +395,16 @@ class WatchPage {
|
||||
this.currentStreamInfo = info;
|
||||
this.updateQualityBadge();
|
||||
|
||||
if (info.needsTranscode) {
|
||||
console.log('[WatchPage] Auto: Using HLS transcode session (incompatible audio/video)');
|
||||
if (info.needsTranscode || settings.upscaleEnabled) {
|
||||
console.log(`[WatchPage] Auto: Using HLS transcode session (${settings.upscaleEnabled ? 'Upscaling' : 'Incompatible audio/video'})`);
|
||||
|
||||
// Heuristic: If video is h264/compat, copy video. Usage: Audio fix.
|
||||
const videoMode = (info.video && info.video.includes('h264')) ? 'copy' : 'encode';
|
||||
const statusText = videoMode === 'copy' ? 'Transcoding (Audio)' : 'Transcoding (Video)';
|
||||
// Heuristic: If video is h264/compat, copy video. Usage: Audio fix.
|
||||
// BUT: If upscaling is enabled, we MUST encode.
|
||||
const videoMode = (info.video && info.video.includes('h264') && !settings.upscaleEnabled) ? 'copy' : 'encode';
|
||||
const statusText = videoMode === 'copy' ? 'Transcoding (Audio)' : (settings.upscaleEnabled ? 'Upscaling' : 'Transcoding (Video)');
|
||||
const statusMode = settings.upscaleEnabled ? 'upscaling' : 'transcoding';
|
||||
|
||||
this.updateTranscodeStatus('transcoding', statusText);
|
||||
this.updateTranscodeStatus(statusMode, statusText);
|
||||
const playlistUrl = await this.startTranscodeSession(url, {
|
||||
videoMode,
|
||||
seekOffset: this.resumeTime, // Ensure seekOffset is passed
|
||||
@@ -434,10 +436,12 @@ class WatchPage {
|
||||
}
|
||||
}
|
||||
|
||||
// Priority 1: Force Video Transcode (Full)
|
||||
if (settings.forceVideoTranscode) {
|
||||
console.log('[WatchPage] Force Video Transcode enabled. Starting session (encode)...');
|
||||
this.updateTranscodeStatus('transcoding', 'Transcoding (Video)');
|
||||
// Priority 1: Force Video Transcode (Full) or Upscaling
|
||||
if (settings.forceVideoTranscode || settings.upscaleEnabled) {
|
||||
const statusText = settings.upscaleEnabled ? 'Upscaling' : 'Transcoding (Video)';
|
||||
const statusMode = settings.upscaleEnabled ? 'upscaling' : 'transcoding';
|
||||
console.log(`[WatchPage] ${statusText} enabled. Starting session (encode)...`);
|
||||
this.updateTranscodeStatus(statusMode, statusText);
|
||||
const playlistUrl = await this.startTranscodeSession(url, {
|
||||
videoMode: 'encode',
|
||||
seekOffset: this.resumeTime
|
||||
|
||||
Reference in New Issue
Block a user