[ui:cwd] fix #1433 create a thumbnail of the video file with ffmpeg

Added volume root options
```php
// Video to Image converters ['TYPE or MIME' => ['func' => function($file){ /* Converts $file to Image */ return true; }, 'maxlen' => (int)TransferLength]]
'imgConverter'    => array(),
// Max length of transfer to image converter
'tmbVideoConvLen' => 10000000,
// Captre point seccond
'tmbVideoConvSec' => 6,
// Resource path of fallback icon images defailt: php/resouces
'resourcePath'    => '',
```

It can specify a specific number of seconds part in the file name.

e.g.
xxx^[sec].[extention] -> video^3.mp4
This commit is contained in:
nao-pon
2016-06-01 23:36:55 +09:00
parent 42df491664
commit 367cdeb82d
2 changed files with 153 additions and 12 deletions
+130 -10
View File
@@ -108,6 +108,13 @@ abstract class elFinderVolumeDriver {
**/
protected $imgLib = 'auto';
/**
* Video to Image converter
*
* @var array
*/
protected $imgConverter = array();
/**
* Library to crypt files name
*
@@ -236,6 +243,14 @@ abstract class elFinderVolumeDriver {
'imgLib' => 'auto',
// Fallback self image to thumbnail (nothing imgLib)
'tmbFbSelf' => true,
// Video to Image converters ['TYPE or MIME' => ['func' => function($file){ /* Converts $file to Image */ return true; }, 'maxlen' => (int)TransferLength]]
'imgConverter' => array(),
// Max length of transfer to image converter
'tmbVideoConvLen' => 10000000,
// Captre point seccond
'tmbVideoConvSec' => 6,
// Resource path of fallback icon images defailt: php/resouces
'resourcePath' => '',
// Jpeg image saveing quality
'jpgQuality' => 100,
// on paste file - if true - old file will be replaced with new one, if false new file get name - original_name-number.ext
@@ -656,6 +671,10 @@ abstract class elFinderVolumeDriver {
$this->tmbPathWritable = is_writable($path);
}
}
// set resouce path
if (! is_dir($this->options['resourcePath'])) {
$this->options['resourcePath'] = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'resources';
}
// set image manipulation library
$type = preg_match('/^(imagick|gd|convert|auto)$/i', $this->options['imgLib'])
@@ -681,6 +700,28 @@ abstract class elFinderVolumeDriver {
$this->imgLib = extension_loaded('imagick')? 'imagick' : (function_exists('gd_info')? 'gd' : '');
}
// check video to img converter
if (! empty($this->options['imgConverter']) && is_array($this->options['imgConverter'])) {
foreach($this->options['imgConverter'] as $_type => $_converter) {
if (isset($_converter['func'])) {
$this->imgConverter[strtolower($_type)] = $_converter;
}
}
}
if (! isset($this->imgConverter['video'])) {
$videoLibCache = 'videoLib';
if (($videoLibCmd = $this->session->get($videoLibCache, false)) === false) {
$videoLibCmd = ($this->procExec('ffmpeg -version') === 0)? 'ffmpeg' : '';
$this->session->set($videoLibCache, $videoLibCmd);
}
if ($videoLibCmd) {
$this->imgConverter['video'] = array(
'func' => array($this, $videoLibCmd . 'ToImg'),
'maxlen' => $this->options['tmbVideoConvLen']
);
}
}
// check archivers
if (empty($this->archivers['create'])) {
$this->disabled[] ='archive';
@@ -1604,7 +1645,18 @@ abstract class elFinderVolumeDriver {
$stat = $this->stat($path);
if (isset($stat['tmb'])) {
return $stat['tmb'] == "1" ? $this->createTmb($path, $stat) : $stat['tmb'];
$res = $stat['tmb'] == "1" ? $this->createTmb($path, $stat) : $stat['tmb'];
if (! $res) {
list($type) = explode('/', $stat['mime']);
$fallback = $this->options['resourcePath'] . DIRECTORY_SEPARATOR . strtolower($type) . '.png';
if (is_file($fallback)) {
$res = $this->tmbname($stat);
if (! copy($fallback, $this->tmbPath . DIRECTORY_SEPARATOR . $res)) {
$res = false;
}
}
}
return $res;
}
return false;
}
@@ -2625,6 +2677,34 @@ abstract class elFinderVolumeDriver {
return false;
}
/**
* Convert Video To Image by ffmpeg
*
* @param $file video source file path
* @param $stat file stat array
* @return bool
* @author Naoki Sawada
*/
public function ffmpegToImg($file, $stat) {
$name = basename($file);
$path = dirname($file);
$tmp = $path . DIRECTORY_SEPARATOR . md5($name);
$GLOBALS['elFinderTempFiles'][] = $tmp; // regist to remove at the end
if (rename($file, $tmp)) {
// specific start time by file name (xxx^[sec].[extention] - video^3.mp4)
if (preg_match('/\^(\d+(?:\.\d+)?)\.[^.]+$/', $stat['name'], $_m)) {
$ss = $_m[1];
} else {
$ss = $this->options['tmbVideoConvSec'];
}
$cmd = sprintf('ffmpeg -ss 00:00:%.3f -vframes 1 -i %s -f image2 %s', $ss, escapeshellarg($tmp), escapeshellarg($file));
$r = $this->procExec($cmd);
unlink($tmp);
return ($r === 0);
}
return false;
}
/**
* Save error message
*
@@ -4126,11 +4206,24 @@ abstract class elFinderVolumeDriver {
* @author Dmitry (dio) Levashov
**/
protected function canCreateTmb($path, $stat, $checkTmbPath = true) {
return (!$checkTmbPath || $this->tmbPathWritable)
&& (!$this->tmbPath || strpos($path, $this->tmbPath) === false) // do not create thumnbnail for thumnbnail
&& $this->imgLib
&& strpos($stat['mime'], 'image') === 0
&& ($this->imgLib == 'gd' ? in_array($stat['mime'], array('image/jpeg', 'image/png', 'image/gif', 'image/x-ms-bmp')) : true);
if ((! $checkTmbPath || $this->tmbPathWritable)
&& (! $this->tmbPath || strpos($path, $this->tmbPath) === false) // do not create thumnbnail for thumnbnail
) {
$mime = strtolower($stat['mime']);
list($type) = explode('/', $mime);
if (! empty($this->imgConverter)) {
if (isset($this->imgConverter[$mime])) {
return true;
}
if (isset($this->imgConverter[$type])) {
return true;
}
}
return $this->imgLib
&& ($type === 'image')
&& ($this->imgLib == 'gd' ? in_array($stat['mime'], array('image/jpeg', 'image/png', 'image/gif', 'image/x-ms-bmp')) : true);
}
return false;
}
/**
@@ -4163,6 +4256,27 @@ abstract class elFinderVolumeDriver {
$name = $this->tmbname($stat);
$tmb = $this->tmbPath.DIRECTORY_SEPARATOR.$name;
$maxlength = -1;
$imgConverter = null;
// check imgConverter
$mime = strtolower($stat['mime']);
list($type) = explode('/', $mime);
if (isset($this->imgConverter[$mime])) {
$imgConverter = $this->imgConverter[$mime]['func'];
if (! empty($this->imgConverter[$mime]['maxlen'])) {
$maxlength = intval($this->imgConverter[$mime]['maxlen']);
}
} else if (isset($this->imgConverter[$type])) {
$imgConverter = $this->imgConverter[$type]['func'];
if (! empty($this->imgConverter[$type]['maxlen'])) {
$maxlength = intval($this->imgConverter[$type]['maxlen']);
}
}
if ($imgConverter && ! is_callable($imgConverter)) {
return false;
}
// copy image into tmbPath so some drivers does not store files on local fs
if (($src = $this->fopenCE($path, 'rb')) == false) {
return false;
@@ -4173,13 +4287,19 @@ abstract class elFinderVolumeDriver {
return false;
}
while (!feof($src)) {
fwrite($trg, fread($src, 8192));
}
stream_copy_to_stream($src, $trg, $maxlength);
$this->fcloseCE($src, $path);
fclose($trg);
// call imgConverter
if ($imgConverter) {
if (! call_user_func_array($imgConverter, array($tmb, $stat, $this))) {
file_exists($tmb) && unlink($tmb);
return false;
}
}
$result = false;
$tmbSize = $this->tmbSize;
@@ -4213,7 +4333,7 @@ abstract class elFinderVolumeDriver {
} catch (Exception $e) {}
}
if (! $result) {
unlink($tmb);
file_exists($tmb) && unlink($tmb);
return false;
}
$result = false;