私のテスト シナリオがユース ケースを代表するものであると仮定すると、回避策をうまくハックできたと思います。
RootReference.root
アプローチの要点は、 andRootReference.stage
を自分が制御する偽のステージ オブジェクトに置き換えることです。ほとんどの jwPlayer クラスは、独自の変数root
やstage
変数ではなく静的変数を参照するため、ほとんどの場合、これでうまくいくようです。最終的に最も複雑な問題となったのStage.stageVideo
は、ハードウェア アクセラレーション ビデオ オブジェクトであると思われるオブジェクトの操作でした。これらは常に にアタッチされているためstage
、フェイク ステージ オブジェクトと互換性がありませんでした。これらの主な問題はポジショニングで、ほぼ解決しましたが、まだ 1 つの不具合があります。これについては後で説明しますが、今は問題ありません。
jwPlayer 埋め込みスクリプトが多くの問題を引き起こしていたので、まず通常の SWFObject ベースの埋め込みに切り替え、呼び出したページgetFlashvars()
に構成設定を返す JavaScript 関数を追加しました。次に、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) {}
}
}
これは、Web ページを使用していないため、おそらく対処する必要がないものです。
偽のステージ クラスが呼び出され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 ステートメントに追加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();
}
}
}
これでうまくいくはずですが、ステージビデオ以外ではテストしていません。また、この更新では、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