http://www.mediawiki.org/wiki/Special:Code/MediaWiki/69006
Revision: 69006
Author: dale
Date: 2010-07-04 15:52:19 +0000 (Sun, 04 Jul 2010)
Log Message:
-----------
added audio track layout support to render
commented out some render time debug lines
Modified Paths:
--------------
branches/MwEmbedStandAlone/modules/EmbedPlayer/skins/kskin/mw.PlayerSkinKskin.js
branches/MwEmbedStandAlone/modules/EmbedPlayer/skins/mw.PlayerControlBuilder.js
branches/MwEmbedStandAlone/modules/Sequencer/mw.FirefoggRender.js
branches/MwEmbedStandAlone/modules/SmilPlayer/mw.EmbedPlayerSmil.js
branches/MwEmbedStandAlone/modules/SmilPlayer/mw.Smil.js
branches/MwEmbedStandAlone/modules/SmilPlayer/mw.SmilBody.js
branches/MwEmbedStandAlone/modules/SmilPlayer/mw.SmilLayout.js
branches/MwEmbedStandAlone/modules/SmilPlayer/tests/VideoCrossfadeSmil.xml
Modified:
branches/MwEmbedStandAlone/modules/EmbedPlayer/skins/kskin/mw.PlayerSkinKskin.js
===================================================================
---
branches/MwEmbedStandAlone/modules/EmbedPlayer/skins/kskin/mw.PlayerSkinKskin.js
2010-07-04 15:29:52 UTC (rev 69005)
+++
branches/MwEmbedStandAlone/modules/EmbedPlayer/skins/kskin/mw.PlayerSkinKskin.js
2010-07-04 15:52:19 UTC (rev 69006)
@@ -339,7 +339,7 @@
.loadingSpinner()
);
- if( mw.getConfig( 'EmbedPlayer.kalturaAttribution' ) == true ){
+ if( mw.getConfig( 'EmbedPlayer.KalturaAttribution' ) == true ){
$target.append(
$j( '<div />' )
.addClass( 'k-attribution' )
Modified:
branches/MwEmbedStandAlone/modules/EmbedPlayer/skins/mw.PlayerControlBuilder.js
===================================================================
---
branches/MwEmbedStandAlone/modules/EmbedPlayer/skins/mw.PlayerControlBuilder.js
2010-07-04 15:29:52 UTC (rev 69005)
+++
branches/MwEmbedStandAlone/modules/EmbedPlayer/skins/mw.PlayerControlBuilder.js
2010-07-04 15:52:19 UTC (rev 69006)
@@ -162,7 +162,7 @@
this.supportedComponets['timedText'] = true;
}
// Check for kalturaAttribution
- if( mw.getConfig( 'EmbedPlayer.KalturaAttribution' ) ){
+ if( mw.getConfig( 'EmbedPlayer.KalturaAttribution' ) ){
this.supportedComponets[ 'kalturaAttribution' ] = true;
}
Modified: branches/MwEmbedStandAlone/modules/Sequencer/mw.FirefoggRender.js
===================================================================
--- branches/MwEmbedStandAlone/modules/Sequencer/mw.FirefoggRender.js
2010-07-04 15:29:52 UTC (rev 69005)
+++ branches/MwEmbedStandAlone/modules/Sequencer/mw.FirefoggRender.js
2010-07-04 15:52:19 UTC (rev 69006)
@@ -81,7 +81,9 @@
},
-
+ getPlayer: function(){
+ return $j( this.playerTarget ).get( 0 );
+ },
// Start rendering
doRender: function() {
var _this = this;
@@ -94,16 +96,30 @@
// Set the continue rendering flag to true:
this.continueRendering = true;
-
- // Get the player:
- this.player = $j( this.playerTarget ).get( 0 );
// Set a target file:
mw.log( "Firefogg Render Settings:" + JSON.stringify(
_this.renderOptions ) );
this.fogg.initRender( JSON.stringify( _this.renderOptions ),
'foggRender.ogv' );
// Add audio if we had any:
+ var audioSet = this.getPlayer().getAudioTimeSet();
+ var previusAudioTime = 0;
+ for( var i=0; i < audioSet.length ; i++) {
+ var currentAudio = audioSet[i];
+ // Check if we need to add silence
+ if( currentAudio.startTime > previusAudioTime ){
+ mw.log("FirefoggRender::addSilence " + (
currentAudio.startTime - previusAudioTime ));
+ this.fogg.addSilence( currentAudio.startTime -
previusAudioTime );
+ }
+ // Add the block of audio from the url
+ mw.log("FirefoggRender::addAudioUrl " +
currentAudio.src +
+ ', ' + currentAudio.offset + ', ' +
currentAudio.duration );
+ this.fogg.addAudioUrl( currentAudio.src,
currentAudio.offset, currentAudio.duration );
+ // Update previusAudioTime
+ previusAudioTime = currentAudio.startTime +
currentAudio.duration;
+ }
+
// Now issue the save video as call
_this.fogg.saveVideoAs();
@@ -120,14 +136,14 @@
( Math.round( _this.player.getDuration() * 10 ) / 10 )
);
*/
- _this.player.setCurrentTime( _this.renderTime, function() {
+ _this.getPlayer().setCurrentTime( _this.renderTime, function()
{
_this.fogg.addFrame( $j( _this.playerTarget ).attr(
'id' ) );
$j( _this.statusTarget ).text( "AddFrame::" + (
Math.round( _this.renderTime * 1000 ) / 1000 ) );
_this.renderTime += _this.interval;
- if ( _this.renderTime >= _this.player.getDuration() ||
! _this.continueRendering ) {
+ if ( _this.renderTime >=
_this.getPlayer().getDuration() || ! _this.continueRendering ) {
_this.doFinalRender();
} else {
// Don't block on render requests
Modified: branches/MwEmbedStandAlone/modules/SmilPlayer/mw.EmbedPlayerSmil.js
===================================================================
--- branches/MwEmbedStandAlone/modules/SmilPlayer/mw.EmbedPlayerSmil.js
2010-07-04 15:29:52 UTC (rev 69005)
+++ branches/MwEmbedStandAlone/modules/SmilPlayer/mw.EmbedPlayerSmil.js
2010-07-04 15:52:19 UTC (rev 69006)
@@ -79,7 +79,7 @@
var _this = this;
this.getSmil( function( smil ){
smil.renderTime( time, function(){
- mw.log( "setCurrentTime:: renderTime callback"
);
+ //mw.log( "setCurrentTime:: renderTime
callback" );
$j('#loadingSpinner_' + _this.id ).remove();
_this.monitor();
@@ -277,9 +277,9 @@
* tracks from movie files.
*/
getAudioTimeSet: function(){
- if(!this.smil)
+ if(!this.smil){
return null;
-
+ }
return this.smil.getAudioTimeSet();
}
Modified: branches/MwEmbedStandAlone/modules/SmilPlayer/mw.Smil.js
===================================================================
--- branches/MwEmbedStandAlone/modules/SmilPlayer/mw.Smil.js 2010-07-04
15:29:52 UTC (rev 69005)
+++ branches/MwEmbedStandAlone/modules/SmilPlayer/mw.Smil.js 2010-07-04
15:52:19 UTC (rev 69006)
@@ -152,6 +152,13 @@
},
/**
+ * Get the set of audio ranges for flattening.
+ */
+ getAudioTimeSet: function(){
+ return this.getBody().getFlatAudioTimeLine();
+ },
+
+ /**
* Pass on the request to start buffering the entire sequence of clips
*/
startBuffer: function(){
@@ -234,17 +241,10 @@
/**
* Some Smil Utility functions
- */
+ */
/**
- * Returns a set of audio ranges for flattening.
- */
- getAudioTimeSet: function( ){
- return {};
- },
-
- /**
- * maps a smil element id to a html safe id
+ * maps a smil element id to a html 'safer' id
* as a decedent subname of the embedPlayer parent
*
* @param {Object} smilElement Element to get id for
@@ -280,9 +280,15 @@
return;
}
// Get the smil type
- var smilType = $j( smilElement ).get(0).nodeName.toLowerCase();
+ var smilType = $j( smilElement ).get(0).nodeName.toLowerCase();
+
+ if( this.getBody().smilBlockTypeMap[ smilType ] != 'ref' ){
+ mw.log("Error: trying to get ref type of node that is
not a ref" + smilType);
+ return null;
+ }
+
+ // If the smilType is ref, check for a content type
if( smilType == 'ref' ){
- // If the smilType is ref, check for a content type
switch( $j( smilElement ).attr( 'type' ) ) {
case 'text/html':
smilType = 'cdata_html';
@@ -292,6 +298,9 @@
case 'video/webm':
smilType = 'video';
break;
+ case 'audio/ogg':
+ smilType = 'audio';
+ break;
}
}
return smilType;
Modified: branches/MwEmbedStandAlone/modules/SmilPlayer/mw.SmilBody.js
===================================================================
--- branches/MwEmbedStandAlone/modules/SmilPlayer/mw.SmilBody.js
2010-07-04 15:29:52 UTC (rev 69005)
+++ branches/MwEmbedStandAlone/modules/SmilPlayer/mw.SmilBody.js
2010-07-04 15:52:19 UTC (rev 69006)
@@ -21,6 +21,16 @@
// This lets us cache a valid element list for a given amount of time
cacheElementList: {},
+ smilBlockTypeMap: {
+ 'body':'seq',
+ 'ref' : 'ref',
+ 'animation':'ref',
+ 'audio' : 'ref',
+ 'img' : 'ref',
+ 'textstream' : 'ref',
+ 'video' : 'ref'
+ },
+
// Constructor:
init: function( smilObject ){
this.smil = smilObject;
@@ -57,7 +67,8 @@
},
/**
- * Render the body elements for a given time, use layout engine to draw
elements
+ * Render the body elements for a given time, use layout engine to draw
elements
+ * @param time
*/
renderTime: function( time, deltaTime ){
var _this = this;
@@ -98,59 +109,172 @@
},
/**
- * Check if we have a valid element cache:
- * XXX not yet working.
- */
- isValidElementCache: function( time ){
- if( time > this.cacheElementList.validStart && time >
this.cacheElementList.validEnd ) {
- return this.cacheElementList.elements;
+ * Firefogg flattener can presently only sequence flat sequence of audio
+ * Also See: http://www.firefogg.org/dev/render.html
+ *
+ * Note if we could "blend" or play two audio files at the same time
+ * none of this would be needed
+ *
+ * ie this code should be replaced once we add improved audio support
+ *
+ * @return {Object} an array of audio with the following properties:
+ * start The start offset of the audio asset.
+ * duration Duration of the audio asset
+ * src The source url, if set to false, silence is inserted for
duration
+ * type Used internally to let audio overlay video.
+ */
+ getFlatAudioTimeLine: function(){
+ var _this = this;
+
+ // Setup some flags:
+ var maxAudioTime =0;
+
+ var elementsWithAudio = [];
+ var audioTimeline = [];
+
+ // xxx could probably do this a bit cleaner
+ var getEarliest = function ( audioTimeline ){
+ var smallTime = null;
+ var smallIndex = null
+ for( var i =0; i < audioTimeline.length; i++ ){
+ if( smallTime === null ){
+ smallTime =
audioTimeline[i]['startTime'];
+ smallIndex = i;
+ }
+
+ if( audioTimeline[i]['startTime'] < smallTime ){
+ smallTime =
audioTimeline[i]['startTime'];
+ smallIndex = i;
+ }
+ }
+ return smallIndex = i;
}
+ // Build an audio timeline starting from the top level node:
+ this.getRefElementsRecurse( this.$dom, 0, function( $node ){
+ var nodeType = _this.smil.getRefType( $node ) ;
+ // Check if the node is audio ( first in wins / "audio"
wins over video)
+ if( nodeType == 'audio' || nodeType == 'video' ) {
+ var audioObj = {
+ 'type' : nodeType,
+ 'src' : _this.smil.getAssetUrl (
$node.attr('src') ),
+ 'duration' : _this.getNodeDuration(
$node ),
+ 'startTime' : $node.data( 'startOffset'
),
+ 'offset' : 0 // have to add in
media-offset support
+ };
+
+ // If audioTimeline is empty insert directly
+ if( audioTimeline.length == 0 ){
+ audioTimeline.push( audioObj )
+ return ;
+ }
+
+ // fill time
+ var addedAudioFlag = false;
+ for( var i = 0; i < audioTimeline.length; i++ ){
+ var currentAudioObj = audioTimeline[i];
+ var audioEndTime =
audioObj['startTime'] + audioObj['duration'];
+ var currentAudioEndTime =
currentAudioObj['startTime'] + currentAudioObj['duration'];
+ if( audioObj['startTime'] <
currentAudioObj['startTime'] ){
+ addedAudioFlag = true;
+ var beforeAudioObj = $j.extend(
audioObj, {
+ 'duration': (
currentAudioObj['startTime'] - audioObj['startTime'] )
+ });
+ // Add before
+ audioTimeline.splice( i, 0,
beforeAudioObj );
+
+ // Update the audioObj if it
extends past the currentAudioObject
+ if( audioEndTime >
currentAudioEndTime){
+ audioObj['startTime'] =
currentAudioEndTime;
+ audioObj['duration'] =
audioEndTime - currentAudioEndTime;
+ } else {
+ // done adding audioObj
+ break;
+ }
+ }
+ }
+ // add audioObject to end ( currentAudioObj has
latest startTime
+ if( ! addedAudioFlag && audioEndTime >
currentAudioEndTime ){
+ var audioObjDuration = ( audioEndTime -
currentAudioEndTime );
+ if( currentAudioEndTime +
audioObjDuration > _this.getDuration() ){
+ audioObjDuration =
_this.getDuration() - currentAudioEndTime;
+ }
+ audioTimeline.push( $j.extend(
audioObj, {
+ 'duration':
audioObjDuration,
+ 'startTime' :
currentAudioEndTime
+ })
+ );
+ }
+
+ // Keep audioTimeline sorted via startTime
+ audioTimeline.sort( function( a, b){
+ return a.startTime - b.startTime;
+ });
+ }
+ });
+
+ return audioTimeline;
},
/**
* Gets all the elements for a given time.
+ *
+ * Note this gets called all the time we may need to build a more
efficient structure to access this info
*/
getElementsForTime: function ( time , inRangeCallback,
outOfRangeCallback ) {
- var startOffset = 0;
+ var _this = this;
if( !time ) {
time =0;
}
- // Empty out the requested element set:
- this.getElementsForTimeRecurse( this.$dom, time, startOffset,
inRangeCallback, outOfRangeCallback);
+ // Recurse on every ref element and run relevant callbacks
+ this.getRefElementsRecurse( this.$dom, 0, function( $node ){
+ var startOffset = $node.data( 'startOffset' );
+ var nodeDuration = _this.getNodeDuration( $node );
+
+ // Check if element is in range:
+ if( time >= startOffset && time <= ( startOffset +
nodeDuration) ){
+ if( typeof inRangeCallback == 'function' ){
+ inRangeCallback( $node );
+ }
+ } else {
+ if( typeof outOfRangeCallback == 'function'){
+ outOfRangeCallback( $node );
+ }
+ }
+ });
},
/**
* getElementsForTimeRecurse
* @param {Object} $node Node to recursively search for elements in the
given time range
*/
- getElementsForTimeRecurse: function( $node, time, startOffset,
inRangeCallback, outOfRangeCallback){
+
+ /**
+ * Recurse over all body elements, issues a callback on all ref and
smilText nodes
+ * adds startOffset info for easy timeline checks.
+ */
+ getRefElementsRecurse: function( $node, startOffset, callback ){
var _this = this;
- // Setup local pointers:
- var nodeDuration = this.getNodeDuration( $node );
+ // Setup local pointers:
var nodeType = this.getNodeSmilType( $node );
- var nodeParentType = this.getNodeSmilType( $node.parent() );
-
-
- // If 'par' or 'seq' recurse to get elements for layout
+
+ // If 'par' or 'seq' recurse on children
if( nodeType == 'par' || nodeType == 'seq' ) {
if( $node.children().length ) {
$node.children().each( function( inx, childNode
){
// mw.log(" recurse:: startOffset:" +
nodeType + ' start offset:' + startOffset );
- var childDur =
_this.getElementsForTimeRecurse(
- $j( childNode ),
- time,
- startOffset,
- inRangeCallback,
- outOfRangeCallback
+ var childDur =
_this.getRefElementsRecurse(
+ $j( childNode ),
+ startOffset,
+ callback
);
// If element parent is a 'seq'
increment startOffset as we recurse for each child
if( nodeType == 'seq' ) {
//mw.log(" Parent Seq:: add
child dur: " + childDur );
startOffset += childDur;
- }
+ }
});
}
- }
+ }
// If the nodeType is "ref" or smilText run the callback
if( nodeType == 'ref' || nodeType == 'smilText' ) {
@@ -161,26 +285,17 @@
}
// Add the parent startOffset
- $node.data( 'startOffset', startOffset );
+ $node.data( 'startOffset', startOffset );
- // Check if element is in range:
- if( time >= startOffset && time <= ( startOffset +
nodeDuration) ){
- if( typeof inRangeCallback == 'function' ){
- inRangeCallback( $node );
- }
- } else {
- if( typeof outOfRangeCallback == 'function'){
- outOfRangeCallback( $node );
- }
- }
- }
+ callback( $node )
+ }
// Return the node Duration for tracking startOffset
return this.getNodeDuration( $node );
},
/**
* Returns the smil body duration
- * ( wraps getDurationRecurse to get top level duration )
+ * ( wraps getDurationRecurse to get top level node duration )
*/
getDuration: function(){
this.duration = this.getNodeDuration( this.$dom );
@@ -215,7 +330,7 @@
$node.data( 'implictDuration',
$node.data('implictDuration') + childDuration );
}
// With par blocks ImplictDuration is longest
duration child
- if( blockType == 'par' ){
+ if( blockType == 'par' ) {
if( childDuration > $node.data(
'implictDuration' ) ){
$node.data( 'implictDuration',
childDuration);
}
@@ -255,18 +370,10 @@
*/
getNodeSmilType: function( $node ){
var blockType = $j( $node ).get(0).nodeName;
- var blockMap = {
- 'body':'seq',
- 'ref' : 'ref',
- 'animation':'ref',
- 'audio' : 'ref',
- 'img' : 'ref',
- 'textstream' : 'ref',
- 'video' : 'ref'
+
+ if( this.smilBlockTypeMap[ blockType ] ){
+ blockType = this.smilBlockTypeMap[ blockType ];
}
- if( blockMap[ blockType ] ){
- blockType = blockMap[ blockType ];
- }
return blockType;
}
}
\ No newline at end of file
Modified: branches/MwEmbedStandAlone/modules/SmilPlayer/mw.SmilLayout.js
===================================================================
--- branches/MwEmbedStandAlone/modules/SmilPlayer/mw.SmilLayout.js
2010-07-04 15:29:52 UTC (rev 69005)
+++ branches/MwEmbedStandAlone/modules/SmilPlayer/mw.SmilLayout.js
2010-07-04 15:52:19 UTC (rev 69006)
@@ -158,6 +158,9 @@
case 'video':
return this.getSmilVideoHtml( smilElement );
break;
+ case 'audio':
+ return this.getSmilAudioHtml( smilElement );
+ break;
// Smil Text: http://www.w3.org/TR/SMIL/smil-text.html
( obviously we support a subset )
case 'smiltext':
return this.getSmilTextHtml( smilElement );
@@ -181,16 +184,28 @@
/**
* Return the video
*/
- getSmilVideoHtml: function( videoElement ){
+ getSmilVideoHtml: function( smilElement ){
return $j('<video />')
.attr( {
- 'id' : this.smil.getAssetId( videoElement ),
- 'src' : this.smil.getAssetUrl( $j( videoElement
).attr( 'src' ) )
+ 'id' : this.smil.getAssetId( smilElement ),
+ 'src' : this.smil.getAssetUrl( $j( smilElement
).attr( 'src' ) )
} )
.addClass( 'smilFillWindow' )
},
/**
+ * Return audio element ( by default audio tracks are hidden )
+ */
+ getSmilAudioHtml: function ( smilElement ){
+ return $j('<audio />')
+ .attr( {
+ 'id' : this.smil.getAssetId( smilElement ),
+ 'src' : this.smil.getAssetUrl( $j( smilElement ).attr(
'src' ) )
+ } )
+ .css( 'display', 'none');
+ },
+
+ /**
* Get Smil CDATA ( passed through jQuery .clean as part of fragment
creation )
* XXX Security XXX
* Here we are parsing in SMIL -> HTML should be careful about XSS or
script elevation
Modified:
branches/MwEmbedStandAlone/modules/SmilPlayer/tests/VideoCrossfadeSmil.xml
===================================================================
--- branches/MwEmbedStandAlone/modules/SmilPlayer/tests/VideoCrossfadeSmil.xml
2010-07-04 15:29:52 UTC (rev 69005)
+++ branches/MwEmbedStandAlone/modules/SmilPlayer/tests/VideoCrossfadeSmil.xml
2010-07-04 15:52:19 UTC (rev 69006)
@@ -17,7 +17,12 @@
</head>
<body>
<par>
-
+
+ <audio
src="http://upload.wikimedia.org/wikipedia/commons/5/5a/La_Donna_E_Mobile_Rigoletto.ogg"
+ begin="1s"
+ dur="10s"
+ />
+
<video
src="http://upload.wikimedia.org/wikipedia/commons/d/d3/Okapia_johnstoni5.ogg"
transIn="fromGreen"
type="video/ogg"
@@ -27,7 +32,7 @@
/>
<video
src="http://upload.wikimedia.org/wikipedia/commons/0/0d/B-36_bomber.ogg"
- begin="5s"
+ begin="5s"
transIn="xFade"
fill="transition"
_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs