Index: trunk/extensions/TimedMediaHandler/TimedMediaHandler.php |
— | — | @@ -41,9 +41,6 @@ |
42 | 42 | // Support iframe for remote embedding |
43 | 43 | $wgEnableIframeEmbed = true; |
44 | 44 | |
45 | | -// Location of oggThumb binary ( used instead of ffmpeg ) |
46 | | -$wgOggThumbLocation = '/usr/bin/oggThumb'; |
47 | | - |
48 | 45 | // The location of ffmpeg2theora ( transcoding ) |
49 | 46 | $wgFFmpeg2theoraLocation = '/usr/bin/ffmpeg2theora'; |
50 | 47 | |
Index: trunk/extensions/TimedMediaHandler/TimedMediaThumbnail.php |
— | — | @@ -11,60 +11,12 @@ |
12 | 12 | } |
13 | 13 | |
14 | 14 | wfDebug( "Creating video thumbnail at" . $options['dstPath'] . "\n" ); |
15 | | - // If try OggThumb: |
16 | | - if( self::tryOggThumb( $options) ){ |
17 | | - return true; |
18 | | - } |
19 | 15 | // Else try ffmpeg and return result: |
20 | 16 | return self::tryFfmpegThumb( $options ); |
21 | 17 | } |
22 | | - /** |
23 | | - * Try to render a thumbnail using oggThumb: |
24 | | - * |
25 | | - * @param $file {Object} File object |
26 | | - * @param $dstPath {string} Destination path for the rendered thumbnail |
27 | | - * @param $dstPath {array} Thumb rendering parameters ( like size and time ) |
28 | | - */ |
29 | | - static function tryOggThumb( $options ){ |
30 | | - global $wgOggThumbLocation; |
31 | | - // Check that the file is 'ogg' format |
32 | | - if( $options['file']->getHandler()->getMetadataType() != 'ogg' ){ |
33 | | - return false; |
34 | | - } |
35 | | - |
36 | | - // Check for $wgOggThumbLocation |
37 | | - if( !$wgOggThumbLocation |
38 | | - || !is_file( $wgOggThumbLocation ) |
39 | | - ){ |
40 | | - return false; |
41 | | - } |
42 | | - |
43 | | - $cmd = wfEscapeShellArg( $wgOggThumbLocation ) . |
44 | | - ' -t '. intval( self::getThumbTime( $options ) ) . ' '; |
45 | | - |
46 | | - // Setting height to 0 will keep aspect: |
47 | | - // http://dev.streamnik.de/75.html |
48 | | - if( isset( $options['width'] ) ){ |
49 | | - $cmd.= ' -s ' . intval( $options['width'] ) . 'x0 '; |
50 | | - } |
51 | | - |
52 | | - $cmd.= ' -n ' . wfEscapeShellArg( $options['dstPath'] ) . ' ' . |
53 | | - ' ' . wfEscapeShellArg( $options['file']->getPath() ) . ' 2>&1'; |
54 | | - |
55 | | - $returnText = wfShellExec( $cmd, $retval ); |
56 | | - |
57 | | - // Check if it was successful |
58 | | - if ( !$options['file']->getHandler()->removeBadFile( $options['dstPath'], $retval ) ) { |
59 | | - return true; |
60 | | - } |
61 | | - return false; |
62 | | - } |
63 | 18 | |
64 | 19 | static function tryFfmpegThumb( $options ){ |
65 | 20 | global $wgFFmpegLocation; |
66 | | - if( !$wgFFmpegLocation || !is_file( $wgFFmpegLocation ) ){ |
67 | | - return false; |
68 | | - } |
69 | 21 | |
70 | 22 | $cmd = wfEscapeShellArg( $wgFFmpegLocation ) . |
71 | 23 | ' -i ' . wfEscapeShellArg( $options['file']->getPath() ); |
Index: trunk/extensions/TimedMediaHandler/README |
— | — | @@ -20,22 +20,33 @@ |
21 | 21 | |
22 | 22 | // For boxes doing transcoding you should increase the allocated shell memory: |
23 | 23 | $wgMaxShellMemory = 102400*64; |
| 24 | + |
| 25 | + |
| 26 | +== Running Transcodes == |
| 27 | +To transcode the video you need to run webVideoTranscode jobs. In the trunk maintenance folder |
| 28 | +you can run as the web user: |
| 29 | + php runJobs.php --type webVideoTranscode --maxjobs 1 |
24 | 30 | |
| 31 | +If you want to have a job runner that checks for new jobs every 5 min in the maintenance folder |
| 32 | +of Timed Media Handler run: |
| 33 | + WebVideoJobRunner.php |
25 | 34 | |
26 | | -Kaltura html5 player library |
| 35 | + |
| 36 | +== Kaltura html5 player library == |
27 | 37 | TimedMediaHandler uses the Kaltura html5 player library for video playback. |
28 | 38 | |
29 | 39 | For more information about the player library visit: |
30 | 40 | http://html5video.org or http://www.kaltura.org/project/HTML5_Video_Media_JavaScript_Library |
31 | 41 | |
32 | 42 | |
33 | | -FFmpeg |
| 43 | +== FFmpeg == |
34 | 44 | |
35 | 45 | We use FFmpeg for creating still images of videos, and for transcoding webm |
36 | 46 | videos. You will need a copy on your server. |
37 | 47 | |
| 48 | +You can download static ffmpeg builds for multiple platforms at: |
| 49 | +http://firefogg.org/nightly/ |
| 50 | + |
38 | 51 | Download source: http://ffmpeg.mplayerhq.hu/download.html |
39 | 52 | About the bug: https://roundup.mplayerhq.hu/roundup/ffmpeg/issue159 |
40 | 53 | |
— | — | @@ -80,12 +91,14 @@ |
81 | 92 | after the require line in LocalSettings.php. |
82 | 93 | |
83 | 94 | |
84 | | -ffmpeg2theora |
| 95 | +== ffmpeg2theora == |
85 | 96 | |
86 | 97 | We use ffmpeg2theora for extract metadata from videos, you will need a copy on your |
87 | 98 | server. |
88 | 99 | |
| 100 | +You can download static ffmpeg2theora builds for multiple platforms at: |
| 101 | +http://firefogg.org/nightly/ |
| 102 | + |
89 | 103 | Set the ffmpeg2theora binary location with: |
90 | 104 | |
91 | 105 | $wgFFmpeg2theoraLocation = '/path/to/ffmpeg2theora'; |
— | — | @@ -93,22 +106,7 @@ |
94 | 107 | Download ffmpeg2theora from: http://firefogg.org/nightly/ |
95 | 108 | |
96 | 109 | |
97 | | -oggThumb |
98 | | - |
99 | | -We use oggvideotools for creating still images of videos, you will need a copy on your |
100 | | -server. |
101 | | - |
102 | | -Set the oggThumb binary location with: |
103 | | - |
104 | | - $wgOggThumbLocation = '/path/to/oggThumb'; |
105 | | - |
106 | | -Download oggThumb from: http://dev.streamnik.de/oggvideotools.html |
107 | | - |
108 | | - |
109 | | -Cortado |
110 | | - |
| 110 | +== Cortado == |
111 | 111 | Wikimedia uses Cortado Java applet from Xiph.org. |
112 | 112 | |
113 | 113 | A .jar file compiled from this tree is provided in the OggHandler directory for |
— | — | @@ -120,9 +118,9 @@ |
121 | 119 | |
122 | 120 | See LICENSE.cortado, LICENSE.jheora and LICENSE.smoke for license information. |
123 | 121 | |
124 | | -PEAR File_Ogg |
125 | 122 | |
| 123 | +== PEAR File_Ogg == |
| 124 | + |
126 | 125 | Tim Starling forked the PEAR File_Ogg package and improved it significantly in order to |
127 | 126 | support this extension. Tim Starling has now taken over maintainership of File_Ogg and |
128 | 127 | merged my changes into the latest release. This extension will now work with |
— | — | @@ -132,11 +130,12 @@ |
133 | 131 | http://pear.php.net/package/File_Ogg |
134 | 132 | |
135 | 133 | As per the usual convention, the PEAR base directory (the one with PEAR.php in |
136 | | -it) must be in your include_path. |
| 134 | +it) must be in your include_path. Note you do not need to install PEAR, its included |
| 135 | +with the TMH. |
137 | 136 | |
138 | 137 | |
139 | | -getID3 |
| 138 | +== getID3 == |
| 139 | + |
140 | 140 | getID3 is used for metadata of WebM files. |
141 | 141 | |
142 | 142 | getID3() by James Heinrich <info@getid3.org> |
Index: trunk/extensions/TimedMediaHandler/TimedMediaHandler.i18n.php |
— | — | @@ -49,7 +49,7 @@ |
50 | 50 | 'timedmedia-derivative-480_880kbs.ogv' => 'Ogg 480P', |
51 | 51 | 'timedmedia-derivative-desc-480_880kbs.ogv' => 'Web streamable Ogg video (480P)', |
52 | 52 | |
53 | | - 'timedmedia-derivative-720_VBR.ogv' => 'Ogg HQ', |
| 53 | + 'timedmedia-derivative-720_VBR.ogv' => 'Ogg 720P', |
54 | 54 | 'timedmedia-derivative-desc-720_VBR.ogv' => 'High quality downloadable Ogg video (720P)', |
55 | 55 | |
56 | 56 | // WebM profiles: |
Index: trunk/extensions/TimedMediaHandler/TimedMediaTransformOutput.php |
— | — | @@ -147,7 +147,7 @@ |
148 | 148 | |
149 | 149 | // Fallback text displayed for browsers without js and without video tag support: |
150 | 150 | /// XXX note we may want to replace this with an image and download link play button |
151 | | - wfMsg( 'timedmedia-no-player-js', $firstSource['src'] ) |
| 151 | + wfMsg( 'timedmedia-no-player-js', $firstSource['src'] ) |
152 | 152 | ); |
153 | 153 | return $s; |
154 | 154 | } |
Index: trunk/extensions/TimedMediaHandler/WebVideoTranscode/WebVideoTranscodeJob.php |
— | — | @@ -77,6 +77,8 @@ |
78 | 78 | // unlink the .log file used in two pass encoding: |
79 | 79 | wfSuppressWarnings(); |
80 | 80 | unlink( $destinationFile . '.log' ); |
| 81 | + // Sometimes ffmpeg gives the file log-0.log extension |
| 82 | + unlink( $destinationFile . 'log-0.log'); |
81 | 83 | wfRestoreWarnings(); |
82 | 84 | } |
83 | 85 | // remove any log files |
Index: trunk/extensions/TimedMediaHandler/WebVideoTranscode/WebVideoTranscode.php |
— | — | @@ -238,9 +238,9 @@ |
239 | 239 | |
240 | 240 | } |
241 | 241 | |
242 | | - /* |
| 242 | + /** |
243 | 243 | * Based on the $wgEnabledTranscodeSet set of enabled derivatives we |
244 | | - * sync the database with $wgEnabledTranscodeSet |
| 244 | + * sync the database with $wgEnabledTranscodeSet and return sources that are ready |
245 | 245 | * |
246 | 246 | * If no transcode is in progress or ready add the job to the jobQueue |
247 | 247 | * |
— | — | @@ -297,10 +297,9 @@ |
298 | 298 | } |
299 | 299 | // Try and add the source |
300 | 300 | self::addSourceIfReady( $file, $sources, $transcodeKey, $options ); |
301 | | - } |
302 | | - |
| 301 | + } |
303 | 302 | // Make sure we have at least one ogg and webm encode |
304 | | - if( !$addOggFlag || !$addWebMFlag){ |
| 303 | + if( !$addOggFlag || !$addWebMFlag ){ |
305 | 304 | foreach( $wgEnabledTranscodeSet as $transcodeKey ){ |
306 | 305 | if( !$addOggFlag && self::$derivativeSettings[$transcodeKey]['videoCodec'] == 'theora' ){ |
307 | 306 | self::addSourceIfReady( $file, $sources, $transcodeKey, $options ); |
— | — | @@ -312,9 +311,9 @@ |
313 | 312 | } |
314 | 313 | } |
315 | 314 | } |
316 | | - |
317 | 315 | return $sources; |
318 | 316 | } |
| 317 | + |
319 | 318 | /** |
320 | 319 | * Get the transcode state for a given filename and transcodeKey |
321 | 320 | * |
— | — | @@ -322,9 +321,9 @@ |
323 | 322 | */ |
324 | 323 | public static function isTranscodeReady( $fileName, $transcodeKey ){ |
325 | 324 | |
326 | | - // check if we need to populate the transcodeState cache: |
| 325 | + // Check if we need to populate the transcodeState cache: |
327 | 326 | if( !self::$transcodeStateCache || !isset( self::$transcodeStateCache[ $fileName ] ) ) { |
328 | | - self::populateTranscodeStateCache( $fileName ); |
| 327 | + self::getTranscodeStateCache( $fileName ); |
329 | 328 | } |
330 | 329 | // If no state is found the cache for this file is false: |
331 | 330 | if( !isset( self::$transcodeStateCache[ $fileName ][ $transcodeKey ]) |
— | — | @@ -344,12 +343,12 @@ |
345 | 344 | } |
346 | 345 | |
347 | 346 | /** |
348 | | - * Populates the local transcoding state cache with the current DB state of transcodes |
| 347 | + * Populates the transcode table with the current DB state of transcodes |
349 | 348 | * if transcodes are not found in the database their state is set to "false" |
350 | 349 | * |
351 | 350 | * @param string $fileName key |
352 | 351 | */ |
353 | | - public static function populateTranscodeStateCache( $fileName ){ |
| 352 | + public static function getTranscodeStateCache( $fileName ){ |
354 | 353 | wfProfileIn( __METHOD__ ); |
355 | 354 | $res = wfGetDB( DB_SLAVE )->select( 'transcode', |
356 | 355 | array( 'transcode_key', 'transcode_time_success','transcode_time_addjob','transcode_final_bitrate' ) , |
— | — | @@ -369,12 +368,28 @@ |
370 | 369 | } |
371 | 370 | /** |
372 | 371 | * Remove any transcode jobs associated with a given $fileName |
| 372 | + * |
| 373 | + * also remove the transcode files: |
373 | 374 | */ |
374 | | - public static function removeTranscodeJobs( $fileName ){ |
375 | | - wfGetDB( DB_MASTER )->delete( 'transcode', |
| 375 | + public static function removeTranscodeJobs( &$file ){ |
| 376 | + $fileName = $file->getTitle()->getDbKey(); |
| 377 | + |
| 378 | + $res = wfGetDB( DB_SLAVE )->select( 'transcode', |
| 379 | + array( 'transcode_key' ), |
| 380 | + array( 'transcode_image_name' => $fileName ) |
| 381 | + ); |
| 382 | + // remove the file |
| 383 | + foreach( $res as $transcodeRow ){ |
| 384 | + $filePath = self::getDerivativeFilePath($file, $transcodeRow->transcode_key ); |
| 385 | + if( ! @unlink( $filePath ) ){ |
| 386 | + wfDebug( "Could not delete file $filePath\n" ); |
| 387 | + } |
| 388 | + } |
| 389 | + // Remove the db entries |
| 390 | + wfGetDB( DB_MASTER )->delete( 'transcode', |
376 | 391 | array( 'transcode_image_name' => $fileName ), |
377 | 392 | __METHOD__ |
378 | | - ); |
| 393 | + ); |
379 | 394 | } |
380 | 395 | |
381 | 396 | /** |
— | — | @@ -388,7 +403,7 @@ |
389 | 404 | if( self::isTranscodeReady( $fileName, $transcodeKey ) ){ |
390 | 405 | $sources[] = self::getDerivativeSourceAttributes( $file, $transcodeKey, $dataPrefix ); |
391 | 406 | } else { |
392 | | - self::updateJobQueue( $file, $transcodeKey ); |
| 407 | + self::updateJobQueue( $file, $transcodeKey ); |
393 | 408 | } |
394 | 409 | } |
395 | 410 | /** |
— | — | @@ -473,9 +488,9 @@ |
474 | 489 | |
475 | 490 | $fileName = $file->getTitle()->getDbKey(); |
476 | 491 | |
477 | | - // Check if we need to populate the transcodeState cache: |
| 492 | + // Check if we need to update the transcode state: |
478 | 493 | if( !self::$transcodeStateCache || !isset( self::$transcodeStateCache[ $fileName ] ) ) { |
479 | | - self::populateTranscodeStateCache( $fileName ); |
| 494 | + self::getTranscodeStateCache( $fileName ); |
480 | 495 | } |
481 | 496 | |
482 | 497 | // Check if the job has been added: |
— | — | @@ -518,7 +533,7 @@ |
519 | 534 | ); |
520 | 535 | } |
521 | 536 | // Update the state cache |
522 | | - self::populateTranscodeStateCache( $fileName ); |
| 537 | + self::getTranscodeStateCache( $fileName ); |
523 | 538 | } |
524 | 539 | // no jobId ? error out in some way? |
525 | 540 | } |
Index: trunk/extensions/TimedMediaHandler/TimedMediaHandler.hooks.php |
— | — | @@ -99,20 +99,14 @@ |
100 | 100 | public static function checkArticleDeleteComplete( &$article, &$user, $reason, $id ){ |
101 | 101 | // Check if the article is a file and remove transcode jobs: |
102 | 102 | if( $article->getTitle()->getNamespace() == NS_FILE ) { |
103 | | - // We can't get the file since the article is deleted :( |
104 | | - // so we can't: |
105 | | - // $file = wfFindFile( $article->getTitle() ); |
106 | | - // $file->getHandler()->getMetadataType() |
107 | 103 | |
108 | | - |
109 | | - // So we have to use this unfortunate file name extension hack :( |
110 | | - // XXX figure out a better way to do this. |
111 | | - $fileName = $article->getTitle()->getDBkey(); |
112 | | - $ext = strtolower( pathinfo( "$fileName", PATHINFO_EXTENSION ) ); |
113 | | - |
114 | | - if( $ext == 'ogg' || $ext == 'webm' || $ext == 'ogv' ){ |
115 | | - WebVideoTranscode::removeTranscodeJobs( $article->getTitle()->getDBkey() ); |
| 104 | + $file = wfFindFile( $article->getTitle() ); |
| 105 | + $mediaType = $file->getHandler()->getMetadataType(); |
| 106 | + |
| 107 | + if( $mediaType == 'webm' || $mediaType == 'ogg' ){ |
| 108 | + WebVideoTranscode::removeTranscodeJobs( $file ); |
116 | 109 | } |
| 110 | + |
117 | 111 | } |
118 | 112 | return true; |
119 | 113 | } |