Current File : /home/jvzmxxx/wiki1/extensions/EmbedVideo/classes/media/FFProbe.php
<?php
/**
 * EmbedVideo
 * FFProbe
 *
 * @author		Alexia E. Smith
 * @license		MIT
 * @package		EmbedVideo
 * @link		https://www.mediawiki.org/wiki/Extension:EmbedVideo
 *
 **/

namespace EmbedVideo;

class FFProbe {
	/**
	 * File Location
	 *
	 * @var		string
	 */
	private $file;

	/**
	 * Meta Data Cache
	 *
	 * @var		array
	 */
	private $metadata = null;

	/**
	 * Main Constructor
	 *
	 * @access	public
	 * @param	string	File Location on Disk
	 * @return	void
	 */
	public function __construct($file) {
		$this->file = $file;
	}

	/**
	 * Return the entire cache of meta data.
	 *
	 * @access	public
	 * @return	array	Meta Data
	 */
	public function getMetaData() {
		if (!is_array($this->metadata)) {
			$this->invokeFFProbe();
		}
		return $this->metadata;
	}

	/**
	 * Get a selected stream.  Follows ffmpeg's stream selection style.
	 *
	 * @access	public
	 * @param	string	Stream identifier
	 * Examples:
	 *		"v:0" - Select the first video stream
	 * 		"a:1" - Second audio stream
	 * 		"i:0" - First stream, whatever it is.
	 * 		"s:2" - Third subtitle
	 * 		"d:0" - First generic data stream
	 * 		"t:1" - Second attachment
	 * @return	mixed	StreamInfo object or false if does not exist.
	 */
	public function getStream($select) {
		$this->getMetaData();

		$types = [
			'v'	=> 'video',
			'a'	=> 'audio',
			'i'	=> false,
			's'	=> 'subtitle',
			'd'	=> 'data',
			't'	=> 'attachment'
		];

		if (!isset($this->metadata['streams'])) {
			return false;
		}

		list($type, $index) = explode(":", $select);
		$index = intval($index);

		$type = (isset($types[$type]) ? $types[$type] : false);

		$i = 0;
		foreach ($this->metadata['streams'] as $stream) {
			if ($type !== false && isset($stream['codec_type'])) {
				if ($index === $i && $stream['codec_type'] === $type) {
					return new StreamInfo($stream);
				}
			}
			if ($type === false || $stream['codec_type'] === $type) {
				$i++;
			}
		}
		return false;
	}

	/**
	 * Get the FormatInfo object.
	 *
	 * @access	public
	 * @return	mixed	FormatInfo object or false if does not exist.
	 */
	public function getFormat() {
		$this->getMetaData();

		if (!isset($this->metadata['format'])) {
			return false;
		}

		return new FormatInfo($this->metadata['format']);
	}

	/**
	 * Invoke ffprobe on the command line.
	 *
	 * @access	private
	 * @return	boolean	Success
	 */
	private function invokeFFProbe() {
		global $wgFFprobeLocation;

		if (!file_exists($wgFFprobeLocation)) {
			$this->metadata = [];
			return false;
		}

		$json = shell_exec(escapeshellcmd($wgFFprobeLocation.' -v quiet -print_format json -show_format -show_streams ').escapeshellarg($this->file));

		$metadata = @json_decode($json, true);

		if (is_array($metadata)) {
			$this->metadata = $metadata;
		} else {
			$this->metadata = [];
			return false;
		}
		return true;
	}
}

class StreamInfo {
	/**
	 * Stream Info
	 *
	 * @var		array
	 */
	private $info = null;

	/**
	 * Main Constructor
	 *
	 * @access	public
	 * @param	array	Stream Info from FFProbe
	 * @return	void
	 */
	public function __construct($info) {
		$this->info = $info;
	}

	/**
	 * Simple helper instead of repeating an if statement everything.
	 *
	 * @access	private
	 * @param	string	Field Name
	 * @return	void
	 */
	private function getField($field) {
		return (isset($this->info[$field]) ? $this->info[$field] : false);
	}

	/**
	 * Return the codec type.
	 *
	 * @access	public
	 * @return 	string	Codec type or false if unavailable.
	 */
	public function getType() {
		return $this->getField('codec_type');
	}

	/**
	 * Return the codec name.
	 *
	 * @access	public
	 * @return 	string	Codec name or false if unavailable.
	 */
	public function getCodecName() {
		return $this->getField('codec_name');
	}

	/**
	 * Return the codec long name.
	 *
	 * @access	public
	 * @return 	string	Codec long name or false if unavailable.
	 */
	public function getCodecLongName() {
		return $this->getField('codec_long_name');
	}

	/**
	 * Return the width of the stream.
	 *
	 * @access	public
	 * @return 	integer	Width or false if unavailable.
	 */
	public function getWidth() {
		return $this->getField('width');
	}

	/**
	 * Return the height of the stream.
	 *
	 * @access	public
	 * @return 	integer	Height or false if unavailable.
	 */
	public function getHeight() {
		return $this->getField('height');
	}

	/**
	 * Return bit depth for a video or thumbnail.
	 *
	 * @access	public
	 * @return 	integer	Bit Depth or false if unavailable.
	 */
	public function getBitDepth() {
		return $this->getField('bits_per_raw_sample');
	}

	/**
	 * Get the duration in seconds.
	 *
	 * @access	public
	 * @return 	mixed	Duration in seconds or false if unavailable.
	 */
	public function getDuration() {
		return $this->getField('duration');
	}

	/**
	 * Bit rate in bPS.
	 *
	 * @access	public
	 * @return 	mixed	Bite rate in bPS or false if unavailable.
	 */
	public function getBitRate() {
		return $this->getField('bit_rate');
	}
}

class FormatInfo {
	/**
	 * Format Info
	 *
	 * @var		array
	 */
	private $info = null;

	/**
	 * Main Constructor
	 *
	 * @access	public
	 * @param	array	Format Info from FFProbe
	 * @return	void
	 */
	public function __construct($info) {
		$this->info = $info;
	}

	/**
	 * Simple helper instead of repeating an if statement everything.
	 *
	 * @access	private
	 * @param	string	Field Name
	 * @return	void
	 */
	private function getField($field) {
		return (isset($this->info[$field]) ? $this->info[$field] : false);
	}

	/**
	 * Get the file path.
	 *
	 * @access	public
	 * @return 	mixed	File path or false if unavailable.
	 */
	public function getFilePath() {
		return $this->getField('filename');
	}

	/**
	 * Get the duration in seconds.
	 *
	 * @access	public
	 * @return 	mixed	Duration in seconds or false if unavailable.
	 */
	public function getDuration() {
		return $this->getField('duration');
	}

	/**
	 * Bit rate in bPS.
	 *
	 * @access	public
	 * @return 	mixed	Bite rate in bPS or false if unavailable.
	 */
	public function getBitRate() {
		return $this->getField('bit_rate');
	}
}