在Android中音视频播放都可以使用MediaPlayer来进行处理。我使用的是SurfaceView 作为载体进行播放视频,还有其他的VideoView也是可以播放的,区别我就不说啦,网络上有很多。简单的来说播放音视频文件只需要两步
第一步
首先创建MediaPlayer实例,设置SurfaceView的管理类SurfaceHolder,为视频播放做准备,
mPlayer = new MediaPlayer();
mPlayer.setDataSource(url);
mPlayer.prepare();
mHolder = mSurface.getHolder();
mHolder.addCallback(callback);
mHolder.setFormat(PixelFormat.RGBA_8888);
setDataSource这个方法是设置视频播放的地址,可以是本地地址,也可以是网络地址,当然了,项目中的资源也可以使用这个,只是写法不同,
AssetFileDescriptor afd = this.getResource().openRawResourceFd (R.raw.avchat_ring);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
playerAudio.setDataSource(afd);
}
关于setDataSource方法还有其他几种,不怎么常用,如果不使用setDataSource,可以直接在MediaPlayer实例化中实现
MediaPlayer player = MediaPlayer.create(PlayVideoActivity.this, R.raw.video);
在第一步中有一个重要的接口实现mHolder.addCallback(callback);
这个接口才是能在SurfaceView控件上面显示的图像的关键;
private SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
mPlayer.setDisplay(holder);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
};
当上面的初始化准备好了之后会调用surfaceCreated这个函数,在这里我们调用setDisplay将SurfaceHolder设置到媒体播放器中。这样就将播放器和我们的显示载体连接到了一起。
第二步
播放设置好的视频源和显示载体,我们就开始播放,调用MediaPlayer的start()函数直接播放。最好是在使用mPlayer 之前,先判断一下,防止出现空指针异常。
if (mPlayer != null) {
mPlayer.start();
}
暂停和停止
暂停播放和停止播放是两个不同的台概念,暂停之后可以直接再次调用start()函数播放视频,停止播放则不能直接调用start()函数播放,必须在播放之前重新准备MediaPlayer才能播放,具体原因就是在Stop的状态下不能直接转到Start的状态,需要先进入Prepare状态。
- 暂停
if (mPlayer != null) {
mPlayer.pause();
}
- 停止
if (mPlayer != null) {
mPlayer.stop();
mPlayer.prepare();
}
- 释放
release()调用该方法之后想要再次播放视频,需要重新实例化MediaPlayer。
if (mPlayer != null) {
mPlayer.release();
mPlayer = null;
}
全部代码
/**
* @介绍: 音频工具类
* @作者: sunset
* @日期: 2018/1/16
*/
public class MediaUtil {
private String TAG = "MediaUtil";
private SurfaceHolder mHolder;
private MediaPlayer mPlayer;
private SurfaceView mSurface;
private ImageView mThumbnail;
private ImageView mPlay;
private OnMediaListener listener;
/**
* 构造函数
*
* @param surface 播放视频的载体,必须传
* @param thumbnail 视频缩略图(可选)
* @param play 视频播放按钮(可选)
*/
public MediaUtil(SurfaceView surface, ImageView thumbnail, ImageView play) {
this.mSurface = surface;
this.mThumbnail = thumbnail;
this.mPlay = play;
}
/**
* 初始化MediaPlayer
*
* @param url 播放源
*/
public void initVideo(String url) {
if (url == null) {
return;
}
try {
mPlayer = new MediaPlayer();
mPlayer.setDataSource(url);
mPlayer.prepare();
mPlayer.setOnCompletionListener(completionListener);
mPlayer.setOnPreparedListener(preparedListener);
mPlayer.setOnVideoSizeChangedListener(sizeChangedListener);
mHolder = mSurface.getHolder();
mHolder.addCallback(callback);
mHolder.setFormat(PixelFormat.RGBA_8888);
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
/**
* SurfaceView 准备好之后触发该接口,一般用来播放
*/
private SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
mPlayer.setDisplay(holder);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
};
/**
* 是否显示缩略图和播放按钮
*
* @param visible {@link Boolean}
*/
public void isVisible(boolean visible) {
if (mThumbnail != null && mPlay != null) {
if (visible) {
mThumbnail.setVisibility(View.VISIBLE);
mPlay.setVisibility(View.VISIBLE);
} else {
mThumbnail.setVisibility(View.GONE);
mPlay.setVisibility(View.GONE);
}
} else {
Log.d(TAG, "不需要缩略图和播放按钮");
}
}
/**
* 开始播放
*/
public void onStartPlay() {
if (mPlayer != null) {
isVisible(false);
mPlayer.start();
}
}
/**
* 判断视频是否正在播放
*
* @return {@link Boolean}
*/
public boolean isPlaying() {
return mPlayer.isPlaying();
}
/**
* 暂停播放
*/
public void onPause() {
if (mPlayer != null) {
mPlayer.pause();
}
}
/**
* 停止播放
*/
public void onStop() {
if (mPlayer != null) {
try {
mPlayer.stop();
mPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}
/**
* 释放MediaPlayer
*/
public void onDestroy() {
Log.v(TAG, "onDestroy");
if (mPlayer != null) {
mPlayer.release();
mPlayer = null;
}
}
private MediaPlayer.OnCompletionListener completionListener = new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
if (listener!=null){
listener.onCompletion(mp);
}
}
};
private MediaPlayer.OnPreparedListener preparedListener = new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
if (listener!=null){
listener.onPrepared(mp);
}
}
};
MediaPlayer.OnVideoSizeChangedListener sizeChangedListener = new MediaPlayer.OnVideoSizeChangedListener() {
@Override
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
if (listener!=null){
listener.onVideoSizeChanged(mp, width, height);
}
}
};
public void setOnMediaListener(OnMediaListener listener) {
this.listener = listener;
}
public interface OnMediaListener {
void onPrepared(MediaPlayer mp);
void onVideoSizeChanged(MediaPlayer mp, int width, int height);
void onCompletion(MediaPlayer mp);
}
/**
* 适应控件的高度显示视频的大小
*/
public void onAdaptiveSize() {
if (mPlayer != null && mSurface != null) {
int videoWidth = mPlayer.getVideoWidth();
int videoHeight = mPlayer.getVideoHeight();
int mSurfaceViewWidth = mSurface.getWidth();
int mSurfaceViewHeight = mSurface.getHeight();
LogUtil.logd(mSurfaceViewHeight + "-----------" + mSurfaceViewWidth);
// mHolder.setFixedSize(mSurfaceViewWidth, mSurfaceViewHeight);
int w = mSurfaceViewHeight * videoWidth / videoHeight;
int margin = (mSurfaceViewWidth - w) / 2;
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(margin, 0, margin, 0);
lp.addRule(RelativeLayout.CENTER_HORIZONTAL);
mSurface.setLayoutParams(lp);
}
}
/**
* 全屏控件的高度显示视频的大小
*/
public void onFullScreenSize() {
if (mPlayer != null && mSurface != null) {
int videoWidth = mPlayer.getVideoWidth();
int videoHeight = mPlayer.getVideoHeight();
int mSurfaceViewWidth = ScreenUtil.getDisplayWidth();
int mSurfaceViewHeight = ScreenUtil.getDisplayHeight();
LogUtil.logd(mSurfaceViewHeight + "-----------" + mSurfaceViewWidth);
// mHolder.setFixedSize(mSurfaceViewWidth, mSurfaceViewHeight);
int w = mSurfaceViewHeight * videoWidth / videoHeight;
int margin = (mSurfaceViewWidth - w) / 2;
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
lp.setMargins(margin, 0, margin, 0);
mSurface.setLayoutParams(lp);
}
}
/**
* 获取视频缩略图
*
* @param filePath
* @param kind
* @return
*/
public Bitmap getVideoThumbnail(String filePath, int kind) {
Bitmap bitmap = null;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
if (filePath.startsWith("http://")
|| filePath.startsWith("https://")
|| filePath.startsWith("widevine://")) {
retriever.setDataSource(filePath, new Hashtable<String, String>());
} else {
retriever.setDataSource(filePath);
}
bitmap = retriever.getFrameAtTime(0, MediaMetadataRetriever.OPTION_CLOSEST_SYNC); //retriever.getFrameAtTime(-1);
} catch (IllegalArgumentException ex) {
// Assume this is a corrupt video file
ex.printStackTrace();
} catch (RuntimeException ex) {
// Assume this is a corrupt video file.
ex.printStackTrace();
} finally {
try {
retriever.release();
} catch (RuntimeException ex) {
// Ignore failures while cleaning up.
ex.printStackTrace();
}
}
if (bitmap == null) {
return null;
}
if (kind == MediaStore.Images.Thumbnails.MINI_KIND) {//压缩图片 开始处
// Scale down the bitmap if it's too large.
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int max = Math.max(width, height);
if (max > 512) {
float scale = 512f / max;
int w = Math.round(scale * width);
int h = Math.round(scale * height);
bitmap = Bitmap.createScaledBitmap(bitmap, w, h, true);
}//压缩图片 结束处
} else if (kind == MediaStore.Images.Thumbnails.MICRO_KIND) {
bitmap = ThumbnailUtils.extractThumbnail(bitmap,
96,
96,
ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
}
return bitmap;
}
}
OnMediaListener 这个接口是对MediaPlayer类的接口进行管理的作用。