Android 音视频开发 - VideoView

Android 音视频开发 - VideoView

本篇文章主要介绍下Android 中的VideoView.

1: VideoView简介

VideoView是一个用于播放视频的视图组件,可以方便地在应用程序中播放本地或网络上的视频文件。

VideoView可以直接在布局文件中使用,也可以在代码中动态创建。

它封装了MediaPlayer和SurfaceView,提供了简单的接口来控制视频的播放和显示。

它提供了一系列方法来控制视频的播放、暂停、停止等操作,并且支持全屏播放和视频控制器的显示。

VideoView播放视频非常简单,只需要指定视频的URL或本地路径.

2: 使用

以下是VideoView的简单使用:

2.1 布局

在XML布局文件中添加VideoView组件.

<VideoViewandroid:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintTop_toTopOf="parent"app:layout_constraintStart_toStartOf="parent"android:id="@+id/videoview"/>
2.2 设置视频源

代码如下:

videoView = findViewById(R.id.videoview);
videoView.setVideoPath("sdcard/test.mp4");

除了setVideoPath外,我们还可以调用:

  1. setVideoURI(Uri uri)
  2. setVideoURI(Uri uri, Map<String, String> headers)

当然不管是setVideoPath或者setVideoURI实际都是执行的setVideoURI(Uri uri, Map<String, String> headers).

源码如下:

/*** Sets video path.** @param path the path of the video.*/
public void setVideoPath(String path) {setVideoURI(Uri.parse(path));
}/*** Sets video URI.** @param uri the URI of the video.*/
public void setVideoURI(Uri uri) {setVideoURI(uri, null);
}
2.3 播放视频
videoView.start();

我们可以看下start()的源码:

@Override
public void start() {if (isInPlaybackState()) {mMediaPlayer.start();mCurrentState = STATE_PLAYING;}mTargetState = STATE_PLAYING;
}

可以看到实际上调用mMediaPlayer.start();另外设置了当前的状态为STATE_PLAYING.

这里直接调用了mMediaPlayer.start();那mMediaPlayer是什么时机初始化的呢?

查看源码可以看到:

private void openVideo() {if (mUri == null || mSurfaceHolder == null) {// not ready for playback just yet, will try again laterreturn;}// we shouldn't clear the target state, because somebody might have// called start() previouslyrelease(false);if (mAudioFocusType != AudioManager.AUDIOFOCUS_NONE) {// TODO this should have a focus listenermAudioManager.requestAudioFocus(null, mAudioAttributes, mAudioFocusType, 0 /*flags*/);}try {mMediaPlayer = new MediaPlayer();// TODO: create SubtitleController in MediaPlayer, but we need// a context for the subtitle renderersfinal Context context = getContext();final SubtitleController controller = new SubtitleController(context, mMediaPlayer.getMediaTimeProvider(), mMediaPlayer);controller.registerRenderer(new WebVttRenderer(context));controller.registerRenderer(new TtmlRenderer(context));controller.registerRenderer(new Cea708CaptionRenderer(context));controller.registerRenderer(new ClosedCaptionRenderer(context));mMediaPlayer.setSubtitleAnchor(controller, this);if (mAudioSession != 0) {mMediaPlayer.setAudioSessionId(mAudioSession);} else {mAudioSession = mMediaPlayer.getAudioSessionId();}mMediaPlayer.setOnPreparedListener(mPreparedListener);mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);mMediaPlayer.setOnCompletionListener(mCompletionListener);mMediaPlayer.setOnErrorListener(mErrorListener);mMediaPlayer.setOnInfoListener(mInfoListener);mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);mCurrentBufferPercentage = 0;mMediaPlayer.setDataSource(mContext, mUri, mHeaders);mMediaPlayer.setDisplay(mSurfaceHolder);mMediaPlayer.setAudioAttributes(mAudioAttributes);mMediaPlayer.setScreenOnWhilePlaying(true);mMediaPlayer.prepareAsync();for (Pair<InputStream, MediaFormat> pending: mPendingSubtitleTracks) {try {mMediaPlayer.addSubtitleSource(pending.first, pending.second);} catch (IllegalStateException e) {mInfoListener.onInfo(mMediaPlayer, MediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE, 0);}}// we don't set the target state here either, but preserve the// target state that was there before.mCurrentState = STATE_PREPARING;attachMediaController();} catch (IOException ex) {Log.w(TAG, "Unable to open content: " + mUri, ex);mCurrentState = STATE_ERROR;mTargetState = STATE_ERROR;mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);return;} catch (IllegalArgumentException ex) {Log.w(TAG, "Unable to open content: " + mUri, ex);mCurrentState = STATE_ERROR;mTargetState = STATE_ERROR;mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);return;} finally {mPendingSubtitleTracks.clear();}
}

可以看到openVideo()

  1. release()方法释放正在播放的视频.
  2. 初始化mMediaPlayer,传入Uri,设置状态 STATE_PREPARING。
  3. attachMediaController()绑定MediaPlayer与VideoView。

最后openVideo()则是在setVideoURI(Uri uri, Map<String, String> headers)内调用。

这样其实已经可以播放指定的视频了。

下面的方法可选。

2.4 MediaController控制器

MediaController是一个用于控制媒体播放器的视图组件。

MediaController的使用步骤如下:

  1. 创建一个MediaController对象:MediaController mediaController = new MediaController(context);
  2. 将MediaController与媒体播放器组件关联:mediaController.setMediaPlayer(mediaPlayer);
  3. 将MediaController添加到布局中:layout.addView(mediaController);
videoView.setMediaController(new MediaController(this));
videoView.start().

直接调用setMediaController,运行后我们可以看到与之前直接调用start()的区别就是多了个控制器的显示。其中包含一组常用的媒体控制按钮,如播放/暂停、快进/快退、前进/后退等,并且可以与MediaPlayer或VideoView等媒体播放器组件进行关联.

我们可以看下源码:

public void setMediaController(MediaController controller) {if (mMediaController != null) {mMediaController.hide();}mMediaController = controller;attachMediaController();
}

可以看到做的操作如下:

  1. 如果存在mMediaController,则调用hide方法。
  2. 对mMediaController赋值
  3. attachMediaController

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

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

相关文章

Matlab与ROS(1/2)---Simulink(二)

0. 简介 在上一章中我们详细介绍了ROS与Matlab链接的基础用法。这一章我们将来学习如何使用Matlab当中的Simulink来完成。Simulink对机器人操作系统(ROS)的支持使我们能够创建与ROS网络一起工作的Simulink模型。ROS是一个通信层&#xff0c;允许机器人系统的不同组件以消息的形…

前端HTML入门基础5(表单)

前端HTML入门基础5&#xff08;表单&#xff09; 表单-基本结构文本框和密码框单选框和复选框隐藏域确认按钮重置按钮普通按钮文本域下拉框禁用表单控件label标签fieldset与legend的使用 表单-基本结构 在HTML中&#xff0c;表单&#xff08;Forms&#xff09;是一种允许用户与…

嵌入式实时操作系统的调度机制与优化

大家好&#xff0c;今天给大家介绍嵌入式实时操作系统的调度机制与优化&#xff0c;文章末尾附有分享大家一个资料包&#xff0c;差不多150多G。里面学习内容、面经、项目都比较新也比较全&#xff01;可进群免费领取。 嵌入式实时操作系统的调度机制与优化 一、引言 嵌入式实…

Esilnt使用记录

已有vue2项目添加eslint自动格式化 参考文章

最前沿・量子退火建模方法(1) : subQUBO讲解和python实现

前言 量子退火机在小规模问题上的效果得到了有效验证&#xff0c;但是由于物理量子比特的大规模制备以及噪声的影响&#xff0c;还没有办法再大规模的场景下应用。 这时候就需要我们思考&#xff0c;如何通过软件的方法怎么样把大的问题分解成小的问题&#xff0c;以便通过现在…

远程桌面防火墙是什么?

远程桌面防火墙&#xff0c;是一种针对远程桌面应用的安全防护工具。它可以在保证远程桌面连接的便利性和高效性的对网络连接进行安全性的保护&#xff0c;防止未经授权的访问和潜在的安全风险。 远程桌面防火墙的主要功能是对远程桌面连接进行监控和管理。它通过识别和验证连接…

python内置函数exec()、filter()详解

Python 中的 exec() 函数 exec() 是 Python 中的一个强大的内置函数&#xff0c;它允许你执行任意 Python 代码&#xff0c;不论其大小。这个函数帮助我们执行动态生成的代码。想象一下 Python 解释器接收一段代码&#xff0c;内部处理并执行它&#xff0c;exec() 函数也是这样…

vue3+vant自动导入+pina+vite+js+pnpm搭建项目框架

vue3vant自动导入pinavitejspnpm搭建项目框架 文章目录 vue3vant自动导入pinavitejspnpm搭建项目框架1. 安装pnpm&#xff08;如果还没有安装&#xff09;&#xff1a;2. 创建项目目录并进入该目录&#xff1a;3. 初始化项目&#xff1a;4. 安装Vite作为构建工具&#xff1a;5.…

双向链表C语言实现

List.h文件 #pragma once #include<stdio.h> #include<stdlib.h> #include<assert.h> //结构 typedef int LTDatatype; typedef struct ListNode {LTDatatype data;struct ListNode* next;struct ListNode* prev; }LTNode; //声明接口和方法 void LTInit(LT…

cron表达式使用手册

cron表达式 我们在使用定时调度任务的时候&#xff0c;最常用的就是cron表达式。通过cron表达式来指定任务在某个时间点或者周期性执行。 范围&#xff1a; 秒&#xff08;0-59&#xff09;&#xff08;可选&#xff09; 分&#xff08;0-59&#xff09; 时&#xff08;0-…

ansible的常见用法

目录 ##编辑hosts文件 ##copy模块##复制过去 ##fetch模块##拉取 ##shell模块 ##好用 ##command模块## ##file模块### ##cron模块### ##crontab 计划任务 ##下载好时间插件 ##script模块 ##yum模块## ##yum下载源配置文件 /etc/yum.repos.d/CentOS-Base.repo ##ser…

Linux 使用 ifconfig 报错:Failed to start LSB: Bring up/down networking

一、报错信息 在运行项目时报错数据库连接失败&#xff0c;我就想着检查一下虚拟机是不是 Mysql 服务忘了开&#xff0c;结果远程连接都连接不上虚拟机上的 Linux 了&#xff0c;想着查一下 IP 地址看看&#xff0c;一查就报错了&#xff0c;报错信息&#xff1a; Restarting…

LeetCode34:在排序数组中查找元素的第一个和最后一个位置(Java)

目录 题目&#xff1a; 题解&#xff1a; 方法一&#xff1a; 方法二&#xff1a; 题目&#xff1a; 给你一个按照非递减顺序排列的整数数组 nums&#xff0c;和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target&…

QCustomPlot移植android后实现曲线放大缩小

一.问题 1.QCustomPlot在windows系统上可以支持鼠标左键按下平移拖动,滚轮放大缩小,矩形放大功能; 但是到了android触摸屏上无法识别鼠标滚轮事件,同时控件也不识别多点触控的放大缩小,这就导致想要实现放大缩小比较困难。 本文会给出两种解决方法。 二.QCustomPlot介绍…

Netty学习——高级篇2 Netty解码技术

接上篇&#xff1a;Netty学习——高级篇1 拆包 、粘包与编解码技术&#xff0c;本章继续介绍Netty的其他解码器 1 DelimiterBasedFrameDecoder分隔符解码器 DelimiterBasedFrameDecoder 分隔符解码器是按照指定分隔符进行解码的解码器&#xff0c;通过分隔符可以将二进制流拆分…

粘性定位应用

现象&#xff1a;当页面滑动到某个位置时&#xff0c;图片吸顶。 思路&#xff1a;创建一个father背景。包含内容和需要吸顶的背景图 当滚轮运动距离大于800px时&#xff0c;将吸顶图的position设置为sticky&#xff0c;距离顶部改为0px。 html代码&#xff1a; <!DOCTYPE …

基于PyTorch神经网络进行温度预测——基于jupyter实现

导入环境 import numpy as np import pandas as pd import matplotlib.pyplot as plt import torch import torch.optim as optim import warnings warnings.filterwarnings("ignore") %matplotlib inline读取文件 ### 读取数据文件 features pd.read_csv(temps.…

Linux第90步_异步通知实验

“异步通知”的核心就是信号&#xff0c;由“驱动设备”主动报告给“应用程序”的。 1、添加“EXTI3.c” #include "EXTI3.h" #include <linux/gpio.h> //使能gpio_request(),gpio_free(),gpio_direction_input(), //使能gpio_direction_output(),gpio_get_v…

Java基础-知识点2(面试|学习)

Java基础-知识点2 Java为什么是单继承的equals与的区别equals的等价关系 Java 访问修饰符publicprotecteddefaultprivate Final、Static、this、superFinalStaticthissuper 深拷贝、浅拷贝浅拷贝深拷贝 引用类型有哪些&#xff1f;Java 泛型泛型类&#xff08;Generic Class&am…

有序二叉树的增删改查(源代码讲解)

有序二叉树的相关实体类 TreeNode类 二叉树结点类&#xff0c;包含三个属性&#xff1a;value&#xff0c;leftChild&#xff0c;rightChild 有序二叉树类就包括这样一个根节点 剩下的getter和setter方法&#xff0c;有参无参构造&#xff0c;toString方法都是老生长谈&…