Просмотр файла vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Format/ProgressListener/AbstractProgressListener.php

Размер файла: 6Kb
  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 int */
  25. private $duration;
  26.  
  27. /** @var int */
  28. private $totalSize;
  29.  
  30. /** @var int */
  31. private $currentSize;
  32.  
  33. /** @var int */
  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 bool */
  46. private $initialized = false;
  47.  
  48. /** @var int */
  49. private $currentPass;
  50.  
  51. /** @var int */
  52. private $totalPass;
  53.  
  54. /**
  55. * Transcoding rate in kb/s
  56. *
  57. * @var int
  58. */
  59. private $rate;
  60.  
  61. /**
  62. * Percentage of transcoding progress (0 - 100)
  63. *
  64. * @var int
  65. */
  66. private $percent = 0;
  67.  
  68. /**
  69. * Time remaining (seconds)
  70. *
  71. * @var int
  72. */
  73. private $remaining = null;
  74.  
  75. /**
  76. * @param FFProbe $ffprobe
  77. * @param string $pathfile
  78. * @param int $currentPass The current pass number
  79. * @param int $totalPass The total number of passes
  80. * @param int $duration
  81. */
  82. public function __construct(FFProbe $ffprobe, $pathfile, $currentPass, $totalPass, $duration = 0)
  83. {
  84. $this->ffprobe = $ffprobe;
  85. $this->pathfile = $pathfile;
  86. $this->currentPass = $currentPass;
  87. $this->totalPass = $totalPass;
  88. $this->duration = $duration;
  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 int
  109. */
  110. public function getCurrentPass()
  111. {
  112. return $this->currentPass;
  113. }
  114.  
  115. /**
  116. * @return int
  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->duration = (int) $this->duration > 0 ? $this->duration : $format->get('duration');
  258. $this->totalSize = $format->get('size') / 1024 * ($this->duration / $format->get('duration'));
  259. $this->initialized = true;
  260. }
  261. }