no commit message
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mangui.osmf.plugins {
|
||||
import flash.display.Sprite;
|
||||
import flash.system.Security;
|
||||
|
||||
import org.osmf.media.PluginInfo;
|
||||
|
||||
public class HLSDynamicPlugin extends Sprite {
|
||||
private var _pluginInfo : PluginInfo;
|
||||
|
||||
public function HLSDynamicPlugin() {
|
||||
super();
|
||||
Security.allowDomain("*");
|
||||
_pluginInfo = new HLSPlugin();
|
||||
}
|
||||
|
||||
public function get pluginInfo() : PluginInfo {
|
||||
return _pluginInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mangui.osmf.plugins {
|
||||
import flash.media.Video;
|
||||
import flash.net.NetStream;
|
||||
|
||||
import org.mangui.hls.HLS;
|
||||
import org.mangui.hls.event.HLSEvent;
|
||||
import org.mangui.osmf.plugins.loader.HLSNetLoader;
|
||||
import org.mangui.osmf.plugins.traits.*;
|
||||
import org.mangui.osmf.plugins.utils.ErrorManager;
|
||||
|
||||
import org.osmf.media.LoadableElementBase;
|
||||
import org.osmf.media.MediaElement;
|
||||
import org.osmf.media.MediaResourceBase;
|
||||
import org.osmf.media.videoClasses.VideoSurface;
|
||||
import org.osmf.net.NetStreamAudioTrait;
|
||||
import org.osmf.net.StreamType;
|
||||
import org.osmf.net.StreamingURLResource;
|
||||
import org.osmf.traits.AudioTrait;
|
||||
import org.osmf.traits.BufferTrait;
|
||||
import org.osmf.traits.DVRTrait;
|
||||
import org.osmf.traits.LoadTrait;
|
||||
import org.osmf.traits.LoaderBase;
|
||||
import org.osmf.traits.MediaTraitType;
|
||||
import org.osmf.traits.PlayTrait;
|
||||
import org.osmf.traits.SeekTrait;
|
||||
import org.osmf.traits.TimeTrait;
|
||||
import org.osmf.utils.OSMFSettings;
|
||||
import org.osmf.events.MediaError;
|
||||
import org.osmf.events.MediaErrorEvent;
|
||||
|
||||
CONFIG::LOGGING {
|
||||
import org.mangui.hls.utils.Log;
|
||||
}
|
||||
|
||||
public class HLSMediaElement extends LoadableElementBase {
|
||||
private var _hls : HLS;
|
||||
private var _stream : NetStream;
|
||||
private var _defaultduration : Number;
|
||||
private var videoSurface : VideoSurface;
|
||||
private var _smoothing : Boolean;
|
||||
|
||||
public function HLSMediaElement(resource : MediaResourceBase, hls : HLS, duration : Number) {
|
||||
_hls = hls;
|
||||
_defaultduration = duration;
|
||||
super(resource, new HLSNetLoader(hls));
|
||||
_hls.addEventListener(HLSEvent.ERROR, _errorHandler);
|
||||
}
|
||||
|
||||
protected function createVideo() : Video {
|
||||
return new Video();
|
||||
}
|
||||
|
||||
override protected function createLoadTrait(resource : MediaResourceBase, loader : LoaderBase) : LoadTrait {
|
||||
return new HLSNetStreamLoadTrait(_hls, _defaultduration, loader, resource);
|
||||
}
|
||||
|
||||
override protected function processLoadingState() : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSMediaElement:processLoadingState");
|
||||
}
|
||||
}
|
||||
|
||||
override protected function processReadyState() : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSMediaElement:processReadyState");
|
||||
}
|
||||
initTraits();
|
||||
}
|
||||
|
||||
override protected function processUnloadingState() : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSMediaElement:processUnloadingState");
|
||||
}
|
||||
removeTrait(MediaTraitType.AUDIO);
|
||||
removeTrait(MediaTraitType.BUFFER);
|
||||
removeTrait(MediaTraitType.TIME);
|
||||
removeTrait(MediaTraitType.DISPLAY_OBJECT);
|
||||
removeTrait(MediaTraitType.PLAY);
|
||||
removeTrait(MediaTraitType.SEEK);
|
||||
removeTrait(MediaTraitType.DYNAMIC_STREAM);
|
||||
removeTrait(MediaTraitType.DVR);
|
||||
removeTrait(MediaTraitType.ALTERNATIVE_AUDIO);
|
||||
if (videoSurface != null) {
|
||||
videoSurface.attachNetStream(null);
|
||||
videoSurface = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies whether the video should be smoothed (interpolated) when it is scaled.
|
||||
* For smoothing to work, the runtime must be in high-quality mode (the default).
|
||||
* The default value is false (no smoothing). Set this property to true to take
|
||||
* advantage of mipmapping image optimization.
|
||||
*
|
||||
* @see flash.media.Video
|
||||
*
|
||||
* @langversion 3.0
|
||||
* @playerversion Flash 10
|
||||
* @playerversion AIR 1.5
|
||||
* @productversion OSMF 1.0
|
||||
**/
|
||||
public function get smoothing() : Boolean {
|
||||
return _smoothing;
|
||||
}
|
||||
|
||||
public function set smoothing(value : Boolean) : void {
|
||||
_smoothing = value;
|
||||
if (videoSurface != null) {
|
||||
videoSurface.smoothing = value;
|
||||
}
|
||||
}
|
||||
|
||||
private function initTraits() : void {
|
||||
_stream = _hls.stream;
|
||||
|
||||
// Set the video's dimensions so that it doesn't appear at the wrong size.
|
||||
// We'll set the correct dimensions once the metadata is loaded. (FM-206)
|
||||
videoSurface = new VideoSurface(OSMFSettings.enableStageVideo && OSMFSettings.supportsStageVideo, createVideo);
|
||||
videoSurface.smoothing = true;
|
||||
videoSurface.deblocking = 1;
|
||||
videoSurface.width = videoSurface.height = 0;
|
||||
videoSurface.attachNetStream(_stream);
|
||||
|
||||
var audioTrait : AudioTrait = new NetStreamAudioTrait(_stream);
|
||||
addTrait(MediaTraitType.AUDIO, audioTrait);
|
||||
|
||||
var ccTrait : HLSClosedCaptionsTrait = new HLSClosedCaptionsTrait(_hls);
|
||||
addTrait(HLSMediaTraitType.CLOSED_CAPTIONS, ccTrait);
|
||||
|
||||
var bufferTrait : BufferTrait = new HLSBufferTrait(_hls);
|
||||
addTrait(MediaTraitType.BUFFER, bufferTrait);
|
||||
|
||||
var timeTrait : TimeTrait = new HLSTimeTrait(_hls, _defaultduration);
|
||||
addTrait(MediaTraitType.TIME, timeTrait);
|
||||
|
||||
var displayObjectTrait : HLSDisplayObjectTrait = new HLSDisplayObjectTrait(_hls,videoSurface, NaN, NaN);
|
||||
addTrait(MediaTraitType.DISPLAY_OBJECT, displayObjectTrait);
|
||||
|
||||
// setup seek trait
|
||||
var seekTrait : SeekTrait = new HLSSeekTrait(_hls, timeTrait);
|
||||
addTrait(MediaTraitType.SEEK, seekTrait);
|
||||
|
||||
if (_hls.levels.length > 1) {
|
||||
// setup dynamic stream trait
|
||||
var dsTrait : HLSDynamicStreamTrait = new HLSDynamicStreamTrait(_hls);
|
||||
addTrait(MediaTraitType.DYNAMIC_STREAM, dsTrait);
|
||||
}
|
||||
|
||||
// retrieve stream type
|
||||
var streamType : String = (resource as StreamingURLResource).streamType;
|
||||
if (streamType == StreamType.DVR) {
|
||||
// add DvrTrait
|
||||
var dvrTrait : DVRTrait = new DVRTrait(true);
|
||||
addTrait(MediaTraitType.DVR, dvrTrait);
|
||||
}
|
||||
|
||||
// setup drm trait
|
||||
// addTrait(MediaTraitType.DRM, drmTrait);
|
||||
|
||||
// setup alternative audio trait
|
||||
var alternateAudioTrait : HLSAlternativeAudioTrait = new HLSAlternativeAudioTrait(_hls, this as MediaElement);
|
||||
addTrait(MediaTraitType.ALTERNATIVE_AUDIO, alternateAudioTrait);
|
||||
|
||||
var playTrait : PlayTrait = new HLSPlayTrait(_hls);
|
||||
addTrait(MediaTraitType.PLAY, playTrait);
|
||||
}
|
||||
|
||||
private function _errorHandler(event : HLSEvent) : void {
|
||||
var errorCode : int = ErrorManager.getMediaErrorCode(event);
|
||||
var errorMsg : String = ErrorManager.getMediaErrorMessage(event);
|
||||
CONFIG::LOGGING {
|
||||
Log.warn("HLS Error event received, dispatching MediaError " + errorCode + "," + errorMsg);
|
||||
}
|
||||
dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(errorCode, errorMsg)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mangui.osmf.plugins {
|
||||
import org.mangui.hls.utils.Params2Settings;
|
||||
import org.mangui.osmf.plugins.loader.HLSLoaderBase;
|
||||
import org.mangui.osmf.plugins.loader.HLSLoadFromDocumentElement;
|
||||
import org.osmf.media.MediaElement;
|
||||
import org.osmf.media.MediaFactoryItem;
|
||||
import org.osmf.media.MediaFactoryItemType;
|
||||
import org.osmf.media.MediaResourceBase;
|
||||
import org.osmf.media.PluginInfo;
|
||||
|
||||
CONFIG::LOGGING {
|
||||
import org.mangui.hls.utils.Log;
|
||||
}
|
||||
|
||||
public class HLSPlugin extends PluginInfo {
|
||||
public function HLSPlugin(items : Vector.<MediaFactoryItem>=null, elementCreatedNotification : Function = null) {
|
||||
items = new Vector.<MediaFactoryItem>();
|
||||
items.push(new MediaFactoryItem('org.mangui.osmf.plugins.HLSPlugin', canHandleResource, createMediaElement, MediaFactoryItemType.STANDARD));
|
||||
|
||||
super(items, elementCreatedNotification);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from super class when plugin has been initialized with the MediaFactory from which it was loaded.
|
||||
* Used for customize HLSSettings with values provided in resource metadata (that was set eg. in flash vars)
|
||||
*
|
||||
* @param resource Provides acces to the resource used to load the plugin and any associated metadata
|
||||
*
|
||||
*/
|
||||
override public function initializePlugin(resource : MediaResourceBase) : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("OSMF HLSPlugin init");
|
||||
}
|
||||
metadataParamsToHLSSettings(resource);
|
||||
}
|
||||
|
||||
private function canHandleResource(resource : MediaResourceBase) : Boolean {
|
||||
return HLSLoaderBase.canHandle(resource);
|
||||
}
|
||||
|
||||
private function createMediaElement() : MediaElement {
|
||||
return new HLSLoadFromDocumentElement(null, new HLSLoaderBase());
|
||||
}
|
||||
|
||||
private function metadataParamsToHLSSettings(resource : MediaResourceBase) : void {
|
||||
if (resource == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var metadataNamespaceURLs : Vector.<String> = resource.metadataNamespaceURLs;
|
||||
|
||||
// set all legal params values to HLSSetings properties
|
||||
for each (var key : String in metadataNamespaceURLs) {
|
||||
Params2Settings.set(key, resource.getMetadataValue(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mangui.osmf.plugins.loader {
|
||||
import org.osmf.elements.proxyClasses.LoadFromDocumentLoadTrait;
|
||||
import org.osmf.events.LoadEvent;
|
||||
import org.osmf.media.MediaResourceBase;
|
||||
import org.osmf.traits.LoadState;
|
||||
import org.osmf.traits.LoadTrait;
|
||||
import org.osmf.traits.LoaderBase;
|
||||
import org.osmf.traits.MediaTraitType;
|
||||
import org.osmf.utils.OSMFStrings;
|
||||
import org.osmf.elements.ProxyElement;
|
||||
|
||||
/**
|
||||
* LoadFromDocumentElement is the base class for MediaElements that load documents
|
||||
* that contain information about the real MediaElement to expose. For example, the
|
||||
* contents of a SMIL document can be represented as a MediaElement, but until the
|
||||
* SMIL document is loaded, it's impossible to know what MediaElement the SMIL
|
||||
* document represents.
|
||||
*
|
||||
* <p>Because of the dynamic nature of this operation, a LoadFromDocumentElement extends
|
||||
* ProxyElement. When the document has been loaded, this class will set the
|
||||
* <code>proxiedElement</code> property to the MediaElement that was generated from
|
||||
* the document.</p>
|
||||
*
|
||||
* <p>This is an abstract base class, and must be subclassed.</p>
|
||||
*
|
||||
* <p>Note: It is simplest to use the MediaPlayer class in conjunction with subclasses of
|
||||
* the LoadFromDocumentElement. If you work directly with a LoadFromDocumentElement, then
|
||||
* it's important to listen for events related to traits being added and removed. If you
|
||||
* use the MediaPlayer class with a LoadFromDocumentElement, then the MediaPlayer will
|
||||
* automatically listen for these events for you.</p>
|
||||
*
|
||||
* @see org.osmf.elements.ProxyElement
|
||||
* @see org.osmf.media.MediaElement
|
||||
* @see org.osmf.media.MediaPlayer
|
||||
*
|
||||
* @langversion 3.0
|
||||
* @playerversion Flash 10
|
||||
* @playerversion AIR 1.5
|
||||
* @productversion OSMF 1.0
|
||||
*/
|
||||
public class HLSLoadFromDocumentElement extends ProxyElement {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param resource The resource associated with this element.
|
||||
* @param loader The LoaderBase used to load the resource. Cannot be null.
|
||||
*
|
||||
* @throws ArgumentError If loader is null.
|
||||
*
|
||||
* @langversion 3.0
|
||||
* @playerversion Flash 10
|
||||
* @playerversion AIR 1.5
|
||||
* @productversion OSMF 1.0
|
||||
*/
|
||||
public function HLSLoadFromDocumentElement(resource : MediaResourceBase = null, loader : LoaderBase = null) {
|
||||
super(null);
|
||||
|
||||
this.loader = loader;
|
||||
this.resource = resource;
|
||||
|
||||
if (loader == null) {
|
||||
throw new ArgumentError(OSMFStrings.getString(OSMFStrings.NULL_PARAM));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*
|
||||
* Overriding is necessary because there is a null proxiedElement.
|
||||
*/
|
||||
override public function set resource(value : MediaResourceBase) : void {
|
||||
if (_resource != value && value != null) {
|
||||
_resource = value;
|
||||
loadTrait = new LoadFromDocumentLoadTrait(loader, resource);
|
||||
loadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange, false, int.MAX_VALUE);
|
||||
|
||||
if (super.getTrait(MediaTraitType.LOAD) != null) {
|
||||
super.removeTrait(MediaTraitType.LOAD);
|
||||
}
|
||||
super.addTrait(MediaTraitType.LOAD, loadTrait);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
override public function get resource() : MediaResourceBase {
|
||||
return _resource;
|
||||
}
|
||||
|
||||
private function onLoadStateChange(event : LoadEvent) : void {
|
||||
if (event.loadState == LoadState.READY) {
|
||||
event.stopImmediatePropagation();
|
||||
|
||||
// Remove the temporary LoadTrait.
|
||||
removeTrait(MediaTraitType.LOAD);
|
||||
|
||||
// Tell the soon-to-be proxied element to load itself.
|
||||
// Note that we do this before setting it as the proxied
|
||||
// element, so as to avoid dispatching a second LOADING
|
||||
// event.
|
||||
|
||||
// Set up a listener so that we can prevent the dispatch
|
||||
// of a second LOADING event.
|
||||
var proxiedLoadTrait : LoadTrait = loadTrait.mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait;
|
||||
proxiedLoadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onProxiedElementLoadStateChange, false, int.MAX_VALUE);
|
||||
|
||||
// Expose the proxied element.
|
||||
proxiedElement = loadTrait.mediaElement;
|
||||
|
||||
// If our proxied element hasn't started loading yet, we should
|
||||
// initiate the load.
|
||||
if (proxiedLoadTrait.loadState == LoadState.UNINITIALIZED) {
|
||||
proxiedLoadTrait.load();
|
||||
}
|
||||
|
||||
function onProxiedElementLoadStateChange(event : LoadEvent) : void {
|
||||
if (event.loadState == LoadState.LOADING) {
|
||||
event.stopImmediatePropagation();
|
||||
} else {
|
||||
proxiedLoadTrait.removeEventListener(LoadEvent.LOAD_STATE_CHANGE, onProxiedElementLoadStateChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var _resource : MediaResourceBase;
|
||||
private var loadTrait : LoadFromDocumentLoadTrait;
|
||||
private var loader : LoaderBase;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mangui.osmf.plugins.loader {
|
||||
import org.mangui.hls.HLS;
|
||||
import org.mangui.hls.event.HLSEvent;
|
||||
import org.mangui.hls.model.Level;
|
||||
import org.mangui.hls.constant.HLSTypes;
|
||||
import org.mangui.osmf.plugins.HLSMediaElement;
|
||||
import org.mangui.osmf.plugins.utils.ErrorManager;
|
||||
import org.osmf.elements.proxyClasses.LoadFromDocumentLoadTrait;
|
||||
import org.osmf.events.MediaError;
|
||||
import org.osmf.events.MediaErrorEvent;
|
||||
import org.osmf.media.MediaElement;
|
||||
import org.osmf.media.MediaResourceBase;
|
||||
import org.osmf.media.URLResource;
|
||||
import org.osmf.net.DynamicStreamingItem;
|
||||
import org.osmf.net.DynamicStreamingResource;
|
||||
import org.osmf.net.StreamType;
|
||||
import org.osmf.net.StreamingURLResource;
|
||||
import org.osmf.traits.LoadState;
|
||||
import org.osmf.traits.LoadTrait;
|
||||
import org.osmf.traits.LoaderBase;
|
||||
|
||||
CONFIG::LOGGING {
|
||||
import org.mangui.hls.utils.Log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loader for .m3u8 playlist file.
|
||||
* Works like a F4MLoader
|
||||
*/
|
||||
public class HLSLoaderBase extends LoaderBase {
|
||||
private var _loadTrait : LoadTrait;
|
||||
/** Reference to the framework. **/
|
||||
private var _hls : HLS = null;
|
||||
|
||||
public function HLSLoaderBase() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static function canHandle(resource : MediaResourceBase) : Boolean {
|
||||
if (resource !== null && resource is URLResource) {
|
||||
var urlResource : URLResource = URLResource(resource);
|
||||
// check for m3u/m3u8
|
||||
if (urlResource.url.search(/(https?|file)\:\/\/.*?\m3u(\?.*)?/i) !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var contentType : Object = urlResource.getMetadataValue("content-type");
|
||||
if (contentType && contentType is String) {
|
||||
// If the filename doesn't include a .m3u or m3u8 extension, but
|
||||
// explicit content-type metadata is found on the
|
||||
// URLResource, we can handle it. Must be either of:
|
||||
// - "application/x-mpegURL"
|
||||
// - "vnd.apple.mpegURL"
|
||||
if ((contentType as String).search(/(application\/x-mpegURL|vnd.apple.mpegURL)/i) !== -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
override public function canHandleResource(resource : MediaResourceBase) : Boolean {
|
||||
return canHandle(resource);
|
||||
}
|
||||
|
||||
override protected function executeLoad(loadTrait : LoadTrait) : void {
|
||||
_loadTrait = loadTrait;
|
||||
updateLoadTrait(loadTrait, LoadState.LOADING);
|
||||
|
||||
if (_hls != null) {
|
||||
_hls.removeEventListener(HLSEvent.MANIFEST_LOADED, _manifestLoadedHandler);
|
||||
_hls.removeEventListener(HLSEvent.ERROR, _errorHandler);
|
||||
_hls.dispose();
|
||||
_hls = null;
|
||||
}
|
||||
_hls = new HLS();
|
||||
_hls.addEventListener(HLSEvent.MANIFEST_LOADED, _manifestLoadedHandler);
|
||||
_hls.addEventListener(HLSEvent.ERROR, _errorHandler);
|
||||
/* load playlist */
|
||||
_hls.load(URLResource(loadTrait.resource).url);
|
||||
}
|
||||
|
||||
override protected function executeUnload(loadTrait : LoadTrait) : void {
|
||||
updateLoadTrait(loadTrait, LoadState.UNINITIALIZED);
|
||||
}
|
||||
|
||||
/** Update video A/R on manifest load. **/
|
||||
private function _manifestLoadedHandler(event : HLSEvent) : void {
|
||||
var resource : MediaResourceBase = URLResource(_loadTrait.resource);
|
||||
|
||||
// retrieve stream type
|
||||
var streamType : String = (resource as StreamingURLResource).streamType;
|
||||
if (streamType == null || streamType == StreamType.LIVE_OR_RECORDED) {
|
||||
if (_hls.type == HLSTypes.LIVE) {
|
||||
streamType = StreamType.LIVE;
|
||||
} else {
|
||||
streamType = StreamType.RECORDED;
|
||||
}
|
||||
}
|
||||
|
||||
var levels : Vector.<Level> = _hls.levels;
|
||||
var nbLevel : int = levels.length;
|
||||
var urlRes : URLResource = resource as URLResource;
|
||||
var dynamicRes : DynamicStreamingResource = new DynamicStreamingResource(urlRes.url);
|
||||
var streamItems : Vector.<DynamicStreamingItem> = new Vector.<DynamicStreamingItem>();
|
||||
|
||||
for (var i : int = 0; i < nbLevel; i++) {
|
||||
if (levels[i].width) {
|
||||
streamItems.push(new DynamicStreamingItem(level2label(levels[i]), levels[i].bitrate / 1024, levels[i].width, levels[i].height));
|
||||
} else {
|
||||
streamItems.push(new DynamicStreamingItem(level2label(levels[i]), levels[i].bitrate / 1024));
|
||||
}
|
||||
}
|
||||
dynamicRes.streamItems = streamItems;
|
||||
dynamicRes.initialIndex = _hls.startLevel;
|
||||
resource = dynamicRes;
|
||||
// set Stream Type
|
||||
var streamUrlRes : StreamingURLResource = resource as StreamingURLResource;
|
||||
streamUrlRes.streamType = streamType;
|
||||
try {
|
||||
var loadedElem : MediaElement = new HLSMediaElement(resource, _hls, event.levels[_hls.startLevel].duration);
|
||||
LoadFromDocumentLoadTrait(_loadTrait).mediaElement = loadedElem;
|
||||
updateLoadTrait(_loadTrait, LoadState.READY);
|
||||
} catch(e : Error) {
|
||||
updateLoadTrait(_loadTrait, LoadState.LOAD_ERROR);
|
||||
_loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(e.errorID, e.message)));
|
||||
}
|
||||
};
|
||||
|
||||
private function level2label(level : Level) : String {
|
||||
if (level.name) {
|
||||
return level.name;
|
||||
} else {
|
||||
if (level.height) {
|
||||
return(level.height + 'p / ' + Math.round(level.bitrate / 1024) + 'kb');
|
||||
} else {
|
||||
return(Math.round(level.bitrate / 1024) + 'kb');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function _errorHandler(event : HLSEvent) : void {
|
||||
var errorCode : int = ErrorManager.getMediaErrorCode(event);
|
||||
var errorMsg : String = ErrorManager.getMediaErrorMessage(event);
|
||||
CONFIG::LOGGING {
|
||||
Log.warn("HLS Error event received, dispatching MediaError " + errorCode + "," + errorMsg);
|
||||
}
|
||||
updateLoadTrait(_loadTrait, LoadState.LOAD_ERROR);
|
||||
_loadTrait.dispatchEvent(new MediaErrorEvent(MediaErrorEvent.MEDIA_ERROR, false, false, new MediaError(errorCode, errorMsg)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mangui.osmf.plugins.loader {
|
||||
import flash.net.NetStream;
|
||||
import flash.net.NetConnection;
|
||||
|
||||
import org.osmf.net.NetLoader;
|
||||
import org.osmf.media.URLResource;
|
||||
import org.mangui.hls.HLS;
|
||||
|
||||
public class HLSNetLoader extends NetLoader {
|
||||
private var _hls : HLS;
|
||||
private var _connection : NetConnection;
|
||||
private var _resource : URLResource;
|
||||
|
||||
public function HLSNetLoader(hls : HLS) {
|
||||
_hls = hls;
|
||||
super();
|
||||
}
|
||||
|
||||
override protected function createNetStream(connection : NetConnection, resource : URLResource) : NetStream {
|
||||
_connection = connection;
|
||||
_resource = resource;
|
||||
return _hls.stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mangui.osmf.plugins.traits {
|
||||
import org.mangui.hls.HLS;
|
||||
import org.mangui.hls.model.AudioTrack;
|
||||
import org.mangui.hls.event.HLSEvent;
|
||||
import org.osmf.events.AlternativeAudioEvent;
|
||||
import org.osmf.media.MediaElement;
|
||||
import org.osmf.net.StreamingItem;
|
||||
import org.osmf.traits.AlternativeAudioTrait;
|
||||
import org.osmf.utils.OSMFStrings;
|
||||
|
||||
CONFIG::LOGGING {
|
||||
import org.mangui.hls.utils.Log;
|
||||
}
|
||||
public class HLSAlternativeAudioTrait extends AlternativeAudioTrait {
|
||||
private var _hls : HLS;
|
||||
private var _media : MediaElement;
|
||||
private var _audioTrackList : Vector.<AudioTrack>;
|
||||
private var _numAlternativeAudioStreams : int;
|
||||
private var _activeTransitionIndex : int = DEFAULT_TRANSITION_INDEX;
|
||||
private var _lastTransitionIndex : int = INVALID_TRANSITION_INDEX;
|
||||
|
||||
public function HLSAlternativeAudioTrait(hls : HLS, media : MediaElement) {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSAlternativeAudioTrait()");
|
||||
}
|
||||
_hls = hls;
|
||||
_audioTrackList = _hls.audioTracks;
|
||||
_numAlternativeAudioStreams = _audioTrackList.length - 1;
|
||||
super(_numAlternativeAudioStreams);
|
||||
_media = media;
|
||||
_hls.addEventListener(HLSEvent.AUDIO_TRACK_SWITCH, _audioTrackChangedHandler);
|
||||
_hls.addEventListener(HLSEvent.AUDIO_TRACKS_LIST_CHANGE, _audioTrackListChangedHandler);
|
||||
}
|
||||
|
||||
override public function dispose() : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSAlternativeAudioTrait:dispose");
|
||||
}
|
||||
_hls.removeEventListener(HLSEvent.AUDIO_TRACK_SWITCH, _audioTrackChangedHandler);
|
||||
_hls.removeEventListener(HLSEvent.AUDIO_TRACKS_LIST_CHANGE, _audioTrackListChangedHandler);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
override public function get numAlternativeAudioStreams() : int {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSAlternativeAudioTrait:numAlternativeAudioStreams:" + _numAlternativeAudioStreams);
|
||||
}
|
||||
return _numAlternativeAudioStreams;
|
||||
}
|
||||
|
||||
override public function getItemForIndex(index : int) : StreamingItem {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSDynamicStreamTrait:getItemForIndex(" + index + ")");
|
||||
}
|
||||
if (index <= INVALID_TRANSITION_INDEX || index >= numAlternativeAudioStreams) {
|
||||
throw new RangeError(OSMFStrings.getString(OSMFStrings.ALTERNATIVEAUDIO_INVALID_INDEX));
|
||||
}
|
||||
|
||||
if (index == DEFAULT_TRANSITION_INDEX) {
|
||||
return null;
|
||||
}
|
||||
var name : String = _audioTrackList[index + 1].title;
|
||||
var streamItem : StreamingItem = new StreamingItem("AUDIO", name);
|
||||
streamItem.info.label = name;
|
||||
return streamItem;
|
||||
}
|
||||
|
||||
override protected function endSwitching(index : int) : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSDynamicStreamTrait:endSwitching(" + index + ")");
|
||||
}
|
||||
if (switching) {
|
||||
executeSwitching(_indexToSwitchTo);
|
||||
}
|
||||
super.endSwitching(index);
|
||||
}
|
||||
|
||||
protected function executeSwitching(indexToSwitchTo : int) : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSDynamicStreamTrait:executeSwitching(" + indexToSwitchTo + ")");
|
||||
}
|
||||
if (_lastTransitionIndex != indexToSwitchTo) {
|
||||
_activeTransitionIndex = indexToSwitchTo;
|
||||
_hls.audioTrack = indexToSwitchTo + 1;
|
||||
}
|
||||
}
|
||||
|
||||
private function _audioTrackChangedHandler(event : HLSEvent) : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSDynamicStreamTrait:_audioTrackChangedHandler");
|
||||
}
|
||||
setSwitching(false, _activeTransitionIndex);
|
||||
_lastTransitionIndex = _activeTransitionIndex;
|
||||
}
|
||||
|
||||
private function _audioTrackListChangedHandler(event : HLSEvent) : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSDynamicStreamTrait:_audioTrackListChangedHandler");
|
||||
}
|
||||
_audioTrackList = _hls.audioTracks;
|
||||
if (_audioTrackList.length > 0) {
|
||||
// try to change default Audio Track Title for GrindPlayer ...
|
||||
if (_audioTrackList[0].title.indexOf("TS/") == -1) {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("default audio track title:" + _audioTrackList[0].title);
|
||||
}
|
||||
_media.resource.addMetadataValue("defaultAudioLabel", _audioTrackList[0].title);
|
||||
}
|
||||
}
|
||||
_numAlternativeAudioStreams = _audioTrackList.length - 1;
|
||||
if (_numAlternativeAudioStreams > 0) {
|
||||
dispatchEvent(new AlternativeAudioEvent(AlternativeAudioEvent.NUM_ALTERNATIVE_AUDIO_STREAMS_CHANGE, false, false, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mangui.osmf.plugins.traits {
|
||||
import org.mangui.hls.HLS;
|
||||
import org.mangui.hls.event.HLSEvent;
|
||||
import org.mangui.hls.constant.HLSPlayStates;
|
||||
import org.osmf.traits.BufferTrait;
|
||||
|
||||
CONFIG::LOGGING {
|
||||
import org.mangui.hls.utils.Log;
|
||||
}
|
||||
|
||||
public class HLSBufferTrait extends BufferTrait {
|
||||
private var _hls : HLS;
|
||||
|
||||
public function HLSBufferTrait(hls : HLS) {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSBufferTrait()");
|
||||
}
|
||||
super();
|
||||
_hls = hls;
|
||||
_hls.addEventListener(HLSEvent.PLAYBACK_STATE, _stateChangedHandler);
|
||||
}
|
||||
|
||||
override public function dispose() : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSBufferTrait:dispose");
|
||||
}
|
||||
_hls.removeEventListener(HLSEvent.PLAYBACK_STATE, _stateChangedHandler);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
override public function get bufferLength() : Number {
|
||||
return _hls.stream.bufferLength;
|
||||
}
|
||||
|
||||
/** state changed handler **/
|
||||
private function _stateChangedHandler(event : HLSEvent) : void {
|
||||
switch(event.state) {
|
||||
case HLSPlayStates.PLAYING_BUFFERING:
|
||||
case HLSPlayStates.PAUSED_BUFFERING:
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSBufferTrait:_stateChangedHandler:setBuffering(true)");
|
||||
}
|
||||
setBuffering(true);
|
||||
break;
|
||||
default:
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSBufferTrait:_stateChangedHandler:setBuffering(false)");
|
||||
}
|
||||
setBuffering(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.mangui.osmf.plugins.traits
|
||||
{
|
||||
public final class HLSClosedCaptionsState
|
||||
{
|
||||
public static const YES:String = "yes";
|
||||
public static const NO:String = "no";
|
||||
public static const UNKNOWN:String = "unknown";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mangui.osmf.plugins.traits {
|
||||
import org.mangui.hls.HLS;
|
||||
import org.mangui.hls.event.HLSEvent;
|
||||
import org.mangui.hls.model.Level;
|
||||
import org.osmf.traits.MediaTraitBase;
|
||||
|
||||
CONFIG::LOGGING {
|
||||
import org.mangui.hls.utils.Log;
|
||||
}
|
||||
|
||||
public class HLSClosedCaptionsTrait extends MediaTraitBase {
|
||||
private var _hls : HLS;
|
||||
private var _hasClosedCapations : String;
|
||||
|
||||
public function HLSClosedCaptionsTrait(hls : HLS, closed_captions : String = HLSClosedCaptionsState.UNKNOWN) {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSClosedCaptionsTrait()");
|
||||
}
|
||||
super(HLSMediaTraitType.CLOSED_CAPTIONS);
|
||||
|
||||
_hasClosedCapations = closed_captions;
|
||||
_hls = hls;
|
||||
_hls.addEventListener(HLSEvent.LEVEL_SWITCH, _levelSwitchHandler);
|
||||
}
|
||||
|
||||
override public function dispose() : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSClosedCaptionsTrait:dispose");
|
||||
}
|
||||
_hls.removeEventListener(HLSEvent.LEVEL_SWITCH, _levelSwitchHandler);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public function hasClosedCaptions() : String {
|
||||
return _hasClosedCapations;
|
||||
}
|
||||
|
||||
/** Update playback position/duration **/
|
||||
private function _levelSwitchHandler(event : HLSEvent) : void {
|
||||
var cc : String = (_hls.levels[event.level] as Level).closed_captions;
|
||||
|
||||
if (cc && cc === "NONE")
|
||||
{
|
||||
// manifest told us to ignore any 608/708 binary
|
||||
_hasClosedCapations = HLSClosedCaptionsState.NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
_hasClosedCapations = HLSClosedCaptionsState.UNKNOWN;
|
||||
}
|
||||
|
||||
// YES only happens for WebVTT, which isn't supported.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mangui.osmf.plugins.traits {
|
||||
|
||||
import flash.display.DisplayObject;
|
||||
import flash.display.Stage;
|
||||
import flash.events.Event;
|
||||
|
||||
import org.mangui.hls.HLS;
|
||||
import org.osmf.media.videoClasses.VideoSurface;
|
||||
import org.osmf.traits.DisplayObjectTrait;
|
||||
|
||||
CONFIG::LOGGING {
|
||||
import org.mangui.hls.utils.Log;
|
||||
}
|
||||
|
||||
public class HLSDisplayObjectTrait extends DisplayObjectTrait {
|
||||
private var videoSurface : VideoSurface;
|
||||
private var _hls : HLS;
|
||||
|
||||
public function HLSDisplayObjectTrait(hls : HLS, videoSurface : DisplayObject, mediaWidth : int = 0, mediaHeight : int = 0) {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSDisplayObjectTrait()");
|
||||
}
|
||||
_hls = hls;
|
||||
super(videoSurface, mediaWidth, mediaHeight);
|
||||
this.videoSurface = videoSurface as VideoSurface;
|
||||
|
||||
if (this.videoSurface is VideoSurface)
|
||||
this.videoSurface.addEventListener(Event.ADDED_TO_STAGE, onStage);
|
||||
}
|
||||
|
||||
override public function dispose() : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSDisplayObjectTrait:dispose");
|
||||
}
|
||||
videoSurface.removeEventListener(Event.ENTER_FRAME, onFrame);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private function onStage(event : Event) : void {
|
||||
_hls.stage = event.target.stage as Stage;
|
||||
videoSurface.removeEventListener(Event.ADDED_TO_STAGE, onStage);
|
||||
videoSurface.addEventListener(Event.ENTER_FRAME, onFrame);
|
||||
}
|
||||
|
||||
private function onFrame(event : Event) : void {
|
||||
var newWidth : int = videoSurface.videoWidth;
|
||||
var newHeight : int = videoSurface.videoHeight;
|
||||
if (newWidth != 0 && newHeight != 0 && (newWidth != mediaWidth || newHeight != mediaHeight)) {
|
||||
// If there is no layout, set as no scale.
|
||||
if (videoSurface.width == 0 && videoSurface.height == 0) {
|
||||
videoSurface.width = newWidth;
|
||||
videoSurface.height = newHeight;
|
||||
}
|
||||
CONFIG::LOGGING {
|
||||
Log.info("HLSDisplayObjectTrait:setMediaSize(" + newWidth + "," + newHeight + ")");
|
||||
}
|
||||
setMediaSize(newWidth, newHeight);
|
||||
}
|
||||
// videoSurface.removeEventListener(Event.ENTER_FRAME, onFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mangui.osmf.plugins.traits {
|
||||
import org.mangui.hls.HLS;
|
||||
import org.mangui.hls.event.HLSEvent;
|
||||
import org.osmf.traits.DynamicStreamTrait;
|
||||
import org.osmf.utils.OSMFStrings;
|
||||
|
||||
CONFIG::LOGGING {
|
||||
import org.mangui.hls.utils.Log;
|
||||
}
|
||||
|
||||
public class HLSDynamicStreamTrait extends DynamicStreamTrait {
|
||||
private var _hls : HLS;
|
||||
|
||||
public function HLSDynamicStreamTrait(hls : HLS) {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSDynamicStreamTrait()");
|
||||
}
|
||||
_hls = hls;
|
||||
_hls.addEventListener(HLSEvent.LEVEL_SWITCH, _levelSwitchHandler);
|
||||
super(true, _hls.startLevel, hls.levels.length);
|
||||
}
|
||||
|
||||
override public function dispose() : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSDynamicStreamTrait:dispose");
|
||||
}
|
||||
_hls.removeEventListener(HLSEvent.LEVEL_SWITCH, _levelSwitchHandler);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
override public function getBitrateForIndex(index : int) : Number {
|
||||
if (index > numDynamicStreams - 1 || index < 0) {
|
||||
throw new RangeError(OSMFStrings.getString(OSMFStrings.STREAMSWITCH_INVALID_INDEX));
|
||||
}
|
||||
var bitrate : Number = _hls.levels[index].bitrate / 1000;
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSDynamicStreamTrait:getBitrateForIndex(" + index + ")=" + bitrate);
|
||||
}
|
||||
return bitrate;
|
||||
}
|
||||
|
||||
override public function switchTo(index : int) : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSDynamicStreamTrait:switchTo(" + index + ")/max:" + maxAllowedIndex);
|
||||
}
|
||||
if (index < 0 || index > maxAllowedIndex) {
|
||||
throw new RangeError(OSMFStrings.getString(OSMFStrings.STREAMSWITCH_INVALID_INDEX));
|
||||
}
|
||||
autoSwitch = false;
|
||||
if (!switching) {
|
||||
setSwitching(true, index);
|
||||
}
|
||||
}
|
||||
|
||||
override protected function autoSwitchChangeStart(value : Boolean) : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSDynamicStreamTrait:autoSwitchChangeStart:" + value);
|
||||
}
|
||||
if (value == true && _hls.autoLevel == false) {
|
||||
_hls.nextLevel = -1;
|
||||
}
|
||||
}
|
||||
|
||||
override protected function switchingChangeStart(newSwitching : Boolean, index : int) : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSDynamicStreamTrait:switchingChangeStart(newSwitching/index):" + newSwitching + "/" + index);
|
||||
}
|
||||
if (newSwitching) {
|
||||
_hls.currentLevel = index;
|
||||
}
|
||||
}
|
||||
|
||||
/** Update playback position/duration **/
|
||||
private function _levelSwitchHandler(event : HLSEvent) : void {
|
||||
var newLevel : int = event.level;
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSDynamicStreamTrait:_qualitySwitchHandler:" + newLevel);
|
||||
}
|
||||
setCurrentIndex(newLevel);
|
||||
setSwitching(false, newLevel);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.mangui.osmf.plugins.traits
|
||||
{
|
||||
public final class HLSMediaTraitType
|
||||
{
|
||||
public static const CLOSED_CAPTIONS:String = "hlsClosedCaptions";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mangui.osmf.plugins.traits {
|
||||
import org.mangui.hls.HLS;
|
||||
import org.mangui.hls.event.HLSEvent;
|
||||
import org.osmf.media.MediaResourceBase;
|
||||
import org.osmf.net.NetStreamLoadTrait;
|
||||
import org.osmf.traits.LoaderBase;
|
||||
|
||||
CONFIG::LOGGING {
|
||||
import org.mangui.hls.utils.Log;
|
||||
}
|
||||
|
||||
public class HLSNetStreamLoadTrait extends NetStreamLoadTrait {
|
||||
private var _hls : HLS;
|
||||
private var _timeLoaded : Number;
|
||||
private var _timeTotal : Number;
|
||||
|
||||
public function HLSNetStreamLoadTrait(hls : HLS, duration : Number, loader : LoaderBase, resource : MediaResourceBase) {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSNetStreamLoadTrait()");
|
||||
}
|
||||
super(loader, resource);
|
||||
_hls = hls;
|
||||
_timeLoaded = 0;
|
||||
_timeTotal = duration;
|
||||
super.netStream = _hls.stream;
|
||||
_hls.addEventListener(HLSEvent.MEDIA_TIME, _mediaTimeHandler);
|
||||
}
|
||||
|
||||
override public function dispose() : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSNetStreamLoadTrait:dispose");
|
||||
}
|
||||
_hls.removeEventListener(HLSEvent.MEDIA_TIME, _mediaTimeHandler);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
override public function get bytesLoaded() : Number {
|
||||
return _timeLoaded;
|
||||
}
|
||||
|
||||
override public function get bytesTotal() : Number {
|
||||
return _timeTotal;
|
||||
}
|
||||
|
||||
public function get hls() : HLS {
|
||||
return _hls;
|
||||
}
|
||||
|
||||
/** **/
|
||||
private function _mediaTimeHandler(event : HLSEvent) : void {
|
||||
var timeTotal : Number = Math.round(10 * event.mediatime.duration) / 10;
|
||||
var timeLoaded : Number = Math.max(0,Math.round(10 * (event.mediatime.position + event.mediatime.buffer)) / 10);
|
||||
|
||||
if (_timeTotal != timeTotal) {
|
||||
if (timeTotal < _timeLoaded || timeTotal < 0) {
|
||||
timeTotal = NaN;
|
||||
}
|
||||
_timeTotal = timeTotal;
|
||||
setBytesTotal(timeTotal);
|
||||
}
|
||||
|
||||
if (_timeLoaded != timeLoaded && timeLoaded <= timeTotal) {
|
||||
_timeLoaded = timeLoaded;
|
||||
setBytesLoaded(timeLoaded);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mangui.osmf.plugins.traits {
|
||||
import org.mangui.hls.HLS;
|
||||
import org.mangui.hls.constant.HLSPlayStates;
|
||||
import org.mangui.hls.event.HLSEvent;
|
||||
import org.osmf.traits.PlayState;
|
||||
import org.osmf.traits.PlayTrait;
|
||||
|
||||
CONFIG::LOGGING {
|
||||
import org.mangui.hls.utils.Log;
|
||||
}
|
||||
|
||||
public class HLSPlayTrait extends PlayTrait {
|
||||
private var _hls : HLS;
|
||||
private var streamStarted : Boolean = false;
|
||||
|
||||
public function HLSPlayTrait(hls : HLS) {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSPlayTrait()");
|
||||
}
|
||||
super();
|
||||
_hls = hls;
|
||||
_hls.addEventListener(HLSEvent.PLAYBACK_STATE, _stateChangedHandler);
|
||||
_hls.addEventListener(HLSEvent.PLAYBACK_COMPLETE, _playbackComplete);
|
||||
}
|
||||
|
||||
override public function dispose() : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSPlayTrait:dispose");
|
||||
}
|
||||
_hls.removeEventListener(HLSEvent.PLAYBACK_STATE, _stateChangedHandler);
|
||||
_hls.removeEventListener(HLSEvent.PLAYBACK_COMPLETE, _playbackComplete);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
override protected function playStateChangeStart(newPlayState:String):void {
|
||||
CONFIG::LOGGING {
|
||||
Log.info("HLSPlayTrait:playStateChangeStart:" + newPlayState);
|
||||
}
|
||||
switch (newPlayState) {
|
||||
case PlayState.PLAYING:
|
||||
if (!streamStarted) {
|
||||
_hls.stream.play();
|
||||
streamStarted = true;
|
||||
}
|
||||
else {
|
||||
_hls.stream.resume();
|
||||
}
|
||||
break;
|
||||
case PlayState.PAUSED:
|
||||
_hls.stream.pause();
|
||||
break;
|
||||
case PlayState.STOPPED:
|
||||
streamStarted = false;
|
||||
_hls.stream.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** state changed handler **/
|
||||
private function _stateChangedHandler(event:HLSEvent):void {
|
||||
switch (event.state) {
|
||||
case HLSPlayStates.PLAYING:
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSPlayTrait:_stateChangedHandler:setBuffering(true)");
|
||||
}
|
||||
if (!streamStarted) {
|
||||
streamStarted = true;
|
||||
play();
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
/** playback complete handler **/
|
||||
private function _playbackComplete(event : HLSEvent) : void {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mangui.osmf.plugins.traits {
|
||||
import org.mangui.hls.HLS;
|
||||
import org.mangui.hls.event.HLSEvent;
|
||||
import org.mangui.hls.constant.HLSSeekStates;
|
||||
import org.osmf.traits.SeekTrait;
|
||||
import org.osmf.traits.TimeTrait;
|
||||
|
||||
CONFIG::LOGGING {
|
||||
import org.mangui.hls.utils.Log;
|
||||
}
|
||||
|
||||
public class HLSSeekTrait extends SeekTrait {
|
||||
private var _hls : HLS;
|
||||
|
||||
public function HLSSeekTrait(hls : HLS, timeTrait : TimeTrait) {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSSeekTrait()");
|
||||
}
|
||||
super(timeTrait);
|
||||
_hls = hls;
|
||||
_hls.addEventListener(HLSEvent.SEEK_STATE, _stateChangedHandler);
|
||||
}
|
||||
|
||||
override public function dispose() : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSSeekTrait:dispose");
|
||||
}
|
||||
_hls.removeEventListener(HLSEvent.SEEK_STATE, _stateChangedHandler);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Communicates a <code>seeking</code> change to the media through the NetStream.
|
||||
* @param newSeeking New <code>seeking</code> value.
|
||||
* @param time Time to seek to, in seconds.
|
||||
*/
|
||||
override protected function seekingChangeStart(newSeeking : Boolean, time : Number) : void {
|
||||
if (newSeeking) {
|
||||
CONFIG::LOGGING {
|
||||
Log.info("HLSSeekTrait:seekingChangeStart(newSeeking/time):(" + newSeeking + "/" + time + ")");
|
||||
}
|
||||
_hls.stream.seek(time);
|
||||
}
|
||||
super.seekingChangeStart(newSeeking, time);
|
||||
}
|
||||
|
||||
/** state changed handler **/
|
||||
private function _stateChangedHandler(event : HLSEvent) : void {
|
||||
if (seeking && event.state != HLSSeekStates.SEEKING) {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSSeekTrait:setSeeking(false);");
|
||||
}
|
||||
setSeeking(false, timeTrait.currentTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mangui.osmf.plugins.traits {
|
||||
import org.mangui.hls.HLS;
|
||||
import org.mangui.hls.constant.HLSTypes;
|
||||
import org.mangui.hls.event.HLSEvent;
|
||||
import org.osmf.traits.TimeTrait;
|
||||
import org.osmf.events.TimeEvent;
|
||||
|
||||
CONFIG::LOGGING {
|
||||
import org.mangui.hls.utils.Log;
|
||||
}
|
||||
|
||||
public class HLSTimeTrait extends TimeTrait {
|
||||
private var _hls : HLS;
|
||||
|
||||
public function HLSTimeTrait(hls : HLS, duration : Number = 0) {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSTimeTrait()");
|
||||
}
|
||||
super(duration);
|
||||
setCurrentTime(0);
|
||||
_hls = hls;
|
||||
_hls.addEventListener(HLSEvent.MEDIA_TIME, _mediaTimeHandler);
|
||||
_hls.addEventListener(HLSEvent.PLAYBACK_COMPLETE, _playbackComplete);
|
||||
}
|
||||
|
||||
override public function dispose() : void {
|
||||
CONFIG::LOGGING {
|
||||
Log.debug("HLSTimeTrait:dispose");
|
||||
}
|
||||
_hls.removeEventListener(HLSEvent.MEDIA_TIME, _mediaTimeHandler);
|
||||
_hls.removeEventListener(HLSEvent.PLAYBACK_COMPLETE, _playbackComplete);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
override protected function signalComplete():void
|
||||
{
|
||||
// live streams shouldn't end based on TimeTrait
|
||||
if (_hls.type !== HLSTypes.LIVE)
|
||||
{
|
||||
dispatchEvent(new TimeEvent(TimeEvent.COMPLETE));
|
||||
}
|
||||
}
|
||||
|
||||
/** Update playback position/duration **/
|
||||
private function _mediaTimeHandler(event : HLSEvent) : void {
|
||||
var newDuration : Number = event.mediatime.duration;
|
||||
var newPosition : Number = Math.max(0, event.mediatime.position);
|
||||
setDuration(newDuration);
|
||||
setCurrentTime(newPosition);
|
||||
};
|
||||
|
||||
/** playback complete handler **/
|
||||
private function _playbackComplete(event : HLSEvent) : void {
|
||||
signalComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mangui.osmf.plugins.utils {
|
||||
import org.mangui.hls.event.HLSError;
|
||||
import org.mangui.hls.event.HLSEvent;
|
||||
import org.osmf.events.MediaErrorCodes;
|
||||
|
||||
public class ErrorManager {
|
||||
|
||||
public static function getMediaErrorCode(event : HLSEvent) : int {
|
||||
var errorCode : int = MediaErrorCodes.NETSTREAM_PLAY_FAILED;
|
||||
if (event && event.error) {
|
||||
switch (event.error.code) {
|
||||
case HLSError.FRAGMENT_LOADING_ERROR:
|
||||
case HLSError.KEY_LOADING_ERROR:
|
||||
case HLSError.MANIFEST_LOADING_IO_ERROR:
|
||||
errorCode = MediaErrorCodes.IO_ERROR;
|
||||
break;
|
||||
case HLSError.FRAGMENT_LOADING_CROSSDOMAIN_ERROR:
|
||||
case HLSError.KEY_LOADING_CROSSDOMAIN_ERROR:
|
||||
case HLSError.MANIFEST_LOADING_CROSSDOMAIN_ERROR:
|
||||
errorCode = MediaErrorCodes.SECURITY_ERROR
|
||||
break;
|
||||
case org.mangui.hls.event.HLSError.FRAGMENT_PARSING_ERROR:
|
||||
case org.mangui.hls.event.HLSError.KEY_PARSING_ERROR:
|
||||
case org.mangui.hls.event.HLSError.MANIFEST_PARSING_ERROR:
|
||||
errorCode = MediaErrorCodes.NETSTREAM_FILE_STRUCTURE_INVALID;
|
||||
break;
|
||||
case org.mangui.hls.event.HLSError.TAG_APPENDING_ERROR:
|
||||
errorCode = MediaErrorCodes.ARGUMENT_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return errorCode;
|
||||
};
|
||||
|
||||
public static function getMediaErrorMessage(event : HLSEvent) : String {
|
||||
return (event && event.error) ? event.error.msg : "Unknown error";
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user