Investigation of CircleCube Video Player (Day 4)

来源:互联网 发布:三相电动机绕组数据 编辑:程序博客网 时间:2024/04/29 06:32


Review of the Structure Design


At the moment, the most helpless functions have been cut off. Only the basic and should be retained features remain. And it's time to figure out the whole program's structure.


Mainly, the application has four view states: normal, playlist view,detail view and share view, and it can interchange among these states. But we've removed the three states, only the normal state left. 


Because in the play list view state, user can play any arbitrary video at run-time, by clicking on the item in list. And the player may be playing a video at that time. So the video player has multi-state, and can jump over these states, we need introduce extra vars to keep track of the change of its state. And currentStatus is for that.  


We now trace this variable through out the program.


internal var currentStatus:String="ready";public function playDown(arg1:flash.events.MouseEvent=null):void{trace("begin playDown - currentStatus: " + currentStatus);vid.visible = true;get_pl();var loc1:*=currentStatus;switch (loc1) {case "ready":{videoTimer.start();if (autoVidLoad) {ns.play(video_flv);if (autoVidPlay) {currentStatus = "playing";vcr.playB.icon.gotoAndStop("playing");vid.setChildIndex(video, vid.numChildren - 2);}else {currentStatus = "loading";ns.pause();vcr.playB.icon.gotoAndStop("paused");autoVidPlay = true;clearVideoStatus();}}else {autoVidLoad = true;}break;}case "loading":{currentStatus = "playing";ns.resume();vcr.playB.icon.gotoAndStop("playing");vid.setChildIndex(video, vid.numChildren - 2);break;}case "playing":{currentStatus = "paused";ns.pause();vcr.playB.icon.gotoAndStop("paused");break;}case "paused":{currentStatus = "playing";ns.resume();vcr.playB.icon.gotoAndStop("playing");vid.setChildIndex(video, vid.numChildren - 2);break;}case "complete":{ns.seek(0);ns.resume();videoTimer.start();currentStatus = "playing";vcr.playB.icon.gotoAndStop("playing");vid.setChildIndex(video, vid.numChildren - 2);break;}default:{trace("ERROR: " + currentStatus);}}return;}public function videoComplete():*{ns.pause();videoTimer.stop();currentStatus = "complete";var loc1:*;vcr.bar.bg.width = loc1 = 0 * vcr.bar.bar.width;vcr.bar.loadbar.width = loc1;vcr.bar.playbar.width = 0 * vcr.bar.bar.width;vcr.bar.scrub.x = 0;vcr.playB.icon.gotoAndStop("paused");clearVideoStatus();vid.setChildIndex(video, vid.numChildren - 2);return;}


According to the code, currentStaus may be the following values:


ready

loading

playing

paused

complete


which means it has five basic status. The initial value is 'ready', and can change to others four values, only under one condition that it will change to loading, which is when autoVidPlayis false. This value has its initial value set to true, and will be over ridden according to xml and Javascript, but xml has its autostart set to true, so this var keeps as true through the initialization stage, apart from that, the program only has logic to change it to true if it's false, none for changing it to false. So it is not really of use. And run the original program, and play around it, see the output:


......begin playDown - currentStatus: readyloading still: files/285533_preview.jpgonMetaData duration: 24.72begin playDown - currentStatus: playingbegin playDown - currentStatus: pausedpl_play 2begin playDown - currentStatus: readyloading still: files/285533_preview.jpgonMetaData duration: 24.72video stop firedbegin playDown - currentStatus: completepl_play 3begin playDown - currentStatus: readyloading still: files/285533_preview.jpgonMetaData duration: 24.72pl_play 0begin playDown - currentStatus: readyloading still: files/285533_preview.jpgonMetaData duration: 24.72begin playDown - currentStatus: playingpl_play 5begin playDown - currentStatus: readyloading still: files/285533_preview.jpgonMetaData duration: 24.72video stop firedbegin playDown - currentStatus: completebegin playDown - currentStatus: playingpl_play 0begin playDown - currentStatus: readyloading still: files/285533_preview.jpgonMetaData duration: 24.72begin playDown - currentStatus: playing

If the video stops, and user clicks the button which would invoke playDown() function, before that currentStatus is 'complete' previously, whereas after user's clicking, it changes to 'playing', or 'pausing'; if user clicks a item in the play list to play another video(a output of 'pl_play n' will show up to indicate that), then it will change to ready, by some other functions, and let's find them out:  

        public function pl_play(arg1:Number=0):void        {            trace("pl_play", arg1);            pl_index = arg1;            if (pl_index < 0 && !pl_loop)             {                pl_index = 0;            }            else if (pl_index < 0 && pl_loop)             {                pl_last();            }            if (pl_index >= pl_total && !pl_loop)             {                pl_index = 0;            }            else if (pl_index >= pl_total && pl_loop)             {                pl_first();            }            else             {                currentStatus = "ready";                pl_duration = false;                playDown();                pl_click();                hidePlayOverlay();            }            return;        }

And it seems that only the code inside else block will be executed eventaully. It set currentStatus to 'ready'. But one question arises: what doespl_durationdo???

Here are the functions that access it:


        internal var pl_duration:Boolean=false;        public function onMetaData(arg1:Object):void        {            if (duration == -1 || !pl_duration)             {                duration = Number(arg1["duration"]);                trace("onMetaData duration:", duration);                pl_duration = true;                playerLayout();            }            return;        }        public function onXMPData(arg1:Object):void        {            if (duration == -1 || !pl_duration)             {                duration = Number(arg1["duration"]);                trace("onXMPdata duration:", duration);                pl_duration = true;                playerLayout();            }            return;        }        public function pl_last():void        {            pl_index = (pl_total - 1);            currentStatus = "ready";            pl_duration = false;            playDown();            pl_click();            hidePlayOverlay();            return;        }        public function pl_first():void        {            pl_index = 0;            currentStatus = "ready";            pl_duration = false;            playDown();            pl_click();            hidePlayOverlay();            return;        }        public function pl_next():void        {            var loc1:*;            pl_index++;            if (pl_index >= pl_total && !pl_loop)             {                pl_index = 0;            }            else if (pl_index >= pl_total && pl_loop)             {                pl_first();            }            else             {                currentStatus = "ready";                pl_duration = false;                playDown();                pl_click();                hidePlayOverlay();            }            return;        }        public function pl_previous():void        {            var loc1:*;            pl_index--;            if (pl_index < 0 && !pl_loop)             {                pl_index = 0;            }            else if (pl_index < 0 && pl_loop)             {                pl_last();            }            else             {                currentStatus = "ready";                pl_duration = false;                playDown();                pl_click();                hidePlayOverlay();            }            return;        }        public function pl_play(arg1:Number=0):void        {            trace("pl_play", arg1);            pl_index = arg1;            if (pl_index < 0 && !pl_loop)             {                pl_index = 0;            }            else if (pl_index < 0 && pl_loop)             {                pl_last();            }            if (pl_index >= pl_total && !pl_loop)             {                pl_index = 0;            }            else if (pl_index >= pl_total && pl_loop)             {                pl_first();            }            else             {                currentStatus = "ready";                pl_duration = false;                playDown();                pl_click();                hidePlayOverlay();            }            return;        }


Each time when playing a new video, it is set to false, and after the metadata loaded, it be changed to true.So it probably be used to indicate that if the duration meta data of the video has been loaded, if yes then it can be used to setup the layout ofvcr MovieClip.

finite state machine


What I am about to do is to remove the 'loading' status, and the logic around, we don't need it at all.

Beside from removing the code for 'loading' state, also removing everything aboutautoVidPlay:


And also remove averything about autoVidLoad, since its always true.


as file(remove ready state, mouse-over event, permalink and description version)


Take a break............................................................................


Now, draft the structure of the program's logic flow, regardless of the user interaction logic.


structure


The vcrLayout() is called in the constructor of main class, and then called by the videoTimer handler functionvideoStatus(),videoStatus() is invoked per 0.1 second. And is it necessary to run vcrLayout() so frequantly? Take a look at it:


        public function vcrLayout():*        {            var loc3:*=null;            vcrSort();            vcr.x = 0;            vcr.y = stage.stageHeight - vcr.bg.height;            vcr.bg.width = stage.stageWidth;            vcrWidthFixed = 0;            var loc1:*=(vcrArray.length - 1);            var loc2:*=0;            while (loc2 < vcrArray.length)             {                if (vcrArray[loc2] != vcr.empty)                 {                    vcrArray[loc2].visible = true;                    if (!(vcrArray[loc2].fixed == "fluid") && !(vcrArray[loc2].fixed == "variable"))                     {                        vcrWidthFixed = vcrWidthFixed + vcrArray[loc2].fixed;                        vcrArray[loc2].myWidth = vcrArray[loc2].fixed;                    }                    else if (vcrArray[loc2].fixed != "variable")                     {                        loc3 = vcrArray[loc2];                        loc1 = loc2;                    }                    else                     {                        vcrWidthFixed = vcrWidthFixed + vcrArray[loc2].timeDisplay.width;                        vcrArray[loc2].myWidth = vcrArray[loc2].timeDisplay.width;                    }                }                ++loc2;            }            vcrFluidWidth = stage.stageWidth - vcrWidthFixed - vcr_padding * 2;            var loc4:*;            loc3.bg.width = loc4 = vcrFluidWidth;            loc3.bar.width = loc4;            loc2 = 0;            while (loc2 <= loc1)             {                vcrLeft = loc2 != 0 ? vcrArray[(loc2 - 1)].x + vcrArray[(loc2 - 1)].myWidth : vcr_padding;                vcrArray[loc2].x = vcrLeft;                vcrArray[loc2].y = 0;                ++loc2;            }            loc2 = (vcrArray.length - 1);            while (loc2 > loc1)             {                vcrLeft = loc2 != (vcrArray.length - 1) ? vcrArray[loc2 + 1].x - vcrArray[loc2].myWidth : stage.stageWidth - vcr_padding - vcrArray[loc2].myWidth;                vcrArray[loc2].x = vcrLeft;                vcrArray[loc2].y = 0;                --loc2;            }            return;        }

remane the variables generated by the decompiler, to improve the readablity:


Laying the Components:


        public function vcrLayout():*        {            var _mc:*=null;            vcrSort();            vcr.x = 0;            vcr.y = stage.stageHeight - vcr.bg.height;            vcr.bg.width = stage.stageWidth;            vcrWidthFixed = 0;            var _total:int=(vcrArray.length - 1);trace(vcrArray.length);            var _i:int=0;            while (_i < vcrArray.length)             {                if (vcrArray[_i] != vcr.empty)                 {                    vcrArray[_i].visible = true;                    if (!(vcrArray[_i].fixed == "fluid") && !(vcrArray[_i].fixed == "variable"))                     {                        vcrWidthFixed = vcrWidthFixed + vcrArray[_i].fixed;                        vcrArray[_i].myWidth = vcrArray[_i].fixed;                    }                    else if (vcrArray[_i].fixed != "variable")                     {                        _mc = vcrArray[_i];                        _total = _i;                    }                    else                     {                        vcrWidthFixed = vcrWidthFixed + vcrArray[_i].timeDisplay.width;                        vcrArray[_i].myWidth = vcrArray[_i].timeDisplay.width;                    }                }                ++_i;            }            vcrFluidWidth = stage.stageWidth - vcrWidthFixed - vcr_padding * 2;                        _mc.bg.width = vcrFluidWidth;            _mc.bar.width = vcrFluidWidth;            _i = 0;trace("_total: " + _total);            while (_i <= _total)             {trace(_i);                vcrLeft = _i != 0 ? vcrArray[(_i - 1)].x + vcrArray[(_i - 1)].myWidth : vcr_padding;                vcrArray[_i].x = vcrLeft;trace("vcrArray[" + _i + "]: x=" + vcrLeft);                vcrArray[_i].y = 0;                ++_i;            }            _i = (vcrArray.length - 1);            while (_i > _total)             {                vcrLeft = _i != (vcrArray.length - 1) ? vcrArray[_i + 1].x - vcrArray[_i].myWidth : stage.stageWidth - vcr_padding - vcrArray[_i].myWidth;                vcrArray[_i].x = vcrLeft;                vcrArray[_i].y = 0;                --_i;            }            return;        }

At the beginning, it calls vcrSort(), it sort the elements in thevcrArrayby their weight. The result is, the less the weight goes, the more left the element laid in vcr MC. 


Array.sortOn() reference on Adobe.com


Each element has another property-fixed, it may be: 'fluid', 'variable' or a numeric value,20 in this program.

According to the program, only one element can be fluid, means its width is determined by how much space left for it. And bar is fluid. current time and total time are variable, their width are determined by theirTextField's width. And others' width are fixed, as their fixed property specify. So the first while loop insidevcrSort() calculates the position and then, the second while loop place the elements left to the bar, which is fluid; align them on left; the last one loop lay the right ones, aligns them on right:


layout


So, actually, the fixed property of the elements are not volatile at all, besides, the first call to vcrLayout() happans before the xml loaded, and there is no re-assignment to the elements' fixed properties, so the later call to vcrLayout() are useless; there'sno need to run it each timevideoStatus() runs.


And now we go back to the structure diagram of the program:


structure































原创粉丝点击