新手学习FFmpeg - 调用API完成录屏并进行H.264编码
Screen Record H.264
目前在网络传输视频/音频流都一般会采用H.264进行编码,所以尝试调用FFMPEG API完成Mac录屏功能,同时编码为H.264格式。
在上一篇文章中,通过调用FFmpeg API完成了Mac平台下的录屏功能。在本篇中,对上次的录屏进行优化,将采集到的视频流编码为H.264格式,同时设定FPS和分辨率。
因为是对上次录屏功能的优化,因此处理思路仍然分为三部分:
- 打开输入设备(默认的屏幕设备)
- 初始化输出设备(mp4文件)
- 内容转码
和上次使用的API对比,本次主要增加了涉及到H.264参数设定和H.264 pts/dts 设定的API:
- avcodec_parameters_from_context
- av_rescale_q
初始化输入设备
仍然采用上篇中打开设备的方法:
- 通过
av_find_input_format("avfoundation")获取AVInputFormat。 - 通过
avformat_open_input打开指定的屏幕设备。
然后FFmpeg会返回此设备中的数据流,而FFmpeg处理数据流一般都遵循:确定codec(编码 or 解码)->初始化codec上下文参数->打开codec,这三步。 针对输入设备也就是下面的顺序:
avcodec_find_decoder -> avcodec_alloc_context3 -> avcodec_open2
AVInputFormat会有多个数据流(视频流/音频流),所以首先找到需要处理的流:
codecpar->codec_type == AVMEDIA_TYPE_VIDEO
然后依次调用avcodec_find_decoder,avcodec_alloc_context3和avcodec_open2来初始化codec。
初始化输出设备
最后是将视频数据编码为H.264,并封装到MP4容器中。所以文件名仍设定为out.mp4。
打开输出设备的方法和打开输入设备方法类似:
avcodec_find_encoder -> avcodec_alloc_context3 -> avcodec_open2 -> avformat_write_header
最后的avformat_write_header不是必须的,只有当容器格式要求写Header时才会调用。与上篇中不同的时,明确指定输出CodecContext的编码器类型:
outCodecContext->codec_id = AV_CODEC_ID_H264;
outCodecContext->codec_type = AVMEDIA_TYPE_VIDEO;
outCodecContext->pix_fmt = AV_PIX_FMT_YUV420P;
outCodecContext->bit_rate = 400000; // 2500000
outCodecContext->width = 1920;
outCodecContext->height = 1080;
同时H.264对pts和dts有要求,因此需要设定timebase:
outCodecContext->time_base = (AVRational) {1, 25};
转码
有了上次的经验之后,处理转码就会稍显简单。 处理流程大致为:
while av_read_frame
|
+---> avcodec_send_packet
|
+----> while avcodec_receive_frame
| 对每一数据帧进行解码
| 通过`sws_scale`进行源帧和目标帧的数据转换
|
+----> avcodec_send_frame
|
+---> while avcodec_receive_packet
|
|
+--->av_interleaved_write_frame (写入到输出设备)
转码最重要的环节就是在avcodec_receive_frame之后的逻辑。 上面说过H.264对pts有要求,因此这里需要对每一帧添加pts值。
int64_t now = av_gettime();
const AVRational codecTimebase = outStream->time_base;
oframe->pts = av_rescale_q(now, (AVRational) {1, 1000000}, codecTimebase);
在最后写入到输出设备之前,仍需要修改pts值:
if (opacket->pts != AV_NOPTS_VALUE)
opacket->pts = av_rescale_q(opacket->pts, outCodecContext->time_base, outStream->time_base);
至此就完成了对视频进行H.264编码的过程。可以看到和上篇处理过程大致相同,唯一不同的地方就是针对H.264编码格式进行了一些特殊处理,除此之外大致流程完全一致。
源码请点击 https://andy-zhangtao.github.io/ffmpeg-examples/
新手学习FFmpeg - 调用API完成录屏并进行H.264编码的更多相关文章
- 新手学习FFmpeg - 调用API完成录屏
调用FFMPEG Device API完成Mac录屏功能. 调用FFMPEG提供的API来完成录屏功能,大致的思路是: 打开输入设备. 打开输出设备. 从输入设备读取视频流,然后经过解码->编码 ...
- 新手学习FFmpeg - 调用API编写实现多次淡入淡出效果的滤镜
前面几篇文章聊了聊FFmpeg的基础知识,我也是接触FFmpeg不久,除了时间处理之外,很多高深(滤镜)操作都没接触到.在学习时间处理的时候,都是通过在ffmpeg目前提供的avfilter基础上面修 ...
- 新手学习FFmpeg - 调用API完成视频的读取和输出
在写了几个avfilter之后,原本以为对ffmpeg应该算是入门了. 结果今天想对一个视频文件进行转码操作,才发现基本的视频读取,输出都搞不定. 痛定思痛,仔细研究了一下ffmpeg提供的examp ...
- 新手学习FFmpeg - 调用API完成两个视频的任意合并
本次尝试在视频A中的任意位置插入视频B. 在上一篇中,我们通过调整PTS可以实现视频的加减速.这只是对同一个视频的调转,本次我们尝试对多个视频进行合并处理. Concat如何运行 ffmpeg提供了一 ...
- 新手学习FFmpeg - 调用API计算关键帧渲染时间点
通过简单的计算来,线上I帧在视频中出现的时间点. 完整代码请参考 https://andy-zhangtao.github.io/ffmpeg-examples/ 名词解释 首先需要明确以下名词概念: ...
- 新手学习FFmpeg - 调用API调整视频局部速率
通过修改setpts代码实现调整视频部分的播放速率. 完整代码可参考: https://andy-zhangtao.github.io/ffmpeg-examples/ 在前面提到了PTS/DTS/T ...
- 新手学习FFmpeg - 通过API实现可控的Filter调用链
虽然通过声明[x][y]avfilter=a=x:b=y;avfilter=xxx的方式可以创建一个可用的Filter调用链,并且在绝大多数场合下这种方式都是靠谱和实用的. 但如果想精细化的管理AVF ...
- 新手学习FFmpeg - 通过API完成filter-complex功能
本篇尝试通过API实现Filter Graph功能. 源码请参看 https://andy-zhangtao.github.io/ffmpeg-examples/ FFmpeg提供了很多实用且强大的滤 ...
- android 调用 screenrecord 实现录屏
首先要说明的是并未实现,本文讲一下自己的思路. adb 使用shell 命令 screenrecord 可录屏. 自己写了个app,通过Process p = Runtime.getRuntime() ...
随机推荐
- springcloud-eureka
作者:纯洁的微笑出处:http://www.ityouknow.com/ 版权归作者所有,转载请注明出处 Eureka是Netflix开源的一款提供服务注册和发现的产品,它提供了完整的Service ...
- SQL语句中的as
- 2019年一半已过,这些大前端技术你都GET了吗?- 上篇
一晃眼2019年已过大半,年初信誓旦旦要学习新技能的小伙伴们立的flag都完成的怎样了?2019年对于大前端技术领域而言变化不算太大,目前三大技术框架日趋成熟,短期内不大可能出现颠覆性的前端框架(内心 ...
- linux字符设备驱动中内核如何调用驱动入口函数 一点记录
/* 内核如何调用驱动入口函数 ? *//* 答: 使用module_init()函数,module_init()函数定义一个结构体,这个结构体里面有一个函数指针,指向first_drv_init() ...
- logging模块 旗舰版
函数式简单配置 import logging logging.debug('debug message') logging.info('info message') logging.warning(' ...
- LFS8.3BOOT引导疑点解决
LFS系统 的BOOT引导 在LFS书中写到的BOOT引导,时直接将宿主机的BOOT分区挂载当LFS的BOOT分区中,虽然这样也是可以实现BOOT引导的,但是我并不想这样做,所以BOOT引导就变得有些 ...
- lvs+keepalived 高可用及负载均衡
一.环境准备 VIP:10.18.43.30 dr1:10.18.43.10 dr2:10.18.43.20 web1:10.18.43.13 web2:10.18.43.14 结构图 (一).预处理 ...
- [Inno Setup]写入注册表时32位系统和64位系统的路由
昨天下午组内一位同事跟说,他想在Inno Setup的安装包中写入一个注册表.目标位置是HKLM:\Software\下面创建自己的注册表项.然后说尝试了好几次都不行, 但是往HKCU下面写入却是OK ...
- Transformation HDU - 4578(线段树——懒惰标记的妙用)
Yuanfang is puzzled with the question below: There are n integers, a 1, a 2, …, a n. The initial val ...
- Streaming+Sparksql使用sql实时分析 rabbitmq+mongodb+hive
SparkConf sparkConf = new SparkConf()//此处使用一个链接切记使用一个链接否则汇报有多个sparkcontext错误 .setAppName("Spark ...