下面的Wowza扩展模块会为HLS切片列表中增加EXT-X-PROGRAM-DATE-TIME 标签。流的第一个切片将作为检索和显示后续切片的基础。
要在HLS切片列表中增加EXT-X-PROGRAM-DATE-TIME标签,你需要为Wowza应用添加cupertinoEnableProgramDateTime属性,并将它设置为true。
注意: 针对Wowza Streaming Engine™ 4.5.0 及以上版本。
package com.wowza.wms.plugin.test2.hlsprogramdatetime; import java.util.*; import org.apache.commons.lang.time.*; import com.wowza.util.*; import com.wowza.wms.amf.*; import com.wowza.wms.application.*; import com.wowza.wms.httpstreamer.cupertinostreaming.livestreampacketizer.*; import com.wowza.wms.media.mp3.model.idtags.*; import com.wowza.wms.module.*; import com.wowza.wms.stream.*; import com.wowza.wms.stream.livepacketizer.*; public class ModuleCupertinoProgramDateTime extends ModuleBase { private static final Class<ModuleCupertinoProgramDateTime> CLASS = ModuleCupertinoProgramDateTime.class; private static final String CLASSNAME = "ModuleCupertinoProgramDateTime"; public static final String PROPNAME_TRACKER = "ModuleCupertinoProgramDateTime.ProgramDateTimeTracker"; public static final String DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'+00:00'"; // The date/time representation is ISO/IEC 8601:2004 - 2010-02-19T14:54:23.031+08:00 private FastDateFormat fastDateFormat = FastDateFormat.getInstance(DATEFORMAT, SystemUtils.gmtTimeZone, Locale.US); //you can change it to Locale.CN private IApplicationInstance appInstance = null; class ProgramDateTimeTracker { long timeOffset = 0; IMediaStream stream = null; public ProgramDateTimeTracker(IMediaStream stream) { this.stream = stream; } } class LiveStreamPacketizerDataHandler implements IHTTPStreamerCupertinoLivePacketizerDataHandler2 { private LiveStreamPacketizerCupertino liveStreamPacketizer = null; private int textId = 1; private String streamName = null; public LiveStreamPacketizerDataHandler(LiveStreamPacketizerCupertino liveStreamPacketizer, String streamName) { this.liveStreamPacketizer = liveStreamPacketizer; this.streamName = streamName; } public ProgramDateTimeTracker getTracker() { ProgramDateTimeTracker tracker = null; while(true) { IMediaStream stream = appInstance.getStreams().getStream(this.streamName); if (stream == null) break; WMSProperties props = stream.getProperties(); synchronized(props) { tracker = (ProgramDateTimeTracker)props.getProperty(PROPNAME_TRACKER); if (tracker == null) { tracker = new ProgramDateTimeTracker(stream); props.put(PROPNAME_TRACKER, tracker); } } break; } return tracker; } @Override public void onFillChunkStart(LiveStreamPacketizerCupertinoChunk chunk) { ProgramDateTimeTracker tracker = getTracker(); if (tracker != null) { ElapsedTimer elapsedTime = tracker.stream.getElapsedTime(); long createTime = elapsedTime.getDate().getTime()+tracker.timeOffset; String programDateTimeStr = fastDateFormat.format(new Date(createTime)); chunk.setProgramDateTime(programDateTimeStr); ID3Frames id3Header = liveStreamPacketizer.getID3FramesHeader(chunk.getRendition()); if (id3Header != null) { ID3V2FrameTextInformationUserDefined comment = new ID3V2FrameTextInformationUserDefined(); comment.setDescription("programDateTime"); comment.setValue(programDateTimeStr); id3Header.clear(); id3Header.putFrame(comment); } } } @Override public void onFillChunkEnd(LiveStreamPacketizerCupertinoChunk chunk, long timecode) { ProgramDateTimeTracker tracker = getTracker(); if (tracker != null) tracker.timeOffset += chunk.getDuration(); } @Override public void onFillChunkDataPacket(LiveStreamPacketizerCupertinoChunk chunk, CupertinoPacketHolder holder, AMFPacket packet, ID3Frames id3Frames) { } @Override public void onFillChunkMediaPacket(LiveStreamPacketizerCupertinoChunk chunk, CupertinoPacketHolder holder, AMFPacket packet) { } } class LiveStreamPacketizerListener extends LiveStreamPacketizerActionNotifyBase { public void onLiveStreamPacketizerCreate(ILiveStreamPacketizer liveStreamPacketizer, String streamName) { if (liveStreamPacketizer instanceof LiveStreamPacketizerCupertino) { getLogger().info(CLASSNAME+"#MyLiveListener.onLiveStreamPacketizerCreate["+((LiveStreamPacketizerCupertino)liveStreamPacketizer).getContextStr()+"]"); ((LiveStreamPacketizerCupertino)liveStreamPacketizer).setDataHandler(new LiveStreamPacketizerDataHandler((LiveStreamPacketizerCupertino)liveStreamPacketizer, streamName)); } } } public void onAppStart(IApplicationInstance appInstance) { this.appInstance = appInstance; appInstance.addLiveStreamPacketizerListener(new LiveStreamPacketizerListener()); getLogger().info(CLASSNAME+".onAppStart["+appInstance.getContextStr()+"]"); } }
- 在Wowza Streaming Engine Manager 管理界面,点击Wowza应用的名字(例如live).
- 点击应用主界面的Propertiestab页,再点击Quick Links导航条的Custom链接.
- 在Custom部分,点击Edit.
- 点击Add Custom Property,然后按下面添加cupertinoEnableProgramDateTime属性:
- Path: 选择 /Root/Application/HTTPStreamer.
- Name: 输入 cupertinoEnableProgramDateTime.
- Type: 选择 Boolean.
- Value: 输入 true.
- Path: 选择 /Root/Application/HTTPStreamer.
- 点击 Add, 再点击Save, 然后根据提示点击Restart。