views:

38

answers:

1

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.

A: 

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):

alt text

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: alt text

www0z0k
I do not understand why pausing at the NetStream.Play.Start event will help. However, I'm rather sure they start the first frame at the same time. However, afterthat, some play slow and some play fast. (all videos were encoded at the same frame rate.) Each video uses its own NetConnection.
Supasate
are the delays always equal?
www0z0k
No they vary. I notice that the delays introduce when CPU is busy and RAM is getting low. I still don't find the way to sync them.
Supasate
@Supasate: using 3 equal flv files stored locally? i'll try and report the result
www0z0k
Yes. They are stored locally.
Supasate