PageRenderTime 20ms CodeModel.GetById 10ms app.highlight 7ms RepoModel.GetById 1ms app.codeStats 0ms

/phpvideotoolkit/adapters/ffmpeg-php/ffmpeg_movie.php

http://phpvideotoolkit.googlecode.com/
PHP | 473 lines | 218 code | 38 blank | 217 comment | 19 complexity | f2e19dc342ae7e5bd6b6ca6a1fc9db3d MD5 | raw file
  1<?php
  2
  3	/**
  4	 * This is a pure php emulation of the PHP module FFmpeg-PHP.
  5	 * NOTE: Please note whenever possible you should use ffmpeg-php as it is much more efficient than this pure PHP emulation.
  6	 * @author Oliver Lillie (aka buggedcom) <publicmail@buggedcom.co.uk>
  7	 * @package PHPVideoToolkit
  8	 * @license BSD
  9	 * @copyright Copyright (c) 2008 Oliver Lillie <http://www.buggedcom.co.uk>
 10	 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
 11	 * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
 12	 * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
 13	 * is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be
 14	 * included in all copies or substantial portions of the Software.
 15	 *
 16	 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 17	 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 18	 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 19	 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 20	 * @uses php-reader
 21	 * 		- @link http://code.google.com/p/php-reader/
 22	 * 		- @author Sven Vollbehr <svollbehr@gmail.com>
 23	 *	  	- @license http://code.google.com/p/php-reader/wiki/License New BSD License
 24	 * @see ffmpeg-php, 
 25	 * 		- @link http://ffmpeg-php.sourceforge.net/
 26	 * 		- @author Todd Kirby.
 27	 * 		- all phpdoc documentation is lifted directly from the ffmpeg-php docs
 28	 */
 29	
 30	if(!defined('DS'))
 31	{
 32		define('DS', DIRECTORY_SEPARATOR);
 33	}
 34	
 35	class ffmpeg_movie
 36	{
 37		
 38		private $_frame_index 	= 1;
 39		private $_toolkit 		= null;
 40		private $_media_data 	= null;
 41		private $_php_reader 	= null;
 42		private $_path_to_media = null;
 43		private $_tmp_directory = null;
 44		
 45		/**
 46		 * Class Constructor
 47		 * @param string $path_to_media The path to the media file you want to use.
 48		 * @param string $persistent (not used in this class - but exists to emulate the ffmpeg-php module)
 49		 * @param string $tmp_directory The temp directory to which to work from. (This is only required by this class
 50		 * 	and not by ffmpeg-php so some minor hacking of your scripts may need to be done). (remember the trailing slash)
 51		 */
 52		function __construct($path_to_media, $persistent=false, $tmp_directory='/tmp/')
 53		{
 54// 			store the media path
 55			$this->_path_to_media = $path_to_media;
 56			$this->_tmp_directory = $tmp_directory;
 57// 			init PHPVideoToolkit class
 58			require_once dirname(dirname(dirname(__FILE__))).DS.'phpvideotoolkit.php5.php';
 59			$this->_toolkit = new PHPVideoToolkit($tmp_directory);
 60			$this->_toolkit->on_error_die = false;
 61// 			set the input
 62			$this->_toolkit->setInputFile($path_to_media);
 63			$this->_media_data = $this->_toolkit->getFileInfo();
 64// 			print_r($this->_media_data);
 65		}
 66		
 67		/**
 68		 * Access and returns the id3 information using getID3.
 69		 * @access private
 70		 * @return boolean true if the information was able to be retrieved, false if not
 71		 */
 72		private function _getPHPReader()
 73		{
 74			if($this->_php_reader === null)
 75			{
 76				$this->_php_reader = -1;
 77				$php_reader = dirname(__FILE__).DS.'php-reader'.DS.'src'.DS.'ID3v1.php';
 78				if(is_file($php_reader))
 79				{
 80					require_once $php_reader;
 81					try 
 82					{
 83						$this->_php_reader = new ID3v1($this->_path_to_media);
 84					} 
 85					catch (Exception $e) 
 86					{
 87						return false;
 88					}
 89					return true;
 90				}
 91			}
 92			return $this->_php_reader !== -1;
 93		}
 94		
 95		/**
 96		 * Return the duration of a movie or audio file in seconds.
 97		 * @access public
 98		 * @return integer
 99		 */
100		public function getDuration()
101		{
102			return $this->_media_data['duration']['seconds'];
103		}
104		
105		/**
106		 * Return the number of frames in a movie or audio file.
107		 * @access public
108		 * @return integer
109		 */
110		public function getFrameCount()
111		{
112			return $this->hasVideo() ? $this->_media_data['video']['frame_count'] : -1;
113		}
114		
115		/**
116		 * Return the frame rate of a movie in fps.
117		 * @access public
118		 * @return integer
119		 */
120		public function getFrameRate()
121		{
122			return $this->hasVideo() ? $this->_media_data['video']['frame_rate'] : -1;
123		}
124		
125		/**
126		 * Return the path and name of the movie file or audio file.
127		 * @access public
128		 * @return string
129		 */
130		public function getFilename()
131		{
132			return basename($this->_path_to_media);
133		}
134		
135		/**
136		 * Makes checks and returns the id3 element value.
137		 * @access private
138		 * @return mixed string | -1 
139		 */
140		private function _getPHPReaderElement($element)
141		{
142			if($this->hasAudio())
143			{
144				if($this->_getPHPReader() && isset($this->_php_reader->{$element}))
145				{
146					return $this->_php_reader->{$element};
147				}
148			}
149			return -1;
150		}
151		
152		/**
153		 * Return the comment field from the movie or audio file.
154		 * Returns -1 on failure.
155		 * @access public
156		 * @return mixed array | -1
157		 */
158		public function getComment()
159		{
160			return $this->_getPHPReaderElement('comment');
161		}
162		
163		/**
164		 * Return the title field from the movie or audio file.
165		 * Returns -1 on failure.
166		 * @access public
167		 * @return string
168		 */
169		public function getTitle()
170		{
171			return $this->_getPHPReaderElement('title');
172		}
173		
174		/**
175		 * Return the copyright field from the movie or audio file.
176		 * @access public
177		 * @return string
178		 */
179		public function getCopyright()
180		{
181			return $this->_getPHPReaderElement('copyright');
182		}
183		
184		/**
185		 * Return the author field from the movie or the artist ID3 field from an mp3 file.
186		 * @uses ffmpeg_movie::getArtist();
187		 * @access public
188		 * @return string
189		 */
190		public function getAuthor()
191		{
192			return $this->getArtist();
193		}
194		
195		/**
196		 * Return the artist ID3 field from an mp3 file.
197		 * @access public
198		 * @return string
199		 */
200		public function getArtist()
201		{
202			return $this->_getPHPReaderElement('artist');
203		}
204		
205		/**
206		 * Return the album ID3 field from an mp3 file.
207		 * @access public
208		 * @return string
209		 */
210		public function getAlbum()
211		{
212			return $this->_getPHPReaderElement('album');
213		}
214		
215		/**
216		 * Return the genre ID3 field from an mp3 file.
217		 * @access public
218		 * @return string
219		 */
220		public function getGenre()
221		{
222			return $this->_getPHPReaderElement('genre');
223		}
224		
225		/**
226		 * Return the track ID3 field from an mp3 file.
227		 * @access public
228		 * @return integer
229		 */
230		public function getTrackNumber()
231		{
232			return $this->_getPHPReaderElement('track');
233		}
234		
235		/**
236		 * Return the year ID3 field from an mp3 file.
237		 * @access public
238		 * @return integer
239		 */
240		public function getYear()
241		{
242			return $this->_getPHPReaderElement('year');
243		}
244		
245		/**
246		 * Return the height of the movie in pixels.
247		 * @access public
248		 * @return integer
249		 */
250		public function getFrameHeight()
251		{
252			return $this->hasVideo() && isset($this->_media_data['video']['dimensions']) ? $this->_media_data['video']['dimensions']['height'] : -1;
253		}
254		
255		/**
256		 * Return the width of the movie in pixels.
257		 * @access public
258		 * @return integer
259		 */
260		public function getFrameWidth()
261		{
262			return $this->hasVideo() && isset($this->_media_data['video']['dimensions']) ? $this->_media_data['video']['dimensions']['width'] : -1;
263		}
264		
265		/**
266		 * Return the pixel format of the movie.
267		 * @access public
268		 * @return mixed string | -1
269		 */
270		public function getPixelFormat()
271		{
272			return $this->hasVideo() ? $this->_media_data['video']['pixel_format'] : -1;
273		}
274		
275		/**
276		 * Return the pixel aspect ratio of the movie
277		 * @access public
278		 * @return integer
279		 */
280		public function getPixelAspectRatio()
281		{
282			return -1; 
283		}
284		
285		/**
286		 * Return the bit rate of the movie or audio file in bits per second.
287		 * @access public
288		 * @return integer
289		 */
290		public function getBitRate()
291		{
292			return isset($this->_media_data['bitrate']) ? $this->_media_data['bitrate'] : -1;
293		}
294		
295		/**
296		 * Return the bit rate of the video in bits per second.
297		 * NOTE: This only works for files with constant bit rate.
298		 * @access public
299		 * @return integer
300		 */
301		public function getVideoBitRate()
302		{
303			return $this->hasVideo() && isset($this->_media_data['video']['bitrate']) ? $this->_media_data['video']['bitrate'] : -1;
304		}
305		
306		/**
307		 * Return the audio bit rate of the media file in bits per second.
308		 * @access public
309		 * @return integer
310		 */
311		public function getAudioBitRate()
312		{
313			return $this->hasAudio() && isset($this->_media_data['audio']['bitrate']) ? $this->_media_data['audio']['bitrate'] : -1;
314		}
315		
316		/**
317		 * Return the audio sample rate of the media file in bits per second.
318		 * @access public
319		 * @return integer
320		 */
321		public function getAudioSampleRate()
322		{
323			return $this->hasAudio() && isset($this->_media_data['audio']['sample_rate']) ? $this->_media_data['audio']['sample_rate'] : -1;
324		}
325		
326		/**
327		 * Return the name of the video codec used to encode this movie as a string.
328		 * @access public
329		 * @param boolean $return_all If true it will return all audio codecs found.
330		 * @return mixed string | array
331		 */
332		public function getVideoCodec($return_all=false)
333		{
334			return $this->hasVideo() ? $this->_media_data['video']['codec'] : -1;
335		}
336		
337		/**
338		 * Return the name of the audio codec used to encode this movie as a string.
339		 * @access public
340		 * @param boolean $return_all If true it will return all audio codecs found.
341		 * @return mixed string | array
342		 */
343		public function getAudioCodec()
344		{
345			return $this->hasAudio() ? $this->_media_data['audio']['codec'] : -1;
346		}
347		
348		/**
349		 * Return the number of audio channels in this movie as an integer.
350		 * @access public
351		 * @return integer
352		 */
353		public function getAudioChannels()
354		{
355			if($this->hasAudio())
356			{
357				if($this->_getPHPReader() && isset($this->_getid3_data['audio']) && isset($this->_getid3_data['audio']['channels']))
358				{
359					return $this->_getid3_data['audio']['channels'];
360				}
361				return 1;
362			}
363			return 0;
364		}
365		
366		/**
367		 * Return boolean value indicating whether the movie has an audio stream.
368		 * @access public
369		 * @return boolean
370		 */
371		public function hasAudio()
372		{
373			return isset($this->_media_data['audio']);
374		}
375		
376		/**
377		 * Return boolean value indicating whether the movie has a video stream.
378		 * @access public
379		 * @return boolean
380		 */
381		public function hasVideo()
382		{
383			return isset($this->_media_data['video']);
384		}
385		
386		/**
387		 * Returns a frame from the movie as an ffmpeg_frame object. 
388		 * Returns false if the frame was not found.
389		 * @access public
390		 * @return mixed boolean | ffmpeg_frame
391		 */
392		public function getFrame($frame_number=false)
393		{
394			if(!$this->hasVideo())
395			{
396				return false;
397			}
398			$this->_toolkit->reset(true);
399			require_once dirname(__FILE__).DS.'ffmpeg_frame.php';
400			if(!$frame_number)
401			{
402				$frame_number = $this->_frame_index;
403				$this->_frame_index += 1;
404			}
405			else
406			{
407				$this->_frame_index = $frame_number;
408			}
409// 			check the frame required exists in the video
410			if($frame_number > $this->getFrameCount())
411			{
412				return false;
413			}
414// 			work out the exact frame to take
415			$frame_rate = $this->getFrameRate();
416// 			generate a unique name
417			$tmp_name	= $this->_toolkit->unique().'-%index.jpg';
418// 			extract the frame
419// 			print_r(array($frame_number, $frame_rate, '%ft'));
420			$this->_toolkit->extractFrame($frame_number, $frame_rate, '%ft');
421			$this->_toolkit->setOutput($this->_tmp_directory, $tmp_name, PHPVideoToolkit::OVERWRITE_EXISTING);
422			$result = $this->_toolkit->execute(false, true);
423// 			check the image has been outputted
424// 			print_r(array($this->_toolkit->getLastError(), $this->_toolkit->getLastCommand()));
425// 			print_r(array($this->_toolkit->getLastCommand()));
426// 			print_r(array($tmp_name, $this->_toolkit->getLastOutput()));
427			if($result !== PHPVideoToolkit::RESULT_OK)
428			{
429				return false;
430			}
431// 			load the frame into gd
432			$temp_output = array_shift(array_flip($this->_toolkit->getLastOutput()));
433			$gd_img = imagecreatefromjpeg($temp_output);
434// 			delete the temp image
435			unlink($temp_output);
436// 			return the ffmpeg frame instance
437			$ffmpeg_frame_time = $this->_toolkit->formatTimecode($frame_number, '%ft', '%hh:%mm:%ss.%ms', $frame_rate);
438			return new ffmpeg_frame($gd_img, $ffmpeg_frame_time);
439		}
440		
441		/**
442		 * Note; this doesn't behave exactly as ffmpeg_movie, this will get the first frame
443		 * of the next second in the movie.
444		 * Returns the next key frame from the movie as an ffmpeg_frame object. 
445		 * Returns false if the frame was not found.
446		 * @uses ffmpeg_movie::getFrame();
447		 * @access public
448		 * @return mixed boolean | ffmpeg_frame
449		 */
450		public function getNextKeyFrame()
451		{
452			$frame_rate 	= $this->getFrameRate();
453// 			work out the next frame
454			$current_second = floor($frame_number/$frame_rate);
455			$excess			= $frame_number-($seconds * $frame_rate);
456			$frames_to_next = $frame_rate-$excess;
457			$this->_frame_index += $frames_to_next;
458// 			get the frame
459			return $this->getFrame();
460		}
461		
462		/**
463		 * Return the current frame index.
464		 * @access public
465		 * @return integer
466		 */
467		public function getFrameNumber()
468		{
469			return $this->_frame_index;
470		}
471		
472	}
473