Skip to content

Commit

Permalink
convert2image: Adds video preview genertion via ffmpeg (#5695)
Browse files Browse the repository at this point in the history
Es wird aus aus der Mitte des Videos ein Vorschaubild-generiert. Ideal
für Video-Poster.
Es wurden keine zusätzlichen Optionen hinzugefügt. 

Es wird geprüft ob ffmpeg verfügbar ist.
Die Ermittlung wie lang ein Film ist, erfolgt über ffprobe.
  • Loading branch information
skerbis committed Sep 1, 2023
1 parent c61ea0d commit 2cd311f
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 6 deletions.
4 changes: 2 additions & 2 deletions redaxo/src/addons/media_manager/lang/de_de.lang
Expand Up @@ -150,11 +150,11 @@ media_manager_effect_convert2img = Datei: In Bild konvertieren
media_manager_effect_convert2img_density = Auflösungsdichte
media_manager_effect_convert2img_convertto = Zielformat
media_manager_effect_convert2img_density_notice = Auflösungsdichte in ppi (pixel per inch).
media_manager_effect_convert2img_convertto_notice = Zielformat, in das die Datei konvertiert wird. Es werden folgende Dateiendungen berücksichtigt: <code>.pdf,.ps,.psd,.tif,.tiff,.bmp,.eps,.ico,.svg</code>.
media_manager_effect_convert2img_convertto_notice = Zielformat, in das die Datei konvertiert wird. Es werden folgende Dateiendungen berücksichtigt: <code>.avi,.mp4,m4v,mov,.pdf,.ps,.psd,.tif,.tiff,.bmp,.eps,.ico,.svg</code>.
media_manager_effect_convert2img_noimagemagick = Achtung: ImageMagick konnte nicht gefunden werden. Dieser Effekt benötigt entweder die PHP-Extension "imagick" oder ImageMagick als "commandline binary", ausführbar per exec().
media_manager_effect_convert2img_color = Farbe für Transparenz
media_manager_effect_convert2img_color_notice = Format "#ffffff", wenn nichts gesetzt wird, dann wird Transparenz genutzt. Bei JPG bitte unbedingt eine Farbe angeben.

media_manager_effect_convert2img_videoconverternotfound = ffmpeg (über exec()) wurde auf diesem System nicht gefunden. Videos können nicht konvertiert werden.

media_manager_effect_image_properties = Bild: Einstellungen (Qualität, Interlace, ...)
media_manager_effect_image_properties_jpg_quality_notice = [0-100]. Leer lassen für Standardwert.
Expand Down
85 changes: 81 additions & 4 deletions redaxo/src/addons/media_manager/lib/effects/effect_convert2img.php
@@ -1,7 +1,7 @@
<?php

/**
* Benutzt den Konsolen convert Befehl.
* Benutzt den Konsolen convert oder ffmpeg Befehl.
*
* @author jan
*
Expand All @@ -21,6 +21,14 @@ class rex_effect_convert2img extends rex_effect_abstract
'ico',
'svg',
];

private const VIDEO_TO_IMAGE_TYPES = [
'mp4',
'm4v',
'avi',
'mov',
];

private const CONVERT_TO = [
'jpg' => [
'ext' => 'jpg',
Expand All @@ -31,6 +39,7 @@ class rex_effect_convert2img extends rex_effect_abstract
'content-type' => 'image/png',
],
];

private const DENSITIES = [100, 150, 200, 300, 600];
private const DENSITY_DEFAULT = 150;
private const CONVERT_TOS = ['jpg', 'png'];
Expand All @@ -44,6 +53,40 @@ public function execute()
$convertTo = self::CONVERT_TO[(string) $this->params['convert_to']];
}

if ($this->isVideoToImageConversionSupported()) {
$inputFile = rex_type::notNull($this->media->getMediaPath());

// Try to get the duration of the video using ffprobe
$ffprobeCmd = 'ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 ' . escapeshellarg($inputFile);
$duration = exec($ffprobeCmd);

if ($duration) {
$timestamp = gmdate('H:i:s', (int) floor((float) $duration / 2));
} else {
$timestamp = '00:00:01';
}

$outputFile = rex_path::addonCache('media_manager', 'media_manager__convert2img_' . md5($inputFile) . '.' . $convertTo['ext']);

$cmd = 'ffmpeg -y -i ' . escapeshellarg($inputFile) . ' -ss ' . escapeshellarg($timestamp) . ' -vframes 1 ' . escapeshellarg($outputFile);
exec($cmd, $out, $ret);

if (0 !== $ret) {
throw new rex_exception('Unable to exec command ' . $cmd);
}

$this->media->setSourcePath($outputFile);
$this->media->refreshImageDimensions();
$this->media->setFormat($convertTo['ext']);
$this->media->setHeader('Content-Type', $convertTo['content-type']);
$filename = $this->media->getMediaFilename();
$this->media->setMediaFilename($filename);
register_shutdown_function(static function () use ($outputFile) {
rex_file::delete($outputFile);
});
return;
}

$density = (int) $this->params['density'];

$color = $this->params['color'] ?? '';
Expand Down Expand Up @@ -128,18 +171,23 @@ public function getName()

public function getParams()
{
$imNotfound = '';
$notSupported = [];
if (!class_exists(Imagick::class) && '' == self::getConvertPath()) {
$imNotfound = '<strong>' . rex_i18n::msg('media_manager_effect_convert2img_noimagemagick') . '</strong>';
$notSupported[] = '<strong>' . rex_i18n::msg('media_manager_effect_convert2img_noimagemagick') . '</strong> ';
}

if (!$this->isFfmpegAvailable()) {
$notSupported[] = '<strong>' . rex_i18n::msg('media_manager_effect_convert2img_videoconverternotfound') . '</strong> ';
}

return [
[
'label' => rex_i18n::msg('media_manager_effect_convert2img_convertto'),
'name' => 'convert_to',
'type' => 'select',
'options' => self::CONVERT_TOS,
'default' => self::CONVERT_TO_DEFAULT,
'prefix' => $imNotfound,
'prefix' => implode('<br>', $notSupported),
'notice' => rex_i18n::msg('media_manager_effect_convert2img_convertto_notice'),
],
[
Expand Down Expand Up @@ -177,4 +225,33 @@ private function getConvertPath()
}
return $path;
}

private function isVideoToImageConversionSupported(): bool
{
$inputFile = $this->media->getMediaPath();

if (null === $inputFile) {
return false;
}

$inputExt = pathinfo($inputFile, PATHINFO_EXTENSION);

if ($this->isFfmpegAvailable()) {
return in_array($inputExt, self::VIDEO_TO_IMAGE_TYPES);
}
return false;
}

private function isFfmpegAvailable(): bool
{
if (!function_exists('exec')) {
return false;
}
$ffmpegPath = 'ffmpeg'; // change to full path if necessary
$output = [];
$returnVar = -1;

exec($ffmpegPath . ' -version', $output, $returnVar);
return 0 === $returnVar;
}
}

0 comments on commit 2cd311f

Please sign in to comment.