Index: trunk/extensions/TimedMediaHandler/TranscodeStatusTable.php |
— | — | @@ -108,33 +108,15 @@ |
109 | 109 | } */ |
110 | 110 | // predicting percent done is not working well right now ( disabled for now ) |
111 | 111 | $doneMsg = ''; |
112 | | - return wfMsgHtml('timedmedia-started-transcode', self::getTimePassedMsg( $timePassed ), $doneMsg ); |
| 112 | + return wfMsgHtml('timedmedia-started-transcode', TimedMediaHandler::getTimePassedMsg( $timePassed ), $doneMsg ); |
113 | 113 | } |
114 | 114 | // Check for job added ( but not started encoding ) |
115 | 115 | if( !is_null( $state['time_addjob'] ) ){ |
116 | 116 | $timePassed = wfTimestampNow() - $db->timestamp( $state['time_addjob'] ) ; |
117 | | - return wfMsgHtml('timedmedia-in-job-queue', self::getTimePassedMsg( $timePassed ) ); |
| 117 | + return wfMsgHtml('timedmedia-in-job-queue', TimedMediaHandler::getTimePassedMsg( $timePassed ) ); |
118 | 118 | } |
119 | 119 | // Return unknown status error: |
120 | 120 | return wfMsgHtml('timedmedia-status-unknown'); |
121 | 121 | } |
122 | | - public static function getTimePassedMsg( $timePassed ){ |
123 | | - $t['days'] = floor($timePassed/60/60/24); |
124 | | - $t['hours'] = floor($timePassed/60/60)%24; |
125 | | - $t['minutes'] = floor($timePassed/60)%60; |
126 | | - $t['seconds'] = $timePassed%60; |
127 | | - |
128 | | - foreach( $t as $k => $v ){ |
129 | | - if($v == 0 ){ |
130 | | - unset( $t[$k] ); |
131 | | - }else{ |
132 | | - $t[$k] = wfMsg( 'timedmedia-' . $k, $v); |
133 | | - } |
134 | | - } |
135 | | - if( count( $t ) == 0 ){ |
136 | | - $t = array( wfMsg( 'timedmedia-seconds', 0) ) ; |
137 | | - } |
138 | | - // Call to the correct set of significant measurements: |
139 | | - return wfMsgHtml( 'timedmedia-time-' . count($t) . '-measurements', $t); |
140 | | - } |
| 122 | + |
141 | 123 | } |
\ No newline at end of file |
Index: trunk/extensions/TimedMediaHandler/TimedMediaHandler.php |
— | — | @@ -34,6 +34,9 @@ |
35 | 35 | // Which users can restart failed or expired transcode jobs |
36 | 36 | $wgGroupPermissions['sysop']['transcode-reset'] = true; |
37 | 37 | |
| 38 | +// How long you have to wait between transcode resets for non-error transcodes |
| 39 | +$wgWaitTimeForTranscodeReset = 3600; |
| 40 | + |
38 | 41 | // The minimum size for an embed video player: |
39 | 42 | $wgMinimumVideoPlayerSize = 200; |
40 | 43 | |
— | — | @@ -171,5 +174,3 @@ |
172 | 175 | 'version' => '0.2', |
173 | 176 | ); |
174 | 177 | |
175 | | - |
176 | | - |
Index: trunk/extensions/TimedMediaHandler/TimedMediaHandler_body.php |
— | — | @@ -143,6 +143,25 @@ |
144 | 144 | } |
145 | 145 | return $time; |
146 | 146 | } |
| 147 | + public static function getTimePassedMsg( $timePassed ){ |
| 148 | + $t['days'] = floor($timePassed/60/60/24); |
| 149 | + $t['hours'] = floor($timePassed/60/60)%24; |
| 150 | + $t['minutes'] = floor($timePassed/60)%60; |
| 151 | + $t['seconds'] = $timePassed%60; |
| 152 | + |
| 153 | + foreach( $t as $k => $v ){ |
| 154 | + if($v == 0 ){ |
| 155 | + unset( $t[$k] ); |
| 156 | + }else{ |
| 157 | + $t[$k] = wfMsg( 'timedmedia-' . $k, $v); |
| 158 | + } |
| 159 | + } |
| 160 | + if( count( $t ) == 0 ){ |
| 161 | + $t = array( wfMsg( 'timedmedia-seconds', 0) ) ; |
| 162 | + } |
| 163 | + // Call to the correct set of significant measurements: |
| 164 | + return wfMsgHtml( 'timedmedia-time-' . count($t) . '-measurements', $t); |
| 165 | + } |
147 | 166 | /** |
148 | 167 | * Converts seconds to Normal play time (NPT) time format: |
149 | 168 | * consist of hh:mm:ss.ms |
Index: trunk/extensions/TimedMediaHandler/ApiTranscodeReset.php |
— | — | @@ -12,9 +12,8 @@ |
13 | 13 | * @ingroup API |
14 | 14 | */ |
15 | 15 | class ApiTranscodeReset extends ApiBase { |
16 | | - |
17 | 16 | public function execute() { |
18 | | - global $wgUser, $wgEnabledTranscodeSet, $wgEnableTranscode; |
| 17 | + global $wgUser, $wgEnabledTranscodeSet, $wgEnableTranscode, $wgWaitTimeForTranscodeReset; |
19 | 18 | // Check if transcoding is enabled on this wiki at all: |
20 | 19 | if( !$wgEnableTranscode ){ |
21 | 20 | $this->dieUsage( 'Transcode is disabled on this wiki', 'disabledtranscode' ); |
— | — | @@ -35,11 +34,68 @@ |
36 | 35 | if( !TimedMediaHandlerHooks::isTranscodableTitle( $titleObj ) ){ |
37 | 36 | $this->dieUsage( array( 'invalidtranscodetitle', $params['title'] ) ); |
38 | 37 | } |
39 | | - WebVideoTranscode::removeTranscodes( $titleObj, isset( $params['transcodekey'] )? $params['transcodekey']: false ); |
| 38 | + $transcodeKey = false; |
| 39 | + // Make sure its a enabled transcode key we are trying to remove: |
| 40 | + // ( if you update your transcode keys the api is not how you purge the database of expired keys ) |
| 41 | + if( isset( $params['transcodekey'] ) ){ |
| 42 | + global $wgEnabledTranscodeSet; |
| 43 | + if( !in_array( $params['transcodekey'], $wgEnabledTranscodeSet ) ){ |
| 44 | + $this->dieUsage( 'Invalid or disabled transcode key: ' . htmlspecialchars( $params['transcodekey'] ) , 'badtranscodekey' ); |
| 45 | + } else { |
| 46 | + $transcodeKey = $params['transcodekey']; |
| 47 | + } |
| 48 | + } |
40 | 49 | |
| 50 | + // Don't reset if less than 1 hour has passed and we have no error ) |
| 51 | + $timeSinceLastReset = self::checkTimeSinceLastRest( $titleObj->getDBKey(), $transcodeKey ); |
| 52 | + if( $timeSinceLastReset < $wgWaitTimeForTranscodeReset){ |
| 53 | + $this->dieUsage( 'Not enough time has passed since the last reset of this transcode. ' . |
| 54 | + TimedMediaHandler::getTimePassedMsg( $wgWaitTimeForTranscodeReset - $timeSinceLastReset ) . |
| 55 | + ' until this transcode can be reset', 'notenoughtimereset'); |
| 56 | + } |
| 57 | + |
| 58 | + // All good do the transcode removal: |
| 59 | + WebVideoTranscode::removeTranscodes( $titleObj, $transcodeKey ); |
| 60 | + |
41 | 61 | $this->getResult()->addValue(null, 'success', 'removed transcode'); |
42 | 62 | } |
43 | | - |
| 63 | + static public function checkTimeSinceLastRest( $fileName, $transcodeKey ){ |
| 64 | + global $wgWaitTimeForTranscodeReset; |
| 65 | + $transcodeStates = WebVideoTranscode::getTranscodeState( $fileName ); |
| 66 | + if( $transcodeKey ){ |
| 67 | + if( ! $transcodeStates[$transcodeKey] ){ |
| 68 | + // transcode key not found |
| 69 | + return $wgWaitTimeForTranscodeReset + 1; |
| 70 | + } |
| 71 | + return self::getStateResetTime( $transcodeStates[$transcodeKey] ); |
| 72 | + } |
| 73 | + // least wait is set to reset time: |
| 74 | + $leastWait = $wgWaitTimeForTranscodeReset + 1; |
| 75 | + // else check for lowest reset time |
| 76 | + foreach($transcodeStates as $tk => $state ){ |
| 77 | + $ctime = self::getStateResetTime( $state ); |
| 78 | + if( $ctime < $leastWait){ |
| 79 | + $leastWait = $ctime; |
| 80 | + } |
| 81 | + } |
| 82 | + return $leastWait; |
| 83 | + } |
| 84 | + static public function getStateResetTime( $state ){ |
| 85 | + global $wgWaitTimeForTranscodeReset; |
| 86 | + $db = wfGetDB( DB_SLAVE ); |
| 87 | + // if an error return waitTime +1 |
| 88 | + if( !is_null( $state['time_error']) ){ |
| 89 | + return $wgWaitTimeForTranscodeReset + 1; |
| 90 | + } |
| 91 | + // return wait time from most recent event |
| 92 | + foreach( array( 'time_success', 'time_startwork', 'time_addjob' ) as $timeField ){ |
| 93 | + if( !is_null( $state[ $timeField ] )){ |
| 94 | + return $db->timestamp() - $db->timestamp( $state[ $timeField ] ); |
| 95 | + } |
| 96 | + } |
| 97 | + // No time info, return resetWaitTime |
| 98 | + return $wgWaitTimeForTranscodeReset + 1; |
| 99 | + } |
44 | 100 | public function mustBePosted() { |
45 | 101 | return true; |
46 | 102 | } |
Index: trunk/extensions/TimedMediaHandler/WebVideoTranscode/WebVideoTranscodeJob.php |
— | — | @@ -1,4 +1,4 @@ |
2 | | -<?php |
| 2 | +<?php |
3 | 3 | /** |
4 | 4 | * Job for transcode jobs |
5 | 5 | * |
— | — | @@ -16,33 +16,6 @@ |
17 | 17 | * @ingroup JobQueue |
18 | 18 | */ |
19 | 19 | |
20 | | - |
21 | | -/** |
22 | | - * Unless I am unaware of some command line trickery, we have to wrap the background |
23 | | - * commands in a script to grab the background exit code ( echo $? ) |
24 | | - * |
25 | | - * Ie in the bellow code "echo $?" gives us the status of "echo $1" not "nohub" call |
26 | | - * a wait $pid & echo $? of course does not work since the background taks is not part |
27 | | - * of a child shell call |
28 | | - * |
29 | | - * pseudo shell code for backgroundTask.sh |
30 | | - * |
31 | | -#/bin/bash |
32 | | - |
33 | | -# simple script to run a background and writing output and exit status to a file |
34 | | -# returns its "pid" for proccess monitoring |
35 | | -# Usage: backgroundTask.sh [command] [stdout target file] [pid target file] [exit status target file] |
36 | | - |
37 | | -# Run the command with output redirected to target file ( in the background ) |
38 | | -$1 > $2 & |
39 | | -# Output the pid to target file: |
40 | | -echo $! > $3 |
41 | | -# wait until task is done |
42 | | -wait $! |
43 | | -# output exit status: |
44 | | -echo $? > $4 |
45 | | - |
46 | | -*/ |
47 | 20 | class WebVideoTranscodeJob extends Job { |
48 | 21 | var $targetEncodePath = null; |
49 | 22 | var $sourceFilePath = null; |
— | — | @@ -103,12 +76,12 @@ |
104 | 77 | ); |
105 | 78 | if( ! is_null( $dbStartTime ) ){ |
106 | 79 | $this->output( 'Error, running transcode job, for job that has already started' ); |
107 | | - // back out of this job. ( if there was a transcode error it should be restarted with api transcode-reset ) |
| 80 | + // back out of this job. ( if there was a transcode error it should be restarted with api transcode-reset ) |
108 | 81 | // not some strange out-of-order error. |
109 | 82 | return false; |
110 | 83 | } |
111 | 84 | |
112 | | - // Update the transcode table letting it know we have "started work": |
| 85 | + // Update the transcode table letting it know we have "started work": |
113 | 86 | $jobStartTimeCache = $db->timestamp(); |
114 | 87 | $dbw->update( |
115 | 88 | 'transcode', |
— | — | @@ -120,8 +93,8 @@ |
121 | 94 | __METHOD__, |
122 | 95 | array( 'LIMIT' => 1 ) |
123 | 96 | ); |
124 | | - |
125 | | - |
| 97 | + |
| 98 | + |
126 | 99 | // Check the codec see which encode method to call; |
127 | 100 | if( $options['videoCodec'] == 'theora' ){ |
128 | 101 | $status = $this->ffmpeg2TheoraEncode( $options ); |
— | — | @@ -159,17 +132,17 @@ |
160 | 133 | if( $status !== true ){ |
161 | 134 | return false; |
162 | 135 | } |
163 | | - // else just continue with db updates, and when the new job comes around it won't start because it will see |
| 136 | + // else just continue with db updates, and when the new job comes around it won't start because it will see |
164 | 137 | // that the job has already been started. |
165 | 138 | } |
166 | 139 | |
167 | | - // If status is oky move the file to its final destination. ( timedMediaHandler will look for it there ) |
168 | | - if( $status === true ){ |
| 140 | + // If status is oky and file exists and is larger than 0 bytes |
| 141 | + if( $status === true && is_file( $this->getTargetEncodePath() ) && filesize( $this->getTargetEncodePath() ) > 0 ){ |
169 | 142 | $finalDerivativeFilePath = WebVideoTranscode::getDerivativeFilePath( $file, $transcodeKey); |
170 | 143 | wfSuppressWarnings(); |
171 | | - $status = rename( $this->getTargetEncodePath(), $finalDerivativeFilePath ); |
| 144 | + $status = rename( $this->getTargetEncodePath(), $finalDerivativeFilePath ); |
| 145 | + $bitrate = round( intval( filesize( $finalDerivativeFilePath ) / $file->getLength() ) * 8 ); |
172 | 146 | wfRestoreWarnings(); |
173 | | - $bitrate = round( intval( filesize( $finalDerivativeFilePath ) / $file->getLength() ) * 8 ); |
174 | 147 | // Update the transcode table with success time: |
175 | 148 | $dbw->update( |
176 | 149 | 'transcode', |
— | — | @@ -186,7 +159,7 @@ |
187 | 160 | ); |
188 | 161 | WebVideoTranscode::invalidatePagesWithFile( $this->title ); |
189 | 162 | } else { |
190 | | - // Update the transcode table with failure time and error |
| 163 | + // Update the transcode table with failure time and error |
191 | 164 | $dbw->update( |
192 | 165 | 'transcode', |
193 | 166 | array( |
— | — | @@ -200,11 +173,11 @@ |
201 | 174 | __METHOD__, |
202 | 175 | array( 'LIMIT' => 1 ) |
203 | 176 | ); |
204 | | - // no need to invalidate all pages with video. Because all pages remain valid ( no $transcodeKey derivative ) |
| 177 | + // no need to invalidate all pages with video. Because all pages remain valid ( no $transcodeKey derivative ) |
205 | 178 | // just clear the file page ( so that the transcode table shows the error ) |
206 | 179 | $this->title->invalidateCache(); |
207 | 180 | } |
208 | | - // Clear the webVideoTranscode cache ( so we don't keep out dated table cache around ) |
| 181 | + // Clear the webVideoTranscode cache ( so we don't keep out dated table cache around ) |
209 | 182 | webVideoTranscode::clearTranscodeCache( $this->title->getDBkey() ); |
210 | 183 | |
211 | 184 | // pass along result status: |
— | — | @@ -280,7 +253,7 @@ |
281 | 254 | } |
282 | 255 | |
283 | 256 | $this->output( "Running cmd: \n\n" .$cmd . "\n" ); |
284 | | - |
| 257 | + |
285 | 258 | // Right before we output remove the old file |
286 | 259 | wfProfileIn( 'ffmpeg_encode' ); |
287 | 260 | $retval = 0; |
— | — | @@ -300,8 +273,8 @@ |
301 | 274 | $cmd =''; |
302 | 275 | // Add the boiler plate vp8 ffmpeg command: |
303 | 276 | $cmd.=" -y -skip_threshold 0 -rc_buf_aggressivity 0 -bufsize 6000k -rc_init_occupancy 4000 -threads 4"; |
304 | | - |
305 | | - // Check for video quality: |
| 277 | + |
| 278 | + // Check for video quality: |
306 | 279 | if ( isset( $options['videoQuality'] ) && $options['videoQuality'] >= 0 ) { |
307 | 280 | // Map 0-10 to 63-0, higher values worse quality |
308 | 281 | $quality = 63 - intval( intval( $options['videoQuality'] )/10 * 63 ); |
— | — | @@ -309,7 +282,7 @@ |
310 | 283 | $cmd .= " -qmax " . wfEscapeShellArg( $quality ); |
311 | 284 | } |
312 | 285 | |
313 | | - // Check for video bitrate: |
| 286 | + // Check for video bitrate: |
314 | 287 | if ( isset( $options['videoBitrate'] ) ) { |
315 | 288 | $cmd.= " -qmin 1 -qmax 51"; |
316 | 289 | $cmd.= " -vb " . wfEscapeShellArg( $options['videoBitrate'] * 1000 ); |
— | — | @@ -317,7 +290,7 @@ |
318 | 291 | // Set the codec: |
319 | 292 | $cmd.= " -vcodec libvpx"; |
320 | 293 | |
321 | | - // Check for aspect ratio ( we don't do anything with this right now) |
| 294 | + // Check for aspect ratio ( we don't do anything with this right now) |
322 | 295 | if ( isset( $options['aspect'] ) ) { |
323 | 296 | $aspectRatio = $options['aspect']; |
324 | 297 | } else { |
— | — | @@ -331,14 +304,14 @@ |
332 | 305 | // Get size transform ( if maxSize is > file, file size is used: |
333 | 306 | list( $width, $height ) = WebVideoTranscode::getMaxSizeTransform( $file, $options['maxSize'] ); |
334 | 307 | $cmd.= ' -s ' . intval( $width ) . 'x' . intval( $height ); |
335 | | - } elseif ( |
336 | | - (isset( $options['width'] ) && $options['width'] > 0 ) |
| 308 | + } elseif ( |
| 309 | + (isset( $options['width'] ) && $options['width'] > 0 ) |
337 | 310 | && |
338 | | - (isset( $options['height'] ) && $options['height'] > 0 ) |
| 311 | + (isset( $options['height'] ) && $options['height'] > 0 ) |
339 | 312 | ){ |
340 | 313 | $cmd.= ' -s ' . intval( $options['width'] ) . 'x' . intval( $options['height'] ); |
341 | 314 | } |
342 | | - |
| 315 | + |
343 | 316 | // Handle crop: |
344 | 317 | $optionMap = array( |
345 | 318 | 'cropTop' => '-croptop', |
— | — | @@ -423,9 +396,9 @@ |
424 | 397 | |
425 | 398 | // Add the output target: |
426 | 399 | $cmd.= ' -o ' . wfEscapeShellArg ( $this->getTargetEncodePath() ); |
427 | | - |
| 400 | + |
428 | 401 | $this->output( "Running cmd: \n\n" .$cmd . "\n" ); |
429 | | - |
| 402 | + |
430 | 403 | wfProfileIn( 'ffmpeg2theora_encode' ); |
431 | 404 | $retval = 0; |
432 | 405 | $shellOutput = $this->runShellExec( $cmd, $retval ); |
— | — | @@ -436,17 +409,15 @@ |
437 | 410 | return true; |
438 | 411 | } |
439 | 412 | /** |
440 | | - * Runs the shell exec command. |
| 413 | + * Runs the shell exec command. |
441 | 414 | * if $wgEnableBackgroundTranscodeJobs is enabled will mannage a background transcode task |
442 | | - * else it just directly passes off to wfShellExec |
| 415 | + * else it just directly passes off to wfShellExec |
443 | 416 | * |
444 | 417 | * @param $cmd String Command to be run |
445 | 418 | * @param $retval String, refrence variable to return the exit code |
446 | 419 | */ |
447 | 420 | public function runShellExec( $cmd, &$retval){ |
448 | | - global $wgEnableNiceBackgroundTranscodeJobs, $wgTranscodeBackgroundPriority, |
449 | | - $wgTranscodeBackgroundTimeLimit; |
450 | | - |
| 421 | + global $wgEnableNiceBackgroundTranscodeJobs, $wgTranscodeBackgroundPriority; |
451 | 422 | // Check if background tasks are enabled |
452 | 423 | if( $wgEnableNiceBackgroundTranscodeJobs === false ){ |
453 | 424 | // Dont display shell output |
— | — | @@ -454,99 +425,150 @@ |
455 | 426 | // Directly execute the shell command: |
456 | 427 | return wfShellExec( $cmd, $retval ); |
457 | 428 | } |
458 | | - // Setup pointers for status and encoding log: |
459 | | - $encodingLog = $this->getTargetEncodePath() . '.stdout.log'; |
460 | | - $exitStatusLog = $this->getTargetEncodePath() . '.exit.log'; |
461 | | - |
462 | | - // Start background shell proc |
463 | | - $pid = wfShellExec( |
464 | | - "nohup nice -n $wgTranscodeBackgroundPriority $cmd > " . wfEscapeShellArg( $encodingLog ) . ' ' . |
465 | | - // ideally we could store the exit status here ( but it causes & echo $! to give us a bad pid ) |
466 | | - // "& echo $? > " . wfEscapeShellArg( $exitStatusLog ) . ' ' . |
467 | | - "& echo $!", |
468 | | - $retval |
469 | | - ); |
470 | | - $pid = trim( $pid ); |
471 | | - $errorMsg = ''; |
472 | | - |
473 | | - if( $pid == '' || $retval != 0){ |
474 | | - $errorMsg = "Failed to start, check $wgMaxShellMemory settings"; |
475 | | - $this->output( $errorMsg); |
| 429 | + |
| 430 | + $encodingLog = $this->getTargetEncodePath() . '.stdout.log'; |
| 431 | + $retvalLog = $this->getTargetEncodePath() . '.retval.log'; |
| 432 | + // Check that we can actually write to these files |
| 433 | + //( no point in running the encode if we can't write ) |
| 434 | + wfSuppressWarnings(); |
| 435 | + if( ! touch( $encodingLog) || ! touch( $retvalLog ) ){ |
| 436 | + wfRestoreWarnings(); |
476 | 437 | $retval = 1; |
477 | | - return $errorMsg; |
| 438 | + return "Error could not write to target location"; |
478 | 439 | } |
| 440 | + wfRestoreWarnings(); |
| 441 | + |
| 442 | + // Fork out a process for running the transcode |
| 443 | + $pid = pcntl_fork(); |
| 444 | + if ($pid == -1) { |
| 445 | + $errorMsg = '$wgEnableNiceBackgroundTranscodeJobs enabled but failed pcntl_fork'; |
| 446 | + $retval = 1; |
| 447 | + $this->output( $errorMsg); |
| 448 | + return $errorMsg; |
| 449 | + } else if ( $pid == 0) { |
| 450 | + // we are the child |
| 451 | + $this->runChildCmd( $cmd, $retval, $encodingLog, $retvalLog); |
| 452 | + // exit with the same code as the transcode: |
| 453 | + exit( $retval ); |
| 454 | + } else { |
| 455 | + // we are the parent monitor and return status |
| 456 | + return $this->monitorTranscode($pid, $retval, $encodingLog, $retvalLog); |
| 457 | + } |
| 458 | + } |
| 459 | + public function runChildCmd( $cmd, &$retval, $encodingLog, $retvalLog ){ |
| 460 | + global $wgTranscodeBackgroundPriority; |
| 461 | + // In theory we should use pcntl_exec but not sure how to get the stdout, ensure |
| 462 | + // we don't max php memory with the same protections provided by wfShellExec. |
| 463 | + |
| 464 | + // pcntl_exec requires a direct path to the exe and arguments as an array: |
| 465 | + //$cmd = explode(' ', $cmd ); |
| 466 | + //$baseCmd = array_shift( $cmd ); |
| 467 | + //print "run:" . $baseCmd . " args: " . print_r( $cmd, true ); |
| 468 | + //$status = pcntl_exec($baseCmd , $cmd ); |
| 469 | + |
| 470 | + // Directly execute the shell command: |
| 471 | + //global $wgTranscodeBackgroundPriority; |
| 472 | + //$status = wfShellExec( 'nice -n ' . $wgTranscodeBackgroundPriority . ' '. $cmd . ' 2>&1', $retval ); |
| 473 | + $status = wfShellExec( $cmd . ' 2>&1', $retval ); |
| 474 | + |
| 475 | + // Output the status: |
| 476 | + wfSuppressWarnings(); |
| 477 | + file_put_contents( $encodingLog, $status ); |
| 478 | + // Output the retVal to the $retvalLog |
| 479 | + file_put_contents( $retvalLog, $retval ); |
| 480 | + wfRestoreWarnings(); |
| 481 | + } |
| 482 | + |
| 483 | + public function monitorTranscode( $pid, &$retval, $encodingLog, $retvalLog ){ |
| 484 | + global $wgTranscodeBackgroundTimeLimit, $wgLang; |
| 485 | + $errorMsg = ''; |
479 | 486 | $loopCount = 0; |
480 | 487 | $oldFileSize = 0; |
481 | 488 | $startTime = time(); |
482 | 489 | $fileIsNotGrowing = false; |
483 | | - |
484 | | - while( true ){ |
485 | | - |
486 | | - // Check if pid still runing |
487 | | - if( ! self::isProcessRunning( $pid ) ){ |
488 | | - // see large note above about background tasks ( echo $? is probably not the exit status we want ) |
489 | | - $retval = wfShellExec( "echo $?"); |
490 | | - //$this->output( $pid . ' is done, $retval: ' .$retval ); |
491 | | - break; |
492 | | - } |
493 | | - |
494 | | - // Check that the target file is growing ( every 5 seconds ) |
| 490 | + |
| 491 | + $this->output( "Encoding with pid: $pid \npcntl_waitpid: " . pcntl_waitpid( $pid, $status, WNOHANG OR WUNTRACED) . |
| 492 | + "\nisProcessRunning: " . self::isProcessRunningKillZombie( $pid ) . "\n" ); |
| 493 | + |
| 494 | + // Check that the child process is still running ( note this does not work well with pcntl_waitpid |
| 495 | + // for some reason :( |
| 496 | + while( self::isProcessRunningKillZombie( $pid ) ) { |
| 497 | + //$this->output( "$pid is running" ); |
| 498 | + |
| 499 | + // Check that the target file is growing ( every 5 seconds ) |
495 | 500 | if( $loopCount == 5 ){ |
496 | | - // only run check if we are outputing to target file |
497 | | - // ( two pass encoding does not output to target on first pass ) |
| 501 | + // only run check if we are outputing to target file |
| 502 | + // ( two pass encoding does not output to target on first pass ) |
498 | 503 | if( is_file( $this->getTargetEncodePath() ) ){ |
499 | 504 | clearstatcache(); |
500 | 505 | $newFileSize = filesize( $this->getTargetEncodePath() ); |
| 506 | + $this->output( $wgLang->formatSize( $newFileSize ). ' Total size, encoding ' . |
| 507 | + $wgLang->formatSize( ( $newFileSize - $oldFileSize ) / 5 ) . ' per second' ); |
501 | 508 | if( $newFileSize == $oldFileSize ){ |
502 | 509 | if( $fileIsNotGrowing ){ |
503 | 510 | $errorMsg = "Target File is not increasing in size, kill process."; |
504 | 511 | $this->output( $errorMsg ); |
505 | 512 | // file is not growing in size, kill proccess |
506 | 513 | $retval = 1; |
507 | | - self::killProcess( $pid ); |
| 514 | + posix_kill( $pid, 9); |
508 | 515 | break; |
509 | 516 | } |
510 | | - // Wait an additional 5 seconds of the file not growing to confirm |
511 | | - // the transcode is frozen. |
| 517 | + // Wait an additional 5 seconds of the file not growing to confirm |
| 518 | + // the transcode is frozen. |
512 | 519 | $fileIsNotGrowing = true; |
| 520 | + } else { |
| 521 | + $fileIsNotGrowing = false; |
513 | 522 | } |
514 | 523 | $oldFileSize = $newFileSize; |
515 | 524 | } |
516 | 525 | // reset the loop counter |
517 | 526 | $loopCount = 0; |
518 | | - } |
519 | | - |
| 527 | + } |
| 528 | + |
520 | 529 | // Check if we have global job run-time has been exceeded: |
521 | 530 | if ( $wgTranscodeBackgroundTimeLimit && time() - $startTime > $wgTranscodeBackgroundTimeLimit ){ |
522 | 531 | $errorMsg = "Encoding exceeded max job run time ( " . TimedMediaHandler::seconds2npt( $maxTime ) . " ), kill process."; |
523 | 532 | $this->output( $errorMsg ); |
524 | 533 | // File is not growing in size, kill proccess |
525 | 534 | $retval = 1; |
526 | | - self::killProcess( $pid ); |
| 535 | + posix_kill( $pid, 9); |
527 | 536 | break; |
528 | 537 | } |
529 | | - |
| 538 | + |
530 | 539 | // Sleep for one second before repeating loop |
531 | 540 | $loopCount++; |
532 | 541 | sleep( 1 ); |
533 | 542 | } |
534 | | - |
535 | | - // return the encoding log contents ( will be inserted into error table if an error ) |
| 543 | + |
| 544 | + $returnPcntl = pcntl_wexitstatus( $status ); |
| 545 | + // check status |
| 546 | + wfSuppressWarnings(); |
| 547 | + $returnCodeFile = file_get_contents( $retvalLog ); |
| 548 | + wfRestoreWarnings(); |
| 549 | + //$this->output( "TranscodeJob:: Child pcntl return:". $returnPcntl . ' Log file exit code:' . $returnCodeFile . "\n" ); |
| 550 | + |
| 551 | + // File based exit code seems more reliable than pcntl_wexitstatus |
| 552 | + $retval = $returnCodeFile; |
| 553 | + |
| 554 | + // return the encoding log contents ( will be inserted into error table if an error ) |
536 | 555 | // ( will be ignored and removed if success ) |
537 | 556 | if( $errorMsg!= '' ){ |
538 | 557 | $errorMsg.="\n\n"; |
539 | 558 | } |
540 | 559 | return $errorMsg . file_get_contents( $encodingLog ); |
541 | 560 | } |
542 | | - public static function isProcessRunning( $pid ){ |
543 | | - exec( "ps $pid", $processState ); |
544 | | - return( count( $processState ) >= 2 ); |
| 561 | + // check if proccess is running and not a zombie |
| 562 | + public static function isProcessRunningKillZombie( $pid ){ |
| 563 | + exec( "ps $pid", $processState ); |
| 564 | + if( !isset( $processState[1] ) ){ |
| 565 | + return false; |
| 566 | + } |
| 567 | + if( strpos( $processState[1], '<defunct>' ) !== false ){ |
| 568 | + posix_kill( $pid, 9); |
| 569 | + return false; |
| 570 | + } |
| 571 | + return true; |
545 | 572 | } |
546 | | - public static function killProcess( $pid ){ |
547 | | - // we are killing a hung prcoces send -9 signal |
548 | | - wfShellExec( "kill -9 $pid"); |
549 | | - } |
550 | | - |
551 | 573 | /** |
552 | 574 | * Mapping between firefogg api and ffmpeg2theora command line |
553 | 575 | * |
— | — | @@ -591,5 +613,5 @@ |
592 | 614 | 'license' => "--license", |
593 | 615 | 'contact' => "--contact" |
594 | 616 | ); |
595 | | - |
| 617 | + |
596 | 618 | } |
Index: trunk/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/EmbedPlayer.config.php |
— | — | @@ -23,7 +23,7 @@ |
24 | 24 | |
25 | 25 | // jQuery selector of tags to be re-written by embedPlayer |
26 | 26 | // Set to empty string or null to avoid automatic video tag rewrites to embedPlayer |
27 | | - "EmbedPlayer.RewriteTags" => "video,audio,playlist", |
| 27 | + "EmbedPlayer.RewriteSelector" => "video,audio,playlist", |
28 | 28 | |
29 | 29 | // Default video size ( if no size provided ) |
30 | 30 | "EmbedPlayer.DefaultSize" => "400x300", |
Index: trunk/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/EmbedPlayer.loader.js |
— | — | @@ -11,9 +11,9 @@ |
12 | 12 | */ |
13 | 13 | $( mw ).bind( 'SetupInterface', function( event, callback ){ |
14 | 14 | // Check if we have tags to rewrite: |
15 | | - if( $( mw.getConfig( 'EmbedPlayer.RewriteTags' ) ).length ) { |
16 | | - // Rewrite the embedPlayer EmbedPlayer.RewriteTags and run callback once ready: |
17 | | - $( mw.getConfig( 'EmbedPlayer.RewriteTags' ) ) |
| 15 | + if( $( mw.getConfig( 'EmbedPlayer.RewriteSelector' ) ).length ) { |
| 16 | + // Rewrite the embedPlayer EmbedPlayer.RewriteSelector and run callback once ready: |
| 17 | + $( mw.getConfig( 'EmbedPlayer.RewriteSelector' ) ) |
18 | 18 | .embedPlayer( callback ); |
19 | 19 | } |
20 | 20 | }); |
Index: trunk/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayer.js |
— | — | @@ -144,6 +144,7 @@ |
145 | 145 | callback(); |
146 | 146 | } |
147 | 147 | } |
| 148 | + |
148 | 149 | /** |
149 | 150 | * Adds a player element for the embedPlayer to rewrite |
150 | 151 | * |