scratch – Blame information for rev 122

Subversion Repositories:
Rev:
Rev Author Line No. Line
120 office 1 <?php
2  
3 /*
4 * This file is part of PHP-FFmpeg.
5 *
6 * (c) Alchemy <info@alchemy.fr>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11  
12 namespace FFMpeg;
13  
14 use Alchemy\BinaryDriver\ConfigurationInterface;
15 use Alchemy\BinaryDriver\Exception\ExecutionFailureException;
16 use Doctrine\Common\Cache\ArrayCache;
17 use Doctrine\Common\Cache\Cache;
18 use FFMpeg\Driver\FFProbeDriver;
19 use FFMpeg\FFProbe\DataMapping\Format;
20 use FFMpeg\FFProbe\Mapper;
21 use FFMpeg\FFProbe\MapperInterface;
22 use FFMpeg\FFProbe\OptionsTester;
23 use FFMpeg\FFProbe\OptionsTesterInterface;
24 use FFMpeg\FFProbe\OutputParser;
25 use FFMpeg\FFProbe\OutputParserInterface;
26 use FFMpeg\Exception\InvalidArgumentException;
27 use FFMpeg\Exception\RuntimeException;
28 use FFMpeg\FFProbe\DataMapping\StreamCollection;
29 use Psr\Log\LoggerInterface;
30  
31 class FFProbe
32 {
33 const TYPE_STREAMS = 'streams';
34 const TYPE_FORMAT = 'format';
35  
36 /** @var Cache */
37 private $cache;
38 /** @var OptionsTesterInterface */
39 private $optionsTester;
40 /** @var OutputParserInterface */
41 private $parser;
42 /** @var FFProbeDriver */
43 private $ffprobe;
44 /** @var MapperInterface */
45 private $mapper;
46  
47 public function __construct(FFProbeDriver $ffprobe, Cache $cache)
48 {
49 $this->ffprobe = $ffprobe;
50 $this->optionsTester = new OptionsTester($ffprobe, $cache);
51 $this->parser = new OutputParser();
52 $this->mapper = new Mapper();
53 $this->cache = $cache;
54 }
55  
56 /**
57 * @return OutputParserInterface
58 */
59 public function getParser()
60 {
61 return $this->parser;
62 }
63  
64 /**
65 * @param OutputParserInterface $parser
66 *
67 * @return FFProbe
68 */
69 public function setParser(OutputParserInterface $parser)
70 {
71 $this->parser = $parser;
72  
73 return $this;
74 }
75  
76 /**
77 * @return FFProbeDriver
78 */
79 public function getFFProbeDriver()
80 {
81 return $this->ffprobe;
82 }
83  
84 /**
85 * @param FFProbeDriver $ffprobe
86 *
87 * @return FFProbe
88 */
89 public function setFFProbeDriver(FFProbeDriver $ffprobe)
90 {
91 $this->ffprobe = $ffprobe;
92  
93 return $this;
94 }
95  
96 /**
97 * @param OptionsTesterInterface $tester
98 *
99 * @return FFProbe
100 */
101 public function setOptionsTester(OptionsTesterInterface $tester)
102 {
103 $this->optionsTester = $tester;
104  
105 return $this;
106 }
107  
108 /**
109 * @return OptionsTesterInterface
110 */
111 public function getOptionsTester()
112 {
113 return $this->optionsTester;
114 }
115  
116 /**
117 * @param Cache $cache
118 *
119 * @return FFProbe
120 */
121 public function setCache(Cache $cache)
122 {
123 $this->cache = $cache;
124  
125 return $this;
126 }
127  
128 /**
129 * @return Cache
130 */
131 public function getCache()
132 {
133 return $this->cache;
134 }
135  
136 /**
137 * @return MapperInterface
138 */
139 public function getMapper()
140 {
141 return $this->mapper;
142 }
143  
144 /**
145 * @param MapperInterface $mapper
146 *
147 * @return FFProbe
148 */
149 public function setMapper(MapperInterface $mapper)
150 {
151 $this->mapper = $mapper;
152  
153 return $this;
154 }
155  
156 /**
157 * @api
158 *
159 * Probes the format of a given file.
160 *
161 * @param string $pathfile
162 *
163 * @return Format A Format object
164 *
165 * @throws InvalidArgumentException
166 * @throws RuntimeException
167 */
168 public function format($pathfile)
169 {
170 return $this->probe($pathfile, '-show_format', static::TYPE_FORMAT);
171 }
172  
173 /**
174 * @api
175 *
176 * Probes the streams contained in a given file.
177 *
178 * @param string $pathfile
179 *
180 * @return StreamCollection A collection of streams
181 *
182 * @throws InvalidArgumentException
183 * @throws RuntimeException
184 */
185 public function streams($pathfile)
186 {
187 return $this->probe($pathfile, '-show_streams', static::TYPE_STREAMS);
188 }
189  
190 /**
191 * @api
192 *
193 * Creates an FFProbe.
194 *
195 * @param array|ConfigurationInterface $configuration
196 * @param LoggerInterface $logger
197 * @param Cache $cache
198 *
199 * @return FFProbe
200 */
201 public static function create($configuration = array(), LoggerInterface $logger = null, Cache $cache = null)
202 {
203 if (null === $cache) {
204 $cache = new ArrayCache();
205 }
206  
207 return new static(FFProbeDriver::create($configuration, $logger), $cache);
208 }
209  
210 private function probe($pathfile, $command, $type, $allowJson = true)
211 {
212 $id = sprintf('%s-%s', $command, $pathfile);
213  
214 if ($this->cache->contains($id)) {
215 return $this->cache->fetch($id);
216 }
217  
218 if (!$this->optionsTester->has($command)) {
219 throw new RuntimeException(sprintf(
220 'This version of ffprobe is too old and '
221 . 'does not support `%s` option, please upgrade', $command
222 ));
223 }
224  
225 $commands = array($pathfile, $command);
226  
227 $parseIsToDo = false;
228  
229 if ($allowJson && $this->optionsTester->has('-print_format')) {
230 // allowed in latest PHP-FFmpeg version
231 $commands[] = '-print_format';
232 $commands[] = 'json';
233 } elseif ($allowJson && $this->optionsTester->has('-of')) {
234 // option has changed in avconv 9
235 $commands[] = '-of';
236 $commands[] = 'json';
237 } else {
238 $parseIsToDo = true;
239 }
240  
241 try {
242 $output = $this->ffprobe->command($commands);
243 } catch (ExecutionFailureException $e) {
244 throw new RuntimeException(sprintf('Unable to probe %s', $pathfile), $e->getCode(), $e);
245 }
246  
247 if ($parseIsToDo) {
248 $data = $this->parser->parse($type, $output);
249 } else {
250 try {
251 // Malformed json may be retrieved
252 $data = $this->parseJson($output);
253 } catch (RuntimeException $e) {
254 return $this->probe($pathfile, $command, $type, false);
255 }
256 }
257  
258 $ret = $this->mapper->map($type, $data);
259  
260 $this->cache->save($id, $ret);
261  
262 return $ret;
263 }
264  
265 private function parseJson($data)
266 {
267 $ret = @json_decode($data, true);
268  
269 if (JSON_ERROR_NONE !== json_last_error()) {
270 throw new RuntimeException(sprintf('Unable to parse json %s', $ret));
271 }
272  
273 return $ret;
274 }
275 }