Completed
Push — master ( 13af20...b94ea6 )
by
unknown
20:11 queued 01:04
created
lib/private/Preview/Movie.php 2 patches
Indentation   +182 added lines, -182 removed lines patch added patch discarded remove patch
@@ -15,186 +15,186 @@
 block discarded – undo
15 15
 use Psr\Log\LoggerInterface;
16 16
 
17 17
 class Movie extends ProviderV2 {
18
-	private IConfig $config;
19
-
20
-	/**
21
-	 * @deprecated 23.0.0 pass option to \OCP\Preview\ProviderV2
22
-	 * @var string
23
-	 */
24
-	public static $avconvBinary;
25
-
26
-	/**
27
-	 * @deprecated 23.0.0 pass option to \OCP\Preview\ProviderV2
28
-	 * @var string
29
-	 */
30
-	public static $ffmpegBinary;
31
-
32
-	/** @var string */
33
-	private $binary;
34
-
35
-	public function __construct(array $config) {
36
-		parent::__construct($config);
37
-		$this->config = Server::get(IConfig::class);
38
-	}
39
-
40
-	public function getMimeType(): string {
41
-		return '/video\/.*/';
42
-	}
43
-
44
-	/**
45
-	 * {@inheritDoc}
46
-	 */
47
-	public function isAvailable(FileInfo $file): bool {
48
-		// TODO: remove when avconv is dropped
49
-		if (is_null($this->binary)) {
50
-			if (isset($this->options['movieBinary'])) {
51
-				$this->binary = $this->options['movieBinary'];
52
-			} elseif (is_string(self::$avconvBinary)) {
53
-				$this->binary = self::$avconvBinary;
54
-			} elseif (is_string(self::$ffmpegBinary)) {
55
-				$this->binary = self::$ffmpegBinary;
56
-			}
57
-		}
58
-		return is_string($this->binary);
59
-	}
60
-
61
-	/**
62
-	 * {@inheritDoc}
63
-	 */
64
-	public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage {
65
-		// TODO: use proc_open() and stream the source file ?
66
-
67
-		if (!$this->isAvailable($file)) {
68
-			return null;
69
-		}
70
-
71
-		$result = null;
72
-		if ($this->useTempFile($file)) {
73
-			// try downloading 5 MB first as it's likely that the first frames are present there
74
-			// in some cases this doesn't work for example when the moov atom is at the
75
-			// end of the file, so if it fails we fall back to getting the full file
76
-			$sizeAttempts = [5242880, null];
77
-		} else {
78
-			// size is irrelevant, only attempt once
79
-			$sizeAttempts = [null];
80
-		}
81
-
82
-		foreach ($sizeAttempts as $size) {
83
-			$absPath = $this->getLocalFile($file, $size);
84
-			if ($absPath === false) {
85
-				Server::get(LoggerInterface::class)->error(
86
-					'Failed to get local file to generate thumbnail for: ' . $file->getPath(),
87
-					['app' => 'core']
88
-				);
89
-				return null;
90
-			}
91
-
92
-			$result = null;
93
-			if (is_string($absPath)) {
94
-				$result = $this->generateThumbNail($maxX, $maxY, $absPath, 5);
95
-				if ($result === null) {
96
-					$result = $this->generateThumbNail($maxX, $maxY, $absPath, 1);
97
-					if ($result === null) {
98
-						$result = $this->generateThumbNail($maxX, $maxY, $absPath, 0);
99
-					}
100
-				}
101
-			}
102
-
103
-			$this->cleanTmpFiles();
104
-
105
-			if ($result !== null) {
106
-				break;
107
-			}
108
-		}
109
-
110
-		return $result;
111
-	}
112
-
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
-
139
-	private function generateThumbNail(int $maxX, int $maxY, string $absPath, int $second): ?IImage {
140
-		$tmpPath = \OC::$server->getTempManager()->getTemporaryFile();
141
-
142
-		$binaryType = substr(strrchr($this->binary, '/'), 1);
143
-
144
-		if ($binaryType === 'avconv') {
145
-			$cmd = [$this->binary, '-y', '-ss', (string)$second,
146
-				'-i', $absPath,
147
-				'-an', '-f', 'mjpeg', '-vframes', '1', '-vsync', '1',
148
-				$tmpPath];
149
-		} elseif ($binaryType === 'ffmpeg') {
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
-			}
165
-		} else {
166
-			// Not supported
167
-			unlink($tmpPath);
168
-			return null;
169
-		}
170
-
171
-		$proc = proc_open($cmd, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes);
172
-		$returnCode = -1;
173
-		$output = '';
174
-		if (is_resource($proc)) {
175
-			$stdout = trim(stream_get_contents($pipes[1]));
176
-			$stderr = trim(stream_get_contents($pipes[2]));
177
-			$returnCode = proc_close($proc);
178
-			$output = $stdout . $stderr;
179
-		}
180
-
181
-		if ($returnCode === 0) {
182
-			$image = new \OCP\Image();
183
-			$image->loadFromFile($tmpPath);
184
-			if ($image->valid()) {
185
-				unlink($tmpPath);
186
-				$image->scaleDownToFit($maxX, $maxY);
187
-
188
-				return $image;
189
-			}
190
-		}
191
-
192
-		if ($second === 0) {
193
-			$logger = \OC::$server->get(LoggerInterface::class);
194
-			$logger->info('Movie preview generation failed Output: {output}', ['app' => 'core', 'output' => $output]);
195
-		}
196
-
197
-		unlink($tmpPath);
198
-		return null;
199
-	}
18
+    private IConfig $config;
19
+
20
+    /**
21
+     * @deprecated 23.0.0 pass option to \OCP\Preview\ProviderV2
22
+     * @var string
23
+     */
24
+    public static $avconvBinary;
25
+
26
+    /**
27
+     * @deprecated 23.0.0 pass option to \OCP\Preview\ProviderV2
28
+     * @var string
29
+     */
30
+    public static $ffmpegBinary;
31
+
32
+    /** @var string */
33
+    private $binary;
34
+
35
+    public function __construct(array $config) {
36
+        parent::__construct($config);
37
+        $this->config = Server::get(IConfig::class);
38
+    }
39
+
40
+    public function getMimeType(): string {
41
+        return '/video\/.*/';
42
+    }
43
+
44
+    /**
45
+     * {@inheritDoc}
46
+     */
47
+    public function isAvailable(FileInfo $file): bool {
48
+        // TODO: remove when avconv is dropped
49
+        if (is_null($this->binary)) {
50
+            if (isset($this->options['movieBinary'])) {
51
+                $this->binary = $this->options['movieBinary'];
52
+            } elseif (is_string(self::$avconvBinary)) {
53
+                $this->binary = self::$avconvBinary;
54
+            } elseif (is_string(self::$ffmpegBinary)) {
55
+                $this->binary = self::$ffmpegBinary;
56
+            }
57
+        }
58
+        return is_string($this->binary);
59
+    }
60
+
61
+    /**
62
+     * {@inheritDoc}
63
+     */
64
+    public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage {
65
+        // TODO: use proc_open() and stream the source file ?
66
+
67
+        if (!$this->isAvailable($file)) {
68
+            return null;
69
+        }
70
+
71
+        $result = null;
72
+        if ($this->useTempFile($file)) {
73
+            // try downloading 5 MB first as it's likely that the first frames are present there
74
+            // in some cases this doesn't work for example when the moov atom is at the
75
+            // end of the file, so if it fails we fall back to getting the full file
76
+            $sizeAttempts = [5242880, null];
77
+        } else {
78
+            // size is irrelevant, only attempt once
79
+            $sizeAttempts = [null];
80
+        }
81
+
82
+        foreach ($sizeAttempts as $size) {
83
+            $absPath = $this->getLocalFile($file, $size);
84
+            if ($absPath === false) {
85
+                Server::get(LoggerInterface::class)->error(
86
+                    'Failed to get local file to generate thumbnail for: ' . $file->getPath(),
87
+                    ['app' => 'core']
88
+                );
89
+                return null;
90
+            }
91
+
92
+            $result = null;
93
+            if (is_string($absPath)) {
94
+                $result = $this->generateThumbNail($maxX, $maxY, $absPath, 5);
95
+                if ($result === null) {
96
+                    $result = $this->generateThumbNail($maxX, $maxY, $absPath, 1);
97
+                    if ($result === null) {
98
+                        $result = $this->generateThumbNail($maxX, $maxY, $absPath, 0);
99
+                    }
100
+                }
101
+            }
102
+
103
+            $this->cleanTmpFiles();
104
+
105
+            if ($result !== null) {
106
+                break;
107
+            }
108
+        }
109
+
110
+        return $result;
111
+    }
112
+
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
+
139
+    private function generateThumbNail(int $maxX, int $maxY, string $absPath, int $second): ?IImage {
140
+        $tmpPath = \OC::$server->getTempManager()->getTemporaryFile();
141
+
142
+        $binaryType = substr(strrchr($this->binary, '/'), 1);
143
+
144
+        if ($binaryType === 'avconv') {
145
+            $cmd = [$this->binary, '-y', '-ss', (string)$second,
146
+                '-i', $absPath,
147
+                '-an', '-f', 'mjpeg', '-vframes', '1', '-vsync', '1',
148
+                $tmpPath];
149
+        } elseif ($binaryType === 'ffmpeg') {
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
+            }
165
+        } else {
166
+            // Not supported
167
+            unlink($tmpPath);
168
+            return null;
169
+        }
170
+
171
+        $proc = proc_open($cmd, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes);
172
+        $returnCode = -1;
173
+        $output = '';
174
+        if (is_resource($proc)) {
175
+            $stdout = trim(stream_get_contents($pipes[1]));
176
+            $stderr = trim(stream_get_contents($pipes[2]));
177
+            $returnCode = proc_close($proc);
178
+            $output = $stdout . $stderr;
179
+        }
180
+
181
+        if ($returnCode === 0) {
182
+            $image = new \OCP\Image();
183
+            $image->loadFromFile($tmpPath);
184
+            if ($image->valid()) {
185
+                unlink($tmpPath);
186
+                $image->scaleDownToFit($maxX, $maxY);
187
+
188
+                return $image;
189
+            }
190
+        }
191
+
192
+        if ($second === 0) {
193
+            $logger = \OC::$server->get(LoggerInterface::class);
194
+            $logger->info('Movie preview generation failed Output: {output}', ['app' => 'core', 'output' => $output]);
195
+        }
196
+
197
+        unlink($tmpPath);
198
+        return null;
199
+    }
200 200
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -83,7 +83,7 @@  discard block
 block discarded – undo
83 83
 			$absPath = $this->getLocalFile($file, $size);
84 84
 			if ($absPath === false) {
85 85
 				Server::get(LoggerInterface::class)->error(
86
-					'Failed to get local file to generate thumbnail for: ' . $file->getPath(),
86
+					'Failed to get local file to generate thumbnail for: '.$file->getPath(),
87 87
 					['app' => 'core']
88 88
 				);
89 89
 				return null;
@@ -112,9 +112,9 @@  discard block
 block discarded – undo
112 112
 
113 113
 	private function useHdr(string $absPath): bool {
114 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');
115
+		$ffprobe_binary = $this->config->getSystemValue('preview_ffprobe_path', null) ?? (pathinfo($this->binary, PATHINFO_DIRNAME).'/ffprobe');
116 116
 		// run ffprobe on the video file to get value of "color_transfer"
117
-		$test_hdr_cmd = [$ffprobe_binary,'-select_streams', 'v:0',
117
+		$test_hdr_cmd = [$ffprobe_binary, '-select_streams', 'v:0',
118 118
 			'-show_entries', 'stream=color_transfer',
119 119
 			'-of', 'default=noprint_wrappers=1:nokey=1',
120 120
 			$absPath];
@@ -142,7 +142,7 @@  discard block
 block discarded – undo
142 142
 		$binaryType = substr(strrchr($this->binary, '/'), 1);
143 143
 
144 144
 		if ($binaryType === 'avconv') {
145
-			$cmd = [$this->binary, '-y', '-ss', (string)$second,
145
+			$cmd = [$this->binary, '-y', '-ss', (string) $second,
146 146
 				'-i', $absPath,
147 147
 				'-an', '-f', 'mjpeg', '-vframes', '1', '-vsync', '1',
148 148
 				$tmpPath];
@@ -150,14 +150,14 @@  discard block
 block discarded – undo
150 150
 			if ($this->useHdr($absPath)) {
151 151
 				// Force colorspace to '2020_ncl' because some videos are
152 152
 				// tagged incorrectly as 'reserved' resulting in fail if not forced.
153
-				$cmd = [$this->binary, '-y', '-ss', (string)$second,
153
+				$cmd = [$this->binary, '-y', '-ss', (string) $second,
154 154
 					'-i', $absPath,
155 155
 					'-f', 'mjpeg', '-vframes', '1',
156 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 157
 					$tmpPath];
158 158
 			} else {
159 159
 				// always default to generating preview using non-HDR command
160
-				$cmd = [$this->binary, '-y', '-ss', (string)$second,
160
+				$cmd = [$this->binary, '-y', '-ss', (string) $second,
161 161
 					'-i', $absPath,
162 162
 					'-f', 'mjpeg', '-vframes', '1',
163 163
 					$tmpPath];
@@ -175,7 +175,7 @@  discard block
 block discarded – undo
175 175
 			$stdout = trim(stream_get_contents($pipes[1]));
176 176
 			$stderr = trim(stream_get_contents($pipes[2]));
177 177
 			$returnCode = proc_close($proc);
178
-			$output = $stdout . $stderr;
178
+			$output = $stdout.$stderr;
179 179
 		}
180 180
 
181 181
 		if ($returnCode === 0) {
Please login to merge, or discard this patch.