开发者

How to synchronize multiple video streams in ActionScript?

I'm trying to play multiple video streams simultaneously. However, I cannot synchronize these videos to play at the same rate.

---- details --------

I have three 45-second videos in FLV format and I use flash.net.NetStream to play these videos. I call netstream.play() of these netstream at the same time (by using a for-loop). However, these videos are out-of-sync even all videos files are on my local machine.

For example, when the wall clock is at 10th second, the first video is at 7th second, the second video is at 10th second, and the last video is at 5th second.

I think it may be affected by different jitter delays when streaming. However, I still cannot find the way to solve this problem.开发者_运维知识库


here are my research results. code:

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

    }
}  

i can mention two synchronization problems:

  • on start: no matter if i use a for loop or just hardcode 3 lines ((arr[0] as NetStream).play('res/ghost_in_the_shell.flv'); - this way) the output on second click (after play is inited) is like this (traces from second and third clicks):
    click N 2
    i = 0 time = 5.251
    i = 1 time = 5.251
    i = 2 time = 5.538
    click N 3
    i = 0 time = 37.721
    i = 1 time = 37.721
    i = 2 time = 37.721
    first and second streams are ok, but the third is always 287ms late (it depends on the onClick function code, previous version always gave 183ms delay)
  • after 600 - 800 seconds: there is an uncertain delta in streams' times (about 100ms usually), traces from 2 next clicks:
    click N 4
    i = 0 time = 756.44
    i = 1 time = 756.558
    i = 2 time = 756.558
    click N 5
    i = 0 time = 4466.965
    i = 1 time = 4466.965
    i = 2 time = 4466.965


and screenshots (first part was shot after the first click (before any synchronization), second after click N 4):

How to synchronize multiple video streams in ActionScript?

flv size is about 207mb btw

UPD: i added 5 more sprites for videos, a textfield for stats and a timer (with 1000ms interval) to call the onClick function which was modified as follows:

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

it had about 20 sync problems per 100 seconds (traces, not issues i could see) because it used a huge amount of system resources, but video objects played smooth enough even if there was a trace about seeking.
here's the picture:

How to synchronize multiple video streams in ActionScript?


Oups.... didn't see it was 2 years old......

I think that you should try to preload your files in each player instance, wait for the load to be completed and then, you can start the videos. Relying on NetStream event is not so great (several times the same notification, or missing notification depending on the file played....) but it should work.

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
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜