Location: PHPKode > scripts > Snapshot > snapshot/snapshot.class.php
<?php
/***************************************************************
 * vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker:
 *
 *
 * PHP versions 5
 *
 * --LICENSE NOTICE--
 * This source file is subject to version 3.01 of the PHP license
 * that is available through the world-wide-web at the following URI:
 * http://www.php.net/license/3_01.txt.  If you did not receive a copy of
 * the PHP License and are unable to obtain it through the web, please
 * send a note to hide@address.com so we can mail you a copy immediately.
 * --LICENSE NOTICE--
 ***************************************************************
 * $File: snapshot.class.php $
 * $Author: mschulz $ - $Date: 2009-06-08 23:35:27 +0100 (Mo, 08 Juni 2009) $
 * $HeadURL: http://tbox.markoschulz.intern/php-001/class/snapshot.class.php $ - $Revision: 6 $
 * $Id: snapshot.class.php 6 2009-06-08 23:35:27Z mschulz $
 * $Description: Class to extract an image from a video file. $
 * $Copyright: (c) 2009 Marko Schulz $
 ***************************************************************/

/**
 * {{{ @example
 *
 * <code>
 *
 * // Define class settings
 * $cfg['snapshot'] = array(
 *  	'program' => '/usr/bin/mplayer',
 *  	'outdir' => '/tmp',
 *  	'progressive' => False,
 *  	'baseline' => True,
 *  	'optimize' => 100,
 *  	'smooth' => 0,
 *  	'quality' => 90,
 *  	'frames' => 19,
 *  	'delete' => False
 * );
 * 
 * // Path to the input file
 * (string) $file = "argonnerwald.flv";
 * 
 * // Load the Snapshot class
 * include_once( 'snapshot.class.php' );
 * 
 * try {
 * 
 *  	// Create the $img object
 *  	(object) $img = new Snapshot( $cfg['snapshot'] );
 * 
 *  	// Extract a jpeg image from defined video file
 *  	if ( $img->extract( $file ) ) {
 *  		if ( is_file($img->getOutfile()) ) {
 *  			// If you have set the parameter delete to Fale, you have
 *  			// to delete the extracted file manually with the remove() method.
 *  			echo $file." was successfuly extracted to <a href=\"file://".$img->getOutfile()."\">".$img->getOutfile()."</a><br/>\n";
 *  		} else {
 *  			echo "Sorry, but I can't find any output file!";
 *  		}
 *  	} else {
 *  		echo "Can't extract an image from the movie [".$file."]!";
 *  	}
 * 
 *  	// You also can stream the image (send image header)
 *  	// if you set the second parameter to True
 *  	//if ( !$img->extract( $file, True ) ) {
 *  	//	echo "Can't extract ".$file;
 *  	//}
 * 
 *  	// You can remove the outfile manullay if $delete is False
 *  	//if ( $cfg['snapshot']['delete'] === False ) {
 *  	//	if ( !$img->remove($img->getOutfile()) )
 *  	//		die( "Can't delete the output file [".$img->getOutfile()."]!" );
 *  	//}
 * 
 * } catch ( Exception $error ) {
 *  	echo "Error: ".$error->getMessage()."; on line ".$error->getLine()." in ".$error->getFile()."\n";
 * }
 *
 * </code>
 *
 * }}}
 */



/**
 * The class provides methods to extract an image from a video file.
 *
 * @category   Video
 * @author     Marko Schulz
 * @copyright  2009 tuxnet24.de
 * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
 * @version    File: $Revision: 6 $
 */

class Snapshot {


	/**
	 * Specify the directory to save the JPEG files.
	 * 
	 * @var string
	 * @access protected
	 * @see $this->outdir
	 */
	protected $outdir = "/tmp";


	/**
	 * The image quality factor <0-100>.
	 * 
	 * @var integer
	 * @access protected
	 * @see $this->quality
	 */
	protected $quality = 75;


	/**
	 * The image smooth factor <0-100>.
	 * 
	 * @var integer
	 * @access protected
	 * @see $this->smooth
	 */
	protected $smooth = 0;


	/**
	 * The image optimization factor <0-100>.
	 * 
	 * @var integer
	 * @access protected
	 * @see $this->optimize
	 */
	protected $optimize = 100;


	/**
	 * Specify use of baseline or not.
	 * 
	 * @var bool
	 * @access protected
	 * @see $this->baseline
	 */
	protected $baseline = True;


	/**
	 * Specify standard or progressive JPEG.
	 * 
	 * @var bool
	 * @access protected
	 * @see $this->progressive
	 */
	protected $progressive = False;


	/**
	 * Path to the mplayer binary
	 *
	 * @var string
	 * @access protected
	 * @see $this->program
	 */
	protected $program = "/usr/bin/mplayer";


	/**
	 * Should the converted file deleted
	 *
	 * @var bool
	 * @access protected
	 * @see $this->delete
	 */
	protected $delete = True;


	/**
	 * The video output driver
	 *
	 * @var string
	 * @access protected
	 * @see $this->driver
	 */
	protected $driver = "jpeg";


	/**
	 * The desired frame where an image should be created >=1
	 *
	 * @var integer
	 * @access protected
	 * @see $this->frames
	 */
	protected $frames = 1;


	/**
	 * All exeption messages
	 *
	 * @var array
	 * @static
	 * @access protected
	 * @see self::$ERROR[]
	 */
	protected static $ERROR = array(
		'NOFILE' => "No input file defined!",
		'NODELETE' => "Can't remove temporary file [%s]",
		'NOREMOVE' => "Can't remove the output file [%s]!"
	);


	/**
	 * This is the class constructor
	 * 
	 * @access public
	 * @param array $args
	 * @return void
	 * @use $this->__construct()
	 */
	public function __construct ( array $args = array() ) {


		if ( is_array($args) ) {
			foreach ( $args as $keys => $value )
				$this->setVar( $keys, $value );
		}

	}


	/**
	 * This is the class destructor
	 * 
	 * @access public
	 * @return void
	 * @use $this->__destruct()
	 */
	public function __destruct () {

		if ( $this->delete && isset($this->outfile) ) {
			if ( !$this->remove( $this->outfile ) ) // Remove extracted file
				throw new Exception( $this->message( 'NOREMOVE', $this->outfile ) );
		}

	}


	/**
	 * This method return the value of the defined variable
	 *
	 * @access public
	 * @param string $keys
	 * @return mixed
	 * @use $this->getVar()
	 */
	public function getVar( $keys ) {

		if ( isset($this->$keys) )
			return $this->$keys;

	}


	/**
	 * This method set the value of the defined variable
	 *
	 * @access public
	 * @param string $keys
	 * @param string $value
	 * @return void
	 * @use $this->setVar()
	 */
	public function setVar ( $keys, $value ) {

		if ( isset($keys) ) {
			switch ($keys) {
				case "outdir":
					if ( self::isDir( $value, True ) === True )
						$this->$keys = $value;
				break;
				case "program":
					if ( self::isBin( $value ) === True )
						$this->$keys = $value;
				break;
				case ( $keys == "quality" || $keys == "smooth" || $keys == "optimize" ):
					if ( self::in_range( $value ) === True )
						$this->$keys = $value;
				break;
				case ( $keys == "baseline" || $keys == "progressive" || $keys == "delete" ):
					if ( is_bool($value) )
						$this->$keys = $value;
				break;
				case "frames":
					if ( self::isInt($value) && $value > 0 )
						$this->$keys = $value;
				break;
			}
		}

	}


	/**
	 * This method call the conversion
	 *
	 * @access public
	 * @param string $input path to input file
	 * @param bool $stream true|false
	 * @return void
	 * @use $this->extract()
	 */
	public function extract ( $input, $stream = False ) {

		if ( !is_bool($stream) ) return False;

		if ( !isset( $input ) || !$this->isFile( $input ) )
			throw new Exception( $this->message( 'NOFILE', $input ) );
		else {
			if ( $this->execute( $input, $stream ) ) return True;
			else return False;
		}

	}


	/**
	 * This method download/stream the extracted file
	 *
	 * @access public
	 * @param string &$file path to extracted file
	 * @return void
	 * @use $this->stream()
	 */
	public function stream ( &$file ) {

		header( "Content-Description: File Transfer\r\n" );
		header( "Content-Type: image/jpeg\r\n" );
		header( "Content-Disposition: ".(!strpos($_SERVER['HTTP_USER_AGENT'],"MSIE 5.5")?"inline; ":"")."filename=".basename( $file )."\r\n" );
		header( "Content-Length: ".filesize( $file )."\r\n" );
		header( "Content-Transfer-Encoding: Binary\n" );
		header( "Pragma: no-cache\r\n" );
		header( "Connection: Close\r\n\r\n" );
		readfile( $file );

	}


	/**
	 * This method return the name and path of the output file
	 *
	 * @access public
	 * @return string
	 * @use $this->getOutfile()
	 */
	public function getOutfile() {

		return self::getVar( 'outfile' );

	}


	/**
	 * This method exec the conversion
	 *
	 * @access protected
	 * @param string $infile path to input file
	 * @param bool $stream should be the output file send to HTTP header
	 * @return bool
	 * @use $this->execute()
	 */
	protected function execute ( &$infile, $stream ) {

		// Execute the mplayer to extract an image from video file
		@/**/exec( $this->program." -nosound "
								."-frames ".$this->frames
								." -vo ".$this->driver
								.":".($this->progressive ? 'progressive' : 'noprogressive')
								.":".($this->baseline ? 'baseline' : 'nobaseline')
								.":optimize=".$this->optimize
								.":smooth=".$this->smooth
								.":quality=".$this->quality
								.":outdir=".$this->outdir." ".$infile." >/dev/null 2>&1", $out = array(), $return );


		// Get a list of all created temporary output files.
		(array) $tmpfiles = self::getFiles( $this->outdir );

		// Get the output file, defined by the frame number.
		$this->outfile = self::setOutfile( $tmpfiles );

		if ( $return !== 0 || !self::isFile($this->outfile) ) return False;
		else {
			if ( $stream ) $this->stream( $this->outfile );
			return True;
		}

	}


	/**
	 * This method get the right output file and delete all others
	 *
	 * @access protected
	 * @param array $filelist list of all extracted files
	 * @return string
	 * @use $this->setOutfile()
	 */
	protected function setOutfile ( $filelist ) {

		// Loop the list of all temporary extracted files
		foreach ( $filelist as $file ) {
			// Get the extracted file with the right frame number
			if ( preg_match( '/^(.*0+'.$this->frames.'\.jpg)$/i', $file, $result ) ) {
				$img = $result[1];
			} else {
				// Delete all other temporary extracted files
				if ( !@/**/unlink($file) )
					throw new Exception( $this->message( 'NODELETE', $file ) );
			}
		}

		return $img;

	}


	/**
	 * This method get all extracted file as array
	 *
	 * @access protected
	 * @param string $dir path to output directory
	 * @return array
	 * @use $this->getFiles()
	 */
	protected function getFiles ( $dir ) {

		(array) $images = array();

		if ( is_dir($dir) ) {
			if ( $dh = opendir($dir) ) {
				while ( ($file = readdir($dh) ) !== false ) {
					if ( preg_match( '/^(0+[0-9]{1,}\.jpg)$/i', $file, $result ) ) {
						array_push( $images, $dir."/".$file );
					}
				}
				closedir($dh);
			}
		}

		return $images;

	}


	/**
	 * This method exec a directory check
	 *
	 * @access protected
	 * @param string &$file path to file
	 * @param bool $writable writable check (default: False)
	 * @return bool
	 * @use $this->isDir()
	 */
	protected function isDir( &$file,  $writable = False ) {

		// clear the status chache
		clearstatcache();

		if ( is_dir($file) && ( $writable ? is_writable($file) : is_readable($file) ) )
			return True;
		else
			return False;

	}


	/**
	 * This method exec a file check
	 *
	 * @access protected
	 * @param string &$file path to file
	 * @param bool $writable writable check (default: False)
	 * @return bool
	 * @use $this->isFile()
	 */
	protected function isFile( &$file,  $writable = False ) {

		// clear the status chache
		clearstatcache();

		if ( is_file($file) && ( $writable ? is_writable($file) : is_readable($file) ) )
			return True;
		else
			return False;

	}


	/**
	 * This method check if the defined file is executable
	 *
	 * @access protected
	 * @param string &$file path to file
	 * @return bool
	 * @use $this->isBin()
	 */
	protected function isBin( &$file ) {

		// clear the status chache
		clearstatcache();

		if ( is_file($file) && is_executable($file) )
			return True;
		else
			return False;

	}


	/**
	 * This method check if variable is an integer
	 *
	 * @access protected
	 * @param string &$number number to check
	 * @return bool
	 * @use $this->isInt()
	 */
	protected function isInt( &$number ) {

		return ((string) $number) === ((string)(int) $number);

	}


	/**
	 * This method check if variable is a definedd range
	 *
	 * @access protected
	 * @param integer &$var number to check
	 * @param integer $start begin of range
	 * @param integer $end end of range
	 * @return bool
	 * @use $this->in_range()
	 */
	protected function in_range( &$var, $start = 0, $end = 100 ) {

		if ( $end <= $start ) return False;
		if ( self::isInt( $var ) && in_array( $var, range( $start, $end ) ) )
			return True;
		else
			return False;

	}


	/**
	 * This method remove the defined file
	 *
	 * @access private
	 * @param string &$file path to file
	 * @return bool
	 * @use $this->remove()
	 */
	public function remove ( &$file ) {

		return @/**/unlink( $file );

	}


	/**
	 * Return the right exception message
	 *
	 * @access private
	 * @param string $err error keyword
	 * @param string $which to replaced string
	 * @return string
	 * @use $this->message()
	 */
	private function message( $err, $which = Null ) {

		// Replace the %s placeholder with $which in ERROR array.
		(string) $except = str_replace( '%s', $which, self::$ERROR[$err] );
		return $except;

	}


}

//***************************************************************
// EOF
?>
Return current item: Snapshot