This requires Flash client. There is not an equivalent for non-Flash clients at present. There is a client-side work-around for iOS here, but it will not have seamless playback. Similar is possible in a Silverlight client. There is no RTSP work-around.
Code:
package com.wowza.wms.example;
import com.wowza.wms.module.*;
import com.wowza.wms.amf.*;
import com.wowza.wms.client.*;
import com.wowza.wms.request.*;
import com.wowza.wms.stream.IMediaStream;
import com.wowza.wms.util.StreamUtils;
import com.wowza.wms.logging.WMSLogger;
import com.wowza.wms.logging.WMSLoggerFactory;
public class ModuleInsertMidRoll extends ModuleBase {
public void play(IClient client, RequestFunction function,
AMFDataList params) {
String streamName = params.getString(PARAM1);
IMediaStream stream =getStream(client, function);
String midRoll = client.getAppInstance().getProperties().getPropertyStr("MidRoll");
Integer featureBreak = client.getAppInstance().getProperties().getPropertyInt("FeatureBreak", 10000);
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 value in milliseconds
customDataList.add(new AMFDataItem(featureBreak)); //duration (-1 means play to the end). Value in milliseconds.
customDataList.add(new AMFDataItem(true)); //reset
invokePrevious(this, client, function, customDataList);
//Midroll
customDataList.set(PARAM1, new AMFDataItem(midRoll));
customDataList.set(PARAM2, new AMFDataItem(0)); // start
customDataList.set(PARAM3, new AMFDataItem(-1)); // duration
customDataList.set(PARAM4, new AMFDataItem(false));
invokePrevious(this, client, function, customDataList);
// Feature continued
customDataList.set(PARAM1, new AMFDataItem(streamName));
customDataList.set(PARAM2, new AMFDataItem(featureBreak)); // start
customDataList.set(PARAM3, new AMFDataItem(-1)); // duration
customDataList.set(PARAM4, new AMFDataItem(false));
invokePrevious(this, client, function, customDataList);
// To send the Flash client the correct duration you must calculate total duration and inject into the metadata.
// In this example we can calculate total duration by adding the duration of feature and midroll.
// If you use start property > then 0 and/or duration property other than -1 in any item,
// you would have to adjust to get actual totalDuration for the playlist
double overrideDuration = StreamUtils.getStreamLength(client.getAppInstance(), streamName);
overrideDuration += StreamUtils.getStreamLength(client.getAppInstance(), midRoll);
//Store the calculated duration in a property of the stream to be extracted by the MediaReaderMP4InjectMetadata shown below.
stream.getProperties().put("overrideDuration", overrideDuration); // Value in seconds.
}
}
Code:
<Module> <Name>ModuleInsertMidRoll</Name> <Description>ModuleInsertMidRoll</Description> <Class>com.wowza.wms.example.ModuleInsertMidRoll</Class> </Module>
<Property>
<Name>MidRoll</Name>
<Value>mp4:sample.mp4</Value>
</Property>
<Property>
<Name>FeatureBreak</Name>
<Value>10000</Value>
<Type>Integer</Type>
</Property>
<Name>MidRoll</Name>
<Value>mp4:sample.mp4</Value>
</Property>
<Property>
<Name>FeatureBreak</Name>
<Value>10000</Value>
<Type>Integer</Type>
</Property>
To send the calculated duration from playlist above to the Flash client, create this MediaReaderMP4InjectMetadata Class, then modify /conf/MediaReaders.xml as shown
Code:
package com.wowza.wms.mediareader;
import java.nio.ByteBuffer;
import java.util.List;
import com.wowza.wms.mediareader.h264.MediaReaderH264;
import com.wowza.wms.amf.AMFDataItem;
import com.wowza.wms.amf.AMFDataList;
import com.wowza.wms.amf.AMFDataMixedArray;
import com.wowza.wms.logging.WMSLogger;
import com.wowza.wms.logging.WMSLoggerFactory;
public class MediaReaderMP4InjectMetadata extends MediaReaderH264
{
public List<ByteBuffer> getMetadata()
{
List<ByteBuffer> ret = super.getMetadata();
WMSLogger getLogger = WMSLoggerFactory.getLogger(null);
// Here the calculated duration stored by above is extracted.
// Note that the default duration is used if there is no duration property in the stream, so simple video streaming will work as usual
double overrideDuration = this.stream.getProperties().getPropertyDouble("overrideDuration", (double) this.duration / 1000); // Value in seconds.
getLogger.info("overrideDuration: " + duration);
while(true)
{
if (ret == null)
break;
if (ret.size() <= 0)
break;
ByteBuffer packet = ret.get(0);
AMFDataList myMetadata = new AMFDataList(packet);
AMFDataMixedArray dataObj = (AMFDataMixedArray)myMetadata.get(1);
dataObj.put("duration", new AMFDataItem(overrideDuration)); // duration in seconds.
byte[] data = myMetadata.serialize();
ByteBuffer newPacket = ByteBuffer.wrap(data);
ret.set(0, newPacket);
break;
}
return ret;
}
}
Code:
from: <ClassBase>com.wowza.wms.mediareader.h264.MediaReaderH264</ClassBase> To: <ClassBase>com.wowza.wms.mediareader.MediaReaderMP4InjectMetadata</ClassBase>
- Click here, if you are having problems or would like to discuss this article.
- Leave a comment below, if there is some aspect of this article you would like to see changed or improved.


Article List
Categories
Wowza Media