【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() {
    @Override
    public void onPrepared(MediaPlayer mp) {
        // 开始播放
        mediaPlayer.start();
    }
});
  • OnCompletionListener:当播放完成时触发该监听器,可以用来处理播放结束后的操作。
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
    @Override
    public void onCompletion(MediaPlayer mp) {
        // 播放完成的逻辑
        mediaPlayer.stop();
    }
});
  • OnErrorListener:当播放过程中出现错误时触发该监听器,便于处理错误。
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
    @Override
    public 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.SceneLayout
        android:id="@+id/video_scene_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <com.eqgis.media.component.VideoTimeLine
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="20dp"
        android:id="@+id/time_line"
        android:layout_width="match_parent"
        android:layout_height="20dp"/>
    <TextView
        android: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")
    @Override
    protected 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() {
            @Override
            public 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() {
            @Override
            public 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() {
            @Override
            public void initializeTexture(ExternalTexture texture) {
                //纹理初始化成功时,触发回调
                externalTexture = texture;
                try {
                    loadDefaultVideo();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        });

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

艺术体操与骑行的完美协奏:维乐Angel Rise+坐垫,激情与力量的展现!

在艺术体操的赛场上&#xff0c;每一次旋转、每一次跳跃&#xff0c;都凝聚着运动员的力量与技巧。这不仅是一场速度与激情的碰撞&#xff0c;更是一次力量与技巧的交融。正如在骑行的领域里&#xff0c;VELO Angel Rise坐垫以它独特的一体成型设计和技术&#xff0c;为骑行者们…

windows通过wsl2安装linux系统之Ubuntu,傻瓜式安装

期望通过每一次分享&#xff0c;让技术的门槛变低&#xff0c;落地更容易。 —— around 目录 1.基础环境和要求2.安装wsl23.安装linux系统4.迁移linux系统挂载5.配置linux账号密码6.配置ssh登录方式待续… 前言 为什么要在windows上安装linux&#xff0c;这个问题当你是研发…

rancher搭建k8s及jenkins自动化部署

1、准备环境 角色IP用途k8s-rancher-master192.168.3.63master节点k8s-rancher-node01192.168.3.64node节点k8s-rancher-node02192.168.3.66node节点k8s-rancher-server192.168.2.33rancher-server节点注: 服务器名需要配置不同,相同服务器名不能加入node节点 在所有节点进行…

1万3医学考研题库医学题库ACCESS\EXCEL数据库

今天这个题库按知识点分章节模块智能练习&#xff0c;覆盖书本上所有知识点以及考点&#xff0c;在真#题的解析里边也有详细的展示&#xff1b;另外&#xff0c;这份数据库与《4820道西#医综合真题西#医真#题ACCESS数据库》、《4170条中#医综合真#题中医真#题ACCESS\EXCEL数据库…

Android V 广播注册和配置注意事项问题

现象 在Android V平台上&#xff0c;应用注册非Protected广播时&#xff0c;如果没有加导出flag会抛出异常导致进程crash。 E/AndroidRuntime: FATAL EXCEPTION: main java.lang.SecurityException: com.demo.myapplication: One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORT…

如何用3个月零基础入门网络安全?_网络安全零基础怎么学习

前 言 写这篇教程的初衷是很多朋友都想了解如何入门/转行网络安全&#xff0c;实现自己的“黑客梦”。文章的宗旨是&#xff1a; 1.指出一些自学的误区 2.提供客观可行的学习表 3.推荐我认为适合小白学习的资源.大佬绕道哈&#xff01; →点击获取网络安全资料攻略← 一、自学…

k8s的配置管理

一、配置管理分为两种&#xff1a; 1. 加密配置&#xff1a;用来保存密码和token密钥对以及其它敏感的k8s资源。 2.应用配置&#xff1a;我们需要定制化的给应用进行配置&#xff0c;我们需要把定制好的配置文件同步到pod当中的容器。 二、加密配置 1.secret三种类型&#xf…

YOLOv8改进 | 模块缝合 | C2f 融合RVB + EMA注意力机制【二次融合 + 结构图】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录 &#xff1a;《YOLOv8改进有效…

《垃圾回收的算法与实现》-算法-摘抄

本文是书籍《垃圾回收的算法与实现》的摘抄&#xff0c;不涉及算法源码及步骤讲解模块。 预备 对象由头(header)和域(field)构成。 头&#xff1a;对象中保存对象本身信息的部分&#xff0c;主要含有以下信息&#xff1a;对象的大小和种类。 域&#xff1a;对象使用者在对象…

图结构详解

概述 图是由有穷非空集合的顶点和顶点之间的边组成的集合&#xff0c;通常表示为 G(V,E)。G 表示一个图&#xff0c;V 是 图 G 顶点的集合&#xff0c;E 是图 G 边的集合。在图形结构中&#xff0c;数据之间具有任意联系&#xff0c;任意两个数据之间都可能相关&#xff0c;可…

彻底解决 node/npm, Electron下载失败相关问题, 从底层源码详解node electron 加速配置

最近玩了一下electron项目, 总是会遇到electron的下载失败问题, 于是看了一下node源码, 做一个记录. node/npm 加速配置 这个配置通过设置node配置里面的registry 这个配置项来完成加速. 配置方法 npm config set registry https://registry.npmmirror.com上面的命令就是将当…

打破界限,自闭症寄宿学校带给孩子的改变

在社会的广阔画卷中&#xff0c;有一群特别的孩子&#xff0c;他们以独特的视角感知世界&#xff0c;以非凡的方式表达情感&#xff0c;他们就是自闭症儿童。自闭症&#xff0c;这个听起来略带神秘色彩的词汇&#xff0c;实则承载着无数家庭的期盼与挑战。在这片充满爱的土地上…

C++设计模式——Iterator迭代器模式

一&#xff0c;迭代器模式的定义 迭代器模式是一种行为型设计模式&#xff0c;它使得遍历一个容器对象中的元素变得更加简单。 迭代器模式将遍历操作从容器对象&#xff08;如集合、列表&#xff09;中分离出来&#xff0c;它通过迭代器对象来遍历容器对象中的元素&#xff0…

RK3568平台开发系列讲解(PWM篇)使用 sysfs 接口操作 pwm

🚀返回专栏总目录 文章目录 一、查看 pwm 设备信息二、使用 sysfs 操作 PWM沉淀、分享、成长,让自己和他人都能有所收获!😄 PWM 子系统被划分为了三个层次, 分别为用户空间、 内核空间和硬件层, 内核空间包括 PWM 设备驱动层、 PWM 核心层和 PWM 适配器驱动层 一、查看…

JS面试真题 part3

JS面试真题 part3 11、bind、call、apply区别&#xff1f;如何实现一个bind12、JavaScript中执行上下文和执行栈是什么13、说说JavaScript中的事件模型14、解释下什么是事件代理&#xff1f;应用场景&#xff1f;15、说说你对闭包的理解&#xff1f;闭包使用场景 11、bind、cal…

分布式技术概览

文章目录 分布式技术1. 分布式数据库&#xff08;Distributed Databases&#xff09;2. 分布式文件系统&#xff08;Distributed File Systems&#xff09;3. 分布式哈希表&#xff08;Distributed Hash Tables, DHTs&#xff09;4. 分布式缓存&#xff08;Distributed Caching…

面向对象需求分析

1. 面向对象分析概述 1.1 面向对象基本概念 以对象为中心&#xff0c;以类为构造机制&#xff0c;来认识、理解、刻画客观世界和设计、构建相应的软件系统。 1.2 UML统一建模语言 为什么要使用UML UML基本概念 统一建模语言&#xff08;UML&#xff09;是一个支持模型化和软…

【电子通识】半导体工艺——刻蚀工艺

在文章【电子通识】半导体工艺——光刻工艺中我们讲到人们经常将 Photo Lithography&#xff08;光刻&#xff09;缩写成 Photo。光刻工艺是在晶圆上利用光线来照射带有电路图形的光罩&#xff0c;从而绘制电路。光刻工艺类似于洗印黑白照片&#xff0c;将在胶片上形成的图像印…

opencv之图像梯度

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

首批通过!华为云CodeArts Snap智能开发助手通过可信AI智能编码工具评估,获当前最高等级

近日&#xff0c;华为云CodeArts Snap智能开发助手在中国信通院组织的智能编码工具首轮评估中&#xff0c;最终获得4级评级, 成为国内首批通过该项评估并获得当前最高评级的企业之一。 此次评估以《智能化软件工程技术和应用要求 第2部分&#xff1a;智能开发能力》为依据&…