文章实时采集(这是捕获音视频而后生成avi,再进行264编码的方法 )
优采云 发布时间: 2022-02-16 01:05文章实时采集(这是捕获音视频而后生成avi,再进行264编码的方法
)
转载:0. 前言
前两篇文章中写了DirectShow中采集音视频,生成avi,然后264编码的方法。该方法有一定的局限性,不适合实时应用,例如:视频会议、视频聊天、视频监控等。本文使用的技术适合这种实时应用。对来自采集的每一帧音视频进行处理后,实现实时编码和实时输出。这是我的直播系列申请的一部分。目前的情况是输入端使用DirectShow技术采集音视频,然后用h.264编码视频,用aac编码音频,在输出端生成文件。扩展输入输出,支持文件、桌面输入、RTSP、RTMP、HTTP 和其他流协议输出。html
1. linux简单介绍
首先是捕获,这里使用DirectShow对其进行了一定程度的封装,包括音频和视频。好处是可以直接使用原生的api,可以随意修改。缺点是不能跨平台。采集音视频的应用也需要下放到Linux平台上。有一种跨平台的方式,视频可以使用OpenCV,音频可以使用OpenAL或者PortAudio等等,就这样。网络
编码有很多选择。视频方面有H264、MPEG-4、WebM/VP8、Theora等,音频方面有Speex、AAC、Ogg/Vorbis等,都有相应的开源项目解决方案。我用的是x264做H264编码,libfaac做aac编码,以后是否改变编码方案,具体项目需求再说。这里要提一下WebM,谷歌牵头的一个项目,完全开放免费,采用VP8和Vorbis编码,webm(mkv)封装,很多巨头都支持,目的是替代目前的H264视频编码,号称比后者,我没有测试过实际效果。但是,如果一家商业公司带头,情况就不同了。各种支持都很全面,有时间可以关注一下。api
2. 逻辑和流程
基本思路是实现dshowISampleGrabberCB接口,通过回调保存每个缓冲区。除了接口线程和dshow本身的线程外,我们分别启动了AudioEncoderThread和VideoEncoderThread两个线程,分别从SampleGrabber中提取数据,调用encoder进行编码,编码后的文件可以直接输出。看图:post
程序是用VS2010搭建的,见张项目截图:test
Base 下面是对系统 API 的一些简单封装,主要是线程和锁。这里我简单封装了dshow的抓包过程,包括graph builder的建立,filter的链接等等,directshow是出了名的难用。由于是VS2010,调用了Windows SDK 7.1中的dshow,没有qedit.h文件,官方定义了ISampleGrabberCB。别着急,系统里还有qedit.dll,我们要做的就是从Windows SDK 6.0中拷贝出来,然后将这几行代码添加到stdafx.h中,然后我们将能够ui
1 #pragma include_alias( "dxtrans.h", "qedit.h" )
2 #define __IDxtCompositor_INTERFACE_DEFINED__
3 #define __IDxtAlphaSetter_INTERFACE_DEFINED__
4 #define __IDxtJpeg_INTERFACE_DEFINED__
5 #define __IDxtKey_INTERFACE_DEFINED__
6 #include "qedit.h"
3. 音视频编码
相关文件:水疗
Encoder下面是音视频编码相关的代码。X264Encoder封装调用x264编码器的操作,FAACEncoder封装调用libfaac编码器的操作,VideoEncoderThread和AudioEncoderThread负责主进程。下面我贴出关键代码,大家可以参考。
A. 视频编码线程
主要流程是先初始化x264编码器,然后开始循环调用DSVideoGraph,从SampleGrabber中取出视频帧,调用x264进行编码。过程比较简单,调用的频率就是你想要得到的视频帧率。需要注意的是,x264 编码比较耗时。在计算线程Sleep时间的时候,要计算这个进程消耗的时间,避免采集的视频帧率错误。
B. 音频编码线程
主要流程与视频编码线程相同。它还初始化FAAC编码器,然后循环调用DSAudioGraph,从SampleGrabber中取出视频帧,调用faac进行编码。和视频不同,音频采样的频率非常快,所以必须采集几乎连续进行,但前提是在SampleGrabber中捕获到新数据,否则你的程序cpu会100%,IsBufferAvailaber( ) 在下面的代码中用于此检测。
调用faac进行编码的时候需要注意,要特别注意,否则编码后的音频会很不正常,做的不好会很头疼。先看下faac.h的相关接口
1 faacEncHandle FAACAPI faacEncOpen(unsigned long sampleRate, unsigned int numChannels,
2 unsigned long *inputSamples, unsigned long *maxOutputBytes);
3
4 int FAACAPI faacEncEncode(faacEncHandle hEncoder, int32_t * inputBuffer, unsigned int samplesInput,
5 unsigned char *outputBuffer, unsigned int bufferSize);
faacEncEncode的第三个参数是指传入样本的数量,应该等于调用faacEncOpen返回的inputSamples。为此,在 dshow 中设置 buffsize,公式为:
BufferSize = aac_frame_len * channels * wBytesPerSample
// aac_frame_len = 1024
4. 程序界面
跑步
采集完成后生成aac和264文件
MediaInfo读取生成的aac文件的编码格式
生成的264文件是MediaInfo读取的编码格式
用mp4box封装,将264和aac存储在mp4容器文件中,就可以在播放器中播放了