How to live-stream video-file on Wowza

30 Jul No Comments

This article is discussed about the way to configure Wowza Media Server to live-stream video-files for IPTV environment

Video File format Supported

  • Video and Audio
    FLV (Flash Video – .flv)
    MP4 (QuickTime container – .mp4, .f4v, .mov, .m4v, .mp4a, .3gp, and .3g2)
    MP3 (.mp3)

Download and extract the wowza media server plugin collection.

To click here to download the ZIP file (wms-plugin-collection.zip).

After the zip file extracted, please read “README.html” to install the plugins

This package contains one jar file that you can use to implement a number of extensions for Wowza Server

To install

1. Copy the file jar file wms-plugin-collection.jar from [package]/lib/ into [install-dir]/lib/

For detailed description and implementation guide for each Module see this article on the Wowza Forum: Module Collection

All modules on this plugin package is described here.

Setting the configuration on Wowza Media Server

After the installation of the plugin-modules, and then follow the instructions on “How to do scheduled streaming with Stream class streams”. particularly, the code listed as below:

package com.wowza.wms.plugin.collection.serverlistener;

import com.wowza.wms.application.*;
import com.wowza.wms.server.*;
import com.wowza.wms.vhost.*;
import com.wowza.wms.stream.publish.*;
import com.wowza.wms.logging.*;
import java.io.File;
import java.text.SimpleDateFormat; 
import java.util.*; 

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element; 
import org.w3c.dom.Node; 
import org.w3c.dom.NodeList;

public class ServerListenerStreamPublisher implements IServerNotify { 

    WMSLogger log = WMSLoggerFactory.getLogger(null); 

    Map streamMap = new HashMap();
    Map playlistMap = new HashMap();

    public void onServerInit(IServer server)
    {
        log.info("ServerListenerStreamPublisher Started.");

        IVHost vhost = null;
        IApplication app = null;

        try
            {
            vhost = VHostSingleton.getInstance(server.getProperties().getPropertyStr("PublishToVHost", "_defaultVHost_"));
            } catch (Exception evhost) {
                log.info("ServerListenerStreamPublisher: Failed to get Vhost can not run.");
                return;
            }

        try 
            {
            app = vhost.getApplication(server.getProperties().getPropertyStr("PublishToApplication", "live"));
            } catch (Exception eapp) {
                log.info("ServerListenerStreamPublisher: Failed to get Application can not run.");
                return;
            }

            // Belt and Braces check for VHost and App
            if ( vhost == null || app == null )
                {
                log.info("ServerListenerStreamPublisher: VHost or Application failed, not running.");
                return;
                }

            Boolean passThruMetaData = server.getProperties().getPropertyBoolean("PassthruMetaData", true);

            String storageDir = app.getAppInstance("_definst_").getStreamStorageDir();

        try
            {            
            String smilLoc = storageDir + "/streamschedule.smil";
            File playlistxml = new File(smilLoc);

            if (playlistxml.exists() == false){
                log.info("ServerListenerStreamPublisher: Could not find playlist file: " + smilLoc);
                return; 
            }
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

            DocumentBuilder db = null;
            Document document = null;
            try {

            db = dbf.newDocumentBuilder();
            document = db.parse("file:///" + smilLoc);

            } catch (Exception e ) { log.info("ServerListenerStreamPublisher: XML Parse failed"); return; }

            document.getDocumentElement().normalize();

            NodeList streams = document.getElementsByTagName("stream");
            for (int i = 0; i < streams.getLength(); i++)
            {
                Node streamItem = streams.item(i);
                if (streamItem.getNodeType() == Node.ELEMENT_NODE)
                { 
                    Element e = (Element) streamItem;
                    String streamName = e.getAttribute("name");

                    log.info("ServerListenerStreamPublisher: Streame name is '"+streamName+"'");

                    Stream stream = Stream.createInstance(vhost, app.getName(), streamName);
                    streamMap.put(streamName, stream);
                    app.getAppInstance("_definst_").getProperties().setProperty(streamName, stream);
                }
            }

            NodeList playList = document.getElementsByTagName("playlist");
            if (playList.getLength() == 0){
                log.info("ServerListenerStreamPublisher: No playlists defined in smil file");
                return;
            } 
            for (int i = 0; i < playList.getLength(); i++)
            {
                Node scheduledPlayList = playList.item(i);

                if (scheduledPlayList.getNodeType() == Node.ELEMENT_NODE)
                {
                    Element e = (Element) scheduledPlayList;    

                    NodeList videos = e.getElementsByTagName("video");
                    if (videos.getLength() == 0){
                         log.info("ServerListenerStreamPublisher: No videos defined in stream");
                        return;
                    }

                    String streamName = e.getAttribute("playOnStream");
                    if (streamName.length()==0)
                        continue;

                    Playlist playlist = new Playlist(streamName);
                    playlist.setRepeat((e.getAttribute("repeat").equals("false"))?false:true);

                    playlistMap.put(e.getAttribute("name"), playlist);

                    for (int j = 0; j < videos.getLength(); j++)
                    {
                        Node video = videos.item(j);                
                        if (video.getNodeType() == Node.ELEMENT_NODE)
                        {
                            Element e2 = (Element) video;
                            String src = e2.getAttribute("src");
                            Integer start = Integer.parseInt(e2.getAttribute("start"));
                            Integer length = Integer.parseInt(e2.getAttribute("length"));
                            playlist.addItem(src, start, length);
                        }
                    }
                    String scheduled = e.getAttribute("scheduled");
                    SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    Date startTime = null;
                    try {

                    startTime = parser.parse(scheduled);
                    } catch (Exception z ) { log.info("Parsing schedule time failed."); return ; }
                    Stream stream = streamMap.get(streamName);
                    stream.setSendOnMetadata(passThruMetaData);
                    ScheduledItem item = new ScheduledItem(startTime, playlist, stream);
                    item.start();
                    IStreamActionNotify actionNotify  = new StreamListener(app.getAppInstance("_definst_"));
                    stream.addListener(actionNotify);
                    log.info("ServerListenerStreamPublisher Scheduled: " + stream.getName() + " for: " + scheduled);
                }    
            }
        }
        catch(Exception ex)
        {
            log.info("ServerListenerStreamPublisher: Error from playlist manager is '"+ex.getMessage()+"'");
        }
    }

private class ScheduledItem {
        public Timer mTimer;
        public TimerTask mTask;
        public Date mStart;
        public Playlist mPL;
        public Stream mStream;
        public ScheduledItem(Date d, Playlist pl, Stream s){
            mStart = d;
            mPL = pl;
            mStream = s;
            mTask = new TimerTask(){
                public void run() {
                    //synchronized(mStream.getLock())
                    //{
                        mPL.open(mStream);
                    //}
                    log.info("ServerListenerStreamPublisher Scheduled stream is now live: " + mStream.getName());
                }
            };
            mTimer = new Timer();
        }

        public void start(){ 

            if (mTimer==null)
                mTimer = new Timer();
            mTimer.schedule(mTask, mStart);
            log.info("scheduled playlist: "+mPL.getName()+
                        " on stream: "+mStream.getName()+
                        " for:"+mStart.toString());
        }

        public void stop(){
            if (mTimer != null){
                mTimer.cancel();
                mTimer=null;
                log.info("cancelled playlist: "+mPL.getName()+
                        " on stream: "+mStream.getName()+
                        " for:"+mStart.toString());
            }
        }
    }
    public void onServerCreate(IServer server)
    {
    }
    public void onServerShutdownComplete(IServer server)
    {
        log.info("ServerListenerStreamPublisher: Shutdown server start");
        for (Map.Entry entry : streamMap.entrySet())
        {
            try
            {
            Stream stream = entry.getValue();
            stream.close();
            stream = null;
            log.info("ServerListenerStreamPublisher Closed Stream: " + entry.getKey());
            }
            catch(Exception ex)
            {
                log.error(ex.getMessage());
            }
        }
        for (Map.Entry entry : playlistMap.entrySet())
        {
            try
            {
            Playlist pl = entry.getValue();
            pl = null;
            }
            catch(Exception ex)
            {
                log.error(ex.getMessage());
            }
        }
    }

    public void onServerShutdownStart(IServer server)
    {

    }

    class StreamListener implements IStreamActionNotify
    {
        StreamListener(IApplicationInstance appInstance)
        {
        }    
        public void onPlaylistItemStop(Stream stream, PlaylistItem item)
        {
        	if (item.getIndex() == (stream.getPlaylist().size() - 1))
        	{
        	if (! stream.getRepeat())
        	{
        	stream.close();
        	WMSLoggerFactory.getLogger(null).info("ServerListenerStreamPublisher: closing stream: " + stream.getName());
        	}
        	}
        }
        public void onPlaylistItemStart(Stream stream, PlaylistItem item) 
        {
            try
            {
            String name = stream.getCurrentItem().getName();
            stream.getPublisher().getAppInstance().broadcastMsg("PlaylistItemStart", name);
            WMSLoggerFactory.getLogger(null).info("ServerListenerStreamPublisher PlayList Item Start: " + name);
            }
            catch(Exception ex)
            {
                WMSLoggerFactory.getLogger(null).info("ServerListenerStreamPublisher Get Item error: " + ex.getMessage());
            }
        }
    }
}

is on the file at <<zip –> wms-plugin-collection -> src -> com -> wowza -> wms -> plugin -> collection -> serverlistener -> ServerListenerStreamPublisher.java >>. If you are interested in studying the code, may follow up the above instruction; otherwise, just followup the next instruction

Adding the following code to /conf/Server.xml below the section of  /ServerListeners

. Input the following code on it

<ServerListener>
    <BaseClass>com.wowza.wms.plugin.collection.serverlistener.ServerListenerStreamPublisher</BaseClass>
</ServerListener>

EVENTUALLY, IT’S BEEN DONE ON SETTING of /conf/Server.xml AFTER THE ABOVE STEP IF YOU HAVE CONFIGURE LIVE CHANNEL ALREADY. Otherwise, still need to following the other 3 steps for furthermore settings.
**********************************************************
IMPORTANT: this server listener requires that there be an application named “live” where the Streams and Playlists are created. You can set another name for the application to be populated in /conf/Server.xml /Properties:

Code:
<Property>
<Name>PublishToApplication</Name>
<Value>MyLiveApp</Value>
</Property>

And if you want to publish to another VHost, add this Property to /conf/Server.xml /Properties:

Code:
<Property>
<Name>PublishToVHost</Name>
<Value>CustomVHost</Value>
</Property>

MetaData from media files are passed to the live stream by default, if you don’t want that to happen, add this Property to /conf/Server.xml /Properties:

Code:
<Property>
    <Name>PassthruMetaData</Name>
    <Value>false</Value>
    <Type>Boolean</Type>
</Property>

The target application must have an Application.xml /StreamType “live” or “live-lowlatency”

*****************************************************
Create the smil file [install-dir]/content/streamschedule.smil
Create the smil file [install-dir]/content/streamschedule.smil

Create at least one stream, then create at least one playlist that plays on that stream. Set repeat to true or false for each playlist. Use start=”-2″ for live sources. Use length=”-1″ to play until media ends.

You can create an elaborate schedule with several streams and many playlists scheduled to play on a stream.

Code:
<smil>
    <head>
    </head>
    <body>

        <stream name="Stream1"></stream>
        <stream name="Stream2"></stream>

        <playlist name="pl1" playOnStream="Stream1" repeat="true" scheduled="2009-12-11 16:00:00">
            <video src="mp4:sample.mp4" start="5" length="5"/>
            <video src="mp4:sample.mp4" start="50" length="5"/>
            <video src="mp4:sample.mp4" start="150" length="5"/>
        </playlist>
        <playlist name="pl2" playOnStream="Stream1" repeat="true" scheduled="2009-12-11 16:30:00">
            <video src="mp4:sample.mp4" start="0" length="-1"/>
        </playlist>

        <playlist name="pl3" playOnStream="Stream2" repeat="true" scheduled="2009-12-11 16:00:00">
            <video src="mp4:sample.mp4" start="30" length="5"/>
        </playlist>

    </body>
</smil>

 

Brief Description of /content/streamschedule.smil

  • all the playlist will be repeated when playing ended
  • stream name = “stream1”: The stream1 means the stream to play
  • “playlist name=”pl1″ playOnStream=”Stream1″ repeat=”true” scheduled=”2009-12-11 16:00:00″”: at 2009/12/11 16:00:00 starting to play the channel to stream1
  • “video src=”mp4:sample.mp4″ start=”5″ length=”5″”: start the 5th second of the file sample.mp4, and playing 5 seconds only.
  • “video src=”mp4:sample.mp4″ start=”50″ length=”5″”: continuing the same file at the 50th second, and playing 5 seconds
  • “playlist name=”pl2″ playOnStream=”Stream1″ repeat=”true” scheduled=”2009-12-11 16:30:00″: at 2009/12/11 16:30:00 start to play this section to Stream1
  • “video src=”mp4:sample.mp4″ start=”0″ length=”-1″”: start to play the file of sample.mp4 from the beginning to the end; when finished, to replay continually.

configuration a client site

Server: rtmp://[wowza-address]/live
Stream: Stream1 (or Stream2. As set in smil file).

REFERENCE

How to do scheduled streaming with Stream class streams

Module Collection

Live Streaming of a MP4

Specifications

Latest Comments

Leave a Reply

相關訊息