Beispiel #1
0
 public static function Get()
 {
     if (empty(self::$instance)) {
         self::$instance = new Video_Tools();
     }
     return self::$instance;
 }
Beispiel #2
0
 public function Extract()
 {
     if (!file_exists($this->filename)) {
         throw new BaseException(_T('Validation:Video file could not be found'), $this->filename);
     }
     $tools = Video_Tools::Get();
     // Check to see if file info has been cached
     if ($this->cache != null) {
         return $this->cache;
     }
     // Execute mplayer to get video file information
     $output = shell_exec($tools->mplayer . ' -identify ' . escapeshellarg($this->filename) . ' -ao null -vo null -frames 0 2>&1');
     $data = array();
     // Extract video file information
     if (preg_match_all('~^ID_([A-Z0-9_]+)=(.*)~m', $output, $matches, PREG_SET_ORDER)) {
         foreach ($matches as $match) {
             $data[strtolower($match[1])] = $match[2];
         }
         if (!isset($data['video_format'])) {
             throw new BaseException(_T('Validation:Video invalid format'), $this->filename, $output);
         }
         $data['video_frames'] = ceil($data['video_fps'] * $data['length']);
         $data['has_audio'] = isset($data['audio_id']) && isset($data['audio_rate']);
         // Length likely incorrect
         if ($data['length'] <= 0.0) {
             $data['length'] = null;
             if (!empty($tools->ffmpeg)) {
                 $output = shell_exec($tools->ffmpeg . ' -i ' . escapeshellarg($this->filename) . ' 2>&1');
                 if (preg_match('~Duration: (\\d+:\\d+:\\d+.\\d+)~', $output, $matches)) {
                     $data['length'] = self::ToSeconds($matches[1]);
                 }
             }
             // All we can do now is guess
             if (empty($data['length'])) {
                 $data['length'] = 5;
             }
         }
         // Video FPS likely incorrect
         if ($data['video_fps'] > 100) {
             $data['video_fps'] = null;
             if (!empty($tools->ffmpeg)) {
                 $output = shell_exec($tools->ffmpeg . ' -i ' . escapeshellarg($this->filename) . ' 2>&1');
                 if (preg_match('~([0-9.]+) tbr~', $output, $matches)) {
                     $data['video_fps'] = $matches[1];
                     $data['video_frames'] = ceil($data['video_fps'] * $data['length']);
                 }
             }
             // All we can do now is guess
             if (empty($data['video_fps'])) {
                 $data['video_fps'] = '29.97';
             }
         }
     }
     // Cache it
     $this->cache = $data;
     return $data;
 }
Beispiel #3
0
 private static function ConvertToMp4($vi, $filename, $directory, $vbitrate, $abitrate, $scale, $callback)
 {
     $tools = Video_Tools::Get();
     $vbitrate = ($vbitrate <= 40 ? 'crf=' : 'ratetol=1.0:bitrate=') . $vbitrate;
     $tmp_file = File::Temporary($directory, self::EXTENSION_AVI);
     $cmd = (!empty($tools->nice) ? $tools->nice . ' ' : '') . $tools->mencoder . ' ' . escapeshellarg($filename) . ' ' . '-o ' . escapeshellarg($tmp_file) . ' ' . '-sws 9 ' . '-noskip ' . '-ovc x264 ' . '-x264encopts ' . escapeshellarg($vbitrate . ':bframes=1:me=umh:partitions=all:trellis=1:qp_step=4:qcomp=0.7:direct_pred=auto:keyint=300:threads=' . self::THREADS) . ' ' . '-vf ' . escapeshellarg((!empty($scale) ? $scale . ',' : '') . 'harddup') . ' ' . ($vi->has_audio ? '-oac faac -faacopts ' . escapeshellarg('br=' . $abitrate . ':mpeg=4:object=2') . ' -channels ' . self::CHANNELS_AAC . ' -srate ' . self::SAMPLE_RATE_AAC . ' ' : ' -nosound ') . '-ofps ' . escapeshellarg($vi->video_fps);
     if (self::ExecuteCmdAsync($cmd, $callback)) {
         File::Delete($tmp_file);
         throw new BaseException('Video conversion was interrupted by user request');
     }
     // Verify video file generated
     if (filesize($tmp_file) == 0) {
         File::Delete($tmp_file);
         throw new BaseException('Unable to convert video file to H.264/AAC MP4', $filename, $output);
     }
     // Get the filenames of the extracted raw streams
     $directory = Dir::StripTrailingSlash($directory);
     $basename = basename($tmp_file, '.' . self::EXTENSION_AVI);
     $videofile = $directory . '/' . $basename . '_video.h264';
     $audiofile_raw = $directory . '/' . $basename . '_audio.raw';
     $audiofile = $directory . '/' . $basename . '_audio.aac';
     // Extract the raw streams
     $cmd = (!empty($tools->nice) ? $tools->nice . ' ' : '') . $tools->mp4box . ' -aviraw video ' . escapeshellarg($tmp_file) . ' 2>&1';
     self::Log($cmd);
     $output = shell_exec($cmd);
     self::Log($output);
     if (!file_exists($videofile)) {
         File::Delete($tmp_file);
         throw new BaseException('Unable to extract video from file using MP4Box', $videofile, $output);
     }
     $output_file = File::Temporary($directory, self::EXTENSION_MP4);
     // Process video files that do have an audio stream
     if ($vi->has_audio) {
         $cmd = (!empty($tools->nice) ? $tools->nice . ' ' : '') . $tools->mp4box . ' -aviraw audio ' . escapeshellarg($tmp_file) . ' 2>&1';
         self::Log($cmd);
         $output = shell_exec($cmd);
         self::Log($output);
         if (!file_exists($audiofile_raw)) {
             File::Delete($tmp_file);
             File::Delete($videofile);
             throw new BaseException('Unable to extract audio from file using MP4Box', $audiofile_raw, $output);
         }
         rename($audiofile_raw, $audiofile);
         $cmd = (!empty($tools->nice) ? $tools->nice . ' ' : '') . $tools->mp4box . ' -add ' . escapeshellarg($videofile) . ' -add ' . escapeshellarg($audiofile) . ' -fps ' . escapeshellarg($vi->video_fps) . ' -inter 500 ' . escapeshellarg($output_file) . ' 2>&1';
         self::Log($cmd);
         $output = shell_exec($cmd);
         self::Log($output);
         File::Delete($audiofile);
     } else {
         $cmd = (!empty($tools->nice) ? $tools->nice . ' ' : '') . $tools->mp4box . ' -add ' . escapeshellarg($videofile) . ' -fps ' . escapeshellarg($vi->video_fps) . ' -inter 500 ' . escapeshellarg($output_file) . ' 2>&1';
         self::Log($cmd);
         $output = shell_exec($cmd);
         self::Log($output);
     }
     // Remove temporary files
     File::Delete($tmp_file);
     File::Delete($videofile);
     if (!file_exists($output_file)) {
         throw new BaseException('Unable to generate MP4 file using MP4Box', $output_file, $output);
     }
     return $output_file;
 }
Beispiel #4
0
 public static function Grab($filename, $directory, $num_frames = 10, $quality = 90, $dimensions = false, $vi = null)
 {
     if (!is_dir($directory) || !is_writeable($directory)) {
         throw new BaseException('Output directory is missing or not writeable', $directory);
     }
     if (!file_exists($filename)) {
         throw new BaseException('Input file is missing', $filename);
     }
     // Get video info if it was not provided
     if (!$vi instanceof Video_Info) {
         $vi = new Video_Info($filename);
         $vi->Extract();
     }
     $output = null;
     $tools = Video_Tools::Get();
     $filter = self::ScaleFilter($dimensions, $vi->video_width, $vi->video_height);
     // Extract frames from short videos (less than 1 minute)
     if ($vi->length < 60) {
         self::Log('Using short video frame extraction method');
         $framestep = floor($vi->video_frames / $num_frames);
         $end = floor($vi->length);
         $cmd = $tools->mplayer . ' -nosound' . ' -vo ' . escapeshellarg('jpeg:quality=' . $quality . ':outdir=' . $directory) . ' -endpos ' . escapeshellarg($end) . ' -sws 9' . ' -speed 100' . ' -vf ' . escapeshellarg('framestep=' . $framestep . ',' . $filter) . ' ' . escapeshellarg($filename) . ' 2>&1';
         self::Log($cmd);
         $output = shell_exec($cmd);
         self::Log($output);
         $frames = glob($directory . '/*.' . JPG_EXTENSION);
         $generated = count($frames);
         self::Log('Total frames generated: ' . $generated);
     } else {
         self::Log('Using long video frame extraction method');
         $start = min(ceil($vi->length * 0.01), 15);
         $end = floor($vi->length - $start);
         $interval = floor(($end - $start) / ($num_frames - 1));
         // Attempt to use the quick frame grab method
         $cmd = $tools->mplayer . ' -nosound' . ' -vo ' . escapeshellarg('jpeg:quality=' . $quality . ':outdir=' . $directory) . ' -frames ' . escapeshellarg($num_frames) . ' -ss ' . escapeshellarg($start) . ' -sstep ' . escapeshellarg($interval) . ' -endpos ' . escapeshellarg($end) . ' -sws 9 ' . ' -vf ' . escapeshellarg($filter) . ' ' . escapeshellarg($filename) . ' 2>&1';
         self::Log($cmd);
         $output = shell_exec($cmd);
         self::Log($output);
         $frames = glob($directory . '/*.' . JPG_EXTENSION);
         $generated = count($frames);
         self::Log('Total frames generated: ' . $generated);
         // Fall back to the slow frame grab method
         if ($generated < 1 || $num_frames > 1 && $generated == 1 || stristr($output, 'first frame is no keyframe')) {
             self::Log('Falling back to long video SLOW frame extraction method');
             // Reset values and directory contents
             $generated = 0;
             if (is_array($frames)) {
                 foreach ($frames as $frame) {
                     unlink($frame);
                 }
             }
             // Grab each frame individually
             for ($i = 0; $i < $num_frames; $i++) {
                 $cmd = $tools->mplayer . ' -nosound' . ' -vo ' . escapeshellarg('jpeg:quality=' . $quality . ':outdir=' . $directory) . ' -frames 1 ' . ' -sws 9 ' . ' -ss ' . ($start + $i * $interval) . ' -vf ' . escapeshellarg($filter) . ' ' . escapeshellarg($filename) . ' 2>&1';
                 self::Log($cmd);
                 $this_output = shell_exec($cmd);
                 $output .= $this_output;
                 self::Log($this_output);
                 if (file_exists("{$directory}/00000001.jpg")) {
                     $generated++;
                     rename("{$directory}/00000001.jpg", $directory . sprintf('/%s%08d.jpg', $generated == 1 ? 't' : '', $generated));
                 }
             }
             if (file_exists("{$directory}/t00000001.jpg")) {
                 rename("{$directory}/t00000001.jpg", "{$directory}/00000001.jpg");
             }
             $frames = glob($directory . '/*.' . JPG_EXTENSION);
             self::Log('Total frames generated: ' . $generated);
         }
     }
     if ($generated < 1) {
         throw new BaseException('Could not grab frames from this video file', $filename, $output);
     }
     if (Video_Thumbnail::CanResize()) {
         $frames = Video_Thumbnail::DiscardBlack($directory);
         self::Log('Total frames generated after black frame removal: ' . count($frames));
     }
     return $frames;
 }