ffmpeg rtmp 不清晰_ffmpeg4从笔记本摄像头推流rtmp

最近由于工作计划的需要,开始研究ffmpeg。

对于命令行的推流服务,其实很简单。但是融合在自己的程序里,不好控制。尤其是在父进程异常关闭的时候,不一定能把 ffmpeg进程干掉,造成一些异常。另外,命令行的最大问题是不能精细化的管理ffmpeg的推流,比如网络不好的情况下,不好感知和处理。

ffmpeg网上买了一些课程,发现大部分都是针对ffmpeg3的,目前的ffmpeg主要是4。语法有较大的不同。

花了一周的时间研究,发现网上的很多代码是多少有点问题。

最后自己用ffmpeg4实现了一版摄像头捕捉推流,有些坑在这里标注一下。其中一些难点和诀窍,很多地方没有说明,我在这里记录一下。

完整可运行的代码,我放在了我的github上。

https://github.com/freeeyes/ffmpeg4_camera_to_rtmp​github.com

在windows下,首先,要获得摄像头的列表,目前windows的设备主要依靠的是dx。

在ffmpeg中,获得列表命令行是:

ffmpeg -list_devices true -f dshow -i dummy  

对应ffmpeg的C++代码如下:

void show_dshow_device(){
    AVFormatContext *pFormatCtx = avformat_alloc_context();
    AVDictionary* options = NULL;
    av_dict_set(&options,"list_devices","true",0);
    AVInputFormat *iformat = av_find_input_format("dshow");
    printf("Device Info=============n");
    avformat_open_input(&pFormatCtx,"video=dummy",iformat,&options);
    printf("========================n");
}

但实际上,这个并不能给代码使用,因为你无法解析输出来的数据。

虽然我在网上查到了一些获得日志输出的回调,但是实际依旧无法操作(你不可能把av_log里面的所有输出全部解析出来,仅仅是为了获得列表)

于是,自己用dx实现了一个,这本身也不难弄。

void 

这里返回了一个vector容器。这里包含了所有显示设备列表,包括USB摄像头。

如果是音频,你可以使用CLSID_AudioInputDeviceCategory获得所有的音频设备列表。

具体实现,可以参考,vediolist.h文件。都是dx的函数,在这里不做具体赘述。

摄像头转rtmp推流到远端,在实现代码中,需要几个过程。

(1)设置原始摄像头的相关参数。

这里有一个东西一定要注意。

对于摄像头的获取,并不是所有的参数都是有效的。

ffmpeg支持字典结构化参数。(多一句嘴,这里最好大家详细的学习了解一下ffmpeg头文件options_table.h,对开发ffmpeg的基础非常有帮助)

av_dict_set

这里的ioptions参数,有些可以控制原始摄像头的参数。比如分辨率大小,帧率,以及编码格式。

这里我要强调一下,pixel_format这个参数。

这里面支持的原始视频流编码格式有很多,具体参见pix_fmt.h的枚举类型。有很多,但是硬件摄像头并不是全部都支持的,要看摄像头支持哪种编码流,一般情况下,摄像头输出的流都是原始流,比如mjpg和YUYV422。

这里的输入流获取,最好使用YUYV422原始编码格式。

(2)创建编码器。

这里很简单,编码器顾名思义就是把码流转换成一种输出的码流。并提供编码过程。

默认目前大部分都使用h264,h265规则其实ffmpeg也是支持的,但是由于专利费的问题,价格过高,实际使用h265的设备生产环境目前还不多。我们就以h264为主。

ffmpeg的编码器支持很多。最常用的就是h264

AVCodec

(3)创建推流。

这里其实更简单,有些参数,可以从输入流中直接设置上。

当然,你也可以设置你想要的输出流的一些参数。

基本都是固定的代码。

AVStream

(4)绑定编码器和推流

这里,主要是声明一个emcode工具,告诉ffmpeg你需要把什么格式的编码流,转成什么格式的编码流。

代码也几乎是固定的。

struct 

(5)不断获得原始帧,通过编码器将原始帧转化为AV_PIX_FMT_YUV420P编码,然后封装入推流的帧,把数据发送出去。

这里需要一个while循环。(这里你可以控制while循环的条件,实现自由控制流的上传和关闭)

这里要特别注意发出流的pts和dts,不能使用输入流的。因为输入流没有考虑网络延迟的情况,所以你在推流的时候,一定要自己重新计算。

if 

以上代码大部分都是固定的。

理解后,你会发现其实ffmpeg的结构非常清晰。

最后放一个测试成功的代码,远端的推流服务器用的是srs。

9292c47a03f551311b6e45e9d7f42ff5.png

以上,全部代码达成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值