Skip to content

Commit 244379a

Browse files
committed
fix(ffmpeg): Autodetect system installed ffmpeg and allow manually setting ffmpeg path
fixes #1096 Signed-off-by: Marcel Klehr <[email protected]>
1 parent b06fc2c commit 244379a

File tree

7 files changed

+62
-3
lines changed

7 files changed

+62
-3
lines changed

appinfo/routes.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
['name' => 'admin#platform', 'url' => '/admin/platform', 'verb' => 'GET'],
3333
['name' => 'admin#musl', 'url' => '/admin/musl', 'verb' => 'GET'],
3434
['name' => 'admin#nice', 'url' => '/admin/nice', 'verb' => 'GET'],
35+
['name' => 'admin#ffmpeg', 'url' => '/admin/ffmpeg', 'verb' => 'GET'],
3536
['name' => 'admin#nodejs', 'url' => '/admin/nodejs', 'verb' => 'GET'],
3637
['name' => 'admin#libtensorflow', 'url' => '/admin/libtensorflow', 'verb' => 'GET'],
3738
['name' => 'admin#wasmtensorflow', 'url' => '/admin/wasmtensorflow', 'verb' => 'GET'],

lib/BackgroundJobs/ClusterFacesJob.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
use OCP\AppFramework\Utility\ITimeFactory;
1414
use OCP\BackgroundJob\IJobList;
1515
use OCP\BackgroundJob\QueuedJob;
16-
use OCP\DB\Exception;
1716
use Psr\Log\LoggerInterface;
1817

1918
final class ClusterFacesJob extends QueuedJob {

lib/Classifiers/Images/ImagenetClassifier.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
use OCA\Recognize\Service\QueueService;
1313
use OCA\Recognize\Service\TagManager;
1414
use OCP\AppFramework\Services\IAppConfig;
15-
use OCP\DB\Exception;
1615
use OCP\Files\IRootFolder;
1716
use OCP\IPreview;
1817
use OCP\ITempManager;

lib/Controller/AdminController.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,24 @@ public function nodejs(): JSONResponse {
219219
return new JSONResponse(['nodejs' => $version]);
220220
}
221221

222+
public function ffmpeg(): JSONResponse {
223+
try {
224+
exec($this->settingsService->getSetting('ffmpeg_binary') . ' -version' . ' 2>&1', $output, $returnCode);
225+
} catch (\Throwable $e) {
226+
return new JSONResponse(['ffmpeg' => null]);
227+
}
228+
229+
if ($returnCode !== 0) {
230+
return new JSONResponse(['ffmpeg' => false]);
231+
}
232+
233+
if (preg_match('/version (.*?) /', trim($output[0]), $matches) !== 1) {
234+
return new JSONResponse(['ffmpeg' => false]);
235+
}
236+
$version = $matches[1];
237+
return new JSONResponse(['ffmpeg' => $version]);
238+
}
239+
222240
public function libtensorflow(): JSONResponse {
223241
try {
224242
exec($this->settingsService->getSetting('node_binary') . ' ' . __DIR__ . '/../../src/test_libtensorflow.js' . ' 2>&1', $output, $returnCode);

lib/Migration/InstallDeps.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public function run(IOutput $output): void {
9393
$this->runTfjsGpuInstall($binaryPath);
9494
$this->setNodeModulesPermissions();
9595
$this->setNiceBinaryPath();
96+
$this->setFfmpegBinaryPath();
9697
} catch (\Throwable $e) {
9798
$output->warning('Failed to automatically install dependencies for recognize. Check the recognize admin panel for potential problems.');
9899
$this->logger->error('Failed to automatically install dependencies for recognize. Check the recognize admin panel for potential problems.', ['exception' => $e]);
@@ -235,6 +236,22 @@ protected function runFfmpegInstall(string $nodeBinary): void {
235236
}
236237
}
237238

239+
protected function setFfmpegBinaryPath() : void {
240+
/* use nice binary from settings if available */
241+
if ($this->config->getAppValueString('ffmpeg_binary', '') !== '') {
242+
$ffmpeg_path = $this->config->getAppValueString('ffmpeg_binary');
243+
} else {
244+
/* returns the path to the nice binary or false if not found */
245+
$ffmpeg_path = $this->binaryFinder->findBinaryPath('ffmpeg');
246+
}
247+
248+
if ($ffmpeg_path !== false) {
249+
$this->config->setAppValueString('ffmpeg_binary', $ffmpeg_path);
250+
} else {
251+
$this->config->setAppValueString('ffmpeg_binary', __DIR__ . '/../../node_modules/ffmpeg-static/ffmpeg');
252+
}
253+
}
254+
238255
protected function downloadNodeBinary(string $server, string $version, string $arch, string $flavor = '') : string {
239256
$name = 'node-'.$version.'-linux-'.$arch;
240257
if ($flavor !== '') {

lib/Service/SettingsService.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ final class SettingsService {
5252
'nice_binary' => '',
5353
'nice_value' => '0',
5454
'concurrency.enabled' => 'false',
55+
'ffmpeg_binary' => '',
5556
];
5657

5758
/** @var array<string,string> */

src/components/ViewAdmin.vue

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,23 @@
329329
</p>
330330
<p>{{ t('recognize', 'For Nextcloud Snap users, you need to adjust this path to point to the snap\'s "current" directory as the pre-configured path will change with each update. For example, set it to "/var/snap/nextcloud/current/nextcloud/extra-apps/recognize/bin/node" instead of "/var/snap/nextcloud/9337974/nextcloud/extra-apps/recognize/bin/node"') }}</p>
331331
</NcSettingsSection>
332+
<NcSettingsSection :name="t('recognize', 'FFMPEG')">
333+
<p v-if="ffmpeg === undefined">
334+
<span class="icon-loading-small" />&nbsp;&nbsp;&nbsp;&nbsp;{{ t('recognize', 'Checking FFMPEG') }}
335+
</p>
336+
<NcNoteCard v-else-if="ffmpeg === false" type="warning">
337+
{{ t('recognize', 'Could not execute the ffmpeg binary. You may need to set the path to a working binary manually.') }}
338+
</NcNoteCard>
339+
<NcNoteCard v-else type="success">
340+
{{ t('recognize', 'ffmpeg {version} binary was installed successfully.', { version: ffmpeg }) }}
341+
</NcNoteCard>
342+
<p>
343+
{{ t('recognize', 'If the shipped ffmpeg binary doesn\'t work on your system for some reason you can set the path to a custom ffmpeg binary.') }}
344+
</p>
345+
<p>
346+
<NcTextField :value.sync="settings['ffmpeg_binary']" @update:value="onChange" />
347+
</p>
348+
</NcSettingsSection>
332349
<NcSettingsSection :name="t('recognize', 'Classifier process priority')">
333350
<p v-if="nice === undefined">
334351
<span class="icon-loading-small" />&nbsp;&nbsp;&nbsp;&nbsp;{{ t('recognize', 'Checking Nice binary') }}
@@ -400,7 +417,7 @@ import { generateUrl } from '@nextcloud/router'
400417
import { loadState } from '@nextcloud/initial-state'
401418
import humanizeDuration from 'humanize-duration'
402419
403-
const SETTINGS = ['tensorflow.cores', 'tensorflow.gpu', 'tensorflow.purejs', 'imagenet.enabled', 'landmarks.enabled', 'faces.enabled', 'musicnn.enabled', 'movinet.enabled', 'node_binary', 'faces.status', 'imagenet.status', 'landmarks.status', 'movinet.status', 'musicnn.status', 'faces.lastFile', 'imagenet.lastFile', 'landmarks.lastFile', 'movinet.lastFile', 'musicnn.lastFile', 'faces.batchSize', 'imagenet.batchSize', 'landmarks.batchSize', 'movinet.batchSize', 'musicnn.batchSize', 'clusterFaces.status', 'clusterFaces.lastRun', 'nice_binary', 'nice_value', 'concurrency.enabled']
420+
const SETTINGS = ['tensorflow.cores', 'tensorflow.gpu', 'tensorflow.purejs', 'imagenet.enabled', 'landmarks.enabled', 'faces.enabled', 'musicnn.enabled', 'movinet.enabled', 'node_binary', 'ffmpeg_binary', 'faces.status', 'imagenet.status', 'landmarks.status', 'movinet.status', 'musicnn.status', 'faces.lastFile', 'imagenet.lastFile', 'landmarks.lastFile', 'movinet.lastFile', 'musicnn.lastFile', 'faces.batchSize', 'imagenet.batchSize', 'landmarks.batchSize', 'movinet.batchSize', 'musicnn.batchSize', 'clusterFaces.status', 'clusterFaces.lastRun', 'nice_binary', 'nice_value', 'concurrency.enabled']
404421
405422
const BOOLEAN_SETTINGS = ['tensorflow.gpu', 'tensorflow.purejs', 'imagenet.enabled', 'landmarks.enabled', 'faces.enabled', 'musicnn.enabled', 'movinet.enabled', 'faces.status', 'imagenet.status', 'landmarks.status', 'movinet.status', 'musicnn.status', 'faces.lastFile', 'imagenet.lastFile', 'landmarks.lastFile', 'movinet.lastFile', 'musicnn.lastFile', 'clusterFaces.status', 'concurrency.enabled']
406423
@@ -427,6 +444,7 @@ export default {
427444
libtensorflow: undefined,
428445
wasmtensorflow: undefined,
429446
gputensorflow: undefined,
447+
ffmpeg: undefined,
430448
cron: undefined,
431449
modelsDownloaded: null,
432450
imagenetJobs: null,
@@ -470,6 +488,7 @@ export default {
470488
this.getMusl()
471489
this.getNice()
472490
this.getNodejsStatus()
491+
this.getFfmpegStatus()
473492
this.getLibtensorflowStatus()
474493
this.getWasmtensorflowStatus()
475494
this.getGputensorflowStatus()
@@ -585,6 +604,11 @@ export default {
585604
const { nodejs } = resp.data
586605
this.nodejs = nodejs
587606
},
607+
async getFfmpegStatus() {
608+
const resp = await axios.get(generateUrl('/apps/recognize/admin/ffmpeg'))
609+
const { ffmpeg } = resp.data
610+
this.ffmpeg = ffmpeg
611+
},
588612
async getLibtensorflowStatus() {
589613
const resp = await axios.get(generateUrl('/apps/recognize/admin/libtensorflow'))
590614
const { libtensorflow } = resp.data

0 commit comments

Comments
 (0)