假设我的测试场景代表了您的用例,我想我设法解决了问题。
该方法的要点是用您控制的假舞台对象替换RootReference.root
和。RootReference.stage
因为大多数 jwPlayer 类都引用这些静态变量而不是它们自己的变量root
和stage
变量,所以这似乎在大多数情况下都有效。最终成为最复杂的问题是使用Stage.stageVideo
对象,我认为这是硬件加速的视频对象。这些总是附加到stage
,因此与假舞台对象不兼容。这些的主要问题是定位,我基本上已经解决了,但仍有一个故障,我稍后会描述,但现在应该没问题。
jwPlayer 嵌入脚本引起了很多问题,所以开始时我切换到普通的基于 SWFObject 的嵌入,并在页面中添加了一个 JavaScript 函数,调用getFlashvars()
该函数返回配置设置。然后,我将com.longtailvideo.jwplayer.utils.Configger.loadExternal()
方法更改为以下内容:
private function loadExternal():void {
if (ExternalInterface.available) {
try {
//var flashvars:Object = ExternalInterface.call("jwplayer.embed.flash.getVars", ExternalInterface.objectID);
var flashvars:Object = ExternalInterface.call("getFlashvars");
if (flashvars !== null) {
// TODO: add ability to pass in JSON directly instead of going to/from a string
for (var param:String in flashvars) {
setConfigParam(param, flashvars[param]);
}
dispatchEvent(new Event(Event.COMPLETE));
return;
}
} catch (e:Error) {}
}
}
如果不使用网页,您可能不必处理这些问题。
假舞台类被称为StageInterceptor
并且是一个单例。为了应用它,类中有一些小的变化RootReference
:
package com.longtailvideo.jwplayer.utils {
import flash.display.DisplayObject;
import flash.display.Stage;
import flash.system.Security;
// added --------
import somePackage.StageInterceptor;
/**
* Maintains a static reference to the stage and root of the application.
*
* @author Pablo Schklowsky
*/
/* Modified for a stackoverflow question: http://stackoverflow.com/questions/13325318/jwplayer-trying-to-bound-the-video-player-inside-my-own-container */
public class RootReference {
/** The root DisplayObject of the application. **/
public static var root:DisplayObject;
// altered --------
/** A reference to the stage. **/
private static var _stage:StageInterceptor;
// altered --------
public static function get stage():StageInterceptor {
return _stage;
}
public function RootReference(displayObj:DisplayObject) {
if (!RootReference.root) {
// altered --------
RootReference.root = StageInterceptor.singleton;
RootReference._stage = StageInterceptor.singleton;
try {
Security.allowDomain("*");
} catch(e:Error) {
// This may not work in the AIR testing suite
}
}
}
}
}
另外,我set stage()
从类中删除了 setter 方法。
在文档类中,我有以下代码。该MouseEvent.CLICK
处理程序用于测试电影的定位和调整大小。您真正需要的只是前几行:
// add StageInterceptor to the display tree
addChild(StageInterceptor.singleton);
// add the jwPlayer:
var p:Player = new Player();
StageInterceptor.singleton.addChild(p);
// for testing only:
stage.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void {
var stg:StageInterceptor = StageInterceptor.singleton;
if (e.altKey) {
// click + alt: ignored (so can play, etc)
return;
} else if (e.shiftKey) {
// click + shift: resizes
stg.width = e.stageX - stg.x;
stg.height = e.stageY - stg.y;
} else {
// click: moves video
stg.x = e.stageX;
stg.y = e.stageY;
}
});
我放进StageInterceptor
了包裹里somePackage
。它看起来像这样:
package somePackage
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.InteractiveObject;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.media.StageVideo;
public class StageInterceptor extends Sprite
{
private static var _singleton:StageInterceptor = new StageInterceptor();
public static function get singleton():StageInterceptor {
return _singleton;
}
private var _bg:Bitmap;
public function StageInterceptor()
{
super();
scrollRect = new Rectangle(0, 0, 500, 500);
var bmpData:BitmapData = new BitmapData(500, 500, false, 0);
_bg = new Bitmap(bmpData);
_bg.alpha = 0.1;
_bg.cacheAsBitmap = true;
addChild(_bg);
if (stage) {
initOnStage();
} else {
addEventListener(Event.ADDED_TO_STAGE, initOnStage);
}
}
private function initOnStage(e:Event = null):void {
if (e) {
removeEventListener(Event.ADDED_TO_STAGE, initOnStage);
}
stage.addEventListener(Event.RESIZE, onStageResized);
}
private function onStageResized(e:Event):void {
e.stopImmediatePropagation();
dispatchEvent(new Event(Event.RESIZE));
updateStageVids();
}
public function updateStageVids():void {
if (stage.stageVideos.length > 0) {
for each (var sv:StageVideo in stage.stageVideos) {
if (!sv.videoWidth || !sv.videoHeight) {
continue;
}
var rect:Rectangle = stretch(sv.videoWidth, sv.videoHeight, width, height);
rect.x = Math.max(0, x + 0.5 * (width - rect.width))
rect.y = Math.max(0, y + 0.5 * (height - rect.height));
sv.viewPort = rect;
}
}
}
override public function get width():Number {
return scrollRect.width;
}
override public function set width(value:Number):void {
if (value != width) {
_bg.width = value;
scrollRect = new Rectangle(0, 0, value, scrollRect.height);
dispatchEvent(new Event(Event.RESIZE));
updateStageVids();
}
}
override public function set height(value:Number):void {
if (value != height) {
_bg.height = value;
scrollRect = new Rectangle(0, 0, scrollRect.width, value);
dispatchEvent(new Event(Event.RESIZE));
updateStageVids();
}
}
override public function get height():Number {
return scrollRect.height;
}
public function get stageWidth():Number {
return scrollRect.width;
}
public function get stageHeight():Number {
return scrollRect.height;
}
public function get scaleMode():String {
return stage.scaleMode;
}
public function set scaleMode(value:String):void {
stage.scaleMode = value;
}
public function get displayState():String {
return stage.displayState;
}
public function set displayState(value:String):void {
stage.displayState = value;
}
public function get focus():InteractiveObject {
return stage.focus;
}
public function set focus(value:InteractiveObject):void {
stage.focus = value;
}
public function get stageVideos():* {
return stage.stageVideos;
}
override public function set x(value:Number):void {
if (value != x) {
super.x = value;
updateStageVids();
}
}
override public function set y(value:Number):void {
if (value != y) {
super.y = value;
updateStageVids();
}
}
/**
* Copied from com.longtailvideo.jwplayer.utils.Stretcher, modified to only
* do 'uniform' stretch and to return a Rectangle class.
**/
public static function stretch(elmW:Number, elmH:Number, availW:Number, availH:Number):Rectangle {
var scale:Number = Math.min(availW / elmW, availH / elmH);
elmW = Math.round(elmW * scale);
elmH = Math.round(elmH * scale);
return new Rectangle(0, 0, elmW, elmH);
}
}
}
剩下的问题与初始化视频实例时的定位有关。我认为只需StageInterceptor.singleton.updateStageVids();
在正确的时间点调用就可以了,但我不确定。下面的编辑介绍了如何解决这个问题。
如果您不使用stageVideo
. 但是,如果运气好的话,这将使事情朝着正确的方向发展。
编辑:
我已经更新了StageInterceptor
课程以更好地缩放和定位视频。
此外,看起来视频的初始位置(至少当它是 stageVideo 时,是你正在使用的吗?)可以通过com.longtailvideo.jwplayer.media.VideoMediaProvider
类中的小编辑来纠正。添加import somePackage.StageInterceptor;
到顶部的导入语句,然后替换此行(链接到源代码):
_stage.viewPort = new Rectangle(_media.x,_media.y,_media.width,_media.height);
到:
StageInterceptor.singleton.updateStageVids();
所以方法看起来像:
/** Resize the video or stage.**/
override public function resize(width:Number, height:Number):void {
if(_media) {
Stretcher.stretch(_media, width, height, _config.stretching);
if (_stage) {
//_stage.viewPort = new Rectangle(_media.x,_media.y,_media.width,_media.height);
StageInterceptor.singleton.updateStageVids();
}
}
}
这应该可以解决问题,但我还没有为非 stageVideos 测试过它。而且,此更新还假设您正在逐步播放视频,而不是使用 RTMP 媒体。
编辑:
要使用非 StageVideo 视频启用播放器的移动和调整大小,但仍会逐步加载,com.longtailvideo.jwplayer.view.View.resizeMasker()
需要注释掉或删除该方法的内容:
protected function resizeMasker():void {
/*
if (_displayMasker == null)
setupDisplayMask();
_displayMasker.graphics.clear();
_displayMasker.graphics.beginFill(0, 1);
_displayMasker.graphics.drawRect(_components.display.x, _components.display.y, _player.config.width, _player.config.height);
_displayMasker.graphics.endFill();
*/
}
我还想提一下 jwPlayer 的开源版本受知识共享许可管理,如其网站上所述:
JW Player 6 — 开源版 JW Player 开源版的使用受知识共享许可的约束。简而言之:
JW Player 开源 - 您可以使用、修改、复制和分发此版本,只要它用于非商业用途,您提供署名并在类似许可下共享。许可证摘要和全文可在此处找到:CC BY-NC-SA 3.0