/** * Saves any changes to the media file to the given save path. * IMPORTANT! This save blocks PHP execution, meaning that once called, the PHP interpretter * will NOT continue untill the video/audio/media file(s) have been transcoded. * * @access public * @author Oliver Lillie * @param MultiOutput $save_path If a string then it is treated as a single output and the argument is the output path * of the generated file, otherwise if a PHPVideoToolkit\MultiOutput object is given then we treat the output * as multiple output. * @param Format $output_format It is the output format for the saved file. * @param string $overwrite One of the following constants determining the overwrite status of the save. * Media::OVERWRITE_FAIL - the save call will fail with an excetion if the save path already exists. * Media::OVERWRITE_EXISTING - the save call will overwrite any existing file with the same name. * Media::OVERWRITE_UNIQUE - the save call will augment the save path with a unique hash so that if a file with * the same name exists then there is no overwrite. * @param ProgressHandlerAbstract $progress_handler The progress handler object to supply to the save process. * @return mixed If the blocking mode of the process is set to block, the it returns a new * Media object on a successfull completion, otherwise an exception is thrown. If the blocking * mode is non blocking then the underlying FfmpegProcess is returned. */ public function save($save_path = null, Format $output_format = null, $overwrite = Media::OVERWRITE_FAIL, ProgressHandlerAbstract &$progress_handler = null) { $this->_saveAddInputFormatCommands($this->_media_input_format); // set the input files. $this->_process->setInputPath($this->_media_file_path); // loop and process the save path to multioutput so we can loop $multi_output = $this->_convertOutputPathToMultiOutput($save_path, $output_format); $index = 0; foreach ($multi_output as $save_path => $output_format) { // increment the output index so the process moves on to the next process to build if the loop continues. $this->_process->setOutputIndex($index); $index += 1; // pre process all of the common functionality and pre process the output format. $this->_savePreProcess($output_format, $save_path, $overwrite); // add the commands from the output format to the exec buffer // NOTE; this cannot be done in _savePreProcess as it must be done after, to ensure all the subclass // _savePreProcess functionality and main media class functionality is properly executed. $this->_saveAddOutputFormatCommands($output_format); // update the output path as the processing path? $this->_process->setOutputPath($this->_processing_path); } // set the progress handler if ($progress_handler !== null) { $progress_handler->setTotalDuration($this->getEstimatedFinalDuration()); $this->_process->attachProgressHandler($progress_handler); } // exec the buffer // set the blocking mode // and execute the ffmpeg process. $buffer = $this->_process->setOutputPath($this->_processing_path)->getExecBuffer()->setBlocking($this->_blocking === null ? true : $this->_blocking); $process = $this->_process; $callback = array($this, '_postProcessOutput'); $buffer->registerCompletionCallback(function () use($callback, $process) { call_user_func($callback, $process); }); if ($progress_handler !== null && $progress_handler->getNonBlockingCompatibilityStatus() === false) { $buffer->execute(function ($exec_buffer, $null, $completed) use($progress_handler, $callback, $process) { if ($progress_handler !== null) { $progress_handler->callback(); } }); } else { $buffer->execute(); } // just return the process if the process return $this->_process; }