Skip to content

haoyang6551/screen_recorder

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

录屏软件

简介

本项目是为了学习FFmpeg开发使用,使用FFmpeg多个库文件(如libavcodec, libavformat, libswresample, libavfilter)中的函数开发录屏软件,同时了解音视频采集、编码、封装的过程。

内容

一、录制桌面视频

1. 打开gdigrab

使用FFmpeg gdi录制桌面。打开音视频输入文件的函数为

int avformat_open_input(AVFormatContext **ps, const char *url, ff_const59 AVInputFormat *fmt, AVDictionary **options);

其中url参数可以是文件名,也可以是流的名称。设置url参数为"desktop",设置fmt参数为av_find_input_format("gdigrab")获得,打开gdigrab。通过options参数设置录屏的区域坐标。

2. 解析输入流中的视频信息

使用int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)函数解析输入文件的媒体流信息,该函数做的工作主要是遍历输入音视频文件中的各路媒体流,读取各路媒体流的信息(如解码器信息),将读取到的流信息保存到输入参数AVFormatContext *icic->streams成员中。

3. 解码录屏视频流

上一步解析视频流的信息保存到了AVFormatContextstreams成员中,而streamAVCodecContext *codec成员包含了解码器相关信息。通过如下代码查找到解码器。

codec_ctx_ = fmt_ctx_->streams[stream_index]->codec;
codec_ = avcodec_find_decoder(codec_ctx_->codec_id);

通过int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)函数对解码器上下文avctx进行初始化。该函数给AVCodecContext内部的数据成员分配内存空间,进行解码参数的校验。

初始化解码相关参数后,将开启桌面图像录制线程。通过int av_read_frame(AVFormatContext *s, AVPacket *pkt)读取一帧录取并压缩后的数据,通过AVPacket结构中的stream_index成员判断这是不是压缩后的视频帧,如果是是一所后的视频帧,通过int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt)将该帧数据送入解码器中,然后通过int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)读取解码器解码后的视频帧,将该帧存到队列中,等待后续编码线程从该队列中取出并编码。录屏线程和后续的编码线程实际是”生产者与消费者“的关系。

二、录制麦克风和扬声器音频

通过FFmpeg对virtual-audio-capturer进行捕获,需要安装screen-capture。录制麦克风扬声器音频的流程和调用的函数和录制桌面视频大致一样。

三、视频格式转换

录屏得到的视频流时RGBA格式的,而H.264编码器的输入格式为YUV,所以编码录屏视频流前,需要对视频流进行格式转换。

格式转换主要利用了libswscale库中的函数,首先初始化SwsContext上下文信息,其中保存了输入图像和输出图像的宽高、像素格式等参数,然后调用sws_scale函数进行转换。

初始化SwsContext用了如下函数,函数的flags参数指定图像在缩放时使用的采样算法或插值算法

struct SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat,
                                  int dstW, int dstH, enum AVPixelFormat dstFormat,
                                  int flags, SwsFilter *srcFilter,
                                  SwsFilter *dstFilter, const double *param);

SwsContext函数声明如下

int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[],
              const int srcStride[], int srcSliceY, int srcSliceH,
              uint8_t *const dst[], const int dstStride[]);

其中srcSlice为一个数组,这个数组保存了图像每个缓存通道的地址,类似于AVFramedata成员。srcStride为一个数组,这个数组记录了输入源图像的每个缓存通道的长度,类似于AVFramelinesize成员。srcSliceY为输入源图像数据在通道中的起始位置偏移量。srcSliceH为输入源图像的通道个数。dst为输出目标图像的缓存地址数组,dstStride为输出目标图像的缓存宽度数组。

四、视频编码

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published