FlashPlayer在执行NetStream.play的时候崩溃的解决办法
FlashPlayer在执行NetStream.play的时候崩溃的解决办法
这是个隐藏非常深的BUG,我都怀疑如果再做一次,我能不能把它找出来。它耗费了我宝贵的三天时间,三天啊……
BUG表现
在使用NetStream连接FMS发布的流时,在执行NetStream.play('streamName')方法时,FlashPlayer会崩溃。独立版、调试版以及基于浏览器的插件版均如此。
但是,这还不是全部。必须满足以下几点,该BUG才会出现。
- 使用Windows 7操作系统。也就是说,Windows XP不会出现这个问题;
- 播放的必须是RTMP流,RTMP流可以由Flash Media Server或者Red5来发布。也就是说,使用NetStream播放本地的flv/f4v/mp4视频不会出现这个问题;
- 播放的流包含音频。也就是说,如果该流只包含视频,不会出现这个问题;
- 播放的流中包含的音频声音较大。也就是说,即使该流包含音频,但如果发布方没有发出声音,或者发出的声音很小,该问题不会出现;当然,不需要很大的声音就能让播放端立即崩溃;
- 使用了Frame标签来做预加载。不了解Frame标签预加载的,看这篇文章:Preloaders in AS3;
- 在预加载完毕之后,使用removeChild移除了预加载类的实例(BUG就在这里)。
开发和测试平台(出现BUG的平台)
- Flex SDK 4.5.1
- Flash Media Server 4.0
- Flash Player 10.3独立版/调试版/插件版
- Windows 7 旗舰版
- Chrome12/Opera11.5/Firefox5/IE9
BUG再现
我写了两个简单的Demo(一个发布端,一个接收端)来重现这个BUG。Demo需要FMS的支持。
错误的重点在于预加载类(PreloaderNSPlay.as)。由于预加载类在完成加载后就不再需要,一般的处理方法是将其从Stage中移除。只要将移除,就会出现这个BUG(并非移除后立即出现,而是在接收音频流的视频出现)。而如果使用visible将预加载类隐藏,就不会出现这个问题。
Demo的使用方法(服务端以FMS为例):
- 安装FMS,在安装目录下建立
/applications/testspeed/
文件夹; - 编译NSPulish和NSPlay,或者 在这里直接下载 ;
- 确认本机安装了摄像头和麦克风,运行NSPublish.swf,单击“连接”按钮,查看log信息确定连接正常,见下图:
- 运行NSPlay.swf,单击“连接”按钮,查看log信息确认连接正常。此时会看到发布端的摄像头视频。如果FlashPlaye没有崩溃的话,就向着麦克风吹口气……呼……整个世界清静了……
下面只贴出了 PreloaderNSPlay.as
的源码,需要整个项目源码可以在 这里 下载。
PreloaderNSPlay.as
1package
2{
3import flash.display.MovieClip;
4import flash.display.DisplayObject;
5import flash.display.StageAlign;
6import flash.display.StageScaleMode;
7import flash.events.Event;
8import flash.events.ProgressEvent;
9import flash.text.TextField;
10import flash.text.TextFormat;
11import flash.utils.getDefinitionByName;
12
13public class PreloaderNSPlay extends MovieClip
14{
15 public function PreloaderNSPlay()
16 {
17 _mainClassName = 'NSPlay';
18 stage.scaleMode = StageScaleMode.NO_SCALE;
19 stage.align = StageAlign.TOP_LEFT;
20 stage.showDefaultContextMenu = false;
21 _tf = new TextField();
22 _tf.defaultTextFormat = new TextFormat(null,12,0,null,null,null,null,null,"center");
23 _tf.mouseEnabled = false;
24 _tf.height = 20;
25 _tf.x = (stage.stageWidth-_tf.width)*.5;
26 _tf.y = stage.stageHeight*.5;
27 this.addChild(_tf);
28
29 this.loaderInfo.addEventListener(ProgressEvent.PROGRESS,progress);
30 this.loaderInfo.addEventListener(Event.COMPLETE,complete);
31 }
32
33 protected var _tf:TextField;
34 protected var _mainClassName:String;
35
36 private function progress(e:ProgressEvent):void
37 {
38 _tf.text = int(e.bytesLoaded/e.bytesTotal*100)+"% 载入中……";
39 }
40
41 private function complete(e:Event):void
42 {
43 gotoAndStop(2);
44 var mainClass:Class = Class(getDefinitionByName(_mainClassName));
45 stage.addChild(new mainClass() as DisplayObject);
46 destroy();
47 }
48
49 private function destroy():void
50 {
51 this.loaderInfo.removeEventListener(ProgressEvent.PROGRESS,progress);
52 this.loaderInfo.removeEventListener(Event.COMPLETE,complete);
53 //将预加载类从舞台移除(parent.removeChild也一样,因为parent就是舞台),就会导致Flash Player崩溃
54 stage.removeChild(this);
55 //parent.removeChild(this);
56
57 //如果只移除显示进度的文本,或者只将自身隐藏而不移除,就不会出现这个Bug
58 //this.removeChild(_tf);
59 //this.visible = false;
60 }
61}
62}
- 文章ID:1390
- 原文作者:zrong
- 原文链接:https://blog.zengrong.net/post/flashplayer_crash_on_netstream_play/
- 版权声明:本作品采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可,非商业转载请注明出处(原文作者,原文链接),商业转载请联系作者获得授权。