Wowza Streaming Engine 4.9.4 is available! Go to the Downloads page to download. See the 4.9.4 Release Notes.

Resolve SMIL file requests with the Wowza Streaming Engine Java API

SMIL files are used in Wowza Streaming Engine™ to describe multi-bitrate streams, both live and video-on-demand. You can use the Wowza Streaming Engine Java API to intercept requests for multi-bitrate streams and provide the stream grouping. To use this feature, you must use the stream name prefix amlst: (which stands for API-based MediaList). A MediaList is a set of Java objects that describe a multi-bitrate stream. When Wowza Streaming Engine reads a SMIL file, it creates a MediaList and passes it back to the streaming provider. The Java API provides a means to intercept these requests and create the MediaList dynamically in a Wowza Streaming Engine module.

Each ApplicationInstance has a IMediaListProvider provider interface. This interface is used to resolve stream names that are prefixed with the amlst: prefix to MediaList objects. In a module you can create your own IMediaListProvider implementation and replace the default implementation.

Note: For examples of intercepting requests for multi-bitrate streams that include captions, see Resolve SMIL file requests with captions with the Wowza Streaming Engine Java API.

MediaList object structure


A MediaList has the following object structure:

MediaList
|
--MediaListSegment
  |
  --MediaListRendition
    [...]

A MediaList has a single MediaListSegment. The MediaListSegement can have multiple MediaListRenditions each representing a single multi-bitrate rendition.

Live streaming sample module


Here is a sample module that implements this interface for live streaming:

package com.wowza.wms.plugin.test.module;

import com.wowza.wms.medialist.*;
import com.wowza.wms.module.*;
import com.wowza.wms.stream.*;
import com.wowza.wms.application.*;

public class ModuleAMLSTTestLive extends ModuleBase 
{
	class MyMediaListProvider implements IMediaListProvider
	{
		public MediaList resolveMediaList(IMediaListReader mediaListReader, IMediaStream stream, String streamName)
		{
			MediaList mediaList = new MediaList();

			MediaListSegment segment = new MediaListSegment();
			mediaList.addSegment(segment);

			MediaListRendition rendition1 = new MediaListRendition();
			segment.addRendition(rendition1);

			rendition1.setName(streamName+"_400");
			rendition1.setBitrateAudio(128000);
			rendition1.setBitrateVideo(400000);
			rendition1.setWidth(320);
			rendition1.setHeight(240);
			rendition1.setAudioCodecId("mp4a.40.2");
			rendition1.setVideoCodecId("avc1.66.12");

			MediaListRendition rendition2 = new MediaListRendition();
			segment.addRendition(rendition2);

			rendition2.setName(streamName+"_800");
			rendition2.setBitrateAudio(128000);
			rendition2.setBitrateVideo(800000);
			rendition2.setWidth(640);
			rendition2.setHeight(480);
			rendition2.setAudioCodecId("mp4a.40.2");
			rendition2.setVideoCodecId("avc1.77.31");

			return mediaList;
		}
	}

	public void onAppStart(IApplicationInstance appInstance)
	{
		appInstance.setMediaListProvider(new MyMediaListProvider());
	}

}

Add this module as the last entry in the <Modules> list in [install-dir]/conf/[application]/Application.xml:

<Module>
	<Name>ModuleAMLSTTestLive</Name>
	<Description>ModuleAMLSTTestLive</Description>
	<Class>com.wowza.wms.plugin.test.module.ModuleAMLSTTestLive</Class>
</Module>

Quickly looking at the components of this module:

  • Module extends the ModuleBase
  • Internal class MyMediaListProvider implements the IMediaListProvider interface and returns a new MediaList based on the stream name.
  • The onAppStart method is used to replace the application instance level IMediaListProvider with our implementation.

This module will intercept any request for stream names that start with amlst: such as

http://[wowza-ip-address]:1935/[application-name]/amlst:myStream/playlist.m3u8

It will return a multi-bitrate description with two renditions using the stream name as the base name for the filename. This is equivalent to the SMIL file:

<smil>
	<head>
	</head>
	<body>
		<switch>
			<video src="myStream_400" width="320" height="240" system-bitrate="528000">
				<param name="audioCodecId" value="mp4a.40.2" valuetype="data"/>
				<param name="videoCodecId" value="avc1.66.12" valuetype="data"/>
				<param name="audioBitrate" value="128000" valuetype="data"/>
				<param name="videoBitrate" value="400000" valuetype="data"/>
			</video>
			<video src="myStream_800" width="640" height="480" system-bitrate="928000">
				<param name="audioCodecId" value="mp4a.40.2" valuetype="data"/>
				<param name="videoCodecId" value="avc1.77.31" valuetype="data"/>
				<param name="audioBitrate" value="128000" valuetype="data"/>
				<param name="videoBitrate" value="800000" valuetype="data"/>
			</video>
		</switch>
	</body>
</smil>

Video-on-demand streaming sample module


Here is a sample module that implements this interface for VOD streaming::

package com.wowza.wms.plugin.test.module;

import com.wowza.wms.medialist.*;
import com.wowza.wms.module.*;
import com.wowza.wms.stream.*;
import com.wowza.wms.application.*;

public class ModuleAMLSTTest extends ModuleBase 
{
	class MyMediaListProvider implements IMediaListProvider
	{
		public MediaList resolveMediaList(IMediaListReader mediaListReader, IMediaStream stream, String streamName)
		{
			MediaList mediaList = new MediaList();

			MediaListSegment segment = new MediaListSegment();
			mediaList.addSegment(segment);

			MediaListRendition rendition1 = new MediaListRendition();
			segment.addRendition(rendition1);

			rendition1.setName("mp4:"+streamName+"_400k.mp4");
			rendition1.setBitrateAudio(128000);
			rendition1.setBitrateVideo(400000);
			rendition1.setWidth(320);
			rendition1.setHeight(240);
			rendition1.setAudioCodecId("mp4a.40.2");
			rendition1.setVideoCodecId("avc1.66.12");

			MediaListRendition rendition2 = new MediaListRendition();
			segment.addRendition(rendition2);

			rendition2.setName("mp4:"+streamName+"_800k.mp4");
			rendition2.setBitrateAudio(128000);
			rendition2.setBitrateVideo(800000);
			rendition2.setWidth(640);
			rendition2.setHeight(480);
			rendition2.setAudioCodecId("mp4a.40.2");
			rendition2.setVideoCodecId("avc1.77.31");

			return mediaList;
		}
	}

	public void onAppStart(IApplicationInstance appInstance)
	{
		appInstance.setMediaListProvider(new MyMediaListProvider());
	}

}

Add this module as the last entry in the <Modules> list in [install-dir]/conf/[application]/Application.xml:

<Module>
	<Name>ModuleAMLSTTest</Name>
	<Description>ModuleAMLSTTest</Description>
	<Class>com.wowza.wms.plugin.test.module.ModuleAMLSTTest</Class>
</Module>

These are the components of this module:

  • Module extends the ModuleBase
  • Internal class MyMediaListProvider implements the IMediaListProvider interface and returns a new MediaList based on the stream name.
  • The onAppStart method is used to replace the application instance level IMediaListProvider with our implementation.

This module will intercept any request for stream names that start with amlst: such as:

http://[wowza-ip-address]:1935/[application-name]/amlst:sample/playlist.m3u8

It will return a multi-bitrate description with two renditions using the stream name as the base name for the filename. This is equivalent to the SMIL file:

<smil>
	<head>
	</head>
	<body>
		<switch>
			<video src="mp4:sample_400.mp4" width="320" height="240" system-bitrate="528000">
				<param name="videoCodecId" value="avc1.66.12" valuetype="data"/>
				<param name="audioCodecId" value="mp4a.40.2" valuetype="data"/>
				<param name="audioBitrate" value="128000" valuetype="data"/>
				<param name="videoBitrate" value="400000" valuetype="data"/>
			</video>
			<video src="mp4:sample_800.mp4" width="640" height="480" system-bitrate="928000">
				<param name="videoCodecId" value="avc1.77.31" valuetype="data"/>
				<param name="audioCodecId" value="mp4a.40.2" valuetype="data"/>
				<param name="audioBitrate" value="128000" valuetype="data"/>
				<param name="videoBitrate" value="800000" valuetype="data"/>
			</video>
		</switch>
	</body>
</smil>
 
Note: The IMediaListReader interface does provide additional context information such as the IHTTPStreamerSession from which the stream is being requested.

Low-Latency HLS live streaming sample module


Here is a sample module that implements this interface for Low-Latency HLS live streaming:

package com.wowza.wms.plugin.test.module;

import com.wowza.wms.medialist.*;
import com.wowza.wms.module.*;
import com.wowza.wms.stream.*;
import com.wowza.wms.application.*;

public class CmafAmlst extends ModuleBase 
{
	class CmafAmlstProvider implements IMediaListProvider
	{
		public MediaList resolveMediaList(IMediaListReader mediaListReader, IMediaStream stream, String streamName)
		{
			MediaList mediaList = new MediaList();

			MediaListSegment segment = new MediaListSegment();
			mediaList.addSegment(segment);

			MediaListRendition rendition1 = new MediaListRendition();
			segment.addRendition(rendition1);

			rendition1.setName(streamName+"_160p");
			rendition1.setBitrateAudio(100000);
			rendition1.setWowzaAudioOnly(true);
			rendition1.setTitle("English");
			rendition1.setLanguage("eng");
			WMSProperties props1 = rendition1.getProperties(true);
				props1.setProperty("cupertinoTag", "EXT-X-MEDIA");
				props1.setProperty("cupertinoTag.GROUP-ID", "aac");
				props1.setProperty("cupertinoTag.DEFAULT", "FALSE");
				props1.setProperty("cupertinoTag.AUTOSELECT", "YES");
			
			MediaListRendition rendition2 = new MediaListRendition();
			segment.addRendition(rendition2);

			rendition2.setName(streamName+"_source");
			rendition2.setBitrateVideo(1300000);
			rendition2.setWidth(960);
			rendition2.setHeight(540);
			rendition2.setAudioCodecId("mp4a.40.2");
			rendition2.setVideoCodecId("avc1.77.32");
			rendition2.setWowzaVideoOnly(true);
			WMSProperties props2 = rendition2.getProperties(true);
				props2.setProperty("cupertinoTag.AUDIO", "aac");

			MediaListRendition rendition3 = new MediaListRendition();
			segment.addRendition(rendition3);

			rendition3.setName(streamName+"_360p");
			rendition3.setBitrateVideo(850000);
			rendition3.setWidth(640);
			rendition3.setHeight(360);
			rendition3.setAudioCodecId("mp4a.40.2");
			rendition3.setVideoCodecId("avc1.77.31");
			rendition3.setWowzaVideoOnly(true);
			WMSProperties props3 = rendition3.getProperties(true);
				props3.setProperty("cupertinoTag.AUDIO", "aac");
			
			MediaListRendition rendition4 = new MediaListRendition();
			segment.addRendition(rendition4);

			rendition4.setName(streamName+"_160p");
			rendition4.setBitrateVideo(200000);
			rendition4.setWidth(284);
			rendition4.setHeight(160);
			rendition4.setAudioCodecId("mp4a.40.2");
			rendition4.setVideoCodecId("avc1.66.21");
			rendition4.setWowzaVideoOnly(true);
			WMSProperties props4 = rendition4.getProperties(true);
				props4.setProperty("cupertinoTag.AUDIO", "aac");

			return mediaList;
		}
	}

	public void onAppStart(IApplicationInstance appInstance)
	{
		appInstance.setMediaListProvider(new CmafAmlstProvider());
	}

}
 
Note: SMIL files for Low-Latency HLS streaming require specific attributes and parameters. For more information, see Create adaptive bitrate CMAF streams using Wowza Streaming Engine.

Add this module as the last entry in the <Modules> list in [install-dir]/conf/[application]/Application.xml:

<Module>
	<Name>CmafAmlst</Name>
	<Description>CmafAmlst</Description>
	<Class>com.wowza.wms.plugin.test.module.CmafAmlst</Class>
</Module>

Quickly looking at the components of this module:

  • Module extends the ModuleBase
  • Internal class CmafAmlstProvider implements the IMediaListProvider interface and returns a new MediaList based on the stream name.
  • The onAppStart method is used to replace the application instance level IMediaListProvider with our implementation.

This module will intercept any request for stream names that start with amlst: such as

http://[wowza-ip-address]:1935/[application-name]/amlst:myStream/playlist.m3u8

It will return a multi-bitrate description with three video renditions and one audio rendition using the stream name as the base name for the filename. This is equivalent to the SMIL file:

<smil>
	<head>
	</head>
	<body>
		<switch>
			<video src="mp4:myStream_160p" system-language="en" title="English" audio-bitrate="100000">
			   <param name="audioOnly" value="TRUE" valuetype="data"/>
			   <param name="cupertinoTag" value="EXT-X-MEDIA" valuetype="data"/>
                           <param name="cupertinoTag.GROUP-ID" value="aac" valuetype="data"/>
                           <param name="cupertinoTag.DEFAULT" value="YES" valuetype="data"/>
                           <param name="cupertinoTag.AUTOSELECT" value="YES" valuetype="data"/>
			</video>
			<video src="mp4:myStream_source" width="960" height="540" video-bitrate="1300000">
                           <param name="videoCodecId" value="avc1.77.32" valuetype="data"/>
                           <param name="videoOnly" value="TRUE" valuetype="data"/>
                           <param name="cupertinoTag.AUDIO" value="aac" valuetype="data"/>
                           <param name="audioCodecId" value="mp4a.40.2" valuetype="data"/>
			</video>
			<video src="mp4:myStream_360p" width="640" height="360" video-bitrate="850000">
                           <param name="videoCodecId" value="avc1.77.31" valuetype="data"/>
                           <param name="videoOnly" value="TRUE" valuetype="data"/>
                           <param name="cupertinoTag.AUDIO" value="aac" valuetype="data"/>
                           <param name="audioCodecId" value="mp4a.40.2" valuetype="data"/>
			</video>
			<video src="mp4:myStream_160p" width="284" height="160" video-bitrate="200000">
                           <param name="videoCodecId" value="avc1.66.21" valuetype="data"/>
                           <param name="videoOnly" value="TRUE" valuetype="data"/>
                           <param name="cupertinoTag.AUDIO" value="aac" valuetype="data"/>
                           <param name="audioCodecId" value="mp4a.40.2" valuetype="data"/>
			</video>
		</switch>
	</body>
</smil>