美文网首页
JNI——FFmpeg音视频同步(二)

JNI——FFmpeg音视频同步(二)

作者: 追寻米K | 来源:发表于2018-10-10 23:11 被阅读0次

    使用OpenSL_ES播放声音

    之前的播放声音是转码得到数据后主动放进AudioTrack进行播放,OpenSL就属于被动了,播放器开始播放先从缓冲区取数据,播放完了调用回调方法再去获取数据。

    OpenSL_ES 跟JNI里的env 很类似,通过结构体实现对象的概念。

    OpenSL ES的开发流程主要有如下6个步骤:

            1、创建引擎对象

            2、创建播放器(录音器)

            3、设置缓冲队列和回调函数

            4、设置播放状态

            5、启动回调函数

            其中创建播放器有需要设置混音器

            其中3和4是播放PCM等数据格式的音频是需要用到的。

    创建OpenSL_ES 对象有个生命周期的概念。

    创建成功后,都进入 SL_OBJECT_STATE_UNREALIZED 状态,这种状态下,系统不会为它分配任何资源,直到调用 Realize 函数为止。

    Realize 后的对象,就会进入 SL_OBJECT_STATE_REALIZED 状态,这是一种“可用”的状态,只有在这种状态下,对象的各个功能和资源才能正常地访问。

    当调用对象的 Destroy 函数后,则会释放资源,并回到 SL_OBJECT_STATE_UNREALIZED 状态。

    生命周期

    播放pcm:

    第一步:创建播放引擎

    第二步:创建播放器

    创建播放器参数

    channel可以设置为2。

    创建播放器需要设置混音器

    其他两个参数

    真的要创建播放器了

    第三步:设置缓冲队列和回调函数

    第四步:设置播放状态

    可以初始化音量控制对象,调节声音大小。

    第五步:启动回调函数

    播放URI

    跟上面的差不多,就是设置SLDataSource这个参数的时候不一样,还不用调用回调方法。

    代码

    音视频同步:

    av_samples_get_buffer_size()可以得到一帧视频的大小size,采样率为什么44100,1秒的数据大小为44100*2*2(双通道16位),一帧的音频播放时间为size除以44100*2*2。

    音视频的同步不是绝对的同步,以音频播放时间为基准(因为人对视频的感知比音频弱),视频或快或慢来同步,用音频帧播放时间减去视频帧播放时间大于某个值,就任务产生延迟了,视频播放通过USleep()来调整视频帧的播放速度达到同步效果。

    在视音频流中的包中都含有DTS和PTS。DTS,Decoding Time Stamp,解码时间戳,告诉解码器packet的解码顺序;PTS,Presentation Time Stamp,显示时间戳,指示从packet中解码出来的数据的显示顺序。

    视频的编码要比音频复杂一些,特别的是预测编码是视频编码的基本工具,这就会造成视频的DTS和PTS的不同。这样视频编码后会有三种不同类型的帧:

             I帧 关键帧,包含了一帧的完整数据,解码时只需要本帧的数据,不需要                              参考其他帧。

            P帧 P是向前搜索,该帧的数据不完全的,解码时需要参考其前一帧的数                                 据。

            B帧 B是双向搜索,解码这种类型的帧是最复杂,不但需要参考其一帧的                                  数据,还需要其后一帧的数据。

    I帧的解码是最简单的,只需要本帧的数据;P帧也不是很复杂,值需要缓存上一帧的数据即可,总体来说都是线性,其解码顺序和显示顺序是一致的。B帧就比较复杂了,需要前后两帧的顺序,并且不是线性的,也是造成了DTS和PTS的不同的“元凶”,也是在解码后有可能得不到完整Frame的原因

    假如一个视频序列,要这样显示I B B P,但是需要在B帧之前得到P帧的信息,因此帧可能以这样的顺序来存储I P B B,这样其解码顺序和显示的顺序就不同了,这也是DTS和PTS同时存在的原因。DTS指示解码顺序,PTS指示显示顺序。

    在计算某一帧的显示时间之前,现来弄清楚FFmpeg中的时间单位:时间基(TIME BASE)。在FFmpeg中存在这多个不同的时间基,对应着视频处理的不同的阶段(分布于不同的结构体中)。在本文中使用的是AVStream的时间基,来指示Frame显示时的时间戳(timestamp)。

    1、解码视频

    解码视频

    2、计算当前帧播放的延迟时间延迟并不断纠正

    计算当前帧播放的时间

    3、拿到视频显示时间和音频的播放时间进行比较,然后控制视频的延迟时间

    4、得到正确的视频帧延迟时间,最后绘制

    对于actual_delay的理解:

    demo代码

    相关文章

      网友评论

          本文标题:JNI——FFmpeg音视频同步(二)

          本文链接:https://www.haomeiwen.com/subject/forobftx.html