【Sceneform-EQR】通过sceneform-eqr实现一个视频播放器(使用安卓MediaPlayer实现视频播放)

在前一篇文档中介绍了如何在AR\三维场景创建几种背景

【Sceneform-EQR】scenefrom-eqr中的几种背景实现(不仅用于AR、三维场景,在图片、视频播放器中也适用)

本文将侧重介绍如何使用安卓MediaPlayer实现视频播放。


↓↓↓↓↓↓↓↓↓↓↓↓ 以下正文 ↓↓↓↓↓↓↓↓↓↓↓↓


Sceneform-EQR

简介

Sceneform-EQR是EQ基于sceneform(filament)扩展的一个用于安卓端的三维渲染器。

相关链接

Git仓库

  • Sceneform-EQR

码云

  • EQ-Renderer的示例工程

EQ-R相关文档

  • 文档目录
  • CSDN专栏

MediaPlayer基础知识

若已熟悉MediaPlayer的使用,则可跳过本小节内容,直接看下一节 “使用MediaPlayer实现视频播放”

介绍

Android 的 MediaPlayer 是一个用于播放音频和视频的类,它支持多种格式的媒体文件和流媒体。它提供了非常高层次的接口,使开发者可以轻松实现媒体播放功能,如播放、暂停、停止、快进、倒退等操作。MediaPlayer 适用于需要播放本地或网络媒体资源的 Android 应用。

功能

  • 支持的媒体类型:MediaPlayer 支持各种常见的媒体文件格式,如 MP3、MP4、MPEG、3GP、AAC、WAV、OGG 等,以及通过网络流式传输的音视频文件。

  • 状态管理:MediaPlayer 有多个状态(如 Idle、Initialized、Prepared、Started、Paused 等),开发者需要在不同状态下正确调用方法以避免崩溃或错误。

  • 事件监听:MediaPlayer 提供了多种监听器(如 OnPreparedListener、OnCompletionListener、OnErrorListener),以处理播放开始、完成、错误等事件。

使用步骤

  • 初始化 MediaPlayer:首先,创建一个 MediaPlayer 对象,可以通过调用 new MediaPlayer() 或者使用静态方法 create() 进行初始化。

  • 设置数据源:使用 setDataSource() 方法为 MediaPlayer 设置音频或视频文件的路径,数据源可以是本地文件、网络 URL 或者其他 URI。

  • 准备播放:调用 prepare() 或 prepareAsync() 方法准备播放资源。对于大文件或网络资源,推荐使用异步准备(prepareAsync()),避免阻塞主线程。

  • 开始播放:当资源准备好后,可以调用 start() 方法开始播放。

  • 暂停和停止:可以使用 pause() 暂停播放,使用 stop() 完全停止播放。

  • 释放资源:当不再需要 MediaPlayer 时,应该调用 release() 方法释放资源,避免内存泄漏。

监听事件

  • OnPreparedListener:当调用 prepareAsync() 后,资源准备完成时触发该监听器。
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {@Overridepublic void onPrepared(MediaPlayer mp) {// 开始播放mediaPlayer.start();}
});
  • OnCompletionListener:当播放完成时触发该监听器,可以用来处理播放结束后的操作。
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {// 播放完成的逻辑mediaPlayer.stop();}
});
  • OnErrorListener:当播放过程中出现错误时触发该监听器,便于处理错误。
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {@Overridepublic boolean onError(MediaPlayer mp, int what, int extra) {// 错误处理逻辑return true;}
});

常见问题

  • 主线程阻塞问题:prepare() 是同步方法,可能会阻塞主线程,尤其是在处理大文件或网络流媒体时。推荐使用 prepareAsync() 异步方法,它不会阻塞主线程,并在准备完成时通过 OnPreparedListener 通知。

  • 内存泄漏问题:未释放 MediaPlayer 资源可能会导致内存泄漏。在 Activity 或 Fragment 销毁时,一定要调用 release() 释放资源。

  • 音视频同步:MediaPlayer 支持同时播放音频和视频,但对于视频播放,可能会遇到音画不同步的问题。这种情况下,可能需要更高级的播放器(如 ExoPlayer)进行优化。


使用MediaPlayer实现视频播放

按惯例,先看结果,再贴代码,最后在补充。

示例结果

示例中实现了基础的视频播放,运行截图如下:
在这里插入图片描述

示例代码

Layout

  • 添加场景布局控件SceneLayout,用于渲染视频。
  • 添加VideoTimeLine组件,用于显示播放进度。
    在这里插入图片描述
    完整xml文件如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".VideoActivity"><com.eqgis.eqr.layout.SceneLayoutandroid:id="@+id/video_scene_layout"android:layout_width="match_parent"android:layout_height="match_parent"/><com.eqgis.media.component.VideoTimeLineandroid:layout_alignParentBottom="true"android:layout_marginBottom="20dp"android:id="@+id/time_line"android:layout_width="match_parent"android:layout_height="20dp"/><TextViewandroid:textSize="24sp"android:text="样例视频"android:layout_centerInParent="true"android:layout_width="wrap_content"android:layout_height="wrap_content"/>
</RelativeLayout>

VideoActivity

在Sceneform-EQR的SmapleProj中,写了个示例VideoActivity供参考。

当ExSceneView初始化成功后,使用MediaPlaer加载默认的视频。

public class VideoActivity extends BaseActivity{private ExternalTexture externalTexture;private MediaPlayer mediaPlayer;private VideoTimeLine videoTimeLine;@SuppressLint("MissingInflatedId")@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//普通三维场景(场景3选1)setContentView(R.layout.activity_video_scene);sceneLayout = findViewById(R.id.video_scene_layout);sceneLayout.enableExSceneView(true).init(this);videoTimeLine = findViewById(R.id.time_line);sceneLayout.getExSceneView().setInitializeListener(new ExSceneView.InitializeListener() {@Overridepublic void initializeTexture(ExternalTexture texture) {//纹理初始化成功时,触发回调externalTexture = texture;try {loadDefaultVideo();} catch (IOException e) {throw new RuntimeException(e);}}});}/*** 加载默认视频* @throws IOException*/private void loadDefaultVideo() throws IOException {//这里使用eq_test_video.mp4为例,实际上,你也可以通过其它方式创建MediaPlayer,并设置数据源mediaPlayer = MediaPlayer.create(this,R.raw.eq_test_video);videoTimeLine.bindView(sceneLayout.getExSceneView(),mediaPlayer);mediaPlayer.setLooping(true);//循环播放mediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {@Overridepublic void onVideoSizeChanged(MediaPlayer mediaPlayer, int w, int h) {if (externalTexture != null){externalTexture.getSurfaceTexture().setDefaultBufferSize(w, h);mediaPlayer.setSurface(externalTexture.getSurface());}}});//就绪时,自动播放mediaPlayer.start();}
}

注意:在SceneLayout初始化(init方法)前,需要启用ExSceneView模式,因为只有ExSceneView实现了背景的扩展(能够获取SurfaceTexture对象),而这里我们要基于此去渲染视频。

补充内容

VideoTimeLine组件

源码:VideoTimeline.java

方式:
使用的是Seekbar去做的播放器的进度条,使用TextView显示时间文本。

关键点:

  • 在Scene的onUpdate事件中,实时更新seekBar的进度。
  • 在拖拽Seekbar时,通过mediaPlayer.seekTo更新视频进度。
  • 此外,需要注意避免上述两点的相互调用引起的冲突。

视频播放

ExSceneView继承SceneView,可用于渲染任何被安卓Surface支持绘制的内容。

SceneLayout基于SceneView实现,通过两步即可将MediaPlayer的播放内容,绘制在SceneLayout组件中。

  • 获取SceneLayout的externalTexture(通过ExSceneView获取)

方式1:初始化成功后回调

       sceneLayout.getExSceneView().setInitializeListener(new ExSceneView.InitializeListener() {@Overridepublic void initializeTexture(ExternalTexture texture) {//纹理初始化成功时,触发回调externalTexture = texture;try {loadDefaultVideo();} catch (IOException e) {throw new RuntimeException(e);}}});

方式2:直接通过ExSceneView的getExternalTexture方法

    /*** 获取拓展纹理* @return {@link ExternalTexture}*/@Nullablepublic ExternalTexture getExternalTexture() {return externalTexture;}
  • 给MediaPlayer设置surface
        mediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {@Overridepublic void onVideoSizeChanged(MediaPlayer mediaPlayer, int w, int h) {if (externalTexture != null){externalTexture.getSurfaceTexture().setDefaultBufferSize(w, h);mediaPlayer.setSurface(externalTexture.getSurface());}}});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/422246.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

李彦宏内部讲话曝光,谈大模型三大认知误区:智能体还是非共识

“外界对大模型有相当多的误解&#xff0c;”近日据媒体报道&#xff0c;李彦宏的一则内部讲话曝光。在最近一次和员工交流中&#xff0c;李彦宏谈及三个大模型认知误区&#xff0c;涵盖了大模型竞争、开源模型效率、智能体趋势等热点话题。 李彦宏认为未来大模型之间的差距可…

DWI扩散磁共振成像和结构连接组学指南

扩散磁共振成像和结构连接组学指南 引言流程概述扩散磁共振成像(dMRI)dMRI基础ADC&#xff08; apparent diffusion coefficient, 表观扩散系数&#xff09;MD&#xff08;mean diffusivity, 平均扩散率&#xff09;FA&#xff08; fractional anisotropy, 分数各向异性&#x…

“左侧文字横向”的QTabWidget

左侧用 QToolButton 组&#xff0c; 右侧用 QStackedWidget&#xff0c;信号槽绑定切换页面 可定制化高 QButtonGroup* btnGp new QButtonGroup(this);btnGp->addButton(ui->btn1, 0);btnGp->addButton(ui->btn2, 1);btnGp->addButton(ui->btn3, 2);connect…

MongoDB的Map-Reduce操作与聚合管道操作的两个实例相互转换

一、插入集合 comment 的文档的内容 二、题目要求 将集合 comment 中的文档进行聚合操作&#xff0c;即将字段 state为1的文档查询出来&#xff0c;然后按字段 nickname 进行分组,最后计算出每个评论者的评论条数。 三、mapReduce 操作代码 db.comment.mapReduce(// Map函数&…

linux搭建深度学习平台

linux搭建深度学习平台&#xff08;Ubuntu&#xff09; /home/guangyao/anaconda3 我服务器的anaconda地址 ~/anaconda3 1 首先就是打开浏览器&#xff0c;我实验室的是火狐&#xff0c;搜索anaconda下载&#xff0c;找到下载目录&#xff0c;cd进去&#xff0c; 2安装 bas…

鸿蒙界面开发——组件(6):属性字符串(StyledString)文本输入

属性字符串StyledString/MutableStyledString MutableStyledString继承于StyledString&#xff0c;以下统一简称StyledString。 是功能强大的标记对象&#xff0c;可用于字符或段落级别设置文本样式。 通过将StyledString附加到文本组件&#xff0c; 可以通过多种方式更改文本…

爆改YOLOv8|利用SCConv改进yolov8-即轻量又涨点

1&#xff0c;本文介绍 SCConv&#xff08;空间和通道重构卷积&#xff09;是一种高效的卷积模块&#xff0c;旨在优化卷积神经网络&#xff08;CNN&#xff09;的性能&#xff0c;通过减少空间和通道的冗余来降低计算资源的消耗。该模块由两个核心组件构成&#xff1a; 空间重…

ELK在Linux上部署教程

Docker Compose搭建ELK Elasticsearch默认使用mmapfs目录来存储索引。操作系统默认的mmap计数太低可能导致内存不足&#xff0c;我们可以使用下面这条命令来增加内存 sysctl -w vm.max_map_count262144创建Elasticsearch数据挂载路径 mkdir -p /echola/elasticsearch/data对…

【截图服务 +打包】pkg打包 puppeteer

目录 最后结论 windows打包成服务 定制executablePath 用程序来查找chrome.exe 代替上面的写配置文件 服务遇到的问题 使用java开一个线程启动 遇到的问题与解决 版本匹配问题 打出包后的运行报错问题 linux下的安装 安装n 库缺少 程序运行后的报错 制作 运行报…

IT前端好用的工具集

在线抠图网站 https://www.remove.bg/ 将iconfont转成css显示 https://transfonter.org/ 免费的在线图片压缩 https://tinypng.com/ JSON在线格式化工具 https://www.sojson.com/ 国内人工智能kimi.moonshot工具 https://kimi.moonshot.cn/chat/crft7a6sdv14grouufs0 自动…

当人工智能聊天机器人出现问题时

在快速发展的人工智能领域&#xff0c;出现了一项新的挑战。“人工智能私语者”正在通过说服行为良好的聊天机器人打破自己制定的规则来探索人工智能伦理的界限。 这些漏洞被称为即时注入或“越狱”&#xff0c;它们暴露了人工智能系统的漏洞&#xff0c;引发了人们对其安全性…

基于SpringBoot+Vue+MySQL的教学资源共享平台

系统展示 用户前台界面 管理员后台界面 系统背景 随着信息技术的迅猛发展&#xff0c;教育领域对高效、便捷的教学资源需求日益增长。传统教学模式已难以满足当前教育的多样化需求&#xff0c;特别是在资源共享与利用方面存在明显不足。因此&#xff0c;构建一个基于SpringBoot…

OPENAIGC开发者大赛企业组AI黑马奖 | 包你面-AI面试助手

在第二届拯救者杯OPENAIGC开发者大赛中&#xff0c;涌现出一批技术突出、创意卓越的作品。为了让这些优秀项目被更多人看到&#xff0c;我们特意开设了优秀作品报道专栏&#xff0c;旨在展示其独特之处和开发者的精彩故事。 无论您是技术专家还是爱好者&#xff0c;希望能带给您…

HashTable哈希表

概念 散列表(Hash Table)&#xff0c;又称哈希表。是一种数据结构&#xff0c;特点是:数据元素的关键字与其存储地址直接相关 在顺序结构以及树型结构中&#xff0c;数据元素的关键字与其存储位置没有对应的关系&#xff0c;因此在查找一个元素时&#xff0c;必须要经过关键码…

【Python篇】PyQt5 超详细教程——由入门到精通(序篇)

文章目录 PyQt5 超详细入门级教程前言序篇&#xff1a;1-3部分&#xff1a;PyQt5基础与常用控件第1部分&#xff1a;初识 PyQt5 和安装1.1 什么是 PyQt5&#xff1f;1.2 在 PyCharm 中安装 PyQt51.3 在 PyCharm 中编写第一个 PyQt5 应用程序1.4 代码详细解释1.5 在 PyCharm 中运…

《论面向服务架构设计及其应用》写作框架,软考高级系统架构设计师

论文真题 面向服务架构(Service-Oriented Architecture, SOA) 是一种应用框架,将日常的业务应用划分为单独的业务功能服务和流程,通过采用良好定义的接口和标准协议将这些服务关联起来。通过实施基于SOA的系统架构,用户可以构建、部署和整合服务,无需依赖应用程序及其运…

计算机毕业设计选题推荐-在线拍卖系统-Java/Python项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

CCDO|数据跃动未来:首席数据官如何引领构建活数据引擎

在数字化浪潮汹涌澎湃的今天&#xff0c;数据已成为企业最宝贵的资产之一&#xff0c;它不仅记录着过去&#xff0c;更预示着未来的方向。随着大数据、人工智能、云计算等技术的飞速发展&#xff0c;数据的潜力被前所未有地激发&#xff0c;而首席数据官&#xff08;CDO&#x…

opencv之图像梯度

图像梯度 图像梯度计算的是图像变化的速度。对于图像的边缘部分&#xff0c;其灰度值变化较大&#xff0c;梯度值也较大&#xff1b;相反&#xff0c;对于图像中比较平滑的部分&#xff0c;其灰度值变化较小&#xff0c;相应的梯度值也较小。一般情况下&#xff0c;图像梯度计…

string类--C++

文章目录 一、标准库中的string类1、string类2、auto和范围for2.1、auto关键字2.2、范围for 二、string类的常用接口说明1、string类对象的常见构造2、string类对象的容量操作3、string类对象的访问及遍历操作4、string类对象的修改操作5、string类非成员函数6、vs和g下string结…