Esempio n. 1
0
 /**
  * Extracts a segment of the media object.
  *
  * @access public
  * @author Oliver Lillie
  * @param Timecode $from_timecode 
  * @param Timecode $to_timecode 
  * @param boolean $accurate If true then accuracy is prefered over performance.
  * @return Media
  */
 public function extractSegment(Timecode $from_timecode = null, Timecode $to_timecode = null, $accurate = false)
 {
     //          check that a segment extract has not already been set
     if (empty($this->_extract_segment) === false) {
         throw new \LogicException('Extract segment options have already been set. You cannot call extractSegment more than once on a ' . get_class($this) . ' object.');
     }
     //          check that a split has already been set as if it has we can't extract a segment
     //          however we can extract a segment, then split it.
     if (empty($this->_split_options) === false) {
         throw new \LogicException('You cannot extract a segment once ' . get_class($this) . '::split has been called. You can however extract a segment, the call ' . get_class($this) . '::split.');
     }
     //          check the timecodes against the duration
     $duration = $this->readDuration();
     if ($from_timecode !== null && $duration->total_seconds < $from_timecode->total_seconds) {
         throw new \InvalidArgumentException('The duration of the media is less than the starting timecode specified.');
     } else {
         if ($to_timecode !== null && $duration->total_seconds < $to_timecode->total_seconds) {
             throw new \InvalidArgumentException('The duration of the media is less than the end timecode specified.');
         }
     }
     $this->_extract_segment = array('preseek' => null, 'seek' => null, 'length' => null);
     //          if the from timecode is greater than say 15 seconds, we will stream seek to 15 seconds before the
     //          required extracted segment before the input to improve extract performance.
     //          See http://ffmpeg.org/trac/ffmpeg/wiki/Seeking%20with%20FFmpeg
     $pre_input_stream_seek_offset = 0;
     $pre_input_stream_seek_adjustment = 15;
     if ($from_timecode !== null) {
         if ($accurate === false) {
             if ($from_timecode->total_seconds > $pre_input_stream_seek_adjustment) {
                 $pre_input_stream_seek_offset = $from_timecode->total_seconds - $pre_input_stream_seek_adjustment;
                 $seek_timecode = new Timecode($pre_input_stream_seek_offset, Timecode::INPUT_FORMAT_SECONDS);
                 $this->_extract_segment['preseek'] = $seek_timecode;
             }
             //                  if we have a pre input stream seek then input video is then offset by that ammount
             if ($pre_input_stream_seek_offset > 0) {
                 $from_timecode = new Timecode($pre_input_stream_seek_adjustment, Timecode::INPUT_FORMAT_SECONDS);
             }
         }
         //              then seek the exact position after input
         $begin_position = $from_timecode->getTimecode('%hh:%mm:%ss.%ms', false);
         $this->_extract_segment['seek'] = $from_timecode;
     } else {
         $from_timecode = new Timecode(0, Timecode::INPUT_FORMAT_SECONDS);
     }
     //          then add the number of seconds to export for if there is an end timecode.
     if ($to_timecode !== null) {
         //              if we have a pre input stream seek then input video is then offset by that ammount
         if ($pre_input_stream_seek_offset > 0) {
             $to_timecode = new Timecode($to_timecode->total_seconds - $pre_input_stream_seek_offset, Timecode::INPUT_FORMAT_SECONDS);
         }
         $this->_extract_segment['length'] = $to_timecode->total_seconds - $from_timecode->total_seconds;
     }
     return $this;
 }
 /**
  * Once the process has been completed this function can be called to return the output
  * of the process. Depending on what the process is outputting depends on what is returned.
  * If a single video or audio is being outputted then the related PHPVideoToolkit media object
  * will be returned. However if multiple files are being outputed then an array of the associated
  * objects are returned. Typically speaking an array will be returned when %index or %timecode
  * are within the output path.
  *
  * @access public
  * @author Oliver Lillie
  * @return mixed
  */
 public function getOutput($post_process_callback = null)
 {
     if ($this->isCompleted() === false) {
         throw new FfmpegProcessOutputException('Encoding has not yet started.');
     }
     //			check for an error.
     if ($this->hasError() === true) {
         //				check for specific recieved signal errors.
         $last_split = $this->getLastSplit();
         if (preg_match('/Received signal ([0-9]+): terminating\\./', $last_split, $matches) > 0) {
             $kill_signals = array(1 => 'Hang up detected on controlling terminal or death of controlling process.', 2 => 'User sent an interrupt signal.', 3 => 'User sent a quit signal.', 4 => 'Illegal instruction.', 6 => 'Abort signal from abort(3).', 8 => 'Floating point exception.', 9 => 'Kill signal sent.', 11 => 'Invalid memory reference', 13 => 'Broken pipe: write to pipe with no readers', 14 => 'Timer signal from alarm(2)', 15 => 'Termination signal sent.', 24 => 'Imposed time limit ({length} seconds) exceeded.');
             // TODO add more signals.
             $kill_int = (int) $matches[1];
             if (isset($kill_signals[$kill_int]) === true) {
                 $message = $kill_signals[$kill_int];
                 if ($kill_int == 24) {
                     $length = $this->getCommand('-timelimit');
                     $length = !$length ? 'unknown' : $length;
                     $message = str_replace('{length}', $length, $message);
                 }
                 throw new FfmpegProcessOutputException('Process was aborted. ' . $message);
             } else {
                 throw new FfmpegProcessOutputException('Termination signal received and the process aborted. Signal was ' . $matches[1]);
             }
         }
         throw new FfmpegProcessOutputException('Encoding failed and an error was returned from ffmpeg. Error code ' . $this->getErrorCode() . ' was returned the message (if any) was: ' . $last_split);
     }
     if ($post_process_callback !== null) {
         if (is_callable($post_process_callback) === false) {
             throw new Exception('The supplied post proces scallback is not callable.');
         }
     }
     //			get the output of the process
     $output_path = $this->getOutputPath();
     //			we have the output path but we now need to treat differently dependant on if we have multiple file output.
     if (preg_match('/\\.(\\%([0-9]*)d)\\.([0-9\\.]+_[0-9\\.]+\\.)?_(i|t)\\./', $output_path, $matches) > 0) {
         //				determine what we have to rename all the files to.
         $convert_back_to = $matches[4] === 't' ? 'timecode' : (int) $matches[2];
         //				get the glob path and then find all the files from this output
         $output_glob_path = str_replace($matches[0], '.*.' . $matches[3] . '_' . $matches[4] . '.', $output_path);
         $outputted_files = glob($output_glob_path);
         //				sort the output naturally so that if there is no index padding that we get the frames in the correct order.
         natsort($outputted_files);
         //				loop to rename the file and then create each output object.
         $output = array();
         $timecode = null;
         foreach ($outputted_files as $path) {
             $actual_path = preg_replace('/\\._u\\.[0-9]{5}_[a-z0-9]{5}_[0-9]+\\.u_\\./', '.', $path);
             if ($convert_back_to === 'timecode') {
                 //						if the start timecode has not been generated then find the required from the path string.
                 if ($timecode === null) {
                     $matches[3] = rtrim($matches[3], '.');
                     $matches[3] = explode('_', $matches[3]);
                     $timecode = new Timecode($matches[3][1], Timecode::INPUT_FORMAT_SECONDS, $matches[3][0]);
                 } else {
                     $timecode->frame += 1;
                 }
                 $actual_path = preg_replace('/\\.[0-9]{12}\\.[0-9\\.]+_[0-9\\.]+\\._t\\./', $timecode->getTimecode('%hh_%mm_%ss_%ms', false), $actual_path);
             } else {
                 $actual_path = preg_replace('/\\.([0-9]+)\\._i\\./', '$1', $actual_path);
             }
             rename($path, $actual_path);
             $media_class = $this->_findMediaClass($actual_path);
             $output_object = new $media_class($actual_path, $this->_config, null, false);
             array_push($output, $output_object);
             unset($output_object);
         }
         unset($outputted_files);
         // TODO create the multiple image output
     } else {
         //				check for a none multiple file existence
         if (empty($output_path) === true) {
             throw new FfmpegProcessOutputException('Unable to find output for the process as it was not set.');
         } else {
             if (is_file($output_path) === false) {
                 throw new FfmpegProcessOutputException('The output "' . $output_path . '", of the Ffmpeg process does not exist.');
             } else {
                 if (filesize($output_path) <= 0) {
                     throw new FfmpegProcessOutputException('The output "' . $output_path . '", of the Ffmpeg process is a 0 byte file. Something must have gone wrong however it wasn\'t reported as an error by FFmpeg.');
                 }
             }
         }
         //				get the media class from the output.
         //				create the object from the class name and return the new object.
         $media_class = $this->_findMediaClass($output_path);
         $output = new $media_class($output, $this->_config, null, false);
     }
     //			do any post processing callbacks
     if ($post_process_callback !== null) {
         $output = call_user_func($post_process_callback, $output, $this);
     }
     //			finally return the output to the user.
     return $output;
 }
 /**
  * Renames any output from ffmpeg that would have been outputted in a sequence, ie using %d. Typically used with imagery.
  *
  * @access public
  * @author Oliver Lillie
  * @param  string $output_path The string notation for the output path.
  * @return array Returns an array of modified file paths.
  */
 protected function _renamePercentDOutput($output_path)
 {
     $output = array();
     //          we have the output path but we now need to treat differently dependant on if we have multiple file output.
     if (preg_match('/\\.(\\%([0-9]*)d)\\.([0-9\\.]+_[0-9\\.]+\\.)?_(i|t)\\./', $output_path, $matches) > 0) {
         //              determine what we have to rename all the files to.
         $convert_back_to = $matches[4] === 't' ? 'timecode' : (int) $matches[2];
         //              get the glob path and then find all the files from this output
         $output_glob_path = str_replace($matches[0], '.*.' . $matches[3] . '_' . $matches[4] . '.', $output_path);
         $outputted_files = glob($output_glob_path);
         //              sort the output naturally so that if there is no index padding that we get the frames in the correct order.
         natsort($outputted_files);
         //              loop to rename the file and then create each output object.
         $timecode = null;
         foreach ($outputted_files as $path) {
             if ($convert_back_to === 'timecode') {
                 //                      if the start timecode has not been generated then find the required from the path string.
                 if ($timecode === null) {
                     $matches[3] = rtrim($matches[3], '.');
                     $matches[3] = explode('_', $matches[3]);
                     $timecode = new Timecode($matches[3][1], Timecode::INPUT_FORMAT_SECONDS, $matches[3][0]);
                 } else {
                     $timecode->frame += 1;
                 }
                 $actual_path = preg_replace('/\\.[0-9]{12}\\.[0-9\\.]+_[0-9\\.]+\\._t\\./', $timecode->getTimecode('%hh_%mm_%ss_%ms', false), $path);
             } else {
                 $actual_path = preg_replace('/\\.([0-9]+)\\._i\\./', '$1', $path);
             }
             $actual_path = preg_replace('/\\._u\\.[0-9]{5}_[a-z0-9]{5}_[0-9]+\\.u_\\./', '.', $actual_path);
             rename($path, $actual_path);
             array_push($output, $actual_path);
         }
         unset($outputted_files);
         // TODO create the multiple image output
     }
     return $output;
 }
Esempio n. 4
0
 echo 'new Timecode(.028427778, Timecode::INPUT_FORMAT_HOURS); = ' . $timecode . '<br />';
 $timecode = new Timecode('00:01:42.34', Timecode::INPUT_FORMAT_TIMECODE);
 echo 'new Timecode(\'00:01:42.34\', Timecode::INPUT_FORMAT_TIMECODE); = ' . $timecode . '<br />';
 $timecode = new Timecode(60);
 echo 'new Timecode(60); = ' . $timecode . '<br />';
 $timecode = new Timecode(360);
 echo 'new Timecode(360); = ' . $timecode . '<br />';
 echo '<hr />';
 echo '<h2>Adjusting timecode values</h2>';
 $timecode = new Timecode('00:01:42.34', Timecode::INPUT_FORMAT_TIMECODE, 24);
 echo '$timecode = new Timecode(\'00:01:42.34\', Timecode::INPUT_FORMAT_TIMECODE); = ' . $timecode . '<br />';
 $adjustments = array(array(15, 'hours', true), array(-54102.34, 'seconds', true), array(-99, 'milliseconds', true), array(59, 'seconds', true), array(1, 'seconds', false), array(59, 'seconds', true), array(999, 'milliseconds', true), array(1, 'milliseconds', true), array(48, 'frames', false), array(-15, 'frames', true), array(-1, 'seconds', true), array(-375, 'milliseconds', true));
 foreach ($adjustments as $value) {
     if ($value[2] === true) {
         $timecode->{$value[1]} += $value[0];
         echo '$timecode->' . $value[1] . ' += ' . $value[0] . '; // = ' . $timecode->getTimecode('%hh:%mm:%ss:%ms') . '<br />';
     } else {
         echo '<Br />$timecode->reset();<br />';
         $timecode->reset();
         $timecode->{$value[1]} = $value[0];
         echo '$timecode->' . $value[1] . ' = ' . $value[0] . '; // = ' . $timecode->getTimecode('%hh:%mm:%ss:%ms') . '<br />';
     }
 }
 echo '<hr />';
 echo '<h2>Setting a timecode value</h2>';
 $timecode->setSeconds(193.7);
 echo '$timecode->setSeconds(193.7); = ' . $timecode . '<br />';
 $timecode->setTimecode('12:45:39.01');
 echo '<br /><strong>IMPORTANT: Notice the difference between total_seconds and seconds</strong><br />$timecode->setTimecode(\'12:45:39.01\'); <br />';
 echo '$timecode->total_seconds = ' . $timecode->total_seconds . '<br />';
 echo '$timecode->seconds = ' . $timecode->seconds . '<br />';