Example #1
0
/**
 * Convert a stored video file to flashvideo
 *
 * @param array $pParamHash
 * @access public
 * @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
 */
function mime_video_converter(&$pParamHash, $pOnlyGetParameters = FALSE)
{
    global $gBitSystem;
    // video conversion can take a while
    ini_set("max_execution_time", "1800");
    $ret = FALSE;
    if (@BitBase::verifyId($pParamHash['attachment_id'])) {
        // we might have some attachment preferences set if this is an update
        LibertyMime::expungeAttachmentPreferences($pParamHash['attachment_id']);
        // these are set in the liberty plugin admin screen
        $ffmpeg = trim($gBitSystem->getConfig('ffmpeg_path', shell_exec('which ffmpeg')));
        $width = trim($gBitSystem->getConfig('mime_video_width', 320));
        $begin = date('U');
        $log = $actionLog = array();
        if (!is_executable($ffmpeg)) {
            $log['time'] = date('Y-M-d - H:i:s O');
            $log['duration'] = 0;
            $log['message'] = 'ERROR: ffmpeg does not seem to be available on your system at: ' . $ffmpeg . ' Please set the path to ffmpeg in the liberty plugin administration screen.';
            $actionLog['log_message'] = "ERROR: ffmpeg does not seem to be available on your system at: '{$ffmpeg}' Please set the path to ffmpeg in the liberty plugin administration screen.";
        } else {
            // this is the codec we'll use - currently this might be: flv, h264, h264-2pass
            $codec = $gBitSystem->getConfig("mime_video_video_codec", "flv");
            $source = STORAGE_PKG_PATH . $pParamHash['upload']['dest_branch'] . $pParamHash['upload']['name'];
            $destPath = dirname($source);
            // set some default values if ffpeg-php isn't available or fails
            $default['aspect'] = 4 / 3;
            $default['video_width'] = $width;
            $default['video_height'] = round($width / 4 * 3);
            $default['size'] = "{$default['video_width']}x{$default['video_height']}";
            $default['offset'] = '00:00:10';
            if (extension_loaded('ffmpeg')) {
                // we silence these calls since they might spew errors
                $movie = @new ffmpeg_movie($source);
                $info = array('vcodec' => @$movie->getVideoCodec(), 'duration' => round(@$movie->getDuration()), 'width' => @$movie->getFrameWidth(), 'height' => @$movie->getFrameHeight(), 'video_bitrate' => @$movie->getVideoBitRate(), 'acodec' => @$movie->getAudioCodec(), 'audio_bitrate' => @$movie->getAudioBitRate(), 'audio_samplerate' => @$movie->getAudioSampleRate());
                // make sure audio sample rate is valid
                if (!empty($info['audio_samplerate']) && !in_array($info['audio_samplerate'], array(11025, 22050, 44100))) {
                    unset($info['audio_samplerate']);
                }
            } else {
                // alternative method using ffmpeg to fetch source dimensions
                $command = "{$ffmpeg} -i " . escapeshellarg($source) . ' 2>&1';
                exec($command, $output, $status);
                if (!preg_match('/Stream #(?:[0-9\\.]+)(?:.*)\\: Video: (?P<videocodec>.*) (?P<width>[0-9]*)x(?P<height>[0-9]*)/', implode('\\n', $output), $matches)) {
                    preg_match('/Could not find codec parameters \\(Video: (?P<videocodec>.*) (?P<width>[0-9]*)x(?P<height>[0-9]*)\\)/', implode('\\n', $output), $matches);
                }
                if (!empty($matches['width']) && !empty($matches['height'])) {
                    $info['width'] = $matches['width'];
                    $info['height'] = $matches['height'];
                }
            }
            // our player supports flv and h264 so we might as well use the default
            if (!$gBitSystem->isFeatureActive('mime_video_force_encode') && !empty($info) && ($info['vcodec'] == 'h264' && (empty($info['acodec']) || $info['acodec'] == 'mpeg4aac' || $info['acodec'] == 'aac') || $info['vcodec'] == 'flv' && (empty($info['acodec']) || $info['acodec'] == 'mp3'))) {
                // work out what the target filename is
                $extension = $info['vcodec'] == "flv" ? "flv" : "mp4";
                $dest_file = $destPath . "/flick.{$extension}";
                // if the video can be processed by ffmpeg-php, width and height are greater than 1
                if (!empty($info['width']) && $info['width'] > 1) {
                    $info['aspect'] = $info['width'] / $info['height'];
                    $info['offset'] = strftime("%T", round($info['duration'] / 5 - 60 * 60));
                } else {
                    $info = $default;
                }
                // store prefs and create thumbnails
                LibertyMime::expungeMetaData($pParamHash['attachment_id']);
                LibertyMime::storeMetaData($pParamHash['attachment_id'], 'Video', $info);
                mime_video_create_thumbnail($source, $info['offset']);
                if (!is_file($dest_file) && !link($source, $dest_file)) {
                    copy($source, $dest_file);
                }
                mime_video_fix_streaming($dest_file);
                $log['message'] = 'SUCCESS: Converted to flash video';
                $actionLog['log_message'] = "Video file was successfully uploaded and thumbnails extracted.";
                $ret = TRUE;
            } else {
                // work out what the target filename is
                $extension = $codec == "flv" ? "flv" : "mp4";
                $dest_file = $destPath . "/flick.{$extension}";
                // if the video can be processed by ffmpeg-php, width and height are greater than 1
                if (!empty($info['width']) && $info['width'] > 1) {
                    // reset some values to reduce video size
                    if ($info['width'] < $width) {
                        $width = $info['width'];
                    }
                    // here we calculate the size and aspect ratio of the output video
                    $size_ratio = $width / $info['width'];
                    $info['aspect'] = $info['width'] / $info['height'];
                    $info['video_width'] = $width;
                    $info['video_height'] = round($size_ratio * $info['height']);
                    // height of video needs to be an even number
                    if ($info['video_height'] % 2) {
                        $info['video_height']++;
                    }
                    $info['size'] = "{$info['video_width']}x{$info['video_height']}";
                } else {
                    $info = $default;
                }
                // transfer settings to vars for easy manipulation for various APIs of ffmpeg
                $audio_bitrate = $gBitSystem->getConfig('mime_video_audio_bitrate', 32000) / 1000 . 'kb';
                $audio_samplerate = $gBitSystem->getConfig('mime_video_audio_samplerate', 22050);
                $video_bitrate = $gBitSystem->getConfig('mime_video_video_bitrate', 160000) / 1000 . 'kb';
                $acodec_mp3 = $gBitSystem->getConfig('ffmpeg_mp3_lib', 'libmp3lame');
                $me_param = $gBitSystem->getConfig('ffmpeg_me_method', 'me');
                if ($codec == "h264") {
                    $parameters = " -i '{$source}'" . " -acodec libfaac" . " -ab {$audio_bitrate}" . " -ar {$audio_samplerate}" . " -vcodec libx264" . " -b {$video_bitrate}" . " -bt {$video_bitrate}" . " -s " . $info['size'] . " -aspect " . $info['aspect'] . " -flags +loop -cmp +chroma -refs 1 -coder 0 -me_range 16 -g 300 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -maxrate 10M -bufsize 10M -rc_eq 'blurCplx^(1-qComp)' -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -level 30" . " -partitions +parti4x4+partp8x8+partb8x8 -{$me_param} epzs -subq 5 -trellis 1" . " -y '{$dest_file}'";
                } elseif ($codec == "h264-2pass") {
                    // it is not possible to pass in the path for the x264 log file and it is always generated in the working dir.
                    $cwd = getcwd();
                    chdir(dirname($dest_file));
                    $passlogfile = dirname($dest_file) . "/ffmpeg2pass";
                    // pass 1
                    $parameters = " -i '{$source}'" . " -an" . " -pass 1" . " -passlogfile {$passlogfile}" . " -vcodec libx264" . " -b {$video_bitrate}" . " -bt {$video_bitrate}" . " -s " . $info['size'] . " -aspect " . $info['aspect'] . " -flags +loop -cmp +chroma -refs 1 -coder 0 -me_range 16 -g 300 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -bf 16 -maxrate 10M -bufsize 10M -rc_eq 'blurCplx^(1-qComp)' -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -level 30" . " -partitions 0 -{$me_param} epzs -subq 1 -trellis 0" . " -y '{$dest_file}'";
                    // pass 2
                    $parameters2 = " -i '{$source}'" . " -acodec libfaac" . " -ab {$audio_bitrate}" . " -ar {$audio_samplerate}" . " -pass 2" . " -passlogfile {$passlogfile}" . " -vcodec libx264" . " -b {$video_bitrate}" . " -bt {$video_bitrate}" . " -s " . $info['size'] . " -aspect " . $info['aspect'] . " -flags +loop -cmp +chroma -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -rc_eq 'blurCplx^(1-qComp)' -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4" . " -partitions +parti8x8+parti4x4+partp8x8+partp4x4+partb8x8 -flags2 +brdo+dct8x8+wpred+bpyramid+mixed_refs -{$me_param} epzs -subq 7 -trellis 1 -refs 6 -bf 16 -directpred 3 -b_strategy 1 -bidir_refine 1 -coder 1" . " -y '{$dest_file}'";
                } else {
                    $parameters = " -i '{$source}'" . " -acodec {$acodec_mp3}" . " -ab {$audio_bitrate}" . " -ar {$audio_samplerate}" . " -f flv" . " -b {$video_bitrate}" . " -bt {$video_bitrate}" . " -s " . $info['size'] . " -aspect " . $info['aspect'] . " -y '{$dest_file}'";
                }
                if ($pOnlyGetParameters) {
                    return $parameters;
                } else {
                    // we keep the output of this that we can store it to the error file if we need to do so
                    $debug = shell_exec("{$ffmpeg} {$parameters} 2>&1");
                    if (!empty($parameters2)) {
                        $debug .= shell_exec("{$ffmpeg} {$parameters2} 2>&1");
                        // change back to whence we came
                        chdir($cwd);
                    }
                }
                // make sure the conversion was successfull
                if (is_file($dest_file) && filesize($dest_file) > 48) {
                    mime_video_fix_streaming($dest_file);
                    // try to work out a reasonable timepoint where to extract a screenshot
                    if (preg_match('!Duration: ([\\d:\\.]*)!', $debug, $time)) {
                        list($h, $m, $s) = explode(':', $time[1]);
                        $seconds = round(60 * 60 * (int) $h + 60 * (int) $m + (double) $s);
                        // we need to subract one hour from our time for strftime to return the correct value
                        $info['offset'] = strftime("%T", round($seconds / 5 - 60 * 60));
                    } else {
                        $info['offset'] = "00:00:10";
                    }
                    // store some video specific settings
                    LibertyMime::expungeMetaData($pParamHash['attachment_id']);
                    LibertyMime::storeMetaData($pParamHash['attachment_id'], 'Video', $info);
                    // since the flv conversion worked, we will create a preview screenshots to show.
                    mime_video_create_thumbnail($dest_file, $info['offset']);
                    $log['message'] = 'SUCCESS: Converted to flash video';
                    $actionLog['log_message'] = "Converted to flashvideo in " . (date('U') - $begin) . " seconds";
                    $ret = TRUE;
                } else {
                    // remove unsuccessfully converted file
                    @unlink($dest_file);
                    $log['message'] = "ERROR: The video you uploaded could not be converted by ffmpeg.\nDEBUG OUTPUT:\n\n" . $debug;
                    $actionLog['log_message'] = "Video could not be converted to flashvideo. An error dump was saved to: " . $destPath . '/error';
                    // write error message to error file
                    $h = fopen($destPath . "/error", 'w');
                    fwrite($h, "{$ffmpeg} {$parameters}\n\n{$debug}");
                    fclose($h);
                }
                @unlink($destPath . '/processing');
            }
        }
        $log['time'] = date('d/M/Y:H:i:s O');
        $log['duration'] = date('U') - $begin;
        // we'll insert some info into the database for reference
        $actionLog['content_id'] = $pParamHash['content_id'];
        $actionLog['title'] = "Uploaded file: {$pParamHash['upload']['name']} [Attchment ID: {$pParamHash['attachment_id']}]";
        // if this all goes t**s up, we'll know why
        $pParamHash['log'] = $log;
        // we'll add an entry in the action logs
        LibertyContent::storeActionLogFromHash(array('action_log' => $actionLog));
        // return the log
        $pParamHash['log'] = $log;
    }
    return $ret;
}