JWPlayer:尝试将视频播放器绑定在我自己的容器中

时间:2012-11-10 19:26:00

标签: actionscript-3 flash actionscript jwplayer

我正在使用6.0.2813(http://developer.longtailvideo.com/trac/)的JWPlayer源代码,虽然我有一个movieclip,但我将jwplayer类作为一个孩子添加,jwplayer创建自己作为主舞台的孩子,从而允许它扩展到舞台的边界,而不是我的影片剪辑(我想成为一个可调整大小/可拖动的容器)。

我向论坛寻求帮助,但是他们说他们从来没有打算这样做,并没有多大帮助。我希望有人熟悉源代码可以指出我的方向正确。

如何将JWPlayer包含在movieclip中?

编辑:

我取得了一些进展。

我在com / longtailvideo / jwplayer / utils / RootReference.as中找到了RootReference类

        public function RootReference(displayObj:DisplayObject) {
            if (!RootReference.root) {
                RootReference.root = displayObj.root;
                RootReference.stage = displayObj.stage;
                try {
                    Security.allowDomain("*");
                } catch(e:Error) {
                    // This may not work in the AIR testing suite
                }
            }
        }

并注意到RootReference.stage是作为孩子添加内容的地方。将玩家类对象作为displayObj发送的RootReference.stage = displayObj.stage;我将其更改为RootReference.stage = MovieClip(root).gui.video_container;

然后在整个代码中使用了RootReference.stage.stageHeightRootReference.stage.stageWidth,因此我将其切换为RootReference.stage.heightRootReference.stage.width。这得到它编译,现在视频在容器内,但视频的左上角是我的video_container中心的中心,视频没有调整到我的容器的大小,而是视频的大小。控制也完全搞砸了。

但我能够调整大小并移动视频

3 个答案:

答案 0 :(得分:2)

我会解决你问题的 jwPlayer 部分,因为flash不是我的强项。

这里的问题是jwPlayer不是简单的Flash播放器,也是 HTML5多媒体播放器


解决方案1:Flash对象中的SWFObject 嵌入式

由于 jwPlayer 已与SWFObject兼容,请将其(即swfobject.js)用作 介体 player.swf文件( aka jwPlayer )加载到您的Flash阶段。可以肯定的是, SWFObject 充当容器,并且将成为" 有界项"在你的舞台上,而不是直接使用 jwPlayer

以下是一个在线演示,说明此解决方案 使用简单的Flash视频播放器。

Flash Web Site with embedded SWFObject Logo Playing Music Video
Flash Web Site Documentation on swfObject

请注意,该Flash网站的HTML source page会将RockOnFlashLogo.swf显示为浏览器整个视口中显示的文件。看deeper,它是用 AS3 写的。

jwPlayer v4 不同,由于其安全性不高,internet上有许多想法可以将该版本嵌入到Flash网站中,我认为您是'会遇到当前 jwPlayer 许可检查,网页就绪事件监听器以及流行的插件集成问题......更不用说流视频内容可能引起的问题。

恕我直言,较新的 jwPlayer API和播放器旨在通过 网页安装 来使用。


解决方案2:Flash对象的SWFObject On-Top

此方法将 jwPlayer 视为如何使用;作为网页安装。我的动机来自Google Chrome Experiment | The Wilderness Downtown的在线演示。

该演示在主浏览器窗口的顶部放置了战略性同步的浏览器窗口。虽然主浏览器窗口负责, 所有窗口构成了整个体验 。同样的方法,但闪存风味,可以使用您当前的项目完成,效果非常好。

您的Flash对象负责且包含为jwPlayer 网页组件 分配的交互式frame。可以肯定的是, jwPlayer 的交互式框架可以接受重新定位,例如,通过拖动框架边缘)和调整大小例如,框架有resize-icon bottom-right ),然后将其转发到网页组件(,{{1} } )通过 SWFObject 标准嵌入技术(位置尺寸设置为player.swf )。

以下是三个分层项目的网页的基本 横截面

enter image description here

黑色图层是网页的jQuery红色图层是您的Flash对象,其中还包含 aqua 中显示的内置交互式框架。 绿色顶层是 jwPlayer HTML文件的 SWFObject

以下是从jwPlayer到您的Flash对象的工作方式:

1。 网页 jwPlayer API 事件监听器处于活动状态,可以接受JavaScript。
2。 然后 jwPlayer API 接收' play'来自玩家的状态,更新玩家活动状态。
3。 播放器的播放器事件状态为 true ,因此触发器条件player.swf言。
4. if语句,然后将JavaScript 传输到您的Flash对象,表示播放模式为true。
5. 您的Flash对象接收播放事件的JavaScript, dims 舞台,水色框架。

以下是从flash对象到jwPlayer的工作方式:

1。 当aqua 框架移至用户互动时舞台的左侧。
2。 您的 AS3 代码相应地移动了aqua 框架,而发送 >该位置的JavaScript。
3。 网页接收 JavaScript并调用函数将jwPlayer播放器置于位置。

提示: 如果使用自定义 jwPlayer Skin ,请将皮肤主题合并到您的闪存中用于统一外观的对象。

此方案的好处是 jwPlayer 维持 100%完整性 ,而这两个Flash对象协同工作在您的网页上。没有黑客攻击,没有破损,没有不可预见的后果,也没有头痛......它正在使用标准的 jwPlayer API AS3 标记。

将鼠标悬停在 jwPlayer 本身 100%jwPlayer ,间接绑定到您的Flash对象。

答案 1 :(得分:2)

根据您的书面评论, JW Player 将无法访问JavaScript,并且将使用Firefox Source 专用的3D Game/Chat Engine 访问播放器外的任何DOM元素,最佳解决方案是使用 JW Player Enterprise Edition

该解决方案可让您与 Marketing&工程部门,可提供交钥匙解决方案,将JW Player 集成到您自己的产品中。

点击下面的图片,其中包括许可信息: enter image description here

答案 2 :(得分:2)

假设我的测试场景代表了您的用例,我认为我设法破解了一个解决方案。

该方法的要点是将RootReference.rootRootReference.stage替换为您控制的假舞台对象。因为大多数jwPlayer类引用那些静态变量而不是它们自己的rootstage变量,所以这似乎在大多数情况下都有效。结果是最复杂的问题是使用Stage.stageVideo对象,我认为这些对象是硬件加速的视频对象。这些始终附加到stage,因此与假舞台对象不兼容。这些问题的主要问题是定位,,我已经解决了这个问题,但是还有一个小问题,我稍后会介绍但现在应该没问题了。

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) {}
    }
}

如果不使用网页,这可能是您无需处理的事情。

假舞台类名为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课程,以便更好地扩展和定位视频。

此外,它看起来像是视频的初始位置(至少在舞台视频中,你正在使用的是什么?)可以通过com.longtailvideo.jwplayer.media.VideoMediaProvider类中的小编辑来纠正。将import somePackage.StageInterceptor;添加到顶部的import语句,然后替换this line (link to source):

_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的开源版本受Creative Commons许可管理,如上所述on their site

  

JW Player 6 - 开源版   JW Player开放源代码版本的使用受Creative Commons许可证的约束。简而言之:

     

JW播放器开源 - 您可以使用,修改,复制和分发此版本,只要它用于非商业用途,您提供归属,并在类似许可下共享。   许可证摘要和全文可在此处找到:CC BY-NC-SA 3.0