好几天没写博客了,处理了一点个人私事加上平时加班,基本上时间不充裕,上篇文章讲了一下用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的更多相关文章

  1. Android音视频之MediaPlayer音视频播放

    前言: 昨天总结了视频录制,今天来学习一下视频的播放,Android的视频播放主要采用MediaPlayer类. MediaPlayer介绍 MediaPlayer类可用于控制音频/视频文件或流的播放 ...

  2. 【Android 多媒体开发】 MediaPlayer 网络视频播放器

    作者 : 万境绝尘 (octopus_truth@163.com) 转载请著名出处 : http://blog.csdn.net/shulianghan/article/details/3889514 ...

  3. Android 视频播放器 (二):使用MediaPlayer播放视频

    在 Android 视频播放器 (一):使用VideoView播放视频 我们讲了一下如何使用VideoView播放视频,了解了基本的播放器的一些知识和内容.也知道VideoView内部封装的就是Med ...

  4. android中使用surfaceview+MediaPlayer播放视频

    Android中播放视频主要有两种方式: 使用其自带的播放器.指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型 使用android自带的VideoView,这种方法 ...

  5. android视频播放心得体会

    android视频播放主要是两种方式1.系统封装好的videoplayer,有前进.后退.暂停/播放.拉动最基本的功能,够一般使用,操作办法也很简单,如果需要自定义程度高就需要用到第二种方法:Surf ...

  6. android视频播放

    视频播放我们用到的是MediaPlayer,显示控件使用的surfaceView 我们向SD卡中先添加个视频文件,我的是xajh.3gp,不要用mp4,MP4会出现 should have subti ...

  7. Android有关surfaceView又一次创建的问题。

    近期在做一个Android视频播放器的项目.遇到一个问题,就是锁屏之后.surfaceview就会被销毁掉,然后就会出现各种错误.到csdn论坛去发帖提问,各种所谓的大神都说,解锁屏在又一次创建一个, ...

  8. Android 视频播放器 (四):使用ExoPlayer播放视频

    一.简介 ExoPlayer是一个Android应用层的媒体播放器,它提供了一套可替换Android MediaPlayer的API,可以播放本地或者是线上的音视频资源.ExoPlayer支持一些An ...

  9. Android 视频播放器切换到下个视频时残留上个视频画面的解决办法

    最近在做一个Android视频播放器,遇到一个问题:切换到下一个视频时,中间会停留上一个视频的残存画面.   这是怎么回事?   我在网上找了很多资料,终于找到了原因:我是用自定义一个surfacev ...

随机推荐

  1. Windows系统php5.6安装Imagick库

    Windows上的安装坑比较多 1.安装Imagick,需要下载6.9.3之下版本的 http://imagemagick.org/script/download.php 官网都是新版本不可以用 我安 ...

  2. 利用arpspoof探取账户密码

    ---恢复内容开始--- > /proc/sys/net/ipv4/ip_forward 首先在kali里开启IP转发功能 arpspoof -t 被害人ip 网关ip -i eth0 例如 再 ...

  3. 【BZOJ】4767: 两双手【组合数学】【容斥】【DP】

    4767: 两双手 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1057  Solved: 318[Submit][Status][Discuss] ...

  4. zoj 2587 判断最小割的唯一性

    算法: 先求出残量网络,计算出从src能够到的点集A,再求出能够到dst的点集B,如果所有点都被访问到了,那么割就是唯一的,即(A,B),否则(A,V-A)和(V-B,B)都是最小割. (注意因为割的 ...

  5. bzoj 3275 最小割

    给你一堆东西,叫你选一些东西出来,使得价值最大,要求选出的东西集合中的任意a,b满足性质p. 可以考虑: 1.拟阵? 2.二分图? 这道题由于数学硬伤,不知道不存在两条直角边是奇数,斜边是整数的直角三 ...

  6. Educational Codeforces Round 13 E. Another Sith Tournament 状压dp

    E. Another Sith Tournament 题目连接: http://www.codeforces.com/contest/678/problem/E Description The rul ...

  7. BZOJ 1022 [SHOI2008]小约翰的游戏John AntiNim游戏

    1022: [SHOI2008]小约翰的游戏John Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1475  Solved: 932[Submit][ ...

  8. HDU step by step

    section 1 不解释~ section 2 1.2.1 a+b coming #include<stdio.h> long long z,x,y; int main( ) { whi ...

  9. Antd前端开发采坑记录

    背景 基于页面友好,界面整洁美观:基于Antd框架开发虾能平台 选型 基于Antd-admin工程架构,进行开发:基于Antd+React+Umj 采坑记录 按照Html方式天机onClick方法,每 ...

  10. Mysql 5.6 慢日志配制

    一.配制my.cnf(/etc/my.cnf) slow_query_log=onlong_query_time=1slow_query_log_file=/var/log/slow_query.lo ...