rrlanham,
I am trying to compile this using the Wowza IDE- 1.0. Beta2 but am getting this error “The public type ModuleInsertMidRoll must be defined in its own file”.
Thanks.
The name of the file has to be same as the class name.
ModuleInsertMidRoll.java
Richard
I’ll test it again in a little while, am in the middle of moving right now.
Richard
NetStream.send in AS3 is something like this:
Publishing client:
netstream.send("switchMovie");
Subscribing client:
var netstream:NetStream
var clientObj:Object
clientObj.switchMovie = function():void
{
trace("switch");
};
netstream.client = clientObject;
Richard
Thomas,
This line is not right:
custom_data_list.add("mp4:/uploads/medias/advert.mp4");
Take out the slash:
custom_data_list.add("mp4:uploads/medias/advert.mp4");
Richard
Look at the metadata handler in the other thread we got going. you should be able to figure out something in the player with the info you get in the metadata when a new item plays.
Richard
Thomas,
Yes, I do have problems with it too. I’ll have to get back to you on that.
Richard
oh, jeeze, right, sorry. yea, I do feel stupid about that…it’s come up before, am now remembering.
I do have a solution for total duration, hold on, let me dig that out.
Richard
Well, what I dug out was a total duration solution for the client-side version of a server-side playlist, which used a version of the calculateBitRate example to get the duration of each clip. But I put together a version that should work with the InsertMidRoll example. This is that example with a getDuration function that is run for each video unless the length param is set (when only a portion of the video is played) in which case you don’t want to know what the duration of the whole video is (which is another problem with getting total duration in a server-side playlist, so this solves two problems)
package com.wowza.forum;
import com.wowza.wms.module.*;
import com.wowza.wms.amf.*;
import com.wowza.wms.application.IApplicationInstance;
import com.wowza.wms.application.WMSProperties;
import com.wowza.wms.client.*;
import com.wowza.wms.request.*;
import com.wowza.wms.stream.IMediaReader;
import com.wowza.wms.stream.IMediaStream;
import com.wowza.wms.stream.MediaReaderFactory;
import com.wowza.wms.stream.MediaStream;
import com.wowza.wms.stream.MediaStreamDisconnected;
import com.wowza.wms.stream.MediaStreamMap;
import com.wowza.wms.util.ModuleUtils;
public class ModuleInsertMidRoll extends ModuleBase {
public void play(IClient client, RequestFunction function,
AMFDataList params) {
String streamName = params.getString(PARAM1);
Integer duration = 0;
String midRoll = client.getAppInstance().getProperties().getPropertyStr("MidRoll");
Integer featureBreak = client.getAppInstance().getProperties().getPropertyInt("FeatureBreak", 10);
getLogger().info("Insert Midroll for: " + streamName);
//Feature start
AMFDataList customDataList = new AMFDataList();
customDataList.add("play");
customDataList.add(0.0);
customDataList.add("null");
customDataList.add(streamName);
customDataList.add(new AMFDataItem(0)); // start
customDataList.add(new AMFDataItem(featureBreak)); //duration
customDataList.add(new AMFDataItem(true)); //reset
invokePrevious(this, client, function, customDataList);
/// for each clip add the video duration with getDuration or Use clip duration instead of full video duration if > -1
// in this case use the clip duration.
duration = featureBreak;
//Midroll
customDataList.set(PARAM1, new AMFDataItem(midRoll));
customDataList.set(PARAM2, new AMFDataItem(0));
customDataList.set(PARAM3, new AMFDataItem(-1));
customDataList.set(PARAM4, new AMFDataItem(false));
duration += getDuration(client, midRoll);
invokePrevious(this, client, function, customDataList);
// Feature continued
customDataList.set(PARAM1, new AMFDataItem(streamName));
customDataList.set(PARAM2, new AMFDataItem(featureBreak));
customDataList.set(PARAM3, new AMFDataItem(-1));
customDataList.set(PARAM4, new AMFDataItem(false));
invokePrevious(this, client, function, customDataList);
duration += getDuration(client, streamName) - featureBreak;
client.call("setDuration", null, duration); // you have to setup the client to process this, see below.
getLogger().info("total duration: " + duration);
}
public Integer getDuration(IClient client, String streamName)
{
String streamExt = MediaStream.BASE_STREAM_EXT;
String queryStr = "";
String[] streamDecode = ModuleUtils.decodeStreamExtension(streamName, streamExt);
streamName = streamDecode[0];
streamExt = streamDecode[1];
int duration = 0;
boolean isStreamNameURL = streamName.indexOf("://") >= 0;
int streamQueryIdx = streamName.indexOf("?");
if (!isStreamNameURL && streamQueryIdx >= 0)
{
queryStr = streamName.substring(streamQueryIdx+1);
streamName = streamName.substring(0, streamQueryIdx);
}
IApplicationInstance appInstance = client.getAppInstance();
IMediaReader mediaReader = MediaReaderFactory.getInstance(appInstance, client.getVHost().getMediaReaders(), streamExt);
if (mediaReader != null)
{
MediaStreamMap streams = appInstance.getStreams();
IMediaStream stream = new MediaStreamDisconnected();
stream.init(streams, 0, new WMSProperties());
stream.setName(streamName, streamExt, stream.getExt(), queryStr, 0, -1, -1);
String basePath = client.getAppInstance().getStreamStoragePath();
mediaReader.init(client.getAppInstance(), stream, streamExt, basePath, streamName);
duration = (int)mediaReader.getDuration();
getLogger().info(streamName + " duration: " + duration);
mediaReader.close();
}
else
getLogger().warn("Could not create MediaReader for stream: "+streamName);
return duration;
}
}
Client-side, you catch this with callback on the NetConnection (not NetStream).
var clientObj:Object = new Object();
clientObj.setDuration = function(duration:String):void
{
trace("totalDuration: " + duration);
// set the scrubber to duration
};
netconnection.client = clientObj;
netconnection.connect("rtmp://ip/app");
Richard
There is another case: where length param = -1, and start param > 0. So duration of that clip is getDuration - start
Richard
Merry Christmas, happy New Year!
Richard
What do you mean, “showing as roll over ads”?
Richard
Using this module, when the client plays a stream, for example:
netstream.play(“FeatureVideo.flv”);
… this module overrides the play command, lets the video the client requested (FeatureVideo.flv) play for a so many seconds (FeatureBreak), then plays the MidRoll (Extremists.flv in the example), then starts playing the first video again starting where it stopped, at FeatureBreak.
So it’s all server-side, the video the client requested comes back with another video inserted.
Richard
Right, this is for video on demand application.
You can manipulate the Stream class streams created with that scheduler to insert clips into those “live” streams, using this Stream controller example:
https://www.wowza.com/forums/showthread.php?p=32659
Richard
You can do that with just the scheduler. The controller is for manipulating the running streams on the fly. If you know exactly what you want to happen you can do it all with the scheduler.
You are doing it about right, except you want to set start and length correctly. You want to stop the first video at a midpoint when it first plays, and have it start where it stopped after the midroll. Something like this:
<playlist name="pl2" playOnStream="Stream2" repeat="true" scheduled="2010-01-07 17:40:00">
<video src="mp4:VTS_01_11.m4v" start="30" length="20"/>
<video src="mp4:MidRolladvert.m4v" start="0" length="-1"/>
<video src="mp4:VTS_01_11.m4v" start="50" length="-1"/>
</playlist>
When the feature part plays the 2nd time it starts at 50, because the first time it started at 30 and played for 20 seconds, so it stopped at 50 and that’s where it should start after the midroll.
Richard
No, you’re right, this doesn’t work with cupertino streaming.
Richard
Updated post for calculated duration.
Richard
I see what you mean. I added this import and IMediaStream reference in the play command to ModuleInsertMidRoll
import com.wowza.wms.stream.IMediaStream;
...
IMediaStream stream =getStream(client, function);
Thanks,
Richard