NetStream.publish捕捉摄像头的图像,并编码后发送到FMS服务器。flash 11终于支持发布h264的流。因为推送h264的流,需要flash player能编码h264格式视频,在flash player 11加入了h264编码器。
官方参考:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/H264VideoStreamSettings.html
编写推送h164的as程序必须要较高版本的sdk,之前使用的flex sdk 4.1的flash player版本是10.0,不能用来编写这个程序。
下载flex sdk:
http://www.adobe.com/devnet/flex/flex-sdk-download.html

h264和h263对比图(同样的码率和分辨率):


as3.0代码:
[javascript]
view plain
copy
print
?
- package??
- {??
-
????import?fl.controls.Button;??
-
????import?fl.controls.CheckBox;??
-
????import?fl.controls.ComboBox;??
-
????import?fl.controls.Label;??
-
????import?fl.controls.TextInput;??
- ??????
-
????import?flash.display.Sprite;??
-
????import?flash.display.StageAlign;??
-
????import?flash.display.StageScaleMode;??
-
????import?flash.events.Event;??
-
????import?flash.events.MouseEvent;??
-
????import?flash.events.NetStatusEvent;??
-
????import?flash.media.Camera;??
-
????import?flash.media.H264Profile;??
-
????import?flash.media.H264VideoStreamSettings;??
-
????import?flash.media.Microphone;??
-
????import?flash.media.Video;??
-
????import?flash.net.NetConnection;??
-
????import?flash.net.NetStream;??
- ??????
-
????public?class?H264Publisher?extends?Sprite??
- ????{?????
-
????????public?function?H264Publisher()??
- ????????{??
-
????????????if(this.stage?==?null){??
-
????????????????this.addEventListener(Event.ADDED_TO_STAGE,?this.onAddedToStage);??
- ????????????}??
-
????????????else{??
-
????????????????this.onAddedToStage(null);??
- ????????????}??
- ????????}??
- ??????????
-
????????private?function?onAddedToStage(evt:Event):void{??
-
????????????this.stage.align?=?StageAlign.TOP_LEFT;??
-
????????????this.stage.scaleMode?=?StageScaleMode.NO_SCALE;??
- ??????????????
-
????????????var?urlPanel:Sprite?=?new?Sprite();??
-
????????????this.addUrlPanel(urlPanel,?onMouseClickStartPublish,?onMouseClickStopPublish);??
- ??????????????
-
????????????var?cameraPanel:Sprite?=?new?Sprite();??
-
????????????this.addCameraPanel(cameraPanel);??
- ??????????????
-
????????????var?encodingPanel:Sprite?=?new?Sprite();??
-
????????????this.addEncodingPanel(encodingPanel);??
- ??????????????
- ????????????urlPanel.x?=?10;??
- ????????????urlPanel.y?=?10;??
- ??????????????
- ????????????cameraPanel.x?=?urlPanel.x;??
- ????????????cameraPanel.y?=?urlPanel.y?+?30;??
- ??????????????
- ????????????encodingPanel.x?=?cameraPanel.x;??
- ????????????encodingPanel.y?=?cameraPanel.y?+?30;??
- ??????????????
-
????????????video?=?new?Video();??
- ????????????video.x?=?encodingPanel.x;??
- ????????????video.y?=?encodingPanel.y?+?30;??
- ??????????????
-
????????????this.addChild(urlPanel);??
-
????????????this.addChild(cameraPanel);??
-
????????????this.addChild(encodingPanel);??
-
????????????this.addChild(video);??
- ????????}??
- ??????????
-
????????private?var?fmsUrl:String;??
-
????????private?var?fmsStream:String;??
-
????????private?function?discoveryFmsUrl():void{??
-
????????????var?url:String?=?txtUrl.text;??
- ??????????????
-
????????????if(url.toLowerCase().indexOf("rtmp://")?<?0){??
-
????????????????trace("[error]?the?url?must?start?with?rtmp://",?"error");??
-
????????????????return;??
- ????????????}??
- ??????????????
-
??????????????
-
????????????url?=?url.substr(url.toLowerCase().indexOf("rtmp://")?+?"rtmp://".length);??
- ??????????????
-
????????????var?server:String?=?url.substr(0,?url.indexOf("/"));??
-
????????????url?=?url.substr(url.indexOf("/")?+?1);??
- ??????????????
-
????????????var?port:String?=?"1935";??
-
????????????if(server.indexOf(":")?>=?0){??
-
????????????????port?=?server.substr(server.indexOf(":")+1);??
-
????????????????server?=?server.substr(0,?server.indexOf(":"));??
- ????????????}??
- ??????????????
-
????????????var?appIndex:int?=?-1;??
-
????????????for(var?i:int?=?0;?i?<?this.cbAppLevel.selectedIndex?+?1;?i++){??
-
????????????????if(url.indexOf("/",?appIndex?+?1)?<?0){??
-
????????????????????break;??
- ????????????????}??
- ??????????????????
-
????????????????appIndex?=?url.indexOf("/",?appIndex?+?1);??
- ????????????}??
-
????????????var?app:String?=?url.substr(0,?appIndex);??
-
????????????var?stream:String?=?url.substr(appIndex?+?1);??
- ??????????????
-
??????????????
-
????????????var?serverIsIPAddress:Boolean?=?true;??
-
????????????var?serverItems:Array?=?server.split(".");??
-
????????????for(i?=?0;?i?<?serverItems.length;?i++){??
-
????????????????if(isNaN(Number(serverItems[i]))){??
-
????????????????????serverIsIPAddress?=?false;??
- ????????????????}??
- ????????????}??
- ??????????????
-
????????????fmsUrl?=?"rtmp://"?+?server?+?":"?+?port?+?"/"?+?app;??
- ????????????fmsStream?=?stream;??
- ????????}??
- ??????????
-
????????private?function?buildEncodingParameters(publishStream:NetStream,?c:Camera,?m:Microphone):void{??
-
????????????var?x264profile:String?=?(this.cbX264Profile.selectedLabel?==?"Main")???H264Profile.MAIN?:?H264Profile.BASELINE;??
-
????????????var?x264level:String?=?this.cbX264Level.selectedLabel;??
-
????????????var?x264KeyFrameInterval:int?=?int(this.cbX264KeyFrameInterval.selectedIndex?+?1);??
-
????????????var?cameraWidth:int?=?int(this.cbCameraSize.selectedLabel.substr(0,?this.cbCameraSize.selectedLabel.indexOf("x")));??
-
????????????var?cameraHeight:int?=?int(this.cbCameraSize.selectedLabel.substr(this.cbCameraSize.selectedLabel.indexOf("x")?+?1));;??
-
????????????var?cameraFps:Number?=?Number(this.cbCameraFps.selectedLabel);??
-
????????????var?cameraBitrate:int?=?int(this.cbCameraBitrate.selectedLabel);??
-
????????????var?cameraQuality:int?=?85;??
-
????????????var?microEncodeQuality:int?=?8;??
-
????????????var?microRate:int?=?22;???
- ??????????????
-
????????????trace("[Publish]?h.264(x264)?encoding?parameters:?"???
-
????????????????+?"profile="?+?x264profile???
-
????????????????+?",?level="?+?x264level??
-
????????????????+?",?keyFrameInterval(gop)="?+?x264KeyFrameInterval??
-
????????????????+?";?video(camera)?width="?+?cameraWidth??
-
????????????????+?",?height="?+?cameraHeight??
-
????????????????+?",?fps="?+?cameraFps??
-
????????????????+?",?bitrate="?+?cameraBitrate??
-
????????????????+?",?quality="?+?cameraQuality??
-
????????????????+?";?audio(microphone)?encodeQuality="?+?microEncodeQuality??
-
????????????????+?",?rate="?+?microRate?+?"(22050Hz)"??
- ????????????);??
- ??????????????
-
????????????var?h264Settings:H264VideoStreamSettings?=?new?H264VideoStreamSettings();??
-
??????????????
- ????????????h264Settings.setProfileLevel(x264profile,?x264level);???
- ????????????publishStream.videoStreamSettings?=?h264Settings;??
-
??????????????
-
??????????????
-
??????????????
-
?????????????
- ?
- ??
- ??????????????
-
??????????????
- ??????????????
-
??????????????
-
??????????????
-
??????????????
-
??????????????
- ????????????c.setKeyFrameInterval(x264KeyFrameInterval);??
- ??????????????
-
??????????????
-
??????????????
-
??????????????
-
??????????????
- ????????????c.setMode(cameraWidth,?cameraHeight,?cameraFps);??
- ??????????????
-
??????????????
-
??????????????
-
??????????????
-
??????????????
-
??????????????
-
??????????????
-
??????????????
-
???????????? ??
-
???????????? ??
-
??????????????
-
??????????????
- ????????????c.setQuality(cameraBitrate?*?1000,?cameraQuality);??
- ??????????????
-
??????????????
-
????????????if(m?==?null){??
-
????????????????return;??
- ????????????}??
- ??????????????
-
??????????????
-
??????????????
-
??????????????
- ????????????m.encodeQuality?=?microEncodeQuality;??
- ??????????????
-
??????????????
-
??????????????
-
??????????????
- ????????????m.rate?=?microRate;??
- ????????}??
- ??????????
-
????????private?var?publishStream:NetStream;??
-
????????private?var?publishConnection:NetConnection;??
-
????????private?function?onMouseClickStartPublish(evt:MouseEvent):void{??
-
??????????????
-
????????????if(publishStream?!=?null){??
-
????????????????return;??
- ????????????}??
- ??????????????
-
????????????this.btnStartPublish.enabled?=?false;??
-
????????????this.btnStopPublish.enabled?=?true;??
- ??????????????
-
????????????this.discoveryFmsUrl();??
- ??????????????
-
????????????publishConnection?=?new?NetConnection();??
-
????????????var?conn:NetConnection?=?publishConnection;??
- ??????????????
- ????????????conn.client?=?{};??
-
????????????conn.client.onBWDone?=?function():void{};??
- ??????????????
-
????????????conn.addEventListener(NetStatusEvent.NET_STATUS,?function(evt:NetStatusEvent):void{??
-
????????????????trace("[Publish][connection]?code:"?+?evt.info.code);??
- ??????????????????
-
????????????????switch(evt.info.code){??
-
????????????????????case?"NetConnection.Connect.Success":??
-
????????????????????????publishStream?=?new?NetStream(conn);??
-
??????????????????????????
-
????????????????????????var?m:Microphone?=?Microphone.getMicrophone(cbMicrophone.selectedIndex);??
-
??????????????????????????
-
????????????????????????var?c:Camera?=?Camera.getCamera(String(cbCamera.selectedIndex));??
-
????????????????????????if(c?==?null){??
-
????????????????????????????trace("[Publish][error]?failed?to?open?camera(name="?+?String(cbCamera.selectedIndex)?+?"):?"?+?cbCamera.selectedLabel,?"error");??
- ????????????????????????????cleanupPublishedStream();??
-
????????????????????????????break;??
- ????????????????????????}??
-
????????????????????????else?if(c.muted){??
-
????????????????????????????trace("[Publish][error]?open?camera(name="?+?String(cbCamera.selectedIndex)?+?")?failed,?it's?muted:?"?+?cbCamera.selectedLabel,?"error");??
- ????????????????????????????cleanupPublishedStream();??
-
????????????????????????????break;??
- ????????????????????????}??
- ??????????????????????????
- ????????????????????????buildEncodingParameters(publishStream,?c,?m);??
- ??????????????????????????
-
????????????????????????publishStream.addEventListener(NetStatusEvent.NET_STATUS,?function(evt:NetStatusEvent):void{??
-
????????????????????????????trace("[Publish][NetStreamStatus]"?+?evt.info.code);??
- ??????????????????????????????
-
????????????????????????????switch(evt.info.code){??
-
????????????????????????????????case?"NetStream.Publish.Start":??
-
????????????????????????????????????var?h264:H264VideoStreamSettings?=?publishStream.videoStreamSettings?as?H264VideoStreamSettings;??
-
????????????????????????????????????trace("[Publish]?video?codec:?"?+?h264.codec???
-
????????????????????????????????????????+?",?profile="?+?h264.profile??
-
????????????????????????????????????????+?",?level="?+?h264.level??
-
????????????????????????????????????????+?",?quality="?+?h264.quality??
-
????????????????????????????????????????+?",?fps="?+?h264.fps??
-
????????????????????????????????????????+?",?gop="?+?h264.keyFrameInterval??
-
????????????????????????????????????????+?",?bandwidth="?+?h264.bandwidth??
-
????????????????????????????????????????+?",?size="?+?h264.width?+?"x"?+?h264.height);??
-
????????????????????????????????????break;??
-
????????????????????????????????case?"NetStream.Publish.BadName":??
- ????????????????????????????????????cleanupPublishedStream();??
-
????????????????????????????????????break;??
- ????????????????????????????}??
- ????????????????????????});??
- ????????????????????????publishStream.publish(fmsStream);??
- ??????????????????????????
-
??????????????????????????
-
????????????????????????trace("[Publish][debug]?start?publish,?using?camera(name="?+?String(cbCamera.selectedIndex)?+?"):?"?+?c.name);??
- ????????????????????????publishStream.attachCamera(c);??
-
????????????????????????if(m?!=?null?&&?!m.muted){??
-
????????????????????????????trace("[Publish][debug]?start?publish,?using?microphone(name="?+?String(cbMicrophone.selectedIndex)?+?"):?"?+?m.name);??
- ????????????????????????????publishStream.attachAudio(m);??
- ????????????????????????}??
- ????????????????????????restartPlayback();??
-
????????????????????????break;??
-
????????????????????case?"NetConnection.Connect.Rejected":??
-
????????????????????case?"NetConnection.Connect.Failed":??
- ????????????????????????cleanupPublishedStream();??
-
????????????????????????break;??
- ????????????????}??
- ????????????});??
- ??????????????
- ????????????conn.connect(fmsUrl);??
- ????????}??
-
????????private?function?cleanupPublishedStream():void{??
-
????????????this.btnStartPublish.enabled?=?true;??
-
????????????this.btnStopPublish.enabled?=?false;??
-
????????????if(this.publishStream?!=?null){??
-
????????????????this.publishStream.close();??
- ????????????}??
-
????????????if(this.publishConnection?!=?null){??
-
????????????????this.publishConnection.close();??
- ????????????}??
-
????????????this.publishStream?=?null;??
- ????????}??
- ??????????
-
????????public?var?stream:NetStream;??
-
????????private?var?conn:NetConnection;??
-
????????private?var?video:Video;??
-
????????private?function?restartPlayback():void{??
-
??????????????
-
????????????if(this.stream?!=?null){??
-
????????????????this.stream.close();??
- ????????????}??
- ??????????????
-
????????????conn?=?new?NetConnection();??
- ??????????????
- ????????????conn.client?=?{};??
-
????????????conn.client.onBWDone?=?function():void{};??
-
????????????conn.addEventListener(NetStatusEvent.NET_STATUS,?function(evt:NetStatusEvent):void{??
-
????????????????trace("[connection]?code:"?+?evt.info.code?+?"?desc:"?+?evt.info.description);??
- ??????????????????
-
????????????????switch(evt.info.code){??
-
????????????????????case?"NetConnection.Connect.Success":??
-
????????????????????????stream?=?new?NetStream(conn);??
- ????????????????????????video.attachNetStream(stream);??
- ??????????????????????????
-
??????????????????????????
-
????????????????????????stream.addEventListener(NetStatusEvent.NET_STATUS,?function(evt:NetStatusEvent):void{??
-
????????????????????????????trace("[NetStreamStatus]"?+?evt.info.code?+?"?desc:"?+?evt.info.description);??
- ????????????????????????});??
- ????????????????????????stream.client?=?{};??
-
????????????????????????stream.client.onMetaData?=?function?onMetadata(metadata:Object):void{??
-
????????????????????????????var?o:Object?=?{};??
-
????????????????????????????for(var?key:String?in?metadata){??
- ????????????????????????????????o[key]?=?metadata[key];??
-
????????????????????????????????trace("[metadata]?"?+?"key="?+?key?+?",?value="?+?o[key]);??
- ????????????????????????????}??
- ??????????????????????????????
-
????????????????????????????if(metadata.width?==?undefined){??
- ????????????????????????????????metadata.width?=?10;??
-
????????????????????????????????trace("[warning]?metadata.width?is?undefied,?set?to?10");??
- ????????????????????????????}??
-
????????????????????????????if(metadata.height?==?undefined){??
- ????????????????????????????????metadata.height?=?10;??
-
????????????????????????????????trace("[warning]?metadata.height?is?undefied,?set?to?10");??
- ????????????????????????????}??
- ??????????????????????????????
- ????????????????????????????video.width?=?metadata.width;??
- ????????????????????????????video.height?=?metadata.height;??
- ????????????????????????};??
- ??????????????????????????
-
????????????????????????if(!cbIsLive.selected){??
- ????????????????????????????stream.play(fmsStream,?0);??
- ????????????????????????}??
-
????????????????????????else{??
- ????????????????????????????stream.play(fmsStream);??
- ????????????????????????}??
-
????????????????????????break;??
-
????????????????????case?"NetConnection.Connect.Rejected":??
-
????????????????????case?"NetConnection.Connect.Failed":??
- ????????????????????????stream.close();??
-
????????????????????????stream?=?null;??
-
????????????????????????break;??
- ????????????????}??
- ????????????});??
- ????????????conn.connect(fmsUrl);??
- ????????}??
- ??????????
-
????????private?function?onMouseClickStopPublish(evt:MouseEvent):void{??
-
????????????this.cleanupPublishedStream();??
- ????????}??
- ??????????
-
????????private?var?txtUrl:TextInput;??
-
????????private?var?btnStartPublish:Button;??
-
????????private?var?btnStopPublish:Button;??
-
????????private?var?cbAppLevel:ComboBox;??
-
????????private?var?cbIsLive:CheckBox;??
-
????????private?function?addUrlPanel(??
- ????????????panel:Sprite,???
- ????????????onMouseClickStartPublish:Function,?onMouseClickStopPublish:Function??
-
????????):void{??
-
????????????var?lblUrl:Label?=?new?Label();??
-
????????????lblUrl.text?=?"RTMP?Url:";??
- ????????????lblUrl.width?=?50;??
- ????????????panel.addChild(lblUrl);??
- ??????????????
-
????????????txtUrl?=?new?TextInput();??
- ????????????txtUrl.width?=?380;??
- ????????????txtUrl.x?=?lblUrl.x?+?lblUrl.width?+?3;??
- ????????????panel.addChild(txtUrl);??
- ??????????????
-
????????????cbIsLive?=?new?CheckBox();??
-
????????????cbIsLive.selected?=?true;??
-
????????????cbIsLive.label?=?"Live";??
- ????????????cbIsLive.width?=?53;??
- ????????????cbIsLive.x?=?txtUrl.x?+?txtUrl.width?+?0;??
- ????????????panel.addChild(cbIsLive);??
- ??????????????
-
????????????cbAppLevel?=?new?ComboBox();??
-
????????????cbAppLevel.addItem({label:?"1级App"});??
-
????????????cbAppLevel.addItem({label:?"2级App"});??
-
????????????cbAppLevel.addItem({label:?"3级App"});??
-
????????????cbAppLevel.addItem({label:?"4级App"});??
- ????????????cbAppLevel.width?=?70;??
- ????????????cbAppLevel.x?=?cbIsLive.x?+?cbIsLive.width?+?0;??
- ????????????panel.addChild(cbAppLevel);??
- ??????????????
-
????????????btnStartPublish?=?new?Button();??
-
????????????btnStartPublish.label?=?"发布流";??
- ????????????btnStartPublish.width?=?60;??
- ????????????btnStartPublish.x?=?cbAppLevel.x?+?cbAppLevel.width?+?3;??
- ????????????btnStartPublish.addEventListener(MouseEvent.CLICK,?onMouseClickStartPublish);??
- ????????????panel.addChild(btnStartPublish);??
- ??????????????
-
????????????btnStopPublish?=?new?Button();??
-
????????????btnStopPublish.label?=?"停止发布";??
- ????????????btnStopPublish.width?=?60;??
-
????????????btnStopPublish.enabled?=?false;??
- ????????????btnStopPublish.x?=?btnStartPublish.x?+?btnStartPublish.width?+?3;??
- ????????????btnStopPublish.addEventListener(MouseEvent.CLICK,?onMouseClickStopPublish);??
- ????????????panel.addChild(btnStopPublish);??
- ????????}??
- ??????????
-
????????private?var?cbX264Profile:ComboBox;??
-
????????private?var?cbX264Level:ComboBox;??
-
????????private?var?cbX264KeyFrameInterval:ComboBox;??
-
????????private?var?cbCameraSize:ComboBox;??
-
????????private?var?cbCameraFps:ComboBox;??
-
????????private?var?cbCameraBitrate:ComboBox;??
-
????????private?function?addEncodingPanel(??
- ????????????panel:Sprite??
-
????????):void{??
-
????????????var?lblX264Profile:Label?=?new?Label();??
-
????????????lblX264Profile.text?=?"Profile:";??
- ????????????lblX264Profile.width?=?38;??
- ????????????lblX264Profile.y?=?2;??
- ????????????panel.addChild(lblX264Profile);??
- ??????????????
-
????????????cbX264Profile?=?new?ComboBox();??
- ????????????cbX264Profile.width?=?72;??
- ????????????cbX264Profile.x?=?lblX264Profile.x?+?lblX264Profile.width?+?0;??
- ????????????panel.addChild(cbX264Profile);??
-
????????????cbX264Profile.addItem({label:"Baseline"});??
-
????????????cbX264Profile.addItem({label:"Main"});??
- ??????????????
-
????????????var?lblX264Level:Label?=?new?Label();??
-
????????????lblX264Level.text?=?"Level:";??
- ????????????lblX264Level.width?=?32;??
- ????????????lblX264Level.y?=?2;??
- ????????????lblX264Level.x?=?cbX264Profile.x?+?cbX264Profile.width?+?1;??
- ????????????panel.addChild(lblX264Level);??
- ??????????????
-
????????????cbX264Level?=?new?ComboBox();??
- ????????????cbX264Level.width?=?45;??
- ????????????cbX264Level.x?=?lblX264Level.x?+?lblX264Level.width?+?1;??
- ????????????panel.addChild(cbX264Level);??
-
????????????var?x264Levels:Array?=?["1",?"1b",?"1.1",?"1.2",?"1.3",?"2",?"2.1",?"2.2",?"3",?"3.1",?"3.2",?"4",?"4.1",?"4.2",?"5",?"5.1"];??
-
????????????for(var?i:int?=?0;?i?<?x264Levels.length;?i++){??
- ????????????????cbX264Level.addItem({label:x264Levels[i]});??
- ????????????}??
- ????????????cbX264Level.selectedIndex?=?8;??
- ??????????????
-
????????????var?lblX264KeyFrameInterval:Label?=?new?Label();??
-
????????????lblX264KeyFrameInterval.text?=?"GOP:";??
- ????????????lblX264KeyFrameInterval.width?=?29;??
- ????????????lblX264KeyFrameInterval.y?=?2;??
- ????????????lblX264KeyFrameInterval.x?=?cbX264Level.x?+?cbX264Level.width?+?1;??
- ????????????panel.addChild(lblX264KeyFrameInterval);??
- ??????????????
-
????????????cbX264KeyFrameInterval?=?new?ComboBox();??
- ????????????cbX264KeyFrameInterval.width?=?87;??
- ????????????cbX264KeyFrameInterval.x?=?lblX264KeyFrameInterval.x?+?lblX264KeyFrameInterval.width?+?1;??
- ????????????panel.addChild(cbX264KeyFrameInterval);??
-
????????????for(i?=?0;?i?<?48;?i++){??
-
????????????????cbX264KeyFrameInterval.addItem({label:String(i?+?1)?+?"?seconds"});??
- ????????????}??
- ????????????cbX264KeyFrameInterval.selectedIndex?=?3;??
- ??????????????
-
????????????var?lblCameraSize:Label?=?new?Label();??
-
????????????lblCameraSize.text?=?"Size:";??
- ????????????lblCameraSize.width?=?30;??
- ????????????lblCameraSize.y?=?2;??
- ????????????lblCameraSize.x?=?cbX264KeyFrameInterval.x?+?cbX264KeyFrameInterval.width?+?1;??
- ????????????panel.addChild(lblCameraSize);??
- ??????????????
-
????????????cbCameraSize?=?new?ComboBox();??
- ????????????cbCameraSize.width?=?82;??
- ????????????cbCameraSize.x?=?lblCameraSize.x?+?lblCameraSize.width?+?1;??
- ????????????panel.addChild(cbCameraSize);??
-
????????????var?sizes:Array?=?["176x144",?"320x240",?"352x240",?"352x288",?"640x480",?"720x480",?"720x576",?"800x600",?"1024x768",?"1280x720",?"1360x768",?"1920x1080"];??
-
????????????for(i?=?0;?i?<?sizes.length;?i++){??
- ????????????????cbCameraSize.addItem({label:sizes[i]});??
- ????????????}??
- ????????????cbCameraSize.selectedIndex?=?1;??
- ??????????????
-
????????????var?lblCameraFps:Label?=?new?Label();??
-
????????????lblCameraFps.text?=?"FPS:";??
- ????????????lblCameraFps.width?=?28;??
- ????????????lblCameraFps.y?=?2;??
- ????????????lblCameraFps.x?=?cbCameraSize.x?+?cbCameraSize.width?+?1;??
- ????????????panel.addChild(lblCameraFps);??
- ??????????????
-
????????????cbCameraFps?=?new?ComboBox();??
- ????????????cbCameraFps.width?=?58;??
- ????????????cbCameraFps.x?=?lblCameraFps.x?+?lblCameraFps.width?+?1;??
- ????????????panel.addChild(cbCameraFps);??
-
????????????var?fpses:Array?=?["1.00",?"4.00",?"5.00",?"6.00",?"8.00",?"10.00",?"12.00",?"14.98",?"15.00",?"20.00",?"24.00",?"25.00",?"29.97",?"30.00",?"59.94",?"60.00"];??
-
????????????for(i?=?0;?i?<?fpses.length;?i++){??
- ????????????????cbCameraFps.addItem({label:fpses[i]});??
- ????????????}??
- ????????????cbCameraFps.selectedIndex?=?8;??
- ??????????????
-
????????????var?lblCameraBitrate:Label?=?new?Label();??
-
????????????lblCameraBitrate.text?=?"Bitrate:";??
- ????????????lblCameraBitrate.width?=?40;??
- ????????????lblCameraBitrate.y?=?2;??
- ????????????lblCameraBitrate.x?=?cbCameraFps.x?+?cbCameraFps.width?+?1;??
- ????????????panel.addChild(lblCameraBitrate);??
- ??????????????
-
????????????cbCameraBitrate?=?new?ComboBox();??
- ????????????cbCameraBitrate.width?=?58;??
- ????????????cbCameraBitrate.x?=?lblCameraBitrate.x?+?lblCameraBitrate.width?+?1;??
- ????????????panel.addChild(cbCameraBitrate);??
-
????????????var?bitrates:Array?=?["10",?"50",?"100",?"200",?"350",?"500",?"650",?"800",?"950",?"1000",?"1200",?"1500",?"1800",?"2000",?"2500",?"20000"];??
-
????????????for(i?=?0;?i?<?bitrates.length;?i++){??
- ????????????????cbCameraBitrate.addItem({label:bitrates[i]});??
- ????????????}??
- ????????????cbCameraBitrate.selectedIndex?=?3;??
- ????????}??
- ??????????
-
????????private?var?cbCamera:ComboBox;??
-
????????private?var?cbMicrophone:ComboBox;??
-
????????private?function?addCameraPanel(??
- ????????????panel:Sprite??
-
????????):void{??
-
??????????????
-
????????????var?lblCamera:Label?=?new?Label();??
-
????????????lblCamera.text?=?"Available?Cameras:";??
- ????????????lblCamera.width?=?100;??
- ????????????panel.addChild(lblCamera);??
- ??????????????
-
????????????cbCamera?=?new?ComboBox();??
- ????????????cbCamera.width?=?160;??
- ????????????cbCamera.x?=?lblCamera.x?+?lblCamera.width?+?3;??
- ????????????panel.addChild(cbCamera);??
- ??????????????
-
????????????var?cameras:Array?=?Camera.names;??
-
????????????for(var?i:int?=?0;?i?<?cameras.length;?i++){??
- ????????????????cbCamera.addItem({label:cameras[i]});??
- ????????????}??
- ??????????????
-
??????????????
-
????????????var?lblMicrophone:Label?=?new?Label();??
-
????????????lblMicrophone.text?=?"Available?Microphones:";??
- ????????????lblMicrophone.width?=?120;??
- ????????????lblMicrophone.x?=?cbCamera.x?+?cbCamera.width?+?10;??
- ????????????panel.addChild(lblMicrophone);??
- ??????????????
-
????????????cbMicrophone?=?new?ComboBox();??
- ????????????cbMicrophone.width?=?180;??
- ????????????cbMicrophone.x?=?lblMicrophone.x?+?lblMicrophone.width?+?3;??
- ????????????panel.addChild(cbMicrophone);??
- ??????????????
-
????????????var?microphones:Array?=?Microphone.names;??
-
????????????for(i?=?0;?i?<?microphones.length;?i++){??
- ????????????????cbMicrophone.addItem({label:microphones[i]});??
- ????????????}??
- ????????}??
- ????}??
- }??
package
{
import fl.controls.Button;
import fl.controls.CheckBox;
import fl.controls.ComboBox;
import fl.controls.Label;
import fl.controls.TextInput;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.NetStatusEvent;
import flash.media.Camera;
import flash.media.H264Profile;
import flash.media.H264VideoStreamSettings;
import flash.media.Microphone;
import flash.media.Video;
import flash.net.NetConnection;
import flash.net.NetStream;
public class H264Publisher extends Sprite
{
public function H264Publisher()
{
if(this.stage == null){
this.addEventListener(Event.ADDED_TO_STAGE,this.onAddedToStage);
}
else{
this.onAddedToStage(null);
}
}
private function onAddedToStage(evt:Event):void{
this.stage.align = StageAlign.TOP_LEFT;
this.stage.scaleMode = StageScaleMode.NO_SCALE;
var urlPanel:Sprite = new Sprite();
this.addUrlPanel(urlPanel,onMouseClickStartPublish,onMouseClickStopPublish);
var cameraPanel:Sprite = new Sprite();
this.addCameraPanel(cameraPanel);
var encodingPanel:Sprite = new Sprite();
this.addEncodingPanel(encodingPanel);
urlPanel.x = 10;
urlPanel.y = 10;
cameraPanel.x = urlPanel.x;
cameraPanel.y = urlPanel.y + 30;
encodingPanel.x = cameraPanel.x;
encodingPanel.y = cameraPanel.y + 30;
video = new Video();
video.x = encodingPanel.x;
video.y = encodingPanel.y + 30;
this.addChild(urlPanel);
this.addChild(cameraPanel);
this.addChild(encodingPanel);
this.addChild(video);
}
private var fmsUrl:String;
private var fmsStream:String;
private function discoveryFmsUrl():void{
var url:String = txtUrl.text;
if(url.toLowerCase().indexOf("rtmp://") < 0){
trace("[error] the url must start with rtmp://","error");
return;
}
// remove the start rtmp://
url = url.substr(url.toLowerCase().indexOf("rtmp://") + "rtmp://".length);
var server:String = url.substr(0,url.indexOf("/"));
url = url.substr(url.indexOf("/") + 1);
var port:String = "1935";
if(server.indexOf(":") >= 0){
port = server.substr(server.indexOf(":")+1);
server = server.substr(0,server.indexOf(":"));
}
var appIndex:int = -1;
for(var i:int = 0; i < this.cbAppLevel.selectedIndex + 1; i++){
if(url.indexOf("/",appIndex + 1) < 0){
break;
}
appIndex = url.indexOf("/",appIndex + 1);
}
var app:String = url.substr(0,appIndex);
var stream:String = url.substr(appIndex + 1);
// if user input ip address,set the server; otherwise,set the vhost.
var serverIsIPAddress:Boolean = true;
var serverItems:Array = server.split(".");
for(i = 0; i < serverItems.length; i++){
if(isNaN(Number(serverItems[i]))){
serverIsIPAddress = false;
}
}
fmsUrl = "rtmp://" + server + ":" + port + "/" + app;
fmsStream = stream;
}
private function buildEncodingParameters(publishStream:NetStream,c:Camera,m:Microphone):void{
var x264profile:String = (this.cbX264Profile.selectedLabel == "Main") ? H264Profile.MAIN : H264Profile.BASELINE;
var x264level:String = this.cbX264Level.selectedLabel;
var x264KeyFrameInterval:int = int(this.cbX264KeyFrameInterval.selectedIndex + 1);
var cameraWidth:int = int(this.cbCameraSize.selectedLabel.substr(0,this.cbCameraSize.selectedLabel.indexOf("x")));
var cameraHeight:int = int(this.cbCameraSize.selectedLabel.substr(this.cbCameraSize.selectedLabel.indexOf("x") + 1));;
var cameraFps:Number = Number(this.cbCameraFps.selectedLabel);
var cameraBitrate:int = int(this.cbCameraBitrate.selectedLabel);
var cameraQuality:int = 85;
var microEncodeQuality:int = 8;
var microRate:int = 22; // 22 === 22050 Hz
trace("[Publish] h.264(x264) encoding parameters: "
+ "profile=" + x264profile
+ ",level=" + x264level
+ ",keyFrameInterval(gop)=" + x264KeyFrameInterval
+ "; video(camera) width=" + cameraWidth
+ ",height=" + cameraHeight
+ ",fps=" + cameraFps
+ ",bitrate=" + cameraBitrate
+ ",quality=" + cameraQuality
+ "; audio(microphone) encodeQuality=" + microEncodeQuality
+ ",rate=" + microRate + "(22050Hz)"
);
var h264Settings:H264VideoStreamSettings = new H264VideoStreamSettings();
// we MUST set its values first,then set the NetStream.videoStreamSettings,or it will keep the origin values.
h264Settings.setProfileLevel(x264profile,x264level);
publishStream.videoStreamSettings = h264Settings;
// the setKeyFrameInterval/setMode/setQuality use the camera settings.
// http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/VideoStreamSettings.html
// Note This feature will be supported in future releases of Flash Player and AIR,for now,Camera parameters are used.
/*h264Settings.setKeyFrameInterval(4);
h264Settings.setMode(800,600,15);
h264Settings.setQuality(500,0);*/
// set the camera and microphone.
// setKeyFrameInterval(keyFrameInterval:int):void
// keyFrameInterval:int — A value that specifies which video frames are transmitted in full (as keyframes) instead of being
// interpolated by the video compression algorithm. A value of 1 means that every frame is a keyframe,a value of 3 means
// that every third frame is a keyframe,and so on. Acceptable values are 1 through 48.
c.setKeyFrameInterval(x264KeyFrameInterval);
// setMode(width:int,height:int,fps:Number,favorArea:Boolean = true):void
// width:int — The requested capture width,in pixels. The default value is 160.
// height:int — The requested capture height,in pixels. The default value is 120.
// fps:Number — The requested rate at which the camera should capture data,in frames per second. The default value is 15.
c.setMode(cameraWidth,cameraHeight,cameraFps);
// setQuality(bandwidth:int,quality:int):void
// bandwidth:int — Specifies the maximum amount of bandwidth that the current outgoing video feed can use,in bytes per second.
// To specify that the video can use as much bandwidth as needed to maintain the value of quality,pass 0 for bandwidth.
// The default value is 16384.
// quality:int — An integer that specifies the required level of picture quality,as determined by the amount of compression
// being applied to each video frame. Acceptable values range from 1 (lowest quality,maximum compression) to 100
// (highest quality,no compression). To specify that picture quality can vary as needed to avoid exceeding bandwidth,// pass 0 for quality.
// winlin:
// bandwidth is in bps not kbps. 500*1000 = 500kbps.
// quality=1 is lowest quality,100 is highest quality.
c.setQuality(cameraBitrate * 1000,cameraQuality);
// if no microphone,donot set the params.
if(m == null){
return;
}
// The encoded speech quality when using the Speex codec. Possible values are from 0 to 10. The default value is 6. Higher numbers
// represent higher quality but require more bandwidth,as shown in the following table. The bit rate values that are listed represent
// net bit rates and do not include packetization overhead.
m.encodeQuality = microEncodeQuality;
// The rate at which the microphone is capturing sound,in kHz. Acceptable values are 5,8,11,22,and 44. The default value is 8 kHz
// if your sound capture device supports this value. Otherwise,the default value is the next available capture level above 8 kHz that
// your sound capture device supports,usually 11 kHz.
m.rate = microRate;
}
private var publishStream:NetStream;
private var publishConnection:NetConnection;
private function onMouseClickStartPublish(evt:MouseEvent):void{
// if published,donothing
if(publishStream != null){
return;
}
this.btnStartPublish.enabled = false;
this.btnStopPublish.enabled = true;
this.discoveryFmsUrl();
publishConnection = new NetConnection();
var conn:NetConnection = publishConnection;
conn.client = {};
conn.client.onBWDone = function():void{};
conn.addEventListener(NetStatusEvent.NET_STATUS,function(evt:NetStatusEvent):void{
trace("[Publish][connection] code:" + evt.info.code);
switch(evt.info.code){
case "NetConnection.Connect.Success":
publishStream = new NetStream(conn);
// microphone and camera
var m:Microphone = Microphone.getMicrophone(cbMicrophone.selectedIndex);
// Remark: the name is the index!
var c:Camera = Camera.getCamera(String(cbCamera.selectedIndex));
if(c == null){
trace("[Publish][error] failed to open camera(name=" + String(cbCamera.selectedIndex) + "): " + cbCamera.selectedLabel,"error");
cleanupPublishedStream();
break;
}
else if(c.muted){
trace("[Publish][error] open camera(name=" + String(cbCamera.selectedIndex) + ") failed,it's muted: " + cbCamera.selectedLabel,"error");
cleanupPublishedStream();
break;
}
buildEncodingParameters(publishStream,c,m);
publishStream.addEventListener(NetStatusEvent.NET_STATUS,function(evt:NetStatusEvent):void{
trace("[Publish][NetStreamStatus]" + evt.info.code);
switch(evt.info.code){
case "NetStream.Publish.Start":
var h264:H264VideoStreamSettings = publishStream.videoStreamSettings as H264VideoStreamSettings;
trace("[Publish] video codec: " + h264.codec
+ ",profile=" + h264.profile
+ ",level=" + h264.level
+ ",quality=" + h264.quality
+ ",fps=" + h264.fps
+ ",gop=" + h264.keyFrameInterval
+ ",bandwidth=" + h264.bandwidth
+ ",size=" + h264.width + "x" + h264.height);
break;
case "NetStream.Publish.BadName":
cleanupPublishedStream();
break;
}
});
publishStream.publish(fmsStream);
// attach video and audio.
trace("[Publish][debug] start publish,using camera(name=" + String(cbCamera.selectedIndex) + "): " + c.name);
publishStream.attachCamera(c);
if(m != null && !m.muted){
trace("[Publish][debug] start publish,using microphone(name=" + String(cbMicrophone.selectedIndex) + "): " + m.name);
publishStream.attachAudio(m);
}
restartPlayback();
break;
case "NetConnection.Connect.Rejected":
case "NetConnection.Connect.Failed":
cleanupPublishedStream();
break;
}
});
conn.connect(fmsUrl);
}
private function cleanupPublishedStream():void{
this.btnStartPublish.enabled = true;
this.btnStopPublish.enabled = false;
if(this.publishStream != null){
this.publishStream.close();
}
if(this.publishConnection != null){
this.publishConnection.close();
}
this.publishStream = null;
}
public var stream:NetStream;
private var conn:NetConnection;
private var video:Video;
private function restartPlayback():void{
// stream is playing,resume it.
if(this.stream != null){
this.stream.close();
}
conn = new NetConnection();
conn.client = {};
conn.client.onBWDone = function():void{};
conn.addEventListener(NetStatusEvent.NET_STATUS,function(evt:NetStatusEvent):void{
trace("[connection] code:" + evt.info.code + " desc:" + evt.info.description);
switch(evt.info.code){
case "NetConnection.Connect.Success":
stream = new NetStream(conn);
video.attachNetStream(stream);
//stream.bufferTime = 3;
stream.addEventListener(NetStatusEvent.NET_STATUS,function(evt:NetStatusEvent):void{
trace("[NetStreamStatus]" + evt.info.code + " desc:" + evt.info.description);
});
stream.client = {};
stream.client.onMetaData = function onMetadata(metadata:Object):void{
var o:Object = {};
for(var key:String in metadata){
o[key] = metadata[key];
trace("[metadata] " + "key=" + key + ",value=" + o[key]);
}
if(metadata.width == undefined){
metadata.width = 10;
trace("[warning] metadata.width is undefied,set to 10");
}
if(metadata.height == undefined){
metadata.height = 10;
trace("[warning] metadata.height is undefied,set to 10");
}
video.width = metadata.width;
video.height = metadata.height;
};
if(!cbIsLive.selected){
stream.play(fmsStream,0);
}
else{
stream.play(fmsStream);
}
break;
case "NetConnection.Connect.Rejected":
case "NetConnection.Connect.Failed":
stream.close();
stream = null;
break;
}
});
conn.connect(fmsUrl);
}
private function onMouseClickStopPublish(evt:MouseEvent):void{
this.cleanupPublishedStream();
}
private var txtUrl:TextInput;
private var btnStartPublish:Button;
private var btnStopPublish:Button;
private var cbAppLevel:ComboBox;
private var cbIsLive:CheckBox;
private function addUrlPanel(
panel:Sprite,onMouseClickStartPublish:Function,onMouseClickStopPublish:Function
):void{
var lblUrl:Label = new Label();
lblUrl.text = "RTMP Url:";
lblUrl.width = 50;
panel.addChild(lblUrl);
txtUrl = new TextInput();
txtUrl.width = 380;
txtUrl.x = lblUrl.x + lblUrl.width + 3;
panel.addChild(txtUrl);
cbIsLive = new CheckBox();
cbIsLive.selected = true;
cbIsLive.label = "Live";
cbIsLive.width = 53;
cbIsLive.x = txtUrl.x + txtUrl.width + 0;
panel.addChild(cbIsLive);
cbAppLevel = new ComboBox();
cbAppLevel.addItem({label: "1级App"});
cbAppLevel.addItem({label: "2级App"});
cbAppLevel.addItem({label: "3级App"});
cbAppLevel.addItem({label: "4级App"});
cbAppLevel.width = 70;
cbAppLevel.x = cbIsLive.x + cbIsLive.width + 0;
panel.addChild(cbAppLevel);
btnStartPublish = new Button();
btnStartPublish.label = "发布流";
btnStartPublish.width = 60;
btnStartPublish.x = cbAppLevel.x + cbAppLevel.width + 3;
btnStartPublish.addEventListener(MouseEvent.CLICK,onMouseClickStartPublish);
panel.addChild(btnStartPublish);
btnStopPublish = new Button();
btnStopPublish.label = "停止发布";
btnStopPublish.width = 60;
btnStopPublish.enabled = false;
btnStopPublish.x = btnStartPublish.x + btnStartPublish.width + 3;
btnStopPublish.addEventListener(MouseEvent.CLICK,onMouseClickStopPublish);
panel.addChild(btnStopPublish);
}
private var cbX264Profile:ComboBox;
private var cbX264Level:ComboBox;
private var cbX264KeyFrameInterval:ComboBox;
private var cbCameraSize:ComboBox;
private var cbCameraFps:ComboBox;
private var cbCameraBitrate:ComboBox;
private function addEncodingPanel(
panel:Sprite
):void{
var lblX264Profile:Label = new Label();
lblX264Profile.text = "Profile:";
lblX264Profile.width = 38;
lblX264Profile.y = 2;
panel.addChild(lblX264Profile);
cbX264Profile = new ComboBox();
cbX264Profile.width = 72;
cbX264Profile.x = lblX264Profile.x + lblX264Profile.width + 0;
panel.addChild(cbX264Profile);
cbX264Profile.addItem({label:"Baseline"});
cbX264Profile.addItem({label:"Main"});
var lblX264Level:Label = new Label();
lblX264Level.text = "Level:";
lblX264Level.width = 32;
lblX264Level.y = 2;
lblX264Level.x = cbX264Profile.x + cbX264Profile.width + 1;
panel.addChild(lblX264Level);
cbX264Level = new ComboBox();
cbX264Level.width = 45;
cbX264Level.x = lblX264Level.x + lblX264Level.width + 1;
panel.addChild(cbX264Level);
var x264Levels:Array = ["1","1b","1.1","1.2","1.3","2","2.1","2.2","3","3.1","3.2","4","4.1","4.2","5","5.1"];
for(var i:int = 0; i < x264Levels.length; i++){
cbX264Level.addItem({label:x264Levels[i]});
}
cbX264Level.selectedIndex = 8;
var lblX264KeyFrameInterval:Label = new Label();
lblX264KeyFrameInterval.text = "GOP:";
lblX264KeyFrameInterval.width = 29;
lblX264KeyFrameInterval.y = 2;
lblX264KeyFrameInterval.x = cbX264Level.x + cbX264Level.width + 1;
panel.addChild(lblX264KeyFrameInterval);
cbX264KeyFrameInterval = new ComboBox();
cbX264KeyFrameInterval.width = 87;
cbX264KeyFrameInterval.x = lblX264KeyFrameInterval.x + lblX264KeyFrameInterval.width + 1;
panel.addChild(cbX264KeyFrameInterval);
for(i = 0; i < 48; i++){
cbX264KeyFrameInterval.addItem({label:String(i + 1) + " seconds"});
}
cbX264KeyFrameInterval.selectedIndex = 3;
var lblCameraSize:Label = new Label();
lblCameraSize.text = "Size:";
lblCameraSize.width = 30;
lblCameraSize.y = 2;
lblCameraSize.x = cbX264KeyFrameInterval.x + cbX264KeyFrameInterval.width + 1;
panel.addChild(lblCameraSize);
cbCameraSize = new ComboBox();
cbCameraSize.width = 82;
cbCameraSize.x = lblCameraSize.x + lblCameraSize.width + 1;
panel.addChild(cbCameraSize);
var sizes:Array = ["176x144","320x240","352x240","352x288","640x480","720x480","720x576","800x600","1024x768","1280x720","1360x768","1920x1080"];
for(i = 0; i < sizes.length; i++){
cbCameraSize.addItem({label:sizes[i]});
}
cbCameraSize.selectedIndex = 1;
var lblCameraFps:Label = new Label();
lblCameraFps.text = "FPS:";
lblCameraFps.width = 28;
lblCameraFps.y = 2;
lblCameraFps.x = cbCameraSize.x + cbCameraSize.width + 1;
panel.addChild(lblCameraFps);
cbCameraFps = new ComboBox();
cbCameraFps.width = 58;
cbCameraFps.x = lblCameraFps.x + lblCameraFps.width + 1;
panel.addChild(cbCameraFps);
var fpses:Array = ["1.00","4.00","5.00","6.00","8.00","10.00","12.00","14.98","15.00","20.00","24.00","25.00","29.97","30.00","59.94","60.00"];
for(i = 0; i < fpses.length; i++){
cbCameraFps.addItem({label:fpses[i]});
}
cbCameraFps.selectedIndex = 8;
var lblCameraBitrate:Label = new Label();
lblCameraBitrate.text = "Bitrate:";
lblCameraBitrate.width = 40;
lblCameraBitrate.y = 2;
lblCameraBitrate.x = cbCameraFps.x + cbCameraFps.width + 1;
panel.addChild(lblCameraBitrate);
cbCameraBitrate = new ComboBox();
cbCameraBitrate.width = 58;
cbCameraBitrate.x = lblCameraBitrate.x + lblCameraBitrate.width + 1;
panel.addChild(cbCameraBitrate);
var bitrates:Array = ["10","50","100","200","350","500","650","800","950","1000","1200","1500","1800","2000","2500","20000"];
for(i = 0; i < bitrates.length; i++){
cbCameraBitrate.addItem({label:bitrates[i]});
}
cbCameraBitrate.selectedIndex = 3;
}
private var cbCamera:ComboBox;
private var cbMicrophone:ComboBox;
private function addCameraPanel(
panel:Sprite
):void{
// camera
var lblCamera:Label = new Label();
lblCamera.text = "Available Cameras:";
lblCamera.width = 100;
panel.addChild(lblCamera);
cbCamera = new ComboBox();
cbCamera.width = 160;
cbCamera.x = lblCamera.x + lblCamera.width + 3;
panel.addChild(cbCamera);
var cameras:Array = Camera.names;
for(var i:int = 0; i < cameras.length; i++){
cbCamera.addItem({label:cameras[i]});
}
// microphone
var lblMicrophone:Label = new Label();
lblMicrophone.text = "Available Microphones:";
lblMicrophone.width = 120;
lblMicrophone.x = cbCamera.x + cbCamera.width + 10;
panel.addChild(lblMicrophone);
cbMicrophone = new ComboBox();
cbMicrophone.width = 180;
cbMicrophone.x = lblMicrophone.x + lblMicrophone.width + 3;
panel.addChild(cbMicrophone);
var microphones:Array = Microphone.names;
for(i = 0; i < microphones.length; i++){
cbMicrophone.addItem({label:microphones[i]});
}
}
}
} 其中用到了FlashCS5的控件,可以将c:Program Files (x86)AdobeAdobe Flash CS5CommonConfigurationComponentsUser Interface.fla打开后导出swc,然后在actionscript3项目中引用这个swc就可以了。
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|