PageRenderTime 133ms CodeModel.GetById 23ms RepoModel.GetById 2ms app.codeStats 1ms

/Vendor/phpvideotoolkit/phpvideotoolkit.php4.php

https://github.com/Wargo/reddevil
PHP | 3295 lines | 1735 code | 168 blank | 1392 comment | 259 complexity | c07fc240df96d0353b02f1aafe1cf221 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0, LGPL-2.1, GPL-3.0
  1. <?php
  2. /* SVN FILE: $Id$ */
  3. /**
  4. * @author Oliver Lillie (aka buggedcom) <publicmail@buggedcom.co.uk>
  5. *
  6. * @license BSD
  7. * @copyright Copyright (c) 2008 Oliver Lillie <http://www.buggedcom.co.uk>
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
  9. * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
  11. * is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be
  12. * included in all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  15. * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  16. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  17. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  18. *
  19. * @package PHPVideoToolkit (was called ffmpeg)
  20. * @version 0.1.5
  21. * @changelog SEE CHANGELOG
  22. * @abstract This class can be used in conjunction with several server binary libraries to manipulate video and audio
  23. * through PHP. It is not intended to solve any particular problems, however you may find it useful. This php class
  24. * is in no way associated with the actual FFmpeg releases. Any mistakes contained in this php class are mine and mine
  25. * alone.
  26. *
  27. * Please Note: There are several prerequisites that are required before this class can be used as an aid to manipulate
  28. * video and audio. You must at the very least have FFMPEG compiled on your server. If you wish to use this class for FLV
  29. * manipulation you must compile FFMPEG with LAME and Ruby's FLVTOOL2. I cannot answer questions regarding the install of
  30. * the server binaries needed by this class. I had too learn the hard way and it isn't easy, however it is a good learning
  31. * experience. For those of you who do need help read the install.txt file supplied along side this class. It wasn't written
  32. * by me however I found it useful when installing ffmpeg for the first time. The original source for the install.txt file
  33. * is located http://www.luar.com.hk/blog/?p=669 and the author is Lunar.
  34. *
  35. * @see install.txt
  36. *
  37. * @uses ffmpeg http://ffmpeg.sourceforge.net/
  38. * @uses lame http://lame.sourceforge.net/
  39. * @uses flvtool2 http://www.inlet-media.de/flvtool2 (and ruby http://www.ruby-lang.org/en/)
  40. *
  41. * @config examples/example-config.php Please edit this files in order for the examples to work.
  42. * @example examples/example01.php Converts video to Flash Video (ie FLV).
  43. * @example examples/example02.php Screen grabs video frames.
  44. * @example examples/example03.php Compile a movie from multiple jpegs
  45. * @example examples/example04.php Watermark a video.
  46. * @example examples/example05.php Access media metadata without using the ffmpeg-php library.
  47. * @example examples/example06.php Extract audio from video.
  48. * @example examples/example07.php Join multiple videos together.
  49. * @example examples/example08.php Easy video conversion to common formats using the adapters.
  50. * @example examples/example09.php Shows you how to access the information about your ffmpeg installation.
  51. * @example examples/example10.php Shows you how to extract a specific frame from a movie.
  52. * @example examples/example11.php Shows you how to use the ffmpeg-php adapters to provide a pure php emulation of ffmpeg-php.
  53. * @example examples/example12.php Shows you how to manipulate/format timecode strings.
  54. * @example examples/example13.php This demonstrates how to simply create a FLV stream script.
  55. */
  56. /**
  57. * Set the ffmpeg binary path
  58. */
  59. if(!defined('PHPVIDEOTOOLKIT_FFMPEG_BINARY'))
  60. {
  61. define('PHPVIDEOTOOLKIT_FFMPEG_BINARY', '/usr/local/bin/ffmpeg');
  62. }
  63. /**
  64. * Set the flvtool2 binary path
  65. */
  66. if(!defined('PHPVIDEOTOOLKIT_FLVTOOLS_BINARY'))
  67. {
  68. define('PHPVIDEOTOOLKIT_FLVTOOLS_BINARY', '/usr/bin/flvtool2');
  69. }
  70. /**
  71. * Set the watermark vhook path
  72. */
  73. if(!defined('PHPVIDEOTOOLKIT_FFMPEG_WATERMARK_VHOOK'))
  74. {
  75. define('PHPVIDEOTOOLKIT_FFMPEG_WATERMARK_VHOOK', '/usr/local/lib/vhook/watermark.so');
  76. }
  77. /**
  78. * Set the memcoder path
  79. */
  80. if(!defined('PHPVIDEOTOOLKIT_MENCODER_BINARY'))
  81. {
  82. define('PHPVIDEOTOOLKIT_MENCODER_BINARY', '/usr/local/bin/mencoder');
  83. }
  84. /**
  85. * Codec support constants
  86. */
  87. define('PHPVIDEOTOOLKIT_ENCODE', 'encode');
  88. define('PHPVIDEOTOOLKIT_DECODE', 'decode');
  89. /**
  90. * Process Results from PHPVideoToolkit::execute
  91. */
  92. // any return value with this means everything is ok
  93. define('PHPVIDEOTOOLKIT_RESULT_OK', true);
  94. // any return value with this means the file has been processed/converted ok however it was
  95. // not able to be written to the output address. If this occurs you will need to move the
  96. // processed file manually from the temp location
  97. define('PHPVIDEOTOOLKIT_RESULT_OK_BUT_UNWRITABLE', -1);
  98. /**
  99. * Overwrite constants used in setOutput
  100. */
  101. define('PHPVIDEOTOOLKIT_OVERWRITE_FAIL', 'fail');
  102. define('PHPVIDEOTOOLKIT_OVERWRITE_PRESERVE', 'preserve');
  103. define('PHPVIDEOTOOLKIT_OVERWRITE_EXISTING', 'existing');
  104. define('PHPVIDEOTOOLKIT_OVERWRITE_UNIQUE', 'unique');
  105. /**
  106. * Formats supported
  107. * 3g2 3gp2 format
  108. * 3gp 3gp format
  109. * aac ADTS AAC
  110. * aiff Audio IFF
  111. * amr 3gpp amr file format
  112. * asf asf format
  113. * avi avi format
  114. * flv flv format
  115. * gif GIF Animation
  116. * mov mov format
  117. * mov,mp4,m4a,3gp,3g2,mj2 QuickTime/MPEG4/Motion JPEG 2000 format
  118. * mp2 MPEG audio layer 2
  119. * mp3 MPEG audio layer 3
  120. * mp4 mp4 format
  121. * mpeg MPEG1 System format
  122. * mpeg1video MPEG video
  123. * mpeg2video MPEG2 video
  124. * mpegvideo MPEG video
  125. * psp psp mp4 format
  126. * rm rm format
  127. * swf Flash format
  128. * vob MPEG2 PS format (VOB)
  129. * wav wav format
  130. * jpeg mjpeg format
  131. * yuv4mpegpipe yuv4mpegpipe format
  132. */
  133. define('PHPVIDEOTOOLKIT_FORMAT_3GP2', '3g2');
  134. define('PHPVIDEOTOOLKIT_FORMAT_3GP', '3gp');
  135. define('PHPVIDEOTOOLKIT_FORMAT_AAC', 'aac');
  136. define('PHPVIDEOTOOLKIT_FORMAT_AIFF', 'aiff');
  137. define('PHPVIDEOTOOLKIT_FORMAT_AMR', 'amr');
  138. define('PHPVIDEOTOOLKIT_FORMAT_ASF', 'asf');
  139. define('PHPVIDEOTOOLKIT_FORMAT_AVI', 'avi');
  140. define('PHPVIDEOTOOLKIT_FORMAT_FLV', 'flv');
  141. define('PHPVIDEOTOOLKIT_FORMAT_GIF', 'gif');
  142. define('PHPVIDEOTOOLKIT_FORMAT_MJ2', 'mj2');
  143. define('PHPVIDEOTOOLKIT_FORMAT_MP2', 'mp2');
  144. define('PHPVIDEOTOOLKIT_FORMAT_MP3', 'mp3');
  145. define('PHPVIDEOTOOLKIT_FORMAT_MP4', 'mp4');
  146. define('PHPVIDEOTOOLKIT_FORMAT_MPEG4', 'mpeg4');
  147. define('PHPVIDEOTOOLKIT_FORMAT_M4A', 'm4a');
  148. define('PHPVIDEOTOOLKIT_FORMAT_MPEG', 'mpeg');
  149. define('PHPVIDEOTOOLKIT_FORMAT_MPEG1', 'mpeg1video');
  150. define('PHPVIDEOTOOLKIT_FORMAT_MPEG2', 'mpeg2video');
  151. define('PHPVIDEOTOOLKIT_FORMAT_MPEGVIDEO', 'mpegvideo');
  152. define('PHPVIDEOTOOLKIT_FORMAT_PSP', 'psp');
  153. define('PHPVIDEOTOOLKIT_FORMAT_RM', 'rm');
  154. define('PHPVIDEOTOOLKIT_FORMAT_SWF', 'swf');
  155. define('PHPVIDEOTOOLKIT_FORMAT_VOB', 'vob');
  156. define('PHPVIDEOTOOLKIT_FORMAT_WAV', 'wav');
  157. define('PHPVIDEOTOOLKIT_FORMAT_JPG', 'mjpeg');
  158. define('PHPVIDEOTOOLKIT_FORMAT_Y4MP', 'yuv4mpegpipe');
  159. /**
  160. * Size Presets
  161. */
  162. define('PHPVIDEOTOOLKIT_SIZE_SAS', 'SameAsSource');
  163. define('PHPVIDEOTOOLKIT_SIZE_SQCIF', '128x96');
  164. define('PHPVIDEOTOOLKIT_SIZE_QCIF', '176x144');
  165. define('PHPVIDEOTOOLKIT_SIZE_CIF', '352x288');
  166. define('PHPVIDEOTOOLKIT_SIZE_4CIF', '704x576');
  167. define('PHPVIDEOTOOLKIT_SIZE_QQVGA', '160x120');
  168. define('PHPVIDEOTOOLKIT_SIZE_QVGA', '320x240');
  169. define('PHPVIDEOTOOLKIT_SIZE_VGA', '640x480');
  170. define('PHPVIDEOTOOLKIT_SIZE_SVGA', '800x600');
  171. define('PHPVIDEOTOOLKIT_SIZE_XGA', '1024x768');
  172. define('PHPVIDEOTOOLKIT_SIZE_UXGA', '1600x1200');
  173. define('PHPVIDEOTOOLKIT_SIZE_QXGA', '2048x1536');
  174. define('PHPVIDEOTOOLKIT_SIZE_SXGA', '1280x1024');
  175. define('PHPVIDEOTOOLKIT_SIZE_QSXGA', '2560x2048');
  176. define('PHPVIDEOTOOLKIT_SIZE_HSXGA', '5120x4096');
  177. define('PHPVIDEOTOOLKIT_SIZE_WVGA', '852x480');
  178. define('PHPVIDEOTOOLKIT_SIZE_WXGA', '1366x768');
  179. define('PHPVIDEOTOOLKIT_SIZE_WSXGA', '1600x1024');
  180. define('PHPVIDEOTOOLKIT_SIZE_WUXGA', '1920x1200');
  181. define('PHPVIDEOTOOLKIT_SIZE_WOXGA', '2560x1600');
  182. define('PHPVIDEOTOOLKIT_SIZE_WQSXGA', '3200x2048');
  183. define('PHPVIDEOTOOLKIT_SIZE_WQUXGA', '3840x2400');
  184. define('PHPVIDEOTOOLKIT_SIZE_WHSXGA', '6400x4096');
  185. define('PHPVIDEOTOOLKIT_SIZE_WHUXGA', '7680x4800');
  186. define('PHPVIDEOTOOLKIT_SIZE_CGA', '320x200');
  187. define('PHPVIDEOTOOLKIT_SIZE_EGA', '640x350');
  188. define('PHPVIDEOTOOLKIT_SIZE_HD480', '852x480');
  189. define('PHPVIDEOTOOLKIT_SIZE_HD720', '1280x720');
  190. define('PHPVIDEOTOOLKIT_SIZE_HD1080', '1920x1080');
  191. /**
  192. * Ratio Presets
  193. */
  194. define('PHPVIDEOTOOLKIT_RATIO_STANDARD', '4:3');
  195. define('PHPVIDEOTOOLKIT_RATIO_WIDE', '16:9');
  196. define('PHPVIDEOTOOLKIT_RATIO_CINEMATIC', '1.85');
  197. /**
  198. * @author Oliver Lillie (aka buggedcom) <publicmail@buggedcom.co.uk>
  199. * @license BSD
  200. * @package PHPVideoToolkit (was called ffmpeg)
  201. */
  202. class PHPVideoToolkit
  203. {
  204. var $version = '0.1.5';
  205. /**
  206. * Error strings
  207. */
  208. var $_messages = array(
  209. 'generic_temp_404' => 'The temporary directory does not exist.',
  210. 'generic_temp_writable' => 'The temporary directory is not write-able by the web server.',
  211. 'getFileInfo_no_input' => 'Input file does not exist so no information can be retrieved.',
  212. 'setInputFile_file_existence' => 'Input file "#file" does not exist',
  213. 'extractAudio_valid_format' => 'Value "#format" set from $toolkit->extractAudio, is not a valid audio format. Valid values ffmpeg PHPVIDEOTOOLKIT_FORMAT_AAC, PHPVIDEOTOOLKIT_FORMAT_AIFF, PHPVIDEOTOOLKIT_FORMAT_MP2, PHPVIDEOTOOLKIT_FORMAT_MP3, PHPVIDEOTOOLKIT_FORMAT_MP4, PHPVIDEOTOOLKIT_FORMAT_MPEG4, PHPVIDEOTOOLKIT_FORMAT_M4A or PHPVIDEOTOOLKIT_FORMAT_WAV. If you wish to specifically try to set another format you should use the advanced function $toolkit->addCommand. Set $command to "-f" and $argument to your required value.',
  214. 'extractFrame_video_frame_rate_404' => 'You have attempted to extract a thumbnail from a video while automagically guessing the framerate of the video, but the framerate could not be accessed. You can remove this error by manually setting the frame rate of the video.',
  215. 'extractFrame_video_info_404' => 'You have attempted to extract a thumbnail from a video and check to see if the thumbnail exists, however it was not possible to access the video information. Please check your temporary directory permissions for read/write access by the webserver.',
  216. 'extractFrame_video_frame_count' => 'You have attempted to extract a thumbnail from a video but the thumbnail you are trying to extract does not exist in the video.',
  217. 'extractFrames_video_begin_frame_count' => 'You have attempted to extract thumbnails from a video but the thumbnail you are trying to start the extraction from does not exist in the video.',
  218. 'extractFrames_video_end_frame_count' => 'You have attempted to extract thumbnails from a video but the thumbnail you are trying to end the extraction at does not exist in the video.',
  219. 'setFormat_valid_format' => 'Value "#format" set from $toolkit->setFormat, is not a valid format. Valid values are PHPVIDEOTOOLKIT_FORMAT_3GP2, PHPVIDEOTOOLKIT_FORMAT_3GP, PHPVIDEOTOOLKIT_FORMAT_AAC, PHPVIDEOTOOLKIT_FORMAT_AIFF, PHPVIDEOTOOLKIT_FORMAT_AMR, PHPVIDEOTOOLKIT_FORMAT_ASF, PHPVIDEOTOOLKIT_FORMAT_AVI, PHPVIDEOTOOLKIT_FORMAT_FLV, PHPVIDEOTOOLKIT_FORMAT_GIF, PHPVIDEOTOOLKIT_FORMAT_MJ2, PHPVIDEOTOOLKIT_FORMAT_MP2, PHPVIDEOTOOLKIT_FORMAT_MP3, PHPVIDEOTOOLKIT_FORMAT_MP4, PHPVIDEOTOOLKIT_FORMAT_MPEG4, PHPVIDEOTOOLKIT_FORMAT_M4A, PHPVIDEOTOOLKIT_FORMAT_MPEG, PHPVIDEOTOOLKIT_FORMAT_MPEG1, PHPVIDEOTOOLKIT_FORMAT_MPEG2, PHPVIDEOTOOLKIT_FORMAT_MPEGVIDEO, PHPVIDEOTOOLKIT_FORMAT_PSP, PHPVIDEOTOOLKIT_FORMAT_RM, PHPVIDEOTOOLKIT_FORMAT_SWF, PHPVIDEOTOOLKIT_FORMAT_VOB, PHPVIDEOTOOLKIT_FORMAT_WAV, PHPVIDEOTOOLKIT_FORMAT_JPG. If you wish to specifically try to set another format you should use the advanced function $toolkit->addCommand. Set $command to "-f" and $argument to your required value.',
  220. 'setAudioSampleFrequency_valid_frequency' => 'Value "#frequency" set from $toolkit->setAudioSampleFrequency, is not a valid integer. Valid values are 11025, 22050, 44100. If you wish to specifically try to set another frequency you should use the advanced function $toolkit->addCommand. Set $command to "-ar" and $argument to your required value.',
  221. 'setAudioFormat_valid_format' => 'Value "#format" set from $toolkit->setAudioFormat, is not a valid format. Valid values are PHPVIDEOTOOLKIT_FORMAT_AAC, PHPVIDEOTOOLKIT_FORMAT_AIFF, PHPVIDEOTOOLKIT_FORMAT_AMR, PHPVIDEOTOOLKIT_FORMAT_ASF, PHPVIDEOTOOLKIT_FORMAT_MP2, PHPVIDEOTOOLKIT_FORMAT_MP3, PHPVIDEOTOOLKIT_FORMAT_MP4, PHPVIDEOTOOLKIT_FORMAT_MPEG2, PHPVIDEOTOOLKIT_FORMAT_RM, PHPVIDEOTOOLKIT_FORMAT_WAV. If you wish to specifically try to set another format you should use the advanced function $toolkit->addCommand. Set $command to "-acodec" and $argument to your required value.',
  222. 'setVideoFormat_valid_format' => 'Value "#format" set from $toolkit->setAudioFormat, is not a valid format. Valid values are PHPVIDEOTOOLKIT_FORMAT_3GP2, PHPVIDEOTOOLKIT_FORMAT_3GP, PHPVIDEOTOOLKIT_FORMAT_AVI, PHPVIDEOTOOLKIT_FORMAT_FLV, PHPVIDEOTOOLKIT_FORMAT_GIF, PHPVIDEOTOOLKIT_FORMAT_MJ2, PHPVIDEOTOOLKIT_FORMAT_MP4, PHPVIDEOTOOLKIT_FORMAT_MPEG4, PHPVIDEOTOOLKIT_FORMAT_M4A, PHPVIDEOTOOLKIT_FORMAT_MPEG, PHPVIDEOTOOLKIT_FORMAT_MPEG1, PHPVIDEOTOOLKIT_FORMAT_MPEG2, PHPVIDEOTOOLKIT_FORMAT_MPEGVIDEO. If you wish to specifically try to set another format you should use the advanced function $toolkit->addCommand. Set $command to "-vcodec" and $argument to your required value.',
  223. 'setAudioBitRate_valid_bitrate' => 'Value "#bitrate" set from $toolkit->setAudioBitRate, is not a valid integer. Valid values are 16, 32, 64, 128. If you wish to specifically try to set another bitrate you should use the advanced function $toolkit->addCommand. Set $command to "-ab" and $argument to your required value.',
  224. 'prepareImagesForConversionToVideo_one_img' => 'When compiling a movie from a series of images, you must include at least one image.',
  225. 'prepareImagesForConversionToVideo_img_404' => '"#img" does not exist.',
  226. 'prepareImagesForConversionToVideo_img_copy' => '"#img" can not be copied to "#tmpfile"',
  227. 'prepareImagesForConversionToVideo_img_type' => 'The images can not be prepared for conversion to video. Please make sure all images are of the same type, ie gif, png, jpeg and then try again.',
  228. 'setVideoOutputDimensions_valid_format' => 'Value "#format" set from $toolkit->setVideoOutputDimensions, is not a valid preset dimension. Valid values are PHPVIDEOTOOLKIT_SIZE_SQCIF, PHPVIDEOTOOLKIT_SIZE_SAS, PHPVIDEOTOOLKIT_SIZE_QCIF, PHPVIDEOTOOLKIT_SIZE_CIF, PHPVIDEOTOOLKIT_SIZE_4CIF, PHPVIDEOTOOLKIT_SIZE_QQVGA, PHPVIDEOTOOLKIT_SIZE_QVGA, PHPVIDEOTOOLKIT_SIZE_VGA, PHPVIDEOTOOLKIT_SIZE_SVGA, PHPVIDEOTOOLKIT_SIZE_XGA, PHPVIDEOTOOLKIT_SIZE_UXGA, PHPVIDEOTOOLKIT_SIZE_QXGA, PHPVIDEOTOOLKIT_SIZE_SXGA, PHPVIDEOTOOLKIT_SIZE_QSXGA, PHPVIDEOTOOLKIT_SIZE_HSXGA, PHPVIDEOTOOLKIT_SIZE_WVGA, PHPVIDEOTOOLKIT_SIZE_WXGA, PHPVIDEOTOOLKIT_SIZE_WSXGA, PHPVIDEOTOOLKIT_SIZE_WUXGA, PHPVIDEOTOOLKIT_SIZE_WOXGA, PHPVIDEOTOOLKIT_SIZE_WQSXGA, PHPVIDEOTOOLKIT_SIZE_WQUXGA, PHPVIDEOTOOLKIT_SIZE_WHSXGA, PHPVIDEOTOOLKIT_SIZE_WHUXGA, PHPVIDEOTOOLKIT_SIZE_CGA, PHPVIDEOTOOLKIT_SIZE_EGA, PHPVIDEOTOOLKIT_SIZE_HD480, PHPVIDEOTOOLKIT_SIZE_HD720, PHPVIDEOTOOLKIT_SIZE_HD1080. You can also manually set the width and height.',
  229. 'setVideoOutputDimensions_sas_dim' => 'It was not possible to determine the input video dimensions so it was not possible to continue. If you wish to override this error please change the call to setVideoOutputDimensions and add a true argument to the arguments list... setVideoOutputDimensions(PHPVIDEOTOOLKIT_SIZE_SAS, true);',
  230. 'setVideoOutputDimensions_valid_integer' => 'You tried to set the video output dimensions to an odd number. FFmpeg requires that the video output dimensions are of event value and divisible by 2. ie 2, 4, 6,... etc',
  231. 'setVideoAspectRatio_valid_ratio' => 'Value "#ratio" set from $toolkit->setVideoOutputDimensions, is not a valid preset dimension. Valid values are PHPVIDEOTOOLKIT_RATIO_STANDARD, PHPVIDEOTOOLKIT_RATIO_WIDE, PHPVIDEOTOOLKIT_RATIO_CINEMATIC. If you wish to specifically try to set another video aspect ratio you should use the advanced function $toolkit->addCommand. Set $command to "-aspect" and $argument to your required value.',
  232. 'addWatermark_img_404' => 'Watermark file "#watermark" does not exist.',
  233. 'addWatermark_vhook_disabled' => 'Vhooking is not enabled in your FFmpeg binary. In order to allow video watermarking you must have FFmpeg compiled with --enable-vhook set. You can however watermark any extracted images using GD. To enable frame watermarking, call $toolkit->addGDWatermark($file) before you execute the extraction.',
  234. 'addVideo_file_404' => 'File "#file" does not exist.',
  235. 'setOutput_output_dir_404' => 'Output directory "#dir" does not exist!',
  236. 'setOutput_output_dir_writable' => 'Output directory "#dir" is not writable!',
  237. 'setOutput_%_missing' => 'The output of this command will be images yet you have not included the "%index" or "%timecode" in the $output_name.',
  238. 'setOutput_%d_depreciated' => 'The use of %d in the output file name is now depreciated. Please use %index. Number padding is still supported. You may also use %timecode instead to add a timecode to the filename.',
  239. 'execute_input_404' => 'Execute error. Input file missing.',
  240. 'execute_output_not_set' => 'Execute error. Output not set.',
  241. 'execute_overwrite_process' => 'Execute error. A file exists in the temp directory and is of the same name as this process file. It will conflict with this conversion. Conversion stopped.',
  242. 'execute_overwrite_fail' => 'Execute error. Output file exists. Process halted. If you wish to automatically overwrite files set the third argument in "PHPVideoToolkit::setOutput();" to "PHPVIDEOTOOLKIT_OVERWRITE_EXISTING".',
  243. 'execute_partial_error' => 'Execute error. Output for file "#input" encountered a partial error. Files were generated, however one or more of them were empty.',
  244. 'execute_image_error' => 'Execute error. Output for file "#input" was not found. No images were generated.',
  245. 'execute_output_404' => 'Execute error. Output for file "#input" was not found. Please check server write permissions and/or available codecs compiled with FFmpeg. You can check the encode decode availability by inspecting the output array from PHPVideoToolkit::getFFmpegInfo().',
  246. 'execute_output_empty' => 'Execute error. Output for file "#input" was found, but the file contained no data. Please check the available codecs compiled with FFmpeg can support this type of conversion. You can check the encode decode availability by inspecting the output array from PHPVideoToolkit::getFFmpegInfo().',
  247. 'execute_image_file_exists' => 'Execute error. There is a file name conflict. The file "#file" already exists in the filesystem. If you wish to automatically overwrite files set the third argument in "PHPVideoToolkit::setOutput();" to "PHPVIDEOTOOLKIT_OVERWRITE_EXISTING".',
  248. 'execute_result_ok_but_unwritable' => 'Process Partially Completed. The process successfully completed however it was not possible to output to "#output". The output was left in the temp directory "#process" for a manual file movement.',
  249. 'execute_result_ok' => 'Process Completed. The process successfully completed. Output was generated to "#output".',
  250. 'ffmpeg_log_ffmpeg_output' => 'OUTPUT',
  251. 'ffmpeg_log_ffmpeg_result' => 'RESULT',
  252. 'ffmpeg_log_ffmpeg_command' => 'COMMAND',
  253. 'ffmpeg_log_ffmpeg_join_gunk' => 'FFMPEG JOIN OUTPUT',
  254. 'ffmpeg_log_ffmpeg_gunk' => 'FFMPEG OUTPUT',
  255. 'ffmpeg_log_separator' => '-------------------------------'
  256. );
  257. /**
  258. * A public var that is to the information available about
  259. * the current ffmpeg compiled binary.
  260. * @var mixed
  261. * @access public
  262. */
  263. var $ffmpeg_info = false;
  264. /**
  265. * A private var that contains the info of any file that is accessed by PHPVideoToolkit::getFileInfo();
  266. * @var array
  267. * @access private
  268. */
  269. var $_file_info = array();
  270. /**
  271. * Determines what happens when an error occurs
  272. * @var boolean If true then the script will die, if not false is return by the error
  273. * @access public
  274. */
  275. var $on_error_die = false;
  276. /**
  277. * Holds the log file name
  278. * @var string
  279. * @access private
  280. */
  281. var $_log_file = null;
  282. /**
  283. * Determines if when outputting image frames if the outputted files should have the %d number
  284. * replaced with the frames timecode.
  285. * @var boolean If true then the files will be renamed.
  286. * @access public
  287. */
  288. var $image_output_timecode = true;
  289. /**
  290. * Holds the timecode separator for when using $image_output_timecode = true
  291. * Not all systems allow ':' in filenames.
  292. * @var string
  293. * @access public
  294. */
  295. var $timecode_seperator_output = '-';
  296. /**
  297. * Holds the starting time code when outputting image frames.
  298. * @var string The timecode hh(n):mm:ss:ff
  299. * @access private
  300. */
  301. var $_image_output_timecode_start = '00:00:00.00';
  302. /**
  303. * The format in which the image %timecode placeholder string is outputted.
  304. * - %hh (hours) representative of hours
  305. * - %mm (minutes) representative of minutes
  306. * - %ss (seconds) representative of seconds
  307. * - %fn (frame number) representative of frames (of the current second, not total frames)
  308. * - %ms (milliseconds) representative of milliseconds (of the current second, not total milliseconds) (rounded to 3 decimal places)
  309. * - %ft (frames total) representative of total frames (ie frame number)
  310. * - %st (seconds total) representative of total seconds (rounded).
  311. * - %sf (seconds floored) representative of total seconds (floored).
  312. * - %mt (milliseconds total) representative of total milliseconds. (rounded to 3 decimal places)
  313. * NOTE; there are special characters that will be replace by PHPVideoToolkit::$timecode_seperator_output, these characters are
  314. * - :
  315. * - .
  316. * @var string
  317. * @access public
  318. */
  319. var $image_output_timecode_format = '%hh-%mm-%ss-%fn';
  320. /**
  321. * Holds the fps of image extracts
  322. * @var integer
  323. * @access private
  324. */
  325. var $_image_output_timecode_fps = 1;
  326. /**
  327. * Holds the current execute commands that will need to be combined
  328. * @var array
  329. * @access private
  330. */
  331. var $_commands = array();
  332. /**
  333. * Holds the commands executed
  334. * @var array
  335. * @access private
  336. */
  337. var $_processed = array();
  338. /**
  339. * Holds the file references to those that have been processed
  340. * @var array
  341. * @access private
  342. */
  343. var $_files = array();
  344. /**
  345. * Holds the errors encountered
  346. * @access private
  347. * @var array
  348. */
  349. var $_errors = array();
  350. /**
  351. * Holds the input file / input file sequence
  352. * @access private
  353. * @var string
  354. */
  355. var $_input_file = null;
  356. /**
  357. * Holds the output file / output file sequence
  358. * @access private
  359. * @var string
  360. */
  361. var $_output_address = null;
  362. /**
  363. * Holds the process file / process file sequence
  364. * @access private
  365. * @var string
  366. */
  367. var $_process_address = null;
  368. /**
  369. * Temporary filename prefix
  370. * @access private
  371. * @var string
  372. */
  373. var $_tmp_file_prefix = 'tmp_';
  374. /**
  375. * Holds the temporary directory name
  376. * @access private
  377. * @var string
  378. */
  379. var $_tmp_directory = null;
  380. /**
  381. * Holds the directory paths that need to be removed by the ___destruct function
  382. * @access private
  383. * @var array
  384. */
  385. var $_unlink_dirs = array();
  386. /**
  387. * Holds the file paths that need to be deleted by the ___destruct function
  388. * @access private
  389. * @var array
  390. */
  391. var $_unlink_files = array();
  392. /**
  393. * Holds the timer start micro-float.
  394. * @access private
  395. * @var integer
  396. */
  397. var $_timer_start = 0;
  398. /**
  399. * Holds the times taken to process each file.
  400. * @access private
  401. * @var array
  402. */
  403. var $_timers = array();
  404. /**
  405. * Holds the times taken to process each file.
  406. * @access private
  407. * @var constant
  408. */
  409. var $_overwrite_mode = null;
  410. /**
  411. * Holds a integer value that flags if the image extraction is just a single frame.
  412. * @access private
  413. * @var integer
  414. */
  415. var $_single_frame_extraction = null;
  416. /**
  417. * Holds the watermark file that is used to watermark any outputted images via GD.
  418. * @access private
  419. * @var string
  420. */
  421. var $_watermark_url = null;
  422. /**
  423. * Holds the watermark options used to watermark any outputted images via GD.
  424. * @access private
  425. * @var array
  426. */
  427. var $_watermark_options = null;
  428. /**
  429. * Holds the number of files processed per run.
  430. * @access private
  431. * @var integer
  432. */
  433. var $_process_file_count = 0;
  434. /**
  435. * Holds the times taken to process each file.
  436. * @access private
  437. * @var array
  438. */
  439. var $_post_processes = array();
  440. /**
  441. * Holds commands should be sent added to the exec before the input file, this is by no means a definitive list
  442. * of all the ffmpeg commands, as it only utilizes the ones in use by this class. Also only commands that have
  443. * specific required places are entered in the arrays below. Anything not in these arrays will be treated as an
  444. * after-input item.
  445. * @access private
  446. * @var array
  447. */
  448. // var $_cmds_before_input = array();
  449. var $_cmds_before_input = array('-inputr');
  450. // var $_cmds_before_input = array('-r', '-f');
  451. /**
  452. * Constructs the class and sets the temporary directory.
  453. *
  454. * @access private
  455. * @param string $tmp_directory A full absolute path to you temporary directory
  456. */
  457. function PHPVideoToolkit($tmp_directory='/tmp/')
  458. {
  459. $this->_tmp_directory = $tmp_directory;
  460. // emulate php5 destructors
  461. register_shutdown_function(array(&$this, '__destruct'));
  462. }
  463. function microtimeFloat()
  464. {
  465. list($usec, $sec) = explode(" ", microtime());
  466. return ((float) $usec + (float) $sec);
  467. }
  468. /**
  469. * Resets the class
  470. *
  471. * @access public
  472. * @param boolean $keep_input_file Determines whether or not to reset the input file currently set.
  473. */
  474. function reset($keep_input_file=false, $keep_processes=false)
  475. {
  476. if($keep_input_file === false)
  477. {
  478. $this->_input_file = null;
  479. }
  480. if($keep_processes === false)
  481. {
  482. $this->_post_processes = array();
  483. }
  484. $this->_single_frame_extraction = null;
  485. $this->_output_address = null;
  486. $this->_process_address = null;
  487. $this->_log_file = null;
  488. $this->_commands = array();
  489. $this->_timer_start = 0;
  490. $this->_process_file_count = 0;
  491. $this->__destruct();
  492. }
  493. /**
  494. * Returns information about the specified file without having to use ffmpeg-php
  495. * as it consults the ffmpeg binary directly.
  496. *
  497. * @access public
  498. * @param string $file The absolute path of the file that is required to be manipulated.
  499. * @return mixed false on error encountered, true otherwise
  500. **/
  501. function getFFmpegInfo()
  502. {
  503. // check to see if this is a static call
  504. if(!$this)
  505. {
  506. $toolkit = new PHPVideoToolkit($tmp_directory);
  507. return $toolkit->getFFmpegInfo();
  508. }
  509. // check to see if the info has already been cached
  510. if($this->ffmpeg_info !== false)
  511. {
  512. return $this->ffmpeg_info;
  513. }
  514. // check to see if this is a static call
  515. $format = '';
  516. $info_file = $this->_tmp_directory.$this->unique('ffinfo').'.info';
  517. // execute the ffmpeg lookup
  518. // exec(PHPVIDEOTOOLKIT_FFMPEG_BINARY.' -formats &> '.$info_file);
  519. exec(PHPVIDEOTOOLKIT_FFMPEG_BINARY.' -formats 2>&1', $buffer);
  520. $buffer = implode("\r\n", $buffer);
  521. // $data = false;
  522. // try to open the file
  523. // $handle = fopen($info_file, 'r');
  524. // if($handle)
  525. // {
  526. // $data = array();
  527. // $buffer = '';
  528. // // loop through the lines of data and collect the buffer
  529. // while (!feof($handle))
  530. // {
  531. // $buffer .= fgets($handle, 4096);
  532. // }
  533. // echo($buffer);
  534. $data['compiler'] = array();
  535. $look_ups = array('configuration'=>'configuration: ', 'formats'=>'File formats:', 'codecs'=>'Codecs:', 'filters'=>'Bitstream filters:', 'protocols'=>'Supported file protocols:', 'abbreviations'=>'Frame size, frame rate abbreviations:', 'Note:');
  536. $total_lookups = count($look_ups);
  537. $pregs = array();
  538. $indexs = array();
  539. foreach($look_ups as $key=>$reg)
  540. {
  541. if(strpos($buffer, $reg) !== false)
  542. {
  543. $index = array_push($pregs, $reg);
  544. $indexs[$key] = $index;
  545. }
  546. }
  547. preg_match('/'.implode('(.*)', $pregs).'/s', $buffer, $matches);
  548. $configuration = trim($matches[$indexs['configuration']]);
  549. // grab the ffmpeg configuration flags
  550. preg_match_all('/--[a-zA-Z0-9\-]+/', $configuration, $config_flags);
  551. $data['compiler']['configuration'] = $config_flags[0];
  552. $data['compiler']['vhook-support'] = in_array('--enable-vhook', $config_flags[0]) && !in_array('--disable-vhook', $config_flags[0]);
  553. // grab the versions
  554. $data['compiler']['versions'] = array();
  555. preg_match_all('/([a-zA-Z0-9\-]+) version: ([0-9\.]+)/', $configuration, $versions);
  556. for($i=0, $a=count($versions[0]); $i<$a; $i++)
  557. {
  558. $data['compiler']['versions'][strtolower(trim($versions[1][$i]))] = $versions[2][$i];
  559. }
  560. // grab the ffmpeg compile info
  561. preg_match('/built on (.*), gcc: (.*)/', $configuration, $conf);
  562. if(count($conf) > 0)
  563. {
  564. $data['compiler']['gcc'] = $conf[2];
  565. $data['compiler']['build_date'] = $conf[1];
  566. $data['compiler']['build_date_timestamp'] = strtotime($conf[1]);
  567. }
  568. // grab the file formats available to ffmpeg
  569. preg_match_all('/ (DE|D|E) (.*) {1,} (.*)/', trim($matches[$indexs['formats']]), $formats);
  570. $data['formats'] = array();
  571. // loop and clean
  572. for($i=0, $a=count($formats[0]); $i<$a; $i++)
  573. {
  574. $data['formats'][strtolower(trim($formats[2][$i]))] = array(
  575. 'encode' => $formats[1][$i] == 'DE' || $formats[1][$i] == 'E',
  576. 'decode' => $formats[1][$i] == 'DE' || $formats[1][$i] == 'D',
  577. 'fullname' => $formats[3][$i]
  578. );
  579. }
  580. // grab the bitstream filters available to ffmpeg
  581. $data['filters'] = array();
  582. if(isset($indexs['filters']) && isset($matches[$indexs['filters']]))
  583. {
  584. $filters = trim($matches[$indexs['filters']]);
  585. if(empty($filters))
  586. {
  587. $data['filters'] = explode(' ', $filters);
  588. }
  589. }
  590. // grab the file prototcols available to ffmpeg
  591. $data['filters'] = array();
  592. if(isset($indexs['protocols']) && isset($matches[$indexs['protocols']]))
  593. {
  594. $protocols = trim($matches[$indexs['protocols']]);
  595. if(empty($protocols))
  596. {
  597. $data['protocols'] = explode(' ', str_replace(':', '', $protocols));
  598. }
  599. }
  600. // grab the abbreviations available to ffmpeg
  601. $data['abbreviations'] = array();
  602. if(isset($indexs['abbreviations']) && isset($matches[$indexs['abbreviations']]))
  603. {
  604. $abbreviations = trim($matches[$indexs['abbreviations']]);
  605. if(empty($abbreviations))
  606. {
  607. $data['abbreviations'] = explode(' ', $abbreviations);
  608. }
  609. }
  610. $this->ffmpeg_info = $data;
  611. }
  612. // fclose($handle);
  613. // if(is_file($info_file))
  614. // {
  615. // // if the info file exists remove it
  616. // unlink($info_file);
  617. // }
  618. $data['ffmpeg-php-support'] = $this->hasFFmpegPHPSupport();
  619. return $data;
  620. }
  621. /**
  622. * Determines the type of support that exists for the FFmpeg-PHP module.
  623. *
  624. * @access public
  625. * @return mixed. Boolean false if there is no support, String 'module' if the actuall
  626. * FFmpeg-PHP module is loaded, or String 'emulated' if the FFmpeg-PHP classes
  627. * can be emulated through the adapter classes.
  628. */
  629. function hasFFmpegPHPSupport()
  630. {
  631. return extension_loaded('ffmpeg') ? 'module' : (is_file(dirname(__FILE__).DIRECTORY_SEPARATOR.'adapters'.DIRECTORY_SEPARATOR.'ffmpeg-php'.DIRECTORY_SEPARATOR.'ffmpeg_movie.php') && is_file(dirname(__FILE__).DIRECTORY_SEPARATOR.'adapters'.DIRECTORY_SEPARATOR.'ffmpeg-php'.DIRECTORY_SEPARATOR.'ffmpeg_frame.php') && is_file(dirname(__FILE__).DIRECTORY_SEPARATOR.'adapters'.DIRECTORY_SEPARATOR.'ffmpeg-php'.DIRECTORY_SEPARATOR.'ffmpeg_animated_gif.php') ? 'emulated' : false);
  632. }
  633. /**
  634. * Determines if the ffmpeg binary has been compiled with vhook support.
  635. *
  636. * @access public
  637. * @return mixed. Boolean false if there is no support, true there is support.
  638. */
  639. function hasVHookSupport()
  640. {
  641. $info = $this->getFFmpegInfo();
  642. return $info['compiler']['vhook-support'];
  643. }
  644. /**
  645. * Returns information about the specified file without having to use ffmpeg-php
  646. * as it consults the ffmpeg binary directly. This idea for this function has been borrowed from
  647. * a French ffmpeg class located: http://www.phpcs.com/codesource.aspx?ID=45279
  648. *
  649. * @access public
  650. * @todo Change the search from string explode to a regex based search
  651. * @param string $file The absolute path of the file that is required to be manipulated.
  652. * @return mixed false on error encountered, true otherwise
  653. **/
  654. function getFileInfo($file=false, $tmp_directory='/tmp/')
  655. {
  656. // check to see if this is a static call
  657. if($file !== false && !$this)
  658. {
  659. $toolkit = new PHPVideoToolkit($tmp_directory);
  660. return $toolkit->getFileInfo($file);
  661. }
  662. // if the file has not been specified check to see if an input file has been specified
  663. if($file === false)
  664. {
  665. if(!$this->_input_file)
  666. {
  667. // input file not valid
  668. return $this->_raiseError('getFileInfo_no_input');
  669. //<- exits
  670. }
  671. $file = $this->_input_file;
  672. }
  673. $file = escapeshellarg($file);
  674. // die($file);
  675. // create a hash of the filename
  676. $hash = md5($file);
  677. // check to see if the info has already been generated
  678. if(isset($this->_file_info[$hash]))
  679. {
  680. return $this->_file_info[$hash];
  681. }
  682. // generate a random filename
  683. $info_file = $this->_tmp_directory.$this->unique($hash).'.info';
  684. // execute the ffmpeg lookup
  685. // exec(PHPVIDEOTOOLKIT_FFMPEG_BINARY.' -i '.$file.' &> '.$info_file);
  686. exec(PHPVIDEOTOOLKIT_FFMPEG_BINARY.' -i '.$file.' 2>&1', $buffer);
  687. $buffer = implode("\r\n", $buffer);
  688. // $data = false;
  689. // // try to open the file
  690. // $handle = fopen($info_file, 'r');
  691. // if($handle)
  692. // {
  693. // $data = array();
  694. // $buffer = '';
  695. // // loop through the lines of data and collect the buffer
  696. // while (!feof($handle))
  697. // {
  698. // $buffer .= fgets($handle, 4096);
  699. // }
  700. // die($buffer);
  701. // grab the duration and bitrate data
  702. preg_match_all('/Duration: (.*)/', $buffer, $matches);
  703. if(count($matches) > 0)
  704. {
  705. $parts = explode(', ', trim($matches[1][0]));
  706. $data['duration'] = array();
  707. $timecode = $parts[0];
  708. $data['duration']['seconds'] = $this->timecodeToSeconds($timecode);
  709. $data['bitrate'] = intval(ltrim($parts[2], 'bitrate: '));
  710. $data['duration']['start'] = ltrim($parts[1], 'start: ');
  711. $data['duration']['timecode'] = array();
  712. $data['duration']['timecode']['rounded'] = substr($timecode, 0, 8);
  713. $data['duration']['timecode']['seconds'] = array();
  714. $data['duration']['timecode']['seconds']['exact'] = $timecode;
  715. $data['duration']['timecode']['seconds']['excess'] = intval(substr($timecode, 9));
  716. }
  717. // match the video stream info
  718. preg_match('/Stream(.*): Video: (.*)/', $buffer, $matches);
  719. if(count($matches) > 0)
  720. {
  721. $data['video'] = array();
  722. // get the dimension parts
  723. // print_r($matches);
  724. preg_match('/([0-9]{1,5})x([0-9]{1,5})/', $matches[2], $dimensions_matches);
  725. // print_r($dimensions_matches);
  726. $dimensions_value = $dimensions_matches[0];
  727. $data['video']['dimensions'] = array(
  728. 'width' => floatval($dimensions_matches[1]),
  729. 'height' => floatval($dimensions_matches[2])
  730. );
  731. // get the framerate
  732. preg_match('/([0-9\.]+) (fps|tb)\(r\)/', $matches[0], $fps_matches);
  733. $data['video']['frame_rate'] = floatval($fps_matches[1]);
  734. $fps_value = $fps_matches[0];
  735. // get the ratios
  736. preg_match('/\[PAR ([0-9\:\.]+) DAR ([0-9\:\.]+)\]/', $matches[0], $ratio_matches);
  737. if(count($ratio_matches))
  738. {
  739. $data['video']['pixel_aspect_ratio'] = $ratio_matches[1];
  740. $data['video']['display_aspect_ratio'] = $ratio_matches[2];
  741. }
  742. // work out the number of frames
  743. if(isset($data['duration']) && isset($data['video']))
  744. {
  745. // set the total frame count for the video
  746. $data['video']['frame_count'] = ceil($data['duration']['seconds'] * $data['video']['frame_rate']);
  747. // set the framecode
  748. $frames = ceil($data['video']['frame_rate']*($data['duration']['timecode']['seconds']['excess']/10));
  749. $data['duration']['timecode']['frames'] = array();
  750. $data['duration']['timecode']['frames']['exact'] = $data['duration']['timecode']['rounded'].'.'.$frames;
  751. $data['duration']['timecode']['frames']['excess'] = $frames;
  752. $data['duration']['timecode']['frames']['total'] = $data['video']['frame_count'];
  753. }
  754. // formats should be anything left over, let me know if anything else exists
  755. $parts = explode(',', $matches[2]);
  756. $other_parts = array($dimensions_value, $fps_value);
  757. $formats = array();
  758. foreach($parts as $key=>$part)
  759. {
  760. $part = trim($part);
  761. if(!in_array($part, $other_parts))
  762. {
  763. array_push($formats, $part);
  764. }
  765. }
  766. $data['video']['pixel_format'] = $formats[1];
  767. $data['video']['codec'] = $formats[0];
  768. }
  769. // match the audio stream info
  770. preg_match('/Stream(.*): Audio: (.*)/', $buffer, $matches);
  771. if(count($matches) > 0)
  772. {
  773. // setup audio values
  774. $data['audio'] = array(
  775. 'stereo' => -1,
  776. 'sample_rate' => -1,
  777. 'sample_rate' => -1
  778. );
  779. $other_parts = array();
  780. // get the stereo value
  781. preg_match('/(stereo|mono)/i', $matches[0], $stereo_matches);
  782. if(count($stereo_matches))
  783. {
  784. $data['audio']['stereo'] = $stereo_matches[0];
  785. array_push($other_parts, $stereo_matches[0]);
  786. }
  787. // get the sample_rate
  788. preg_match('/([0-9]{3,6}) Hz/', $matches[0], $sample_matches);
  789. if(count($sample_matches))
  790. {
  791. $data['audio']['sample_rate'] = count($sample_matches) ? floatval($sample_matches[1]) : -1;
  792. array_push($other_parts, $sample_matches[0]);
  793. }
  794. // get the bit rate
  795. preg_match('/([0-9]{1,3}) kb\/s/', $matches[0], $bitrate_matches);
  796. if(count($bitrate_matches))
  797. {
  798. $data['audio']['bitrate'] = count($bitrate_matches) ? floatval($bitrate_matches[1]) : -1;
  799. array_push($other_parts, $bitrate_matches[0]);
  800. }
  801. // formats should be anything left over, let me know if anything else exists
  802. $parts = explode(',', $matches[2]);
  803. $formats = array();
  804. foreach($parts as $key=>$part)
  805. {
  806. $part = trim($part);
  807. if(!in_array($part, $other_parts))
  808. {
  809. array_push($formats, $part);
  810. }
  811. }
  812. $data['audio']['codec'] = $formats[0];
  813. }
  814. // check that some data has been obtained
  815. if(!count($data))
  816. {
  817. $data = false;
  818. }
  819. else
  820. {
  821. $data['_raw_info'] = $buffer;
  822. }
  823. // fclose($handle);
  824. // }
  825. // if(is_file($info_file))
  826. // {
  827. // // if the info file exists remove it
  828. // unlink($info_file);
  829. // }
  830. // cache info and return
  831. return $this->_file_info[$hash] = $data;
  832. }
  833. /**
  834. * Determines if your ffmpeg has particular codec support for encode or decode.
  835. *
  836. * @access public
  837. * @param string $codec The name of the codec you are checking for.
  838. * @param const $support PHPVideoToolkit::ENCODE or PHPVideoToolkit::DECODE, depending on which functionality is desired.
  839. * @return mixed. Boolean false if there is no support, true if there is support.
  840. */
  841. public function hasCodecSupport($codec, $support=PHPVideoToolkit::ENCODE)
  842. {
  843. $codec = strtolower($codec);
  844. $data = $this->getFFmpegInfo();
  845. return isset($data['formats'][$codec]) ? $data['formats'][$codec][$support] : false;
  846. }
  847. /**
  848. * Sets the input file that is going to be manipulated.
  849. *
  850. * @access public
  851. * @param string $file The absolute path of the file that is required to be manipulated.
  852. * @param mixed $input_frame_rate If 0 (default) then no input frame rate is set, if false it is automatically retreived, otherwise
  853. * any other integer will be set as the incoming frame rate.
  854. * @return boolean false on error encountered, true otherwise
  855. */
  856. function setInputFile($file, $input_frame_rate=0)
  857. {
  858. $files_length = count($file);
  859. // if the total number of files entered is 1 then only one file is being processed
  860. if($files_length == 1)
  861. {
  862. // check the input file, if there is a %d in there or a similar %03d then the file inputted is a sequence, if neither of those is found
  863. // then qheck to see if the file exists
  864. if(!preg_match('/\%([0-9]+)d/', $file) && strpos($file, '%d') === false && !is_file($file))
  865. {
  866. // input file not valid
  867. return $this->_raiseError('setInputFile_file_existence', array('file'=>$file));
  868. //<- exits
  869. }
  870. $escaped_name = $file;
  871. // $escaped_name = escapeshellarg($files[0]);
  872. $this->_input_file = $escaped_name;
  873. $this->_input_file_id = md5($escaped_name);
  874. // the -inputr is a hack for -r to come before the input
  875. if($input_frame_rate !== 0)
  876. {
  877. $info = $this->getFileInfo();
  878. if(isset($info['video']))
  879. {
  880. if($input_frame_rate === false)
  881. {
  882. $input_frame_rate = $info['video']['frame_rate'];
  883. }
  884. // input frame rate is a command hack
  885. $this->addCommand('-inputr', $input_frame_rate);
  886. }
  887. }
  888. }
  889. else
  890. {
  891. // more than one video is being added as input so we must join them all
  892. call_user_func_array(array(&$this, 'addVideo'), array($file, $input_frame_rate));
  893. }
  894. return true;
  895. }
  896. /**
  897. * A shortcut for converting video to FLV.
  898. *
  899. * @access public
  900. * @param integer $audio_sample_frequency
  901. * @param integer $audio_bitrate
  902. */
  903. function setFormatToFLV($audio_sample_frequency=44100, $audio_bitrate=64)
  904. {
  905. $this->addCommand('-sameq');
  906. $this->setAudioFormat(PHPVIDEOTOOLKIT_FORMAT_MP3);
  907. // adjust the audio rates
  908. $this->setAudioBitRate($audio_bitrate);
  909. $this->setAudioSampleFrequency($audio_sample_frequency);
  910. // set the video format
  911. $this->setFormat(PHPVIDEOTOOLKIT_FORMAT_FLV);
  912. // flag that the flv has to have meta data added after the excecution of this command
  913. // register the post tidy process
  914. $this->registerPostProcess('_addMetaToFLV', $this);
  915. }
  916. /**
  917. * When converting video to FLV the meta data has to be added by a ruby program called FLVTools2.
  918. * This is a second exec call only after the video has been converted to FLV
  919. * http://inlet-media.de/flvtool2
  920. *
  921. * @access private
  922. */
  923. function _addMetaToFLV($files)
  924. {
  925. $file = array_pop($files);
  926. // prepare the command suitable for exec
  927. $exec_string = $this->_prepareCommand(PHPVIDEOTOOLKIT_FLVTOOLS_BINARY, '-U '.$file);
  928. // execute the command
  929. exec($exec_string);
  930. if(is_array($this->_processed[0]))
  931. {
  932. array_push($this->_processed[0], $exec_string);
  933. }
  934. else
  935. {
  936. $this->_processed[0] = array($this->_processed[0], $exec_string);
  937. }
  938. return true;
  939. }
  940. /**
  941. * Streams a FLV file from a given point. You can control bandwidth, cache and session options.
  942. * Inspired by xmoov-php
  943. * @see xmoov-php,
  944. * - @link http://xmoov.com/
  945. * - @author Eric Lorenzo Benjamin jr
  946. * @access public
  947. * @param integer $seek_pos The position in the file to seek to.
  948. * @param array|boolean $bandwidth_options If a boolean value, false then no bandwidth limiting will take place.
  949. * If true then bandwidth limiting will take place with packet_size = 90 and packet_interval = 0.3.
  950. * If an array the following values are default packet_size = 90 and packet_interval = 0.3, you will also
  951. * have to set active = true, ie array('active'=>true, 'packet_size'=>90, 'packet_interval'=>0.3)
  952. * @param boolean $allow_cache If true the file will be allowed to cache in the browser, if false then it won't
  953. * @return boolean
  954. */
  955. public function flvStreamSeek($seek_pos=0, $bandwidth_options=array(), $allow_cache=true)
  956. {
  957. // check for input file
  958. if(!$this->_input_file)
  959. {
  960. // input file not valid
  961. return $this->_raiseError('streamFLV_no_input');
  962. //<- exits
  963. }
  964. // make the pos safe
  965. $seek_pos = intval($seek_pos);
  966. // absorb the bandwidth options
  967. $bandwidth_options = is_array($bandwidth_options) ? array_merge(array('active'=>false, 'packet_size'=>90, 'packet_interval'=>0.3), $bandwidth_options) : array('active'=>$bandwidth_options, 'packet_size'=>90, 'packet_interval'=>0.3);
  968. // if this file is not allowed to be cached send cache headers for all browsers.
  969. if(!$allow_cache)
  970. {
  971. session_cache_limiter('nocache');
  972. header('Expires: Thu, 19 Nov 1981 08:52:00 GMT');
  973. header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
  974. header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
  975. header('Pragma: no-cache');
  976. }
  977. // open file
  978. $handle = fopen($this->_input_file, 'rb');
  979. $file_size = filesize($this->_input_file) - (($seek_pos > 0) ? $seek_pos + 1 : 0);
  980. // send the flv headers
  981. header('Content-Type: video/x-flv');
  982. header('Content-Disposition: attachment; filename="'.basename($this->_input_file).'"');
  983. header('Content-Length: '.$file_size);
  984. // flv format header
  985. if($seek_pos != 0)
  986. {
  987. print('FLV');
  988. print(pack('C', 1));
  989. print(pack('C', 1));
  990. print(pack('N', 9));
  991. print(pack('N', 9));
  992. }
  993. // seek to the required point
  994. if(fseek($handle, $seek_pos) === -1)
  995. {
  996. // input file not valid
  997. return $this->_raiseError('streamFLV_passed_eof');
  998. //<- exits
  999. }
  1000. // if bandwidth control is active then workout the options
  1001. if($bandwidth_options['active'])
  1002. {
  1003. $packet_interval = intval($bandwidth_options['packet_interval']);
  1004. $packet_size = intval($bandwidth_options['packet_size']) * 1042;
  1005. }
  1006. // output the file
  1007. while(!feof($handle))
  1008. {
  1009. // limit the bandwidth
  1010. if($bandwidth_options['active'] && $packet_interval > 0)
  1011. {
  1012. // output the required packet
  1013. $time_start = $this->microtimeFloat();
  1014. echo fread($handle, $packet_size);
  1015. $time_stop = $this->microtimeFloat();
  1016. // delay the output
  1017. $time_difference = $time_stop - $time_start;
  1018. if($time_difference < $packet_interval)
  1019. {
  1020. usleep(($packet_interval * 1000000) - ($time_difference * 1000000));
  1021. }
  1022. }
  1023. // no bandwidth limiting
  1024. else
  1025. {
  1026. echo fread($handle, $file_size);
  1027. }
  1028. }
  1029. // close the file
  1030. fclose($handle);
  1031. return true;
  1032. }
  1033. /**
  1034. * This is an alias for setFormat, but restricts it to audio only formats.
  1035. *
  1036. * @access public
  1037. * @param integer $format A supported audio format.
  1038. * @param integer $audio_sample_frequency
  1039. * @param integer $audio_bitrate
  1040. **/
  1041. function extractAudio($format=PHPVIDEOTOOLKIT_FORMAT_MP3, $audio_sample_frequency=44100, $audio_bitrate=64)
  1042. {
  1043. // check the format is one of the audio formats
  1044. if(!in_array($format, array(PHPVIDEOTOOLKIT_FORMAT_AAC, PHPVIDEOTOOLKIT_FORMAT_AIFF, PHPVIDEOTOOLKIT_FORMAT_MP2, PHPVIDEOTOOLKIT_FORMAT_MP3, PHPVIDEOTOOLKIT_FORMAT_MP4, PHPVIDEOTOOLKIT_FORMAT_MPEG4, PHPVIDEOTOOLKIT_FORMAT_M4A, PHPVIDEOTOOLKIT_FORMAT_WAV)))
  1045. {
  1046. return $this->_raiseError('extractAudio_valid_format', array('format'=>$format));
  1047. //<- exits
  1048. }
  1049. $this->setFormat($format);
  1050. // adjust the audio rates
  1051. $this->setAudioBitRate($audio_bitrate);
  1052. $this->setAudioSampleFrequency($audio_sample_frequency);
  1053. }
  1054. /**
  1055. * Sets the new video format.
  1056. *
  1057. * @access public
  1058. * @param defined $format The format should use one of the defined variables stated below.
  1059. * PHPVIDEOTOOLKIT_FORMAT_3GP2 - 3g2
  1060. * PHPVIDEOTOOLKIT_FORMAT_3GP - 3gp
  1061. * PHPVIDEOTOOLKIT_FORMAT_AAC - aac
  1062. * PHPVIDEOTOOLKIT_FORMAT_AIFF - aiff
  1063. * PHPVIDEOTOOLKIT_FORMAT_AMR - amr
  1064. * PHPVIDEOTOOLKIT_FORMAT_ASF - asf
  1065. * PHPVIDEOTOOLKIT_FORMAT_AVI - avi
  1066. * PHPVIDEOTOOLKIT_FORMAT_FLV - flv
  1067. * PHPVIDEOTOOLKIT_FORMAT_GIF - gif
  1068. * PHPVIDEOTOOLKIT_FORMAT_MJ2 - mj2
  1069. * PHPVIDEOTOOLKIT_FORMAT_MP2 - mp2
  1070. * PHPVIDEOTOOLKIT_FORMAT_MP3 - mp3
  1071. * PHPVIDEOTOOLKIT_FORMAT_MP4 - mp4
  1072. * PHPVIDEOTOOLKIT_FORMAT_MPEG4 - mpeg4
  1073. * PHPVIDEOTOOLKIT_FORMAT_M4A - m4a
  1074. * PHPVIDEOTOOLKIT_FORMAT_MPEG - mpeg
  1075. * PHPVIDEOTOOLKIT_FORMAT_MPEG1 - mpeg1video
  1076. * PHPVIDEOTOOLKIT_FORMAT_MPEG2 - mpeg2video
  1077. * PHPVIDEOTOOLKIT_FORMAT_MPEGVIDEO - mpegvideo
  1078. * PHPVIDEOTOOLKIT_FORMAT_PSP - psp
  1079. * PHPVIDEOTOOLKIT_FORMAT_RM - rm
  1080. * PHPVIDEOTOOLKIT_FORMAT_SWF - swf
  1081. * PHPVIDEOTOOLKIT_FORMAT_VOB - vob
  1082. * PHPVIDEOTOOLKIT_FORMAT_WAV - wav
  1083. * PHPVIDEOTOOLKIT_FORMAT_JPG - jpg
  1084. * @return boolean false on error encountered, true otherwise
  1085. */
  1086. function setFormat($format)
  1087. {
  1088. // validate input
  1089. if(!in_array($format, array(PHPVIDEOTOOLKIT_FORMAT_3GP2, PHPVIDEOTOOLKIT_FORMAT_3GP, PHPVIDEOTOOLKIT_FORMAT_AAC, PHPVIDEOTOOLKIT_FORMAT_AIFF, PHPVIDEOTOOLKIT_FORMAT_AMR, PHPVIDEOTOOLKIT_FORMAT_ASF, PHPVIDEOTOOLKIT_FORMAT_AVI, PHPVIDEOTOOLKIT_FORMAT_FLV, PHPVIDEOTOOLKIT_FORMAT_GIF, PHPVIDEOTOOLKIT_FORMAT_MJ2, PHPVIDEOTOOLKIT_FORMAT_MP2, PHPVIDEOTOOLKIT_FORMAT_MP3, PHPVIDEOTOOLKIT_FORMAT_MP4, PHPVIDEOTOOLKIT_FORMAT_MPEG4, PHPVIDEOTOOLKIT_FORMAT_M4A, PHPVIDEOTOOLKIT_FORMAT_MPEG, PHPVIDEOTOOLKIT_FORMAT_MPEG1, PHPVIDEOTOOLKIT_FORMAT_MPEG2, PHPVIDEOTOOLKIT_FORMAT_MPEGVIDEO, PHPVIDEOTOOLKIT_FORMAT_PSP, PHPVIDEOTOOLKIT_FORMAT_RM, PHPVIDEOTOOLKIT_FORMAT_SWF, PHPVIDEOTOOLKIT_FORMAT_VOB, PHPVIDEOTOOLKIT_FORMAT_WAV, PHPVIDEOTOOLKIT_FORMAT_JPG)))
  1090. {
  1091. return $this->_raiseError('setFormat_valid_format', array('format'=>$format));
  1092. //<- exits
  1093. }
  1094. return $this->addCommand('-f', $format);
  1095. }
  1096. /**
  1097. * Sets the audio sample frequency for audio outputs
  1098. *
  1099. * @access public
  1100. * @param integer $audio_sample_frequency Valid values are 11025, 22050, 44100
  1101. * @return boolean false on error encountered, true otherwise
  1102. */
  1103. function setAudioSampleFrequency($audio_sample_frequency)
  1104. {
  1105. // validate input
  1106. if(!in_array(intval($audio_sample_frequency), array(11025, 22050, 44100)))
  1107. {
  1108. return $this->_raiseError('setAudioSampleFrequency_valid_frequency', array('frequency'=>$audio_sample_frequency));
  1109. //<- exits
  1110. }
  1111. return $this->addCommand('-ar', $audio_sample_frequency);
  1112. }
  1113. /**
  1114. * @access public
  1115. * @depreciated
  1116. * @see PHPVideoToolkit::setAudioCodec()
  1117. */
  1118. public function setAudioFormat($video_format)
  1119. {
  1120. return $this->setAudioCodec($video_format);
  1121. }
  1122. /**
  1123. * Sets the audio format for audio outputs
  1124. *
  1125. * @access public
  1126. * @param integer $audio_format Valid values are PHPVIDEOTOOLKIT_FORMAT_AAC, PHPVIDEOTOOLKIT_FORMAT_AIFF, PHPVIDEOTOOLKIT_FORMAT_AMR, PHPVIDEOTOOLKIT_FORMAT_ASF, PHPVIDEOTOOLKIT_FORMAT_MP2, PHPVIDEOTOOLKIT_FORMAT_MP3, PHPVIDEOTOOLKIT_FORMAT_MP4, PHPVIDEOTOOLKIT_FORMAT_MPEG2, PHPVIDEOTOOLKIT_FORMAT_RM, PHPVIDEOTOOLKIT_FORMAT_WAV
  1127. * @return boolean false on error encountered, true otherwise
  1128. */
  1129. function setAudioCodec($audio_format)
  1130. {
  1131. // validate input
  1132. if(!in_array($audio_format, array(PHPVIDEOTOOLKIT_FORMAT_AAC, PHPVIDEOTOOLKIT_FORMAT_AIFF, PHPVIDEOTOOLKIT_FORMAT_AMR, PHPVIDEOTOOLKIT_FORMAT_ASF, PHPVIDEOTOOLKIT_FORMAT_MP2, PHPVIDEOTOOLKIT_FORMAT_MP3, PHPVIDEOTOOLKIT_FORMAT_MP4, PHPVIDEOTOOLKIT_FORMAT_MPEG2, PHPVIDEOTOOLKIT_FORMAT_RM, PHPVIDEOTOOLKIT_FORMAT_WAV)))
  1133. {
  1134. return $this->_raiseError('setAudioFormat_valid_format', array('format'=>$audio_format));
  1135. //<- exits
  1136. }
  1137. // run a libmp3lame check as it require different mp3 codec
  1138. // updated thanks to Varon for providing the research
  1139. if($audio_format == PHPVIDEOTOOLKIT_FORMAT_MP3)
  1140. {
  1141. $info = $this->getFFmpegInfo();
  1142. if(isset($info['formats']['libmp3lame']))
  1143. {
  1144. // $audio_format = 'liblamemp3';
  1145. $audio_format = 'libmp3lame';
  1146. }
  1147. }
  1148. return $this->addCommand('-acodec', $audio_format);
  1149. }
  1150. /**
  1151. * @access public
  1152. * @depreciated
  1153. * @see PHPVideoToolkit::setVideoCodec()
  1154. */
  1155. public function setVideoFormat($video_format)
  1156. {
  1157. return $this->setVideoCodec($video_format);
  1158. }
  1159. /**
  1160. * Sets the video format for video outputs. This should not be confused with setFormat. setVideoFormat does not generally need to
  1161. * be called unless setting a specific video format for a type of media format. It gets a little confusing...
  1162. *
  1163. * @access public
  1164. * @param integer $video_format Valid values are 11025, 22050, 44100
  1165. * @return boolean false on error encountered, true otherwise
  1166. */
  1167. function setVideoCodec($video_format)
  1168. {
  1169. // validate input
  1170. if(!in_array($video_format, array(PHPVIDEOTOOLKIT_FORMAT_3GP2, PHPVIDEOTOOLKIT_FORMAT_3GP, PHPVIDEOTOOLKIT_FORMAT_AVI, PHPVIDEOTOOLKIT_FORMAT_FLV, PHPVIDEOTOOLKIT_FORMAT_GIF, PHPVIDEOTOOLKIT_FORMAT_MJ2, PHPVIDEOTOOLKIT_FORMAT_MP4, PHPVIDEOTOOLKIT_FORMAT_MPEG4, PHPVIDEOTOOLKIT_FORMAT_M4A, PHPVIDEOTOOLKIT_FORMAT_MPEG, PHPVIDEOTOOLKIT_FORMAT_MPEG1, PHPVIDEOTOOLKIT_FORMAT_MPEG2, PHPVIDEOTOOLKIT_FORMAT_MPEGVIDEO)))
  1171. {
  1172. return $this->_raiseError('setVideoFormat_valid_format', array('format'=>$video_format));
  1173. //<- exits
  1174. }
  1175. return $this->addCommand('-vcodec', $video_format);
  1176. }
  1177. /**
  1178. * Disables audio encoding
  1179. *
  1180. * @access public
  1181. * @return boolean false on error encountered, true otherwise
  1182. */
  1183. function disableAudio()
  1184. {
  1185. return $this->addCommand('-an');
  1186. }
  1187. /**
  1188. * Sets the audio bitrate
  1189. *
  1190. * @access public
  1191. * @param integer $audio_bitrate Valid values are 16, 32, 64
  1192. * @return boolean false on error encountered, true otherwise
  1193. */
  1194. function setAudioBitRate($bitrate)
  1195. {
  1196. // validate input
  1197. if(!in_array(intval($bitrate), array(16, 32, 64, 128)))
  1198. {
  1199. return $this->_raiseError('setAudioBitRate_valid_bitrate', array('bitrate'=>$bitrate));
  1200. //<- exits
  1201. }
  1202. return $this->addCommand('-ab', $bitrate.'kb');
  1203. }
  1204. /**
  1205. * Compiles an array of images into a video. This sets the input file (setInputFile) so you do not need to set it.
  1206. * The images should be a full absolute path to the actual image file.
  1207. * NOTE 1; This copies and renames all the supplied images into a temporary folder so the images don't have to be specifically named. However, when
  1208. * creating the ffmpeg instance you will need to set the absolute path to the temporary folder. The default path is '/tmp/'.
  1209. * NOTE 2; Please make sure all of the images are all of the same type.
  1210. *
  1211. * @access public
  1212. * @param array $images An array of images that are to be joined and converted into a video
  1213. * @param integer $input_frame_rate An integer that will specify the input frame rate for the images.
  1214. * @return boolean Returns false on encountering an error
  1215. */
  1216. function prepareImagesForConversionToVideo($images, $input_frame_rate)
  1217. {
  1218. // http://ffmpeg.mplayerhq.hu/faq.html#TOC3
  1219. // ffmpeg -f image2 -i img%d.jpg /tmp/a.mpg
  1220. if(empty($images))
  1221. {
  1222. return $this->_raiseError('prepareImagesForConversionToVideo_one_img');
  1223. //<- exits
  1224. }
  1225. // loop through and validate existence first before making a temporary copy
  1226. foreach ($images as $key=>$img)
  1227. {
  1228. if(!is_file($img))
  1229. {
  1230. return $this->_raiseError('prepareImagesForConversionToVideo_img_404', array('img'=>$img));
  1231. //<- exits
  1232. }
  1233. }
  1234. if(!is_dir($this->_tmp_directory))
  1235. {
  1236. return $this->_raiseError('generic_temp_404');
  1237. //<- exits
  1238. }
  1239. if(!is_writeable($this->_tmp_directory))
  1240. {
  1241. return $this->_raiseError('generic_temp_writable');
  1242. //<- exits
  1243. }
  1244. // get the number of preceding places for the files based on how many files there are to copy
  1245. $total = count($images);
  1246. // create a temp dir in the temp dir
  1247. $uniqid = $this->unique();
  1248. mkdir($this->_tmp_directory.$uniqid, 0777);
  1249. // loop through, copy and rename specified images to the temp dir
  1250. $ext = false;
  1251. foreach ($images as $key=>$img)
  1252. {
  1253. $file_ext = array_pop(explode('.', $img));
  1254. if($ext !== false && $ext !== $file_ext)
  1255. {
  1256. return $this->_raiseError('prepareImagesForConversionToVideo_img_type');
  1257. //<- exits
  1258. }
  1259. $ext = $file_ext;
  1260. $tmp_file = $this->_tmp_directory.$uniqid.DIRECTORY_SEPARATOR.$this->_tmp_file_prefix.$key.'.'.$ext;
  1261. if(!@copy($img, $tmp_file))
  1262. {
  1263. return $this->_raiseError('prepareImagesForConversionToVideo_img_copy', array('img'=>$img, 'tmpfile'=>$tmp_file));
  1264. //<- exits
  1265. }
  1266. // push the tmp file name into the unlinks so they can be deleted on class destruction
  1267. array_push($this->_unlink_files, $tmp_file);
  1268. }
  1269. // the inputr is a hack for -r to come before the input
  1270. $this->addCommand('-inputr', $input_frame_rate);
  1271. // exit;
  1272. // add the directory to the unlinks
  1273. array_push($this->_unlink_dirs, $this->_tmp_directory.$uniqid);
  1274. // get the input file format
  1275. $file_iteration = $this->_tmp_file_prefix.'%d.'.$ext;
  1276. // set the input filename
  1277. return $this->setInputFile($this->_tmp_directory.$uniqid.DIRECTORY_SEPARATOR.$file_iteration);
  1278. }
  1279. /**
  1280. * Sets the video bitrate
  1281. *
  1282. * @access public
  1283. * @param integer $bitrate
  1284. * @return boolean
  1285. */
  1286. function setVideoBitRate($bitrate)
  1287. {
  1288. $bitrate = intval($bitrate);
  1289. return $this->addCommand('-b', $bitrate.'kb');
  1290. }
  1291. /**
  1292. * Sets the amount of time an animated gif output will loop
  1293. *
  1294. * @access public
  1295. * @param integer $loop_count If false the gif will not loop, if 0 it will loop endlessly, any other number it will loop that amount.
  1296. */
  1297. function setGifLoops($loop_count)
  1298. {
  1299. if($loop_count !== false)
  1300. {
  1301. $this->addCommand('-loop_output', $loop_count);
  1302. }
  1303. }
  1304. /**
  1305. * @access public
  1306. * @depreciated
  1307. * @see PHPVideoToolkit::setVideoDimensions()
  1308. */
  1309. public function setVideoOutputDimensions($width, $height=null)
  1310. {
  1311. return $this->setVideoDimensions($width, $height);
  1312. }
  1313. /**
  1314. * Sets the video output dimensions (in pixels)
  1315. *
  1316. * @access public
  1317. * @param mixed $width If an integer height also has to be specified, otherwise you can use one of the class constants
  1318. * PHPVIDEOTOOLKIT_SIZE_SAS = Same as input source
  1319. * PHPVIDEOTOOLKIT_SIZE_SQCIF = 128 x 96
  1320. * PHPVIDEOTOOLKIT_SIZE_QCIF = 176 x 144
  1321. * PHPVIDEOTOOLKIT_SIZE_CIF = 352 x 288
  1322. * PHPVIDEOTOOLKIT_SIZE_4CIF = 704 x 576
  1323. * PHPVIDEOTOOLKIT_SIZE_QQVGA = 160 x 120
  1324. * PHPVIDEOTOOLKIT_SIZE_QVGA = 320 x 240
  1325. * PHPVIDEOTOOLKIT_SIZE_VGA = 640 x 480
  1326. * PHPVIDEOTOOLKIT_SIZE_SVGA = 800 x 600
  1327. * PHPVIDEOTOOLKIT_SIZE_XGA = 1024 x 768
  1328. * PHPVIDEOTOOLKIT_SIZE_UXGA = 1600 x 1200
  1329. * PHPVIDEOTOOLKIT_SIZE_QXGA = 2048 x 1536
  1330. * PHPVIDEOTOOLKIT_SIZE_SXGA = 1280 x 1024
  1331. * PHPVIDEOTOOLKIT_SIZE_QSXGA = 2560 x 2048
  1332. * PHPVIDEOTOOLKIT_SIZE_HSXGA = 5120 x 4096
  1333. * PHPVIDEOTOOLKIT_SIZE_WVGA = 852 x 480
  1334. * PHPVIDEOTOOLKIT_SIZE_WXGA = 1366 x 768
  1335. * PHPVIDEOTOOLKIT_SIZE_WSXGA = 1600 x 1024
  1336. * PHPVIDEOTOOLKIT_SIZE_WUXGA = 1920 x 1200
  1337. * PHPVIDEOTOOLKIT_SIZE_WOXGA = 2560 x 1600
  1338. * PHPVIDEOTOOLKIT_SIZE_WQSXGA = 3200 x 2048
  1339. * PHPVIDEOTOOLKIT_SIZE_WQUXGA = 3840 x 2400
  1340. * PHPVIDEOTOOLKIT_SIZE_WHSXGA = 6400 x 4096
  1341. * PHPVIDEOTOOLKIT_SIZE_WHUXGA = 7680 x 4800
  1342. * PHPVIDEOTOOLKIT_SIZE_CGA = 320 x 200
  1343. * PHPVIDEOTOOLKIT_SIZE_EGA = 640 x 350
  1344. * PHPVIDEOTOOLKIT_SIZE_HD480 = 852 x 480
  1345. * PHPVIDEOTOOLKIT_SIZE_HD720 = 1280 x 720
  1346. * PHPVIDEOTOOLKIT_SIZE_HD1080 = 1920 x 1080
  1347. * @param integer $height
  1348. * @return boolean
  1349. */
  1350. function setVideoDimensions($width, $height=null)
  1351. {
  1352. if($height === null || $height === true)
  1353. {
  1354. // validate input
  1355. if(!in_array($width, array(PHPVIDEOTOOLKIT_SIZE_SAS, PHPVIDEOTOOLKIT_SIZE_SQCIF, PHPVIDEOTOOLKIT_SIZE_QCIF, PHPVIDEOTOOLKIT_SIZE_CIF, PHPVIDEOTOOLKIT_SIZE_4CIF, PHPVIDEOTOOLKIT_SIZE_QQVGA, PHPVIDEOTOOLKIT_SIZE_QVGA, PHPVIDEOTOOLKIT_SIZE_VGA, PHPVIDEOTOOLKIT_SIZE_SVGA, PHPVIDEOTOOLKIT_SIZE_XGA, PHPVIDEOTOOLKIT_SIZE_UXGA, PHPVIDEOTOOLKIT_SIZE_QXGA, PHPVIDEOTOOLKIT_SIZE_SXGA, PHPVIDEOTOOLKIT_SIZE_QSXGA, PHPVIDEOTOOLKIT_SIZE_HSXGA, PHPVIDEOTOOLKIT_SIZE_WVGA, PHPVIDEOTOOLKIT_SIZE_WXGA, PHPVIDEOTOOLKIT_SIZE_WSXGA, PHPVIDEOTOOLKIT_SIZE_WUXGA, PHPVIDEOTOOLKIT_SIZE_WOXGA, PHPVIDEOTOOLKIT_SIZE_WQSXGA, PHPVIDEOTOOLKIT_SIZE_WQUXGA, PHPVIDEOTOOLKIT_SIZE_WHSXGA, PHPVIDEOTOOLKIT_SIZE_WHUXGA, PHPVIDEOTOOLKIT_SIZE_CGA, PHPVIDEOTOOLKIT_SIZE_EGA, PHPVIDEOTOOLKIT_SIZE_HD480, PHPVIDEOTOOLKIT_SIZE_HD720, PHPVIDEOTOOLKIT_SIZE_HD1080)))
  1356. {
  1357. return $this->_raiseError('setVideoOutputDimensions_valid_format', array('format'=>$format));
  1358. //<- exits
  1359. }
  1360. if($width === PHPVIDEOTOOLKIT_SIZE_SAS)
  1361. {
  1362. // and override is made so no command is added in the hope that ffmpeg will just output the source
  1363. if($height === true)
  1364. {
  1365. return true;
  1366. }
  1367. // get the file info
  1368. $info = $this->getFileInfo();
  1369. if(!isset($info['video']) || !isset($info['video']['dimensions']))
  1370. {
  1371. return $this->_raiseError('setVideoOutputDimensions_sas_dim');
  1372. }
  1373. else
  1374. {
  1375. $width = $info['video']['dimensions']['width'].'x'.$info['video']['dimensions']['height'];
  1376. }
  1377. }
  1378. }
  1379. else
  1380. {
  1381. // check that the width and height are even
  1382. if($width % 2 !== 0 || $height % 2 !== 0)
  1383. {
  1384. return $this->_raiseError('setVideoOutputDimensions_valid_integer');
  1385. //<- exits
  1386. }
  1387. $width = $width.'x'.$height;
  1388. }
  1389. $this->addCommand('-s', $width);
  1390. return true;
  1391. }
  1392. /**
  1393. * Sets the video aspect ratio
  1394. *
  1395. * @access public
  1396. * @param string|integer $ratio Valid values are PHPVIDEOTOOLKIT_RATIO_STANDARD, PHPVIDEOTOOLKIT_RATIO_WIDE, PHPVIDEOTOOLKIT_RATIO_CINEMATIC, or '4:3', '16:9', '1.85'
  1397. * @return boolean
  1398. */
  1399. function setVideoAspectRatio($ratio)
  1400. {
  1401. if(!in_array($ratio, array(PHPVIDEOTOOLKIT_RATIO_STANDARD, PHPVIDEOTOOLKIT_RATIO_WIDE, PHPVIDEOTOOLKIT_RATIO_CINEMATIC)))
  1402. {
  1403. return $this->_raiseError('setVideoAspectRatio_valid_ratio', array('ratio'=>$ratio));
  1404. }
  1405. $this->addCommand('-aspect', $ratio);
  1406. return true;
  1407. }
  1408. /**
  1409. * Sets the frame rate of the video
  1410. *
  1411. * @access public
  1412. * @param string|integer $fps 1 being 1 frame per second, 1:2 being 0.5 frames per second
  1413. * @return boolean
  1414. */
  1415. function setVideoFrameRate($fps)
  1416. {
  1417. return $this->addCommand('-r', $fps);
  1418. }
  1419. /**
  1420. * Extracts frames from a video.
  1421. * (Note; If set to 1 and the duration set by $extract_begin_timecode and $extract_end_timecode is equal to 1 you get more than one frame.
  1422. * For example if you set $extract_begin_timecode='00:00:00' and $extract_end_timecode='00:00:01' you might expect because the time span is
  1423. * 1 second only to get one frame if you set $frames_per_second=1. However this is not correct. The timecode you set in $extract_begin_timecode
  1424. * acts as the beginning frame. Thus in this example the first frame exported will be from the very beginning of the video, the video will
  1425. * then move onto the next frame and export a frame there. Therefore if you wish to export just one frame from one position in the video,
  1426. * say 1 second in you should set $extract_begin_timecode='00:00:01' and set $extract_end_timecode='00:00:01'.)
  1427. *
  1428. * @access public
  1429. * @param string $extract_begin_timecode A timecode (hh:mm:ss.fn - you can change the timecode format by changing the $timecode_format param
  1430. * it obeys the formatting of PHPVideoToolkit::formatTimecode(), see below for more info)
  1431. * @param string|integer|boolean $extract_end_timecode A timecode (hh:mm:ss.fn - you can change the timecode format by changing the $timecode_format param
  1432. * it obeys the formatting of PHPVideoToolkit::formatTimecode(), see below for more info), or false
  1433. * if all frames from the begin timecode are to be exported. (Boolean added by Matthias. Thanks. 12th March 2007)
  1434. * @param boolean|integer $frames_per_second The number of frames per second to extract. If left as default false, then the number of frames per second
  1435. * will be automagically gained from PHPVideoToolkit::fileGetInfo();
  1436. * @param boolean|integer $frame_limit Frame limiter. If set to false then all the frames will be exported from the given time codes, however
  1437. * if you wish to set a export limit to the number of frames that are exported you can set an integer. For example; if you set
  1438. * $extract_begin_timecode='00:00:11.01', $extract_end_timecode='00:01:10.01', $frames_per_second=1, you will get one frame for every second
  1439. * in the video between 00:00:11 and 00:01:10 (ie 60 frames), however if you ant to artificially limit this to exporting only ten frames
  1440. * then you set $frame_limit=10. You could of course alter the timecode to reflect you desired frame number, however there are situations
  1441. * when a shortcut such as this is useful and necessary.
  1442. * @param integer $timecode_format The format of the $extract_begin_timecode and $extract_end_timecode timecodes are being given in.
  1443. * default '%hh:%mm:%ss'
  1444. * - %hh (hours) representative of hours
  1445. * - %mm (minutes) representative of minutes
  1446. * - %ss (seconds) representative of seconds
  1447. * - %fn (frame number) representative of frames (of the current second, not total frames)
  1448. * - %ms (milliseconds) representative of milliseconds (of the current second, not total milliseconds) (rounded to 3 decimal places)
  1449. * - %ft (frames total) representative of total frames (ie frame number)
  1450. * - %st (seconds total) representative of total seconds (rounded).
  1451. * - %sf (seconds floored) representative of total seconds (floored).
  1452. * - %mt (milliseconds total) representative of total milliseconds. (rounded to 3 decimal places)
  1453. * Thus you could use an alternative, '%hh:%mm:%ss:%ms', or '%hh:%mm:%ss' dependent on your usage.
  1454. */
  1455. function extractFrames($extract_begin_timecode, $extract_end_timecode, $frames_per_second=false, $frame_limit=false, $timecode_format='%hh:%mm:%ss.%fn', $check_frames_exist=true)
  1456. {
  1457. // are we autoguessing the frame rate?
  1458. if($frames_per_second === false || $check_frames_exist)
  1459. {
  1460. // get the file info, will exit if no input has been set
  1461. $info = $this->getFileInfo();
  1462. if(!isset($info['video']))
  1463. {
  1464. // the input has not returned any video data so the frame rate can not be guessed
  1465. return $this->_raiseError('extractFrame_video_frame_rate_404');
  1466. }
  1467. }
  1468. // check to see if we have to get the fps of the input movie
  1469. if($frames_per_second === false)
  1470. {
  1471. $frames_per_second = $info['video']['frame_rate'];
  1472. }
  1473. // check if frame exists
  1474. if($check_frames_exist)
  1475. {
  1476. if($info['video']['frame_count'] < $this->formatTimecode($extract_end_timecode, $timecode_format, '%ft', $frames_per_second))
  1477. {
  1478. // the input has not returned any video data so the frame rate can not be guessed
  1479. return $this->_raiseError('extractFrames_video_end_frame_count');
  1480. }
  1481. else if($info['video']['frame_count'] < $this->formatTimecode($extract_begin_timecode, $timecode_format, '%ft', $frames_per_second))
  1482. {
  1483. // the input has not returned any video data so the frame rate can not be guessed
  1484. return $this->_raiseError('extractFrames_video_begin_frame_count');
  1485. }
  1486. }
  1487. // disable audio output
  1488. $this->disableAudio();
  1489. // format the begin timecode if the timecode format is not already ok.
  1490. if($timecode_format !== '%hh:%mm:%ss.%ms')
  1491. {
  1492. $extract_begin_timecode = $this->formatTimecode($extract_begin_timecode, $timecode_format, '%hh:%mm:%ss.%ms', $frames_per_second);
  1493. }
  1494. $this->addCommand('-ss', $extract_begin_timecode);
  1495. // added by Matthias on 12th March 2007
  1496. // allows for exporting the entire timeline
  1497. if($extract_end_timecode !== false)
  1498. {
  1499. // format the end timecode if the timecode format is not already ok.
  1500. if($timecode_format !== '%hh:%mm:%ss.%ms')
  1501. {
  1502. $extract_end_timecode = $this->formatTimecode($extract_end_timecode, $timecode_format, '%hh:%mm:%ss.%ms', $frames_per_second);
  1503. }
  1504. $this->addCommand('-t', $extract_end_timecode);
  1505. }
  1506. // set the output frame rate
  1507. $this->setVideoFrameRate($frames_per_second);
  1508. // do we need to limit the number of frames outputted?
  1509. if($frame_limit !== false)
  1510. {
  1511. $this->addCommand('-vframes', $frame_limit);
  1512. }
  1513. $this->_image_output_timecode_start = $extract_begin_timecode;
  1514. $this->_image_output_timecode_fps = $frames_per_second;
  1515. }
  1516. /**
  1517. * Extracts exactly one frame
  1518. *
  1519. * @access public
  1520. * @uses $toolkit->extractFrames
  1521. * @param string $frame_timecode A timecode (hh:mm:ss.fn) where fn is the frame number of that second
  1522. * @param integer|boolean $frames_per_second The frame rate of the movie. If left as the default, false. We will use PHPVideoToolkit::getFileInfo() to get
  1523. * the actual frame rate. It is recommended that it is left as false because an incorrect frame rate may produce unexpected results.
  1524. * @param integer $timecode_format The format of the $extract_begin_timecode and $extract_end_timecode timecodes are being given in.
  1525. * default '%hh:%mm:%ss'
  1526. * - %hh (hours) representative of hours
  1527. * - %mm (minutes) representative of minutes
  1528. * - %ss (seconds) representative of seconds
  1529. * - %fn (frame number) representative of frames (of the current second, not total frames)
  1530. * - %ms (milliseconds) representative of milliseconds (of the current second, not total milliseconds) (rounded to 3 decimal places)
  1531. * - %ft (frames total) representative of total frames (ie frame number)
  1532. * - %st (seconds total) representative of total seconds (rounded).
  1533. * - %sf (seconds floored) representative of total seconds (floored).
  1534. * - %mt (milliseconds total) representative of total milliseconds. (rounded to 3 decimal places)
  1535. * Thus you could use an alternative, '%hh:%mm:%ss:%ms', or '%hh:%mm:%ss' dependent on your usage.
  1536. * @param boolean $check_frame_exists Makes an explicit check to see if the frame exists, default = true.
  1537. * Thanks to Istvan Szakacs for suggesting this check. Note, to improve performance disable this check.
  1538. */
  1539. function extractFrame($frame_timecode, $frames_per_second=false, $frame_timecode_format='%hh:%mm:%ss.%fn', $check_frame_exists=true)
  1540. {
  1541. // get the file info, will exit if no input has been set
  1542. if($check_frame_exists || $frames_per_second === false)
  1543. {
  1544. $info = $this->getFileInfo();
  1545. if($info === false || !isset($info['video']))
  1546. {
  1547. // the input has not returned any video data so the frame rate can not be guessed
  1548. return $this->_raiseError('extractFrame_video_info_404');
  1549. }
  1550. }
  1551. // are we autoguessing the frame rate?
  1552. if($frames_per_second === false)
  1553. {
  1554. if(!isset($info['video']['frame_rate']))
  1555. {
  1556. // the input has not returned any video data so the frame rate can not be guessed
  1557. return $this->_raiseError('extractFrame_video_frame_rate_404');
  1558. }
  1559. $frames_per_second = $info['video']['frame_rate'];
  1560. }
  1561. // check if frame exists
  1562. if($check_frame_exists)
  1563. {
  1564. if($info['video']['frame_count'] < $this->formatTimecode($frame_timecode, $frame_timecode_format, '%ft', $frames_per_second))
  1565. {
  1566. // the input has not returned any video data so the frame rate can not be guessed
  1567. return $this->_raiseError('extractFrame_video_frame_count');
  1568. }
  1569. }
  1570. // format the frame details if the timecode format is not already ok.
  1571. if($frame_timecode_format !== '%hh:%mm:%ss.%ms')
  1572. {
  1573. $frame_timecode = $this->formatTimecode($frame_timecode, $frame_timecode_format, '%hh:%mm:%ss.%ms', $frames_per_second);
  1574. }
  1575. $this->_single_frame_extraction = 1;
  1576. // we will limit the number of frames produced so the desired frame is the last image
  1577. // this way we limit the cpu usage of ffmpeg
  1578. // Thanks to Istvan Szakacs for pointing out that ffmpeg can export frames using the -ss hh:mm:ss[.xxx]
  1579. // it has saved a lot of cpu intensive processes.
  1580. $this->extractFrames($frame_timecode, $frame_timecode, $frames_per_second, 1, '%hh:%mm:%ss.%ms', false);
  1581. // register the post tidy process
  1582. // $this->registerPostProcess('_extractFrameTidy', $this);
  1583. }
  1584. // /**
  1585. // * Tidies up after ffmpeg exports all frames from one second of video.
  1586. // *
  1587. // * @access public
  1588. // * @uses $toolkit->extractFrames
  1589. // * @param string $frame_timecode A timecode (hh:mm:ss.fn) where fn is the frame number of that second
  1590. // * @param integer|boolean $frames_per_second The frame rate of the movie. If left as the default, false. We will use PHPVideoToolkit::getFileInfo() to get
  1591. // * the actual frame rate. It is recommended that it is left as false because an incorrect frame rate may produce unexpected results.
  1592. // */
  1593. // function _extractFrameTidy(&$files)
  1594. // {
  1595. // $frame_number = 1;
  1596. // $frame_file = array();
  1597. // // print_r($files);
  1598. // foreach($files as $file=>$filename)
  1599. // {
  1600. // // print_R(array($this->_single_frame_extraction, $frame_number));
  1601. // if($this->_single_frame_extraction == $frame_number)
  1602. // {
  1603. // // leave this file alone as it is the required frame
  1604. // $frame_file[$file] = $filename;
  1605. // }
  1606. // else
  1607. // {
  1608. // // add the frame to the unlink files list
  1609. // array_push($this->_unlink_files, $file);
  1610. // }
  1611. // $frame_number += 1;
  1612. // }
  1613. // // print_r($frame_file);
  1614. // // update the files list
  1615. // $files = $frame_file;
  1616. // return true;
  1617. // }
  1618. /**
  1619. * Adds a watermark to the outputted files. This effects both video and image output.
  1620. *
  1621. * @access public
  1622. * @param string $watermark_url The absolute path to the watermark image.
  1623. * @param string $vhook The absolute path to the ffmpeg vhook watermark library.
  1624. */
  1625. function addWatermark($watermark_url, $vhook=PHPVIDEOTOOLKIT_FFMPEG_WATERMARK_VHOOK)
  1626. {
  1627. // check to see if the ffmpeg binary has support for vhooking
  1628. if(!$this->hasVHookSupport())
  1629. {
  1630. return $this->_raiseError('addWatermark_vhook_disabled');
  1631. }
  1632. // does the file exist?
  1633. if(!is_file($watermark_url))
  1634. {
  1635. return $this->_raiseError('addWatermark_img_404', array('watermark'=>$watermark_url));
  1636. }
  1637. $this->addCommand('-vhook', $vhook.' -f '.$watermark_url);
  1638. }
  1639. /**
  1640. * Adds a watermark to the outputted image files using the PHP GD module.
  1641. * This effects only image output.
  1642. *
  1643. * @access public
  1644. * @param string $watermark_url The absolute path to the watermark image.
  1645. */
  1646. function addGDWatermark($watermark_url, $options=array('x-offset'=>0, 'y-offset'=>0, 'position'=>'bottom-right'))
  1647. {
  1648. // does the file exist?
  1649. if(!is_file($watermark_url))
  1650. {
  1651. return $this->_raiseError('addWatermark_img_404', array('watermark'=>$watermark_url));
  1652. }
  1653. // save the watermark_url
  1654. $this->_watermark_url = $watermark_url;
  1655. $this->_watermark_options = array_merge(array('x-offset'=>0, 'y-offset'=>0, 'position'=>'bottom-right'), $options);
  1656. // register the post process
  1657. $this->registerPostProcess('_addGDWatermark', $this);
  1658. }
  1659. /**
  1660. * Adds watermark to any outputted images via GD instead of using vhooking.
  1661. *
  1662. * @access private
  1663. * @param array $files An array of image files.
  1664. * @return array
  1665. */
  1666. function _addGDWatermark($files)
  1667. {
  1668. // create the watermark resource and give it alpha blending
  1669. $info = pathinfo($this->_watermark_url);
  1670. switch(strtolower($info['extension']))
  1671. {
  1672. case 'jpeg' :
  1673. case 'jpg' :
  1674. $watermark = imagecreatefromjpeg($this->_watermark_url);
  1675. break;
  1676. case 'gif' :
  1677. $watermark = imagecreatefromgif($this->_watermark_url);
  1678. break;
  1679. case 'png' :
  1680. $watermark = imagecreatefrompng($this->_watermark_url);
  1681. break;
  1682. default :
  1683. return false;
  1684. }
  1685. imagealphablending($watermark, true);
  1686. imagesavealpha($watermark, true);
  1687. // get the watermark dimensions
  1688. $watermark_width = imagesx($watermark);
  1689. $watermark_height = imagesy($watermark);
  1690. // $image = imagecreatetruecolor($watermark_width, $watermark_height);
  1691. // loop and watermark each file
  1692. $blended_files = array();
  1693. foreach($files as $file=>$filename)
  1694. {
  1695. // detect the file extension and create the resource from them appropriate function
  1696. $info = pathinfo($file);
  1697. $quality = $output_function = null;
  1698. switch(strtolower($info['extension']))
  1699. {
  1700. case 'jpeg' :
  1701. case 'jpg' :
  1702. $quality = 80;
  1703. $output_function = 'imagejpeg';
  1704. $image = imagecreatefromjpeg($file);
  1705. break;
  1706. case 'gif' :
  1707. $output_function = 'imagegif';
  1708. $image = imagecreatefromgif($file);
  1709. break;
  1710. case 'png' :
  1711. $quality = 9;
  1712. $output_function = 'imagepng';
  1713. $image = imagecreatefrompng($file);
  1714. break;
  1715. default :
  1716. continue 1;
  1717. }
  1718. // the dimensions will/should be the same for each image however still best to check
  1719. $image_width = imagesx($image);
  1720. $image_height = imagesy($image);
  1721. // calculate where to position the watermark
  1722. $dest_x = 0;
  1723. $dest_y = 0;
  1724. switch($this->_watermark_options['position'])
  1725. {
  1726. case 'top-left' :
  1727. $dest_x = 0;
  1728. $dest_y = 0;
  1729. break;
  1730. case 'top-middle' :
  1731. $dest_x = ($image_width-$watermark_width)/2;
  1732. $dest_y = 0;
  1733. break;
  1734. case 'top-right' :
  1735. $dest_x = $image_width-$watermark_width;
  1736. $dest_y = 0;
  1737. break;
  1738. case 'center-left' :
  1739. $dest_x = 0;
  1740. $dest_y = ($image_height-$watermark_height)/2;
  1741. break;
  1742. case 'center-middle' :
  1743. $dest_x = ($image_width-$watermark_width)/2;
  1744. $dest_y = ($image_height-$watermark_height)/2;
  1745. break;
  1746. case 'center-right' :
  1747. $dest_x = $image_width-$watermark_width;
  1748. $dest_y = ($image_height-$watermark_height)/2;
  1749. break;
  1750. case 'bottom-left' :
  1751. $dest_x = 0;
  1752. $dest_y = $image_height - $watermark_height;
  1753. break;
  1754. case 'bottom-middle' :
  1755. $dest_x = ($image_width-$watermark_width)/2;
  1756. $dest_y = $image_height - $watermark_height;
  1757. break;
  1758. case 'bottom-right' :
  1759. default :
  1760. $dest_x = $image_width-$watermark_width;
  1761. $dest_y = $image_height - $watermark_height;
  1762. break;
  1763. }
  1764. $dest_x += $this->_watermark_options['x-offset'];
  1765. $dest_y += $this->_watermark_options['y-offset'];
  1766. // copy the watermark to the new image
  1767. // print_r(array($this->_watermark_url, $image, $watermark, $dest_x, $dest_y, 0, 0, $watermark_width, $watermark_height));
  1768. imagecopy($image, $watermark, $dest_x, $dest_y, 0, 0, $watermark_width, $watermark_height);
  1769. // delete the old image
  1770. unlink($file);
  1771. // save the new image in place of the old
  1772. $output_function($image, $file, $quality);
  1773. // remove the image resouce
  1774. imagedestroy($image);
  1775. array_push($blended_files, $file);
  1776. }
  1777. // remove the watermark resource
  1778. imagedestroy($watermark);
  1779. return $blended_files;
  1780. }
  1781. // /**
  1782. // * This will overlay an audio file over the top of a video file
  1783. // **/
  1784. // function overlayAudio($audio_file)
  1785. // {
  1786. // $this->addCommand('-newaudio', '');
  1787. // }
  1788. /**
  1789. * This will adjust the audio volume.
  1790. *
  1791. * @access public
  1792. * @param integer $vol 256 = normal
  1793. **/
  1794. function adjustVolume($vol=256)
  1795. {
  1796. $this->addCommand('-vol', '');
  1797. }
  1798. /**
  1799. * This process will combine the original input video with the video specified by this function.
  1800. * This function accepts more than one video as arguments. They will be added in order of the arguments.
  1801. * ie. input_video -> video1 -> video2 etc
  1802. * The process of doing this can take a long time as each incoming video has to be first converted
  1803. * into a format that accepts joining. The default joining codec is "mpg". However for almost lossless
  1804. * quality you can use the "yuv4mpegpipe" format. This is of course dependent upon your ffmpeg binary.
  1805. * You can check to see if you server supports yuv4mpegpipe by typing "ffmpeg -formats" into the
  1806. * command line. If you want to use the yuv4mpegpipe format you can add the flag, FFMPEG_USE_HQ_JOIN to the
  1807. * end of the video inputs. WARNING: High Quality joins will take longer to process. (well duh!)
  1808. *
  1809. * @access public
  1810. * @param $video1, $video2, $video3... $video(n) Paths of videos to attach to the input video.
  1811. * @param $flag integer FFMPEG_USE_HQ_JOIN If you wish to use the yuv4mpegpipe format for join add this to the end of the video list.
  1812. */
  1813. function addVideo()
  1814. {
  1815. $videos = func_get_args();
  1816. $videos_length = count($videos);
  1817. // is last arg the hq join flag
  1818. // check to see if a starter file has been added, if not set the input as an array
  1819. if($this->_input_file === null)
  1820. {
  1821. $this->_input_file = array();
  1822. }
  1823. // if the input file is already set as a string that means as start file has been added so absorb into the input array
  1824. else if(is_string($this->_input_file))
  1825. {
  1826. $this->_input_file = array($this->_input_file);
  1827. }
  1828. foreach($videos as $key=>$file)
  1829. {
  1830. if(!preg_match('/\%([0-9]+)d/', $file) && strpos($file, '%d') === false && !is_file($file))
  1831. {
  1832. // input file not valid
  1833. return $this->_raiseError('addVideo_file_404', array('file'=>$file));
  1834. //<- exits
  1835. }
  1836. array_push($this->_input_file, $file);
  1837. // array_push($this->_input_file, escapeshellarg($file));
  1838. }
  1839. }
  1840. /**
  1841. * @access public
  1842. * @uses addVideo()
  1843. */
  1844. function addVideos()
  1845. {
  1846. $videos = func_get_args();
  1847. call_user_func_array(array(&$this, 'addVideo'), $videos);
  1848. }
  1849. /**
  1850. * Sets the output.
  1851. *
  1852. * @access public
  1853. * @param string $output_directory The directory to output the command output to
  1854. * @param string $output_name The filename to output to.
  1855. * (Note; if you are outputting frames from a video then you will need to add an extra item to the output_name. The output name you set is required
  1856. * to contain '%d'. '%d' is replaced by the image number. Thus entering setting output_name $output_name='img%d.jpg' will output
  1857. * 'img1.jpg', 'img2.jpg', etc... However 'img%03d.jpg' generates `img001.jpg', `img002.jpg', etc...)
  1858. * @param boolean $overwrite_mode Accepts one of the following class constants
  1859. * - PHPVIDEOTOOLKIT_OVERWRITE_FAIL - This produces an error if there is a file conflict and the processing is halted.
  1860. * - PHPVIDEOTOOLKIT_OVERWRITE_PRESERVE - This continues with the processing but no file overwrite takes place. The processed file is left in the temp directory
  1861. * for you to manually move.
  1862. * - PHPVIDEOTOOLKIT_OVERWRITE_EXISTING - This will replace any existing files with the freshly processed ones.
  1863. * - PHPVIDEOTOOLKIT_OVERWRITE_UNIQUE - This will appended every output with a unique hash so that the filesystem is preserved.
  1864. * @return boolean false on error encountered, true otherwise
  1865. */
  1866. function setOutput($output_directory, $output_name, $overwrite_mode=PHPVIDEOTOOLKIT_OVERWRITE_FAIL)
  1867. {
  1868. // check if directoy exists
  1869. if(!is_dir($output_directory))
  1870. {
  1871. return $this->_raiseError('setOutput_output_dir_404', array('dir'=>$output_directory));
  1872. //<- exits
  1873. }
  1874. // check if directory is writeable
  1875. if(!is_writable($output_directory))
  1876. {
  1877. return $this->_raiseError('setOutput_output_dir_writable', array('dir'=>$output_directory));
  1878. //<- exits
  1879. }
  1880. $process_name = '';
  1881. // check to see if a output delimiter is set
  1882. $has_d = preg_match('/\%([0-9]+)d/', $output_name) || strpos($output_name, '%d') !== false;
  1883. if($has_d)
  1884. {
  1885. return $this->_raiseError('setOutput_%d_depreciated');
  1886. //<- exits
  1887. }
  1888. else
  1889. {
  1890. // determine if the extension is an image. If it is then we will be extracting frames so check for %d
  1891. $output_name_info = pathinfo($output_name);
  1892. $is_image = in_array(strtolower($output_name_info['extension']), array('jpg', 'jpeg', 'png'));
  1893. $is_gif = strtolower($output_name_info['extension']) === 'gif';
  1894. // NOTE: for now we'll just stick to the common image formats, SUBNOTE: gif is ignore because ffmpeg can create animated gifs
  1895. if($this->_single_frame_extraction !== null && strpos($output_name, '%timecode') !== false && !(preg_match('/\%index/', $output_name) || strpos($output_name, '%index') !== false) && $is_image)
  1896. {
  1897. return $this->_raiseError('setOutput_%_missing');
  1898. //<- exits
  1899. }
  1900. $process_name = '.'.$output_name_info['extension'];
  1901. // print_r(array($is_image, ($this->_single_frame_extraction !== null && $is_gif)));
  1902. if($is_image || ($this->_single_frame_extraction !== null && $is_gif))
  1903. {
  1904. $process_name = '-%12d'.$process_name;
  1905. }
  1906. }
  1907. // set the output address
  1908. $this->_output_address = $output_directory.$output_name;
  1909. // set the processing address in the temp folder so it does not conflict with any other conversions
  1910. $this->_process_address = $this->_tmp_directory.$this->unique().$process_name;
  1911. $this->_overwrite_mode = $overwrite_mode;
  1912. return true;
  1913. }
  1914. /**
  1915. * Sets a constant quality value to the encoding. (but a variable bitrate)
  1916. *
  1917. * @param integer $quality The quality to adhere to. 100 is highest quality, 1 is the lowest quality
  1918. */
  1919. function setConstantQuality($quality)
  1920. {
  1921. // interpret quality into ffmpeg value
  1922. $quality = 31 - round(($quality/100) * 31);
  1923. if($quality > 31)
  1924. {
  1925. $quality = 31;
  1926. }
  1927. else if($quality < 1)
  1928. {
  1929. $quality = 1;
  1930. }
  1931. $this->addCommand('-qscale', $quality);
  1932. }
  1933. /**
  1934. * Translates a number of seconds to a timecode.
  1935. * NOTE: this is now a depreciated, use formatSeconds() instead.
  1936. *
  1937. * @depreciated Use formatSeconds() instead.
  1938. * @access public
  1939. * @uses PHPVideoToolkit::formatSeconds()
  1940. * @param integer $input_seconds The number of seconds you want to calculate the timecode for.
  1941. */
  1942. function secondsToTimecode($input_seconds=0)
  1943. {
  1944. return $this->formatSeconds($input_seconds, '%hh:%mm:%ss');
  1945. }
  1946. /**
  1947. * Translates a timecode to the number of seconds.
  1948. * NOTE: this is now a depreciated, use formatTimecode() instead.
  1949. *
  1950. * @depreciated Use formatTimecode() instead.
  1951. * @access public
  1952. * @uses PHPVideoToolkit::formatTimecode()
  1953. * @param integer $input_seconds The number of seconds you want to calculate the timecode for.
  1954. */
  1955. function timecodeToSeconds($input_timecode='00:00:00')
  1956. {
  1957. return $this->formatTimecode($input_timecode, '%hh:%mm:%ss', '%st');
  1958. }
  1959. /**
  1960. * Translates a number of seconds to a timecode.
  1961. *
  1962. * @access public
  1963. * @param integer $input_seconds The number of seconds you want to calculate the timecode for.
  1964. * @param integer $return_format The format of the timecode to return. The default is
  1965. * default '%hh:%mm:%ss'
  1966. * - %hh (hours) representative of hours
  1967. * - %mm (minutes) representative of minutes
  1968. * - %ss (seconds) representative of seconds
  1969. * - %fn (frame number) representative of frames (of the current second, not total frames)
  1970. * - %ms (milliseconds) representative of milliseconds (of the current second, not total milliseconds) (rounded to 3 decimal places)
  1971. * - %ft (frames total) representative of total frames (ie frame number)
  1972. * - %st (seconds total) representative of total seconds (rounded).
  1973. * - %sf (seconds floored) representative of total seconds (floored).
  1974. * - %sc (seconds ceiled) representative of total seconds (ceiled).
  1975. * - %mt (milliseconds total) representative of total milliseconds. (rounded to 3 decimal places)
  1976. * Thus you could use an alternative, '%hh:%mm:%ss:%ms', or '%hh:%mm:%ss' dependent on your usage.
  1977. * @param mixed|boolean|integer $frames_per_second The number of frames per second to translate for. If left false
  1978. * the class automagically gets the fps from PHPVideoToolkit::getFileInfo(), but the input has to be set
  1979. * first for this to work properly.
  1980. * @return string|integer Returns the timecode, but if $frames_per_second is not set and a frame rate lookup is required
  1981. * but can't be reached then -1 will be returned.
  1982. */
  1983. function formatSeconds($input_seconds, $return_format='%hh:%mm:%ss', $frames_per_second=false)
  1984. {
  1985. $timestamp = mktime(0, 0, $input_seconds, 0, 0);
  1986. $floored = floor($input_seconds);
  1987. $hours = date('H', $timestamp);
  1988. $mins = date('i', $timestamp);
  1989. $searches = array();
  1990. $replacements = array();
  1991. // these ones are the simple replacements
  1992. // replace the hours
  1993. $using_hours = strpos($return_format, '%hh') !== false;
  1994. if($using_hours)
  1995. {
  1996. array_push($searches, '%hh');
  1997. array_push($replacements, $hours);
  1998. }
  1999. // replace the minutes
  2000. $using_mins = strpos($return_format, '%mm') !== false;
  2001. if($using_mins)
  2002. {
  2003. array_push($searches, '%mm');
  2004. // check if hours are being used, if not and hours are required enable smart minutes
  2005. if(!$using_hours && $hours > 0)
  2006. {
  2007. $value = ($hours * 60) + $mins;
  2008. }
  2009. else
  2010. {
  2011. $value = $mins;
  2012. }
  2013. array_push($replacements, $value);
  2014. }
  2015. // replace the seconds
  2016. if(strpos($return_format, '%ss') !== false)
  2017. {
  2018. // check if hours are being used, if not and hours are required enable smart minutes
  2019. if(!$using_mins && !$using_hours && $hours > 0)
  2020. {
  2021. $mins = ($hours * 60) + $mins;
  2022. }
  2023. // check if mins are being used, if not and hours are required enable smart minutes
  2024. if(!$using_mins && $mins > 0)
  2025. {
  2026. $value = ($mins * 60) + date('s', $timestamp);
  2027. }
  2028. else
  2029. {
  2030. $value = date('s', $timestamp);
  2031. }
  2032. array_push($searches, '%ss');
  2033. array_push($replacements, $value);
  2034. }
  2035. // replace the milliseconds
  2036. if(strpos($return_format, '%ms') !== false)
  2037. {
  2038. $milli = round($input_seconds - $floored, 3);
  2039. $milli = substr($milli, 2);
  2040. $milli = empty($milli) ? '0' : $milli;
  2041. array_push($searches, '%ms');
  2042. array_push($replacements, $milli);
  2043. }
  2044. // replace the total seconds (rounded)
  2045. if(strpos($return_format, '%st') !== false)
  2046. {
  2047. array_push($searches, '%st');
  2048. array_push($replacements, round($input_seconds));
  2049. }
  2050. // replace the total seconds (floored)
  2051. if(strpos($return_format, '%sf') !== false)
  2052. {
  2053. array_push($searches, '%sf');
  2054. array_push($replacements, floor($input_seconds));
  2055. }
  2056. // replace the total seconds (ceiled)
  2057. if(strpos($return_format, '%sc') !== false)
  2058. {
  2059. array_push($searches, '%sc');
  2060. array_push($replacements, ceil($input_seconds));
  2061. }
  2062. // replace the total seconds
  2063. if(strpos($return_format, '%mt') !== false)
  2064. {
  2065. array_push($searches, '%mt');
  2066. array_push($replacements, round($input_seconds, 3));
  2067. }
  2068. // these are the more complicated as they depend on $frames_per_second / frames per second of the current input
  2069. $has_frames = strpos($return_format, '%fn') !== false;
  2070. $has_total_frames = strpos($return_format, '%ft') !== false;
  2071. if($has_frames || $has_total_frames)
  2072. {
  2073. // if the fps is false then we must automagically detect it from the input file
  2074. if($frames_per_second === false)
  2075. {
  2076. $info = $this->getFileInfo();
  2077. // check the information has been received
  2078. if($info === false || (!isset($info['video']) || !isset($info['video']['frame_rate'])))
  2079. {
  2080. // fps cannot be reached so return -1
  2081. return -1;
  2082. }
  2083. $frames_per_second = $info['video']['frame_rate'];
  2084. }
  2085. // replace the frames
  2086. $excess_frames = false;
  2087. if($has_frames)
  2088. {
  2089. $excess_frames = ceil(($input_seconds - $floored) * $frames_per_second);
  2090. // print_r(array($input_seconds, $excess_frames));
  2091. array_push($searches, '%fn');
  2092. array_push($replacements, $excess_frames);
  2093. }
  2094. // replace the total frames (ie frame number)
  2095. if($has_total_frames)
  2096. {
  2097. $round_frames = $floored * $frames_per_second;
  2098. if(!$excess_frames)
  2099. {
  2100. $excess_frames = ceil(($input_seconds - $floored) * $frames_per_second);
  2101. }
  2102. array_push($searches, '%ft');
  2103. array_push($replacements, $round_frames + $excess_frames);
  2104. }
  2105. }
  2106. // print_r(array($searches, $replacements, $return_format));
  2107. // print_r(array($input_seconds, $timestamp, $return_format, str_replace($searches, $replacements, $return_format)));
  2108. return str_replace($searches, $replacements, $return_format);
  2109. }
  2110. /**
  2111. * Translates a timecode to the number of seconds
  2112. *
  2113. * @access public
  2114. * @param integer $input_seconds The number of seconds you want to calculate the timecode for.
  2115. * @param integer $input_format The format of the timecode is being given in.
  2116. * default '%hh:%mm:%ss'
  2117. * - %hh (hours) representative of hours
  2118. * - %mm (minutes) representative of minutes
  2119. * - %ss (seconds) representative of seconds
  2120. * - %fn (frame number) representative of frames (of the current second, not total frames)
  2121. * - %ms (milliseconds) representative of milliseconds (of the current second, not total milliseconds) (rounded to 3 decimal places)
  2122. * - %ft (frames total) representative of total frames (ie frame number)
  2123. * - %st (seconds total) representative of total seconds (rounded).
  2124. * - %sf (seconds floored) representative of total seconds (floored).
  2125. * - %mt (milliseconds total) representative of total milliseconds. (rounded to 3 decimal places)
  2126. * Thus you could use an alternative, '%hh:%mm:%ss:%ms', or '%hh:%mm:%ss' dependent on your usage.
  2127. * @param integer $return_format The format of the timecode to return. The default is
  2128. * default '%ts'
  2129. * - %hh (hours) representative of hours
  2130. * - %mm (minutes) representative of minutes
  2131. * - %ss (seconds) representative of seconds
  2132. * - %fn (frame number) representative of frames (of the current second, not total frames)
  2133. * - %ms (milliseconds) representative of milliseconds (of the current second, not total milliseconds) (rounded to 3 decimal places)
  2134. * - %ft (frames total) representative of total frames (ie frame number)
  2135. * - %st (seconds total) representative of total seconds (rounded).
  2136. * - %sf (seconds floored) representative of total seconds (floored).
  2137. * - %sc (seconds ceiled) representative of total seconds (ceiled).
  2138. * - %mt (milliseconds total) representative of total milliseconds. (rounded to 3 decimal places)
  2139. * Thus you could use an alternative, '%hh:%mm:%ss:%ms', or '%hh:%mm:%ss' dependent on your usage.
  2140. * @param mixed|boolean|integer $frames_per_second The number of frames per second to translate for. If left false
  2141. * the class automagically gets the fps from PHPVideoToolkit::getFileInfo(), but the input has to be set
  2142. * first for this to work properly.
  2143. * @return float Returns the value of the timecode in seconds.
  2144. */
  2145. function formatTimecode($input_timecode, $input_format='%hh:%mm:%ss', $return_format='%ts', $frames_per_second=false)
  2146. {
  2147. // first we must get the timecode into the current seconds
  2148. $input_quoted = preg_quote($input_format);
  2149. $placeholders = array('%hh', '%mm', '%ss', '%fn', '%ms', '%ft', '%st', '%sf', '%sc', '%mt');
  2150. $seconds = 0;
  2151. $input_regex = str_replace($placeholders, '([0-9]+)', preg_quote($input_format));
  2152. preg_match('/'.$input_regex.'/', $input_timecode, $matches);
  2153. // work out the sort order for the placeholders
  2154. $sort_table = array();
  2155. foreach($placeholders as $key=>$placeholder)
  2156. {
  2157. if(($pos = strpos($input_format, $placeholder)) !== false)
  2158. {
  2159. $sort_table[$pos] = $placeholder;
  2160. }
  2161. }
  2162. ksort($sort_table);
  2163. // check to see if frame related values are in the input
  2164. $has_frames = strpos($input_format, '%fn') !== false;
  2165. $has_total_frames = strpos($input_format, '%ft') !== false;
  2166. if($has_frames || $has_total_frames)
  2167. {
  2168. // if the fps is false then we must automagically detect it from the input file
  2169. if($frames_per_second === false)
  2170. {
  2171. $info = $this->getFileInfo();
  2172. // check the information has been received
  2173. if($info === false || (!isset($info['video']) || !isset($info['video']['frame_rate'])))
  2174. {
  2175. // fps cannot be reached so return -1
  2176. return -1;
  2177. }
  2178. $frames_per_second = $info['video']['frame_rate'];
  2179. }
  2180. }
  2181. // increment the seconds with each placeholder value
  2182. $key = 1;
  2183. foreach($sort_table as $placeholder)
  2184. {
  2185. if(!isset($matches[$key]))
  2186. {
  2187. break;
  2188. }
  2189. $value = $matches[$key];
  2190. switch($placeholder)
  2191. {
  2192. // time related ones
  2193. case '%hh' :
  2194. $seconds += $value * 3600;
  2195. break;
  2196. case '%mm' :
  2197. $seconds += $value * 60;
  2198. break;
  2199. case '%ss' :
  2200. case '%sf' :
  2201. case '%sc' :
  2202. $seconds += $value;
  2203. break;
  2204. case '%ms' :
  2205. $seconds += floatval('0.'.$value);
  2206. break;
  2207. case '%st' :
  2208. case '%mt' :
  2209. $seconds = $value;
  2210. break 1;
  2211. break;
  2212. // frame related ones
  2213. case '%fn' :
  2214. $seconds += $value/$frames_per_second;
  2215. break;
  2216. case '%ft' :
  2217. $seconds = $value/$frames_per_second;
  2218. break 1;
  2219. break;
  2220. }
  2221. $key += 1;
  2222. }
  2223. // then we just format the seconds
  2224. return $this->formatSeconds($seconds, $return_format, $frames_per_second);
  2225. }
  2226. /**
  2227. * This is a function that joins multiple input sources into one source before
  2228. * the final processing takes place. All videos are temporarily converted into mpg for
  2229. * joining.
  2230. *
  2231. * PLEASE NOTE. This process is experimental an might not work on all systems.
  2232. *
  2233. * @access private
  2234. * @param boolean $log
  2235. */
  2236. function _joinInput($log)
  2237. {
  2238. die('INPUT CANNOT YET BE JOINED.');
  2239. // ---- ffmpeg works
  2240. /*
  2241. mkfifo /Users/ollie/Sites/@Projects/ffmpeg/checkout/root/examples/tmp/intermediate1.mpg
  2242. mkfifo /Users/ollie/Sites/@Projects/ffmpeg/checkout/root/examples/tmp/intermediate2.mpg
  2243. ffmpeg -i /Users/ollie/Sites/@Projects/ffmpeg/checkout/root/examples/tmp/MOV02820.MPG -sameq -y /Users/ollie/Sites/@Projects/ffmpeg/checkout/root/examples/tmp/intermediate1.mpg < /dev/null &
  2244. ffmpeg -i /Users/ollie/Sites/@Projects/ffmpeg/checkout/root/examples/tmp/MOV02832.MPG -sameq -y /Users/ollie/Sites/@Projects/ffmpeg/checkout/root/examples/tmp/intermediate2.mpg < /dev/null &
  2245. cat /Users/ollie/Sites/@Projects/ffmpeg/checkout/root/examples/tmp/intermediate1.mpg /Users/ollie/Sites/@Projects/ffmpeg/checkout/root/examples/tmp/intermediate2.mpg |\
  2246. ffmpeg -f mpeg -i - -sameq -vcodec flv -acodec mp3 -ar 22050 /Users/ollie/Sites/@Projects/ffmpeg/checkout/root/examples/tmp/output.flv
  2247. */
  2248. // ---- mencoder works
  2249. /*
  2250. PHPVIDEOTOOLKIT_MENCODER_BINARY.' -oac copy -ovc copy -idx -o '.$temp_file.' '.implode(' ', $this->_input_file);
  2251. */
  2252. // run a libmp3lame check as it require different mp3 codec
  2253. $audio_codec = 'mp3';
  2254. $info = $this->getFFmpegInfo();
  2255. if(isset($info['compiler']['configuration']) && in_array('--enable-libmp3lame', $info['compiler']['configuration']))
  2256. {
  2257. // $audio_codec = 'liblamemp3';
  2258. $audio_codec = 'libmp3lame';
  2259. }
  2260. // build commands
  2261. $temp_files = array();
  2262. $mkinfo_commands = array();
  2263. $ffmpeg_commands = array();
  2264. $cat_files = array();
  2265. $unique = $this->unique();
  2266. foreach($this->_input_file as $key=>$file)
  2267. {
  2268. $unique_name = $this->_tmp_directory.$unique.'-'.$key.'-temp.mpg';
  2269. $unique_name_escaped = escapeshellarg($unique_name);
  2270. $logfile1 = $this->_tmp_directory.$unique.'-'.$key.'-log1.log';
  2271. $logfile2 = $this->_tmp_directory.$unique.'-'.$key.'-log2.log';
  2272. array_push($mkinfo_commands, array('cmd'=> 'mkfifo '.$unique_name_escaped.($log ? ' &> '.$logfile1 : ''), 'logfile'=>$logfile1));
  2273. array_push($ffmpeg_commands, array('cmd'=> PHPVIDEOTOOLKIT_FFMPEG_BINARY.' -i '.escapeshellarg($file).' -acodec '.$audio_codec.' -sameq '.$unique_name_escaped.' < /dev/null '.($log ? '&> '.$logfile2 : '&'), 'logfile'=>$logfile2));
  2274. array_push($cat_files, $unique_name_escaped);
  2275. // array_push($this->_unlink_files, $unique_name);
  2276. if($log)
  2277. {
  2278. // array_push($this->_unlink_files, $logfile1);
  2279. // array_push($this->_unlink_files, $logfile2);
  2280. }
  2281. }
  2282. // start log
  2283. if($log)
  2284. {
  2285. $log_lines = array();
  2286. array_unshift($log_lines, $this->_getMessage('ffmpeg_log_separator'), $this->_getMessage('ffmpeg_log_ffmpeg_join_gunk'), $this->_getMessage('ffmpeg_log_separator'));
  2287. }
  2288. // mkinfo for temp files
  2289. foreach($mkinfo_commands as $cmd)
  2290. {
  2291. // exec($cmd['cmd']);
  2292. echo($cmd['cmd']."\r\n");
  2293. if($log)
  2294. {
  2295. array_push($log_lines, '---------', trim(file_get_contents($cmd['logfile'])));
  2296. }
  2297. }
  2298. // extract data
  2299. foreach($ffmpeg_commands as $cmd)
  2300. {
  2301. // exec($cmd['cmd']);
  2302. echo($cmd['cmd']."\r\n");
  2303. if($log)
  2304. {
  2305. array_push($log_lines, trim(file_get_contents($cmd['logfile'])), '---------');
  2306. }
  2307. }
  2308. // join command
  2309. $unique = $this->unique();
  2310. $temp_join_file = $this->_tmp_directory.$unique.'-combined-joined.mpg';
  2311. $temp_join_file_escaped = escapeshellarg($temp_join_file);
  2312. $temp_process_file = $this->_tmp_directory.$unique.'-combined-temp.mpg';
  2313. $temp_process_file_escaped = escapeshellarg($temp_process_file);
  2314. $logfile = $this->_tmp_directory.$unique.'.log';
  2315. // command for use with cat mkinfo files
  2316. // exec('cat '.implode(' ', $cat_files).' |\
  2317. // '.PHPVIDEOTOOLKIT_FFMPEG_BINARY.' -f mpeg -i - -sameq -vcodec mpeg4 -acodec '.$audio_codec.' '.escapeshellarg($temp_process_file).($log ? ' &> '.$logfile : ''));
  2318. echo('cat '.implode(' ', $cat_files).' |\
  2319. '.PHPVIDEOTOOLKIT_FFMPEG_BINARY.' -f mpeg -i - -sameq -vcodec mpeg4 -acodec '.$audio_codec.' '.escapeshellarg($temp_process_file).($log ? ' &> '.$logfile : '')."\r\n");
  2320. // echo('cat '.implode(' ', $cat_files).' > '.$temp_join_file_escaped.'
  2321. // '.PHPVIDEOTOOLKIT_FFMPEG_BINARY.' -i '.$temp_join_file_escaped.' -sameq -vcodec mpeg4 -acodec '.$audio_codec.' '.$temp_process_file_escaped.($log ? ' &> '.$logfile : ''));
  2322. // exec('cat '.implode(' ', $cat_files).' > '.$temp_join_file_escaped.'
  2323. // '.PHPVIDEOTOOLKIT_FFMPEG_BINARY.' -i '.$temp_join_file_escaped.' -sameq -vcodec mpeg4 -acodec '.$audio_codec.' '.$temp_process_file_escaped.($log ? ' &> '.$logfile : ''));
  2324. if($log)
  2325. {
  2326. array_push($log_lines, trim(file_get_contents($logfile)));
  2327. array_push($this->_unlink_files, $logfile);
  2328. $this->_addToLog($log_lines, 'r+');
  2329. print_r($log_lines);
  2330. }
  2331. // create a temp dir in the temp dir
  2332. // $temp_file = $this->_tmp_directory.$this->unique().'.'.array_pop(explode('.', $this->_process_address));
  2333. // print_r($temp_file);
  2334. $this->addCommand('-i', $temp_process_file);
  2335. // array_push($this->_unlink_files, $temp_process_file);
  2336. exit;
  2337. }
  2338. /**
  2339. * Commits all the commands and executes the ffmpeg procedure. This will also attempt to validate any outputted files in order to provide
  2340. * some level of stop and check system.
  2341. *
  2342. * @access public
  2343. * @param $multi_pass_encode boolean Determines if multi (2) pass encoding should be used.
  2344. * @param $log boolean Determines if a log file of the results should be generated.
  2345. * @return mixed
  2346. * - false On error encountered.
  2347. * - PHPVIDEOTOOLKIT_RESULT_OK (bool true) If the file has successfully been processed and moved ok to the output address
  2348. * - PHPVIDEOTOOLKIT_RESULT_OK_BUT_UNWRITABLE (int -1) If the file has successfully been processed but was not able to be moved correctly to the output address
  2349. * If this is the case you will manually need to move the processed file from the temp directory. You can
  2350. * get around this by settings the third argument from PHPVideoToolkit::setOutput(), $overwrite to true.
  2351. * - n (int) A positive integer is only returned when outputting a series of frame grabs from a movie. It dictates
  2352. * the total number of frames grabbed from the input video. You should also not however, that if a conflict exists
  2353. * with one of the filenames then this return value will not be returned, but PHPVIDEOTOOLKIT_RESULT_OK_BUT_UNWRITABLE
  2354. * will be returned instead.
  2355. * Because of the mixed return value you should always go a strict evaluation of the returned value. ie
  2356. *
  2357. * $result = $toolkit->excecute();
  2358. * if($result === false)
  2359. * {
  2360. * // error
  2361. * }
  2362. * else if($result === PHPVIDEOTOOLKIT_RESULT_OK_BUT_UNWRITABLE)
  2363. * {
  2364. * // ok but a manual move is required. The file to move can be it can be retrieved by $toolkit->getLastOutput();
  2365. * }
  2366. * else if($result === PHPVIDEOTOOLKIT_RESULT_OK)
  2367. * {
  2368. * // everything is ok.
  2369. * }
  2370. */
  2371. function execute($multi_pass_encode=false, $log=false)
  2372. {
  2373. // check for inut and output params
  2374. $has_placeholder = preg_match('/\%([0-9]+)index/', $this->_process_address) || (strpos($this->_process_address, '%index') === false && strpos($this->_process_address, '%timecode') === false);
  2375. if($this->_input_file === null && !$has_placeholder)
  2376. {
  2377. return $this->_raiseError('execute_input_404');
  2378. //<- exits
  2379. }
  2380. // check to see if the output address has been set
  2381. if($this->_process_address === null)
  2382. {
  2383. return $this->_raiseError('execute_output_not_set');
  2384. //<- exits
  2385. }
  2386. if(($this->_overwrite_mode == PHPVIDEOTOOLKIT_OVERWRITE_PRESERVE || $this->_overwrite_mode == PHPVIDEOTOOLKIT_OVERWRITE_FAIL) && is_file($this->_process_address))
  2387. {
  2388. return $this->_raiseError('execute_overwrite_process');
  2389. //<- exits
  2390. }
  2391. // carry out some overwrite checks if required
  2392. $overwrite = '';
  2393. switch($this->_overwrite_mode)
  2394. {
  2395. case PHPVIDEOTOOLKIT_OVERWRITE_UNIQUE :
  2396. // insert a unique id into the output address (the process address already has one)
  2397. $unique = $this->unique();
  2398. $last_index = strrpos($this->_output_address, DIRECTORY_SEPARATOR);
  2399. $this->_output_address = substr($this->_output_address, 0, $last_index+1).$unique.'-'.substr($this->_output_address, $last_index+1);
  2400. break;
  2401. case PHPVIDEOTOOLKIT_OVERWRITE_EXISTING :
  2402. // add an overwrite command to ffmpeg execution call
  2403. $overwrite = '-y ';
  2404. break;
  2405. case PHPVIDEOTOOLKIT_OVERWRITE_PRESERVE :
  2406. // do nothing as the preservation comes later
  2407. break;
  2408. case PHPVIDEOTOOLKIT_OVERWRITE_FAIL :
  2409. default :
  2410. // if the file should fail
  2411. if(!$has_placeholder && is_file($this->_output_address))
  2412. {
  2413. return $this->_raiseError('execute_overwrite_fail');
  2414. //<- exits
  2415. }
  2416. break;
  2417. }
  2418. $this->_timer_start = PHPVideoToolkit::microtimeFloat();
  2419. // we have multiple inputs that require joining so convert them to a joinable format and join
  2420. if(is_array($this->_input_file))
  2421. {
  2422. $this->_joinInput($log);
  2423. }
  2424. // add the input file command to the mix
  2425. $this->addCommand('-i', $this->_input_file);
  2426. // if multi pass encoding is enabled add the commands and logfile
  2427. if($multi_pass_encode)
  2428. {
  2429. $multi_pass_file = $this->_tmp_directory.$this->unique().'-multipass';
  2430. $this->addCommand('-pass', 1);
  2431. $this->addCommand('-passlogfile', $multi_pass_file);
  2432. }
  2433. // combine all the output commands
  2434. $command_string = $this->_combineCommands();
  2435. // prepare the command suitable for exec
  2436. // the input and overwrite commands have specific places to be set so they have to be added outside of the combineCommands function
  2437. $exec_string = $this->_prepareCommand(PHPVIDEOTOOLKIT_FFMPEG_BINARY, $command_string, $overwrite.escapeshellcmd($this->_process_address));
  2438. // $exec_string = $this->_prepareCommand(PHPVIDEOTOOLKIT_FFMPEG_BINARY, '-i '.$this->_commands['-i'].' '.$command_string, $overwrite.escapeshellcmd($this->_process_address));
  2439. if($log)
  2440. {
  2441. $this->_log_file = $this->_tmp_directory.$this->unique().'.info';
  2442. array_push($this->_unlink_files, $this->_log_file);
  2443. $exec_string = $exec_string.' &> '.$this->_log_file;
  2444. }
  2445. // execute the command
  2446. exec($exec_string);
  2447. // track the processed command by adding it to the class
  2448. array_unshift($this->_processed, $exec_string);
  2449. // create the multiple pass encode
  2450. if($multi_pass_encode)
  2451. {
  2452. $pass2_exc_string = str_replace('-pass '.escapeshellarg(1), '-pass '.escapeshellarg(2), $exec_string);
  2453. exec($pass2_exc_string);
  2454. $this->_processed[0] = array($this->_processed[0], $pass2_exc_string);
  2455. // remove the multipass log file
  2456. unlink($multi_pass_file.'-0.log');
  2457. }
  2458. // keep track of the time taken
  2459. $execution_time = PHPVideoToolkit::microtimeFloat() - $this->_timer_start;
  2460. array_unshift($this->_timers, $execution_time);
  2461. // add the exec string to the log file
  2462. if($log)
  2463. {
  2464. $lines = $this->_processed[0];
  2465. if(!is_array($lines))
  2466. {
  2467. $lines = array($lines);
  2468. }
  2469. array_unshift($lines, $this->_getMessage('ffmpeg_log_separator'), $this->_getMessage('ffmpeg_log_ffmpeg_command'), $this->_getMessage('ffmpeg_log_separator'));
  2470. array_unshift($lines, $this->_getMessage('ffmpeg_log_separator'), $this->_getMessage('ffmpeg_log_ffmpeg_gunk'), $this->_getMessage('ffmpeg_log_separator'));
  2471. $this->_addToLog($lines, 'r+');
  2472. }
  2473. // must validate a series of outputed items
  2474. // detect if the output address is a sequence output
  2475. if(preg_match('/\%([0-9]+)d/', $this->_process_address, $d_matches) || strpos($this->_process_address, '%d') !== false)
  2476. {
  2477. // get the path details
  2478. $process_info = pathinfo($this->_process_address);
  2479. $output_info = pathinfo($this->_output_address);
  2480. $pad_amount = intval($d_matches[1]);
  2481. // print_r(array($process_info, $output_info));
  2482. // get the %index padd amounts
  2483. $has_preg_index = preg_match('/\%([0-9]+)index/', $output_info['basename'], $index_matches);
  2484. $output_index_pad_amount = isset($index_matches[1]) ? intval($index_matches[1], 1) : 0;
  2485. // var_dump($index_matches);
  2486. // init the iteration values
  2487. $num = 1;
  2488. $files = array();
  2489. $produced = array();
  2490. $error = false;
  2491. $name_conflict = false;
  2492. $file_exists = false;
  2493. // get the first files name
  2494. $filename = $process_info['dirname'].DIRECTORY_SEPARATOR.str_replace($d_matches[0], str_pad($num, $pad_amount, '0', STR_PAD_LEFT), $process_info['basename']);
  2495. $use_timecode = strpos($output_info['basename'], '%timecode') !== false;
  2496. $use_index = $has_preg_index || strpos($output_info['basename'], '%index') !== false;
  2497. // if(!$use_timecode && $use_index)
  2498. // {
  2499. // if($log)
  2500. // {
  2501. // $this->_logResult('execute_overwrite_fail');
  2502. // }
  2503. // return $this->_raiseError('execute_overwrite_fail');
  2504. // }
  2505. // start the timecode pattern replacement values
  2506. if($use_timecode)
  2507. {
  2508. $secs_start = $this->formatTimecode($this->_image_output_timecode_start, '%hh:%mm:%ss.%ms', '%mt', $this->_image_output_timecode_fps);
  2509. $fps_inc = 1/$this->_image_output_timecode_fps;
  2510. $fps_current_sec = 0;
  2511. $fps_current_frame = 0;
  2512. }
  2513. // loop checking for file existence
  2514. while(@is_file($filename))
  2515. {
  2516. // check for empty file
  2517. $size = filesize($filename);
  2518. if($size == 0)
  2519. {
  2520. $error = true;
  2521. }
  2522. array_push($produced, $filename);
  2523. // create the substitution arrays
  2524. $searches = array();
  2525. $replacements = array();
  2526. if($use_index)
  2527. {
  2528. array_push($searches, isset($index_matches[0]) ? $index_matches[0] : '%index');
  2529. array_push($replacements, str_pad($num, $output_index_pad_amount, '0', STR_PAD_LEFT));
  2530. }
  2531. // check if timecode is in the output name, no need to use it if not
  2532. if($use_timecode)
  2533. {
  2534. $fps_current_sec += $fps_inc;
  2535. $fps_current_frame += 1;
  2536. if($fps_current_sec >= 1)
  2537. {
  2538. $fps_current_sec = $fps_inc;
  2539. $secs_start += 1;
  2540. $fps_current_frame = 1;
  2541. }
  2542. $timecode = $this->formatSeconds($secs_start, $this->image_output_timecode_format, $this->_image_output_timecode_fps);
  2543. $timecode = str_replace(array(':', '.'), $this->timecode_seperator_output, $timecode);
  2544. // add to the substitution array
  2545. array_push($searches, '%timecode');
  2546. array_push($replacements, $timecode);
  2547. }
  2548. // check if the file exists already and if it does check that it can be overriden
  2549. $old_filename = $filename;
  2550. // print_r(array($searches, $replacements, $output_info['basename']));
  2551. $new_file = str_replace($searches, $replacements, $output_info['basename']);
  2552. $new_filename = $output_info['dirname'].DIRECTORY_SEPARATOR.$new_file;
  2553. // var_dump($filename, $new_filename);
  2554. if(!is_file($new_filename) || $this->_overwrite_mode == PHPVIDEOTOOLKIT_OVERWRITE_EXISTING)
  2555. {
  2556. rename($filename, $new_filename);
  2557. $filename = $new_filename;
  2558. }
  2559. // the file exists and is not allowed to be overriden so just rename in the temp directory using the timecode
  2560. else if($this->_overwrite_mode == PHPVIDEOTOOLKIT_OVERWRITE_PRESERVE)
  2561. {
  2562. $new_filename = $process_info['dirname'].DIRECTORY_SEPARATOR.'tbm-'.$this->unique().'-'.$new_file;
  2563. rename($filename, $new_filename);
  2564. $filename = $new_filename;
  2565. // add the error to the log file
  2566. if($log)
  2567. {
  2568. $this->_logResult('execute_image_file_exists', array('file'=>$new_filename));
  2569. }
  2570. // flag the conflict
  2571. $file_exists = true;
  2572. }
  2573. // the file exists so the process must fail
  2574. else
  2575. {
  2576. // add the error to the log file
  2577. if($log)
  2578. {
  2579. $this->_logResult('execute_overwrite_fail');
  2580. }
  2581. // tidy up the produced files
  2582. array_merge($this->_unlink_files, $produced);
  2583. return $this->_raiseError('execute_overwrite_fail');
  2584. }
  2585. // process the name change if the %d is to be replaced with the timecode
  2586. $num += 1;
  2587. $files[$filename] = $size > 0 ? basename($filename) : false;
  2588. // print_r("\r\n\r\n".is_file($old_filename)." - ".$old_filename.' => '.$new_filename);
  2589. // print_r($files);
  2590. // get the next incremented filename to check for existance
  2591. $filename = $process_info['dirname'].DIRECTORY_SEPARATOR.str_replace($d_matches[0], str_pad($num, $pad_amount, '0', STR_PAD_LEFT), $process_info['basename']);
  2592. }
  2593. // de-increment the last num as it wasn't found
  2594. $num -= 1;
  2595. // if the file was detected but were empty then display a different error
  2596. if($error === true)
  2597. {
  2598. // add the error to the log file
  2599. if($log)
  2600. {
  2601. $this->_logResult('execute_partial_error', array('input'=>$this->_input_file));
  2602. }
  2603. return $this->_raiseError('execute_partial_error', array('input'=>$this->_input_file));
  2604. //<- exits
  2605. }
  2606. // post process any files
  2607. // print_r($files);
  2608. $post_process_result = $this->_postProcess($log, $files);
  2609. // print_r($files);
  2610. if(is_array($post_process_result))
  2611. {
  2612. // post process has occurred and everything is fine
  2613. $num = count($files);
  2614. }
  2615. else if($post_process_result !== false)
  2616. {
  2617. // the file has encountered an error in the post processing of the files
  2618. return $post_process_result;
  2619. }
  2620. // var_dump("\r\n\r\n", $files, __LINE__, __FILE__, "\r\n\r\n");
  2621. // exit;
  2622. // if the result is false then no post process has taken place
  2623. $this->_process_file_count = $num;
  2624. // no files were generated in this sequence
  2625. if($num == 0)
  2626. {
  2627. // add the error to the log file
  2628. if($log)
  2629. {
  2630. $this->_logResult('execute_image_error', array('input'=>$this->_input_file));
  2631. }
  2632. return $this->_raiseError('execute_image_error', array('input'=>$this->_input_file));
  2633. //<- exits
  2634. }
  2635. // add the files the the class a record of what has been generated
  2636. array_unshift($this->_files, $files);
  2637. array_push($lines, $this->_getMessage('ffmpeg_log_separator'), $this->_getMessage('ffmpeg_log_ffmpeg_output'), $this->_getMessage('ffmpeg_log_separator'), implode("\n", $files));
  2638. $this->_addToLog($lines, 'r+');
  2639. return $file_exists ? PHPVIDEOTOOLKIT_RESULT_OK_BUT_UNWRITABLE : PHPVIDEOTOOLKIT_RESULT_OK;
  2640. }
  2641. // must validate one file
  2642. else
  2643. {
  2644. // check that it is a file
  2645. if(!is_file($this->_process_address))
  2646. {
  2647. // add the error to the log file
  2648. if($log)
  2649. {
  2650. $this->_logResult('execute_output_404', array('input'=>$this->_input_file));
  2651. }
  2652. return $this->_raiseError('execute_output_404', array('input'=>$this->_input_file));
  2653. //<- exits
  2654. }
  2655. // the file does exist but is it empty?
  2656. if(filesize($this->_process_address) == 0)
  2657. {
  2658. // add the error to the log file
  2659. if($log)
  2660. {
  2661. $this->_logResult('execute_output_empty', array('input'=>$this->_input_file));
  2662. }
  2663. return $this->_raiseError('execute_output_empty', array('input'=>$this->_input_file));
  2664. //<- exits
  2665. }
  2666. // the file is ok so move to output address
  2667. if(!is_file($this->_output_address) || $this->_overwrite_mode == PHPVIDEOTOOLKIT_OVERWRITE_EXISTING)
  2668. {
  2669. // post process any files
  2670. $post_process_result = $this->_postProcess($log, array($this->_process_address));
  2671. if(is_array($post_process_result) || $post_process_result === true)
  2672. {
  2673. // post process has occurred and everything is fine
  2674. }
  2675. else if($post_process_result !== false)
  2676. {
  2677. return $post_process_result;
  2678. }
  2679. // if the result is false then no post process has taken place
  2680. // rename the file to the final destination and check it went ok
  2681. if(rename($this->_process_address, $this->_output_address))
  2682. {
  2683. array_push($lines, $this->_getMessage('ffmpeg_log_separator'), $this->_getMessage('ffmpeg_log_ffmpeg_output'), $this->_getMessage('ffmpeg_log_separator'), $this->_output_address);
  2684. $this->_addToLog($lines, 'r+');
  2685. // the file has been renamed ok
  2686. // add the error to the log file
  2687. if($log)
  2688. {
  2689. $this->_logResult('execute_result_ok', array('output'=>$this->_output_address));
  2690. }
  2691. $this->_process_file_count = 1;
  2692. // add the file the the class a record of what has been generated
  2693. array_unshift($this->_files, array($this->_output_address));
  2694. return PHPVIDEOTOOLKIT_RESULT_OK;
  2695. }
  2696. // renaming failed so return ok but erro
  2697. else
  2698. {
  2699. // add the error to the log file
  2700. if($log)
  2701. {
  2702. $this->_logResult('execute_result_ok_but_unwritable', array('process'=>$this->_process_address, 'output'=>$this->_output_address));
  2703. }
  2704. // add the file the the class a record of what has been generated
  2705. array_unshift($this->_files, array($this->_process_address));
  2706. array_push($lines, $this->_getMessage('ffmpeg_log_separator'), $this->_getMessage('ffmpeg_log_ffmpeg_output'), $this->_getMessage('ffmpeg_log_separator'), $this->_process_address);
  2707. $this->_addToLog($lines, 'r+');
  2708. return PHPVIDEOTOOLKIT_RESULT_OK_BUT_UNWRITABLE;
  2709. }
  2710. }
  2711. // if it is not we signal that it has been created but has not been moved.
  2712. else if($this->_overwrite_mode == PHPVIDEOTOOLKIT_OVERWRITE_PRESERVE)
  2713. {
  2714. // add the error to the log file
  2715. if($log)
  2716. {
  2717. $this->_logResult('execute_result_ok_but_unwritable', array('process'=>$this->_process_address, 'output'=>$this->_output_address));
  2718. }
  2719. // add the file the the class a record of what has been generated
  2720. array_unshift($this->_files, array($this->_process_address));
  2721. return PHPVIDEOTOOLKIT_RESULT_OK_BUT_UNWRITABLE;
  2722. }
  2723. // the file exists so the process must fail
  2724. else
  2725. {
  2726. // add the error to the log file
  2727. if($log)
  2728. {
  2729. $this->_logResult('execute_overwrite_fail');
  2730. }
  2731. // tidy up the produced files
  2732. array_push($this->_unlink_files, $this->_process_address);
  2733. return $this->_raiseError('execute_overwrite_fail');
  2734. }
  2735. }
  2736. return null;
  2737. }
  2738. /**
  2739. * This function registers a post process after the internal handling of the ffmpeg output has been cleaned and checked.
  2740. * Each function that is set will be called in the order it is set unless an index is specified. All callbacks will be
  2741. * supplied with one argument with is an array of the outputted files.
  2742. *
  2743. * NOTE1: If a post process function is being applied to an outputted video or audio then the process will be applied
  2744. * before it has been moved to it's final destination, however if the output is an image sequence the post process
  2745. * function will be called after the images have been moved to their final destinations.
  2746. *
  2747. * NOTE2: Also it is important to return a boolean 'true' if the post process has been carried out ok. If the process is not
  2748. * a true value then the value will be treated/returned as an error and if applicable logged.
  2749. *
  2750. * @access public
  2751. * @param string $function The name of a function
  2752. * @param object|boolean $class The name of the callback class. If left as false the callback will be treated as a standalone function.
  2753. * @param integer|boolean $index The index of the callback array to put the callback into. If left as false it will be pushed to the end of the array.
  2754. */
  2755. function registerPostProcess($function, $class=false, $index=false)
  2756. {
  2757. // create the callback
  2758. $callback = $class === false ? $function : array(&$class, $function);
  2759. // add it to the post process array
  2760. if($index === false)
  2761. {
  2762. array_push($this->_post_processes, $callback);
  2763. }
  2764. else
  2765. {
  2766. $this->_post_processes[$index] = $callback;
  2767. }
  2768. }
  2769. /**
  2770. * Carries out the post processing of the files.
  2771. *
  2772. * @access private
  2773. * @param boolean $log Determines if logging of errors should be carried out.
  2774. * @param array $files The array of files that have just been processed.
  2775. * @return mixed
  2776. */
  2777. function _postProcess($log, $files)
  2778. {
  2779. if(count($this->_post_processes))
  2780. {
  2781. // loop through the post processes
  2782. foreach($this->_post_processes as $key=>$process)
  2783. {
  2784. // call the process
  2785. $return_value = call_user_func_array($process, array($files));
  2786. // if the return value is not strictly equal to true the result will be treated as an error and exit the process loop
  2787. if(!is_array($return_value) && $return_value !== true)
  2788. {
  2789. if($log)
  2790. {
  2791. $this->_logResult($return_value);
  2792. }
  2793. return $this->_raiseError($return_value);
  2794. }
  2795. }
  2796. return $return_value;
  2797. }
  2798. return false;
  2799. }
  2800. /**
  2801. * Returns the number of files outputted in this run. It will be reset when you call PHPVideoToolkit::reset();
  2802. *
  2803. * @access public
  2804. * @return integer
  2805. */
  2806. function getFileOutputCount()
  2807. {
  2808. return $this->_process_file_count;
  2809. }
  2810. /**
  2811. * Adds lines to the current log file.
  2812. *
  2813. * @access private
  2814. * @param $message
  2815. * @param $replacements
  2816. */
  2817. function _logResult($message, $replacements=false)
  2818. {
  2819. $this->_addToLog(array($this->_getMessage('ffmpeg_log_separator'), $this->_getMessage('ffmpeg_log_ffmpeg_result'), $this->_getMessage('ffmpeg_log_separator'), $this->_getMessage($message, $replacements)));
  2820. }
  2821. /**
  2822. * Adds lines to the current log file.
  2823. *
  2824. * @access private
  2825. * @param $lines array An array of lines to add to the log file.
  2826. */
  2827. function _addToLog($lines, $where='a')
  2828. {
  2829. $handle = fopen($this->_log_file, $where);
  2830. if(is_array($lines))
  2831. {
  2832. $data = implode("\n", $lines)."\n";
  2833. }
  2834. else
  2835. {
  2836. $data = $lines."\n";
  2837. }
  2838. fwrite($handle, $data);
  2839. fclose($handle);
  2840. }
  2841. /**
  2842. * Moves the current log file to another file.
  2843. *
  2844. * @access public
  2845. * @param $destination string The absolute path of the new filename for the log.
  2846. * @return boolean Returns the result of the log file rename.
  2847. */
  2848. function moveLog($destination)
  2849. {
  2850. $result = false;
  2851. if($this->_log_file !== null && is_file($this->_log_file))
  2852. {
  2853. $result = rename($this->_log_file, $destination);
  2854. $this->_log_file = $destination;
  2855. }
  2856. return $result;
  2857. }
  2858. /**
  2859. * Reads the current log file
  2860. *
  2861. * @access public
  2862. * @return string|boolean Returns the current log file content. Returns false on failure.
  2863. */
  2864. function readLog()
  2865. {
  2866. if($this->_log_file !== null && is_file($this->_log_file))
  2867. {
  2868. $handle = fopen($this->_log_file, 'r');
  2869. $contents = fread($handle, filesize($this->_log_file));
  2870. fclose($handle);
  2871. return $contents;
  2872. }
  2873. return false;
  2874. }
  2875. /**
  2876. * Returns the last outputted file that was processed by ffmpeg from this class.
  2877. *
  2878. * @access public
  2879. * @return mixed array|string Will return an array if the output was a sequence, or string if it was a single file output
  2880. */
  2881. function getLastOutput()
  2882. {
  2883. return $this->_files[0];
  2884. }
  2885. /**
  2886. * Returns all the outputted files that were processed by ffmpeg from this class.
  2887. *
  2888. * @access public
  2889. * @return array
  2890. */
  2891. function getOutput()
  2892. {
  2893. return $this->_files;
  2894. }
  2895. /**
  2896. * Returns the amount of time taken of the last file to be processed by ffmpeg.
  2897. *
  2898. * @access public
  2899. * @return mixed integer Will return the time taken in seconds.
  2900. */
  2901. function getLastProcessTime()
  2902. {
  2903. return $this->_timers[0];
  2904. }
  2905. /**
  2906. * Returns the amount of time taken of all the files to be processed by ffmpeg.
  2907. *
  2908. * @access public
  2909. * @return array
  2910. */
  2911. function getProcessTime()
  2912. {
  2913. return $this->_timers;
  2914. }
  2915. /**
  2916. * Returns the last encountered error message.
  2917. *
  2918. * @access public
  2919. * @return string
  2920. */
  2921. function getLastError()
  2922. {
  2923. return $this->_errors[0];
  2924. }
  2925. /**
  2926. * Returns all the encountered errors as an array of strings
  2927. *
  2928. * @access public
  2929. * @return array
  2930. */
  2931. function getErrors()
  2932. {
  2933. return $this->_errors;
  2934. }
  2935. /**
  2936. * Returns the last command that ffmpeg was given.
  2937. * (Note; if setFormatToFLV was used in the last command then an array is returned as a command was also sent to FLVTool2)
  2938. *
  2939. * @access public
  2940. * @return mixed array|string
  2941. */
  2942. function getLastCommand()
  2943. {
  2944. return $this->_processed[0];
  2945. }
  2946. /**
  2947. * Returns all the commands sent to ffmpeg from this class
  2948. *
  2949. * @access public
  2950. * @return unknown
  2951. */
  2952. function getCommands()
  2953. {
  2954. return $this->_processed;
  2955. }
  2956. /**
  2957. * Raises an error
  2958. *
  2959. * @access private
  2960. * @param string $message
  2961. * @param array $replacements a list of replacements in search=>replacement format
  2962. * @return boolean Only returns false if $toolkit->on_error_die is set to false
  2963. */
  2964. function _raiseError($message, $replacements=false)
  2965. {
  2966. $msg = 'FFMPEG ERROR: '.$this->_getMessage($message, $replacements);
  2967. // check what the error is supposed to do
  2968. if($this->on_error_die === true)
  2969. {
  2970. die($msg);
  2971. //<- exits
  2972. }
  2973. // add the error message to the collection
  2974. array_unshift($this->_errors, $msg);
  2975. return false;
  2976. }
  2977. /**
  2978. * Gets a message.
  2979. *
  2980. * @access private
  2981. * @param string $message
  2982. * @param array $replacements a list of replacements in search=>replacement format
  2983. * @return boolean Only returns false if $toolkit->on_error_die is set to false
  2984. */
  2985. function _getMessage($message, $replacements=false)
  2986. {
  2987. $message = isset($this->_messages[$message]) ? $this->_messages[$message] : 'Unknown!!!';
  2988. if($replacements)
  2989. {
  2990. $searches = $replaces = array();
  2991. foreach($replacements as $search=>$replace)
  2992. {
  2993. array_push($searches, '#'.$search);
  2994. array_push($replaces, $replace);
  2995. }
  2996. $message = str_replace($searches, $replaces, $message);
  2997. }
  2998. return $message;
  2999. }
  3000. /**
  3001. * Adds a command to be bundled into the ffmpeg command call.
  3002. * (SPECIAL NOTE; None of the arguments are checked or sanitized by this function. BE CAREFUL if manually using this. The commands and arguments are escaped
  3003. * however it is still best to check and sanitize any params given to this function)
  3004. *
  3005. * @access public
  3006. * @param string $command
  3007. * @param mixed $argument
  3008. * @return boolean
  3009. */
  3010. function addCommand($command, $argument='')
  3011. {
  3012. $this->_commands[$command] = escapeshellarg($argument);
  3013. return true;
  3014. }
  3015. /**
  3016. * Determines if the the command exits.
  3017. *
  3018. * @access public
  3019. * @param string $command
  3020. * @return mixed boolean if failure or value if exists.
  3021. */
  3022. function hasCommand($command)
  3023. {
  3024. return isset($this->_commands[$command]) ? $this->_commands[$command] : false;
  3025. }
  3026. /**
  3027. * Combines the commands stored into a string
  3028. *
  3029. * @access private
  3030. * @return string
  3031. */
  3032. function _combineCommands()
  3033. {
  3034. $before_input = array();
  3035. $after_input = array();
  3036. $input = null;
  3037. foreach ($this->_commands as $command=>$argument)
  3038. {
  3039. $command_string = trim($command.($argument ? ' '.$argument : ''));
  3040. // check for specific none combinable commands as they have specific places they have to go in the string
  3041. switch($command)
  3042. {
  3043. case '-i' :
  3044. $input = $command_string;
  3045. break;
  3046. case '-inputr' :
  3047. $command_string = trim('-r'.($argument ? ' '.$argument : ''));;
  3048. default :
  3049. if(in_array($command, $this->_cmds_before_input))
  3050. {
  3051. array_push($before_input, $command_string);
  3052. }
  3053. else
  3054. {
  3055. array_push($after_input, $command_string);
  3056. }
  3057. }
  3058. }
  3059. $before_input = count($before_input) ? implode(' ', $before_input).' ' : '';
  3060. $after_input_string = ' ';
  3061. if(count($after_input))
  3062. {
  3063. $input .= ' ';
  3064. $after_input_string = implode(' ', $after_input).' ';
  3065. }
  3066. return $before_input.$input.$after_input_string;
  3067. }
  3068. /**
  3069. * Prepares the command for execution
  3070. *
  3071. * @access private
  3072. * @param string $path Path to the binary
  3073. * @param string $command Command string to execute
  3074. * @param string $args Any additional arguments
  3075. * @return string
  3076. */
  3077. function _prepareCommand($path, $command, $args='')
  3078. {
  3079. if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN' || !preg_match('/\s/', $path))
  3080. {
  3081. return $path.' '.$command.' '.$args;
  3082. }
  3083. return 'start /D "'.$path.'" /B '.$command.' '.$args;
  3084. }
  3085. /**
  3086. * Generates a unique id. Primarily used in jpeg to movie production
  3087. *
  3088. * @access public
  3089. * @param string $prefix
  3090. * @return string
  3091. */
  3092. function unique($prefix='')
  3093. {
  3094. return uniqid($prefix.time().'-');
  3095. }
  3096. /**
  3097. * Destructs ffmpeg and removes any temp files/dirs
  3098. * @access private
  3099. */
  3100. function __destruct()
  3101. {
  3102. // loop through the temp files to remove first as they have to be removed before the dir can be removed
  3103. if(!empty($this->_unlink_files))
  3104. {
  3105. foreach ($this->_unlink_files as $key=>$file)
  3106. {
  3107. if(is_file($file))
  3108. {
  3109. @unlink($file);
  3110. }
  3111. }
  3112. $this->_unlink_files = array();
  3113. }
  3114. // loop through the dirs to remove
  3115. if(!empty($this->_unlink_dirs))
  3116. {
  3117. foreach ($this->_unlink_dirs as $key=>$dir)
  3118. {
  3119. if(is_dir($dir))
  3120. {
  3121. @rmdir($dir);
  3122. }
  3123. }
  3124. $this->_unlink_dirs = array();
  3125. }
  3126. }
  3127. }