PHP Classes

File: src/PHPVideoToolkit/FfmpegParserAbstract.php

Recommend this page to a friend!
  Classes of Oliver Lillie   PHP Video Toolkit   src/PHPVideoToolkit/FfmpegParserAbstract.php   Download  
File: src/PHPVideoToolkit/FfmpegParserAbstract.php
Role: Class source
Content type: text/plain
Description: Class source
Class: PHP Video Toolkit
Manipulate and convert videos with ffmpeg program
Author: By
Last change: Update FfmpegParserAbstract.php

Should be $data_type_matches[1][0]
updated exception types thrown

Signed-off-by: Oliver Lillie <buggedcom@gmail.com>
updated class documentation. Added various exception changes where required.
fixed bug in extract data from media. updated data returned from various probes to contain the read at date to determine if the cache is stale or not
added from-cache keys to data being returned from parser functions
fixed small issue of whitespace
updated version in source
Date: 1 year ago
Size: 37,215 bytes
 

Contents

Class file image Download
<?php /** * This file is part of the PHP Video Toolkit v2 package. * * @author Oliver Lillie (aka buggedcom) <publicmail@buggedcom.co.uk> * @license Dual licensed under MIT and GPLv2 * @copyright Copyright (c) 2008-2014 Oliver Lillie <http://www.buggedcom.co.uk> * @package PHPVideoToolkit V2 * @version 2.1.7-beta * @uses ffmpeg http://ffmpeg.sourceforge.net/ */ namespace PHPVideoToolkit; /** * Abstract class based upon Parser to server as a base class for creating FFmpeg parser classes from differing sources. * * @author Oliver Lillie */ abstract class FfmpegParserAbstract extends Parser { /** * Returns the raw codec data. * * @access public * @author Oliver Lillie * @param boolean $read_from_cache If true and the data exists within a cache then that data is used. If false * then the data is re-read from ffmpeg. * @return string Returns the raw buffer data from ffmpeg. */ abstract function getRawCodecData($read_from_cache=true); /** * Returns the raw filters data. * * @access public * @author Oliver Lillie * @param boolean $read_from_cache If true and the data exists within a cache then that data is used. If false * then the data is re-read from ffmpeg. * @return string Returns the raw buffer data from ffmpeg. */ abstract function getRawBitstreamFiltersData($read_from_cache=true); /** * Returns the raw filters data. * * @access public * @author Oliver Lillie * @param boolean $read_from_cache If true and the data exists within a cache then that data is used. If false * then the data is re-read from ffmpeg. * @return string Returns the raw buffer data from ffmpeg. */ abstract function getRawFiltersData($read_from_cache=true); /** * Returns the raw protocols data. * * @access public * @author Oliver Lillie * @param boolean $read_from_cache If true and the data exists within a cache then that data is used. If false * then the data is re-read from ffmpeg. * @return string Returns the raw buffer data from ffmpeg. */ abstract function getRawProtocolsData($read_from_cache=true); /** * Returns the raw data returned from ffmpeg about the available supported pixel formats. * * @access public * @author Oliver Lillie * @param boolean $read_from_cache If true and the data exists within a cache then that data is used. If false * then the data is re-read from ffmpeg. * @return string Returns the raw buffer data from ffmpeg. * @throws PHPVideoToolkit\FfmpegProcessException If the call to ffmpeg encounters an error. */ public function getRawPixelFormatsData($read_from_cache=true) { $cache_key = 'ffmpeg_parser/raw_pixel_formats_data'; if($read_from_cache === true && ($data = $this->_cacheGet($cache_key))) { return $data; } $exec = new FfmpegProcess('ffmpeg', $this->_config); $data = $exec->addCommand('-pix_fmt', 'list') ->addCommand('-pix_fmts') ->execute() ->getBuffer(); // check the process for any errors. if($exec->hasError() === true) { throw new FfmpegProcessException('An error was encountered when attempting to read the pixel format data. FFmpeg reported: '.$exec->getLastLine(), null, $exec); } $this->_cacheSet($cache_key, $data); return $data; } /** * Returns the raw data returned from ffmpeg help command. * * @access public * @author Oliver Lillie * @param boolean $read_from_cache If true and the data exists within a cache then that data is used. If false * then the data is re-read from ffmpeg. * @return string Returns the raw buffer data from ffmpeg. * @throws PHPVideoToolkit\FfmpegProcessException If the call to ffmpeg encounters an error. */ public function getRawCommandsData($read_from_cache=true) { $cache_key = 'ffmpeg_parser/raw_commands_data'; if($read_from_cache === true && ($data = $this->_cacheGet($cache_key))) { return $data; } $exec = new FfmpegProcess('ffmpeg', $this->_config); $data = $exec->addCommand('-h', 'long') ->execute() ->getBuffer(); // check the process for any errors. if($exec->hasError() === true) { throw new FfmpegProcessException('An error was encountered when attempting to read FFmpegs\' available commands. FFmpeg reported: '.$exec->getLastLine(), null, $exec); } $this->_cacheSet($cache_key, $data); return $data; } /** * Returns the available filters in their processed easy to use format. * * @access public * @author Oliver Lillie * @param boolean $read_from_cache If true and the data exists within a cache then that data is used. If false * then the data is re-read from ffmpeg. * @return array Returns an array of data about the current ffmpeg binary. */ public function getFfmpegData($read_from_cache=true) { $cache_key = 'ffmpeg_parser/ffmpeg_data'; if($read_from_cache === true && ($data = $this->_cacheGet($cache_key))) { return $data; } // get the raw format information $raw_data = $this->getRawFfmpegData($read_from_cache); // then match out the relevant data, clean and process. $data = array( 'from-cache' => true, 'read-at' => time(), 'binary' => array( 'configuration' => array(), 'vhook-support' => false, ), 'compiler' => array( 'gcc' => null, 'build_date' => null, ), ); if(preg_match_all('/--[a-zA-Z0-9\-]+/', $raw_data, $config_flags) > 0) { $data['binary']['configuration'] = $config_flags[0]; $data['binary']['vhook-support'] = in_array('--enable-vhook', $config_flags[0]) === true || in_array('--disable-vhook', $config_flags[0]) === false; if(preg_match('/built on (.*)(?:, gcc:| with) (.*)/', $raw_data, $conf) > 0) // { $data['compiler']['gcc'] = $conf[2]; //$data['compiler']['build_date'] = $conf[1]; $data['compiler']['build_date'] = strtotime($conf[1]); } } $this->_cacheSet($cache_key, $data); $data['from-cache'] = false; return $data; } /** * Returns the version of ffmpeg if it is found and available. * * @access public * @author Jorrit Schippers * @param boolean $read_from_cache If true and the data exists within a cache then that data is used. If false * then the data is re-read from ffmpeg. * @return array Returns an array with the following keys; build, version. Note, depending on your version of ffmpeg * either one or both of these keys will container values. * @throws PHPVideoToolkit\FfmpegProcessException If a version is not found in the basic information then we call ffmpeg -version * to get the version information. If that call encounters an error this exception is thrown. */ public function getVersion($read_from_cache=true) { $cache_key = 'ffmpeg_parser/ffmpeg_version'; if($read_from_cache === true && ($data = $this->_cacheGet($cache_key))) { return $data; } $version = null; $build = null; $raw_data = $this->getRawFfmpegData($read_from_cache); // Search for SVN string // FFmpeg version SVN-r20438, Copyright (c) 2000-2009 Fabrice Bellard, et al. if($build === null && preg_match('/(?:ffmpeg|avconv) version SVN-r([0-9.]*)/i', $raw_data, $matches) > 0) { $build = $matches[1]; } // // Some OSX versions are built from a very early CVS // // I do not know what to do with this version- using 1 for now // if(preg_match('/(?:ffmpeg|avconv) version(.*)CVS.*Mac OSX universal/msUi', $raw_data, $matches) > 0) // { // $build = $matches[1]; // } // Search for git string // FFmpeg version git-N-29240-gefb5fa7, Copyright (c) 2000-2011 the FFmpeg developers. // ffmpeg version N-31145-g59bd0fe, Copyright (c) 2000-2011 the FFmpeg developers if($build === null && preg_match('/(?:ffmpeg|avconv) version.*N-([0-9.]*)/i', $raw_data, $matches) > 0) { // Versions above this seem to be ok if($matches[1] >= 29240) { $build = $matches[1]; } } // Do we have a release? // ffmpeg version 0.4.9-pre1, build 4736, Copyright (c) 2000-2004 Fabrice Bellard if($build === null && preg_match('/(?:ffmpeg|avconv) version ([^,]+) build ([0-9]+),/i', $raw_data, $matches) > 0) { $version = $matches[1]; $build = $matches[2]; } // Do we have a build version? // ffmpeg version 0.4.9-pre1, build 4736, Copyright (c) 2000-2004 Fabrice Bellard if($build === null && preg_match('/(?:ffmpeg|avconv) version.*, build ([0-9]*)/i', $raw_data, $matches) > 0) { $build = $matches[1]; } // ffmpeg version 1.1.2 Copyright (c) 2000-2013 the FFmpeg developers if($version === null && preg_match('/ffmpeg version ([^\s]+) Copyright/i', $raw_data, $matches) > 0) { $version = $matches[1]; } // avconv version 0.8.9-4:0.8.9-0ubuntu0.12.04.1, Copyright (c) 2000-2013 the Libav developers built on Nov 9 2013 19:08:00 with gcc 4.6.3 if($version === null && preg_match('/avconv version\s+([^:]+):/msUi', $raw_data, $matches) > 0) { $version = $matches[1]; } // get the version from -version if($version === null) { $exec = new FfmpegProcess('ffmpeg', $this->_config); $data = $exec->addCommand('-version') ->execute() ->getBuffer(); // check the process for any errors. if($exec->hasError() === true) { throw new FfmpegProcessException('An error was encountered when attempting to read FFmpegs\' version. FFmpeg reported: '.$exec->getLastLine(), null, $exec); } if(preg_match('/FFmpeg version ([0-9\.]+)/i', $data, $matches) > 0) { $version = $matches[1]; } else if(preg_match('/FFmpeg ([0-9]+\.[0-9]+\.[0-9]+)/i', $data, $matches) > 0) { $version = $matches[1]; } } // if both version and build are not available throw a new exception to get the user to provide their ffmpeg data to github so we can start building up different formats of ffmpeg output. if($version === null && $build === null) { throw new FfmpegProcessException('Unable to determine your FFmpeg version or build. Please create an issue at the github repository for PHPVideoToolkit 2; https://github.com/buggedcom/phpvideotoolkit-v2/issues. Please add the following data to the ticket:<br /> <br /> <code>'.$this->getRawFfmpegData($read_from_cache).'</code>'); } $data = array( 'build' => $build, 'version' => $version, 'from-cache' => true, 'read-at' => time(), ); $this->_cacheSet($cache_key, $data); $data['from-cache'] = false; return $data; } /** * Returns the information about ffmpeg itself. * * @access public * @author Oliver Lillie * @param boolean $read_from_cache If true and the data exists within a cache then that data is used. If false * then the data is re-read from ffmpeg. * @return array Returns all the information available about ffmpeg in a single array. */ public function getInformation($read_from_cache=true) { $cache_key = 'ffmpeg_parser/parsed_information'; if($read_from_cache === true && ($data = $this->_cacheGet($cache_key))) { return $data; } $data = $this->getFfmpegData($read_from_cache); $data['version'] = $this->getVersion($read_from_cache); $data['has-ffmpeg-php-support'] = $this->hasFfmpegPhpSupport($read_from_cache); $data['formats'] = $this->getFormats($read_from_cache); $data['codecs'] = $this->getCodecs(null, $read_from_cache); $data['protocols'] = $this->getProtocols($read_from_cache); $data['pixel_formats'] = $this->getPixelFormats($read_from_cache); //$data['commands'] = $this->getCommands(); $this->_cacheSet($cache_key, $data); return $data; } /** * Determines if we are able to utilise FFmpeg-PHP either through a loaded * module or one of our emulators. * * @access public * @author Oliver Lillie * @param boolean $read_from_cache * @return mixed Returns false (boolean) on failure otherwise returns module or emulated. */ public function hasFfmpegPhpSupport($read_from_cache=true) { $cache_key = 'ffmpeg_parser/ffmpeg_php_available'; if($read_from_cache === true && ($data = $this->_cacheGet($cache_key, -1)) !== -1) { return $data; } // check to see if the module is loaded. if(extension_loaded('ffmpeg') === true) { $data = 'module'; $this->_cacheSet($cache_key, $data); return $data; } // check to see if an adapter exists $base_dir = dirname(dirname(__FILE__)); if( is_file($base_dir.'/emulators/ffmpeg-php/ffmpeg_movie.php') === true && is_file($base_dir.'/emulators/ffmpeg-php/ffmpeg_frame.php') === true && is_file($base_dir.'/emulators/ffmpeg-php/ffmpeg_animated_gif.php') === true) { $data = 'emulated'; $this->_cacheSet($cache_key, $data); return $data; } $data = false; $this->_cacheSet($cache_key, $data); return $data; } /** * Returns the available formats in a processed easy to use format. * * @access public * @author Oliver Lillie * @param boolean $read_from_cache If true and the data exists within a cache then that data is used. If false * then the data is re-read from ffmpeg. * @return array Returns an array of formats and related information about each format. */ public function getFormats($read_from_cache=true) { $cache_key = 'ffmpeg_parser/parsed_formats'; if($read_from_cache === true && ($data = $this->_cacheGet($cache_key))) { return $data; } // get the raw format information $raw_data = $this->getRawFormatData(); // then match out the relevant data, clean and process. $data = array(); if(preg_match_all('/ (DE|D|E) (.*) {1,} (.*)/', $raw_data, $format_matches) > 0) { foreach($format_matches[0] as $key=>$match) { $format_code = strtolower(trim($format_matches[2][$key])); $mux_and_demux = $format_matches[1][$key] === 'DE'; $data[$format_code] = array( 'mux' => $mux_and_demux === true || $format_matches[1][$key] === 'E', 'demux' => $mux_and_demux === true || $format_matches[1][$key] === 'D', 'fullname' => $format_matches[3][$key], 'extensions'=> Formats::toExtensions($format_code), ); } } $this->_cacheSet($cache_key, $data); return $data; } /** * Returns the available codecs in their processed easy to use format. * * @access public * @author Oliver Lillie * @param mixed $component If not set or set to null then all the audio, video and subtitle codecs * are returned, otherwise if set to 'audio', 'video', or 'subtitle' then just the related data * is returned. * @param boolean $read_from_cache If true and the data exists within a cache then that data is used. If false * then the data is re-read from ffmpeg. * @return array Returns an array of formats and related information about each codec. * @throws \InvalidArgumentException If the $component argument is invalid. */ public function getCodecs($component=null, $read_from_cache=true) { if(in_array($component, array('video', 'audio', 'subtitle', null)) === false) { throw new \InvalidArgumentException('Unrecognised codec component specified.'); } $cache_key = 'ffmpeg_parser/parsed_codecs'; if($read_from_cache === true && ($data = $this->_cacheGet($cache_key))) { return $component === null ? $data : (isset($data[$component]) === true ? $data[$component] : false); } // get the raw format information $raw_data = $this->getRawCodecData(); // then match out the relevant data, clean and process. $data = array( 'video' => array(), 'audio' => array(), 'subtitle' => array() ); if(preg_match_all('/ ((?:[DEVAST ]{6})|(?:[DEVASTFB ]{8})|(?:[DEVASIL\.]{6})) ([A-Za-z0-9\_]+) (.+)/', $raw_data, $codec_matches) > 0) { // FFMPEG 0.12+ // D..... = Decoding supported // .E.... = Encoding supported // ..V... = Video codec // ..A... = Audio codec // ..S... = Subtitle codec // ...I.. = Intra frame-only codec // ....L. = Lossy compression // .....S = Lossless compression // FFMPEG OTHER // D..... = Decoding supported // .E.... = Encoding supported // ..V... = Video codec // ..A... = Audio codec // ..S... = Subtitle codec // ...S.. = Supports draw_horiz_band // ....D. = Supports direct rendering method 1 // .....T = Supports weird frame truncation // TODO, seperate out into distinct functions foreach ($codec_matches[3] as $key => $fullname) { $options = preg_split('//', $codec_matches[1][$key], -1, PREG_SPLIT_NO_EMPTY); if(empty($options) === false) { $id = trim($codec_matches[2][$key]); $type = $options[2] === 'V' ? 'video' : ($options[2] === 'A' ? 'audio' : 'subtitle'); switch ($options[2]) { // video case 'V' : $data[$type][$id] = array( 'encode' => isset($options[1]) === true && $options[1] === 'E', 'decode' => isset($options[0]) === true && $options[0] === 'D', 'draw_horizontal_band' => isset($options[3]) === true && $options[3] === 'S', 'direct_rendering_method_1' => isset($options[4]) === true && $options[4] === 'D', 'weird_frame_truncation' => isset($options[5]) === true && $options[5] === 'T', 'fullname' => trim($fullname), ); break; // audio and subtitles. case 'A' : case 'S' : $data[$type][$id] = array( 'encode' => isset($options[1]) === true && $options[1] === 'E', 'decode' => isset($options[0]) === true && $options[0] === 'D', 'fullname' => trim($fullname), ); break; } } } } $this->_cacheSet($cache_key, $data); // are we to only return a specific component of the data? if($component !== null) { return $data[$component]; } return $data; } /** * Returns the available bitstream filters in their processed easy to use format. * * @access public * @author Oliver Lillie * @param boolean $read_from_cache If true and the data exists within a cache then that data is used. If false * then the data is re-read from ffmpeg. * @return array Returns an array of bitstream filter strings. */ public function getBitstreamFilters($read_from_cache=true) { $cache_key = 'ffmpeg_parser/parsed_bitstream_filters'; if($read_from_cache === true && ($data = $this->_cacheGet($cache_key))) { return $data; } // get the raw format information $raw_data = $this->getRawBitstreamFiltersData(); // then match out the relevant data, clean and process. $data = array(); $locate = 'Bitstream filters:'; if(empty($raw_data) === false && ($pos = strpos($raw_data, $locate)) !== false) { $raw_data = trim(substr($raw_data, $pos + strlen($locate))); $data = explode("\n", $raw_data); array_walk($data, function(&$filter, $key) { $filter = trim($filter); }); } $this->_cacheSet($cache_key, $data); return $data; } /** * Returns the available filters in their processed easy to use format. * * @access public * @author Oliver Lillie * @param boolean $just_filter_names If true then just the list of available filters will be returned. * otherwise all the available data will be returned. * @param boolean $read_from_cache If true and the data exists within a cache then that data is used. If false * then the data is re-read from ffmpeg. * @return array Returns an array of available filters. If $just_filter_names is true, then just the filter names * are returned, otherwise the array is returned with the filter names as the key and the value as another array containing * information about the filter. */ public function getFilters($just_filter_names=true, $read_from_cache=true) { $component = $just_filter_names === true ? 'filters' : 'verbose'; $cache_key = 'ffmpeg_parser/parsed_filters'; if($read_from_cache === true && ($data = $this->_cacheGet($cache_key))) { return $component === 'verbose' ? $data : array_keys($data); } // get the raw format information $raw_data = $this->getRawFiltersData(); // then match out the relevant data, clean and process. $data = array(); $locate = 'Filters:'; if(empty($raw_data) === false && ($pos = strpos($raw_data, $locate)) !== false) { $raw_data = trim(substr($raw_data, $pos + strlen($locate))); if(preg_match_all('/([a-z]+)\s+([\|VA]{1,2})\->([\|VA]{1,2})\s+(.*)/i', $raw_data, $matches) > 0) { foreach ($matches[1] as $key => $filter) { $from = $matches[2][$key]; $from_name = $from === 'V' ? 'video1' : ($from === 'VV' ? 'video2' : ($from === 'A' ? 'audio1' : ($from === 'AA' ? 'audio2' : ($from === '|' ? 'pipe' : null)))); $to = $matches[2][$key]; $to_name = $to === 'V' ? 'video1' : ($to === 'VV' ? 'video2' : ($to === 'A' ? 'audio1' : ($to === 'AA' ? 'audio2' : ($to === '|' ? 'pipe' : null)))); $data[$filter] = array( 'filter' => $filter, 'description' => $matches[4][$key], 'from' => $from_name, 'to' => $to_name, ); } } } $this->_cacheSet($cache_key, $data); return $component === 'verbose' ? $data : array_keys($data); } /** * Returns the available filters in their processed easy to use format. * * @access public * @author Oliver Lillie * @param boolean $read_from_cache If true and the data exists within a cache then that data is used. If false * then the data is re-read from ffmpeg. * @return array Returns an array of available protocols and whether or not they are input or ouput protocols. */ public function getProtocols($read_from_cache=true) { $cache_key = 'ffmpeg_parser/parsed_protocols'; if($read_from_cache === true && ($data = $this->_cacheGet($cache_key))) { return $data; } // get the raw format information $raw_data = $this->getRawProtocolsData(); // then match out the relevant data, clean and process. $data = array(); if(empty($raw_data) === false) { // check to see if we have input and output settings. $input_locate = 'Input:'; if(($input_pos = strpos($raw_data, $input_locate)) !== false) { // seperate out input and output protocols $input_locate_length = strlen($input_locate); $raw_data = substr($raw_data, $input_pos+$input_locate_length); $raw_data = explode('Output:', $raw_data); // process the input $input = trim($raw_data[0]); $input = explode("\n", $input); if(empty($input) === false) { foreach($input as $protocol) { $data[$protocol] = array( 'input' => true, 'output' => false, ); } } // if the output protocols are found, process them by augmenting the existing data // or creating a new record in the data. if(isset($raw_data[1]) === true && empty($raw_data[1]) === false) { $output = trim($raw_data[1]); $output = explode("\n", $output); foreach($output as $protocol) { if(isset($data[$protocol]) === true) { $data[$protocol]['output'] = true; } else { $data[$protocol] = array( 'input' => false, 'output' => true, ); } } } } else { // this is the older version of the protocol format. $locate = 'Supported file protocols:'; if(($pos = strpos($raw_data, $locate)) !== false) { $raw_data = trim(substr($raw_data, $pos + strlen($locate))); $raw_data = explode("\n", $raw_data); array_walk($raw_data, function(&$protocol, $key) { // both input and output is assumed to be true $data[$protocol] = array( 'input' => true, 'output' => true, ); }); } } } $this->_cacheSet($cache_key, $data); return $data; } /** * Returns the available filters in their processed easy to use format. * * @access public * @author Oliver Lillie * @param boolean $read_from_cache If true and the data exists within a cache then that data is used. If false * then the data is re-read from ffmpeg. * @return array Returns an array of information about the available pixel formats. */ public function getPixelFormats($read_from_cache=true) { $cache_key = 'ffmpeg_parser/parsed_pixel_formats'; if($read_from_cache === true && ($data = $this->_cacheGet($cache_key))) { return $data; } // get the raw format information $raw_data = $this->getRawPixelFormatsData(); // then match out the relevant data, clean and process. $data = array(); if(strpos($raw_data, 'Pixel formats') === false) { // Format: // name nb_channels depth is_alpha // yuv420p 3 8 n // yuyv422 1 8 n if(preg_match_all('/(\w+)\s+(\d+)\s+(\d+)\s+(y|n)/', $raw_data, $matches, PREG_SET_ORDER) > 0) { foreach($matches as $match) { // we have to assume both encode and decode are true. $data[$match[1]] = array( 'encode' => true, 'decode' => true, 'components' => (int) $match[2], 'bpp' => (int) $match[3], 'hardware_accelerated' => null, 'paletted_format' => null, 'bitstream_format' => null, 'alpha' => $match[4] === 'y', ); } } } else { // Format: // Pixel formats: // I.... = Supported Input format for conversion // .O... = Supported Output format for conversion // ..H.. = Hardware accelerated format // ...P. = Paletted format // ....B = Bitstream format // FLAGS NAME NB_COMPONENTS BITS_PER_PIXEL // ----- // IO... yuv420p 3 12 if(preg_match_all('/(I|\.)(O|\.)(H|\.)(P|\.)(B|\.)\s+(\w+)\s+(\d+)\s+(\d+)/', $raw_data, $matches, PREG_SET_ORDER) > 0) { foreach ($matches as $match) { $data[$match[6]] = array( 'encode' => $match[1] === 'I', 'decode' => $match[2] === 'O', 'components' => (int) $match[7], 'bpp' => (int) $match[8], 'hardware_accelerated' => $match[3] === 'H', 'paletted_format' => $match[4] === 'P', 'bitstream_format' => $match[5] === 'B', 'alpha' => null, ); } } } $this->_cacheSet($cache_key, $data); return $data; } /** * Returns the available filters in their processed easy to use format. * * @access public * @author Oliver Lillie * @param boolean $read_from_cache If true and the data exists within a cache then that data is used. If false * then the data is re-read from ffmpeg. * @return array Returns the list of commands the ffmpeg can support. */ public function getCommands($read_from_cache=true) { $cache_key = 'ffmpeg_parser/parsed_commands'; if($read_from_cache === true && ($data = $this->_cacheGet($cache_key))) { return $data; } // get the raw format information $raw_data = $this->getRawCommandsData(); // then match out the relevant data, clean and process. $data = array(); if(preg_match_all('/\n-(\w+)(.*) (.*)/', $raw_data, $matches, PREG_SET_ORDER) > 0) { foreach ($matches as $key=>$match) { $data_type = null; if(preg_match_all('/(?:\s+<(int|string|binary|flags|int64|float|rational)>)/', $match[2], $data_type_matches) > 0) { $data_type = trim($data_type_matches[1][0]); } $args = trim($match[2]); $args = empty($args) === true ? array() : explode(' ', $args); $deprecated = strpos($match[3], 'deprecated') !== false; $removed = strpos($match[3], 'Removed') !== false; $data[$match[1]] = array( 'datatype' => $data_type, 'description' => $match[3], 'arguments' => $args, 'status' => $deprecated === true ? 'deprecated' : ($removed === true ? 'removed' : null), ); } } $this->_cacheSet($cache_key, $data); return $data; } }