【问题标题】:How to synchronize multiple video streams in ActionScript?如何在 ActionScript 中同步多个视频流?
【发布时间】:2010-10-29 12:53:08
【问题描述】:

我正在尝试同时播放多个视频流。但是,我无法同步这些视频以相同的速率播放。

----详情--------

我有三个 FLV 格式的 45 秒视频,我使用 flash.net.NetStream 播放这些视频。我同时调用这些 netstream 的 netstream.play() (通过使用 for 循环)。但是,即使所有视频文件都在我的本地计算机上,这些视频也不同步。

例如,当挂钟在第 10 秒时,第一个视频在第 7 秒,第二个视频在第 10 秒,最后一个视频在第 5 秒。

我认为流式传输时可能会受到不同抖动延迟的影响。但是,我仍然找不到解决此问题的方法。

【问题讨论】:

    标签: flash actionscript-3 synchronization video-streaming


    【解决方案1】:

    这是我的研究结果。 代码:

    package
    {
        public class Main extends Sprite 
        {
            private var zeroBG:Sprite;
            private var oneBG:Sprite;
            private var twoBG:Sprite;
            private var arr:Array = new Array();
            private var oldSchoolMC:MovieClip;
            public function Main():void 
            {
                oldSchoolMC = new MovieClip();
                addChild(oldSchoolMC);
                oldSchoolMC.x = 400;
                oldSchoolMC.y = 350;
                oldSchoolMC.buttonMode = true;
                addFrames();
                //the string below is just a way to get about +15% CPU load (on Intel Dual-Core T4400), comment it out if you don't need it
                oldSchoolMC.addEventListener(Event.ENTER_FRAME, onEnterFrame);
                oldSchoolMC.addEventListener(MouseEvent.CLICK, onClick);
                zeroBG = new Sprite();
                oneBG = new Sprite();
                twoBG = new Sprite();
                oneBG.x = 350;
                twoBG.x = 700;
                addChild(zeroBG);
                addChild(oneBG);
                addChild(twoBG);
    
                genVideoSampleOnDefaultClasses(zeroBG);
                genVideoSampleOnDefaultClasses(oneBG);
                genVideoSampleOnDefaultClasses(twoBG);
            }
            private function onClick(e:MouseEvent):void {
                var secs:int = 0;
                if ((arr[0] as NetStream).time != 0 && (arr[0] as NetStream).time != (arr[arr.length - 1] as NetStream).time) {
                    secs = Math.ceil((arr[0] as NetStream).time);
                }
                for (var i:int = 0; i < arr.length; i++) {
                    var ns:NetStream = arr[i] as NetStream;
                    if(ns.time == 0){
                        ns.play('res/ghost_in_the_shell.flv');
                        continue;
                    }else {
                        trace('i = ' + i + ' time = ' + ns.time);
                        if (secs != 0) {
                            ns.seek(secs);
                        }
                    }               
                }
            }
    
            private function addFrames():void {
                for (var i:int = 0 ; i < 0xffffff ; i+=100000) {
                    oldSchoolMC.addChild(genColRect(i));
                    if (oldSchoolMC.numChildren > 0) {
                        oldSchoolMC.getChildAt(oldSchoolMC.numChildren - 1).scaleX = (250 - oldSchoolMC.numChildren) / 250;
                        oldSchoolMC.getChildAt(oldSchoolMC.numChildren - 1).scaleY = (250 - oldSchoolMC.numChildren) / 250;
                    }
                }
    
            }
    
            private function onEnterFrame(e:Event):void {
                for (var i:int = 0 ; i < oldSchoolMC.numChildren ; i++) {
                    oldSchoolMC.getChildAt(i).rotation += (oldSchoolMC.numChildren - i);
                }        
            }
    
            private function genColRect(col:int = 0xffffff):Shape {
                var spr:Shape = new Shape();
                spr.graphics.beginFill(col);
                spr.graphics.drawRect( -50, -50, 100, 100);
                spr.graphics.endFill();
                return spr;
            }        
    
            private function genVideoSampleOnDefaultClasses(spr:Sprite):void {
                var vid:Video = new Video();
                var nc:NetConnection = new NetConnection();
                nc.connect(null);
                var ns:NetStream = new NetStream(nc);
                ns.client = new Object();
                ns.client.onMetaData = function(info:Object):void { };
                vid.attachNetStream(ns);
                spr.addChild(vid);
                arr.push(ns);
            }
    
        }
    }  
    

    我可以提到两个同步问题:

    • 开始时: 无论我使用for 循环还是硬编码 3 行((arr[0] as NetStream).play('res/ghost_in_the_shell.flv'); - 这种方式),第二次点击(播放开始后)的输出都是这样的(来自第二次和第三次点击):
      点击 N 2
      i = 0 次 = 5.251
      i = 1 次 = 5.251
      i = 2 次 = 5.538
      点击 N 3
      i = 0 次 = 37.721
      i = 1 次 = 37.721
      i = 2 次 = 37.721
      第一个和第二个流都可以,但是第三个总是延迟287ms(取决于onClick函数代码,以前的版本总是延迟183ms)
    • 600 - 800 秒后: 流的时间存在不确定的增量(通常约为 100 毫秒),来自 2 次下一次点击的跟踪:
      点击 N 4
      i = 0 时间 = 756.44
      i = 1 次 = 756.558
      i = 2 次 = 756.558
      点击 N 5
      i = 0 时间 = 4466.965
      i = 1 次 = 4466.965
      i = 2 次 = 4466.965


    和屏幕截图(第一部分是在第一次点击之后(在任何同步之前)拍摄的,第二部分是在点击 N 4 之后拍摄的):

    flv 大小约为 207mb 顺便说一句

    UPD:我为视频添加了 5 个精灵、一个用于统计信息的文本字段和一个用于调用 onClick 函数的计时器(间隔为 1000 毫秒),修改如下:

        private function onClick(e:Event):void {
            tf.text = '';
            var secs:int = 0;
            if ((arr[0] as NetStream).time != 0 && (arr[0] as NetStream).time != (arr[arr.length - 1] as NetStream).time) {
                secs = Math.ceil((arr[0] as NetStream).time);
                trace(counter++ + ' : time = ' + secs);
            }
            for (var i:int = 0; i < arr.length; i++) {
                var ns:NetStream = arr[i] as NetStream;
                if(ns.time == 0){
                    ns.play('res/ghost_in_the_shell.flv');
                    if (i == arr.length - 1) {
                        streamTimer.start();
                    }
                    continue;
                }else {
                    tf.appendText('# ' + i + ' [' + ns.time + ']\n');
                    if (secs != 0) {
                        ns.seek(secs);
                    }
                }               
            }
        }
    

    它每 100 秒有大约 20 个同步问题(跟踪,不是我能看到的问题),因为它使用了大量的系统资源,但是即使有关于搜索的跟踪,视频对象也能播放得足够流畅。
    这是图片:

    【讨论】:

    • 我不明白为什么在 NetStream.Play.Start 事件处暂停会有帮助。但是,我很确定他们会同时开始第一帧。但是,在那之后,有些播放慢,有些播放快。 (所有视频都以相同的帧速率编码。)每个视频都使用自己的 NetConnection。
    • 不,它们各不相同。我注意到当 CPU 繁忙且 RAM 变低时会出现延迟。我仍然找不到同步它们的方法。
    • @Supasate:使用本地存储的 3 个相等的 flv 文件?我会尝试报告结果
    • 是的。它们存储在本地。
    【解决方案2】:

    Oups.... 没看到它是 2 岁......

    我认为您应该尝试在每个播放器实例中预加载文件,等待加载完成,然后,您可以开始播放视频。依赖 NetStream 事件不是很好(多次相同的通知,或者缺少通知,具体取决于播放的文件......)但它应该可以工作。

    function Preload() : void {
        aNet              = new NetConnection();
        aNet.connect(null);
        stream                = new NetStream( aNet );
        stream.client     = this;
        stream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus, false, 0, true );
        stream.addEventListener(IOErrorEvent.IO_ERROR, errSnd, false, 0, true );
        stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError, false, 0, true );
        stream.play("your file");
    }
    
    
    // Here you wait for the load notification, and then pause the video.
    private function onNetStatus( e : NetStatusEvent ) : void {
         switch( e.info.code ) {
          case "NetStream.Buffer.Full" :    
                   if (bNotified) return;
                   stream.pause();
                   // Store that the file is loaded
                   bNotified = true;
                   // Dispatch an event
                   dispatchEvent( new Event("VIDEO LOADED") ); 
           break;               
        }
    }
    
    private function errSnd(e: IOErrorEvent ) : void {
    // error handling   
    
    }
    
    private function onAsyncError(e: AsyncErrorEvent ) : void {
        // Error handling
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-11
      • 2014-06-11
      • 2016-10-24
      相关资源
      最近更新 更多