关于OpenSL ES播放音频数据的一个奇怪的问题

Author:lihaiping1603@aliyun.com

最近用业余时间做了一个android平台的播放器sdk,其中视频用的opengl es,音频用的opensl es 做渲染,其中整个播放器在音视频同步的过程中,使用的视频同步到音频的方式,以音频作为主时钟。

今天在测试的过程中发现一个奇怪的问题,我音频数据的填充,使用了单独的音频线程,这其中的实现,主要参考ijk的实现代码和方式。

整个流程方式:我在音频播放的过程中设置的200ms的播放缓冲区给底层队列,当我把音频数据缓冲区填满以后,就wait_timeout(1s),如果在wait的过程中,底层有回调,就会signal,从而唤醒wait函数,然后再查询缓冲区大小,是否可以填充数据,如果可以填充数据的话,就填充数据进去,同时在填充数据的函数中,通过计算音频的pts和缓冲区的剩余数据大小,来更新当前的音频播放时钟位置。其中问题就是出在更新音频时钟位置的这个地方,我们计算剩余缓冲区的数据大小的时候,通过调用这个函数来获取底层数据的缓冲区延时:

通过计算state.count的计数来获取这个延时时间。

那么现在的问题现象是这样的,在视频正常播放的过程中,我填充了200ms满的缓冲区音频数据去播放,在填充数据线程中wait,然后在大概过了120ms之后,底层回调:

发送信号唤醒wait函数,然后我去拷贝音频数据,拷贝完数据之后,计算时钟,这个时候查询底层缓冲区数据还剩多少,发现state.count=17,也就是说填满的时候20,现在获取还剩17,意思是中间难道只消耗了30ms的音频数据?不太可能啊,正常播放的情况下,120ms应该消耗120ms的音频数据才对啊,为啥这个地方只消耗了30ms的数据呢?

经过进一步的排查和分析,发现了问题,如果经过了120ms的播放时间,底层实际消耗的音频数据是为120ms,而他开始回调,并连续回调12次。但第一次回调的时候,我们就唤醒了wait函数,这个时候我们去拷贝数据,而从唤醒到拷贝数据完成,并重新获取底层缓冲区大小的的这个过程,因为时间很短,短到他12次的连续回调,实际上只完成了3次回调,这个时候我们就去获取了state.count,发现它比之前只少了3次,所以误认为这个时间他只消耗了30ms的数据。因为state.count这个底层计数,他回调一次-1,并不会真正的实时反映实际的数据消耗过程。

那么我的代码和ijk的貌似看上去一致啊,为啥他的不会出现这个问题?后面思考发现问题所在,ijk在播放填充的数据线程中,通过回调给上层,他在上层的实现中实现了音频数据的解码,也就是正是这个解码函数产生的影响,他的这个耗时,完全足以让底层的音频连续回调,回调完毕,所以再去拿数据以后,就是正确的结果。

本人主要是个人对调试的理解和记录,仅供参考。

转载请注明出处:https://www.cnblogs.com/lihaiping/p/11739836.html

(原)关于OpenSL ES播放音频数据的一个奇怪的问题的更多相关文章

  1. Android OpenSL ES 开发:Android OpenSL 录制 PCM 音频数据

    一.实现说明 OpenSL ES的录音要比播放简单一些,在创建好引擎后,再创建好录音接口基本就可以录音了.在这里我们做的是流式录音,所以需要用至少2个buffer来缓存录制好的PCM数据,这里我们可以 ...

  2. Android 音视频深入 十四 FFmpeg与OpenSL ES 播放mp3音乐,能暂停(附源码下载)

    项目地址https://github.com/979451341/FFmpegOpenslES 这次说的是FFmpeg解码mp3,数据给OpenSL ES播放,并且能够暂停. 1.创建引擎 slCre ...

  3. iOS 9音频应用播放音频之第一个ios9音频实例2

    iOS 9音频应用播放音频之第一个ios9音频实例2 ios9音频应用关联 iOS9音频应用中对于在主视图上添加的视图或控件,在使用它们时必须要与插座变量进行关联.ios9插座变量其实就是为主视图中的 ...

  4. iOS 9音频应用播放音频之第一个ios9音频实例

    iOS 9音频应用播放音频之第一个ios9音频实例 第一个ios9音频实例 为了让开发者可以对上面的内容有更加深入的了解,本节将实现播放音频的第一个实例.在此实例中会涉及到项目的创建.界面设计.关联以 ...

  5. Android音视频学习第7章:使用OpenSL ES进行音频解码

    /* * *这里使用了transcode-1.1.7对wav文件进行解码.然后使用opensl es进行播放 * */ //用到的变量和结构体 WAV wav; //wav文件指针 SLObjectI ...

  6. OpenSL ES: 利用OpenSL ES播放一个存在于SDcard上的PCM文件

    native-lib.cpp #include <jni.h> #include <string> #include <SLES/OpenSLES.h> #incl ...

  7. 【Android 多媒体应用】使用MediaCodec解码使用AudioTrack播放音频数据

    1.MainActivity.java import android.app.Activity; import android.os.Bundle; import android.os.Environ ...

  8. 【Android 多媒体应用】使用MediaRecoder录制,MediaPlayer播放音频数据

    1.MainActivity.java import android.annotation.TargetApi; import android.app.Activity; import android ...

  9. Android OpenSL ES 开发:OpenSL ES利用SoundTouch实现PCM音频的变速和变调

    缘由 OpenSL ES 学习到现在已经知道 OpenSL ES 不仅能播放和录制PCM音频数据,还能改变声音大小.设置左声道或右声道播放.还能变速播放,可谓是播放音频的王者.但是变速有一点不好的就是 ...

随机推荐

  1. send fd 无法传

    string success = "1"; string urlstr = "http://localhost:8080/getfilecontent?filename= ...

  2. error: ‘Poco::UInt16’ has not been declared

    碰到Poco库和其他第三方库共用的时候,当include-POCO库的头文件的时候,此时也include-其他库,导致这个报错. 原因是在这两个库中都对 UINT16 定义,导致冲突. 可以把这两个库 ...

  3. C++输入输出流 cin/cout 及格式化输出简介

    C++ 可通过流的概念进行程序与外界环境( 用户.文件等 )之间的交互.流是一种将数据自源( source )推送至目的地( destination )的管道.在 C++ 中,与标准输入/输出相关的流 ...

  4. springboot集成jsp,访问jsp页面下载问题

    1.导入相关依赖     (存在jsp页面下载问题,可能是缺少tomcat-embed-jasper的依赖对jsp的支持) <parent> <groupId>org.spri ...

  5. 电商平台+keepalived高可用

    192.168.189.131 电商平台 192.168.189.129 MySQL主192.168.189.130 MySQL备192.168.189.181 VIP 配置MySQL为互为主从并结合 ...

  6. sql 记录一次灾难 游标问题

    起因:游标执行存储过程 下载begin 外面了.. ,造成一直触发存储过程 收获:定义变量统一在游标外部使用, 书写内容在begin 内部书写 alter PROCEDURE USP_dgd_wzh_ ...

  7. linux学习13 Linux运维常用文件管理命令及系统变量基础

    一.文件管理命令 1.cp命令,copy a.单源复制,cp [OPTION]... [-T] SOURCE DEST 如果DEST不存在:则事先创建此文件,并复制源文件的数据流至DEST中. 如果D ...

  8. 洛谷 P3371【模板】单源最短路径(弱化版)

    题面 既然是模板, 那就直接贴代码? 两种思路 1.迪杰斯特拉 #include <cstdio> #include <cstring> #include <iostre ...

  9. 【LG3582】[POI2015]KIN

    [LG3582][POI2015]KIN 题面 洛谷 题解 这题维护区间的信息有点像最大子段和,我们往最大子段和上面靠. 对于一个颜色,我们有一个直观的想法就是将它一次出现的权值设为正,二次出现就设为 ...

  10. linux命令之------Mv命令

    Mv命令 1)作用:用来为文件或目录改名/或将文件或目录一如其他位置 2)-i:若指定目录已有同名文件,则先询问是否覆盖旧文件: 3)-f:在mv操作要覆盖某已有的目标文件时,不给任何指示: 4)案例 ...