Android多媒体技术之视频播放
1、Android中视频播放方式
- surfaceView+MediaPlayer,通过MediaPlayer来控制视频的播放、暂停、进度等;
- 使用VideoView 来播放,这个类其实也是继承了SurfaceView 类,并且实现了MediaController。MediaPlayerController 这个用于控制媒体播放的接口,另外在VideoView上还有一个用于对媒体播放进行控制的面板,包括快进、快退、播放、暂停按钮以及一个进度条;
- 系统提供的播放器
2、surfaceView+MediaPlayer实现视频播放基本步骤
- 在布局文件内定义SurfaceView
- 在代码中实现SurfaceHolder.Callback接口,重写三个方法
- 通过方法getHolder();得到SurfaceHolder,然后设置SurfaceHolder
- 为MediaPlayer通过setDisplay()方法,设置SurfaceHolder
- 使用setDataSource()方法为MediaPlayer设置播放文件
- 进行播放
- 优点:灵活性高,可以进行自定义;
- 缺点:难度比较大;
public class MainActivity extends Activity implements OnClickListener { private EditText et_path; private Button bt_play, bt_replay, bt_pause, bt_stop; private SurfaceView sv; private MediaPlayer mediaPlayer; private int currentPosition; private SeekBar sb; private boolean isplaying; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_path = (EditText) findViewById(R.id.et_path); bt_play = (Button) findViewById(R.id.bt_play); bt_replay = (Button) findViewById(R.id.bt_replay); bt_pause = (Button) findViewById(R.id.bt_pause); bt_stop = (Button) findViewById(R.id.bt_stop); sb = (SeekBar) findViewById(R.id.sb); sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { @Override public void onStopTrackingTouch(SeekBar seekBar) { int process = seekBar.getProgress(); if (mediaPlayer != null && mediaPlayer.isPlaying()) { mediaPlayer.seekTo(process); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { } }); sv = (SurfaceView) findViewById(R.id.sv); // 低版本手机加上参数,指定自己不维护缓冲区 /* 下面设置Surface不维护自己的缓冲区,而是等待屏幕的渲染引擎将内容推送到用户面前 */ sv.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); sv.getHolder().addCallback(new Callback() { @Override public void surfaceDestroyed(SurfaceHolder holder) { System.out.println("holder被销毁了"); if (mediaPlayer != null && mediaPlayer.isPlaying()) { currentPosition = mediaPlayer.getCurrentPosition(); stop(); } } @Override public void surfaceCreated(SurfaceHolder holder) { System.out.println("holder被创建了"); if (currentPosition > 0) { play(currentPosition); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { System.out.println("holder大小变化了"); } }); bt_play.setOnClickListener(this); bt_replay.setOnClickListener(this); bt_pause.setOnClickListener(this); bt_stop.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.bt_play: play(0); break; case R.id.bt_replay: replay(); break; case R.id.bt_stop: stop(); break; case R.id.bt_pause: pause(); break; } } /** * 暂停播放 */ private void pause() { if ("继续".equals(bt_pause.getText().toString().trim())) { mediaPlayer.start(); bt_pause.setText("暂停"); return; } if (mediaPlayer != null && mediaPlayer.isPlaying()) { mediaPlayer.pause(); bt_pause.setText("继续"); return; } } /** * 重新播放 */ private void replay() { bt_pause.setText("暂停"); if (mediaPlayer != null && mediaPlayer.isPlaying()) { mediaPlayer.seekTo(0); return; } play(0); } /** * 停止播放音乐 */ private void stop() { if (mediaPlayer != null && mediaPlayer.isPlaying()) { mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; bt_pause.setText("暂停"); bt_play.setEnabled(true); isplaying = false; } } /** * 播放视频 */ private void play(final int currentPosition2) { String path = et_path.getText().toString().trim(); try { mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); /* 设置Video影片以SurfaceHolder播放 */ mediaPlayer.setDisplay(sv.getHolder()); mediaPlayer.setDataSource(path); mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(new OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mediaPlayer.start(); int max = mediaPlayer.getDuration(); sb.setMax(max); mediaPlayer.seekTo(currentPosition2); new Thread() { public void run() { isplaying = true; while (isplaying) { int position = mediaPlayer.getCurrentPosition(); sb.setProgress(position); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); } }); mediaPlayer.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { bt_play.setEnabled(true); } }); mediaPlayer.setOnErrorListener(new OnErrorListener() { @Override public boolean onError(MediaPlayer mp, int what, int extra) { bt_play.setEnabled(true); isplaying = false; return false; } }); bt_play.setEnabled(false); } catch (Exception e) { Toast.makeText(this, "播放失败", 0).show(); e.printStackTrace(); } } }
3、VideoView实现视频播放基本步骤
- * 在onCreate方法中,首先获取布局管理器中添加的VideoView组件。并创建一个要播放视频所对应的对象。
- * 然后创建一个MediaController对象,用于控制视频的播放。
- *使用VideoView播放该视频
- 优点:比较简单,可以直接进行使用;
- 缺点:灵活性不高;
public class MainActivity extends Activity { private VideoView vv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); vv = (VideoView) findViewById(R.id.vv); MediaController mc = new MediaController(this); mc.setAnchorView(vv); vv.setMediaController(mc); vv.setVideoPath("mnt/sdcard/areyouok.3gp"); vv.start(); } }
4、View, surfaceView, GLSurfaceView区别
- view是最基础的,必须在UI主线程内更新画面,速度较慢。
- SurfaceView 是view的子类,类似使用双缓机制,在新的线程中更新画面所以刷新界面速度比view快
- GLSurfaceView 是SurfaceView的子类,opengl 专用的
SurfaceView和View最本质的区别在于,surfaceView是在一个新起的单独线程中可以重新绘制画面而View必须在UI的主线程中更新画面。
那么在UI的主线程中更新画面 可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。
当使用surfaceView 由于是在新的线程中更新画面所以不会阻塞你的UI主线程。但这也带来了另外一个问题,就是事件同步。比如你触屏了一下,你需要surfaceView中thread处理,一般就需要有一个event queue的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。
基于以上,根据游戏特点,一般分成两类。
- 被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。
- 主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main UI thread。所以显然view不合适,需要surfaceView来控制。
Android中的SurfaceView类就是双缓冲机制。因此,开发游戏时尽量使用SurfaceView而不要使用View,这样的话效率较高,而且SurfaceView的功能也更加完善。
5、SurfaceHolder
可以通过SurfaceHolder接口访问这个Surface.用getHolder()方法可以得到这个接口。
surfaceview变得可见时,surface被创建;surfaceview隐藏前,surface被销毁。这样能节省资源。
如果你要查看 surface被创建和销毁的时机,可以重载surfaceCreated(SurfaceHolder)和 surfaceDestroyed(SurfaceHolder)。
surfaceview的核心在于提供了两个线程:UI线程和渲染线程。
这里应注意:
- 所有SurfaceView和SurfaceHolder.Callback的方法都应该在UI线程里调用,一般来说就是应用程序主线程。渲染线程所要访问的各种变量应该作同步处理。
- 由于surface可能被销毁,它只在SurfaceHolder.Callback.surfaceCreated()和 SurfaceHolder.Callback.surfaceDestroyed()之间有效,所以要确保渲染线程访问的是合法有效的surface。
Android多媒体技术之视频播放的更多相关文章
- android实现控制视频播放次数
android实现控制视频播放次数,实质就是每个视频片段播放完后,通过MediaPlayer设置监听器setOnCompletionListener监听视频播放完毕,用Handler发送消息再次激活视 ...
- Android几种视频播放方式,VideoView、SurfaceView+MediaPlayer、TextureView+MediaPlayer,以及主流视频播放器开源项目
简单的说下一Android的几种视频播放功能: 1.VideoView:最简单的视频播放 <FrameLayout xmlns:android="http://schemas.andr ...
- android 自己定义视频播放器之2/1
非常久没更新博客,相信大家年后都比較忙. 今天给大家带来了一款视频播放器,首先确认的得有几点. 1.首先得有个播放视频的view. 2.加点额外功能进去左边上下滑动调节亮度,右边上下滑动调节声量: 3 ...
- 开源安卓Android流媒体音视频播放器实现声音自动停止、恢复、一键静音功能源码
本文转自EasyDarwin团队John的博客:http://blog.csdn.net/jyt0551/article/details/60802145 我们在开发安卓Android流媒体音视频播放 ...
- Android开发 VideoView视频播放详解
前言 VideoView是Android主要的视频播放View,它其实是对MediaPlayer的再次封装.如果你已经了解过MediaPlayer在使用VideoView是十分简单的.如果你想先了解M ...
- android 全屏视频播放(SurfaceView + MediaPlayer)
介绍个第三方: JieCaoVideoPlayer 实现Android的全屏视频播放,支持完全自定义UI.手势修改进度和音量.hls.rtsp,设置http头信息,也能在ListView.ViewPa ...
- 玩转Android之在线视频播放控件Vitamio的使用
其实Android中自带的MediaPlayer本身就能播放在线视频,MediaPlayer结合SurfaceView播放在线视频也是不错的选择(如果你没有性能或者用户体验上的要求),关于MediaP ...
- 分享几个不错的Android开源音视频播放器
整理了一下Github上几个开源的音视频播放器项目,有兴趣的同学可以clone代码去研究学习. UniversalMusicPlayer https://github.com/googlesamp ...
- Android高级_视频播放控件
一.Android系统自带VideoView控件 1. 创建步骤: (1)自带视频文件放入res/raw文件夹下: (2)声明初始化VideoView控件: (3)创建视频文件Uri路径,Uri调用p ...
随机推荐
- .NET基础 (10)流和序列化
流和序列化1 什么是流,.NET中有哪些常见的流2 如何使用压缩流3 Serializable特性有何作用4 .NET提供了哪几种可进行序列化操作的类型5 如何自定义序列化和反序列化的过程 流和序列化 ...
- Forward团队-爬虫豆瓣top250项目-模块测试过程
我所做的模块不需要测试,但在后续其他人编写代码的时候,我需要对网页源码进行进一步的规范,然后指导别人在网页源码中的标签用法.
- jsp中路径的写法
在JavaWeb开发中,常使用绝对路径的方式来引入JavaScript和CSS文件,这样可以避免因为目录变动导致引入文件找不到的情况 代码” ${pageContext.request.context ...
- java 传参数时 类型后跟 3个点 "..." 的意义
对照代码和运行结果便知"..." 的意义 import java.util.ArrayList; public class StringDemo { public static v ...
- 自定义Team Foundation Server (TFS) 与Project Professional的集成字段
用户可以象使用Office Excel一样,使用Project Professional连接TFS,将数据下载到本地修改,并且发布到TFS服务器上,如果你习惯使用Project来计划你的项目,那么Pr ...
- 命令式语言和声明式语言对比——JavaScript实现快速排序为例
什么是命令式编程 (Imperative Programming)? 命令机器如何做事情,强调细节实现 java.c.c++等都属此类. “这些语言的特征在于,写出的代码除了表现出“什么(What)” ...
- 对SIP摘要认证方案的理解
一.口令认证常见机制 基于口令认证的系统一般有以下几种口令验证方式: 1.客户端以明文形式将用户名密码通过网络发送到服务器,服务器与已经保存在服务端的用户名密码进行比较,一致则通过验证: HTTP基本 ...
- Solr相似度名词:VSM(Vector Space Model)向量空间模型
最近想学习下Lucene ,以前运行的Demo就感觉很神奇,什么原理呢,尤其是查找相似度最高的.最优的结果.索性就直接跳到这个问题看,很多资料都提到了VSM(Vector Space Model)即向 ...
- [JAVA]java复制文件的4种方式
尽管Java提供了一个可以处理文件的IO操作类. 但是没有一个复制文件的方法. 复制文件是一个重要的操作,当你的程序必须处理很多文件相关的时候. 然而有几种方法可以进行Java文件复制操作,下面列举出 ...
- [UWP开发]在windows10中设置壁纸~UserProfilePersonalizationSettings
在之前的wp8.1和wp8中,微软没有公开设置壁纸的API,只有一个设置锁屏的API,但在Windows10中,微软为我们提供了设置壁纸的API:TrySetWallpaperImageAsync,他 ...