如何自动对直播流进行录制?
转载请注明:文章来自www.wowza.cn
注意: 要访问最新的技术资料,请访问http://www.ttstream.com/wowza/
你可以用LiveStreamRecordAPI和IMediaStreamActionNotify3接口写一个自定义的模块对一个直播流自动录制,当直播流进入wowza Stream Engine 4时自动录制,当直播流停止时自动停止录制。

注意: 适用Wowza Media Server® 3.5.0及更高版本。

关于LiveStreamRecordAutoRecord 例子代码


LiveStreamRecordAutoRecord 例子代码使用了startRecordSegmentByDuration API按每隔60分钟的播放时长自动对直播流进行分割。下面的代码录制了一个应用的每一个直播流。
Code:
package com.wowza.wms.example.module;

import java.util.HashMap;
import java.util.Map;

import com.wowza.wms.livestreamrecord.model.ILiveStreamRecord;
import com.wowza.wms.livestreamrecord.model.LiveStreamRecorderMP4;
import com.wowza.wms.media.model.MediaCodecInfoAudio;
import com.wowza.wms.media.model.MediaCodecInfoVideo;
import com.wowza.wms.module.*;
import com.wowza.wms.stream.*;
import com.wowza.wms.amf.AMFPacket;
import com.wowza.wms.application.IApplicationInstance;
import com.wowza.wms.application.WMSProperties;

public class ModuleLiveStreamRecordAutoRecord extends ModuleBase implements IModuleOnStream
{
	private Map<String, ILiveStreamRecord> recorders = new HashMap<String, ILiveStreamRecord>();
	private IApplicationInstance appInstance;
	
	
	public void onAppStart(IApplicationInstance appInstance)
	{
     	this.appInstance = appInstance;
	}
	
	class StreamListener implements IMediaStreamActionNotify3
	{
		public void onMetaData(IMediaStream stream, AMFPacket metaDataPacket)
		{
			System.out.println("onMetaData[" + stream.getContextStr() + "]: " + metaDataPacket.toString());
		}

		public void onPauseRaw(IMediaStream stream, boolean isPause, double location)
		{
			System.out.println("onPauseRaw[" + stream.getContextStr() + "]: isPause:" + isPause + " location:" + location);
		}

		public void onPause(IMediaStream stream, boolean isPause, double location)
		{
			System.out.println("onPause[" + stream.getContextStr() + "]: isPause:" + isPause + " location:" + location);
		}

		public void onPlay(IMediaStream stream, String streamName, double playStart, double playLen, int playReset)
		{
			System.out.println("onPlay[" + stream.getContextStr() + "]: playStart:" + playStart + " playLen:" + playLen + " playReset:" + playReset);
		}

		public void onPublish(IMediaStream stream, String streamName, boolean isRecord, boolean isAppend)
		{
			System.out.println("onPublish[" + stream.getContextStr() + "]: streamName:" + streamName + " isRecord:" + isRecord + " isAppend:" + isAppend);
			//create a livestreamrecorder instance to create .mp4 files
			ILiveStreamRecord recorder = new LiveStreamRecorderMP4();
		    recorder.init(appInstance);
		    recorder.setRecordData(true);
		    recorder.setStartOnKeyFrame(true);
		    recorder.setVersionFile(true);
		       
			// add it to the recorders list
			synchronized (recorders)
			{
				ILiveStreamRecord prevRecorder = recorders.get(streamName);
				if (prevRecorder != null)
					prevRecorder.stopRecording();
				recorders.put(streamName, recorder);
			}
			// start recording, create 1 minute segments using default content path
			System.out.println("--- startRecordingSegmentByDuration for 60 minutes");
			recorder.startRecordingSegmentByDuration(stream, null, null, 60*60*1000);
			// start recording, create 1MB segments using default content path
			//System.out.println("--- startRecordingSegmentBySize for 1MB");
			//recorder.startRecordingSegmentBySize(stream, null, null, 1024*1024);
			// start recording, create new segment at 1:00am each day.
			//System.out.println("--- startRecordingSegmentBySchedule every "0 1 * * * *");
			//recorder.startRecordingSegmentBySchedule(stream, null, null, "0 1 * * * *");
			
		    // start recording, using the default content path, do not append (i.e. overwrite if file exists)
			//System.out.println("--- startRecording");
		    //recorder.startRecording(stream, false);
		    
		    // log where the recording is being written
			System.out.println("onPublish[" + stream.getContextStr() + "]: new Recording started:" + recorder.getFilePath());
		}
        
		public void onUnPublish(IMediaStream stream, String streamName, boolean isRecord, boolean isAppend)
		{
			System.out.println("onUnPublish[" + stream.getContextStr() + "]: streamName:" + streamName + " isRecord:" + isRecord + " isAppend:" + isAppend);
			
			ILiveStreamRecord recorder = null;
			synchronized (recorders)
			{
				recorder = recorders.remove(streamName);
			}
			
			if (recorder != null)
			{
				// grab the current path to the recorded file
				String filepath = recorder.getFilePath();
				
				// stop recording
				recorder.stopRecording();
				System.out.println("onUnPublish[" + stream.getContextStr() + "]: File Closed:" + filepath);
			}
			else
			{
				System.out.println("onUnPublish[" + stream.getContextStr() + "]: streamName:" + streamName + " stream recorder not found");
			}
		}
		
		public void onSeek(IMediaStream stream, double location)
		{
			System.out.println("onSeek[" + stream.getContextStr() + "]: location:" + location);
		}

		public void onStop(IMediaStream stream)
		{
			System.out.println("onStop[" + stream.getContextStr() + "]: ");
		}

		public void onCodecInfoAudio(IMediaStream stream,MediaCodecInfoAudio codecInfoAudio) {
			System.out.println("onCodecInfoAudio[" + stream.getContextStr() + " Audio Codec" + codecInfoAudio.toCodecsStr() + "]: ");
		}

		public void onCodecInfoVideo(IMediaStream stream,MediaCodecInfoVideo codecInfoVideo) {
			System.out.println("onCodecInfoVideo[" + stream.getContextStr() + " Video Codec" + codecInfoVideo.toCodecsStr() + "]: ");
		}
	}

	public void onStreamCreate(IMediaStream stream)
	{
		getLogger().info("onStreamCreate["+stream+"]: clientId:" + stream.getClientId());
		IMediaStreamActionNotify3 actionNotify = new StreamListener();

		WMSProperties props = stream.getProperties();
		synchronized (props)
		{
			props.put("streamActionNotifier", actionNotify);
		}
		stream.addClientListener(actionNotify);
	}

	public void onStreamDestroy(IMediaStream stream)
	{
		getLogger().info("onStreamDestroy["+stream+"]: clientId:" + stream.getClientId());

		IMediaStreamActionNotify3 actionNotify = null;
		WMSProperties props = stream.getProperties();
		synchronized (props)
		{
			actionNotify = (IMediaStreamActionNotify3) stream.getProperties().get("streamActionNotifier");
		}
		if (actionNotify != null)
		{
			stream.removeClientListener(actionNotify);
			getLogger().info("removeClientListener: " + stream.getSrc());
		}
	}
}
注意: When using this module, streams must have a unique name within the application. If a duplicate stream name is used, the existing recording associated with the current stream name will be stopped and a new recording will be started for the duplicate stream name.

为 "live"应用配置LiveStreamRecordAutoRecord模块


安装和配置module

  1. Compile the above code and then copy the .jar file to the [install-dir]/lib/ folder.
  2. Create an application folder named [install-dir]/applications/live.
  3. Create a configuration folder [install-dir]/conf/live and copy [install-dir]/conf/Application.xml to this new folder.
  4. Open [install-dir]/conf/live/Application.xml in a text editor then
    • change /Streams /StreamType to "live"
    • add the following module definition as the last entry in the <Modules> list:
      Code:
      <Module>
           <Name>ModuleLiveStreamRecordAutoRecord</Name>
           <Description>ModuleLiveStreamRecordAutoRecord</Description>
           <Class>com.wowza.wms.example.module.ModuleLiveStreamRecordAutoRecord</Class>
      </Module>
      www.wowza.cn
  5. 如果Wowza服务器正在运行,请重启Wowza
  6. 发布到live应用的直播流将被自动录制在[install-dir]/content目录下