stash icon indicating copy to clipboard operation
stash copied to clipboard

[Feature] Set Default live transcode or change priority

Open slimthick opened this issue 2 years ago • 2 comments

Is your feature request related to a problem? Please describe. My WMV files seek and load faster when using DASH/HLS instead of the default mp4 live transcode

Describe the solution you'd like A way to set the default transcode or reorder the list in the player.

Describe alternatives you've considered I checked the yaml config file as well and couldn't find anything.

slimthick avatar Oct 05 '23 20:10 slimthick

In case anyone else was interested I wrote some custom Javascript to resolve this problem because I couldn't locate the vjsplayer instance on the page so I had to observe it. While writing this I discovered that

  1. To unlock the full power of a 12th gen Intel for transcoding vs QuickSync I need the "non-free" drivers that I was supposed to know about.
  2. At least according to intel_gpu_top, the reason why HLS/DASH/WEBM transcodes are faster is because MP4 doesn't use the integrated GPU. It also doesn't work as hard which means the fan doesn't spin up and the minipc is quieter.
//https://stackoverflow.com/a/17799291
function contains(selector, text) {
  var elements = document.querySelectorAll(selector);
  return [].filter.call(elements, function(element){
	return RegExp(text).test(element.textContent);
  });
}


function useHLS(){
	if( !videoPlayer.canBeStreamed() && !videoPlayer.hlsElementSelected() ){
				
		window.usingHLS = true;
			
		videoPlayer.hlsElement().click();
				
		console.log("Video has to be transcoded, using HLS");
		
	} 
}

//Observe less often while not on the scene player because hundreds of observations can occur
//and any observation can confirm if the url contains /scenes/
function delayObservation(delay){
	urlObserver.disconnect();
		
	setTimeout(function(){
		urlObserver.observe( document.getElementsByClassName('main container-fluid')[0], urlObserverConfig);
	}, delay);
}

/*------------------------------------------------------------------------------------------------*/

var videoPlayer = {
	
	videoJsElement : null,
	
	loadedPlayer:  null,
	
	isPlaying: function(){ //https://stackoverflow.com/a/36898221
					return  this.loadedPlayer.currentTime > 0 && 
							!this.loadedPlayer.paused && 
							!this.loadedPlayer.ended && 
							this.loadedPlayer.readyState > this.loadedPlayer.HAVE_CURRENT_DATA;
				},
				
	canBeStreamed: function(){
		return ( contains('.vjs-menu-item-text', /^direct stream$/i).length > 0 );
	},
	
	hlsElement: function(){ //optional chaining (?.)
		return ( contains('.vjs-menu-item-text', /^hls$/i)[0]?.parentElement );
	},
	
	hlsElementSelected: function(){
		return ( this.hlsElement()?.classList.contains('vjs-selected') );
	}
};

var oldScene = '';
var delay = 1000;

/*------------------------------------------------------------------------------------------------*/

const videoPlayerObserverConfig = {attributes: true};

const videoPlayerObserver = new MutationObserver(function(mutations, observer) {
			
//wait until the video is playing to avoid triggering a "The play() request was interrupted" error
//"It is worth noting that the (play())Promise won't fulfill until playback has actually started" https://developer.chrome.com/blog/play-request-was-interrupted/
	
	if( videoPlayer.isPlaying() ) {	

		observer.disconnect();		
		useHLS();
		
	}
	
});

//https://stackoverflow.com/a/67825703 
//One page application that updates href but doesnt reload the page. Observe when the application gets to
//the scenes player and attach the final observer to default to HLS as needed		

const urlObserverConfig = {childList: true, subtree: true};

var urlObserver = new MutationObserver(function(mutations, observer) {
	
	var onPlayerPage = location.href.toLocaleLowerCase().indexOf('/scenes/') !== -1;
	
	if ( onPlayerPage && (!videoPlayer.loadedPlayer) ) {
			
		videoPlayer.videoJsElement = document.querySelector('#VideoJsPlayer');
		videoPlayer.loadedPlayer = document.querySelector('#VideoJsPlayer_html5_api');

	}
	
	if ( onPlayerPage && videoPlayer.loadedPlayer ){
		
		var currentScene = location.href.match(/.*\/scenes\/\d+/i)[0];
		
	// /scenes? is the scene list while /scenes/{number}? is the scene player	
		if( currentScene !== oldScene){
			oldScene = currentScene;
			videoPlayerObserver.observe( videoPlayer.videoJsElement, videoPlayerObserverConfig );
		}
		
		delayObservation(delay);
	}

	if( !onPlayerPage ){
	
		if(videoPlayer.loadedPlayer){
			videoPlayer.loadedPlayer = null;
			videoPlayer.videoJsElement = null;
		}
		
		delayObservation(delay);
	}
});

//Only existing elements can be observed and the root element is always present
//The content of the application is then housed and updated within main
new MutationObserver(function(mutations, observer) {
	
	observer.disconnect();
	
	urlObserver.observe( document.getElementsByClassName('main container-fluid')[0], urlObserverConfig);
	
}).observe( document.getElementById('root'), {childList: true});

slimthick avatar Dec 04 '23 14:12 slimthick

This is from user PB Stash on discord channel:

It's should just be a matter of updating the following logic in ScenePlayer.tsx:

    const sourceSelector = player.sourceSelector();
    sourceSelector.setSources(
      scene.sceneStreams
        .filter((stream) => {
          const src = new URL(stream.url);
          const isFileTranscode = !isDirect(src);

          return !(isFileTranscode && isSafari);
        })
        .map((stream) => {
          const src = new URL(stream.url);

          return {
            src: stream.url,
            type: stream.mime_type ?? undefined,
            label: stream.label ?? undefined,
            offset: !isDirect(src),
            duration,
          };
        })
    );```

to filter the unsupported sources for Apple devices. The `isPlatformUniquelyRenderedByApple()` util method reports apple devices.

tonynca avatar Sep 27 '24 22:09 tonynca