public function run() { // get a local pointer to the file $file = wfLocalFile( $this->title ); // Validate the file exists : if( !$file || !is_file( $this->getSourceFilePath() ) ){ $this->output( 'File not found: ' . $this->title ); return false; } // Validate the transcode key param: $transcodeKey = $this->params['transcodeKey']; // Build the destination target if( ! isset( WebVideoTranscode::$derivativeSettings[ $transcodeKey ] )){ $this->output( "Transcode key $transcodeKey not found, skipping" ); return false; } $options = WebVideoTranscode::$derivativeSettings[ $transcodeKey ]; $this->output( "Encoding to codec: " . $options['videoCodec'] ); $dbw = wfGetDB( DB_MASTER ); $db = wfGetDB( DB_SLAVE ); // Check if we have "already started" the transcode ( possible error ) $dbStartTime = $db->selectField( 'transcode', 'transcode_time_startwork', array( 'transcode_image_name = ' . $db->addQuotes( $this->title->getDBKey() ), 'transcode_key =' . $db->addQuotes( $transcodeKey ) ) ); if( ! is_null( $dbStartTime ) ){ $this->output( 'Error, running transcode job, for job that has already started' ); // back out of this job. ( if there was a transcode error it should be restarted with api transcode-reset ) // not some strange out-of-order error. return false; } // Update the transcode table letting it know we have "started work": $jobStartTimeCache = $db->timestamp(); $dbw->update( 'transcode', array( 'transcode_time_startwork' => $jobStartTimeCache ), array( 'transcode_image_name' => $this->title->getDBkey(), 'transcode_key' => $transcodeKey ), __METHOD__, array( 'LIMIT' => 1 ) ); // Check the codec see which encode method to call; if( $options['videoCodec'] == 'theora' ){ $status = $this->ffmpeg2TheoraEncode( $options ); } elseif( $options['videoCodec'] == 'vp8' ){ // Check for twopass: if( isset( $options['twopass'] ) ){ // ffmpeg requires manual two pass $status = $this->ffmpegEncode( $options, 1 ); if( $status ){ $status = $this->ffmpegEncode( $options, 2 ); } } else { $status = $this->ffmpegEncode( $options ); } } else { wfDebug( 'Error unknown codec:' . $options['codec'] ); $status = 'Error unknown target encode codec:' . $options['codec']; } // Remove any log files all useful info should be in status and or we are done with 2 passs encoding $this->removeFffmpgeLogFiles(); // Do a quick check to confirm the job was not restarted or removed while we were transcoding // Confirm the in memory $jobStartTimeCache matches db start time $dbStartTime = $db->selectField( 'transcode', 'transcode_time_startwork', array( 'transcode_image_name = ' . $db->addQuotes( $this->title->getDBKey() ), 'transcode_key =' . $db->addQuotes( $transcodeKey ) ) ); // Check for ( hopefully rare ) issue of or job restarted while transcode in progress if( $db->timestamp( $jobStartTimeCache ) != $db->timestamp( $dbStartTime ) ){ $this->output('Possible Error, transcode task restarted, removed, or completed while transcode was in progress'); // if an error; just error out, we can't remove temp files or update states, because the new job may be doing stuff. if( $status !== true ){ return false; } // else just continue with db updates, and when the new job comes around it won't start because it will see // that the job has already been started. } // If status is oky and file exists and is larger than 0 bytes if( $status === true && is_file( $this->getTargetEncodePath() ) && filesize( $this->getTargetEncodePath() ) > 0 ){ $finalDerivativeFilePath = WebVideoTranscode::getDerivativeFilePath( $file, $transcodeKey); //wfSuppressWarnings(); // @TODO: use a FileRepo store function $op = array( 'op' => 'store', 'src' => $this->getTargetEncodePath(), 'dst' => $finalDerivativeFilePath, 'overwriteDest' => true ); // Copy derivaitve from the FS into storage at $finalDerivativeFilePath $opts = array( 'ignoreErrors' => true, 'nonLocking' => true ); // performance $file = $this->getFile(); $status = $file->getRepo()->getBackend()->doOperation( $op, $opts ); if (!$status->isOK() ) { // Update the transcode table with failure time and error $dbw->update( 'transcode', array( 'transcode_time_error' => $db->timestamp(), 'transcode_error' => $status ), array( 'transcode_image_name' => $this->title->getDBkey(), 'transcode_key' => $transcodeKey ), __METHOD__, array( 'LIMIT' => 1 ) ); // no need to invalidate all pages with video. Because all pages remain valid ( no $transcodeKey derivative ) // just clear the file page ( so that the transcode table shows the error ) $this->title->invalidateCache(); } else { $bitrate = round( intval( filesize( $finalDerivativeFilePath ) / $file->getLength() ) * 8 ); //wfRestoreWarnings(); // Update the transcode table with success time: $dbw->update( 'transcode', array( 'transcode_time_success' => $db->timestamp(), 'transcode_final_bitrate' => $bitrate ), array( 'transcode_image_name' => $this->title->getDBkey(), 'transcode_key' => $transcodeKey, ), __METHOD__, array( 'LIMIT' => 1 ) ); WebVideoTranscode::invalidatePagesWithFile( $this->title ); } //remove temoprary file in any case $this->getTargetEncodePath()->purge(); } else { // Update the transcode table with failure time and error $dbw->update( 'transcode', array( 'transcode_time_error' => $db->timestamp(), 'transcode_error' => $status ), array( 'transcode_image_name' => $this->title->getDBkey(), 'transcode_key' => $transcodeKey ), __METHOD__, array( 'LIMIT' => 1 ) ); // no need to invalidate all pages with video. Because all pages remain valid ( no $transcodeKey derivative ) // just clear the file page ( so that the transcode table shows the error ) $this->title->invalidateCache(); } // Clear the webVideoTranscode cache ( so we don't keep out dated table cache around ) webVideoTranscode::clearTranscodeCache( $this->title->getDBkey() ); // pass along result status: return $status; }