| 
									
										
										
										
											2012-04-13 10:20:54 +02:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-13 14:34:53 +02:00
										 |  |  | /* | 
					
						
							|  |  |  |  * This file is part of PHP-FFmpeg. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * (c) Alchemy <info@alchemy.fr> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * For the full copyright and license information, please view the LICENSE | 
					
						
							|  |  |  |  * file that was distributed with this source code. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-13 10:20:54 +02:00
										 |  |  | namespace FFMpeg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  | use Alchemy\BinaryDriver\ConfigurationInterface; | 
					
						
							| 
									
										
										
										
											2013-08-05 14:36:27 +02:00
										 |  |  | use Alchemy\BinaryDriver\Exception\ExecutionFailureException; | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  | use Doctrine\Common\Cache\ArrayCache; | 
					
						
							|  |  |  | use Doctrine\Common\Cache\Cache; | 
					
						
							|  |  |  | use FFMpeg\Driver\FFProbeDriver; | 
					
						
							|  |  |  | use FFMpeg\FFProbe\DataMapping\Format; | 
					
						
							|  |  |  | use FFMpeg\FFProbe\Mapper; | 
					
						
							|  |  |  | use FFMpeg\FFProbe\MapperInterface; | 
					
						
							|  |  |  | use FFMpeg\FFProbe\OptionsTester; | 
					
						
							|  |  |  | use FFMpeg\FFProbe\OptionsTesterInterface; | 
					
						
							|  |  |  | use FFMpeg\FFProbe\OutputParser; | 
					
						
							|  |  |  | use FFMpeg\FFProbe\OutputParserInterface; | 
					
						
							| 
									
										
										
										
											2012-05-25 16:21:16 +02:00
										 |  |  | use FFMpeg\Exception\InvalidArgumentException; | 
					
						
							|  |  |  | use FFMpeg\Exception\RuntimeException; | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  | use Psr\Log\LoggerInterface; | 
					
						
							| 
									
										
										
										
											2012-04-13 15:12:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  | class FFProbe | 
					
						
							| 
									
										
										
										
											2012-04-13 10:20:54 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     const TYPE_STREAMS = 'streams'; | 
					
						
							|  |  |  |     const TYPE_FORMAT = 'format'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** @var Cache */ | 
					
						
							|  |  |  |     private $cache; | 
					
						
							|  |  |  |     /** @var OptionsTesterInterface */ | 
					
						
							|  |  |  |     private $optionsTester; | 
					
						
							|  |  |  |     /** @var OutputParserInterface */ | 
					
						
							|  |  |  |     private $parser; | 
					
						
							|  |  |  |     /** @var FFProbeDriver */ | 
					
						
							|  |  |  |     private $ffprobe; | 
					
						
							|  |  |  |     /** @var MapperInterface */ | 
					
						
							|  |  |  |     private $mapper; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function __construct(FFProbeDriver $ffprobe, Cache $cache) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->ffprobe = $ffprobe; | 
					
						
							|  |  |  |         $this->optionsTester = new OptionsTester($ffprobe, $cache); | 
					
						
							|  |  |  |         $this->parser = new OutputParser(); | 
					
						
							|  |  |  |         $this->mapper = new Mapper(); | 
					
						
							|  |  |  |         $this->cache = $cache; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-04-13 10:20:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @return OutputParserInterface | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function getParser() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->parser; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-11-25 15:40:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-13 15:12:43 +02:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |      * @param OutputParserInterface $parser | 
					
						
							| 
									
										
										
										
											2012-05-31 16:16:35 +02:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |      * @return FFProbe | 
					
						
							| 
									
										
										
										
											2012-04-13 15:12:43 +02:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     public function setParser(OutputParserInterface $parser) | 
					
						
							| 
									
										
										
										
											2012-04-13 10:20:54 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         $this->parser = $parser; | 
					
						
							| 
									
										
										
										
											2012-04-13 10:20:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-11-25 15:40:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @return FFProbeDriver | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function getFFProbeDriver() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->ffprobe; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-04-13 10:20:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @param FFProbeDriver $ffprobe | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return FFProbe | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function setFFProbeDriver(FFProbeDriver $ffprobe) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->ffprobe = $ffprobe; | 
					
						
							| 
									
										
										
										
											2012-05-31 15:54:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * @param OptionsTesterInterface $tester | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return FFProbe | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function setOptionsTester(OptionsTesterInterface $tester) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->optionsTester = $tester; | 
					
						
							| 
									
										
										
										
											2012-05-31 15:54:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-05-31 15:54:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @return OptionsTesterInterface | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function getOptionsTester() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->optionsTester; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-05-31 15:54:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @param Cache $cache | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return FFProbe | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function setCache(Cache $cache) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->cache = $cache; | 
					
						
							| 
									
										
										
										
											2012-05-31 15:54:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-05-31 15:54:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @return Cache | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function getCache() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->cache; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-05-31 15:54:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @return MapperInterface | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function getMapper() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->mapper; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-05-31 15:54:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @param MapperInterface $mapper | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return FFProbe | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function setMapper(MapperInterface $mapper) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->mapper = $mapper; | 
					
						
							| 
									
										
										
										
											2012-05-31 15:54:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         return $this; | 
					
						
							| 
									
										
										
										
											2012-04-13 10:20:54 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-13 15:12:43 +02:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |      * @api | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2013-06-25 10:40:20 +02:00
										 |  |  |      * Probes the format of a given file. | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |      * | 
					
						
							|  |  |  |      * @param string $pathfile | 
					
						
							| 
									
										
										
										
											2012-04-13 15:12:43 +02:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |      * @return Format A Format object | 
					
						
							| 
									
										
										
										
											2012-05-31 16:16:35 +02:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2012-05-25 16:21:16 +02:00
										 |  |  |      * @throws InvalidArgumentException | 
					
						
							|  |  |  |      * @throws RuntimeException | 
					
						
							| 
									
										
										
										
											2012-04-13 15:12:43 +02:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     public function format($pathfile) | 
					
						
							| 
									
										
										
										
											2012-04-13 10:20:54 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         return $this->probe($pathfile, '-show_format', static::TYPE_FORMAT); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-05-28 19:46:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @api | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2013-06-25 10:40:20 +02:00
										 |  |  |      * Probes the streams contained in a given file. | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |      * | 
					
						
							|  |  |  |      * @param string $pathfile | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return StreamCollection A collection of streams | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @throws InvalidArgumentException | 
					
						
							|  |  |  |      * @throws RuntimeException | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function streams($pathfile) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->probe($pathfile, '-show_streams', static::TYPE_STREAMS); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-05-31 15:54:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @api | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2013-06-25 21:43:19 +02:00
										 |  |  |      * Creates an FFProbe. | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |      * @param array|ConfigurationInterface $configuration | 
					
						
							|  |  |  |      * @param LoggerInterface              $logger | 
					
						
							|  |  |  |      * @param Cache                        $cache | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return FFProbe | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public static function create($configuration = array(), LoggerInterface $logger = null, Cache $cache = null) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (null === $cache) { | 
					
						
							|  |  |  |             $cache = new ArrayCache(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2012-05-31 15:54:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         return new static(FFProbeDriver::create($configuration, $logger), $cache); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-05-31 15:54:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     private function probe($pathfile, $command, $type, $allowJson = true) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $id = sprintf('%s-%s', $command, $pathfile); | 
					
						
							| 
									
										
										
										
											2012-05-28 19:46:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         if ($this->cache->contains($id)) { | 
					
						
							|  |  |  |             return $this->cache->fetch($id); | 
					
						
							| 
									
										
										
										
											2012-05-28 19:46:49 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2012-05-30 12:23:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         if (!$this->optionsTester->has($command)) { | 
					
						
							|  |  |  |             throw new RuntimeException(sprintf( | 
					
						
							|  |  |  |                 'This version of ffprobe is too old and ' | 
					
						
							|  |  |  |                 . 'does not support `%s` option, please upgrade', $command | 
					
						
							|  |  |  |             )); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2012-04-13 10:20:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         $commands = array($pathfile, $command); | 
					
						
							| 
									
										
										
										
											2012-05-25 16:21:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         $parseIsToDo = false; | 
					
						
							| 
									
										
										
										
											2012-05-25 16:21:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         if ($allowJson && $this->optionsTester->has('-print_format')) { | 
					
						
							|  |  |  |             $commands[] = '-print_format'; | 
					
						
							|  |  |  |             $commands[] = 'json'; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             $parseIsToDo = true; | 
					
						
							| 
									
										
										
										
											2012-04-13 15:12:43 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2012-04-13 10:20:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-05 14:36:27 +02:00
										 |  |  |         try { | 
					
						
							|  |  |  |             $output = $this->ffprobe->command($commands); | 
					
						
							|  |  |  |         } catch (ExecutionFailureException $e) { | 
					
						
							|  |  |  |             throw new RuntimeException(sprintf('Unable to probe %s', $pathfile), $e->getCode(), $e); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2012-05-25 16:21:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         if ($parseIsToDo) { | 
					
						
							|  |  |  |             $data = $this->parser->parse($type, $output); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             try { | 
					
						
							|  |  |  |                 // Malformed json may be retrieved
 | 
					
						
							|  |  |  |                 $data = $this->parseJson($output); | 
					
						
							|  |  |  |             } catch (RuntimeException $e) { | 
					
						
							|  |  |  |                 return $this->probe($pathfile, $command, $type, false); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2012-04-13 10:20:54 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         $ret = $this->mapper->map($type, $data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $this->cache->save($id, $ret); | 
					
						
							| 
									
										
										
										
											2012-05-25 16:21:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         return $ret; | 
					
						
							| 
									
										
										
										
											2012-04-13 10:20:54 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |     private function parseJson($data) | 
					
						
							| 
									
										
										
										
											2012-04-13 10:20:54 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-06-25 10:03:20 +02:00
										 |  |  |         $ret = @json_decode($data, true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (JSON_ERROR_NONE !== json_last_error()) { | 
					
						
							|  |  |  |             throw new RuntimeException(sprintf('Unable to parse json %s', $ret)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $ret; | 
					
						
							| 
									
										
										
										
											2012-04-13 10:20:54 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } |