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

    分享两个不错的播客. http://blog.csdn.net/u010425035/article/details/10410851 http://blog.csdn.net/xiaoyafang1 ...

  2. sqlldr errors

    sqlldr myUser/myPWD@myCONN control='d:/sqlload/new/test/loader1.ctl' errors=1000000

  3. JavaSE基础之double数据类型的格式化

    JavaSE基础之double数据类型的格式化 1.double 数据类型的格式化工具类:DoubleFormatUtil.java package cn.com.zfc.util; import j ...

  4. luoguP4696 [CEOI2011]Matching KMP+树状数组

    可以非常轻易的将题意转化为有多少子串满足排名相同 注意到$KMP$算法只会在当前字符串的某尾添加和删除字符 因此,如果添加和删除后面的字符对于前面的字符没有影响时,我们可以用$KMP$来模糊匹配 对于 ...

  5. from setuptools import setup, find_packages ImportError: No module named set

    1 from setuptools import setup, find_packages ImportError: No module named set wget http://peak.tele ...

  6. hdu 1732 bfs

    题意:推箱子游戏 代码写错居然卡内存!! 搞了两天了 #include <iostream> #include <cstdio> #include <cstring> ...

  7. mysql慢查询配置

    1.慢查询有什么用? 能记录下所有执行超过long_query_time时间的SQL语句, 帮你找到执行慢的SQL, 方便我们对这些SQL进行优化. 2. 如何开启慢查询? 首先我们先查看MYSQL服 ...

  8. 自动化运维工具 ~puppet~

    一.模板的应用 到目前为止,资源申报.定义类.声明类等所有功能都只能一个manifest文件中实现,但这却非有效的基于puppet管理IT资源架构的方式.实践 中,一般需要把manifest文件分解成 ...

  9. CentOS 7修改网卡名为eth0

    第一步: 编辑文件加入如下所示参数 vi /etc/sysconfig/grub GRUB_CMDLINE_LINUX=”rd.lvm.lv=vg0/swap vconsole.keymap=us c ...

  10. Android4.2.2启动动画前播放视频

    首先声明測试平台为瑞芯微的rk3168,Android4.2.2,Android版本号非常重要,由于Android4.0和Android4.2.2的代码有些地方就有差别,并不通用! 首先接到任务不知怎 ...