Wowza Community

file name control

I’m using Wowza 2.2.3 + patch 6 , I receive stream from Adobe Flash Media Live Encoder 3.2 (connected to Roku).

With Wowza IDE compile the following module:

package streamrecord.hourly.monthlyrollover;

import java.io.File;

import java.util.Calendar;

import java.util.Collections;

import java.util.Date;

import java.util.HashMap;

import java.util.Iterator;

import java.util.List;

import java.util.Map;

import java.util.TimeZone;

import com.wowza.wms.application.*;

import com.wowza.wms.module.*;

import com.wowza.wms.plugin.integration.liverecord.*;

import com.wowza.wms.stream.IMediaStream;

import com.wowza.wms.stream.IMediaStreamActionNotify;

import com.wowza.wms.stream.IMediaStreamNotify;

public class ModuleStreamRecord extends ModuleBase implements IMediaStreamNotify {

private IApplicationInstance appInstance;

private String timezone;

private StreamTimer streamTimer;

private int date;

private int startHour = 0;

private int endHour = 23;

private int hourOfDay = -1;

private PublishNotifier publishNotifier;

private List streams;

public static final int FORMAT_UNKNOWN = 0;

public static final int FORMAT_FLV = 1;

public static final int FORMAT_MP4 = 2;

private Map<String, ILiveStreamRecord> recorders = null;

private class StreamTimer extends Thread {

private boolean doQuit = false;

public synchronized void quit() {

doQuit = true;

}

public void run() {

while (true) {

try {

TimeZone tz = TimeZone.getTimeZone(timezone);

Calendar cal = Calendar.getInstance(tz);

date = cal.get(Calendar.DATE);

int prevHour = hourOfDay;

hourOfDay = cal.get(Calendar.HOUR_OF_DAY);

int start = startHour;

int end = endHour;

if (start > end && hourOfDay > start) {

end += 24;

}

if (end < start && hourOfDay < end) {

start -=24;

}

boolean record = false;

if (hourOfDay >= start && hourOfDay < end) {

record = true;

}

streams = appInstance.getMediaCasterStreams().getMediaCasterNames();

if (prevHour != hourOfDay && record) {

for (String streamName : streams) {

IMediaStream stream = appInstance.getStreams().getStream(streamName);

appInstance.getVHost().getHandlerThreadPool().execute(new DoStartRecording(stream, streamName));

}

} else if(!record) {

for (String streamName : streams) {

ILiveStreamRecord recorder = recorders.remove(streamName);

if(recorder != null)

recorder.stopRecording();

}

}

Thread.currentThread();

Thread.sleep(60000);

synchronized (this) {

if (doQuit) {

break;

}

}

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

public void onAppStart(IApplicationInstance appInstance) {

this.appInstance = appInstance;

WMSProperties props = appInstance.getProperties();

startHour = props.getPropertyInt(“startHour”, 0);

endHour = props.getPropertyInt(“endHour”, 24);

timezone = props.getPropertyStr(“timezone”, “America/Chicago”);

TimeZone tz = TimeZone.getTimeZone(timezone);

Calendar cal = Calendar.getInstance(tz);

hourOfDay = cal.get(Calendar.HOUR_OF_DAY);

appInstance.addMediaStreamListener(this);

recorders = Collections.synchronizedMap(new HashMap<String, ILiveStreamRecord>());

publishNotifier = new PublishNotifier();

streamTimer = new StreamTimer();

streamTimer.setName(“RecordController-” + appInstance.getApplication().getName());

streamTimer.setDaemon(true);

streamTimer.start();

}

public void onAppStop(IApplicationInstance appInstance) {

streamTimer.quit();

// cleanup any recorders that are still running

synchronized (recorders) {

Iterator iter = recorders.keySet().iterator();

while(iter.hasNext())

{

String streamName = iter.next();

ILiveStreamRecord recorder = recorders.get(streamName);

recorder.stopRecording();

getLogger().info(" stopRecording: "+streamName);

}

recorders.clear();

}

recorders = null;

appInstance.removeMediaStreamListener(this);

publishNotifier = null;

}

private synchronized void startRecording(IMediaStream stream) {

String streamAlias = stream.getName().substring(0, stream.getName().indexOf(".stream"));

if (!streamAlias.isEmpty()) {

String outputPath = appInstance.getStreamStorageDir()+"/"+String.format("%02d", date); //day;

boolean append = false;

File path = new File(outputPath);

if (path.exists()) {

File outputFile = new File(path.getPath()+File.separator+streamAlias+"_" +String.format("%02d", hourOfDay)+".mp4");

Date today = new Date();

if (!(outputFile.lastModified() < today.getTime() - 86400000)) {

append = true;

}

} else {

path.mkdirs();

}

recordStream(stream, FORMAT_MP4, append, outputPath+File.separator+streamAlias+"_"+String.format("%02d", hourOfDay)+".mp4", false, true, true);

}

}

private void recordStream(IMediaStream stream, int format, boolean append, String outputPath, boolean versionFile, boolean startOnKeyFrame, boolean recordData)

{

String streamName = stream.getName();

// if a format was not specified then check the stream prefix and choose accordingly

if (format == FORMAT_UNKNOWN)

{

format = FORMAT_FLV;

String extStr = stream.getExt();

if (extStr.equals(“mp4”))

format = FORMAT_MP4;

}

String params = “stream:”+streamName;

params += " format:"+(format==FORMAT_MP4?“mp4”:“flv”);

params += " append:"+append;

if (outputPath != null)

params += " outputPath:"+outputPath;

else

{

File writeFile = stream.getStreamFileForWrite();

params += " outputPath:"+writeFile.getAbsolutePath();

}

params += " versionFile:"+versionFile;

params += " startOnKeyFrame:"+startOnKeyFrame;

params += " recordData:"+recordData;

getLogger().info("ModuleStreamRecord.startRecordin g: "+params);

// create a stream recorder and save it in a map of recorders

ILiveStreamRecord recorder = null;

// create the correct recorder based on format

if (format == FORMAT_MP4)

recorder = new LiveStreamRecorderMP4();

else

recorder = new LiveStreamRecorderFLV();

// add it to the recorders list

ILiveStreamRecord prevRecorder = recorders.get(streamName);

if (prevRecorder != null)

prevRecorder.stopRecording();

recorders.put(streamName, recorder);

// if you want to record data packets as well as video/audio

recorder.setRecordData(recordData);

// Set to true if you want to version the previous file rather than overwrite it

recorder.setVersionFile(versionFile);

// If recording only audio set this to false so the recording starts immediately

recorder.setStartOnKeyFrame(startOnKeyFrame);

// start recording

recorder.startRecording(stream, outputPath, append);

}

@Override

public void onMediaStreamCreate(IMediaStream stream) {

stream.addClientListener(publishNotifier);

}

@Override

public void onMediaStreamDestroy(IMediaStream stream) {

stream.removeClientListener(publishNotifier);

if(!stream.isPlay()) {

ILiveStreamRecord recorder = recorders.remove(stream.getName());

if (recorder != null)

recorder.stopRecording();

}

}

private class PublishNotifier implements IMediaStreamActionNotify {

@Override

public void onPause(IMediaStream stream, boolean isPause,

double location) {

// TODO Auto-generated method stub

}

@Override

public void onPlay(IMediaStream stream, String streamName,

double playStart, double playLen, int playReset) {

// TODO Auto-generated method stub

}

@Override

public void onPublish(IMediaStream stream, String streamName,

boolean isRecord, boolean isAppend) {

// appInstance.getVHost().getHandlerThreadPool().exec ute(new DoStartRecording(stream, streamName));

}

@Override

public void onSeek(IMediaStream stream, double location) {

// TODO Auto-generated method stub

}

@Override

public void onStop(IMediaStream stream) {

// TODO Auto-generated method stub

}

@Override

public void onUnPublish(IMediaStream stream, String streamName,

boolean isRecord, boolean isAppend) {

ILiveStreamRecord recorder = recorders.remove(streamName);

if (recorder != null)

{

// stop recording

recorder.stopRecording();

}

}

}

private class DoStartRecording implements Runnable {

private IMediaStream stream;

private String streamName;

private DoStartRecording(IMediaStream stream, String streamName) {

this.stream = stream;

this.streamName = streamName;

}

public void run() {

List mediaCasters = appInstance.getMediaCasterStreams().getMediaCasterNames();

if (mediaCasters.contains(streamName)) {

int lockCount = appInstance.getMediaCasterStreams().getMediaCaster (streamName).getLockCount();

if (lockCount > 0)

startRecording(stream);

}

}

}

}

My configuration file Application.xml :

true

live

${com.wowza.wms.context.VHostConfigHome}/content

${com.wowza.wms.context.VHostConfigHome}/keys

cupertinostreamingpacketizer, smoothstreamingpacketizer, sanjosestreamingpacketizer

cupertinostreaming, smoothstreaming, sanjosestreaming

-1

*

*

*

*

digest

none

senderreport

12000

75

90000

0

0.0.0.0

127.0.0.1

*

base

Base

com.wowza.wms.module.ModuleCore

properties

Properties

com.wowza.wms.module.ModuleProperties

logging

Client Logging

com.wowza.wms.module.ModuleClientLogging

flvplayback

FLVPlayback

com.wowza.wms.module.ModuleFLVPlayback

ModuleMediaWriterFileMover

ModuleMediaWriterFileMover

com.wowza.wms.module.ModuleMediaWriterFileMover

ModuleStreamRecord

File Management

streamrecord.hourly.monthlyrollover.ModuleStreamRecord

fileMoverDestinationPath

/Wowfiles

fileMoverDeleteOriginal

true

Boolean

starHour

00

Integer

endHour

24

Integer

timezone

GMT-08:00

String

As far as I understand this module is to record the stream into separate files every hour, but this does not happen.

All is correct? Thanks in advance.

Wowza IDE gives:

C:\Program Files\Wowza Media Systems\Wowza Media Server 2.2.3\lib\ModuleStreamRecord.jar

BUILD SUCCESSFUL

In folder C:\Program Files\Wowza Media Systems\Wowza Media Server 2.2.3\lib\ appeared file ModuleStreamRecord.jar

Please help!

THX for Help Richard

Log from Wowza IDE:

Configure logging: file:///C:/Program Files/Wowza Media Systems/Wowza Media Server 2.2.3/conf/log4j.properties

INFO server server-start Wowza 2 Eval edition 15 March 2011 2.2.3.06 build27099 -

INFO server comment - Serial number: XXXXX-XXXXX-XXXXX-XXXXX-FQACS

INFO server comment - Maximum connections: Unlimited

INFO server comment - Hardware Available Processors: 2

INFO server comment - Hardware Physical Memory: 2043MB/2047MB

INFO server comment - Hardware Swap Space: 4095MB/4095MB

INFO server comment - Max File Descriptor Count: Unlimited

INFO server comment - OS Name: Windows 7

INFO server comment - OS Version: 6.1

INFO server comment - OS Architecture: x86

INFO server comment - OS CPU: pentium_pro+mmx pentium_pro pentium+mmx pentium i486 i386 i86

INFO server comment - Java Name: Java HotSpot™ Client VM

INFO server comment - Java Vendor: Sun Microsystems Inc.

INFO server comment - Java Version: 1.6.0_23

INFO server comment - Java VM Version: 19.0-b09

INFO server comment - Java Spec Version: 1.6

INFO server comment - Java Home: C:\Program Files\Java\jre6

INFO server comment - Java Max Heap Size: 742MB

INFO server comment - Java Architecture: 32

INFO server comment - Java Encoding[file.encoding]: Cp1251

INFO server comment - Java Args[0]: -Xmx768M

INFO server comment - Java Args[1]: -Dcom.wowza.wms.AppHome=C:/Program

INFO server comment - Java Args[2]: Files/Wowza

INFO server comment - Java Args[3]: Media

INFO server comment - Java Args[4]: Systems/Wowza

INFO server comment - Java Args[5]: Media

INFO server comment - Java Args[6]: Server

INFO server comment - Java Args[7]: 2.2.3

INFO server comment - Java Args[8]: -Dcom.wowza.wms.ConfigHome=C:/Program

INFO server comment - Java Args[9]: Files/Wowza

INFO server comment - Java Args[10]: Media

INFO server comment - Java Args[11]: Systems/Wowza

INFO server comment - Java Args[12]: Media

INFO server comment - Java Args[13]: Server

INFO server comment - Java Args[14]: 2.2.3

INFO server comment - Java Args[15]: -Dcom.sun.management.jmxremote=true

INFO server comment - Java Args[16]: -Dfile.encoding=Cp1251

INFO server comment - Java GC[0]: Copy

INFO server comment - Java GC[1]: MarkSweepCompact

INFO server comment - Server threads[h/t]: 10/10

INFO server comment - CMDInterface now listening: [any]:8083

INFO vhost vhost-start defaultVHost -

INFO server comment - defaultVHost threads[h/t]:120/80 home:C:/Program Files/Wowza Media Systems/Wowza Media Server 2.2.3

INFO vhost comment defaultVHost Bind attempt ([any]:1935:4)

INFO vhost comment defaultVHost Bind successful ([any]:1935)

INFO vhost comment defaultVHost Bind attempt ([any]:8086:1)

INFO vhost comment defaultVHost Bind successful ([any]:8086)

INFO server comment - Wowza Media Server is started!

INFO server comment - ModuleMediaWriterFileMover.onAppStart: live/definst

INFO application app-start definst live/definst

INFO session connect-pending 127.0.0.1 -

INFO session connect 127.0.0.1 -

INFO stream create - -

INFO stream publish livestream -

INFO server comment - LiveStreamPacketizerSanJose.init[live/definst/livestream]: chunkDurationTarget: 10000

INFO server comment - LiveStreamPacketizerSanJose.init[live/definst/livestream]: chunkDurationTolerance: 500

INFO server comment - LiveStreamPacketizerSanJose.init[live/definst/livestream]: playlistChunkCount:4

INFO server comment - MediaStreamMap.getLiveStreamPacketizer: Create live stream packetizer: sanjosestreamingpacketizer:livestream

INFO server comment - SanJosePacketHandler.startStream[live/definst/livestream]

INFO server comment - LiveStreamPacketizerSanJose.handlePacket: Video codec: H264

INFO server comment - LiveStreamPacketizerCupertino.init[live/definst/livestream]: chunkDurationTarget: 10000

INFO server comment - LiveStreamPacketizerCupertino.init[live/definst/livestream]: chunkDurationTolerance: 500

INFO server comment - LiveStreamPacketizerCupertino.init[live/definst/livestream]: audioGroupCount: 3

INFO server comment - LiveStreamPacketizerCupertino.init[live/definst/livestream]: playlistChunkCount:3

INFO server comment - MediaStreamMap.getLiveStreamPacketizer: Create live stream packetizer: cupertinostreamingpacketizer:livestream

INFO server comment - CupertinoPacketHandler.startStream[live/definst/livestream]

INFO server comment - LiveStreamPacketizerCupertino.handlePacket[live/definst/livestream]: Video codec:H264 isCompatible:true

INFO server comment - LiveStreamPacketizerCupertino.handlePacket[live/definst/livestream][avc1.66.31]: H.264 (Video may not be playable on older iPhone and iPod touch devices where Baseline/Level 3.0 or lower is required) Video info: {H264CodecConfigInfo: profile: “Baseline”, level: 3.1, frameSize: 320x240, displaySize: 320x240, PAR: 1:1, frameRate: 5.0}

INFO server comment - MediaStreamMap.getLiveStreamPacketizer: Create live stream packetizer: smoothstreamingpacketizer:livestream

INFO server comment - LiveStreamPacketizerSanJose.handlePacket: Audio codec: MP3

INFO server comment - LiveStreamPacketizerSmoothStreaming.startStream[live/definst/livestream]

INFO server comment - LiveStreamPacketizerCupertino.handlePacket[live/definst/livestream]: Audio codec:MP3 isCompatible:true

INFO server comment - LiveStreamPacketizerSmoothStreaming.handlePacket[live/definst/livestream]: Fragment durations: [1.2,0.8,0.8]

INFO server comment - LiveStreamPacketizerSmoothStreaming.flushPendingVideo: Bitrate[live/definst/livestream]: 860199

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:video id:0 count:25 duration:1285

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:video id:1 count:25 duration:834

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:video id:2 count:25 duration:834

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:video id:3 count:25 duration:835

INFO server comment - LiveStreamPacketizerSmoothStreaming.flushPendingAudio: Bitrate[live/definst/livestream]: 47745

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:audio id:0 count:77 duration:2012

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:video id:4 count:25 duration:834

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:video id:5 count:25 duration:834

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:video id:6 count:25 duration:834

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:audio id:1 count:77 duration:2013

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:video id:7 count:25 duration:834

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:video id:8 count:25 duration:835

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:audio id:2 count:77 duration:2013

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:video id:9 count:25 duration:834

INFO server comment - LiveStreamPacketizerSanJose.endChunkTS[live/definst/livestream]: Add chunk: id:1 a/v/k:401/301/12 duration:10461

INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[live/definst/livestream]: Add chunk: id:1 a/v/k:133/300/12 duration:10461

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:video id:10 count:25 duration:834

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:audio id:3 count:77 duration:2012

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:audio id:4 count:77 duration:2013

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:audio id:5 count:77 duration:2013

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:audio id:6 count:77 duration:2003

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:audio id:7 count:77 duration:2009

INFO server comment - LiveStreamPacketizerSanJose.endChunkTS[live/definst/livestream]: Add chunk: id:2 a/v/k:383/301/12 duration:10009

INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[live/definst/livestream]: Add chunk: id:2 a/v/k:128/300/12 duration:10009

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:audio id:8 count:77 duration:2013

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:audio id:9 count:77 duration:2013

INFO server comment - LiveStreamPacketizerSmoothStreaming.addFragment[live/definst/livestream]: Add chunk: type:audio id:10 count:77 duration:2013

INFO server comment - LiveStreamPacketizerSanJose.endChunkTS[live/definst/livestream]: Add chunk: id:3 a/v/k:373/293/12 duration:9744

INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[live/definst/livestream]: Add chunk: id:3 a/v/k:124/292/12 duration:9744

INFO server comment - LiveStreamPacketizerSanJose.endChunkTS[live/definst/livestream]: Add chunk: id:4 a/v/k:383/301/12 duration:10010

INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[live/definst/livestream]: Add chunk: id:4 a/v/k:128/300/12 duration:10010

INFO server comment - LiveStreamPacketizerSanJose.endChunkTS[live/definst/livestream]: Add chunk: id:5 a/v/k:384/301/12 duration:10010

INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[live/definst/livestream]: Add chunk: id:5 a/v/k:128/300/12 duration:10010

INFO server comment - LiveStreamPacketizerSanJose.endChunkTS[live/definst/livestream]: Add chunk: id:6 a/v/k:382/301/12 duration:10010

INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[live/definst/livestream]: Add chunk: id:6 a/v/k:127/300/12 duration:10010

INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[live/definst/livestream]: Add chunk: id:7 a/v/k:128/300/12 duration:10009

INFO server comment - LiveStreamPacketizerSanJose.endChunkTS[live/definst/livestream]: Add chunk: id:7 a/v/k:384/301/12 duration:10009

INFO server comment - LiveStreamPacketizerSanJose.endChunkTS[live/definst/livestream]: Add chunk: id:8 a/v/k:384/301/12 duration:10044

INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[live/definst/livestream]: Add chunk: id:8 a/v/k:128/300/12 duration:10044

INFO server comment - LiveStreamPacketizerSanJose.endChunkTS[live/definst/livestream]: Add chunk: id:9 a/v/k:383/301/12 duration:10009

INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[live/definst/livestream]: Add chunk: id:9 a/v/k:128/300/12 duration:10009

INFO server comment - LiveStreamPacketizerSanJose.endChunkTS[live/definst/livestream]: Add chunk: id:10 a/v/k:383/301/12 duration:10011

INFO server comment - LiveStreamPacketizerCupertino.endChunkTS[live/definst/livestream]: Add chunk: id:10 a/v/k:128/300/12 duration:10011

Hi dynamic,

This thread has a few hints about your topic: RTMP stream alive check

Take a look at post #10 in this thread: http://www.wowza.com/forums/showthread.php?15035-Recording-Instance

Hello,

What button I need to click on Wowza IDE to compile a .jar file? I copied the code but I do not know how to generate the .jar file.

Hi randall,

Thank you a lot.