按照这些步骤在 Flash Builder 中设置项目:
您可以在项目中找到两个应用程序(Screenrecording_VideoOnly.mxml 和 Screenrecording_VideoSound.mxml)。第一个应用程序说明如何只记录屏幕。第二个应用程序以第一个为构建基础,并增加了记录声音的功能。
您可能知道 VLC 是一个可播放几乎所有音频和视频文件的媒体播放器,但它的功能远不止这些。它是一个全面的媒体框架,可用于对各种类型的数据、甚至流媒体进行代码转换。它不太知名的功能之一是能够记录用户的屏幕。
VLC 屏幕记录功能的一个缺点是无法同时记录屏幕和音频。在本文中,我们将使用 AIR 2 中的另一个新增功能(记录麦克风输入的能力)修复这个问题。
为了在您的应用程序中使用新的 NativeProcess 类,您需要在应用程序描述符文件中添加一行内容:
<supportedProfiles>extendedDesktop</supportedProfiles>
您可以在 Screenrecording_VideoOnly-app.xml 和 Screenrecording_VideoSound-app.xml 中找到上面这一行。
它告诉编译器您创建的不是普通的 AIR 文件,而是本机应用程序,它有访问外部应用程序等扩展权限。
屏幕记录代码在类 de.benz.exec.ScreenRecorder 中。要使用这个类,将它传递给要用作 File 对象的命令行应用程序。在实际应用程序中,您需要处理不同平台上的不同文件路径。例如,在 Mac OS X 上,VLC 程序的默认路径是 /Applications/VLC.app/Contents/MacOS/VLC 在 Windows 上,它通常为 C:\Program Files\VideoLAN\VLC\vlc.exe。一个解决方案是将外部应用程序与本机安装程序一起打包,然后使用 File 类的常量独立于用户的平台访问二进制文件。另一个解决方案是在应用程序第一次启动时由用户选择路径。为了简便起见,本示例中对路径进行了硬编码;您可能需要根据系统情况调整它们。
要在 AIR 中创建本机进程,您需要将一个 NativeProcessStartupInfo 对象实例化,它将存储实际启动该进程的所有必需信息;例如:
var startupInfo:NativeProcessStartupInfo = new NativeProcessStartupInfo();
startupInfo.executable = vlcFile;
将 NativeProcessStartupInfo 对象实例化后,您将指向 VLC 可执行文件的 File 对象传递给它。
现在,您需要提供命令行参数。NativeProcessStartupInfo 对象有一个属性 arguments,它是一个包含所有必要参数的 Vector。
可以通过命令行完全控制 VLC。但是,您在大多数情况下通过 VLC 提供的界面使用它,因此决定要使用哪些参数有点困难。经过一番研究,我得出以下组合:
-I rc --rc-fake-tty screen://
:screen-fps=15 :screen-caching=100 :sout=#transcode{venc=x264{bframes=0,nocabac,ref=1,nf,level=13,crf=24,partitions=none},vcodec=h264,fps=15,vb=3000,
width=1024,height=740,acodec=none}:duplicate{dst=std{mux=mp4,access=file,
dst='Set target file path here'}}
要测试这些参数,您可以直接在命令行试用它们。
包装在 Vector 对象中的该命令如下:
var processArgs:Vector.<String> = new Vector.<String>();
processArgs.push("-I");
processArgs.push("rc");
processArgs.push("--rc-fake-tty");
processArgs.push("screen://");
processArgs.push(":screen-fps=15");
processArgs.push(":screen-caching=100");
processArgs.push(":sout=#transcode{venc=x264{bframes=0,nocabac,ref=1,nf,level=13,crf=24,partitions=none},vcodec=h264,fps=15,vb=3000,width=1024,height=740,acodec=none}:duplicate{dst=std{mux=mp4,access=file,dst='"+targetFile.nativePath+"'}}");
startupInfo.arguments = processArgs;
主要参数为:
acodec=none ),这是因为 VLC 不支持同时记录屏幕和音频。mp4)以及所生成视频的目标。它还告诉 VLC 生成一个物理文件 (access=file)。NativeProcessStartupInfo 对象现已完成,您可以通过新建一个 NativeProcess 对象创建实际流程,为标准输出、错误和退出事件添加事件监听器:
p = new NativeProcess();
p.addEventListener(ProgressEvent.STANDARD_OUTPUT_DATA, onOutputData);
p.addEventListener(ProgressEvent.STANDARD_ERROR_DATA, onErrorData);
p.addEventListener(NativeProcessExitEvent.EXIT, onExit);
错误和输出事件处理函数只是将结果跟踪到控制台。
private function onOutputData(evt:ProgressEvent):void{
var outputData:String = p.standardOutput.readUTFBytes(p.standardOutput.bytesAvailable);
trace(outputData);
}
private function onErrorData(evt:ProgressEvent):void{
var errorData:String = p.standardError.readUTFBytes(p.standardError.bytesAvailable);
trace(errorData);
}
要启动进程,调用 NativeProcess 对象的 start() 方法,并将 NativeProcessStartupInfo 对象作为一个参数进行传递。
p.start(startupInfo);
现在,进程正在运行并且 VLC 正在记录屏幕。要停止记录,只杀死进程还不够,因为这会导致视频文件受损。您必须与运行的进程通信,此处通过标准输入 (STDIN) 进行通信。在 AIR 2 中,您可以使用 NativeProcess 类的 standardInput 属性,将数据发送到一个运行的进程管道。standardInput 属性的类型为 IDataOutput,所以您可以像 ByteArray 一样写入它。在 ScreenRecorder.as 中,stopRecording() 用于停止记录进程:
public function stopRecording():void{
p.standardInput.writeUTFBytes("stop" + "\n");
setTimeout(kill,4000);
}
此方法编写一个停止命令,后跟一个换行符。换行符与在终端窗口中按回车键发出命令的效果相同。
该命令触发 VLC 正确关闭记录视频的文件流。随后,即可安全退出 VLC。但是,由于编写实际文件所需的时间稍长,代码通过一个超时延迟这一任务,使 VLC 能首先完成编写操作并关闭文件。
要退出进程,kill() 方法发出一个退出命令,如下:
private function kill():void{
p.standardInput.writeUTFBytes("quit" + "\n");
isRecording = false;
dispatchEvent(new Event(Event.COMPLETE));
}
此时,视频已创建,它将载入 Screenrecording_VideoOnly.mxml 的 WindowedApplication 的 onComplete 处理函数中的 VideoDisplay 对象。
private function onComplete(evt:Event):void{
vPlayer.source = screenRecorder.targetFile.url;
}
第一部分到此结束。您现在有了一个可记录用户屏幕的工具。目前,文件只包含视频数据,没有音频数据。在下一部分中,您将使用 AIR 的本机麦克风记录功能记录麦克风声音。
在上一部分中,您学会了如何使用 VLC 记录没有声音的视频数据。幸运的是,AIR 2 引入了从连接的麦克风访问原始 PCM 声音数据的功能。在 AIR 2 之前,从线路输入记录声音的唯一方法是将记录的字节通过 NetConnection 发送到 Flash Media Server 实例,而 NetConnection 对于大多数桌面应用程序并不是最佳的。
在 AIR 2 中,开发人员可以通过新的 SampleDataEvent.SAMPLE_DATA 事件直接访问麦克风,该事件由 Microphone 类的一个实例引发。
首先,您希望用户有机会为记录选择一个已连接设备。您可以通过为用户界面添加一个 ComboBox 做到这一点,该界面有一个已连接麦克风的列表:
<s:ComboBox id="mic_cb" dataProvider="{new
ArrayCollection(Microphone.names)}" selectedIndex="0" />
这只需要在主应用程序类中添加一行 MXML。以上代码添加一个 ComboBox,其中数据提供程序设置为包装在 ArrayCollection 中的 Microphone 类的静态属性 names。
实际记录逻辑在类 de.benz.screenrecording.AudioRecorder 中。AudioRecorder.as 中的 startRecording 方法将两个参数作为参数。第一个是输入设备的选定索引,第二个是对将存储所记录的声音数据的文件的引用。
要开始记录,您首先必须配置麦克风。通过调用 Microphone 类的静态函数 getMicrophone(),获得一个麦克风实例。
microphone = Microphone.getMicrophone(micIndex);
microphone.setSilenceLevel(0);
microphone.rate = 44;
microphone.addEventListener(SampleDataEvent.SAMPLE_DATA,
onMicData);
为了确保麦克风即使在没有声音时也持续记录,请将静音级别设置为零。microphone.rate = 44; 用于设置声音采样率,它决定了每秒从输入信号采样的数量(本例中为 44100)。
最后一步中,需要为 SampleDataEvent.SAMPLE_DATA 添加一个事件监听器,用于调用 onMicData 函数。
下一步是创建用于编写声音字节的流。文件流以 APPEND 模式打开,这样记录过程中每次写入文件时,将新字节添加到文件最后。为此,您还需要确保在打开流之前删除目标文件;否则,字节将添加到之前的记录部分。
if(targetFile.exists){
targetFile.deleteFile();
}
outputStream = new FileStream();
outputStream.open(targetFile, FileMode.APPEND);
soundBytes = new ByteArray();
声音字节的实际编写在 onMicData 方法中进行,SampleDataEvent.SAMPLE_DATA 事件在记录过程中将反复调用它。该事件有一个 data 属性,此属性是一个包含已记录声音样本的 ByteArray。每个声音样本是一个正常值在 -1 和 1 之间的 32 位浮点数,可使用 readFloat() 方法从字节数组读取它。
protected function onMicData(sampleData:SampleDataEvent):void {
while(sampleData.data.bytesAvailable){
sample = sampleData.data.readFloat();
outputStream.writeShort(sample*32767); // normalize for bitrate 16
}
}
要在之后使用这些字节,需要将值转换为 16 位签名整数,它们可以包含 -32768 和 +32767 之间的值。要执行转换,只需将运算值乘以 32767。随即使用 writeShort() 将样本写入文件流。
要停止记录,将删除 SampleDataEvent.SAMPLE_DATA 事件监听器并关闭文件流。
public function stopRecording():void
{
microphone.removeEventListener(SampleDataEvent.SAMPLE_DATA, onMicData);
outputStream.close();
}
如果运行应用程序,它将生成两个文件:无声的 H.264 视频文件以及一个包含声音原始字节的文件。在下一部分和最后一个部分中,您将使用 FFmpeg 合并这两个文件并生成一个包含视频和音轨的文件。
FFmpeg 是一个用于处理各种媒体文件的跨平台应用程序。它可以通过命令行实现完全控制,并且理解现在的大多数常用视频和音频编解码器和文件格式。它的命令行使用方式及跨平台性质使它成为 AIR 应用程序的理想之选。在本部分中,您将了解如何将 FFmpeg 用作一个外部进程,将视频轨道与原始声音字节合并起来。
VideoSoundMerger 类的一般设置与 ScreenRecorder 类十分相似,因为它也运行本机进程。传递到 NativeProcessStartupInfo 对象的进程参数不同。并且,不必与运行的进程交互,因为它只处理命令并且在完成时自动关闭。以下是使用 FFmpeg 合并声音和视频轨道所使用的命令行参数:
-isync -f s16be -i <PATH TO SOUND FILE> -i <PATH TO
VIDEO FILE> -acodec libfaac -ab 128 -vcodec copy
在 ActionScript 中,这些参数如下:
var processArgs:Vector.<String> = new Vector.<String>();
processArgs.push("-isync");
processArgs.push("-f");
processArgs.push("s16be");
processArgs.push("-i");
processArgs.push(soundFile.nativePath);
processArgs.push("-i");
processArgs.push(videoFile.nativePath);
processArgs.push("-acodec");
processArgs.push("libfaac");
processArgs.push("-ab");
processArgs.push("128");
processArgs.push("-vcodec");
processArgs.push("copy");
processArgs.push(targetFile.nativePath);
调用 p.start startupInfo 启动 FFmpeg 后,它将生成屏幕记录的最终视频文件。
本文涵盖 AIR 2 中的新 NativeProcess API 和麦克风功能的基础知识。NativeProcess API 为扩展 AIR 应用程序带来许多机会。您可能已经想到它令人兴奋的一些用途。
要获得更多灵感,请访问 Adobe AIR 开发人员中心或观看 Adobe AIR 2 新增功能视频。
Adobe AIR Forums |
More |
| 04/11/2012 | Surround sound 5.1 with Air 3.2 on desktop app? |
|---|---|
| 12/12/2011 | Live Streaming H.264 Video on iOS using AIR |
| 04/17/2012 | HTMLLoader - Google Maps? |
| 04/12/2012 | Tabindex in forms on mobile? |
Adobe AIR Blog |
More |