invario 3 days ago
committed by GitHub
parent
commit
9a1016c648
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 31
      apps/files_external/lib/Lib/Storage/AmazonS3.php
  2. 121
      lib/private/Preview/Movie.php

31
apps/files_external/lib/Lib/Storage/AmazonS3.php

@ -757,4 +757,35 @@ class AmazonS3 extends Common {
return $size;
}
/**
* Generates and returns a presigned URL that expires after set duration
*
*/
public function getDirectDownload(string $path): array|false {
$command = $this->getConnection()->getCommand('GetObject', [
'Bucket' => $this->bucket,
'Key' => $path,
]);
$duration = '+10 minutes';
$expiration = new \DateTime();
$expiration->modify($duration);
// generate a presigned URL that expires after $duration time
$request = $this->getConnection()->createPresignedRequest($command, $duration, []);
try {
$presignedUrl = (string)$request->getUri();
} catch (S3Exception $exception) {
$this->logger->error($exception->getMessage(), [
'app' => 'files_external',
'exception' => $exception,
]);
}
$result = [
'url' => $presignedUrl,
'presigned' => true,
'expiration' => $expiration,
];
return $result;
}
}

121
lib/private/Preview/Movie.php

@ -42,6 +42,26 @@ class Movie extends ProviderV2 {
return is_string($this->binary);
}
private function connectDirect(File $file): string|false {
if (stream_get_meta_data($file->fopen('r'))['seekable'] !== true) {
return false;
}
// Checks for availability to access the video file directly via HTTP/HTTPS.
// Returns a string containing URL if available. Only implemented and tested
// with Amazon S3 currently. In all other cases, return false. ffmpeg
// supports other protocols so this function may expand in the future.
$gddValues = $file->getStorage()->getDirectDownload($file->getName());
if (is_array($gddValues)) {
if (array_key_exists('url', $gddValues) && array_key_exists('presigned', $gddValues)) {
$directUrl = (str_starts_with($gddValues['url'], 'http') && ($gddValues['presigned'] === true)) ? $gddValues['url'] : false;
return $directUrl;
}
}
return false;
}
/**
* {@inheritDoc}
*/
@ -54,58 +74,72 @@ class Movie extends ProviderV2 {
$result = null;
$connectDirect = $this->connectDirect($file);
// Timestamps to make attempts to generate a still
$timeAttempts = [5, 1, 0];
// By default, download $sizeAttempts from the file along with
// the 'moov' atom.
// Example bitrates in the higher range:
// 4K HDR H265 60 FPS = 75 Mbps = 9 MB per second needed for a still
// 1080p H265 30 FPS = 10 Mbps = 1.25 MB per second needed for a still
// 1080p H264 30 FPS = 16 Mbps = 2 MB per second needed for a still
$sizeAttempts = [1024 * 1024 * 10];
if ($this->useTempFile($file)) {
if ($file->getStorage()->isLocal()) {
// Temp file required but file is local, so retrieve $sizeAttempt bytes first,
// and if it doesn't work, retrieve the entire file.
$sizeAttempts[] = null;
// If HTTP/HTTPS direct connect is not available or if the file is encrypted,
// process normally
if (($connectDirect === false) || $file->isEncrypted()) {
// By default, download $sizeAttempts from the file along with
// the 'moov' atom.
// Example bitrates in the higher range:
// 4K HDR H265 60 FPS = 75 Mbps = 9 MB per second needed for a still
// 1080p H265 30 FPS = 10 Mbps = 1.25 MB per second needed for a still
// 1080p H264 30 FPS = 16 Mbps = 2 MB per second needed for a still
$sizeAttempts = [1024 * 1024 * 10];
if ($this->useTempFile($file)) {
if ($file->getStorage()->isLocal()) {
// Temp file required but file is local, so retrieve $sizeAttempt bytes first,
// and if it doesn't work, retrieve the entire file.
$sizeAttempts[] = null;
}
} else {
// Temp file is not required and file is local so retrieve entire file.
$sizeAttempts = [null];
}
} else {
// Temp file is not required and file is local so retrieve entire file.
$sizeAttempts = [null];
}
foreach ($sizeAttempts as $size) {
$absPath = false;
// File is remote, generate a sparse file
if (!$file->getStorage()->isLocal()) {
$absPath = $this->getSparseFile($file, $size);
}
// Defaults to existing routine if generating sparse file fails
if ($absPath === false) {
$absPath = $this->getLocalFile($file, $size);
}
if ($absPath === false) {
Server::get(LoggerInterface::class)->error(
'Failed to get local file to generate thumbnail for: ' . $file->getPath(),
['app' => 'core']
);
return null;
}
foreach ($sizeAttempts as $size) {
$absPath = false;
// File is remote, generate a sparse file
if (!$file->getStorage()->isLocal()) {
$absPath = $this->getSparseFile($file, $size);
}
// Defaults to existing routine if generating sparse file fails
if ($absPath === false) {
$absPath = $this->getLocalFile($file, $size);
}
if ($absPath === false) {
Server::get(LoggerInterface::class)->error(
'Failed to get local file to generate thumbnail for: ' . $file->getPath(),
['app' => 'core']
);
return null;
}
// Attempt still image grabs from selected timestamps
foreach ($timeAttempts as $timeStamp) {
$result = $this->generateThumbNail($maxX, $maxY, $absPath, $timeStamp);
if ($result !== null) {
break;
}
}
$this->cleanTmpFiles();
// Attempt still image grabs from selected timestamps
foreach ($timeAttempts as $timeStamp) {
$result = $this->generateThumbNail($maxX, $maxY, $absPath, $timeStamp);
if ($result !== null) {
break;
}
}
$this->cleanTmpFiles();
if ($result !== null) {
break;
} else {
// HTTP/HTTPS direct connect is available so pass the URL directly to ffmpeg
foreach ($timeAttempts as $timeStamp) {
$result = $this->generateThumbNail($maxX, $maxY, $connectDirect, $timeStamp);
if ($result !== null) {
break;
}
}
}
return $result;
@ -219,7 +253,8 @@ class Movie extends ProviderV2 {
private function useHdr(string $absPath): bool {
// load ffprobe path from configuration, otherwise generate binary path using ffmpeg binary path
$ffprobe_binary = $this->config->getSystemValue('preview_ffprobe_path', null) ?? (pathinfo($this->binary, PATHINFO_DIRNAME) . '/ffprobe');
$ffprobe_binary = $this->config->getSystemValue('preview_ffprobe_path', null)
?? (pathinfo($this->binary, PATHINFO_DIRNAME) . '/ffprobe');
// run ffprobe on the video file to get value of "color_transfer"
$test_hdr_cmd = [$ffprobe_binary,'-select_streams', 'v:0',
'-show_entries', 'stream=color_transfer',

Loading…
Cancel
Save