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);
	}
时间: 2024-11-29 09:45:52

Android视频播放-SurfaceView和Mediaplayer的相关文章

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

作者 : 万境绝尘 ([email protected]) 转载请著名出处 : http://blog.csdn.net/shulianghan/article/details/38895143 一. 相关模块解析 1. 播放载体 SurfaceView 简介 (1) SurfaceView 与 Surface SurfaceView 与 Surface 简介 : SurfaceView 中嵌入了一个 Surface, SurfaceView 可以操控 Surface 的 位置, 大小尺寸等;

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

近期在做一个Android视频播放器的项目.遇到一个问题,就是锁屏之后.surfaceview就会被销毁掉,然后就会出现各种错误.到csdn论坛去发帖提问,各种所谓的大神都说,解锁屏在又一次创建一个,问他详细怎么做,就没有回复了.后来也尝试手动创建,可是报错说surfaceview必须在mediaPlayer之前创建. 事实上这个问题,根本不用又一次创建! .! 解锁屏之后.surfaceview就会自己主动又一次创建.所以.仅仅需在又一次创建之后恢复到曾经的状态就能够了.

Android视频播放1

为何那么决绝?不给我喘气的机会. 突然就想搞一下视频播放,就查了一下资料.网上大牛真多,都讲的很详细.我就纵览细品了一下大牛们的代码.然后就随心写了一个综合的小例子. 其中涉及到:视频播放,文件选择等.用的重点内容:MediaPlayer SurfaceView SurfaceHolder VideoView 除此之外还有最基本的:Activity/Intent/Toast/Dialog/Menu等等.比较适合有一定基础的菜鸟.大鸟可选择性飞过.代码比较多.亲测. 一.视频播放的三种方法 第一种

android视频播放

视频播放我们用到的是MediaPlayer,显示控件使用的surfaceView 我们向SD卡中先添加个视频文件,我的是xajh.3gp,不要用mp4,MP4会出现 should have subtitle controller already set的错误,应该是格式的问题造成的 我们看下布局文件 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="

Android有关surfaceView重新创建的问题。

最近在做一个Android视频播放器的项目,遇到一个问题,就是锁屏之后,surfaceview就会被销毁掉,然后就会出现各种错误.到csdn论坛去发帖提问,各种所谓的大神都说,解锁屏在重新创建一个,问他具体怎么做,就没有回复了.后来也尝试手动创建,但是报错说surfaceview必须在mediaPlayer之前创建. 其实这个问题,根本不用重新创建!!!解锁屏之后,surfaceview就会自动重新创建,所以,只需在重新创建之后恢复到以前的状态就可以了. 版权声明:本文为博主原创文章,未经博主允

android视频播放的代码

本地视频播放,包括播放.暂停,继续等,还有显示播放的进度.效果如下: 1.activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tool

Android视图SurfaceView的实现原理分析

附:Android控件TextView的实现原理分析 来源:http://blog.csdn.net/luoshengyang/article/details/8661317 在Android系统中,有一种特殊的视图,称为SurfaceView,它拥有独立的绘图表面,即它不与其宿主窗口共享同一个绘图表面.由于拥有独立的绘图表面,因此SurfaceView的UI就可以在一个独立的线程中进行绘制.又由于不会占用主线程资源,SurfaceView一方面可以实现复杂而高效的UI,另一方面又不会导致用户输

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

最近在做一个Android视频播放器,遇到一个问题:切换到下一个视频时,中间会停留上一个视频的残存画面. 这是怎么回事? 我在网上找了很多资料,终于找到了原因:我是用自定义一个surfaceview来显示画面的,切换视频时并没有将surfaceview显示的 内容做处理. 怎么解决? 知道原因,那就很好解决了. 首先,视频切换时,不再显示视频,及播放器不显示视频内容. 我找到了我代码中的这个方法:mVideoView.setRender(0); public void setRender(int

Android视频播放之VideoView

1.VideoView类介绍 Android的VideoView组件可以从不同的来源(例如资源文件或内容提供器)读取图像,计算和维护视频的画面尺寸以使其适用于任何布局管理器,并提供一些诸如缩放.着色之类的显示选项,包含在widget下面:android.widget.VideoView.Android中视屏播放框架如下图: 从图中可以看出,VideoView组件进行视频播放的过程可以分为三步: (1)JAVA Framework层,应用程序进来之后到VideoView,再经过Surface: (