FFmpeg API 熟悉记录,目标:播放本地MP4

发布时间 2023-04-14 14:08:32作者: J0K3Rzz
  1. 简要熟悉api之后 包括解码器,编码器,输入输出文件之后,开始分析ffplay,我们知道ffplay使用的是sdl的相关库进行播放,在这里我将把sdl舍弃,移植到android平台上即可。

  2. 简单手撸播放器的想法,看了几天代码 和ffplay的源码分析,和ijkplayer的部分实现思路,总结来说,大致流程图比较简单,先熟悉posix多线程c++语法,然后根据流程图大致实现相关的功能,这里只实现简单的播放功能。

  3. 简单流程

     

     

     

  4. 先简单只播放本地文件,我的c功底不好,也先从c开始吧。

  • List item从读取音频的播放开始,基本上音视频同步是以音频播放的时序为准
    大概流程图

 

 

初始化播放音频线程

目前进度写到解析出音频的frame 但是需要播放的接口,了解到有OpenSL 这么一个东西
刚好joyy有位老大哥分享了他学习ffmpeg的demo https://github.com/jiangdongguo/FFMPEG4Android
这里它的实现大同小异,我主要是学习OpenSL的使用方法和对应的格式。后续播放视频的相关surface 使用在他的项目中也有使用,很受用,基本上有很多疑惑都可以从他的demo中找到 https://juejin.cn/post/7031848037311840293 这个文章不错 ,可以大致了解一下

  1. 音频 关键字

采样率 sampleRate = 1s采集的样本数
采样深度 sampleFomat
声道数 nb_channel
音频帧的样本数 nb_samples
一帧播放时间 = 采样率/音频帧的样本数 sampleRate/nb_samples

遇到的问题:
1.写到一半发现ffmpeg会把所有的packet一起读出来,不会单独只读某个流里的avpacket,api并没有支持某个特定流的,所以必须得过滤掉其它index的流。
2.不知道为什么怎么解析音频流avcodec_receive_frame都没有EOF的返回?好像只能判断没有下一个packet去结束解码,打断点是结束的了,但是无法打印相关日志
3.简单实现完了 但是一直有崩溃,需要追查一下原因
4. 2023 2.13 音频demo完成 目前问题就是 播放时间不知道为什么这么长,而且没有声音。。。待排查
播放时间长的原因是重采样的格式未对应,没有声音待解决
swr_init in:nb_channel:1 sampleFormat:8 sampleRate:44100 out:nb_channel:2 sampleFormat:1 sampleRate:44100
createOpenSLEngine nbChannels:2 sampleRate:44100 sampleFormat:1
解决:
没有声音的原因是因为我free了pcm的数据。。当时为了写demo写快了,忘记把相关代码删除,下次需要留一个好一点的习惯,现在还有一个问题就是有杂音而且仔细发现时长稍长,这个稍微思考一下确认是pcm的size应该设置变长了,可以发现播放时间长的原因是播放pcm设置的size为缓冲区的大小,重新按照转换后的nb_samples重新计算size即可。

7.播放视频,这里分两部分,一个是显示RGB数据,一个是音视频同步部分

  • 显示RGB数据
    得益于ffmpge的接口设计,解码视频的流程和音频的大同小异。
    难点:需要了解andorid的surface原理和合理设计解码的数据传递方向
    大致学习了一下,主要存在一下几个问题:
    1.缓冲区格式和视频解码格式对应问题,
    这个问题还是比较好解决,统一设置缓冲区的图片格式为ARGB8,解码出来的格式缩放并使用ARB8缓存出来
    2.jni层和java层surface传递问题,相关资料阅读一下即可,这里略过
  • 音视频同步部分(待完成)
    1.android显示是有VSYNC信号的,也就是视频的timebase和VSYNC的timebase直接是有差异的,这里还有加上一个音频的timebase,这里需要制定一个策略将三者的timebase结合。
    目前可以记录音频和视频播放的播放位置,但是同步策略为简单暂时先放弃VSYNC的信号,按照音视频流一起解析至缓冲区,也就是忽略VSYNC的影响,只用音视频同步,并将视频的帧推至缓冲区中。这里采用ffplay的同步策略
    2.视频的帧比较大,需要注意缓冲区的时机,视频解码线程阻塞获取视频帧问题,实现了缓冲区,但是有个问题就是读取readpacket 的时候生产视频和音频的在同一个线程,其中一个缓冲区满了都会影响下一个包的读取,主要需要的是即时将依赖的缓冲区清空。按照视频播放的规律都是可以即时清理干净的
    3.视频文件较大的时候packet不可以全部解析至内存中,视频帧也是用两个buffer即可。
    4.如何确定到底谁慢谁快
    这里出现了一个问题就是,不知道为什么视频帧的速度解析速度一直比音频的慢就导致音频播放的时候无法等待视频解析但是视频帧数一直解析不过来

自己研究的很有问题,这里还是跟着书从头开始《音视频开发进阶指南》
其实看了一下 也没差多少 ,主要是想迁移一下音频同步模块的差异。