Android SurfaceView + MediaPlayer实现视频播放器
2015-08-25 15:28
633 查看
什么是SurfaceView 请参考,非常详细
参考博客
SeekBarChangeEvent:
得到SurfaceView的实例并进行设置:
通过surfaceView得到surfaceHolder:
SurfaceHolder.Callback
创建一个Time滴答器,每秒记录一次进度:
创建MediaPlayer,将surfaceHolder添加进MediaPlayer
OnBufferingUpdateListener的回调
OnPreparedListener的回调
开始播放
暂停播放:
停止播放
Player:
XML布局文件:
参考博客
实现功能:
实现一个可拖拽,可暂停的视频播放控件。步骤总结:
创建一个拖拽条:skbProgress = (SeekBar) this.findViewById(R.id.skbProgress); skbProgress.setOnSeekBarChangeListener(new SeekBarChangeEvent());
SeekBarChangeEvent:
class SeekBarChangeEvent implements SeekBar.OnSeekBarChangeListener { int progress; @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { //原本是(progress/seekBar.getMax())*player.mediaPlayer.getDuration() this.progress = progress * player.mediaPlayer.getDuration() / seekBar.getMax(); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { // seekTo()的参数是相对与影片时间的数字,而不是与seekBar.getMax()相对的数字 player.mediaPlayer.seekTo(progress); } }
得到SurfaceView的实例并进行设置:
surfaceView = (SurfaceView) this.findViewById(R.id.surfaceView1);
通过surfaceView得到surfaceHolder:
surfaceHolder=surfaceView.getHolder(); // 给holder设置callback surfaceHolder.addCallback(SurfaceHolder.Callback);
SurfaceHolder.Callback
@Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { // 变化时调用 } @Override public void surfaceCreated(SurfaceHolder arg0) { // 创建时调用 } @Override public void surfaceDestroyed(SurfaceHolder arg0) { // 销毁时调用 }
创建一个Time滴答器,每秒记录一次进度:
Timer mTimer=new Timer(); mTimer.schedule(mTimerTask, 0, 1000); TimerTask mTimerTask = new TimerTask() { @Override public void run() { if(mediaPlayer==null) return; if (mediaPlayer.isPlaying() && skbProgress.isPressed() == false) { handleProgress.sendEmptyMessage(0); } } }; Handler handleProgress = new Handler() { public void handleMessage(Message msg) { int position = mediaPlayer.getCurrentPosition(); int duration = mediaPlayer.getDuration(); if (duration > 0) { long pos = skbProgress.getMax() * position / duration; skbProgress.setProgress((int) pos); } }; };
创建MediaPlayer,将surfaceHolder添加进MediaPlayer
mediaPlayer = new MediaPlayer(); mediaPlayer.setDisplay(surfaceHolder); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); // 监听缓存刷新 mediaPlayer.setOnBufferingUpdateListener(OnBufferingUpdateListener); // 监听MediaPlayer是否准备好 mediaPlayer.setOnPreparedListener(OnPreparedListener);
OnBufferingUpdateListener的回调
@Override public void onBufferingUpdate(MediaPlayer arg0, int bufferingProgress) { // 通过回调返回的bufferingProgress同步进度条的进度 skbProgress.setSecondaryProgress(bufferingProgress); int currentProgress=skbProgress.getMax()*mediaPlayer.getCurrentPosition()/mediaPlayer.getDuration(); Log.e(currentProgress+"% play", bufferingProgress + "% buffer"); }
OnPreparedListener的回调
/** * 通过onPrepared回调时播放 * 在播放器准备好时调用 * 如果宽高都是0则说明视频加载失败了 */ @Override public void onPrepared(MediaPlayer arg0) { videoWidth = mediaPlayer.getVideoWidth(); videoHeight = mediaPlayer.getVideoHeight(); if (videoHeight != 0 && videoWidth != 0) { arg0.start(); } Log.e("mediaPlayer", "onPrepared"); } /** * 这个不知道是什么时候调用 * 是准备完毕时还是播放完毕时? * API:Called when the end of a media source is reached during playback. */ @Override public void onCompletion(MediaPlayer arg0) { // TODO Auto-generated method stub }
开始播放
public void playUrl(String videoUrl) { try { mediaPlayer.reset(); mediaPlayer.setDataSource(videoUrl); mediaPlayer.prepare();//prepare之后自动播放 //mediaPlayer.start(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
暂停播放:
public void pause() { mediaPlayer.pause(); }
停止播放
public void stop() { if (mediaPlayer != null) { mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; } }
全部源码:
MainActivity:package com.example.oracleen.arcdemo;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.SeekBar;
public class MainActivity extends Activity {
private SurfaceView surfaceView;
private Button btnPause, btnPlayUrl, btnStop;
private SeekBar skbProgress;
private Player player;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
surfaceView = (SurfaceView) this.findViewById(R.id.surfaceView1);
btnPlayUrl = (Button) this.findViewById(R.id.btnPlayUrl);
btnPlayUrl.setOnClickListener(new ClickEvent());
btnPause = (Button) this.findViewById(R.id.btnPause);
btnPause.setOnClickListener(new ClickEvent());
btnStop = (Button) this.findViewById(R.id.btnStop);
btnStop.setOnClickListener(new ClickEvent());
skbProgress = (SeekBar) this.findViewById(R.id.skbProgress); skbProgress.setOnSeekBarChangeListener(new SeekBarChangeEvent());
player = new Player(surfaceView, skbProgress);
}
class ClickEvent implements OnClickListener {
@Override
public void onClick(View arg0) {
if (arg0 == btnPause) {
player.pause();
} else if (arg0 == btnPlayUrl) {
String url="http://125.39.68.104/data6/video09/2015/07/28/3463441-102-0204.mp4";
player.playUrl(url);
} else if (arg0 == btnStop) {
player.stop();
}
}
}
class SeekBarChangeEvent implements SeekBar.OnSeekBarChangeListener {
int progress;
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// 原本是(progress/seekBar.getMax())*player.mediaPlayer.getDuration()
this.progress = progress * player.mediaPlayer.getDuration()
/ seekBar.getMax();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// seekTo()的参数是相对与影片时间的数字,而不是与seekBar.getMax()相对的数字
player.mediaPlayer.seekTo(progress);
}
}
}
Player:
package com.example.oracleen.arcdemo; import java.io.IOException; import java.util.Timer; import java.util.TimerTask; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaPlayer.OnBufferingUpdateListener; import android.media.MediaPlayer.OnCompletionListener; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.widget.SeekBar; public class Player implements OnBufferingUpdateListener, OnCompletionListener, MediaPlayer.OnPreparedListener, SurfaceHolder.Callback { private int videoWidth; private int videoHeight; public MediaPlayer mediaPlayer; private SurfaceHolder surfaceHolder; private SeekBar skbProgress; private Timer mTimer=new Timer(); public Player(SurfaceView surfaceView,SeekBar skbProgress) { this.skbProgress=skbProgress; surfaceHolder=surfaceView.getHolder(); surfaceHolder.addCallback(this); surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); mTimer.schedule(mTimerTask, 0, 1000); } /******************************************************* * 通过定时器和Handler来更新进度条 ******************************************************/ TimerTask mTimerTask = new TimerTask() { @Override public void run() { if(mediaPlayer==null) return; if (mediaPlayer.isPlaying() && skbProgress.isPressed() == false) { handleProgress.sendEmptyMessage(0); } } }; Handler handleProgress = new Handler() { public void handleMessage(Message msg) { int position = mediaPlayer.getCurrentPosition(); int duration = mediaPlayer.getDuration(); if (duration > 0) { long pos = skbProgress.getMax() * position / duration; skbProgress.setProgress((int) pos); } }; }; //***************************************************** public void playUrl(String videoUrl) { try { mediaPlayer.reset(); mediaPlayer.setDataSource(videoUrl); mediaPlayer.prepare();//prepare之后自动播放 // mediaPlayer.start(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void pause() { mediaPlayer.pause(); } public void stop() { if (mediaPlayer != null) { mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; } } @Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { Log.e("mediaPlayer", "surface changed"); } @Override public void surfaceCreated(SurfaceHolder arg0) { try { mediaPlayer = new MediaPlayer(); mediaPlayer.setDisplay(surfaceHolder); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setOnBufferingUpdateListener(this); mediaPlayer.setOnPreparedListener(this); } catch (Exception e) { Log.e("mediaPlayer", "error", e); } Log.e("mediaPlayer", "surface created"); } @Override public void surfaceDestroyed(SurfaceHolder arg0) { Log.e("mediaPlayer", "surface destroyed"); } @Override /** * 通过onPrepared播放 */ public void onPrepared(MediaPlayer arg0) { videoWidth = mediaPlayer.getVideoWidth(); videoHeight = mediaPlayer.getVideoHeight(); if (videoHeight != 0 && videoWidth != 0) { arg0.start(); } Log.e("mediaPlayer", "onPrepared"); } @Override public void onCompletion(MediaPlayer arg0) { // TODO Auto-generated method stub } @Override public void onBufferingUpdate(MediaPlayer arg0, int bufferingProgress) { skbProgress.setSecondaryProgress(bufferingProgress); int currentProgress=skbProgress.getMax()*mediaPlayer.getCurrentPosition()/mediaPlayer.getDuration(); Log.e(currentProgress+"% play", bufferingProgress + "% buffer"); } }
XML布局文件:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <SurfaceView android:id="@+id/surfaceView1" android:layout_width="300dp" android:layout_height="300dp"></SurfaceView> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:orientation="vertical"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="4.0dip" android:orientation="horizontal"> <Button android:id="@+id/btnPlayUrl" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="播放网络视频"></Button> <Button android:id="@+id/btnPause" android:layout_width="80dip" android:layout_height="wrap_content" android:text="暂停"></Button> <Button android:id="@+id/btnStop" android:layout_width="80dip" android:layout_height="wrap_content" android:text="停止"></Button> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:orientation="horizontal"> <SeekBar android:id="@+id/skbProgress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_weight="1.0" android:max="100" android:paddingLeft="10dip" android:paddingRight="10dip"></SeekBar> </LinearLayout> </LinearLayout> </FrameLayout>
相关文章推荐
- android中读取原始(Raw)资源
- android 学习笔记 内容提供器ContentResolver
- Android 给控件自定义Shape背景
- ffmpeg移植到Android
- android TextView 带滚动条,和ScrollView 用法(暂时觉得ScrollView滑动速度比较快)
- Android 多分辨率机适应
- WeakReference 在android中的应用
- Android基础入门教程——2.3.11 Date & Time组件(上)
- AndroidMainifest标签说明2——<activity>
- android 图片尺寸 资料
- 49、android ListView几个比较特别的属性
- Android NDK资料
- A2DP Sink, AVRCP Controller and HFP Client in Android L
- Android开发之HelloWorld程序
- Android FragmentManager BackStackRecord.run throwing NullPointerException
- Android studio无法创建新项目问题解决方案一
- Android 4.4 源码编译
- Android在不同状态下的调试方法
- 【ActionBar】Android ActionBar完全解析,使用官方推荐的最佳导航栏(下)
- android 进程间通信---bind的前世