[关闭]
@ltlovezh 2021-01-11T16:54:32.000000Z 字数 1853 阅读 1155

AVIOContext和边合成边上传

ffmpeg


基础知识

AVFormatContext->pb是一个AVIOContext结构体,负责IO操作。
一般情况下,我们通过avio_open函数创建并初始化AVFormatContext->pb;通过avio_closep函数关闭AVFormatContext->pb。

  1. // 创建AVIOContext,用于读写url标识的文件
  2. int avio_open(AVIOContext **s, const char *url, int flags);
  3. // 关闭AVIOContext资源
  4. int avio_closep(AVIOContext **s);

Mux流程:

  1. avio_open(打开AVIOContext)
  2. avformat_write_header(写封装格式头信息)
  3. av_interleaved_write_frame(写入AVPacket)
  4. av_write_trailer(写封装格式尾信息)
  5. avio_closep(关闭AVIOContext)

边合成边上传

所谓边合成边上传,就是在写文件的同时,通过回调向外抛出一份Buffer数据,业务侧可以基于Buffer数据同步做文件上传。

核心逻辑就是创建自定义AVIOContext,接管文件IO。

  1. // 创建Buffer
  2. uint8_t *avio_buffer = (uint8_t*)av_malloc(avio_ctx_buffer_size);
  3. // 创建AVIOContext,read_packet函数负责读buffer,write_packet负责写buffer,seek_user负责seek
  4. AVIOContext io = avio_alloc_context(avio_buffer, avio_ctx_buffer_size, 1, opaque, &read_packet, &write_packet, &seek_user);
  5. io->seekable = AVIO_SEEKABLE_NORMAL;
  6. AVFormatContext->pb = io;

Mux时,AVIOContext->write_packet收到Buffer数据,可以一边写文件,一边向外回调Buffer,业务侧进行同步上传。

下面的48字节,一开始就会输出,其中ftyp和free box是固定的40字节,最后8字节表示mdat box header,在所有AVPacket输出完之后(只有所有AVPacket都输出完了,才知道mdat box size),会更新40~43字节的mdat box size。

  1. ftyp box header
  2. 0, 0, 0, 20, // ftyp box 共32字节
  3. 66, 74, 79, 70,
  4. 69, 73, 6f, 6d,
  5. 0, 0, 2, 0,
  6. 69, 73, 6f, 6d,
  7. 69, 73, 6f, 32,
  8. 61, 76, 63, 31,
  9. 6d, 70, 34, 31,
  10. free box header
  11. 0, 0, 0, 8, // free box 共8字节
  12. 66, 72, 65, 65,
  13. mdat box header
  14. 0, d, a1, af,
  15. 6d, 64, 61, 74,

最后生成的Mp4文件,正好可以与前48字节对应起来:
ftyp

输出完所有AVPacket之后,调用av_write_trailer输出尾部数据,例如:Mp4的moov box。

调用av_write_trailer之后,AVIOContext->write_packet首先重写mdat box size(40~43字节),然后输出moov数据。

  1. moov box header
  2. 0, 0, 10, 2d, // moov box size
  3. 6d, 6f, 6f, 76,
  4. // 后续为moov具体内容
  5. 0, 0, 0, 6c,
  6. 6d, 76, 68, 64
  7. ............

最终生成的Mp4文件,正好与尾部数据一致:
moov

总结

AVIOContext->write_packet函数首先输出48字节,包含ftyp box、free box、mdat box header,然后输出所有的AVPacket,最后调用av_write_trailer函数后,AVIOContext->write_packet函数先调整40~43字节的mdat size,然后输出moov box。

在边合成边上传场景中,可以先缓存48字节的文件头和MOOV文件尾,等到所有AVPacket向外回调之后,再单独回调文件头Buffer和文件尾Buffer。

因为会存在修改已上传数据(40~43)的情况,并且上传SDK并不支持这种操作,所以才分为文件主内容(AVPacket)、文件头和文件尾三部分向外回调。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注