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>