Android视频播放-SurfaceView和Mediaplayer
好几天没写博客了,处理了一点个人私事加上平时加班,基本上时间不充裕,上篇文章讲了一下用Mediaplayer来播放音乐,这次就讲讲使用Mediaplayer来和SurfaceView配合播放一个视频流媒体。MediaPlayer不仅可以播放视频,还可以与SurfaceView的配合,SurfaceView主要用于显示MediaPlayer播放的视频流媒体的画面渲染,两者可以一起协同播放视频。
基础维护
先来看下要实现的界面:
如果你看过上篇文章,就发现其实很简单的就是多了一个进度条,还有一个就是SurfaceView,就是下面那块黑色区域;
布局文件代码:
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- tools:context="com.example.googlevideo.MainActivity" >
- <EditText
- android:id="@+id/edit_musicPath"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="输入MV的路径" />
- <SeekBar
- android:id="@+id/seekBar_video"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <Button
- android:id="@+id/btn_Play"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:onClick="playEvent"
- android:text="播放" />
- <Button
- android:id="@+id/btn_Pause"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:onClick="pauseEvent"
- android:text="暂停" />
- <Button
- android:id="@+id/btn_Stop"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:onClick="stopEvent"
- android:text="停止" />
- <Button
- android:id="@+id/btn_Replay"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:onClick="replayEvent"
- android:text="重播" />
- </LinearLayout>
- <SurfaceView
- android:id="@+id/surface_video"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- </LinearLayout>
Demo实现
实现Demo之前应该讲讲视频播放的原理,先确定视频的格式,这个和解码相关,不同的格式视频编码不同,然后通过编码格式进行解码,最后得到一帧一帧的图像,并把这些图像快速的显示在界面上,即为播放一段视频。SurfaceView在Android中就是完成这个功能的。SurfaceView是配合MediaPlayer使用的,MediaPlayer也提供了相应的方法设置SurfaceView显示图片,只需要为MediaPlayer指定SurfaceView显示图像即可。它的完整签名:void setDisplay(SurfaceHolder sh)。它需要传递一个SurfaceHolder对象,SurfaceHolder可以理解为SurfaceView装载需要显示的一帧帧图像的容器,它可以通过SurfaceHolder.getHolder()方法获得。使用MediaPlayer配合SurfaceView播放视频的步骤与播放使用MediaPlayer播放MP3大体一致,只需要额外设置显示的SurfaceView即可。
先准备一段能播放的视频:
播放视频效果图:
代码如下:
- editText = (EditText) findViewById(R.id.edit_musicPath);
- pathString = editText.getText().toString().trim();
- File file = new File(pathString);
- if (file.exists()) {
- try {
- mediaPlayer = new MediaPlayer();
- mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- mediaPlayer.setDataSource(pathString);
- //通过SurfaceView获取的Holder
- mediaPlayer.setDisplay(holder);
- mediaPlayer.prepare();
- mediaPlayer.start();
- btn_PlayButton.setEnabled(false);
- //设置Bar的最大值
- int max=mediaPlayer.getDuration();
- seekBarVideo.setMax(max);
- //定时器更新进度条
- timer=new Timer();
- timeTask=new TimerTask() {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- seekBarVideo.setProgress(mediaPlayer.getCurrentPosition());
- }
- };
- timer.schedule(timeTask, 0, 500);
- //视频播放完之后重新设置显示
- mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
- @Override
- public void onCompletion(MediaPlayer mp) {
- // TODO Auto-generated method stub
- btn_PlayButton.setEnabled(true);
- }
- });
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- } else {
- Toast.makeText(this, "Sorry,你输入的路径有问题,请仔细检查", Toast.LENGTH_SHORT)
- .show();
- }
SeekBar的使用:
- //设置Bar的最大值
- int max=mediaPlayer.getDuration();
- seekBarVideo.setMax(max);
- //定时器更新进度条
- timer=new Timer();
- timeTask=new TimerTask() {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- seekBarVideo.setProgress(mediaPlayer.getCurrentPosition());
- }
- };
- timer.schedule(timeTask, 0, 500);
其中holder是SurfaceHolder,在onCreate中获取:
- surfaceView = (SurfaceView) findViewById(R.id.surface_video);
- holder = surfaceView.getHolder();
- //兼容4.0以后的手机版本,本身是不维护的
- holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
如果正在播放视频,最小化的时候是会有声音的,需要在回调函数中处理一下:
- holder.addCallback(new Callback() {
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- // TODO Auto-generated method stub
- Log.i(tag, "销毁了Holder");
- if (mediaPlayer!=null&&mediaPlayer.isPlaying()) {
- currentPosition=mediaPlayer.getCurrentPosition();
- mediaPlayer.stop();
- mediaPlayer.release();
- mediaPlayer=null;
- timer.cancel();
- timeTask.cancel();
- timer=null;
- timeTask=null;
- }
- }
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- // TODO Auto-generated method stub
- Log.i(tag,"创建了Holder");
- if (currentPosition>0) {
- try {
- mediaPlayer = new MediaPlayer();
- mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- mediaPlayer.setDataSource(pathString);
- //通过SurfaceView获取的Holder
- mediaPlayer.setDisplay(holder);
- mediaPlayer.prepare();
- mediaPlayer.start();
- mediaPlayer.seekTo(currentPosition);
- btn_PlayButton.setEnabled(false);
- //视频播放完之后重新设置显示
- mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
- @Override
- public void onCompletion(MediaPlayer mp) {
- // TODO Auto-generated method stub
- btn_PlayButton.setEnabled(true);
- }
- });
- int max=mediaPlayer.getDuration();
- seekBarVideo.setMax(max);
- //定时器更新进度条
- timer=new Timer();
- timeTask=new TimerTask() {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- seekBarVideo.setProgress(mediaPlayer.getCurrentPosition());
- }
- };
- timer.schedule(timeTask, 0, 500);
- } catch (Exception e) {
- // TODO: handle exception
- }
- }
- }
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width,
- int height) {
- // TODO Auto-generated method stub
- Log.i(tag,"改变了Holder");
- }
- });
进度条是SeekBar,如果需要快进或者后退的时候是需要将焦点赋值给mediaPlayer的:
- seekBarVideo=(SeekBar) findViewById(R.id.seekBar_video);
- seekBarVideo.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- // TODO Auto-generated method stub
- int position=seekBar.getProgress();
- if (mediaPlayer!=null&&mediaPlayer.isPlaying()) {
- mediaPlayer.seekTo(position);
- }
- }
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- // TODO Auto-generated method stub
- }
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress,
- boolean fromUser) {
- // TODO Auto-generated method stub
- }
- });
暂停事件:
- public void pauseEvent(View view) {
- if (btn_PauseButton.getText().equals("继续")) {
- mediaPlayer.start();
- btn_PauseButton.setText("暂停");
- return;
- }
- if (mediaPlayer != null && mediaPlayer.isPlaying()) {
- mediaPlayer.pause();
- btn_PauseButton.setText("继续");
- }
- }
停止事件:
- public void stopEvent(View view) {
- if (mediaPlayer != null && mediaPlayer.isPlaying()) {
- btn_PlayButton.setEnabled(true);
- mediaPlayer.stop();
- // 释放mediaplayer否则的话会占用内存
- mediaPlayer.release();
- mediaPlayer = null;
- }
- btn_PauseButton.setText("暂停");
- btn_PlayButton.setEnabled(true);
- }
重播事件:
- public void replayEvent(View view) {
- surfaceView.setVisibility(View.VISIBLE);
- if (mediaPlayer != null && mediaPlayer.isPlaying()) {
- mediaPlayer.seekTo(0);
- } else {
- playEvent(view);
- }
- // 重播的时候应该设置播放的状态
- btn_PlayButton.setEnabled(true);
- }
Android视频播放-SurfaceView和Mediaplayer的更多相关文章
- Android音视频之MediaPlayer音视频播放
前言: 昨天总结了视频录制,今天来学习一下视频的播放,Android的视频播放主要采用MediaPlayer类. MediaPlayer介绍 MediaPlayer类可用于控制音频/视频文件或流的播放 ...
- 【Android 多媒体开发】 MediaPlayer 网络视频播放器
作者 : 万境绝尘 (octopus_truth@163.com) 转载请著名出处 : http://blog.csdn.net/shulianghan/article/details/3889514 ...
- Android 视频播放器 (二):使用MediaPlayer播放视频
在 Android 视频播放器 (一):使用VideoView播放视频 我们讲了一下如何使用VideoView播放视频,了解了基本的播放器的一些知识和内容.也知道VideoView内部封装的就是Med ...
- android中使用surfaceview+MediaPlayer播放视频
Android中播放视频主要有两种方式: 使用其自带的播放器.指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型 使用android自带的VideoView,这种方法 ...
- android视频播放心得体会
android视频播放主要是两种方式1.系统封装好的videoplayer,有前进.后退.暂停/播放.拉动最基本的功能,够一般使用,操作办法也很简单,如果需要自定义程度高就需要用到第二种方法:Surf ...
- android视频播放
视频播放我们用到的是MediaPlayer,显示控件使用的surfaceView 我们向SD卡中先添加个视频文件,我的是xajh.3gp,不要用mp4,MP4会出现 should have subti ...
- Android有关surfaceView又一次创建的问题。
近期在做一个Android视频播放器的项目.遇到一个问题,就是锁屏之后.surfaceview就会被销毁掉,然后就会出现各种错误.到csdn论坛去发帖提问,各种所谓的大神都说,解锁屏在又一次创建一个, ...
- Android 视频播放器 (四):使用ExoPlayer播放视频
一.简介 ExoPlayer是一个Android应用层的媒体播放器,它提供了一套可替换Android MediaPlayer的API,可以播放本地或者是线上的音视频资源.ExoPlayer支持一些An ...
- Android 视频播放器切换到下个视频时残留上个视频画面的解决办法
最近在做一个Android视频播放器,遇到一个问题:切换到下一个视频时,中间会停留上一个视频的残存画面. 这是怎么回事? 我在网上找了很多资料,终于找到了原因:我是用自定义一个surfacev ...
随机推荐
- synchoronized和lock区别
synchoronized是JVM的内置锁,而lock是Java代码实现的.lock是sync对的扩展,完全可以替代后者.lock可以重入,允许同一个线程连续多次获得同一把锁.其次,lock独有的功能 ...
- Linux安装系统选择 日报 18/06/23
Linux安装系统选择 Centos7 程序体积7个G,如果是学习伊始, 注意不要选择那个体积小的,因为我装过之后进去发现这个wifie还要自己进行一些烈的命令才能连接成功.很麻烦的. 安装比较顺利但 ...
- sklearn六大板块
六大板块 分类 回归 聚类 数据降维 数据预处理 特征抽取 统一API estimator.fit(X_train,[y_train]) estimator.fit(X_train,[y_train] ...
- navicat premium 的使用——navicat 连接MySQL数据库
最近,在学习navicat premium这款第三方软件,他是一个三方数据库管理软件,在前一段时间实习的时候,我使用这款软件调用过服务器上的数据库,不过,当时并没有仔细研究,再次遇到这个软件,我决定仔 ...
- CF17E Palisection 差分+manacher算法
题目大意: 给定一个串$S$,询问有多少对相交的回文子串 直接做的办法: 我们先考虑求出以$i$为结尾的串的数量,这个很好统计 之后,我们再求出所有包含了点$i$的回文串的数目 这个相当于在$i$的左 ...
- 2-SAT的一些题目
http://blog.sina.com.cn/s/blog_64675f540100k2xj.html 都一个类型的不是很想写.
- 2018 计蒜之道复赛 贝壳找房魔法师顾问(并查集+dfs判环)
贝壳找房在遥远的传奇境外,找到了一个强大的魔法师顾问.他有 22 串数量相同的法力水晶,每个法力水晶可能有不同的颜色.为了方便起见,可以将每串法力水晶视为一个长度不大于 10^5105,字符集不大于 ...
- voith项目配置服务程序
项目需求: 1.程序可以最小化到任务栏 2.tpms标签和限速标签同时只能选择一个,并且要通过button确定修改 3.在程序中需要显示SequenceScanner1.0服务的运行状态 4.能够打开 ...
- UC浏览器 垂直水平居中
今天使用下述方式定义水平垂直居中不起作用 #box{ position: fixed; left:; right:; top:; bottom:; margin: auto; } 然后改用: #box ...
- Windows下C语言调用dll动态链接库
dll是windows下的动态链接库文件,下面记录一下在windows下如何调用C语言开发的dll动态链接库. 1.dll动态链接库的源代码 hello_dll.c #include "st ...