话接上回,这次真刀真枪输出1080p的视频了. 前前后后折腾了一天,终于顺利输出无报错了,注意点有两个:
1. 不要使用 FlvEncoder 的 Alchemy 模式,我每次渲染都会在进行到一分多钟的时候报错,排查下来是使用 Alchemy 的 helper 不能正常生成 ArrayByte (长度为0,位于 VideoPayloadMakerAlchemy.as Line 74). Adobe 自己也反复表明不建议将其用于生产环境中,看来还是有道理的.
1 2 3 4 5 6 7 8 9 10 |
screen_fps = 30; video_width = 1920; video_height = 1080; video_num = 0; video_file = new File("./").resolvePath("video" + video_num + ".flv"); fsFlvEncoder= new FileStreamFlvEncoder(video_file, screen_fps); fsFlvEncoder.fileStream.openAsync(video_file, FileMode.UPDATE); fsFlvEncoder.setVideoProperties(video_width, video_height, VideoPayloadMaker); fsFlvEncoder.setAudioProperties(FlvEncoder.SAMPLERATE_44KHZ, false, true, true); //其实用不到音频 fsFlvEncoder.start(); |
2. 将视频分段,as3 没有 64 位版本也没有 int_64 ,写入超过 4G 的文件会很成问题. 我之前一直奇怪为什么文件一到 4.xG AIR 就 crash 了,也并未留下任何错误信息,后来文件分段后就不再存在这个问题了. 还有一个好处是防止内存泄漏,据我测试下来 FlvEncoder 是存在内存泄漏的,就算强制 System.gc() 也不能降低内存用量,而我把视频编码功能关闭后(注释掉了 FlvEncoder.addFrame() 行)内存用量就稳定了. 因此每写到 2G 大小的时候(通过 fileStream.position 来判断)就重新创建一个视频文件和 FlvEncoder 对象.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
if(fsFlvEncoder.fileStream.position >= 2147483647){ fsFlvEncoder.updateDurationMetadata(); fsFlvEncoder.fileStream.close(); fsFlvEncoder.kill(); fsFlvEncoder = null; System.gc(); video_num ++; trace("Splite video. " + (video_num - 1) + " -> " + video_num); video_file = new File(".:/").resolvePath("video" + video_num + ".flv"); fsFlvEncoder= new FileStreamFlvEncoder(video_file, screen_fps); fsFlvEncoder.fileStream.open(video_file, FileMode.UPDATE); fsFlvEncoder.setVideoProperties(video_width, video_height, VideoPayloadMaker); fsFlvEncoder.setAudioProperties(FlvEncoder.SAMPLERATE_44KHZ, false, true, true); fsFlvEncoder.start(); } |
3. 注意其他内存泄漏. bitmapData 有个方法 dispose() 可以用于释放像素所占的内存. 根据 Jason Sturges 的说法,虽然最终 GC 会回收掉 bitmapData 的所有内存,可是使用此方法可以做到立即回收,在高密度使用 bitmapData的应用中很有用. (似乎我这个项目里直接复用同一个 bitmapData 更好?)
1 2 3 4 5 6 7 |
var bmp:BitmapData = new BitmapData(video_width, video_height); bmp.draw(this); var sound_frame:ByteArray = new ByteArray(); fsFlvEncoder.addFrame(bmp, sound_frame); // No sounds will be recorded sound_frame = null; bmp.dispose(); bmp = null; |
最终 5’29” 的视频渲染(其实是编码)了我一小时,占用 17G 的空间(不包括音频),用 x264 aac 转码封装之后的最终大小是 39M ,连贯无丢帧,且音画同步.
以下两个B站投稿都是用这套方法渲染并用 ffmpeg 将音频轨合并的.
突然戳进来啦!新加上的照片很好看!半年没更啦T^T
哎呀人是会变懒的呀..
这个不错。谢谢分享!
大神,能把那个FLVEncoder包共享一下吗?
能的话发到freeflylinyz@126.com这个邮箱。谢谢。