流媒体技术世界——分享技术,增值服务
如何在采用RTMP协议播放视频时插入一段段视频?
本文的例子展示了在采用RTMP协议播放时,如何动态的插入一个短视频或服务端的播放列表。在这个例子中,被请求的视频流会被分成两个部分,中间会插入一个短视频。

目前,这个方案只针对使用Flash客户端的RTMP协议播放,现在还没有针对非Flash客户端的类似方案。此外还有一个采用Apple Http Live Streaming播放的客户端侧方案,详见这里,但是它无法做到平滑切换。在Silverlight客户端也是同样的情况。现在也还没有针对RTSP的方案。

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.

		}
}
www.ttstream.com
将这个Module添加到/conf/[app-name]/Application.xml 的模块列表中。将它放在最下面,作为最后一个模块。

Code:
<Module>
	<Name>ModuleInsertMidRoll</Name>
	<Description>ModuleInsertMidRoll</Description>
	<Class>com.wowza.wms.example.ModuleInsertMidRoll</Class>
</Module>
在Application.xml /Properties 中添加下面的参数:

<Property>
<Name>MidRoll</Name>
<Value>mp4:sample.mp4</Value>
</Property>

<Property>
<Name>FeatureBreak</Name>
<Value>10000</Value>
<Type>Integer</Type>
</Property>

要向Flash客户端提供重新计算后的播放时长,你要创建MediaReaderMP4InjectMetadata Java类,然后修改/conf/MediaReaders.xml 中的配置:
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;
	}
}
要调用这个Java类,你要编辑[install-dir]/conf/MediaReaders.xml 文件,修改针对mp4文件的读取类:
Code:
from:
<ClassBase>com.wowza.wms.mediareader.h264.MediaReaderH264</ClassBase>
To:
<ClassBase>com.wowza.wms.mediareader.MediaReaderMP4InjectMetadata</ClassBase>
匿名用户
评论

我们的地址


北京市朝阳区管庄西里建基商务楼423室


邮编:100024

关于我们


北京联方信科信息技术有限责任公司


官网:www.ttstream.com

联系我们


王经理:phone


柳经理:phone

京ICP备14033868号-2