FFMPEG录屏(1)----录制桌面

≡放荡痞女 提交于 2020-03-11 16:56:23

https://blog.csdn.net/peilinok/article/details/102981560

首先录制桌面有很多种方法,原生windows api进行GDI抓屏,Mirror,Direct等,本文针对ffmpeg gdi抓屏进行介绍,也开始录屏软件开发之旅。

准备ffmpeg,无所谓是动态库、静态库,请自行前往下载并引入工程。

在本系列文章中,一些FFMPEG的结构、函数并不会做过多说明,请自行了解,重点放在了桌面录制的整体流程。

参考资料:

ffmpeg 源代码简单分析

初始化FFMPEG

av_register_all();
avdevice_register_all();
准备屏幕参数,包含了帧率、录制区域的起始坐标、大小、是否绘制鼠标等参数。

char buff_video_size[50] = { 0 };
sprintf_s(buff_video_size, 50, "%dx%d", rect.right - rect.left, rect.bottom - rect.top);
 
AVDictionary *options = NULL;
av_dict_set_int(&options, "framerate", fps, AV_DICT_MATCH_CASE);
av_dict_set_int(&options, "offset_x", rect.left, AV_DICT_MATCH_CASE);
av_dict_set_int(&options, "offset_y", rect.top, AV_DICT_MATCH_CASE);
av_dict_set(&options, "video_size", buff_video_size, AV_DICT_MATCH_CASE);
av_dict_set_int(&options, "draw_mouse", 1, AV_DICT_MATCH_CASE);
创建一个AVformatContext句柄,这个结构了不得,将会贯穿整个录屏软件的所有模块,描述了众多音视频信息。

AVFormatContext *_fmt_ctx = avformat_alloc_context();
获取gdigrab

AVInputFormat *_input_fmt = av_find_input_format("gdigrab");
打开gidgrab,这时候就要把准备好的捕获区域等配置信息一同传入api

avformat_open_input(&_fmt_ctx, "desktop", _input_fmt, &options);
获取桌面流信息和索引

avformat_find_stream_info(_fmt_ctx, NULL);
int stream_index = -1;
for (int i = 0; i < _fmt_ctx->nb_streams; i++) {
    if (_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
        stream_index = i;
        break;
    }
}
请务必保存上面获取的索引,他将用于后面的捕获线程。

为gidgrab创建对应的解码器,这一点在后续的声音录制中也很重要,可以通过解码器获取数据的基本信息,如数据格式、采样率等等。

AVCodecContext *_codec_ctx = _fmt_ctx->streams[stream_index]->codec;
AVCodec *_codec = avcodec_find_decoder(_codec_ctx->codec_id);
查找到对应的解码器后,打开或初始化解码器。

avcodec_open2(_codec_ctx, _codec, NULL);
至此我们的初始化工作已经完成,这其中的API调用请务必判断所有的返回值,并进行相应的错误处理。最后,在初始化函数中进行最后一步,释放存放配置信息的字典。

av_dict_free(&options);
接下来就是我们的第一个录制线程了,请以喜欢或者习惯的方式启动一个线程。

为捕获出来的数据初始化两个结构体,AVFrame和AVPacket,这两个结构体也将在各种捕获、压缩、转码过程中出现,最好能读一下结构体介绍。

AVPacket *packet = (AVPacket*)av_malloc(sizeof(AVPacket));
AVFrame *frame_rgb = av_frame_alloc();
随后就是一个while循环进行屏幕数据的捕获以及解码。注意av_read_frame函数将会在某些情况下阻塞,例如读取网络流时,在本例中他将尽可能的按照我们所设定的帧率返回桌面图像数据。

int got_pic = 0;
while (_running == true) {
    ret = av_read_frame(_fmt_ctx, packet);
 
    if (ret < 0) {
        al_fatal("read frame failed:%d", ret);
        break;
    }
 
    if (packet->stream_index == _stream_index) {
      ret = avcodec_decode_video2(_codec_ctx, frame_rgb, &got_pic, packet);
      if (ret < 0) {
        if (_on_error) _on_error(AE_FFMPEG_DECODE_FRAME_FAILED);
        al_fatal("decode desktop frame failed");
        break;
      }
 
      if (got_pic) {
        //do something here with frame_rgba
      }
    }
 
    av_free_packet(packet);
}
 
av_free(frame_rgb);
以上就是通过ffmpeg进行gdi抓屏的全部过程了。下一篇将对桌面数据压缩进行介绍。

 

CSDN源码下载

GitHub持续更新地址


————————————————
版权声明:本文为CSDN博主「ssslar」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/peilinok/article/details/102981560

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!