音视频开发经验:ijkplayer 实际开发中遇到的问题总结
liuian 2024-12-23 12:08 28 浏览
前言:ijkplayer 中一些问题记录优化
- 在弱网时如何优化
- ijkplayer 播放卡顿如何优化
- 如何支持 https 链接播放?
- 如何降低 ijkplayer 延迟效应
- ijkplayer 中音视频同步,是如何做的?
一、在弱网时如何优化
好的网络下视音频能够得到及时的发送,不会造成视音频数据在本地的堆积,直播效果流畅,延时较小。而在弱网网络环境下,视音频数据发送不出去,则需要我们对视音频数据进行处理。差网络环境下对视音频数据一般有四种处理方式:缓存区设计、网络检测、丢帧处理、降码率处理。
1、缓冲区设计
视音频数据传入缓冲区,发送者从缓冲区获取数据进行发送,这样就形成了一个异步的生产者消费者模式。生产者只需要将采集、编码后的视音频数据推送到缓冲区,而消费者则负责从这个缓冲区里面取出数据发送。
视音频缓冲区
上图中只显示了视频帧,显然里面也有相应的音频帧。要构建异步的生产者消费者模式,java 中使用 LinkedBlockingQueue,可以对之后进行丢帧、插入、取出等处理。
2、网络检测
差网络处理过程中一个重要的过程是网络检测,当网络变差的时候能够快速地检测出来,然后进行相应的处理,这样对网络反应就比较灵敏,效果就会好很多。通过实时计算每秒输入缓冲区的数据和发送出去数据,如果发送出去的数据小于输入缓冲区的数据,那么说明网络带宽不行,这时候缓冲区的数据会持续增多,这时候就要启动相应的机制。
3、丢帧处理
当检测到网络变差的时候,丢帧是一个很好的应对机制。视频经过编码后有关键帧和非关键帧,关键帧也就是一副完整的图片,而非关键帧描述图像的相对变化。
丢帧策略多钟多样,可以自行定义,一个需要注意的地方是:如果要丢弃 P 帧(非关键帧),那么需要丢弃两个关键帧之间的所有非关键帧,不然的话会出现马赛克。对于丢帧策略的设计因需求而异,可以自行进行设计。如下我一个丢帧实例:
当 CPU 在处理视频帧的时候处理得太慢,默认的音视频同步方案是视频同步到音频, 导致了音频播放过快,视频跟不上。
在 ffffplayoptions.h 中,找到如下代码:
可以通过修改 framedrop 的值来解决不同步的问题,framedrop 是在视频帧处理不过来的时候丢弃一些帧达到同步的效果。具体设置,在上层 Java 层中 IjkVideoView 中:
默认 ijkplayer 中是 1,你可以自行,修改这个值。
4、降码率
在 Android 中,如果使用了硬编进行编码,在差网络环境下,我们可以实时改变硬编的码率,从而使直播更为流畅。当检测到网络环境较差的时候,在丢帧的同时,我们也可以降低视音频的码率。在 Android sdk 版本大于等于 19 的时候,可以通过传递参数给 MediaCodec,从而改变硬编编码器出来数据的码率。
Bundle bitrate = new Bundle();bitrate.putInt(MediaCodec.PARAMETER_KEY_VIDEO_BITRATE, bps * 1024);
mMediaCodec.setParameters(bitrate);
二、ijkplayer 播放卡顿如何优化
在做音频播放的时候,使用的是开源的 ijkplayer 播放器,ijkplayer 解码使用的是 ffmpeg,声音输出使用的是 audiotrack,在某机型上面播放遇到锁屏、返回后台、点击 home 键的时候会出现声音卡顿的现象,会输出下面的 log
W/AudioTrack: releaseBuffer() track 0xcce8b600 disabled due to previous underrun, restarting
我实现播放调用步骤是在 AsyncTask 中,查阅资料发现是因为在线程中播放造成的问题,经过查看 asynctask 构造方法发现,asynctask 会把线程的优先级设置为 THREADPRIORITYBACKGROUND 后台线程,于是我将线程的优先级设置为 THREADPRIORITYURGENT_AUDIO,解决了播放卡顿的问题,我猜测播放线程优先级降低,系统分配时间片会减少,会导致底层 ijk 读数据输出数据时得不到及时的回应,audiotrack 频繁的 releasebuffer,restarting 声道,造成卡顿。
三、如何支持 https 链接播放?
如果你的项目要进行加密播放 HLS 协议的视频,要想支持 https,须要在普通编译的基础上,进行一些配置。
接下来我们来编译 openssl
1.init openssl
$ cd .. 进入到ijkplayer的目下
$ ./init-android-openssl.sh 去远程仓库拉取openssl的远程代码,如果是iOS的,这里是init-ios-openssl.h
2.compile openssl
$ cd android/contrib
$ ./compile-openssl.sh clean
$ ./compile-openssl.sh all
经过以上步骤已经编译好 openssl 了,然后我们执行一下方法
$./compile-ffmpeg.sh clean
编译ffmpeg软解码库,这个过程会生成各种架构的ffmpeg 这个过程比较耗时
$./compile-ffmpeg.sh all
相关视频推荐
ijkplayer播放器设计原理和实现|c/c++|音视频|流媒体_哔哩哔哩_bilibili
60万年薪音视频开发岗位需要掌握哪些技术点|音视频编码算法到底要掌握多少,FFmpeg命令行、API、源码分析、流媒体服务器RTMP/HLS/HTTP-FLV_哔哩哔哩_bilibili
学习地址:【免费】FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发-学习视频教程-腾讯课堂
需要更多ffmpeg/webrtc..音视频流媒体开发学习资料加群812855908领取
四、如何降低 ijkplayer 延迟效应
通过修改源文件,因为 ijkplayer 实际上是基于 ffplay.c 实现的:
ijkmedia>ijkplayer>ff_ffplay.c 这个文件
static double vp_duration(VideoState *is, Frame *vp, Frame *nextvp) {
if(vp->serial == nextvp->serial) {
doubleduration = nextvp->pts - vp->pts;
if(isnan(duration) || duration <=0|| duration > is->max_frame_duration)
return vp->duration;
else
return duration;
}else{
return 0.0;
}
}
直接换成:
static double vp_duration(VideoState*is,Frame*vp,Frame*nextvp) {
return vp->duration;
}
2、接着改 staticintffplayvideothread 这个方法:
static int ffplay_video_thread(void*arg){
FFPlayer*ffp = arg;
VideoState*is = ffp->is;
AVFrame*frame =av_frame_alloc();
doublepts;
doubleduration;
intret;
AVRationaltb = is->video_st->time_base;
//注释如下一行代码
//AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL);
//......省略部分代码
//注释如下一行代码
//duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational) {frame_rate.den, frame_rate.num}) : 0);
//直接这里写出
duration=0.01;
//........
}
改完后发现延迟明显降低,高分辨率开启硬解码,不支持的话会自动切换到软解,就算开启 mediacodec,如果设备不支持,显示的解码器也是 avcodec 软解。
五、ijkplayer 中音视频同步,是如何做的?
对于播放器来说,音视频同步是一个关键点,同时也是一个难点,同步效果的好坏,直接决定着播放器的质量。通常音视频同步的解决方案就是选择一个参考时钟(主 clock),播放时读取音视频帧上的时间戳,同时参考当前时钟参考时钟(主 clock)上的时间来安排播放。如下图所示:
- 如果音视频帧的播放时间大于当前参考时钟上的时间,则不急于播放该帧,直到参考时钟达到该帧的时间戳;
- 如果音视频帧的时间戳小于当前参考时钟上的时间,则需要“尽快”播放该帧或丢弃,以便播放进度追上参考时钟。
参考时钟的选择也有多种方式:
- 选取视频时间戳作为参考时钟源
- 选取音频时间戳作为参考时钟源
- 选取外部时间作为参考时钟源
考虑人对视频、和音频的敏感度,在存在音频的情况下,优先选择音频作为主时钟源。
ijkplayer 在默认情况下也是使用音频作为参考时钟源,我们可以找到 ffffplay.c 文件中,处理同步的过程主要在视频渲染 videorefresh_thread 的线程中:
从上述实现可以看出,该方法中主要循环做两件事情:
- 休眠等待,remainingtime 的计算在 videorefresh 中
- 调用 video_refresh 方法,刷新视频帧
可见同步的重点是在 video_refresh 中,下面看该方法一些关键部分:
lastvp 是上一帧,vp 是当前帧,lastduration 则是根据当前帧和上一帧的 pts(Presentation Time Stamp。PTS 主要用于度量解码后的视频帧什么时候被显示出来),计算出来上一帧的显示时间,经过 computetarget_delay 方法,计算出显示当前帧需要等待的时间。
在 computetargetdelay 函数中,如果发现当前主 Clock 源不是 video,则计算当前视频时钟与主时钟的差值:
- 如果当前视频帧落后于主时钟源,则需要减小下一帧画面的等待时间;
- 如果视频帧超前,并且该帧的显示时间大于显示更新门槛,则显示下一帧的时间为超前的时间差加上上一帧的显示时间
- 如果视频帧超前,并且上一帧的显示时间小于显示更新门槛,则采取加倍延时的策略。
回到 video_refresh 函数中,有如下逻辑:
frametimer 实际上就是上一帧的播放时间,而 frametimer + delay 实际上就是当前这一帧的播放时间,如果系统时间还没有到当前这一帧的播放时间,直接跳转至 display,而此时 is->forcerefresh 变量为 0,不显示当前帧,进入 videorefresh_thread 中下一次循环,并睡眠等待。
如果当前这一帧的播放时间已经过了,并且其和当前系统时间的差值超过了 AVSYNCTHRESHOLDMAX,则将当前这一帧的播放时间改为系统时间,并在后续判断是否需要丢帧,其目的是为后面帧的播放时间重新调整 frametimer,如果缓冲区中有更多的数据,并且当前的时间已经大于当前帧的持续显示时间,则丢弃当前帧,尝试显示下一帧。
否则进入正常显示当前帧的流程,调用 video_display2 开始渲染。
相关推荐
- Html中Css样式Ⅱ_html+css+
-
元素的定位(方式五种定位方式):静态定位:position:static;相对定位:position:relative;绝对定位:position:absolute;固定定位:position...
- HTML 标签和属性值的基本格式_html标签及属性的语法规则
-
HTML:HyperTextMarkupLanguage超文本标记语言HTML代码不区分大小写,包括HTML标记、属性、属性值都不区分大小写;任何空格或回车键在代码中都无效,插入空格或回车有...
- C#中使用Halcon开发视觉检测程序教程
-
一、环境准备1.安装Halcon从Halcon官方网站下载适合你操作系统的安装包,按照安装向导完成安装。安装过程中,记住安装路径,后续配置环境时会用到。2.配置VisualStudio项目打开V...
- 【开源】C#功能强大,灵活的跨平台开发框架 - Uno Platform
-
前言今天给广大网友分享一个基于C#开源、功能强大、灵活的跨平台开发框架,她就是:UnoPlatform。通过UnoPlatform,开发者可以利用单一代码库实现多平台兼容,极大地提高了开发效率和...
- C# 的发展简史_c#的发展前景
-
1.C#的诞生和初期(2000-2005)2000年:在微软的PDC大会上,由AndersHejlsberg首次公开展示了C#语言。2002年:微软发布了.NETFramework1.0,其...
- Visual Studio 2010-C#跟西门子1200(Sharp7)窗体控制②-启动按钮
-
VisualStudio2010--C#跟西门子1200(Sharp7)窗体控制②--启动按钮上期回顾(上期主要是新建窗体应用程序,添加sharp7的类库并引用,建立一个button按钮):本期将...
- Visual Studio窗口布局混乱后的恢复与优化指南
-
在使用VisualStudio进行开发时,我们常因误操作(如拖拽窗口、关闭面板、多显示器切换)导致界面布局混乱,代码编辑器、解决方案资源管理器、属性面板等组件“错位”,严重影响开发效率。本文将针对布...
- 使用Visual Studio 2017为AutoCAD创建一个c#模板
-
本教程的目标是展示如何在VisualStudio2017中创建AutoCAD的c#项目模板,该模板允许在调试模式下从VisualStudio加载DLL来自动启动AutoCAD。本文展示的示例使用...
- IT科技-续3Visual Studio2019-C#实战练习
-
上次完成了登录页面的窗体设计,本次完成管理界面的设计。第一步ComBox控制深度操作点击编辑选项,加入预定选项,完成操作。第二步复制Buttons控件依次为保存、删除、重置、编辑按钮属性设置,参考...
- 如何在 C# 中将文本转换为 Word 以及将 Word 转换为文本
-
在现代软件开发中,处理文档内容是一个非常常见的需求。无论是生成报告、存储日志,还是处理用户输入,开发者都可能需要在纯文本与Word文档之间进行转换。有时需要将文本转换为Word,以便生成结构化的...
- 简短的C#入门教程 # C# 入门教程 C#(读作...
-
简短的C#入门教程#C#入门教程C#(读作CSharp)是一种由Microsoft开发的多范式编程语言,它具有广泛的应用,特别是在Windows平台上。本教程将介绍C#的基础知识,以帮助您入门这...
- JavaScript中this指向各种场景_前端中this的指向
-
在JavaScript中,this的指向是一个核心概念,其值取决于函数的调用方式,而非定义位置(箭头函数除外)。以下是this指向的常见场景及具体说明:1.全局作用域中的this在全局作用域(非...
- 微信WeUI设计规范文件下载及使用方法
-
来人人都是产品经理【起点学院】,BAT实战派产品总监手把手系统带你学产品、学运营。WeUI是一套同微信原生视觉体验一致的基础样式库,由微信官方设计团队为微信Web开发量身设计,可以令用户的使用感知...
- JavaScript技术:如何动态添加事件?
-
随着前端技术的不断发展,JavaScript已经成为了不可或缺的一部分,它可以让网页变得更加流畅和美观。但是,在JavaScript中动态添加事件还是一个比较困难的问题,为此,本文将从入门到精通,介绍...
- 一周热门
-
-
【验证码逆向专栏】vaptcha 手势验证码逆向分析
-
Python实现人事自动打卡,再也不会被批评
-
Psutil + Flask + Pyecharts + Bootstrap 开发动态可视化系统监控
-
一个解决支持HTML/CSS/JS网页转PDF(高质量)的终极解决方案
-
再见Swagger UI 国人开源了一款超好用的 API 文档生成框架,真香
-
网页转成pdf文件的经验分享 网页转成pdf文件的经验分享怎么弄
-
C++ std::vector 简介
-
飞牛OS入门安装遇到问题,如何解决?
-
系统C盘清理:微信PC端文件清理,扩大C盘可用空间步骤
-
10款高性能NAS丨双十一必看,轻松搞定虚拟机、Docker、软路由
-
- 最近发表
-
- Html中Css样式Ⅱ_html+css+
- HTML 标签和属性值的基本格式_html标签及属性的语法规则
- 基于Visual Studio C#语言开发上位机,做定制设计后有多好看
- C#中使用Halcon开发视觉检测程序教程
- 【开源】C#功能强大,灵活的跨平台开发框架 - Uno Platform
- C# 的发展简史_c#的发展前景
- Visual Studio 2010-C#跟西门子1200(Sharp7)窗体控制②-启动按钮
- Visual Studio窗口布局混乱后的恢复与优化指南
- 使用Visual Studio 2017为AutoCAD创建一个c#模板
- IT科技-续3Visual Studio2019-C#实战练习
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- vscode切换git分支 (35)
- python bytes转16进制 (35)
- grep前后几行 (34)
- hashmap转list (35)
- c++ 字符串查找 (35)
- mysql刷新权限 (34)