public function register(Application $app) { $app['ffmpeg.configuration'] = array(); $app['ffmpeg.default.configuration'] = array('ffmpeg.threads' => 4, 'ffmpeg.timeout' => 300, 'ffmpeg.binaries' => array('avconv', 'ffmpeg'), 'ffprobe.timeout' => 30, 'ffprobe.binaries' => array('avprobe', 'ffprobe')); $app['ffmpeg.logger'] = null; $app['ffmpeg.configuration.build'] = $app->share(function (Application $app) { return array_replace($app['ffmpeg.default.configuration'], $app['ffmpeg.configuration']); }); $app['ffmpeg'] = $app['ffmpeg.ffmpeg'] = $app->share(function (Application $app) { $configuration = $app['ffmpeg.configuration.build']; if (isset($configuration['ffmpeg.timeout'])) { $configuration['timeout'] = $configuration['ffmpeg.timeout']; } return FFMpeg::create($configuration, $app['ffmpeg.logger'], $app['ffmpeg.ffprobe']); }); $app['ffprobe.cache'] = $app->share(function () { return new ArrayCache(); }); $app['ffmpeg.ffprobe'] = $app->share(function (Application $app) { $configuration = $app['ffmpeg.configuration.build']; if (isset($configuration['ffmpeg.timeout'])) { $configuration['timeout'] = $configuration['ffprobe.timeout']; } return FFProbe::create($configuration, $app['ffmpeg.logger'], $app['ffprobe.cache']); }); }
/** * @covers MediaVorus\MediaCollection::match */ public function testMatch() { $logger = new Logger('test'); $logger->pushHandler(new NullHandler()); $mediavorus = new MediaVorus(Reader::create($logger), Writer::create($logger), FFProbe::create()); $collection = $mediavorus->inspectDirectory(__DIR__ . '/../../files/'); $audio = $collection->match(new MediaType(MediaInterface::TYPE_AUDIO)); $this->assertInstanceOf('\\Doctrine\\Common\\Collections\\ArrayCollection', $audio); $this->assertGreaterThan(0, $audio->count()); foreach ($audio as $audio) { $this->assertEquals(MediaInterface::TYPE_AUDIO, $audio->getType()); } $notAudio = $collection->match(new MediaType(MediaInterface::TYPE_AUDIO), true); $this->assertGreaterThan(0, $notAudio->count()); $this->assertInstanceOf('\\Doctrine\\Common\\Collections\\ArrayCollection', $notAudio); foreach ($notAudio as $audio) { $this->assertFalse(MediaInterface::TYPE_AUDIO === $audio->getType()); } }
/** * Instantiate mediavorus to register the mime types */ public function setUp() { parent::setUp(); $logger = new Logger('test'); $logger->pushHandler(new NullHandler()); $mediavorus = new MediaVorus(Reader::create($logger), Writer::create($logger), FFProbe::create()); }
public function getProbe() { try { return FFProbe::create(); } catch (FFMpegExecutableNotFound $e) { } return null; }
public function __construct($file, $screenshotDirectory = '/tmp') { $this->file = $file; $this->screenshotDirectory = $screenshotDirectory; $this->ffmpeg = FFMpeg::create(); $this->ffprobe = FFProbe::create(); $this->movie = $this->ffmpeg->open($file); $this->info = $this->ffprobe->format($file); }
public function setUp() { if (!class_exists('FFMpeg\\FFProbe')) { $this->markTestSkipped('FFMpeg\\FFProbe not available.'); } try { $this->reader = new FfprobeReader(FFProbe::create()); } catch (\Exception $e) { $this->markTestSkipped('FfprobeReader not available.'); } }
/** * Create screenshot from uploaded video * @param \App\Models\Video $video The object we created * @return boolean Always true */ private function capture(\App\Models\Video $video) { //that's easier $video_path = public_path('/videos/' . $video->video); //find duration $ffprobe = \FFMpeg\FFProbe::create(); $duration = $ffprobe->format($video_path)->get('duration'); //take the shot $ffmpeg = \FFMpeg\FFMpeg::create(); $capture = $ffmpeg->open($video_path); $capture->frame(\FFMpeg\Coordinate\TimeCode::fromSeconds($duration > 5 ? 5 : (int) ($duration / 2)))->save(public_path('/previews/' . $video->getKey() . '.jpg')); return true; }
protected function __construct() { $basedir = dirname(dirname(dirname(__DIR__))); StitchLib::$log_dir = $basedir . DIRECTORY_SEPARATOR . 'logs'; StitchLib::$tmp_dir = sys_get_temp_dir(); if (!is_dir(StitchLib::$log_dir)) { mkdir(StitchLib::$log_dir); } if (!is_dir(StitchLib::$tmp_dir)) { mkdir(StitchLib::$tmp_dir, 0777, true); } $this->logger = new Logger(StitchLib::$log_dir); $this->ffprobe = \FFMpeg\FFProbe::create([], $this->logger); }
public function setUp() { parent::setUp(); $logger = new Logger('Tests'); $logger->pushHandler(new NullHandler()); $this->reader = Reader::create($logger); $this->writer = Writer::create($logger); $file = __DIR__ . '/../../../files/ExifTool.jpg'; $this->object = new Image(new File($file), $this->reader->reset()->files($file)->first(), $this->writer); $logger = new Logger('test'); $logger->pushHandler(new NullHandler()); $this->ffprobe = FFProbe::create(); $this->mediavorus = new MediaVorus($this->reader, $this->writer, $this->ffprobe); }
/** * Create. * * This method creates the thumbnail from the video. * * @param string $videoFile Video file to process * @param string $thumbnailFile Output gif * @param int|null $count Number of frames to use * @param int|null $interval The interval beetween the frames of the gif * @param int|null $width Width of the gif * @param int|null $height Height of the gif * @param int|null $start The start of the video part * @param int|null $end The end of the video part * * @throws VideoException If error during procession or writing. */ public function create($videoFile, $thumbnailFile, $count = null, $interval = null, $width = null, $height = null, $start = null, $end = null) { $count = $count ?: $this->defaults['count']; $interval = $interval ?: $this->defaults['interval']; $width = $width ?: $this->defaults['width']; $height = $height ?: $this->defaults['height']; try { $ffmpeg = FFMpeg::create(); $ffprobe = FFProbe::create(); } catch (\Exception $e) { throw new VideoException('Cannot start FFMpeg or FFProbe', 0, $e); } try { // Determine the duration of the video $duration = $ffprobe->format($videoFile)->get('duration'); } catch (\Exception $e) { throw new VideoException(sprintf('Cannot determine the duration of %s', $videoFile), 0, $e); } // If invalid start or end time, assume it is the start and the end // of the video. $start = max(0, $start ?: 0); $end = min($duration, $end ?: $duration); $delay = (double) ($end - $start) / ($count + 1); $video = $ffmpeg->open($videoFile); $hashDir = $this->tmpDir . '/video-gif/' . md5($videoFile . time()); if (!file_exists($hashDir)) { mkdir($hashDir, 0777, true); } $pos = $start; $frames = array(); $durations = array(); // Grab frames for ($i = 0; $i < $count; ++$i) { $pos += $delay; $video->frame(TimeCode::fromSeconds($pos))->save(sprintf($hashDir . '/tmp-frame%03d.jpg', $i)); Image::open(sprintf($hashDir . '/tmp-frame%03d.jpg', $i))->cropResize($width, $height)->save(sprintf($hashDir . '/frame%03d.jpg', $i)); $frames[] = sprintf($hashDir . '/frame%03d.jpg', $i); $durations[] = $interval; } $gc = new GifCreator(); $gc->create($frames, $durations, 0); $this->removeDirectory($hashDir); if (false === @file_put_contents($thumbnailFile, $gc->getGif())) { throw new VideoException(sprintf('Cannot write %s', $thumbnailFile)); } }
/** * Get video properties * * @param $path * @return array|null * @throws ErrorException */ public static function getProperties($path) { if (is_file($path)) { // init $ffprobe = FFProbe::create(); $streams = $ffprobe->streams($path); // extracts streams informations // get video data $video = $streams->videos()->first(); // filters video first streams $dimensions = $video->getDimensions(); // get audio data $audio = $streams->audios()->first(); // filters audio first streams return ['screen_width' => $dimensions->getWidth(), 'screen_height' => $dimensions->getHeight(), 'video_bitrate' => $video->get('bit_rate'), 'audio_bitrate' => $audio->get('bit_rate')]; } throw new ErrorException('Not found file: ' . $path); }
/** * Create MediaVorus * * @return MediaVorus */ public static function create() { $logger = new Logger('MediaVorus'); $logger->pushHandler(new NullHandler()); return new static(Reader::create($logger), Writer::create($logger), FFProbe::create(array(), $logger)); }
public function __construct($file) { parent::__construct($file); $this->ffprobe = FFProbe::create(['ffmpeg.binaries' => env('FFMPEG'), 'ffprobe.binaries' => env('FFPROBE')]); $this->ffmpeg = FFMpeg::create(['ffmpeg.binaries' => env('FFMPEG'), 'ffprobe.binaries' => env('FFPROBE')]); }
public function testProbeOnRemoteFile() { $ffprobe = FFProbe::create(); $this->assertGreaterThan(0, count($ffprobe->streams('http://vjs.zencdn.net/v/oceans.mp4'))); }
/** * Generates sprite and WebVTT for selected video * * @throws \Exception */ public function generate() { // create temporay directory $tempDir = new Tempdir('sprite'); $tempDir->addPlugin(new ListFiles()); // get basic info about video $ffprobe = FFProbe::create()->format($this->getSource()); $duration = floatval($ffprobe->get('duration')); // check if sample rate is high enough to reach desired minimum amount of thumbnails if ($duration <= $this->getMinThumbs()) { // we only have a 1 second resolution, so we can't get lower than 1 obviously $this->setRate(1); } else { if ($duration / $this->getRate() < $this->getMinThumbs()) { // sample rate too high, let's adjust rate a little $this->setRate(floor($duration / $this->getMinThumbs())); } } // capture images to tempdir for ($i = 0; $i <= $duration; $i += $this->getRate()) { $cmd = sprintf('ffmpeg -y -ss %d -i %s -frames:v 1 -filter:v scale=%d:-1 %s/%04d.jpg', $i, $this->getSource(), $this->getWidth(), $tempDir->getPath(), floor($i / $this->getRate())); $proc = new Process($cmd); $proc->setTimeout(null); $proc->run(); if (!$proc->isSuccessful()) { throw new \RuntimeException($cmd . ":" . $proc->getErrorOutput()); } } // combine all images to one sprite with quadratic tiling $gridSize = ceil(sqrt(count($tempDir->listFiles()))); $firstImage = Image::make(sprintf('%s/0001.jpg', $tempDir->getPath())); $spriteFile = sprintf('%s/%s.jpg', $this->getOutputDirectory(), $this->getPrefix()); $spriteUrl = empty($this->getUrlPrefix()) ? basename($spriteFile) : sprintf('%s/%s', $this->getUrlPrefix(), basename($spriteFile)); $cmd = sprintf('montage %1$s/*.jpg -tile %2$dx -geometry %3$dx%4$d+0+0 %5$s', $tempDir->getPath(), $gridSize, $firstImage->width(), $firstImage->height(), $spriteFile); $proc = new Process($cmd); $proc->run(); if (!$proc->isSuccessful()) { throw new RuntimeException($proc->getErrorOutput()); } // create WebVTT output $vttFile = sprintf('%s/%s.vtt', $this->getOutputDirectory(), $this->getPrefix()); $vtt = new WebvttFile(); for ($i = 0; $i < count($tempDir->listFiles()); $i++) { $start = $i * $this->getRate(); $end = ($i + 1) * $this->getRate(); $x = $i % $gridSize * $firstImage->width(); $y = floor($i / $gridSize) * $firstImage->height(); $vtt->addCue(new WebvttCue($this->secondsToCue($start), $this->secondsToCue($end), sprintf('%s#xywh=%d,%d,%d,%d', $spriteUrl, $x, $y, $firstImage->width(), $firstImage->height()))); } $vtt->build(); $vtt->save($vttFile); }
/** * Creates a new FFMpeg instance. * * @param array|ConfigurationInterface $configuration * @param LoggerInterface $logger * @param FFProbe $probe * * @return FFMpeg */ public static function create($configuration = array(), LoggerInterface $logger = null, FFProbe $probe = null) { if (null === $probe) { $probe = FFProbe::create($configuration, $logger, null); } return new static(FFMpegDriver::create($logger, $configuration), $probe); }
private function ingestImageAsset($filepath, $type, $ffprobe_config) { $msg = "Creating probe, for file: {$filepath}"; $this->report[] = $msg; static::$logger->info($msg); try { $probe = FFProbe::create($ffprobe_config, static::$logger); if (!$probe) { throw new \Exception('FFProbe failed to create.'); } else { $msg = "Probe created"; $this->report[] = $msg; static::$logger->info($msg); } } catch (Exception $e) { $msg = "Probe creation failed: " . $e->getMessage(); $this->report[] = $msg; static::$logger->info($msg); } $assignedProperties = []; $msg = "Probing file properties: {$filepath}"; $this->report[] = $msg; static::$logger->info($msg); try { $props = $probe->format($filepath)->all(); if ($props) { $assignedProperties[] = $this->formatToJsonArray($props); } } catch (ExecutionFailureException $e) { $msg = $e->getMessage(); static::$logger->addWarning($msg); return false; // triggers rejection in ingest } $msg = "Probing exif properties"; $this->report[] = $msg; static::$logger->info($msg); $exif = new Exif($filepath); $msg = "Encoding derived metadata"; $this->report[] = $msg; static::$logger->info($msg); $exif_json = json_encode($exif->toArray(), JSON_UNESCAPED_SLASHES); $exif_obj = Util::decode_json($exif_json); $msg = "Encoding assignedProperties"; $this->report[] = $msg; static::$logger->info($msg); $json_props = implode(",\n", $assignedProperties); $data = Util::decode_json($json_props); if ($exif_obj) { $msg = "Attaching derived exif props"; $this->report[] = $msg; static::$logger->info($msg); $data->{'exif'} = $exif_obj; } $msg = "Returning derived data object"; $this->report[] = $msg; static::$logger->info($msg); return $data; }
public function getVideoLength($videoPath) { $ffprobe = \FFMpeg\FFProbe::create(); return $ffprobe->streams($videoPath)->videos()->first()->get('duration'); }
/** * Get FFProbe */ private function getFFProbe() { return $ffmpeg = \FFMpeg\FFProbe::create($this->getFFMpegConfig()); }
/** * @dataProvider provideCreateOptions */ public function testCreate($logger, $conf, $cache) { $finder = new ExecutableFinder(); $found = false; foreach (array('avprobe', 'ffprobe') as $name) { if (null !== $finder->find($name)) { $found = true; } } if (!$found) { $this->markTestSkipped("Unable to find avprobe or ffprobe on system"); } $ffprobe = FFProbe::create(); $this->assertInstanceOf('FFMpeg\\FFprobe', $ffprobe); $ffprobe = FFProbe::create($conf, $logger, $cache); $this->assertInstanceOf('FFMpeg\\FFprobe', $ffprobe); if (null !== $cache) { $this->assertSame($cache, $ffprobe->getCache()); } if (null !== $logger) { $this->assertSame($logger, $ffprobe->getFFProbeDriver()->getProcessRunner()->getLogger()); } if ($conf instanceof ConfigurationInterface) { $this->assertSame($conf, $ffprobe->getFFProbeDriver()->getConfiguration()); } }
public function __construct() { $this['logger.name'] = 'Media-Alchemyst drivers logger'; $this['logger.level'] = function (Pimple $container) { return Logger::DEBUG; }; $this['logger.handler'] = $this->share(function (Pimple $container) { return new NullHandler($container['logger.level']); }); $bridge = class_exists('Symfony\\Bridge\\Monolog\\Logger'); $this['logger.class'] = $bridge ? 'Symfony\\Bridge\\Monolog\\Logger' : 'Monolog\\Logger'; $this['logger'] = $this->share(function (Pimple $container) { $logger = new $container['logger.class']($container['logger.name']); $logger->pushHandler($container['logger.handler']); return $logger; }); $this['default.configuration'] = array('ffmpeg.threads' => 4, 'ffmpeg.ffmpeg.timeout' => 3600, 'ffmpeg.ffprobe.timeout' => 60, 'ffmpeg.ffmpeg.binaries' => null, 'ffmpeg.ffprobe.binaries' => null, 'imagine.driver' => null, 'gs.timeout' => 60, 'gs.binaries' => null, 'mp4box.timeout' => 60, 'mp4box.binaries' => null, 'swftools.timeout' => 60, 'swftools.pdf2swf.binaries' => null, 'swftools.swfrender.binaries' => null, 'swftools.swfextract.binaries' => null, 'unoconv.binaries' => null, 'unoconv.timeout' => 60); $this['configuration'] = array(); $this['configuration.merged'] = $this->share(function (Pimple $container) { return array_replace($container['default.configuration'], $container['configuration']); }); $this['ffmpeg.ffmpeg'] = $this->share(function (Pimple $container) { try { return FFMpeg::create(array_filter(array('ffmpeg.threads' => $container['configuration.merged']['ffmpeg.threads'], 'timeout' => $container['configuration.merged']['ffmpeg.ffmpeg.timeout'], 'ffmpeg.binaries' => $container['configuration.merged']['ffmpeg.ffmpeg.binaries'])), $container['logger'], $container['ffmpeg.ffprobe']); } catch (FFMpegExecutableNotFound $e) { throw new RuntimeException('Unable to create FFMpeg driver', $e->getCode(), $e); } }); $this['ffmpeg.ffprobe.cache'] = $this->share(function (Pimple $container) { return new ArrayCache(); }); $this['ffmpeg.ffprobe'] = $this->share(function (Pimple $container) { try { return FFProbe::create(array_filter(array('timeout' => $container['configuration.merged']['ffmpeg.ffprobe.timeout'], 'ffprobe.binaries' => $container['configuration.merged']['ffmpeg.ffprobe.binaries'])), $container['logger'], $container['ffmpeg.ffprobe.cache']); } catch (FFMpegExecutableNotFound $e) { throw new RuntimeException('Unable to create FFProbe driver', $e->getCode(), $e); } }); $this['imagine'] = $this->share(function (Pimple $container) { $driver = $container['configuration.merged']['imagine.driver']; switch (true) { case 'imagick' === strtolower($driver): case null === $driver && class_exists('Imagick'): $driver = 'Imagine\\Imagick\\Imagine'; break; case 'gmagick' === strtolower($driver): case null === $driver && class_exists('Gmagick'): $driver = 'Imagine\\Gmagick\\Imagine'; break; case 'gd' === strtolower($driver): case null === $driver && extension_loaded('gd'): $driver = 'Imagine\\Gd\\Imagine'; break; } if (false === class_exists($driver) || false === in_array('Imagine\\Image\\ImagineInterface', class_implements($driver))) { throw new InvalidArgumentException(sprintf('Invalid Imagine driver %s', $driver)); } return new $driver(); }); $this['swftools.driver-container'] = $this->share(function (Pimple $container) { return DriverContainer::create(array_filter(array('pdf2swf.binaries' => $container['configuration.merged']['swftools.pdf2swf.binaries'], 'swfrender.binaries' => $container['configuration.merged']['swftools.swfrender.binaries'], 'swfextract.binaries' => $container['configuration.merged']['swftools.swfextract.binaries'], 'timeout' => $container['configuration.merged']['swftools.timeout'])), $container['logger']); }); $this['swftools.flash-file'] = $this->share(function (Pimple $container) { return new FlashFile($container['swftools.driver-container']); }); $this['swftools.pdf-file'] = $this->share(function (Pimple $container) { return new PDFFile($container['swftools.driver-container']); }); $this['unoconv'] = $this->share(function (Pimple $container) { try { return Unoconv::create(array_filter(array('unoconv.binaries' => $container['configuration.merged']['unoconv.binaries'], 'timeout' => $container['configuration.merged']['unoconv.timeout'])), $container['logger']); } catch (ExecutableNotFoundException $e) { throw new RuntimeException('Unable to create Unoconv driver', $e->getCode(), $e); } }); $this['exiftool.exiftool'] = $this->share(function (Pimple $container) { return new Exiftool($container['logger']); }); $this['exiftool.rdf-parser'] = $this->share(function (Pimple $container) { return new RDFParser(); }); $this['exiftool.reader'] = $this->share(function (Pimple $container) { return new Reader($container['exiftool.exiftool'], $container['exiftool.rdf-parser']); }); $this['exiftool.writer'] = $this->share(function (Pimple $container) { return new Writer($container['exiftool.exiftool']); }); $this['exiftool.preview-extractor'] = $this->share(function (Pimple $container) { return new PreviewExtractor($container['exiftool.exiftool']); }); $this['ghostscript.transcoder'] = $this->share(function (Pimple $container) { try { return Transcoder::create(array_filter(array('gs.binaries' => $container['configuration.merged']['gs.binaries'], 'timeout' => $container['configuration.merged']['gs.timeout'])), $container['logger']); } catch (ExecutableNotFoundException $e) { throw new RuntimeException('Unable to create Unoconv driver', $e->getCode(), $e); } }); $this['mp4box'] = $this->share(function (Pimple $container) { try { return MP4Box::create(array_filter(array('mp4box.binaries' => $container['configuration.merged']['mp4box.binaries'], 'timeout' => $container['configuration.merged']['mp4box.timeout']))); } catch (ExecutableNotFoundException $e) { throw new RuntimeException('Unable to create Unoconv driver', $e->getCode(), $e); } }); $this['mediavorus'] = $this->share(function (Pimple $container) { $ffprobe = null; try { $ffprobe = $container['ffmpeg.ffprobe']; } catch (RuntimeException $e) { } return new MediaVorus($container['exiftool.reader'], $container['exiftool.writer'], $ffprobe); }); }
public function testProbeOnRemoteFile() { $ffprobe = FFProbe::create(); $this->assertGreaterThan(0, count($ffprobe->streams('http://video-js.zencoder.com/oceans-clip.mp4'))); }