当前位置: 首页 > news >正文

视频播放器倍速、清晰度切换、m3u8下载

视频上很容易就可以做到倍速播放,一般的视频格式都是每秒固定的帧数,按比例跳帧就可以了。音频上其实也可以用这种方式来直接删除一些周期,因为电脑里的音频也是数字化离散化地储存的。但是为了使声音不失真,应该都用了稍复杂一点的算法的,比方说把相邻时钟周期内的声音电平信号取平均,或者用高斯平均值代替原信号,再精细点可以自适应地在音调信号比较丰富的地方设置比较高的权重来尽量少压缩保持音色,总之有很多种方法都可以做到啦。因为没有关注过这个,所以并不知道在软件里具体是怎么实现的,但是数字信号的缩放、滤波这些算法应该都差不多是这么做的,音频的加速也不像是需要使用更复杂的非线性自适应滤波的样子。

我们很多时候需要实现的效果是变速不变调。项目基于FFMpeg和WebRtc,通过FFMpeg从网络读取视频流,经过解封装、解复用分离成音频数据包和视频数据包。并分别对音视频数据包进行解码,解码完成之后的音频PCM(44100Hz,16bit,MONO)数据通过WebRtc提供的接口抛给AudioTrack,视频YUV420数据抛给WebRtc通过VideoRenderer进行渲染。

弯路:
1.一下子给播放设备(通过WebRtc注册的Audio Playout Device)喂两倍的数据:可以实现两倍速不变调,原理未知(WebRtc内部实现机制),但是有刺啦刺啦的噪音,推测是基音周期的问题,会产生基音断裂,定位困难,靠自己实现困难,放弃了该方案。

2.将解码的速率变成22050Hz,通过WebRtc播放(播放器初始化为44100Hz)可以实现两倍,但是会变调,放弃。

3.丢帧,每隔一帧丢一帧,可以实现音频倍速,但是也会有刺啦刺啦的噪音(基音断裂的问题),而且声音会产生断续,体验十分差,放弃。

解决方法

靠自己解决这个基音周期的问题需要算法和实现,不现实,只能通过调用现有的库进行处理。经过调研,发现有两个库支持倍速处理,一个是SoundTouch,另一个是Sonic。由于谷歌官方提供了一个ExoPlayer播放器,其中应用的方法是Sonic,并且网上有对两个库进行比较的文章,Sonic的效果要略好于SoundTouch,于是决定用Sonic库。

Sonic库有两种实现,一种是Java实现的Sonic.java,一种是C实现的Sonic-ndk,因为我们要和FFMpeg共同处理,所以需要使用ndk开发。对于没有自研究条件的团队,选择第三方是最好的方案。

以JiaoZiVideoPlayer为例 ,本身自带的播放引擎是MediaPlayer,也就是Android自带的播放器,有很多不完善的地方,倍速切换只支持5.0以上,否则报NoClassDefFoundError 错误。而且还不支持rtmp类型的播放流。

所以在播放引擎上建议不要使用默认的,目前比较流行的是 ijkplayer

但是只使用ijkplayer,还需要自己写逻辑,布局等等。为了简便,直接给 JiaoZiVideoPlayer 使用 ijk 播放引擎,省去了写布局和播放逻辑的麻烦。

实例

首先,引入相关的jar包支持,

 

implementation 'cn.jzvd:jiaozivideoplayer:6.2.7'
implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.4'
implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4'
implementation 'com.jwkj:M3U8Manger:v2.1.9'

Android Studio 3.0 以上建议使用 implementation 方式引入第三方库,以下使用 compile。

自定义播放器布局

JiaoZi的播放器控件是 JZVideoPlayerStandard。所有关于播放器布局控件的操作都需要通过该控件,能满足一般的视频播放需求。但是如果需要在 JiaoZi 播放器中添加按钮,就需要自定义JZVideoPlayerStandard, 比如倍速播放、下载、清晰度切换等功能。如果不需要修改布局,直接在xml布局文件中使用即可。

a、重写 XML
如果需要给播放器添加新的控件,或者更换图片,修改按钮位置等必须要把原来的 XML 完整拷贝至新建 XML 中,控件名称建议不能修改,只添加你需要的控件就行了。通过 getLayoutId() 方法设置自定义布局文件。例如:

 

@Override
public int getLayoutId() {
return

b、添加倍速切换、下载控件
在 init 方法中初始化控件。

 

video_speed = (TextView) findViewById(R.id.video_speed);
video_speed.setOnClickListener(this);

c、监听
注意:JZVideoPlayerStandard 只是提供了布局的相关操作。倍速切换涉及到引擎的加速,所以暂时用广播的方式去通知 Activity 调用引擎。

 

@Override
public void onClick(View v) {
super.onClick(v);
int i = v.getId();
if (i == R.id.video_speed) {
// 切换倍速
video_speed.setText(resolveTypeUI(mFloat) + "X");
mFloat = resolveTypeUI(mFloat);
EventBus.getDefault().post(new SpeedEvent(mFloat));
// 更新播放状态
onStatePreparingChangingUrl(0, getCurrentPositionWhenPlaying());
}else if (i == R.id.video_download) {
// 下载
}
}
/*显示倍速比例*/
public static float resolveTypeUI(float speed) {
if (speed == 1) {
speed = 1.25f;
} else if (speed == 1.25f) {
speed = 1.5f;
} else if (speed == 1.5f) {
speed = 2f;
} else if (speed == 2f) {
speed = 1f;
}
return

d,针对播放状态控制控件显隐
实际需求中,如果是在全屏状态才需要展示控件,那么就需要这一步操作。
JiaoZiVideoPlayer 默认有清晰度切换的控件,不需要重复写相关逻辑。

 

@Override
public void setUp(Object[] dataSourceObjects, int defaultUrlMapIndex, int screen, Object... objects) {
super.setUp(dataSourceObjects, defaultUrlMapIndex, screen, objects);
//如果是全屏才显示相关按钮
Log.e("data========:", dataSourceObjects.length+"");
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
video_speed.setVisibility(VISIBLE);
video_download.setVisibility(VISIBLE);
} else if (currentScreen == SCREEN_WINDOW_NORMAL) {
video_speed.setVisibility(GONE);
video_download.setVisibility(GONE);
} else if

自定义播放引擎

如果要实现倍速播放,不管是 自带的MediaPlayer 还是 ijkPlayer 都必须要自定义播放引擎,只不过各自继承的引擎不同。

a、提供倍速切换的方法

 

//播放速度,默认1
public float speeding=1f;
public float getSpeeding() {
return speeding;
}
public void setSpeeding(float speeding) {
this.speeding = speeding;
}

通过引擎切换倍速ijkPlayer。

 

@Override
public void onPrepared(IMediaPlayer iMediaPlayer) {
Log.e("speed=======:", getSpeeding() + "");
ijkMediaPlayer.setSpeed(getSpeeding());
ijkMediaPlayer.start();
}
MediaPlayer:
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
//设置倍速,5.0以下不支持,会抛异常
try {
mediaPlayer.setPlaybackParams(new PlaybackParams().setSpeed(getSpeeding()));
}catch

使用实例

a,设置播放控件

 

<com.wapchief.qiniuplayer.views.myjzvideoplayerstandard android:layout_width="match_parent" android:layout_height="200dp"
android:id="@+id/jiaozi_player"
style="font-size: inherit;color: inherit;
line-height: inherit;"></com.wapchief.qiniuplayer.views.myjzvideoplayerstandard>

b,初始化播放地址
如果不需要清晰度切换直接把objects 替换成视频 URL链接就行了。

 

private String[] mediaName = {"普通","高清","原画"};
private void initPlayerUrl() {
Object[] objects = new Object[3];
LinkedHashMap map = new LinkedHashMap();
for (int i = 0; i < 3; i++) {
map.put(mediaName[i], MediaUrl.URL_M3U8);
}
objects[0] = map;
objects[1] = false;
objects[2] = new HashMap<>();
((HashMap) objects[2]).put("key", "value");
mPlayerStandard.setUp(objects, 0, JZVideoPlayer.SCREEN_WINDOW_NORMAL, "");
}

c,初始化播放引擎

登录后复制 

 

//自定义 MediaPlayer
MyJZMediaSystem mJZMediaSystem = new MyJZMediaSystem();
//自定义 ijk
MyIJKMediaSystem mIJKMediaSystem = new MyIJKMediaSystem();
@Override
protected void onPause() {
super.onPause();
JZVideoPlayer.releaseAllVideos();
JZVideoPlayer.setMediaInterface(mIJKMediaSystem);
}
@Override
public void onBackPressed() {
if (JZVideoPlayer.backPress()) {
return;
}
super.onBackPressed();
}

d,倍速切换事件

 

public void onMessageEventPostSpeed(SpeedEvent event) {
mJZMediaSystem.setSpeeding(event.getSpeed());
mIJKMediaSystem.setSpeeding(event.getSpeed());
Toast.makeText(this, "正在切换倍速:"+event.getSpeed(), Toast.LENGTH_LONG).show();
}

相关文章:

视频播放器倍速、清晰度切换、m3u8下载

视频上很容易就可以做到倍速播放&#xff0c;一般的视频格式都是每秒固定的帧数&#xff0c;按比例跳帧就可以了。音频上其实也可以用这种方式来直接删除一些周期&#xff0c;因为电脑里的音频也是数字化离散化地储存的。但是为了使声音不失真&#xff0c;应该都用了稍复杂一点…...

将Nginx 核心知识点扒了个底朝天(五)

什么叫 CDN 服务&#xff1f; CDN &#xff0c;即内容分发网络。 其目的是&#xff0c;通过在现有的 Internet中 增加一层新的网络架构&#xff0c;将网站的内容发布到最接近用户的网络边缘&#xff0c;使用户可就近取得所需的内容&#xff0c;提高用户访问网站的速度。 一般…...

【基础算法】差分

&#x1f339;作者:云小逸 &#x1f4dd;个人主页:云小逸的主页 &#x1f4dd;Github:云小逸的Github &#x1f91f;motto:要敢于一个人默默的面对自己&#xff0c;强大自己才是核心。不要等到什么都没有了&#xff0c;才下定决心去做。种一颗树&#xff0c;最好的时间是十年前…...

【LeetCode】剑指 Offer(5)

目录 写在前面&#xff1a; 题目&#xff1a; 题目的接口&#xff1a; 解题思路1&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 解题思路2&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 写在最后&#xff1a;…...

外包出来,朋友内推我去一家公司,问的实在是太...

外包出来&#xff0c;没想到算法死在另一家厂子&#xff0c;自从加入这家公司&#xff0c;每天都在加班&#xff0c;钱倒是给的不少&#xff0c;所以也就忍了。没想到8月一纸通知&#xff0c;所有人不许加班&#xff0c;薪资直降30%&#xff0c;顿时有吃不起饭的赶脚。 好在有…...

刷题记录:牛客NC54585小魂和他的数列 [线段树卡常,真恶心]

传送门:牛客 题目描述: 一天&#xff0c;小魂正和一个数列玩得不亦乐乎。 小魂的数列一共有n个元素&#xff0c;第i个数为Ai。 他发现&#xff0c;这个数列的一些子序列中的元素是严格递增的。 他想知道&#xff0c;这个数列一共有多少个长度为K的子序列是严格递增的。 请你帮…...

2019蓝桥杯真题旋转 C语言/C++

题目描述 图片旋转是对图片最简单的处理方式之一&#xff0c;在本题中&#xff0c;你需要对图片顺时针旋转 90 度。 我们用一个 nm 的二维数组来表示一个图片&#xff0c;例如下面给出一个 34 的 图片的例子&#xff1a; 1 3 5 7 9 8 7 6 3 5 9 7 这个图片顺时针旋转 90 度…...

<JVM上篇:内存与垃圾回收篇>11 - 垃圾回收相关算法

对象存活判断 在堆里存放着几乎所有的 Java 对象实例&#xff0c;在 GC 执行垃圾回收之前&#xff0c;首先需要区分出内存中哪些是存活对象&#xff0c;哪些是已经死亡的对象。只有被标记为己经死亡的对象&#xff0c;GC 才会在执行垃圾回收时&#xff0c;释放掉其所占用的内存…...

狂飙Linux平台,软件部署大全

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…...

积分球原理及积分球类型介绍

标题积分球标准型积分球LED积分球均匀光源便携式高亮度积分球均匀光源微光积分球均匀光源积分球均匀光源iSphere高光谱响应光学积分球其他分类积分球 积分球原理:由于球体内整涂有白色漫反射材料的空腔球体&#xff0c;球壁上开有采样口&#xff0c;当待测样品光源进入积分球的…...

Vision Transformer(ViT) 2: 应用及代码讲解

文章目录1. 代码讲解1.1 PatchEmbed类1&#xff09;__init__ 函数2) forward 过程1.2 Attention类1&#xff09;__init__ 函数2&#xff09;forward 过程1.3 MLP类1&#xff09;__init__ 函数2&#xff09;forward函数1.4 Block类1&#xff09;__init__ 函数2&#xff09;forwa…...

高频面试题|JVM虚拟机的体系结构是什么样的?

一. 前言最近有很多小伙伴都在找工作&#xff0c;他们在面试时经常被面试官问到一个问题&#xff1a;请说说JVM虚拟机的体系结构是什么样的?很多小伙伴都能说出堆、栈等相关内容&#xff0c;但面试官紧接着又问&#xff0c;你还知道其他内容吗&#xff1f;这时不少小伙伴就语塞…...

MyBatis-Plus详细讲解(整合spring Boot)

哈喽&#xff0c;大家好&#xff0c;今天带大家了解的是MyBatis-Plus&#xff08;简称 MP&#xff09;&#xff0c;是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。首先说一下MyBatis-Plus的愿景是什么&…...

骨传导耳机是不是智商税?骨传导耳机真的不伤耳吗?

很多人对骨传导耳机是具有一定的了解&#xff0c;但是对骨传导耳机还是有一定的刻板印象&#xff0c;那么骨传导耳机到底是不是智商税呢&#xff1f;主要还是要从骨传导耳机传声原理上讨论。 骨传导耳机是属于固体传声的一种方式&#xff0c;通过骨骼传递声音&#xff0c;在使用…...

模拟实现string

目录 1、基本成员变量 2、默认成员函数 构造函数 析构函数 拷贝构造函数(深拷贝) 赋值运算符重载 3、容量与大小相关的函数 size capacity 4、字符串访问相关函数 operator [ ]重载 迭代器 5、增加的相关函数 reserve扩容 resize push_back追加字符 appe…...

自监督表征预训练之掩码图像建模

自监督表征预训练之掩码图像建模 前言 目前&#xff0c;在计算机视觉领域&#xff0c;自监督表征预训练有两个主流方向&#xff0c;分别是对比学习&#xff08;contrastive learning&#xff09;和掩码图像建模&#xff08;masked image modeling&#xff09;。两个方向在近几…...

华为OD机试题 - 磁盘容量(JavaScript)| 代码+思路+重要知识点

最近更新的博客 华为OD机试题 - 字符串加密(JavaScript) 华为OD机试题 - 字母消消乐(JavaScript) 华为OD机试题 - 字母计数(JavaScript) 华为OD机试题 - 整数分解(JavaScript) 华为OD机试题 - 单词反转(JavaScript) 使用说明 参加华为od机试,一定要注意不要完全背…...

ChatGPT:“抢走你工作的不会是 AI ,而是先掌握 AI 能力的人”

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; ChatGPT&#xff1a;“抢走你工作的不会是 AI &#xff0c;而是先掌握 AI 能力的人” ChatGPT&#xff1a;美国OpenAI 研发的聊天机器人程序&#xff0c;人工智能技术…...

数据结构与算法(Java版) | 线性结构和非线性结构

之前&#xff0c;我们说过&#xff0c;数据结构是算法的基础&#xff0c;因此接下来在这一讲我就要来给大家重点介绍一下数据结构了。 首先&#xff0c;大家需要知道的是&#xff0c;数据结构包括两部分&#xff0c;即线性结构和非线性结构。知道这点之后&#xff0c;接下来我…...

电商数据查询平台:母婴行业妈妈用品全网热销,头部品牌格局初现

以往&#xff0c;奶粉、纸尿裤这类产品基本就代表了整体母婴市场中的消费品。而如今&#xff0c;随着母婴行业的高速发展和消费升级&#xff0c;母婴商品的种类日益丰富&#xff0c;需求也不断深入。 在京东平台&#xff0c;母婴大品类中除了包含婴童相关的食品&#xff08;奶粉…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互

引擎版本&#xff1a; 3.8.1 语言&#xff1a; JavaScript/TypeScript、C、Java 环境&#xff1a;Window 参考&#xff1a;Java原生反射机制 您好&#xff0c;我是鹤九日&#xff01; 回顾 在上篇文章中&#xff1a;CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

Mysql8 忘记密码重置,以及问题解决

1.使用免密登录 找到配置MySQL文件&#xff0c;我的文件路径是/etc/mysql/my.cnf&#xff0c;有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

C++ 设计模式 《小明的奶茶加料风波》

&#x1f468;‍&#x1f393; 模式名称&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09; &#x1f466; 小明最近上线了校园奶茶配送功能&#xff0c;业务火爆&#xff0c;大家都在加料&#xff1a; 有的同学要加波霸 &#x1f7e4;&#xff0c;有的要加椰果…...

掌握 HTTP 请求:理解 cURL GET 语法

cURL 是一个强大的命令行工具&#xff0c;用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中&#xff0c;cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...

Vue ③-生命周期 || 脚手架

生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#xff08;越早越好&#xff09; 什么时候可以开始操作dom&#xff1f;&#xff08;至少dom得渲染出来&#xff09; Vue生命周期&#xff1a; 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...