/[drupal]/contributions/modules/ffmpeg_wrapper/ffmpeg_wrapper.module
ViewVC logotype

Contents of /contributions/modules/ffmpeg_wrapper/ffmpeg_wrapper.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.5 - (show annotations) (download) (as text)
Fri Mar 21 19:59:59 2008 UTC (20 months, 1 week ago) by arthuregg
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +2 -2 lines
File MIME type: text/x-php
fixes a legacy function name
1 <?php
2
3 /* $Id: ffmpeg_wrapper.module,v 1.4 2008/03/16 14:11:41 arthuregg Exp $ */
4
5 // This implements a wrapper for FFmpeg so that we don't have to reinvent the
6 // the wheel everytime we want to do soemthing with video, audio, or images
7
8
9 /* ************************************************ */
10 /* DRUPAL HOOKS */
11 /* ************************************************ */
12
13 /**
14 * Implementation of hook_menu().
15 */
16 function ffmpeg_wrapper_menu($may_cache) {
17 $items = array();
18 if ($may_cache) {
19 $items[] = array(
20 'path' => 'admin/settings/ffmpeg_wrapper',
21 'title' => t('Settings'),
22 'callback' => 'drupal_get_form',
23 'callback arguments' => array('ffmpeg_wrapper_admin'),
24 'access' => user_access('administer ffmpeg wrapper'),
25 );
26 }
27 return $items;
28 }
29
30
31 /**
32 * implementation of hook_perm()
33 */
34 function ffmpeg_wrapper_perm() {
35 return array('administer ffmpeg wrapper');
36 }
37
38
39 /**
40 * builds the admin form
41 * @return drupal form array
42 */
43 function ffmpeg_wrapper_admin() {
44
45 $form['ffmpeg_wrapper'] = array(
46 '#type' => 'fieldset',
47 '#title' => t('FFmpeg'),
48 );
49
50 $form['ffmpeg_wrapper']['mm_ffmpeg_about'] = array(
51 '#type' => 'fieldset',
52 '#title' => t('About FFmpeg installation'),
53 '#collapsible' => true,
54 '#collapsed' => true,
55 );
56
57 $form['ffmpeg_wrapper']['mm_ffmpeg_about']['mm_ffmpeg_version'] = array(
58 '#type' => 'item',
59 '#title' => t('FFmpeg version'),
60 '#value' => '<blockquote>'. ffmpeg_wrapper_run_command(' -v') .'</blockquote>',
61 '#description' => t('Version of FFmpeg running on your system'),
62 );
63
64 $form['ffmpeg_wrapper']['mm_ffmpeg_about']['mm_ffmpeg_formats'] = array(
65 '#type' => 'item',
66 '#title' => t('Supported file formats'),
67 '#value' => ffmpeg_wrapper_formats_data_display(),
68 '#description' => t('File formats that the installed version of FFmpeg supports.'),
69 );
70
71 $form['ffmpeg_wrapper']['mm_ffmpeg_about']['mm_ffmpeg_codecs'] = array(
72 '#type' => 'item',
73 '#title' => t('Installed codecs'),
74 '#value' => ffmpeg_wrapper_get_codecs_display(),
75 '#description' => t('FFmpeg was either compiled with these codecs, or these are the codecs available on your system'),
76 );
77
78 $form['ffmpeg_wrapper']['ffmpeg_wrapper_path'] = array(
79 '#type' => 'textfield',
80 '#title' => t('FFmpeg path'),
81 '#default_value' => variable_get('ffmpeg_wrapper_path', '/usr/bin/ffmpeg'),
82 '#description' => t("Absolute path to the FFmpeg exeutable."),
83 );
84
85 return system_settings_form($form);
86 }
87
88 /* ************************************************ */
89 /* FFmpeg Wrapper Functions */
90 /* ************************************************ */
91
92
93 /**
94 * gets data from ffmpeg
95 * @param $options are the options to run ffmpeg with
96 * @return output of the command
97 */
98 function ffmpeg_wrapper_run_command($options) {
99 $command = variable_get('ffmpeg_wrapper_path', '/opt/ffmpeg/current/bin/ffmpeg') .' '. $options;
100
101 ob_start();
102 passthru($command." 2>&1", $command_return );
103 $command_output = ob_get_contents();
104 ob_end_clean();
105
106 return $command_output;
107 }
108
109
110
111 /**
112 * checks an incoming file path extension to
113 * see if it can be decoded
114 * @param $file is a full system filepath
115 * @return true if file is in the list of decodeable files
116 */
117 function ffmpeg_wrapper_can_decode($path){
118 $file_types = ffmpeg_wrapper_get_file_formats('decode');
119
120 $path_parts = pathinfo($path);
121
122 // exception handling
123 // WMVs are sometimes asf files
124 if ($path_parts['extension'] == 'wmv') {$exception = 'asf';}
125
126 if ($file_types) {
127 foreach ($file_types as $file_type) {
128 if ($path_parts['extension']) {
129 if (stristr($file_type, $path_parts['extension']) || stristr($file_type, $exception) ) {
130 return true;
131 }
132 }
133 }
134 }
135 return false;
136 }
137
138
139 /**
140 * gets an array of codec types usable on this system
141 * this should probably be smoothed out so that it doesn't rely on
142 * text so much
143 * @ TODO this needs to be rethought to pass params right
144 * @param string $ret determins hand back of encode/decode
145 * @return is array of codecs or specific encode/decode options
146 */
147 function ffmpeg_wrapper_get_codecs($ret = null) {
148
149 // get formats from ffmpeg
150 $output = ffmpeg_wrapper_run_command('-formats');
151
152 // parse the list
153 // we know where the codecs are by looking at the output of ffmpeg -formats
154 $codecs_formats_pos = strpos($output, "Codecs:");
155 $codecs_formats_pos_end = strpos($output, "upported file protocols:");
156
157 $video_formats = substr($output, $codecs_formats_pos, ($codecs_formats_pos_end - $codecs_formats_pos));
158
159 $video_formats = str_replace('Codecs:', '', $video_formats);
160 $video_formats = explode("\n", $video_formats);
161
162 foreach ($video_formats as $format) {
163
164 // codec names seem to always be here
165 $a_format['name'] = substr($format, 8);
166
167 if (substr($format, 3, 1) == 'A') {
168 $a_format['type'] = t('audio');
169 $encode_formats[] = $a_format['name'];
170 }
171 else {
172 $a_format['type'] = t('video');
173 }
174
175 // get the decode
176 if (substr($format, 1, 1) == 'D') {
177 $a_format['decode'] = t('yes');
178 $decode_formats[] = $a_format['name'];
179 }
180 else {
181 $a_format['decode'] = t('no');
182 }
183
184 // get the encode
185 if (substr($format, 2, 1) == 'E') {
186 $a_format['encode'] = t('yes');
187 $encode_formats[] = $a_format['name'];
188 }
189 else {
190 $a_format['encode'] = t('no');
191 }
192
193 if ($a_format['name']) {
194 $rows[] = $a_format;
195 }
196 $a_format = null;
197 }
198
199 switch ($ret) {
200 case 'encode':
201 return $encode_formats;
202 break;
203 case 'decode':
204 return $decode_formats;
205 break;
206 default:
207 return $rows;
208 break;
209 }
210 }
211
212
213 /**
214 * gets an array of format types usable on this system
215 * this should probably be smoothed out so that it doesn't rely on
216 * text so much
217 * @param string $ret determins what to hand back (encode/decode)
218 * @return array of options
219 */
220 function ffmpeg_wrapper_get_file_formats($ret = null) {
221 static $rows, $encode_formats, $decode_formats;
222
223 // only parse if this hasn't been set
224 if (! is_array($rows)) {
225 $formats = ffmpeg_wrapper_run_command('-formats');
226
227 // slice up the format output
228 $startpos = strpos($formats, 'File formats:');
229 $endpos = strpos($formats, 'Codecs:');
230 $formats = substr($formats, $startpos, $endpos);
231
232 //remove the header
233 $formats = str_replace('File formats:', '', $formats);
234
235 $formats = explode("\n", $formats);
236
237 $decode_formats = array();
238 $encode_formats = array();
239
240 foreach ($formats as $format) {
241
242 // only run on lines longer than 3
243 if (! strlen($format) < 3) {
244 // codec names seem to always be here
245 $pattern = '/\s+/';
246 $replace = ' ';
247 $type = preg_replace($pattern, $replace, substr($format, 4, 19));
248 $type = explode(' ', $type);
249
250 $a_format['type'] = $type[0];
251 $a_format['name'] = $type[1];
252
253 if (substr($format, 1, 1) == 'D') {
254 $a_format['decode'] = t('yes');
255 $decode_formats[] = $a_format['type'];
256 }
257 else {
258 $a_format['decode'] = t('no');
259 }
260
261 if (substr($format, 2, 1) == 'E') {
262 $a_format['encode'] = t('yes');
263 $encode_formats[] = $a_format['type'];
264 }
265 else {
266 $a_format['encode'] = t('no');
267 }
268
269 $a_format['description'] = substr($format, 20);
270 if ($a_format['description']) {
271 $rows[] = $a_format;
272 }
273 }
274 }
275 }
276
277 switch ($ret) {
278 case 'encode':
279 return $encode_formats;
280 break;
281 case 'decode':
282 return $decode_formats;
283 break;
284 default:
285 return $rows;
286 break;
287 }
288 }
289
290
291 /**
292 * this gets the duration of a video
293 * @param string $path is the path to file
294 * @param boolean $timecode return time code or seconds
295 * @return int is the duration in seconds or timecode as string
296 */
297 function ffmpeg_wrapper_file_duration($path, $timecode) {
298 // get duration from ffmpeg
299 $output = ffmpeg_wrapper_run_command("-i $path");
300
301 // parse the output looking for "Duration: 00:02:12"
302 $pattern = "/Duration: (.*[0-9:])(\.*[0-9]), start/";
303 preg_match($pattern, $output, $matches);
304
305 $time = $matches[1];
306
307 if (! $timecode) {
308 // now we need to convert the time code to seconds
309 // get the time into an array, note that the array is hh:mm:ss
310 $time = explode(':', $time);
311
312 $seconds = $time[2];
313
314 if ($time[1] != '00') {
315 $seconds = $seconds + ($time[1] * 60);
316 }
317 if ($time[0] != '00') {
318 $seconds = $seconds + ($time[0] * 3600);
319 }
320
321 $time = $seconds;
322 }
323
324 return $time;
325 }
326
327
328 /**
329 * checks to make sure that FFmpeg is in the path
330 * @return boolean
331 */
332 function ffmpeg_wrapper_executable(){
333 if (! ffmpeg_wrapper_run_command('')) {
334 return false;
335 }
336 return true;
337 }
338
339
340 /**
341 * displays a table of the supported ffmpeg file formats
342 */
343 function ffmpeg_wrapper_formats_data_display() {
344 $header = array(t('name'), t('type'), t('decode'), t('encode'), t('description') );
345 $output = theme('table', $header, ffmpeg_wrapper_get_file_formats() );
346 return $output;
347 }
348
349
350 /**
351 * displays a table of the ffmpeg encoding and decoding options
352 */
353 function ffmpeg_wrapper_get_codecs_display() {
354 $header = array(t('codec'), t('codec type'), t('decode'), t('encode'));
355 $output = theme('table', $header, ffmpeg_wrapper_get_codecs() );
356 return $output;
357 }
358
359
360 /**
361 * checks ffmpeg's output for errors and tries to handle them some way
362 * @param $output is the output from a shell command
363 * @param $file is the input file
364 * @param $command is the command run
365 * @param $watchdog is boolean, log errors to drupal's watchdog
366 * @return true if no errors, false if errors
367 *
368 **/
369 function ffmpeg_wrapper_error_check($output, $file, $command, $watchdog = true) {
370
371 // build the error conditions
372 // these are all pulled by hand at this point
373 $errors = array(
374 '/Segmentation fault/i',
375 '/Unsupported/i',
376 //'/Error while/i', // this is not necessarily fatal
377 '/Unable for find a suitable output format for/i',
378 '/Incorrect frame size/i',
379 '/Unsupported codec/i',
380 '/Could not write header/i',
381 '/Incorrect frame size/i',
382 );
383
384 // check for error conditions
385 foreach ($errors as $error) {
386 if ($match = preg_match($error, $output)) {
387 ffmpeg_wrapper_error_log($output, $file, $command, $watchdog);
388 return false;
389 }
390 }
391 return true;
392 }
393
394
395 /**
396 * takes error conditions from the conversion process and deals
397 * with them according to the admin configuration
398 *
399 * @param $output is the command line output
400 * @param $file is the file that failed
401 * @param $configuration is the configuration that was running
402 * @param boolean $watchdog should we log this?
403 */
404 function ffmpeg_wrapper_error_log($output, $file, $command, $watchdog){
405
406 // create an error log
407 $message = t('FFmpeg had an error converting this file: %file', array('%file' => $file));
408 $message .= '<br />'. t('The command was: ') . $command;
409
410 if ($watchdog) {
411 watchdog('FFmpeg', $message, 'WATCHDOG_NOTICE');
412 }
413 }
414

  ViewVC Help
Powered by ViewVC 1.1.2