android之VideoView和视频播放View的扩展

2023-12-05 12:58

本文主要是介绍android之VideoView和视频播放View的扩展,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.概念及扩展

  VideoView 是android 系统提供的一个媒体播放显示和控制的控件。其结构层次如下:

  原型:VideoView extends SurfaceView implements MediaController.MediaPlayerControl

  类结构:

      java.lang.Object
        ↳ android.view.View
          ↳ android.view.SurfaceView
            ↳ android.widget.VideoView

  通过VideoView 的原型可知:如果构建更为复杂和有特色个性的视频View,需要继承SurfaceView 和实现MediaPlayerControl接口。其中SurfaceView 为显示提供支持,MediaPlayerControl则为媒体控制提供了支持。

2.案例

1)VideoView案例

(我们没有管理MediaPalyer的各种状态,这些状态都让VideoView给封装了,并且,当VideoView创建的时候,MediaPalyer对象将会创建,当VideoView对象销毁的时候,MediaPlayer对象将会释放。)

布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent"android:layout_height="fill_parent">
<VideoView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent"android:layout_centerInParent="true" />
</LinearLayout>

主程序:

public class VideoPlayer extends Activity implements MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener {public static final String TAG = "VideoPlayer";private VideoView mVideoView;private Uri mUri;private int mPositionWhenPaused = -1;private MediaController mMediaController;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);//Set the screen to landscape.
        this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);mVideoView = (VideoView)findViewById(R.id.video_view);//Video file
        mUri = Uri.parse(Environment.getExternalStorageDirectory() + "/1.3gp");//Create media controller,组件可以控制视频的播放,暂停,回复,seek等操作,不需要你实现
        mMediaController = new MediaController(this);mVideoView.setMediaController(mMediaController);}public void onStart() {// Play Video
        mVideoView.setVideoURI(mUri);mVideoView.start();super.onStart();}public void onPause() {// Stop video when the activity is pause.
        mPositionWhenPaused = mVideoView.getCurrentPosition();mVideoView.stopPlayback();super.onPause();}public void onResume() {// Resume video player
        if(mPositionWhenPaused >= 0) {mVideoView.seekTo(mPositionWhenPaused);mPositionWhenPaused = -1;}super.onResume();}public boolean onError(MediaPlayer player, int arg1, int arg2) {return false;}public void onCompletion(MediaPlayer mp) {this.finish();}
}

2)自定义VideoView

和VideoView实现类似,继承了SurfaceView并且实现了MediaPlayerControl。

public class CustomerVideoView extends SurfaceView implements MediaPlayerControl { private static String TAG = "customer.videoplayer"; private boolean pause; private boolean seekBackward; private boolean seekForward; private Uri videoUri; private MediaPlayer mediaPlayer; private Context context; private OnPreparedListener onPreparedListener; private int videoWidth; private int videoHeight; private MediaController mediaController; protected SurfaceHolder surfaceHolder; private Callback surfaceHolderCallback = new SurfaceHolder.Callback() { public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { } public void surfaceCreated(SurfaceHolder holder) { surfaceHolder = holder; if (mediaPlayer != null) { mediaPlayer.setDisplay(surfaceHolder); resume(); } else { openVideo(); } } public void surfaceDestroyed(SurfaceHolder holder) { surfaceHolder = null; if (mediaController != null) { mediaController.hide(); } release(true); } }; private void release(boolean cleartargetstate) { if (mediaPlayer != null) { mediaPlayer.reset(); mediaPlayer.release(); mediaPlayer = null; } } public void resume() { if (surfaceHolder == null) { return; } if (mediaPlayer != null) { return; } openVideo(); } public CustomerVideoView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); this.context = context; this.initVideoView(); } public CustomerVideoView(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; this.initVideoView(); } public CustomerVideoView(Context context) { super(context); this.context = context; this.initVideoView(); } @Override public boolean canPause() { return this.pause; } @Override public boolean canSeekBackward() { return this.seekBackward; } @Override public boolean canSeekForward() { return this.seekForward; } @Override public int getBufferPercentage() { return 0; } @Override public int getCurrentPosition() { return mediaPlayer!=null?mediaPlayer.getCurrentPosition():0; } @Override public int getDuration() { return mediaPlayer!=null?mediaPlayer.getDuration():0; } @Override public boolean isPlaying() { return false; } @Override public void pause() { } @Override public void seekTo(int mSec) { } @Override public void start() { } public void setVideoURI(Uri uri) { this.videoUri = uri; openVideo(); requestLayout(); invalidate(); } private void openVideo() { this.mediaPlayer = new MediaPlayer(); try { this.mediaPlayer.setDataSource(this.context, this.videoUri); } catch (Exception e) { Log.e(TAG, e.getMessage()); throw new RuntimeException(e); } this.mediaPlayer.prepareAsync(); this.mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); this.mediaPlayer.setOnPreparedListener(onPreparedListener); attachMediaController(); } private void attachMediaController() { if (mediaPlayer != null && mediaController != null) { mediaController.setMediaPlayer(this); View anchorView = this.getParent() instanceof View ? (View) this .getParent() : this; mediaController.setAnchorView(anchorView); mediaController.setEnabled(true); } } public void setMediaController(MediaController controller) { if (mediaController != null) { mediaController.hide(); } mediaController = controller; attachMediaController(); } public void setOnPreparedListener(OnPreparedListener onPreparedListener) { this.onPreparedListener = onPreparedListener; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = getDefaultSize(videoWidth, widthMeasureSpec); int height = getDefaultSize(videoHeight, heightMeasureSpec); if (videoWidth > 0 && videoHeight > 0) { if (videoWidth * height > width * videoHeight) { height = width * videoHeight / videoWidth; } else if (videoWidth * height < width * videoHeight) { width = height * videoWidth / videoHeight; } } Log.i(TAG, "setting size: " + width + ‘x’ + height); setMeasuredDimension(width, height); } private void initVideoView() { videoWidth = 0; videoHeight = 0; getHolder().addCallback(surfaceHolderCallback); getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); setFocusable(true); setFocusableInTouchMode(true); requestFocus(); } 
}

  一般情况下,android界面的绘制和更新,要交给主ui线程来操作,通过Handler机制。但是播放视频,需要比较优先和实时的改变和绘制界面。android提供了使用单独线程绘制UI的机制,就是SurfaceView。使用SurfaceView,需要实现SurfaceHolder.Callback接口:

  • surfaceCreated,在Surface(SurfaceView内部包含一个Surface实例)创建后,会立即调用该方法,可在该方法中做绘制界面相关的初始化工作;
  • surfaceChanged,当Surface的状态发生变化,比如大小,会调用该方法,在surfaceCreated方法调用过至少会调用一次该方法;
  • surfaceDestroyed,当销毁Surface的时候调用。

  开发者不能直接操作Surface实例,要通过SurfaceHandler,在SurfaceView中可以通过getHandler方法获取到SurfaceHandler实例。
SurfaceHander有一些类型,用来标识Surface实例界面数据来源,可以通过setType来操作:

  • SURFACE_TYPE_NORMAL:RAM缓存的原生数据
  • SURFACE_TYPE_HARDWARE:通过DMA,direct memory access,就是直接写屏技术获取到的数据,或者其他硬件加速的数据
  • SURFACE_TYPE_GPU:通过GPU加速的数据
  • SURFACE_TYPE_PUSH_BUFFERS:标识数据来源于其他对象,比如照相机,比如视频播放服务器(android内部有视频播放的服务器,所有播放视频相当于客户端)


  CustomerVideoView的构造方法,使用超类的构造方法。都会执行initVideoView()方法用来初始化界面和参数。另外一个主要的内容是openVideo()方法:

  • mediaPlayer.prepareAsync(),用来异步准备播放,另外还有个prepare()方法,是同步的,也就是全部下载完毕才能播放,显然,在播放网上视频的时候需要用前者;
  • 通过attachMediaController()方法,把控制条附加到播放视频的SurfaceView上,这里实现的不完全,因此还不能使用,仅仅是把MediaPlayerControl实例通过setMediaPlayer方法设置一下,供OnPreparedListener用来得到加载成功的回调,另外供外面代码调用得到视频的时长和当前时长。
绿色通道: 好文要顶 关注我 收藏该文 与我联系

这篇关于android之VideoView和视频播放View的扩展的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/457663

相关文章

Android实现打开本地pdf文件的两种方式

《Android实现打开本地pdf文件的两种方式》在现代应用中,PDF格式因其跨平台、稳定性好、展示内容一致等特点,在Android平台上,如何高效地打开本地PDF文件,不仅关系到用户体验,也直接影响... 目录一、项目概述二、相关知识2.1 PDF文件基本概述2.2 android 文件访问与存储权限2.

Android Studio 配置国内镜像源的实现步骤

《AndroidStudio配置国内镜像源的实现步骤》本文主要介绍了AndroidStudio配置国内镜像源的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、修改 hosts,解决 SDK 下载失败的问题二、修改 gradle 地址,解决 gradle

在Android平台上实现消息推送功能

《在Android平台上实现消息推送功能》随着移动互联网应用的飞速发展,消息推送已成为移动应用中不可或缺的功能,在Android平台上,实现消息推送涉及到服务端的消息发送、客户端的消息接收、通知渠道(... 目录一、项目概述二、相关知识介绍2.1 消息推送的基本原理2.2 Firebase Cloud Me

基于Python和MoviePy实现照片管理和视频合成工具

《基于Python和MoviePy实现照片管理和视频合成工具》在这篇博客中,我们将详细剖析一个基于Python的图形界面应用程序,该程序使用wxPython构建用户界面,并结合MoviePy、Pill... 目录引言项目概述代码结构分析1. 导入和依赖2. 主类:PhotoManager初始化方法:__in

Android中Dialog的使用详解

《Android中Dialog的使用详解》Dialog(对话框)是Android中常用的UI组件,用于临时显示重要信息或获取用户输入,本文给大家介绍Android中Dialog的使用,感兴趣的朋友一起... 目录android中Dialog的使用详解1. 基本Dialog类型1.1 AlertDialog(

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

Python+PyQt5实现多屏幕协同播放功能

《Python+PyQt5实现多屏幕协同播放功能》在现代会议展示、数字广告、展览展示等场景中,多屏幕协同播放已成为刚需,下面我们就来看看如何利用Python和PyQt5开发一套功能强大的跨屏播控系统吧... 目录一、项目概述:突破传统播放限制二、核心技术解析2.1 多屏管理机制2.2 播放引擎设计2.3 专

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

使用Python实现文本转语音(TTS)并播放音频

《使用Python实现文本转语音(TTS)并播放音频》在开发涉及语音交互或需要语音提示的应用时,文本转语音(TTS)技术是一个非常实用的工具,下面我们来看看如何使用gTTS和playsound库将文本... 目录什么是 gTTS 和 playsound安装依赖库实现步骤 1. 导入库2. 定义文本和语言 3