99
1010use OCP \Files \File ;
1111use OCP \Files \FileInfo ;
12+ use OCP \IConfig ;
1213use OCP \IImage ;
1314use OCP \Server ;
1415use Psr \Log \LoggerInterface ;
1516
1617class 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