Source code for HTTPProviderMediaList in Wowza Media Server

This article provides the HTTPProviderMediaList source code that's built into Wowza Media Server.

Note: Wowza Media Server™ 3.5.0 or later is required.
package com.wowza.wms.http;

import java.io.OutputStream;
import java.util.*;

import com.wowza.util.HTTPUtils;
import com.wowza.wms.application.*;
import com.wowza.wms.httpstreamer.cupertinostreaming.httpstreamer.CupertinoStreamingURL;
import com.wowza.wms.httpstreamer.util.HTTPStreamerUtils;
import com.wowza.wms.logging.WMSLoggerFactory;
import com.wowza.wms.medialist.*;
import com.wowza.wms.stream.IMediaReader;
import com.wowza.wms.util.*;
import com.wowza.wms.vhost.*;

public class HTTPProviderMediaList extends HTTProvider2Base
{
	private HTTPCrossdomainHandler crossdomainHandler = new HTTPCrossdomainHandler();

	public void onBind(IVHost vhost, HostPort hostPort)
	{
		super.onBind(vhost, hostPort);
		crossdomainHandler.setVHost(vhost);
	}

	public void setProperties(WMSProperties properties)
	{
		super.setProperties(properties);
		crossdomainHandler.setProperties(properties);
	}

	public void onHTTPRequest(IVHost vhost, IHTTPRequest req, IHTTPResponse resp)
	{
		if (!doHTTPAuthentication(vhost, req, resp))
			return;

		String smilStr = null;
		String contentTypeStr = "text/xml";
		while(true)
		{
			String queryStr = req.getQueryString();
			if (queryStr == null)
			{
				WMSLoggerFactory.getLogger(HTTPProviderMediaList.class).warn("HTTPProviderMediaList.onHTTPRequest: Query string missing");
				break;
			}

	        Map<String, String> queryMap = HTTPUtils.splitQueryStr(queryStr);

	        String streamName = null;
	        String comboAppStr = null;
	        String formatStr = "smil";
	        String domainStr = req.getHeader("host");
	        String protocolStr = "rtmp";

            String url = req.getHeader("context");
            if (url == null)
                break;

            if (url.indexOf("crossdomain.xml") >= 0)
            {
				WMSLoggerFactory.getLogger(HTTPProviderMediaList.class).warn("HTTPProviderMediaList.onHTTPRequest: crossdomain.xml request");
            	crossdomainHandler.handleCrossdomainRequest(vhost, req, resp);
            	return;
            }

    		int qloc = url.indexOf("?");
            if (qloc >= 0)
            	url = url.substring(0, qloc);

            url = HTTPStreamerUtils.urlDecode(url);

	        if (queryMap.get("streamname") != null)
	        	streamName = queryMap.get("streamname");

	        if (queryMap.get("format") != null)
	        	formatStr = queryMap.get("format");

	        if (queryMap.get("application") != null)
	        	comboAppStr = queryMap.get("application");

	        if (queryMap.get("protocol") != null)
	        	protocolStr = queryMap.get("protocol");

	        if (queryMap.get("domain") != null)
	        	domainStr = queryMap.get("domain");

	        boolean decodePath = false;

	        if (url.endsWith("jwplayer.rss"))
	        {
	        	decodePath = true;
	        	formatStr = "rss.jwplayer";
	        }
	        else if (url.endsWith("jwplayer.smil"))
	        {
	        	decodePath = true;
	        	formatStr = "smil.jwplayer";
	        }
	        else if (url.endsWith("medialist.smil"))
	        {
	        	decodePath = true;
	        	formatStr = "smil";
	        }
	        else if (url.endsWith("manifest-rtmp.f4m"))
	        {
	        	decodePath = true;
	        	formatStr = "f4m.rtmp";
	        }

	        if (decodePath)
	        {
	        	CupertinoStreamingURL urlDecoded = new CupertinoStreamingURL(url, true);
	        	if (urlDecoded != null)
	        	{
		        	streamName = urlDecoded.getStreamName();
		        	comboAppStr = urlDecoded.getAppName()+"/"+urlDecoded.getAppInstanceName();
	        	}
	        }

	        if (streamName == null)
			{
				WMSLoggerFactory.getLogger(HTTPProviderMediaList.class).warn("HTTPProviderMediaList.onHTTPRequest: Streamname not specified");
				break;
			}

	        if (comboAppStr == null)
			{
				WMSLoggerFactory.getLogger(HTTPProviderMediaList.class).warn("HTTPProviderMediaList.onHTTPRequest: Application name not specified");
				break;
			}

	        String applicationStr = comboAppStr;
	        String appInstanceStr = IApplicationInstance.DEFAULT_APPINSTANCE_NAME;

	        int cindex = applicationStr.indexOf("/");
	        if (cindex > 0)
	        {
	        	appInstanceStr = applicationStr.substring(cindex+1);
	        	applicationStr = applicationStr.substring(0, cindex);
	        }

			IApplication applicationLoc = vhost.getApplication(applicationStr);
			if (applicationLoc == null)
			{
				WMSLoggerFactory.getLogger(HTTPProviderMediaList.class).warn("HTTPProviderMediaList.onHTTPRequest: Application could not be loaded: "+applicationStr);
				break;
			}

			IApplicationInstance appInstance = applicationLoc.getAppInstance(appInstanceStr);
			if (appInstance == null)
			{
				WMSLoggerFactory.getLogger(HTTPProviderMediaList.class).warn("HTTPProviderMediaList.onHTTPRequest: Application instance could not be loaded: "+applicationStr+"/"+appInstanceStr);
				break;
			}

			String streamExt = "smil";

			String[] streamDecode = ModuleUtils.decodeStreamExtension(streamName, streamExt);
			streamName = streamDecode[0];
			streamExt = streamDecode[1];

			if (appInstance.getMediaReaderContentType(streamExt) != IMediaReader.CONTENTTYPE_MEDIALIST)
			{
				WMSLoggerFactory.getLogger(HTTPProviderMediaList.class).warn("HTTPProviderMediaList.onHTTPRequest: Stream is not a MediaList: "+applicationStr+"/"+appInstanceStr+"/"+streamExt+":"+streamName);
				break;
			}

			MediaList mediaList = MediaListUtils.parseMediaList(appInstance, streamName, streamExt, null);
			if (mediaList == null)
			{
				WMSLoggerFactory.getLogger(HTTPProviderMediaList.class).warn("HTTPProviderMediaList.onHTTPRequest: MediaList not found: "+applicationStr+"/"+appInstanceStr+"/"+streamExt+":"+streamName);
				break;
			}

			if (formatStr.equalsIgnoreCase("f4m.rtmp"))
			{
				//<?xml version="1.0" encoding="utf-8"?>
				//<manifest xmlns="_http://ns.adobe.com/f4m/1.0"> 
				//     <id>dynamicStream</id> 
				//     <mimeType>video/mp4</mimeType> 
				//     <streamType>live</streamType> 
				//     <baseURL>rtmp://someURL.net/files-live</baseURL> 
				//     <media url="file1500" bitrate="1500" /> 
				//     <media url="file800" bitrate="800" /> 
				//     <media url="file400" bitrate="400" /> 
				//</manifest>
				StringBuffer strBuf = new StringBuffer();

				strBuf.append("<?xml version="1.0" encoding="utf-8"?>
");
				strBuf.append("<manifest xmlns="http://ns.adobe.com/f4m/1.0">
");
				strBuf.append("	<id>"+streamName+"</id>
");
				strBuf.append("	<mimeType>video/mp4</mimeType>
");
				strBuf.append("	<streamType>live</streamType>
");
				strBuf.append("	<deliveryType>streaming</deliveryType>
");
				strBuf.append("	<baseURL>"+protocolStr+"://"+domainStr+"/"+applicationStr+"/"+appInstanceStr+"</baseURL>
");
				while(true)
				{
					MediaListSegment segment = mediaList.getFirstSegment();
					if (segment == null)
						break;

					List<MediaListRendition> renditions = segment.getRenditions();
					Iterator<MediaListRendition> iter = renditions.iterator();
					while(iter.hasNext())
					{
						MediaListRendition rendtion = iter.next();

						String urlStr = "";
						if (rendtion.getName() != null)
							urlStr = " url=""+rendtion.getName()+""";

						String widthStr = "";
						String heightStr = "";
						if (rendtion.getWidth() > 0)
							widthStr = " width=""+rendtion.getWidth()+""";
						if (rendtion.getHeight() > 0)
							heightStr = " height=""+rendtion.getHeight()+""";

						String bitrateStr = "";
						if (rendtion.getBitrateTotal() > 0)
							bitrateStr = " bitrate=""+(rendtion.getBitrateTotal()/1000)+""";

						strBuf.append("	<media"+urlStr+bitrateStr+widthStr+heightStr+"/>
");
					}
					break;
				}
				strBuf.append("</manifest>
");

				smilStr = strBuf.toString();
			}
			else if (formatStr.equalsIgnoreCase("smil.jwplayer"))
			{
				//<smil>
				//  <head>
				//    <meta base="rtmp://example.com/vod/" />
				//  </head>
				//  <body>
				//    <switch>
				//      <video src="myVideo-high.mp4" height="720"
				//system-bitrate="2000000" width="1280" />
				//      <video src="myVideo-medium.mp4" height="360"
				//system-bitrate="800000" width="640" />
				//      <video src="myVideo-low.mp4" height="180"
				//system-bitrate="300000" width="320" />
				//    </switch>
				//  </body>
				//</smil>

				StringBuffer strBuf = new StringBuffer();

				strBuf.append("<smil>
");
				strBuf.append("	<head>
");
				strBuf.append("		<meta base=""+protocolStr+"://"+domainStr+"/"+applicationStr+"/"+appInstanceStr+"" />
");
				strBuf.append("	</head>
");
				strBuf.append("	<body>
");
				strBuf.append("		<switch>
");

				while(true)
				{
					MediaListSegment segment = mediaList.getFirstSegment();
					if (segment == null)
						break;

					List<MediaListRendition> renditions = segment.getRenditions();
					Iterator<MediaListRendition> iter = renditions.iterator();
					while(iter.hasNext())
					{
						MediaListRendition rendtion = iter.next();

						// skip textstream
						if (rendtion.getType() == IVHost.CONTENTTYPE_DATA)
							continue;

						String urlStr = "";
						if (rendtion.getName() != null)
							urlStr = " src=""+rendtion.getName()+""";

						String widthStr = "";
						String heightStr = "";
						if (rendtion.getWidth() > 0)
							widthStr = " width=""+rendtion.getWidth()+""";
						if (rendtion.getHeight() > 0)
							heightStr = " height=""+rendtion.getHeight()+""";

						String bitrateStr = "";
						if (rendtion.getBitrateTotal() > 0)
							bitrateStr = " system-bitrate=""+(rendtion.getBitrateTotal())+""";

						strBuf.append("			<video"+urlStr+bitrateStr+widthStr+heightStr+"/>
");
					}
					break;
				}

				strBuf.append("		</switch>
");
				strBuf.append("	</body>
");
				strBuf.append("</smil>
");

				smilStr = strBuf.toString();
			}
			else if (formatStr.equalsIgnoreCase("rss.jwplayer"))
			{
				//<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/"
				//  xmlns:jwplayer="http://developer.longtailvideo.com/">
				//  <channel>
				//    <item>
				//      <title>Demos Flash Bitrate Switching</title>
				//      <description>Demos Flash Bitrate Switching</description>
				//      <jwplayer:streamer>rtmp://184.72.239.149/demos</jwplayer:streamer>
				//      <media:group>
				//        <media:content bitrate="1500" url="bigbuckbunny_1500.mp4"  width="1080" />
				//        <media:content bitrate="1100" url="bigbuckbunny_1100.mp4" width="640"/>
				//        <media:content bitrate="750" url="bigbuckbunny_750.mp4" width="476" />
				//        <media:content bitrate="450" url="bigbuckbunny_450.mp4" width="320" />
				//      </media:group>
				//    </item>
				//  </channel>
				//</rss>

				StringBuffer strBuf = new StringBuffer();

				strBuf.append("<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/" xmlns:jwplayer="http://developer.longtailvideo.com/">
");
				strBuf.append("	<channel>
");
				strBuf.append("		<item>
");
				strBuf.append("			<title>"+streamName+"</title>
");
				strBuf.append("			<description>"+streamName+"</description>
");
				strBuf.append("			<jwplayer:streamer>"+protocolStr+"://"+domainStr+"/"+applicationStr+"/"+appInstanceStr+"</jwplayer:streamer>
");
				strBuf.append("			<media:group>
");

				while(true)
				{
					MediaListSegment segment = mediaList.getFirstSegment();
					if (segment == null)
						break;

					List<MediaListRendition> renditions = segment.getRenditions();
					Iterator<MediaListRendition> iter = renditions.iterator();
					while(iter.hasNext())
					{
						MediaListRendition rendtion = iter.next();

						String urlStr = "";
						if (rendtion.getName() != null)
							urlStr = " url=""+rendtion.getName()+""";

						String widthStr = "";
						String heightStr = "";
						if (rendtion.getWidth() > 0)
							widthStr = " width=""+rendtion.getWidth()+""";
						if (rendtion.getHeight() > 0)
							heightStr = " height=""+rendtion.getHeight()+""";

						String bitrateStr = "";
						if (rendtion.getBitrateTotal() > 0)
							bitrateStr = " bitrate=""+(rendtion.getBitrateTotal()/1000)+""";

						strBuf.append("				<media:content"+urlStr+bitrateStr+widthStr+heightStr+"/>
");
					}
					break;
				}

				strBuf.append("			</media:group>
");
				strBuf.append("		</item>
");
				strBuf.append("	</channel>
");
				strBuf.append("</rss>");

				smilStr = strBuf.toString();
			}
			else
				smilStr = mediaList.toSMILString();
			break;
		}

		try
		{
			if (smilStr != null)
			{
				resp.setHeader("Content-Type", contentTypeStr);

				OutputStream out = resp.getOutputStream();

				byte[] outBytes = smilStr.getBytes();

				out.write(outBytes);
			}
			else
				resp.setResponseCode(404);
		}
		catch (Exception e)
		{
			WMSLoggerFactory.getLogger(HTTPProviderMediaList.class).error("HTTPProviderMediaList.onHTTPRequest ", e);
		}
	}
}

Originally Published: For Wowza Media Server 3.5.0 on 01-10-2013.

If you're having problems or want to discuss this article, post in our forum.