Skip to content

Commit b94ea69

Browse files
authored
Merge pull request nextcloud#51712 from invario/master
Enhancement: Better previews for HDR video (attempt nextcloud#2)
2 parents 13af20a + eb3ca40 commit b94ea69

1 file changed

Lines changed: 49 additions & 7 deletions

File tree

lib/private/Preview/Movie.php

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@
99

1010
use OCP\Files\File;
1111
use OCP\Files\FileInfo;
12+
use OCP\IConfig;
1213
use OCP\IImage;
1314
use OCP\Server;
1415
use Psr\Log\LoggerInterface;
1516

1617
class Movie extends ProviderV2 {
18+
private IConfig $config;
19+
1720
/**
1821
* @deprecated 23.0.0 pass option to \OCP\Preview\ProviderV2
1922
* @var string
@@ -29,9 +32,11 @@ class Movie extends ProviderV2 {
2932
/** @var string */
3033
private $binary;
3134

32-
/**
33-
* {@inheritDoc}
34-
*/
35+
public function __construct(array $config) {
36+
parent::__construct($config);
37+
$this->config = Server::get(IConfig::class);
38+
}
39+
3540
public function getMimeType(): string {
3641
return '/video\/.*/';
3742
}
@@ -105,6 +110,32 @@ public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage {
105110
return $result;
106111
}
107112

113+
private function useHdr(string $absPath): bool {
114+
// load ffprobe path from configuration, otherwise generate binary path using ffmpeg binary path
115+
$ffprobe_binary = $this->config->getSystemValue('preview_ffprobe_path', null) ?? (pathinfo($this->binary, PATHINFO_DIRNAME) . '/ffprobe');
116+
// run ffprobe on the video file to get value of "color_transfer"
117+
$test_hdr_cmd = [$ffprobe_binary,'-select_streams', 'v:0',
118+
'-show_entries', 'stream=color_transfer',
119+
'-of', 'default=noprint_wrappers=1:nokey=1',
120+
$absPath];
121+
$test_hdr_proc = proc_open($test_hdr_cmd, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $test_hdr_pipes);
122+
if ($test_hdr_proc === false) {
123+
return false;
124+
}
125+
$test_hdr_stdout = trim(stream_get_contents($test_hdr_pipes[1]));
126+
$test_hdr_stderr = trim(stream_get_contents($test_hdr_pipes[2]));
127+
proc_close($test_hdr_proc);
128+
// search build options for libzimg (provides zscale filter)
129+
$ffmpeg_libzimg_installed = strpos($test_hdr_stderr, '--enable-libzimg');
130+
// Only values of "smpte2084" and "arib-std-b67" indicate an HDR video.
131+
// Only return true if video is detected as HDR and libzimg is installed.
132+
if (($test_hdr_stdout === 'smpte2084' || $test_hdr_stdout === 'arib-std-b67') && $ffmpeg_libzimg_installed !== false) {
133+
return true;
134+
} else {
135+
return false;
136+
}
137+
}
138+
108139
private function generateThumbNail(int $maxX, int $maxY, string $absPath, int $second): ?IImage {
109140
$tmpPath = \OC::$server->getTempManager()->getTemporaryFile();
110141

@@ -116,10 +147,21 @@ private function generateThumbNail(int $maxX, int $maxY, string $absPath, int $s
116147
'-an', '-f', 'mjpeg', '-vframes', '1', '-vsync', '1',
117148
$tmpPath];
118149
} elseif ($binaryType === 'ffmpeg') {
119-
$cmd = [$this->binary, '-y', '-ss', (string)$second,
120-
'-i', $absPath,
121-
'-f', 'mjpeg', '-vframes', '1',
122-
$tmpPath];
150+
if ($this->useHdr($absPath)) {
151+
// Force colorspace to '2020_ncl' because some videos are
152+
// tagged incorrectly as 'reserved' resulting in fail if not forced.
153+
$cmd = [$this->binary, '-y', '-ss', (string)$second,
154+
'-i', $absPath,
155+
'-f', 'mjpeg', '-vframes', '1',
156+
'-vf', 'zscale=min=2020_ncl:t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p',
157+
$tmpPath];
158+
} else {
159+
// always default to generating preview using non-HDR command
160+
$cmd = [$this->binary, '-y', '-ss', (string)$second,
161+
'-i', $absPath,
162+
'-f', 'mjpeg', '-vframes', '1',
163+
$tmpPath];
164+
}
123165
} else {
124166
// Not supported
125167
unlink($tmpPath);

0 commit comments

Comments
 (0)