c++ 读取内存数据 基址_ffmpeg内存实时转码

简单ffmpeg内存转码

上篇文章记录了一个基于FFmpeg的内存播放器,可以使用FFmpeg读取并播放内存中的数据。这篇文章记录一个基于FFmpeg的内存转码器。该转码器可以使用FFmpeg读取内存中的数据,转码为H.264之后再将数据输出到内存。

关于如何从内存读取数据,以及如何将数据输出到内存,可以参考文章:

ffmpeg 从内存中读取数据(或将数据输出到内存)

FFmpeg读写内存的关键点有2个:

1. 初始化自定义的AVIOContext,指定自定义的回调函数。

2. 自己写回调函数。注意函数的参数和返回值(尤其是返回值)。

转码实际上就是解码和编码的结合。该方面的知识可以参考文章:

解码:100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x)

编码:最简单的基于FFMPEG的视频编码器(YUV编码为H.264)

转码: 最简单的基于FFMPEG的转码程序

流程

程序的流程图如下图所示。从图中可以看出,首先分别初始化了输入和输出的AVFormatContext。然后首先解码输入的AVPacket,得到存储像素数据(YUV420P格式)的AVFrame,然后编码AVFrame为H.264的AVPacket,最后将编码后的AVPacket输出。

bf8642c29f566d4c98f8ffc18d3e5cb6.png

FFMPEG基于内存的转码实例

FFMPEG支持内存转码的,但没有现成可用的封装得很好的接口。几经翻阅网络文章,找到了些许方法,结合自己的实验,完成既定目标。网络上暂未发现有此类应用,写出来,尽一人绵薄之力。至于经常偷窃他人成果,亦于此略表心意。

在FFMPEG中,转换视频有一套固定的方式,初始化好参数后,就是调用avformat_write_header写头部信息,调用av_write_frame写一帧数据,调用av_write_trailer写尾部信息,它们都使用AVFormatContext结构体作为参数。

对于使用文件名(file协议)的情况,初始化参数后,调用avio_open来打开文件。后面可以不用管文件名称了。

对于使用ftp协议的情况,除了在协议路径上加“ftp://ip/”,其它的步骤和上述情况一样。但必须注意的是,编译FFMPEG时要添加对应的协议,否则会不成功。另外还要在代码加上avformat_network_init函数进行初始化。

说回本文重点。本文关注的是使用FFMPEG将转换好的视频数据放到内存中,该内存中的数据是完全的视频,直接保存成文件即可播放而不用。很多年以前搞AVI时研究过其格式,知道在写AVI文件时要将文件指针定位到文件头部,写文件总大小,会使用seek函数。有的FTP服务是不支持回写和sekk功能的,这也是为什么我之前的尝试会失败。

鉴于此,想到了将所有的视频数据放到开辟好的内存,而seek则直接用指针来运算。网络有这方面的文章,请参考文后地址。

FFMPEG支持自定义AVIOContext,使用avio_alloc_context返回AVIOContext结构体,同时该函数会传递自定义的read、write、seek函数。再使用avformat_alloc_output_context2函数分配AVFormatContext结构体,再将上面分配的AVIOContext结构体赋值给AVFormatContext的pb成员。

下面说说我所做的步骤。

1、定义好write、seek或read。具体参考文后源码。要注意的是,这里没有读操作,因此不实现,关注的是转码后的数据,因而实现了write和seek。在write过程中,会出现内存不够的情况所以我使用av_realloc函数来扩展内存,每次只扩展一半,不够再扩。

2、创建AVIOContext,关赋值,示例如下:

dde2a2f4c104ffafef95d8c0e5164c74.png

在这里要注意avformat_alloc_output_context2函数,它会分配AVOutputFormat(如果不指定的话),out_filename是根据文件名来判断是哪一种格式,因为我没有限制使用什么格式,这和前面提到不使用文件是两回事。详见代码。

3、由于不使用文件了,所以不需要调用avio_open了。我在这里也纠结好久,一时没转过弯来。

其它就和普通文件的操作类似。

FFMPEG工程浩大,可以参考的书籍又不是很多,因此很多刚学习FFMPEG的人常常感觉到无从下手。因此特地分离出了一个简单的视频编码器供学习之用。 该视频转码器实现了视频格式之间的转换。包含了封装格式的转换以及视音频编码格式的转换。 尽管该视频转码器的代码十分简单,但是几乎包含了使用FFMPEG转码一个视频所有必备的API。十分适合FFmpeg的初学者。

关注+私信免费领取领取一份99的视频学习资料哦

f328a2dcba341f318ffc3a5b76fff168.png

ffmpeg转码速度控制方法

FFMPEG 像读取直播流一样读取文件

HLS当前吵得这么熙熙攘攘的,不知道大伙有没有遇到视频播着播着就卡住的问题

其实播着播着就卡住的这个问题,完全是因为吐流吐得太快了,m3u8更新得太快了,或者生成m3u8列表中的新INF太慢了,导致的数据处理问题,卡住,ffmpeg的转码进度其实可以控制,通过help可以看到如下信息:

e7c08bac1ff1f7e9eedb98960de49538.png

可以使用-re这个参数来控制转码的速度,也就是说,像是播放实时流一样的输出文件,这么做可以控制HLS输出的速度,非常nice

关注+私信可以免费领取一份99的视频学习资料哦,内容包括:C/C++,Linux,golang,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,ffmpeg,

DPDK,嵌入式 等。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值