PDA

View Full Version : Standard media interface across platforms


kmeixner
11-10-2011, 08:28 AM
Here are some classes I created so that I can have a standard media interface and behaviour across different runtimes and media types:


<switch>
<when property="$dhtml">
<!-- Not-yet-released OpenLaszlo html5video and html5audio classes -->
<include href="/usr/local/lps-5.0.x/Server/lps-5.0.x/lps/components/av/html5/library.lzx" />
</when>
</switch>

<class name="sarbasemediacontainer" extends="view">

<!--- @param text src: The URL to load the media from -->
<attribute name="src" type="text" />

<!--- @keywords private -->
<!--- @param boolean autoplay: (private, for future use only) if true autoplay the video/audio -->
<attribute name="autoplay" type="boolean" value="false" />

</class>

<class name="sarvideocontainer" extends="sarbasemediacontainer">

<!---
@param boolean use_videoview: (default: false) if true use <videoview>
container for the video rather than <view>.
(Applies to Flash mode only)
-->
<attribute name="use_videoview" type="boolean" value="false" />

<switch>

<when property="$dhtml">

<!-- *** METHODS *** -->

<method name="doPlay">
this.vwMedia.play();
</method>

<method name="doPause">
this.vwMedia.pause();
</method>

<method name="doStop">
// KM NOTE: HTML5 video/audio has no stop() so need this workaround:
this.vwMedia.pause();
this.vwMedia.setAttribute('currentTime', 0);
</method>

<method name="seekToMs" args="nMilliseconds, blnPauseMedia, nFrameInterval">
if (!blnPauseMedia){
this.vwMedia.setAttribute('currentTime', nMilliseconds);
}
else {
this.vwMedia.pause();
this.vwMedia.setAttribute('currentTime', nMilliseconds);
}
</method>

<!-- *** EVENTS *** -->

<handler name="onsrc" args="strSrc">
this.vwMedia.unload(); // TBD: Does this work with html5 elements?
this.vwMedia.setAttribute('src', strSrc);
</handler>

<!-- *** COMPONENTS *** -->

<html5videoview name="vwMedia"
controls="false"
stretches="both"
width="${parent.width}"
height="${parent.height}"
autoplay="${parent.autoplay}"
/>

</when>

<otherwise>

<state name="stSWFVideo" applied="${!classroot.use_videoview}">

<!-- *** METHODS *** -->

<method name="doPlay">
this.vwMedia.play();
</method>

<method name="doPause">
this.vwMedia.stop();
</method>

<method name="doStop">
this.vwMedia.stop(0, false);
</method>

<method name="seekToMs" args="nMilliseconds, blnPauseMedia, nFrameInterval">
if (!blnPauseMedia){
this.vwMedia.play(Math.floor(nMilliseconds/nFrameInterval));
}
else {
this.vwMedia.stop(Math.floor(nMilliseconds/nFrameInterval));
}
</method>

<!-- *** EVENTS *** -->

<handler name="onsrc" args="strSrc">
this.vwMedia.unload(); // workaround: prevent retention of media when strSrc set to ''
this.vwMedia.setSource(strSrc);
</handler>

<!-- *** COMPONENTS *** -->

<view name="vwMedia"
stretches="both"
width="${parent.width}"
height="${parent.height}"
>

<!-- Method 1: audio plays for a couple seconds then pauses -->

<handler name="onresource">
if (!parent.autoplay)
parent.doStop();
</handler>

<!-- Method 2: does not seem to work for video but no harm in including just in case -->

<!--- @keywords private -->
<!--- @param boolean iscompletedloading: this changes only when loadratio becomes 1 or not 1 -->
<attribute name="iscompletedloading" type="boolean" value="false" />

<handler name="onloadratio" args="nLoadRatio">
<![CDATA[

// Workaround for OpenLaszlo problem where nLoadRatio will be
// called a "bazillion" times with nLoadRatio=1, trigger
// oniscompletedloading change only once when needed

if (nLoadRatio == 1 && !this.iscompletedloading){
this.setAttribute('iscompletedloading', true);
}
else if (this.iscompletedloading){
this.setAttribute('iscompletedloading', false);
}

]]>
</handler>
<!-- OL problem Workaround: This will only fire when nLoadRatio becomes 1 or not 1 -->
<handler name="oniscompletedloading" args="blnIsCompletedLoading">

if (!blnIsCompletedLoading)
return;

if (!parent.autoplay){
parent.doStop();
}
else {
parent.doPlay();
}

</handler>

</view>
</state>

<state name="stMP4orFLV" applied="${classroot.use_videoview}">
<!-- *** METHODS *** -->

<method name="doPlay">
this.vwMedia.stream.play();
</method>

<method name="doPause">
this.vwMedia.stream.pause(true); // true forces stop playback
</method>

<method name="doStop">
//this.vwMedia.stream.stop(); // Note: broken in OL 4.9.0, use pause(), seek(0) workaround
this.vwMedia.stream.pause(true); // true forces stop playback
this.vwMedia.stream.seek(0);
</method>

<method name="seekToMs" args="nMilliseconds, blnPauseMedia, nFrameInterval">
if (!blnPauseMedia){
this.vwMedia.stream.seek(nMilliseconds/1000);
}
else {
this.vwMedia.stream.pause(true); // true forces stop playback
this.vwMedia.stream.seek(nMilliseconds/1000);
}
</method>

<!-- *** EVENTS *** -->

<handler name="onsrc" args="strSrc">
this.vwMedia.unload(); // workaround: prevent retention of media when strSrc set to ''
this.vwMedia.setAttribute('url', strSrc);
</handler>

<!-- *** COMPONENTS *** -->

<videoview name="vwMedia" type="http"
stretches="both"
width="${parent.width}"
height="${parent.height}"
autoplay="${parent.autoplay}"
>
</videoview>
</state>

</otherwise>

</switch>

<method name="destroy">
this.vwMedia.unload();
super.destroy();
</method>

</class>

<class name="saraudiocontainer" extends="sarbasemediacontainer"
width="0"
height="0"
>

<switch>

<when property="$dhtml">

<!-- *** METHODS *** -->

<method name="doPlay">
this.vwMedia.play();
</method>

<method name="doPause">
this.vwMedia.pause();
</method>

<method name="doStop">
// KM NOTE: HTML5 video/audio has no stop() so need this workaround:
this.vwMedia.pause();
this.vwMedia.setAttribute('currentTime', 0);
</method>

<method name="seekToMs" args="nMilliseconds, blnPauseMedia, nFrameInterval">
if (!blnPauseMedia){
this.vwMedia.setAttribute('currentTime', nMilliseconds);
}
else {
this.vwMedia.pause();
this.vwMedia.setAttribute('currentTime', nMilliseconds);
}
</method>

<!-- *** EVENTS *** -->

<handler name="onsrc" args="strSrc">
this.vwMedia.unload(); // TBD: Does this work with html5 elements?
this.vwMedia.setAttribute('src', strSrc);
</handler>

<!-- *** COMPONENTS *** -->

<html5audioview name="vwMedia"
controls="false"
width="0"
height="0"
autoplay="${parent.autoplay}"
/>

</when>

<otherwise>

<!-- *** METHODS *** -->

<method name="doPlay">
this.vwMedia.play();
</method>

<method name="doPause">
this.vwMedia.stop();
</method>

<method name="doStop">
this.vwMedia.stop(0, false);
</method>

<method name="seekToMs" args="nMilliseconds, blnPauseMedia, nFrameInterval">
// KM NOTE: Even though this is an audio file, using fps works in OpenLaszlo
if (!blnPauseMedia){
this.vwMedia.play(Math.floor(nMilliseconds/nFrameInterval));
}
else {
this.vwMedia.stop(Math.floor(nMilliseconds/nFrameInterval));
}
</method>

<!-- *** EVENTS *** -->

<handler name="onsrc" args="strSrc">
this.vwMedia.unload(); // workaround: prevent retention of media when strSrc set to ''
this.vwMedia.setSource(strSrc);
</handler>

<!-- *** COMPONENTS *** -->

<view name="vwMedia">

<!-- Method 1: audio plays for a couple seconds then pauses -->

<!--handler name="onresource">
if (!parent.autoplay)
parent.doStop();
</handler-->

<!-- Method 2: results in audio silent from the start -->

<!--- @keywords private -->
<!--- @param boolean iscompletedloading: this changes only when loadratio becomes 1 or not 1 -->
<attribute name="iscompletedloading" type="boolean" value="false" />

<handler name="onloadratio" args="nLoadRatio">
<![CDATA[

// Workaround for OpenLaszlo problem where nLoadRatio will be
// called a "bazillion" times with nLoadRatio=1, trigger
// oniscompletedloading change only once when needed

if (nLoadRatio == 1 && !this.iscompletedloading){
this.setAttribute('iscompletedloading', true);
}
else if (this.iscompletedloading){
this.setAttribute('iscompletedloading', false);
}

]]>
</handler>
<!-- OL problem Workaround: This will only fire when nLoadRatio becomes 1 or not 1 -->
<handler name="oniscompletedloading" args="blnIsCompletedLoading">

if (!blnIsCompletedLoading)
return;

if (!parent.autoplay){
parent.doStop();
}
else {
parent.doPlay();
}

</handler>

</view>

</otherwise>
</switch>

<method name="destroy">
this.vwMedia.unload();
super.destroy();
</method>

</class>

<class name="sarimagecontainer" extends="sarbasemediacontainer">

<!-- *** METHODS *** -->

<method name="doPlay">
return; // do nothing for image
</method>

<method name="doPause">
return; // do nothing for image
</method>

<method name="doStop">
return; // do nothing for image
</method>

<method name="seekToMs" args="nMilliseconds, blnPauseMedia, nFrameInterval">
return; // do nothing for image
</method>

<!-- *** EVENTS *** -->

<handler name="onsrc" args="strSrc">
this.vwMedia.unload(); // workaround: prevent retention of media when strSrc set to ''
this.vwMedia.setSource(strSrc);
</handler>

<!-- *** COMPONENTS *** -->

<view name="vwMedia"
stretches="both"
width="${parent.width}"
height="${parent.height}"
/>

<method name="destroy">
this.vwMedia.unload();
super.destroy();
</method>

</class>

<class name="sarmediacontainer" extends="view">

<!-- *** ATTRIBUTES *** -->

<!--- @param text mediatype: image|audio|video -->
<attribute name="mediatype" type="text" required="true" />

<!--- @param text src: the media url -->
<attribute name="src" type="text" required="true" />

<!---
@param boolean use_videoview: (default: false) if true use <videoview>
container for the video rather than <view>.
(Applies to Flash mode only, set to true for
MP4 or FLV playback in Flash mode)
-->
<attribute name="use_videoview" type="boolean" value="false" />

<!---
@param text fpstype: (optional)(Default: ntsc) The type of fps system.
ntsc|pal for North American, European respectfully
-->
<attribute name="fpstype" type="text" value="ntsc" />

<state name="stFpsNtsc" applied="$once{classroot.fpstype == 'ntsc'}">

<!--- @keywords private -->
<!--- @param number fps: Frames Per Second -->
<attribute name="fps" type="number" value="$once{30/1001}" />

<!--- @keywords private -->
<!--- @param number frameinterval: Time between frames in milliseconds -->
<attribute name="frameinterval" type="number" value="$once{1001/30}" />

</state>

<state name="stFpsPal" applied="$once{classroot.fpstype == 'pal'}">

<!--- @keywords private -->
<!--- @param number fps: Frames Per Second -->
<attribute name="fps" type="number" value="25" />

<!--- @keywords private -->
<!--- @param number frameinterval: Time between frames in milliseconds -->
<attribute name="frameinterval" type="number" value="40" />

</state>

<!--- @param boolean autoplay: if true start playing the media immediately -->
<attribute name="autoplay" type="boolean" value="false" />

<!-- *** METHODS *** -->

<method name="doPlay">
this.vwDisplay.doPlay();
</method>

<method name="doPause">
this.vwDisplay.doPause();
</method>

<method name="doStop">
this.vwDisplay.doStop();
</method>

<method name="seekToMs" args="nMilliseconds, blnPauseMedia=false">
this.vwDisplay.seekToMs(nMilliseconds, blnPauseMedia, this.frameinterval);
</method>

<!-- *** EVENTS *** -->

<handler name="oninit">
this.vwDisplay.setAttribute('src', this.src);
</handler>

<handler name="onsrc" args="strSrc">

if (!this['vwDisplay'])
return; // not initialized yet

this.vwDisplay.setAttribute('src', strSrc);
</handler>

<!-- *** COMPONENTS *** -->

<state name="stImage" applied="${classroot.mediatype == 'image'}">
<sarimagecontainer name="vwDisplay"
width="${parent.width}"
height="${parent.height}"
/>
</state>

<state name="stAudio" applied="${classroot.mediatype == 'audio'}">
<saraudiocontainer name="vwDisplay"
autoplay="${parent.autoplay}"
width="0"
height="0"
/>
</state>

<state name="stVideo" applied="${classroot.mediatype == 'video'}">
<sarvideocontainer name="vwDisplay"
use_videoview="${parent.use_videoview}"
autoplay="${parent.autoplay}"
width="${parent.width}"
height="${parent.height}"
/>
</state>

</class>



This is tested and works under OpenLaszlo 4.9.0 assuming you include the following library from the nightly build:

<include href="/usr/local/lps-5.0.x/Server/lps-5.0.x/lps/components/av/html5/library.lzx" />


I thought it might be useful to others.

Kevin