vod: switch to new config pattern
parent
722f426d3f
commit
ec4db393b3
|
@ -32,6 +32,8 @@ class VideoSetup extends Command
|
||||||
{
|
{
|
||||||
protected IConfig $config;
|
protected IConfig $config;
|
||||||
protected OutputInterface $output;
|
protected OutputInterface $output;
|
||||||
|
protected string $sampleFile;
|
||||||
|
protected string $logFile;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
IConfig $config
|
IConfig $config
|
||||||
|
@ -50,16 +52,18 @@ class VideoSetup extends Command
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
{
|
{
|
||||||
|
$this->output = $output;
|
||||||
|
|
||||||
// Preset executables
|
// Preset executables
|
||||||
$ffmpegPath = $this->config->getSystemValue('memories.ffmpeg_path', 'ffmpeg');
|
$ffmpegPath = $this->config->getSystemValue('memories.vod.ffmpeg', 'ffmpeg');
|
||||||
if ('ffmpeg' === $ffmpegPath) {
|
if ('ffmpeg' === $ffmpegPath) {
|
||||||
$ffmpegPath = trim(shell_exec('which ffmpeg') ?: 'ffmpeg');
|
$ffmpegPath = trim(shell_exec('which ffmpeg') ?: 'ffmpeg');
|
||||||
$this->config->setSystemValue('memories.ffmpeg_path', $ffmpegPath);
|
$this->config->setSystemValue('memories.vod.ffmpeg', $ffmpegPath);
|
||||||
}
|
}
|
||||||
$ffprobePath = $this->config->getSystemValue('memories.ffprobe_path', 'ffprobe');
|
$ffprobePath = $this->config->getSystemValue('memories.vod.ffprobe', 'ffprobe');
|
||||||
if ('ffprobe' === $ffprobePath) {
|
if ('ffprobe' === $ffprobePath) {
|
||||||
$ffprobePath = trim(shell_exec('which ffprobe') ?: 'ffprobe');
|
$ffprobePath = trim(shell_exec('which ffprobe') ?: 'ffprobe');
|
||||||
$this->config->setSystemValue('memories.ffprobe_path', $ffprobePath);
|
$this->config->setSystemValue('memories.vod.ffprobe', $ffprobePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get ffmpeg version
|
// Get ffmpeg version
|
||||||
|
@ -83,12 +87,12 @@ class VideoSetup extends Command
|
||||||
if (null === $ffmpeg || null === $ffprobe) {
|
if (null === $ffmpeg || null === $ffprobe) {
|
||||||
$output->writeln('ffmpeg and ffprobe are required for video transcoding');
|
$output->writeln('ffmpeg and ffprobe are required for video transcoding');
|
||||||
|
|
||||||
return $this->suggestDisable($output);
|
return $this->suggestDisable();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check go-vod binary
|
// Check go-vod binary
|
||||||
$output->writeln('Checking for go-vod binary');
|
$output->writeln('Checking for go-vod binary');
|
||||||
$goVodPath = $this->config->getSystemValue('memories.transcoder', false);
|
$goVodPath = $this->config->getSystemValue('memories.vod.path', false);
|
||||||
|
|
||||||
if (!\is_string($goVodPath) || !file_exists($goVodPath)) {
|
if (!\is_string($goVodPath) || !file_exists($goVodPath)) {
|
||||||
// Detect architecture
|
// Detect architecture
|
||||||
|
@ -97,9 +101,9 @@ class VideoSetup extends Command
|
||||||
|
|
||||||
if (!$goVodPath) {
|
if (!$goVodPath) {
|
||||||
$output->writeln('<error>Compatible go-vod binary not found</error>');
|
$output->writeln('<error>Compatible go-vod binary not found</error>');
|
||||||
$this->suggestGoVod($output);
|
$this->suggestGoVod();
|
||||||
|
|
||||||
return $this->suggestDisable($output);
|
return $this->suggestDisable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,9 +113,9 @@ class VideoSetup extends Command
|
||||||
$goVod = shell_exec($goVodPath.' test');
|
$goVod = shell_exec($goVodPath.' test');
|
||||||
if (!$goVod || false === strpos($goVod, 'test successful')) {
|
if (!$goVod || false === strpos($goVod, 'test successful')) {
|
||||||
$output->writeln('<error>go-vod could not be run</error>');
|
$output->writeln('<error>go-vod could not be run</error>');
|
||||||
$this->suggestGoVod($output);
|
$this->suggestGoVod();
|
||||||
|
|
||||||
return $this->suggestDisable($output);
|
return $this->suggestDisable();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go transcode is working. Yay!
|
// Go transcode is working. Yay!
|
||||||
|
@ -127,70 +131,251 @@ class VideoSetup extends Command
|
||||||
$output->writeln('Do you want to enable transcoding and HLS? [Y/n]');
|
$output->writeln('Do you want to enable transcoding and HLS? [Y/n]');
|
||||||
|
|
||||||
if ('n' === trim(fgets(fopen('php://stdin', 'r')))) {
|
if ('n' === trim(fgets(fopen('php://stdin', 'r')))) {
|
||||||
$this->config->setSystemValue('memories.no_transcode', true);
|
$this->config->setSystemValue('memories.vod.disable', true);
|
||||||
$output->writeln('<error>Transcoding and HLS are now disabled</error>');
|
$output->writeln('<error>Transcoding and HLS are now disabled</error>');
|
||||||
|
|
||||||
$this->killGoVod($output, $goVodPath);
|
$this->killGoVod($goVodPath);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->config->setSystemValue('memories.transcoder', $goVodPath);
|
$this->config->setSystemValue('memories.vod.path', $goVodPath);
|
||||||
$this->config->setSystemValue('memories.no_transcode', false);
|
$this->config->setSystemValue('memories.vod.disable', false);
|
||||||
$output->writeln('Transcoding and HLS are now enabled! Monitor the output at /tmp/go-vod.log for any errors');
|
|
||||||
$output->writeln('You should restart the server for changes to take effect');
|
|
||||||
|
|
||||||
// Check for VAAPI
|
// Feature detection
|
||||||
$output->writeln("\nChecking for VAAPI (/dev/dri/renderD128)");
|
$this->detectFeatures();
|
||||||
if (file_exists('/dev/dri/renderD128')) {
|
|
||||||
$output->writeln('VAAPI is available. Do you want to enable it? [Y/n]');
|
|
||||||
|
|
||||||
if ('n' === trim(fgets(fopen('php://stdin', 'r')))) {
|
// Success
|
||||||
$this->config->setSystemValue('memories.qsv', false);
|
$output->writeln("\nTranscoding and HLS are now enabled! Monitor the log file for any errors");
|
||||||
$output->writeln('VAAPI is now disabled');
|
$output->writeln('<error>You should restart the server for changes to take effect</error>');
|
||||||
} else {
|
|
||||||
$output->writeln("\nVAAPI is now enabled. You may still need to install the Intel Media Driver");
|
|
||||||
$output->writeln('and ensure proper permissions for /dev/dri/renderD128.');
|
|
||||||
$output->writeln('See the documentation for more details.');
|
|
||||||
$this->config->setSystemValue('memories.qsv', true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$output->writeln('VAAPI is not available');
|
|
||||||
$this->config->setSystemValue('memories.qsv', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->killGoVod($output, $goVodPath);
|
$this->killGoVod();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function suggestGoVod(OutputInterface $output): void
|
protected function suggestGoVod(): void
|
||||||
{
|
{
|
||||||
$output->writeln('You may build go-vod from source');
|
$this->output->writeln('You may build go-vod from source');
|
||||||
$output->writeln('It can be downloaded from https://github.com/pulsejet/go-vod');
|
$this->output->writeln('It can be downloaded from https://github.com/pulsejet/go-vod');
|
||||||
$output->writeln('Once built, point the path to the binary in the config for `memories.transcoder`');
|
$this->output->writeln('Once built, point the path to the binary in the config for `memories.vod.path`');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function suggestDisable(OutputInterface $output)
|
protected function suggestDisable()
|
||||||
{
|
{
|
||||||
$output->writeln('Without transcoding, video playback may be slow and limited');
|
$this->output->writeln('Without transcoding, video playback may be slow and limited');
|
||||||
$output->writeln('Do you want to disable transcoding and HLS streaming? [y/N]');
|
$this->output->writeln('Do you want to disable transcoding and HLS streaming? [y/N]');
|
||||||
if ('y' !== trim(fgets(fopen('php://stdin', 'r')))) {
|
if ('y' !== trim(fgets(fopen('php://stdin', 'r')))) {
|
||||||
$output->writeln('Aborting');
|
$this->output->writeln('Aborting');
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->config->setSystemValue('memories.no_transcode', true);
|
$this->config->setSystemValue('memories.vod.disable', true);
|
||||||
$output->writeln('<error>Transcoding and HLS are now disabled</error>');
|
$this->output->writeln('<error>Transcoding and HLS are now disabled</error>');
|
||||||
$output->writeln('You should restart the server for changes to take effect');
|
$this->output->writeln('You should restart the server for changes to take effect');
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function killGoVod(OutputInterface $output, string $path): void
|
protected function detectFeatures()
|
||||||
{
|
{
|
||||||
$output->writeln("\nKilling any existing go-vod processes");
|
$this->output->writeln("\nStarting ffmpeg feature detection");
|
||||||
|
$this->output->writeln('This may take a while. Please be patient');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Download test file
|
||||||
|
$this->output->write("\nDownloading test video file ... ");
|
||||||
|
$this->sampleFile = $this->downloadSampleFile();
|
||||||
|
if (!file_exists($this->sampleFile)) {
|
||||||
|
$this->output->writeln('FAIL');
|
||||||
|
$this->output->writeln('<error>Could not download sample file</error>');
|
||||||
|
$this->output->writeln('<error>Failed to perform feature detection</error>');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->output->writeln('OK');
|
||||||
|
|
||||||
|
// Start go-vod
|
||||||
|
if (!$this->startGoVod()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->checkCPU();
|
||||||
|
$this->checkVAAPI();
|
||||||
|
} finally {
|
||||||
|
if (file_exists($this->sampleFile)) {
|
||||||
|
unlink($this->sampleFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->output->writeln("\nFeature detection completed");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkCPU()
|
||||||
|
{
|
||||||
|
$this->output->writeln('');
|
||||||
|
$this->testResult('CPU');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkVAAPI()
|
||||||
|
{
|
||||||
|
// Check for VAAPI
|
||||||
|
$this->output->write("\nChecking for VAAPI acceleration (/dev/dri/renderD128) ... ");
|
||||||
|
if (!file_exists('/dev/dri/renderD128')) {
|
||||||
|
$this->output->writeln('NOT FOUND');
|
||||||
|
$this->config->setSystemValue('memories.vod.vaapi', false);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->output->writeln('OK');
|
||||||
|
|
||||||
|
// Check permissions
|
||||||
|
$this->output->write('Checking for permissions on /dev/dri/renderD128 ... ');
|
||||||
|
if (!is_readable('/dev/dri/renderD128')) {
|
||||||
|
$this->output->writeln('NO');
|
||||||
|
$this->output->writeln('<error>Current user does not have read permissions on /dev/dri/renderD128</error>');
|
||||||
|
$this->output->writeln('VAAPI will not work. You may need to add your user to the video/render groups');
|
||||||
|
$this->config->setSystemValue('memories.vod.vaapi', false);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->output->writeln('OK');
|
||||||
|
|
||||||
|
// Try enabling VAAPI
|
||||||
|
$this->config->setSystemValue('memories.vod.vaapi', true);
|
||||||
|
$basic = $this->testResult('VAAPI');
|
||||||
|
|
||||||
|
// Try with low_power
|
||||||
|
$this->config->setSystemValue('memories.vod.vaapi.low_power', true);
|
||||||
|
$lowPower = $this->testResult('VAAPI (low_power)');
|
||||||
|
if (!$lowPower) {
|
||||||
|
$this->config->deleteSystemValue('memories.vod.vaapi.low_power');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if passed any test
|
||||||
|
if (!$basic && !$lowPower) {
|
||||||
|
$this->config->setSystemValue('memories.vod.vaapi', false);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything is good
|
||||||
|
$this->output->writeln('Do you want to enable VAAPI acceleration? [Y/n]');
|
||||||
|
if ('n' === trim(fgets(fopen('php://stdin', 'r')))) {
|
||||||
|
$this->config->setSystemValue('memories.vod.vaapi', false);
|
||||||
|
$this->output->writeln('VAAPI is now disabled');
|
||||||
|
} else {
|
||||||
|
$this->output->writeln("\nVAAPI is now enabled. You may still need to install the Intel Media Driver");
|
||||||
|
$this->output->writeln('and ensure proper permissions for /dev/dri/renderD128.');
|
||||||
|
$this->output->writeln('See the documentation for more details.');
|
||||||
|
$this->config->setSystemValue('memories.vod.vaapi', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function test(): void
|
||||||
|
{
|
||||||
|
$url = \OCA\Memories\Controller\VideoController::getGoVodUrl('test', $this->sampleFile, '360p-000001.ts');
|
||||||
|
|
||||||
|
// Make a GET request
|
||||||
|
$ch = curl_init($url);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
|
||||||
|
// Check for errors
|
||||||
|
if (curl_errno($ch)) {
|
||||||
|
throw new \Exception('Curl: '.curl_error($ch));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for 200
|
||||||
|
if (200 !== $httpCode) {
|
||||||
|
throw new \Exception('HTTP status: '.$httpCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check response size is greater than 10kb
|
||||||
|
if (\strlen($response) < 10240) {
|
||||||
|
throw new \Exception('Response size is too small');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function testResult(string $name): bool
|
||||||
|
{
|
||||||
|
$this->output->write("Testing transcoding with {$name} ... ");
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->restartGoVod($this->output);
|
||||||
|
$this->test();
|
||||||
|
$this->output->writeln('OK');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$msg = $e->getMessage();
|
||||||
|
$logFile = $this->logFile;
|
||||||
|
$this->output->writeln('FAIL');
|
||||||
|
$this->output->writeln("<error>{$name} transcoding failed with error {$msg}</error>");
|
||||||
|
$this->output->writeln("Check the log file of go-vod for more details ({$logFile})");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function startGoVod(bool $suppress = false): bool
|
||||||
|
{
|
||||||
|
if (!$suppress) {
|
||||||
|
$this->output->write("\nAttempting to start go-vod ... ");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->logFile = $logFile = \OCA\Memories\Controller\VideoController::startGoVod();
|
||||||
|
if (!$suppress) {
|
||||||
|
$this->output->writeln('OK');
|
||||||
|
$this->output->writeln("go-vod logs will be stored at: {$logFile}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
if (!$suppress) {
|
||||||
|
$this->output->writeln('FAIL');
|
||||||
|
} else {
|
||||||
|
$this->output->writeln('<error>Failed to (re-)start go-vod</error>');
|
||||||
|
}
|
||||||
|
$this->output->writeln($e->getMessage());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function killGoVod(string $path = ''): void
|
||||||
|
{
|
||||||
|
if ('' === $path) {
|
||||||
|
$path = $this->config->getSystemValue('memories.vod.path');
|
||||||
|
}
|
||||||
|
|
||||||
\OCA\Memories\Util::pkill($path);
|
\OCA\Memories\Util::pkill($path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function restartGoVod(): void
|
||||||
|
{
|
||||||
|
$this->killGoVod();
|
||||||
|
sleep(1);
|
||||||
|
$this->startGoVod(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function downloadSampleFile(): string
|
||||||
|
{
|
||||||
|
$sampleFile = tempnam(sys_get_temp_dir(), 'sample.mp4');
|
||||||
|
$fp = fopen($sampleFile, 'w+');
|
||||||
|
$ch = curl_init('https://github.com/pulsejet/memories-assets/raw/main/sample.mp4');
|
||||||
|
curl_setopt($ch, CURLOPT_FILE, $fp);
|
||||||
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||||
|
curl_exec($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
fclose($fp);
|
||||||
|
|
||||||
|
return $sampleFile;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,7 +151,7 @@ class PageController extends Controller
|
||||||
$initialState->provideInitialState('version', $appManager->getAppInfo('memories')['version']);
|
$initialState->provideInitialState('version', $appManager->getAppInfo('memories')['version']);
|
||||||
|
|
||||||
// Video configuration
|
// Video configuration
|
||||||
$initialState->provideInitialState('notranscode', $config->getSystemValue('memories.no_transcode', 'UNSET'));
|
$initialState->provideInitialState('notranscode', $config->getSystemValue('memories.vod.disable', 'UNSET'));
|
||||||
$initialState->provideInitialState('video_default_quality', $config->getSystemValue('memories.video_default_quality', '0'));
|
$initialState->provideInitialState('video_default_quality', $config->getSystemValue('memories.video_default_quality', '0'));
|
||||||
|
|
||||||
// Geo configuration
|
// Geo configuration
|
||||||
|
|
|
@ -43,7 +43,7 @@ class VideoController extends ApiBase
|
||||||
public function transcode(string $client, int $fileid, string $profile): Http\Response
|
public function transcode(string $client, int $fileid, string $profile): Http\Response
|
||||||
{
|
{
|
||||||
// Make sure not running in read-only mode
|
// Make sure not running in read-only mode
|
||||||
if (false !== $this->config->getSystemValue('memories.no_transcode', 'UNSET')) {
|
if (false !== $this->config->getSystemValue('memories.vod.disable', 'UNSET')) {
|
||||||
return new JSONResponse(['message' => 'Transcoding disabled'], Http::STATUS_FORBIDDEN);
|
return new JSONResponse(['message' => 'Transcoding disabled'], Http::STATUS_FORBIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ class VideoController extends ApiBase
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transcode video if allowed
|
// Transcode video if allowed
|
||||||
if ($transcode && !$this->config->getSystemValue('memories.no_transcode', true)) {
|
if ($transcode && !$this->config->getSystemValue('memories.vod.disable', true)) {
|
||||||
// If video path not given, write to temp file
|
// If video path not given, write to temp file
|
||||||
if (!$liveVideoPath) {
|
if (!$liveVideoPath) {
|
||||||
$liveVideoPath = tempnam(sys_get_temp_dir(), 'livevideo');
|
$liveVideoPath = tempnam(sys_get_temp_dir(), 'livevideo');
|
||||||
|
@ -223,18 +223,17 @@ class VideoController extends ApiBase
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getUpstream($client, $path, $profile)
|
/**
|
||||||
|
* Start the transcoder.
|
||||||
|
*
|
||||||
|
* @return string Path to log file
|
||||||
|
*/
|
||||||
|
public static function startGoVod()
|
||||||
{
|
{
|
||||||
$returnCode = $this->getUpstreamInternal($client, $path, $profile);
|
$config = \OC::$server->get(\OCP\IConfig::class);
|
||||||
|
|
||||||
// If status code was 0, it's likely the server is down
|
|
||||||
// Make one attempt to start after killing whatever is there
|
|
||||||
if (0 !== $returnCode) {
|
|
||||||
return $returnCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get transcoder path
|
// Get transcoder path
|
||||||
$transcoder = $this->config->getSystemValue('memories.transcoder', false);
|
$transcoder = $config->getSystemValue('memories.vod.path', false);
|
||||||
if (!$transcoder) {
|
if (!$transcoder) {
|
||||||
throw new \Exception('Transcoder not configured');
|
throw new \Exception('Transcoder not configured');
|
||||||
}
|
}
|
||||||
|
@ -255,65 +254,41 @@ class VideoController extends ApiBase
|
||||||
// Kill the transcoder in case it's running
|
// Kill the transcoder in case it's running
|
||||||
\OCA\Memories\Util::pkill($transcoder);
|
\OCA\Memories\Util::pkill($transcoder);
|
||||||
|
|
||||||
// Check for environment variables
|
|
||||||
$env = [];
|
|
||||||
|
|
||||||
// QSV with VAAPI
|
|
||||||
if ($this->config->getSystemValue('memories.qsv', false)) {
|
|
||||||
$env[] = 'VAAPI=1';
|
|
||||||
}
|
|
||||||
|
|
||||||
// NVENC
|
|
||||||
if ($this->config->getSystemValue('memories.nvenc', false)) {
|
|
||||||
$env[] = 'NVENC=1';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind address / port
|
|
||||||
$port = $this->config->getSystemValue('memories.govod_port', 47788);
|
|
||||||
$env[] = "GOVOD_BIND='127.0.0.1:{$port}'";
|
|
||||||
|
|
||||||
// Paths
|
|
||||||
$ffmpegPath = $this->config->getSystemValue('memories.ffmpeg_path', 'ffmpeg');
|
|
||||||
$ffprobePath = $this->config->getSystemValue('memories.ffprobe_path', 'ffprobe');
|
|
||||||
$env[] = "FFMPEG='{$ffmpegPath}'";
|
|
||||||
$env[] = "FFPROBE='{$ffprobePath}'";
|
|
||||||
|
|
||||||
// Get temp directory
|
|
||||||
$defaultTmp = sys_get_temp_dir().'/go-vod/';
|
|
||||||
$tmpPath = $this->config->getSystemValue('memories.tmp_path', $defaultTmp);
|
|
||||||
|
|
||||||
// Make sure path ends with slash
|
|
||||||
if ('/' !== substr($tmpPath, -1)) {
|
|
||||||
$tmpPath .= '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add instance ID to path
|
|
||||||
$tmpPath .= $this->config->getSystemValue('instanceid', 'default');
|
|
||||||
|
|
||||||
// (Re-)create temp dir
|
|
||||||
shell_exec("rm -rf '{$tmpPath}' && mkdir -p '{$tmpPath}' && chmod 755 '{$tmpPath}'");
|
|
||||||
|
|
||||||
// Check temp directory exists
|
|
||||||
if (!is_dir($tmpPath)) {
|
|
||||||
throw new \Exception("Temp directory could not be created ({$tmpPath})");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check temp directory is writable
|
|
||||||
if (!is_writable($tmpPath)) {
|
|
||||||
throw new \Exception("Temp directory is not writable ({$tmpPath})");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set temp dir
|
|
||||||
$env[] = "GOVOD_TEMPDIR='{$tmpPath}'";
|
|
||||||
|
|
||||||
// Start transcoder
|
// Start transcoder
|
||||||
$env = implode(' ', $env);
|
[$configFile, $logFile] = self::makeGoVodConfig($config);
|
||||||
$logFile = $tmpPath.'.log';
|
shell_exec("nohup {$transcoder} {$configFile} >> '{$logFile}' 2>&1 & > /dev/null");
|
||||||
shell_exec("{$env} nohup {$transcoder} > '{$logFile}' 2>&1 & > /dev/null");
|
|
||||||
|
|
||||||
// wait for 1s and try again
|
// wait for 1s
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
||||||
|
return $logFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the upstream URL for a video.
|
||||||
|
*/
|
||||||
|
public static function getGoVodUrl(string $client, string $path, string $profile): string
|
||||||
|
{
|
||||||
|
$config = \OC::$server->get(\OCP\IConfig::class);
|
||||||
|
$path = rawurlencode($path);
|
||||||
|
$port = $config->getSystemValue('memories.govod_port', 47788);
|
||||||
|
|
||||||
|
return "http://127.0.0.1:{$port}/{$client}{$path}/{$profile}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getUpstream(string $client, string $path, string $profile)
|
||||||
|
{
|
||||||
|
$returnCode = $this->getUpstreamInternal($client, $path, $profile);
|
||||||
|
|
||||||
|
// If status code was 0, it's likely the server is down
|
||||||
|
// Make one attempt to start after killing whatever is there
|
||||||
|
if (0 !== $returnCode) {
|
||||||
|
return $returnCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start goVod and get log file
|
||||||
|
$logFile = self::startGoVod();
|
||||||
|
|
||||||
$returnCode = $this->getUpstreamInternal($client, $path, $profile);
|
$returnCode = $this->getUpstreamInternal($client, $path, $profile);
|
||||||
if (0 === $returnCode) {
|
if (0 === $returnCode) {
|
||||||
throw new \Exception("Transcoder could not be started, check {$logFile}");
|
throw new \Exception("Transcoder could not be started, check {$logFile}");
|
||||||
|
@ -322,14 +297,11 @@ class VideoController extends ApiBase
|
||||||
return $returnCode;
|
return $returnCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getUpstreamInternal($client, $path, $profile)
|
private function getUpstreamInternal(string $client, string $path, string $profile)
|
||||||
{
|
{
|
||||||
$path = rawurlencode($path);
|
|
||||||
|
|
||||||
// Make sure query params are repeated
|
// Make sure query params are repeated
|
||||||
// For example, in folder sharing, we need the params on every request
|
// For example, in folder sharing, we need the params on every request
|
||||||
$port = $this->config->getSystemValue('memories.govod_port', 47788);
|
$url = self::getGoVodUrl($client, $path, $profile);
|
||||||
$url = "http://127.0.0.1:{$port}/{$client}{$path}/{$profile}";
|
|
||||||
if ($params = $_SERVER['QUERY_STRING']) {
|
if ($params = $_SERVER['QUERY_STRING']) {
|
||||||
$url .= "?{$params}";
|
$url .= "?{$params}";
|
||||||
}
|
}
|
||||||
|
@ -383,4 +355,98 @@ class VideoController extends ApiBase
|
||||||
|
|
||||||
return $returnCode;
|
return $returnCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct the goVod config JSON.
|
||||||
|
*
|
||||||
|
* @return array [config file, log file]
|
||||||
|
*/
|
||||||
|
private static function makeGoVodConfig(\OCP\IConfig $config): array
|
||||||
|
{
|
||||||
|
// Migrate legacy config: remove in 2024
|
||||||
|
self::migrateLegacyConfig($config);
|
||||||
|
|
||||||
|
// Get temp directory
|
||||||
|
$defaultTmp = sys_get_temp_dir().'/go-vod/';
|
||||||
|
$tmpPath = $config->getSystemValue('memories.vod.tempdir', $defaultTmp);
|
||||||
|
|
||||||
|
// Make sure path ends with slash
|
||||||
|
if ('/' !== substr($tmpPath, -1)) {
|
||||||
|
$tmpPath .= '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add instance ID to path
|
||||||
|
$tmpPath .= $config->getSystemValue('instanceid', 'default');
|
||||||
|
|
||||||
|
// (Re-)create temp dir
|
||||||
|
shell_exec("rm -rf '{$tmpPath}' && mkdir -p '{$tmpPath}' && chmod 755 '{$tmpPath}'");
|
||||||
|
|
||||||
|
// Check temp directory exists
|
||||||
|
if (!is_dir($tmpPath)) {
|
||||||
|
throw new \Exception("Temp directory could not be created ({$tmpPath})");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check temp directory is writable
|
||||||
|
if (!is_writable($tmpPath)) {
|
||||||
|
throw new \Exception("Temp directory is not writable ({$tmpPath})");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get config from system values
|
||||||
|
$env = [
|
||||||
|
'bind' => $config->getSystemValue('memories.vod.bind', '127.0.0.1:47788'),
|
||||||
|
'ffmpeg' => $config->getSystemValue('memories.vod.ffmpeg', 'ffmpeg'),
|
||||||
|
'ffprobe' => $config->getSystemValue('memories.vod.ffprobe', 'ffprobe'),
|
||||||
|
'tempdir' => $tmpPath,
|
||||||
|
|
||||||
|
'vaapi' => $config->getSystemValue('memories.vod.vaapi', false),
|
||||||
|
'vaapiLowPower' => $config->getSystemValue('memories.vod.vaapi.low_power', false),
|
||||||
|
|
||||||
|
'nvenc' => $config->getSystemValue('memories.vod.nvenc', false),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Write config to file
|
||||||
|
$logFile = $tmpPath.'.log';
|
||||||
|
$configFile = $tmpPath.'.json';
|
||||||
|
file_put_contents($configFile, json_encode($env, JSON_PRETTY_PRINT));
|
||||||
|
|
||||||
|
// Log file is not in config
|
||||||
|
// go-vod just writes to stdout/stderr
|
||||||
|
return [$configFile, $logFile];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate legacy config to new.
|
||||||
|
*
|
||||||
|
* Remove in year 2024
|
||||||
|
*/
|
||||||
|
private static function migrateLegacyConfig(\OCP\IConfig $config)
|
||||||
|
{
|
||||||
|
if (null === $config->getSystemValue('memories.no_transcode', null)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mapping
|
||||||
|
$legacyConfig = [
|
||||||
|
'memories.no_transcode' => 'memories.vod.disable',
|
||||||
|
'memories.transcoder' => 'memories.vod.path',
|
||||||
|
'memories.ffmpeg_path' => 'memories.vod.ffmpeg',
|
||||||
|
'memories.ffprobe_path' => 'memories.vod.ffprobe',
|
||||||
|
'memories.qsv' => 'memories.vod.vaapi',
|
||||||
|
'memories.nvenc' => 'memories.vod.nvenc',
|
||||||
|
'memories.tmp_path' => 'memories.vod.tempdir',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($legacyConfig as $old => $new) {
|
||||||
|
if (null !== $config->getSystemValue($old, null)) {
|
||||||
|
$config->setSystemValue($new, $config->getSystemValue($old));
|
||||||
|
$config->deleteSystemValue($old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate bind address
|
||||||
|
if ($port = null !== $config->getSystemValue('memories.govod_port', null)) {
|
||||||
|
$config->setSystemValue('memories.vod.bind', "127.0.0.1:{$port}");
|
||||||
|
$config->deleteSystemValue('memories.govod_port');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue