使用这个模块可以动态的调整每一个RTSP直播流的RTP/AVSyncMethod(例如一个从IP摄像头或mpeg-ts编码器输出的流)。
只要你设置一个文本文件来记录每一个RTSP流和它们希望的音视频同步方式,当这个流输入到Wowza时,这个模块就会解析这个文件。
下面的代码,你无需修改就可以直接编译使用,或者你可以根据你的需求修改它。
下面是这个Module的完整的代码示例:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import com.wowza.wms.amf.*;
import com.wowza.wms.bootstrap.Bootstrap;
import com.wowza.wms.logging.WMSLoggerFactory;
import com.wowza.wms.module.*;
import com.wowza.wms.stream.*;
import com.wowza.wms.media.model.*;
import com.wowza.wms.rtp.model.*;
public class ModuleIPCameraDynamicallySetAVSync extends ModuleBase {
private String logPrefix = "ModuleIPCameraDynamicallySetAVSync::";
class StreamListener implements IMediaStreamActionNotify3 {
private String logPrefix = "ModuleIPCameraDynamicallySetAVSync::StreamListener::";
public void onMetaData(IMediaStream stream, AMFPacket metaDataPacket) {
}
public void onPauseRaw(IMediaStream stream, boolean isPause,
double location) {
}
public void onPause(IMediaStream stream, boolean isPause,
double location) {
}
public void onPlay(IMediaStream stream, String streamName,
double playStart, double playLen, int playReset) {
}
private int getAvsyncMethodPropertyInt(String name){
if(name.toLowerCase().equalsIgnoreCase("rtptimecode")){
return RTPStream.AVSYNCMETHODS_RTPTIMECODE;
}
else if(name.toLowerCase().equalsIgnoreCase("sendreport")){
return RTPStream.AVSYNCMETHODS_SENDERREPORT;
}
else if(name.toLowerCase().equalsIgnoreCase("systemclock")){
return RTPStream.AVSYNCMETHODS_SYSTEMCLOCK;
}
return RTPStream.AVSYNCMETHODS_UNKNOWN;
}
private int getAvsyncStreamMethod(String filePath, String streamName) {
ArrayList<String> mediaCacheFiles = new ArrayList<String>();
try {
FileInputStream in = new FileInputStream(filePath);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String item = "";
while ((item = br.readLine()) != null) {
item = item.trim();
if (!item.startsWith("#") && item.length() > 0) {
String[] parts = item.split(" ");
if(parts.length==2){
String fileStreamName = parts[0].trim();
String fileSyncMethod = parts[1].trim();
if(fileStreamName.equals(streamName)){
return this.getAvsyncMethodPropertyInt(fileSyncMethod);
}
}
}
}
} catch (Exception e) {
WMSLoggerFactory.getLogger(null).info(
this.logPrefix + "getAvsyncStreamMethod::" + e.getMessage());
}
return -1;
}
public void onPublish(IMediaStream stream, String streamName,
boolean isRecord, boolean isAppend) {
String avSyncTxtFilePath = Bootstrap
.getServerHome(Bootstrap.CONFIGHOME)
+ "/conf/avsyncstreams.txt";
getLogger().info(
this.logPrefix+"#onPublish["
+ stream.getContextStr() + "]: " + streamName+" :: "+avSyncTxtFilePath);
int method = this.getAvsyncStreamMethod(avSyncTxtFilePath, streamName);
if(method>=0){
RTPStream rtpStream = stream.getRTPStream();
if (rtpStream != null){
getLogger().info(
this.logPrefix+"#onPublish["
+ stream.getContextStr() + "]: " + streamName +" set Avsync Method to "+method);
rtpStream.setAVSyncMethod(method);
}
else{
getLogger().info(
this.logPrefix+"#onPublish["
+ stream.getContextStr() + "]: " + streamName +" is not RTPStream");
}
}
else{
getLogger().info(
this.logPrefix+"#onPublish["
+ stream.getContextStr() + "]: " + streamName+" is not a valid stream");
}
}
public void onSeek(IMediaStream stream, double location) {
}
public void onStop(IMediaStream stream) {
}
public void onUnPublish(IMediaStream stream, String streamName,
boolean isRecord, boolean isAppend) {
}
public void onCodecInfoVideo(IMediaStream stream,
MediaCodecInfoVideo codecInfoVideo) {
}
public void onCodecInfoAudio(IMediaStream stream,
MediaCodecInfoAudio codecInfoAudio) {
}
}
public void onStreamCreate(IMediaStream stream) {
IMediaStreamActionNotify2 actionNotify = new StreamListener();
stream.addClientListener(actionNotify);
}
}
在上面的publish事件中,这个代码尝试用/conf目录下的avsyncstreams.txt文件来匹配一个输入流。如果匹配到了,就会接着去找到对应的音视频同步的参数,然后将其设置到setAVSyncmethod方法中。
可以使用以下几种音视频同步方式:
- senderreport – 使用Real Time Transport Control Protocol (RTCP)协议的Sender Report (SR) 数据包。这是默认的方式。
- rtptimecode – 假定RTP timecodes 是绝对的时间戳
- systemclock – 用系统时钟来进行同步。
配置
- 使用Wowza IDE编译这个模块的源代码(Module 部分)
- 将下面的Module添加到你的[install-dir]/conf/[application]/Application.xml文件的Root/Application/Modules 部分:
<Module> <Name>ModuleIPCameraDynamicallySetAVSync</Name> <Description>ModuleIPCameraDynamicallySetAVSync</Description> <Class>com.wowza.wms.plugin.test.module.ModuleIPCameraDynamicallySetAVSync</Class> </Module> - 在[install-dir]/conf目录下添加avsyncstreams.txt文件
- 按下面的格式添加流的名字和对应的音视频同步方式:
#StreamName[space]AVSyncMethod #camera.stream syncmethod cam1.stream sendreport
