scratch – Blame information for rev 115

Subversion Repositories:
Rev:
Rev Author Line No. Line
115 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\Format\ProgressListener;
13  
14 use Alchemy\BinaryDriver\Listeners\ListenerInterface;
15 use Evenement\EventEmitter;
16 use FFMpeg\FFProbe;
17 use FFMpeg\Exception\RuntimeException;
18  
19 /**
20 * @author Robert Gruendler <r.gruendler@gmail.com>
21 */
22 abstract class AbstractProgressListener extends EventEmitter implements ListenerInterface
23 {
24 /** @var integer */
25 private $duration;
26  
27 /** @var integer */
28 private $totalSize;
29  
30 /** @var integer */
31 private $currentSize;
32  
33 /** @var integer */
34 private $currentTime;
35  
36 /** @var double */
37 private $lastOutput = null;
38  
39 /** @var FFProbe */
40 private $ffprobe;
41  
42 /** @var string */
43 private $pathfile;
44  
45 /** @var Boolean */
46 private $initialized = false;
47  
48 /** @var integer */
49 private $currentPass;
50  
51 /** @var integer */
52 private $totalPass;
53  
54 /**
55 * Transcoding rate in kb/s
56 *
57 * @var integer
58 */
59 private $rate;
60  
61 /**
62 * Percentage of transcoding progress (0 - 100)
63 *
64 * @var integer
65 */
66 private $percent = 0;
67  
68 /**
69 * Time remaining (seconds)
70 *
71 * @var integer
72 */
73 private $remaining = null;
74  
75 /**
76 * @param FFProbe $ffprobe
77 * @param string $pathfile
78 * @param integer $currentPass The cureent pass number
79 * @param integer $totalPass The total number of passes
80 *
81 * @throws RuntimeException
82 */
83 public function __construct(FFProbe $ffprobe, $pathfile, $currentPass, $totalPass)
84 {
85 $this->ffprobe = $ffprobe;
86 $this->pathfile = $pathfile;
87 $this->currentPass = $currentPass;
88 $this->totalPass = $totalPass;
89 }
90  
91 /**
92 * @return FFProbe
93 */
94 public function getFFProbe()
95 {
96 return $this->ffprobe;
97 }
98  
99 /**
100 * @return string
101 */
102 public function getPathfile()
103 {
104 return $this->pathfile;
105 }
106  
107 /**
108 * @return integer
109 */
110 public function getCurrentPass()
111 {
112 return $this->currentPass;
113 }
114  
115 /**
116 * @return integer
117 */
118 public function getTotalPass()
119 {
120 return $this->totalPass;
121 }
122  
123 /**
124 * @return int
125 */
126 public function getCurrentTime()
127 {
128 return $this->currentTime;
129 }
130  
131 /**
132 * {@inheritdoc}
133 */
134 public function handle($type, $data)
135 {
136 if (null !== $progress = $this->parseProgress($data)) {
137 $this->emit('progress', array_values($progress));
138 }
139 }
140  
141 /**
142 * {@inheritdoc}
143 */
144 public function forwardedEvents()
145 {
146 return array();
147 }
148  
149 /**
150 * Get the regex pattern to match a ffmpeg stderr status line
151 */
152 abstract protected function getPattern();
153  
154 /**
155 * @param string $progress A ffmpeg stderr progress output
156 *
157 * @return array the progressinfo array or null if there's no progress available yet.
158 */
159 private function parseProgress($progress)
160 {
161 if (!$this->initialized) {
162 $this->initialize();
163 }
164  
165 if (null === $this->totalSize || null === $this->duration) {
166 return;
167 }
168  
169 $matches = array();
170  
171 if (preg_match($this->getPattern(), $progress, $matches) !== 1) {
172 return null;
173 }
174  
175 $currentDuration = $this->convertDuration($matches[2]);
176 $currentTime = microtime(true);
177 $currentSize = trim(str_replace('kb', '', strtolower(($matches[1]))));
178 $percent = max(0, min(1, $currentDuration / $this->duration));
179  
180 if ($this->lastOutput !== null) {
181 $delta = $currentTime - $this->lastOutput;
182  
183 // Check the type of the currentSize variable and convert it to an integer if needed.
184 if(!is_numeric($currentSize)) {
185 $currentSize = (int)$currentSize;
186 }
187  
188 $deltaSize = $currentSize - $this->currentSize;
189 $rate = $deltaSize * $delta;
190 if ($rate > 0) {
191 $totalDuration = $this->totalSize / $rate;
192 $this->remaining = floor($totalDuration - ($totalDuration * $percent));
193 $this->rate = floor($rate);
194 } else {
195 $this->remaining = 0;
196 $this->rate = 0;
197 }
198 }
199  
200 $percent = $percent / $this->totalPass + ($this->currentPass - 1) / $this->totalPass;
201  
202 $this->percent = floor($percent * 100);
203 $this->lastOutput = $currentTime;
204 $this->currentSize = (int) $currentSize;
205 $this->currentTime = $currentDuration;
206  
207 return $this->getProgressInfo();
208 }
209  
210 /**
211 *
212 * @param string $rawDuration in the format 00:00:00.00
213 * @return number
214 */
215 private function convertDuration($rawDuration)
216 {
217 $ar = array_reverse(explode(":", $rawDuration));
218 $duration = floatval($ar[0]);
219 if (!empty($ar[1])) {
220 $duration += intval($ar[1]) * 60;
221 }
222 if (!empty($ar[2])) {
223 $duration += intval($ar[2]) * 60 * 60;
224 }
225  
226 return $duration;
227 }
228  
229 /**
230 * @return array
231 */
232 private function getProgressInfo()
233 {
234 if ($this->remaining === null) {
235 return null;
236 }
237  
238 return array(
239 'percent' => $this->percent,
240 'remaining' => $this->remaining,
241 'rate' => $this->rate
242 );
243 }
244  
245 private function initialize()
246 {
247 try {
248 $format = $this->ffprobe->format($this->pathfile);
249 } catch (RuntimeException $e) {
250 return;
251 }
252  
253 if (false === $format->has('size') || false === $format->has('duration')) {
254 return;
255 }
256  
257 $this->totalSize = $format->get('size') / 1024;
258 $this->duration = $format->get('duration');
259  
260 $this->initialized = true;
261 }
262 }