Override play insert Midroll

https://www.wowza.com/docs/how-to-insert-a-pre-roll-or-mid-roll-for-video-on-demand-playback-in-flash-rtmp-client

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

I tested and updated that post:

http://community.wowza.com/t/-/241&page=2#19

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