*/ /** * Define some constants */ define('VIDEO_RENDERING_PENGING', 0); define('VIDEO_RENDERING_ACTIVE', 5); define('VIDEO_RENDERING_COMPLETE', 10); /** * Implementation of hook_help(). */ function video_ffmpeg_helper_help($section) { switch ($section) { case 'admin/modules#description': return t('Enable thumbnails support for video module.'); } } /** * Implementation of hook_menu() */ function video_ffmpeg_helper_menu($may_cache) { $items = array(); if ($may_cache) { $items[] = array( 'path' => 'admin/content/video/ffmpeg_helper', 'title' => t('Video ffmpeg Helper'), 'description' => t('Administer video_ffmpeg_helper module settings'), 'callback' => 'drupal_get_form', 'callback arguments' => array('video_ffmpeg_helper_admin_settings'), 'access' => user_access('administer site configuration'), 'type' => MENU_NORMAL_ITEM, ); } return $items; } /** * Validation for settings form */ function video_ffmpeg_helper_admin_settings_validate($form_id, &$form_values, &$form) { if ($form_values['video_ffmpeg_helper_auto_thumbnail']) { if (function_exists('is_executable')) { $test = 'is_executable'; } else { $test = 'file_exists'; } if (!$test($form_values['video_ffmpeg_helper_ffmpeg_path'])) { form_set_error('video_image_ffmpeg_path', t('Set correct path for thumbnailer')); } if (!is_numeric($form_values['video_ffmpeg_helper_auto_thumbnail_seek'])) { form_set_error('video_ffmpeg_helper_auto_thumbnail_seek', t('Seek time must be an integer')); } $options = $form_values['video_ffmpeg_helper_thumbnailer_options']; if (!strstr($options, '%videofile') || !strstr($options, '%thumbfile')) { form_set_error('video_ffmpeg_helper_thumbnailer_options', t('Thumbnail options must contain mandatory arguments %videofile and %thumbfile')); } } } /** * Settings form */ function video_ffmpeg_helper_admin_settings() { // let's execute after video_image if (module_exists('video_image')) { if (variable_get('video_ffmpeg_helper_auto_thumbnail', 0)) { $upload_weight = db_result(db_query("SELECT weight FROM {system} WHERE name='video_image'")); db_query("UPDATE {system} SET weight=".($upload_weight+1)." WHERE name='video_ffmpeg_helper'"); } } $form['video_ffmpeg_helper_ffmpeg_path'] = array( '#type' => 'textfield', '#title' => t('FFmpeg executable path'), '#description' => t('Set the full path to the ffmpeg executable here.'), '#default_value' => variable_get('video_ffmpeg_helper_ffmpeg_path', '/usr/bin/ffmpeg'), ); $form['video_ffmpeg_helper_auto_resolution'] = array( '#type' => 'checkbox', '#title' => t('Enable resolution helper'), '#description' => t('Use ffmpeg Helper to automaticcally get the resolution from the video.'), '#default_value' => variable_get('video_ffmpeg_helper_auto_resolution', false), ); $form['video_ffmpeg_helper_auto_playtime'] = array( '#type' => 'checkbox', '#title' => t('Enable playtime helper'), '#description' => t('Use ffmpeg Helper to automaticcally get the playtime from the video.'), '#default_value' => variable_get('video_ffmpeg_helper_auto_playtime', false), ); $form['autothumb'] = array( '#type' => 'fieldset', '#title' => t('Automatic video thumbnailing'), '#collapsible' => TRUE, '#collapsed' => TRUE ); $form['autothumb']['video_ffmpeg_helper_auto_thumbnail'] = array( '#type' => 'checkbox', '#title' => t('Auto thumbnail for videos'), '#description' => t('If set up correctly, this will auto-generate a thumbnail for each video created.'), '#default_value' => variable_get('video_ffmpeg_helper_auto_thumbnail', false), ); $form['autothumb']['video_ffmpeg_helper_auto_thumbnail_only'] = array( '#type' => 'checkbox', '#title' => t('Use auto-thumbnailer exclusively for video images'), '#description' => t('If checked, this will disable the file upload box for the user-supplied thumbnail. Only check this if you have checked to be sure that auto-thumbnailing works. Auto thumbnail must be selected for this to be enabled.'), '#default_value' => variable_get('video_ffmpeg_helper_auto_thumbnail_only', false), '#disabled' => !variable_get('video_ffmpeg_helper_auto_thumbnail', false), ); $form['autothumb']['video_ffmpeg_helper_thumbnailer_options'] = array( '#type' => 'textfield', '#title' => t('Video thumbnailer options'), '#description' => t('Provide the options for the thumbnailer. Available argument values are: ').'
  1. '.t('%videofile (the video file to thumbnail)').'
  2. '.t('%thumbfile (a newly created temporary file to overwrite with the thumbnail)').'
  3. '.t('%seek (seconds to seek into video before extracting image).').'
'.t('Only the first two are mandatory. For example, older versions of ffmpeg should use something like: !old While newer versions should use something like: !new', array('!old' => "
-i %videofile -y -an -f mjpeg -ss %seek -t 0.001 %thumbfile
", '!new' => '
-i %videofile -an -y -f mjpeg -ss %seek -vframes 1 %thumbfile
')), '#default_value' => variable_get('video_ffmpeg_helper_thumbnailer_options', '-i %videofile -an -y -f mjpeg -ss %seek -vframes 1 %thumbfile'), ); $form['autothumb']['video_ffmpeg_helper_auto_thumbnail_seek'] = array( '#type' => 'textfield', '#title' => t('Video seek offset for thumbnail'), '#description' => t('Time in seconds to seek into video before extracting the thumbnail'), '#default_value' => variable_get('video_ffmpeg_helper_auto_thumbnail_seek', 2), ); $form['autothumb']['video_ffmpeg_helper_auto_thumbnail_debug'] = array( '#type' => 'checkbox', '#title' => t('Debug auto-thumbnail process'), '#default_value' => variable_get('video_ffmpeg_helper_auto_thumbnail_debug', false), ); // automatic video conversion settings $form['autoconv'] = array( '#type' => 'fieldset', '#title' => t('Automatic video conversion'), '#collapsible' => TRUE, '#collapsed' => TRUE ); $form['autoconv']['video_ffmpeg_helper_auto_conversion'] = array( '#type' => 'checkbox', '#title' => t('Auto conversion for videos'), '#description' => t('If set up correctly, this will auto-convert each uploaded video to the configured format.') . '
' . t("IMPORTANT: you will need the video_render.php correctly configured and run by cron. See README.txt for more informations."), '#default_value' => variable_get('video_ffmpeg_helper_auto_conversion', false), ); $form['autoconv']['video_ffmpeg_helper_auto_converter_width'] = array( '#type' => 'textfield', '#title' => t('Video rendering width'), '#description' => t('The width of the converted video. The height will be automatically calculated to maintain aspect ratio.'), '#size' => 3, '#maxlength' => 3, '#default_value' => variable_get('video_ffmpeg_helper_auto_converter_width', 400), ); $form['autoconv']['video_ffmpeg_helper_auto_converter_video_bitrate'] = array( '#type' => 'textfield', '#title' => t('Video bitrate'), '#description' => t('The video bitrate in kbit/s of the converted video.'), '#size' => 3, '#maxlength' => 4, '#default_value' => variable_get('video_ffmpeg_helper_auto_converter_video_bitrate', 200), ); $form['autoconv']['video_ffmpeg_helper_auto_converter_audio_bitrate'] = array( '#type' => 'textfield', '#title' => t('Audio bitrate'), '#description' => t('The audio bitrate in kbit/s of the converted video.'), '#size' => 3, '#maxlength' => 4, '#default_value' => variable_get('video_ffmpeg_helper_auto_converter_audio_bitrate', 64), ); $form['autoconv']['video_ffmpeg_helper_auto_converter_busy_video_path'] = array( '#type' => 'textfield', '#title' => t('Busy video path'), '#description' => t('Provide the relative path to a video displayed when the video is being rendered.'), '#default_value' => variable_get('video_ffmpeg_helper_auto_converter_busy_video_path', 'busy.flv'), ); $form['autoconv']['advanced'] = array( '#type' => 'fieldset', '#title' => t('Advanced settings'), '#collapsible' => TRUE, '#collapsed' => TRUE ); $form['autoconv']['advanced']['video_ffmpeg_helper_auto_converter_options'] = array( '#type' => 'textfield', '#title' => t('Video converter options'), '#description' => t('Provide the ffmpeg options to configure the video conversion. Available argument values are: ').''. t('For further informations refer to the !ffmpegdoc', array('!ffmpegdoc' => l(t('Official FFMpeg documentation.'), 'http://ffmpeg.mplayerhq.hu/ffmpeg-doc.html', NULL, NULL, TRUE))), '#default_value' => variable_get('video_ffmpeg_helper_auto_converter_options', '-y -i %videofile -f flv -ar 22050 -ab %audiobitrate -s %size -b %videobitrate %convertfile'), ); return system_settings_form($form); } /** * Implementation of hook_form_alter() */ function video_ffmpeg_helper_form_alter($form_id, &$form) { //print_r($form); if($form_id == 'video_node_form') { if (function_exists('_image_check_settings')) { _image_check_settings(); $form['#attributes'] = array("enctype" => "multipart/form-data"); if (variable_get('video_ffmpeg_helper_auto_thumbnail_only', false)) { // delete the video image parts $form['image'] = NULL; } } if(variable_get('video_ffmpeg_helper_auto_resolution', false) || variable_get('video_ffmpeg_helper_auto_convert', false)) { $form['video']['videox'] = NULL; $form['video']['videoy'] = NULL; } if(variable_get('video_ffmpeg_helper_auto_playtime', false)) { $form['video']['playtime'] = NULL; } } } /** * Implementation of hook_nodeapi() */ function video_ffmpeg_helper_nodeapi(&$node, $op, $teaser) { if($node->type == 'video') { switch ($op) { case 'load': ; // for future uses break; case 'submit': if(variable_get('video_ffmpeg_helper_auto_resolution', false) || variable_get('video_ffmpeg_helper_auto_playtime', false)) { _video_ffmpeg_helper_get_video_info($node); } break; case 'insert': if(variable_get('video_ffmpeg_helper_auto_conversion', false)) { // add rendering job to queue _video_ffmpeg_helper_add_rendering($node); } break; case 'prepare': ; // for future uses break; case 'view': ; // for future uses break; case 'delete': db_query('DELETE FROM {video_rendering} WHERE vid = %d AND nid = %d', $node->vid, $node->nid); break; } } } /** * Add a video conversion rendering process to the queue */ function _video_ffmpeg_helper_add_rendering(&$node) { $file = $_SESSION['video_upload_file_stored']->filepath; //print_r($node); die; db_query('INSERT INTO {video_rendering} (vid, nid, origfile, pid, status, started, completed) VALUES (%d, %d, "%s", %d, %d, %d, %d)', $node->vid, $node->nid, $file, 0, VIDEO_RENDERING_PENGING, 0, 0); // let's add the rendering in progress video $node->vidfile = variable_get('video_ffmpeg_helper_auto_converter_busy_video_path', 'busy.flv'); db_query('UPDATE {video} SET vidfile = "%s" WHERE nid=%d AND vid=%d', $node->vidfile, $node->nid, $node->vid); } /** * Get some informations from the video file */ function _video_ffmpeg_helper_get_video_info(&$node) { // escape file name for safety $file = escapeshellarg($_SESSION['video_upload_file']->filepath); // create the full command to execute $command = variable_get('video_ffmpeg_helper_ffmpeg_path', '/usr/bin/ffmpeg') . ' -i ' . $file; drupal_set_message('executing' . $command); //execute the command ob_start(); passthru($command." 2>&1", $command_return); $command_output = ob_get_contents(); ob_end_clean(); // print $command_output; if(variable_get('video_ffmpeg_helper_auto_resolution', false)) { // get resolution $pattern = '/[0-9]{3}x[0-9]{3}/'; preg_match_all($pattern, $command_output, $matches, PREG_PATTERN_ORDER); $resolution = $matches[0][0]; $xy = explode("x", $resolution); // store resolution information to the node object $node->videox = $xy[0]; $node->videoy = $xy[1]; } if(variable_get('video_ffmpeg_helper_auto_playtime', false)) { // get playtime $pattern = '/[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]/'; preg_match_all($pattern, $command_output, $matches, PREG_PATTERN_ORDER); $playtime = $matches[0][0]; // ffmpge return lenght as 00:00:31.1 Let's get playtime from that $hmsmm = explode(":", $playtime); $tmp = explode(".", $hmsmm[2]); $seconds = $tmp[0]; $hours = $hmsmm[0]; $minutes = $hmsmm[1]; $node->playtime_seconds = $seconds + ($hours * 3600) + ($minutes * 60); } //print_r($node); die; } /* Generates a thumbnail from the video file * * @param $node * object with node information * * @return * a drupal file object */ function _video_ffmpeg_helper_auto_thumbnail(&$node) { if(empty($_SESSION['video_upload_file']) || !$_SESSION['video_upload_file']->newfile || $node->iid || $_SESSION['video_upload_file']->iid || $_SESSION['video_upload_file']->thumbnailed) { if (variable_get('video_image_auto_thumbnail_debug', false)) { if (empty($_SESSION['video_upload_file'])) drupal_set_message(t('no video has been uploaded: make sure that video_image weight is greater than video_upload weight; make sure that the video file is not too large to be uploaded.')); } return null; } $debug = variable_get('video_image_auto_thumbnail_debug', false); $videofile = escapeshellarg($_SESSION['video_upload_file']->filepath); $thumbfile = tempnam(file_directory_temp(), 'tnail-thumb'); $seek = variable_get('video_image_auto_thumbnail_seek', 2); $tnail = variable_get('video_image_thumbnailer_path', '/usr/bin/ffmpeg'); $options = preg_replace(array('/%videofile/', '/%thumbfile/', '/%seek/'), array($videofile, $thumbfile, $seek), variable_get('video_image_thumbnailer_options', '-i %videofile -an -y -f mjpeg -ss %seek -vframes 1 %thumbfile')); $command = "$tnail $options"; ob_start(); passthru($command." 2>&1", $tnail_return); $tnail_output = ob_get_contents(); ob_end_clean(); if ($debug) { drupal_set_message(t('Thumbnailer command: ').$command); drupal_set_message(t('Thumbnailer output: ')."
\n$tnail_output\n
"); } if (!file_exists($thumbfile)) { drupal_set_message(t('video_image_auto_thumbnail: file %file does not exist', array('%file' => $thumbfile)), 'error'); } $file = array( 'filename' => $_SESSION['video_upload_file']->filename . ".video-thumb.jpg", 'filemime' => 'image/jpeg', 'filesize' => filesize($thumbfile), 'filepath' => $thumbfile, 'nid' => $node->nid, ); $_SESSION['video_upload_file']->thumbnailed = TRUE; if ($debug) { if ($tnail_return) { drupal_set_message(t('Failed to thumbnail video')); } else { drupal_set_message(t('Successfully thumbnailed video')); } } return (object)$file; }