Android多媒体的编写主要是播放器的选择,总的来说有两种选择。
1.选用android原生videoview控件,这是最简单的办法,但是videoview的功能有限,涉及到一些操作是无法实现的。
videoview实现很简单。代码如下。
布局文件中声明控件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
tools:context=".MainActivity">
<VideoView
android:id="@+id/videoview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
activity中使用:
private VideoView videoView;
videoView = (VideoView)findViewById(R.id.videoview);
videoView.setVideoPath("http://live.hkstv.hk.lxdns.com/live/hks/playlist.m3u8"); // 香港卫视地址
videoView.start();
//使视频能够暂停、播放、进度条显示等控制
MediaController mediaController = new MediaController(this);
videoView.setMediaController(mediaController);
mediaController.setMediaPlayer(videoView);
manifest中声明权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
如果是本地视频路径setVideoPath()括号中换成本地视频路径即可。
也可以使用自定义VIdeoview控件实现播放视频,这样有更多的可操作性
2.选用Meidaplayer + surfaceView播放视频。
将mediaplayer的方法集成到一个类中
public class SambaVideoPlayer extends FrameLayout {
private String TAG = "SambaVideoPlayer";
private Context mContext;
private IMediaPlayer mMediaPlayer;
private SurfaceView surfaceView;
private static int currentPosition;
private static int duration;
public static boolean isPreparing = false;
public SambaVideoPlayer(Context context) {
super(context);
}
public SambaVideoPlayer(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
mContext = context;
createSurfaceView();
}
private void createSurfaceView() {
surfaceView = new SurfaceView(mContext);
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mMediaPlayer != null) {
mMediaPlayer.setDisplay(holder);
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
LayoutParams layoutParams =
new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
Gravity.CENTER);
addView(surfaceView, 0, layoutParams);
}
//创建一个新的player
private IMediaPlayer createPlayer() {
//todo 各个参数的含义
IjkMediaPlayer ijkMediaPlayer = new IjkMediaPlayer();
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 1);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "http-detect-range-support", 1);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "min-frames", 100);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", 1);
ijkMediaPlayer.setVolume(1.0f, 1.0f);
return ijkMediaPlayer;
}
//开始加载视频
public void load(String mPath) throws IOException {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
mMediaPlayer = createPlayer();
mMediaPlayer.setDisplay(surfaceView.getHolder());
mMediaPlayer.setDataSource(mContext, Uri.parse(mPath));
mMediaPlayer.prepareAsync();
// setListener(mMediaPlayer);
Log.d(TAG, "prepareAsync");
}
private void setListener(IMediaPlayer player) {
Log.d(TAG, "setListener");
player.setOnPreparedListener(new IMediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(IMediaPlayer iMediaPlayer) {
Log.d(TAG, "onPrepared");
if (mMediaPlayer != null) {
mMediaPlayer.start();
Log.d(TAG, "mMediaPlayer.start();" + mMediaPlayer.getDuration());
}
isPreparing = true;
}
});
player.setOnVideoSizeChangedListener(new IMediaPlayer.OnVideoSizeChangedListener() {
@Override
public void onVideoSizeChanged(IMediaPlayer iMediaPlayer, int i, int i1, int i2, int i3) {
}
});
}
public void setOnPreparedListener(IMediaPlayer.OnPreparedListener preparedListener) {
mMediaPlayer.setOnPreparedListener(preparedListener);
}
public boolean isSmabaPlaying() {
if (mMediaPlayer != null) {
return mMediaPlayer.isPlaying();
}
return false;
}
public void play() {
if (mMediaPlayer != null) {
mMediaPlayer.start();
}
}
public void release() {
if (mMediaPlayer != null) {
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer = null;
}
}
public void pause() {
if (mMediaPlayer != null) {
mMediaPlayer.pause();
}
}
public void stop() {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
}
}
public void reset() {
if (mMediaPlayer != null) {
mMediaPlayer.reset();
}
}
public void seekTo(long position) {
if (mMediaPlayer != null){
mMediaPlayer.seekTo(position);
}
}
public ITrackInfo[] getTrackInfo() {
String mime = "und";
if(mMediaPlayer != null){
ITrackInfo[] iTracks = mMediaPlayer.getTrackInfo();
MediaInfo mediaInfo = mMediaPlayer.getMediaInfo();
Log.d(TAG, "iTracks" + mediaInfo.mVideoDecoder);
for(ITrackInfo info : iTracks){
Log.d(TAG, "iTracks" + info.getFormat());
if(info.getTrackType() == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_VIDEO){
// MediaFormat mediaFormat = (MediaFormat)info.getFormat();
Log.d(TAG,"getVideoMimeType ~ mime==" + info.getFormat());
// if (mediaFormat != null){
// mime = mediaFormat.getString(MediaFormat.KEY_MIME);
// Log.d(TAG,"getVideoMimeType ~ mime==" + mime);
// break;
// }
}
}
return iTracks;
}
return null;
}
}
播放活动中调用
public class SambaPlayActivity extends Activity {
private String TAG = "SambaPlayActivity";
private static final int PROGRESS_CHANGE = 0;
private View contentView;
private RelativeLayout parentLayout;
private ControlView mControlView;
protected int mDisPlayWidth;
protected int mDisPlayHeight;
private int position;
boolean isplaying;
SambaVideoPlayer sambaVideoPlayer;
final Handler myHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case PROGRESS_CHANGE:
mControlView.setCurrentTime(position);
mControlView.setProgress(position);
//Log.d(TAG, "PROGRESS_CHANGE" + position);
break;
}
}
};
public static SambaPlayActivity mInstance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.samba_video_layout);
Const.isSambaPlayer = true;
sambaVideoPlayer = findViewById(R.id.video);
parentLayout = findViewById(R.id.samba_layout);
mInstance = this;
Uri uri = getIntent().getData();
Log.d(TAG, "uri" + uri);
try {
sambaVideoPlayer.load(uri.toString());
sambaVideoPlayer.setOnPreparedListener(preparedListener);
} catch (IOException e) {
Toast.makeText(this,"播放失败",Toast.LENGTH_SHORT);
e.printStackTrace();
}
DisplayMetrics dm = new DisplayMetrics();
this.getWindowManager().getDefaultDisplay().getMetrics(dm);
ScreenConstant.SCREEN_WIDTH = dm.widthPixels;
ScreenConstant.SCREEN_HEIGHT = dm.heightPixels;
getPopView(R.layout.mmp_popupvideo, MultiMediaConstant.VIDEO,
mControlImp);
showPopUpWindow(parentLayout);
mControlView.setTimeViewVisibility(true);
getTrackInfo();
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onDestroy() {
isplaying = false;
Const.isSambaPlayer = false;
sambaVideoPlayer.stop();
removeControlView();
sambaVideoPlayer.release();
super.onDestroy();
}
public static SambaPlayActivity getInstance(){
return mInstance;
}
protected void getPopView(int resource, int mediatype, ControlView.ControlPlayState controlImp) {
contentView = LayoutInflater.from(SambaPlayActivity.this).inflate(
resource, null);
mDisPlayWidth = ScreenConstant.SCREEN_WIDTH;
mDisPlayHeight = ScreenConstant.SCREEN_HEIGHT;
mControlView = new ControlView(this, mediatype, controlImp,
contentView, mDisPlayWidth * 2, (mDisPlayHeight * 2) / 7);
Log.i(TAG, " mDisPlayWidth" + mDisPlayWidth + "mDisPlayHeight" + mDisPlayHeight);
}
protected void showPopUpWindow(final View topview) {
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
Log.i(TAG, "---------- showPopUpWindow IdleHandler mControlView:" + mControlView);
mControlView.showAtLocation(topview,
Gravity.LEFT | Gravity.BOTTOM, 0,
0);
// isControlBarShow = true;
return false;
}
});
}
private final ControlView.ControlPlayState mControlImp = new ControlView.ControlPlayState() {
@Override
public void play() {
sambaVideoPlayer.play();
}
@Override
public void pause() {
sambaVideoPlayer.pause();
}
};
public boolean isSmabaPlaying(){
return sambaVideoPlayer.isSmabaPlaying();
}
public void seekTo(long position){
sambaVideoPlayer.seekTo(position);
}
private void removeControlView(){
if(mControlView != null){
mControlView.dismiss();
}
}
public void getTrackInfo(){
Log.d(TAG, "getTrackInfo = " + sambaVideoPlayer.getTrackInfo());
}
private IMediaPlayer.OnPreparedListener preparedListener = new IMediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(IMediaPlayer iMediaPlayer) {
Log.d(TAG, "onPrepared");
iMediaPlayer.start();
int duration = (int) iMediaPlayer.getDuration();
Log.d(TAG, "mMediaPlayer.start();" + "duration" + duration);
mControlView.setEndtime(duration);
mControlView.setProgressMax(duration);
new Thread() {
public void run() {
isplaying = true;
while (isplaying) {
position = (int)iMediaPlayer.getCurrentPosition();
myHandler.sendEmptyMessage(PROGRESS_CHANGE);
//Log.d(TAG, "position = " + position);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Log.d(TAG, "run = " + position);
};
}.start();
}
};
}
mediaplayer主要方法就是
mMediaPlayer.setDisplay(surfaceView.getHolder());设置surfaceview
mMediaPlayer.setDataSource(mContext, Uri.parse(mPath));可以是文件路径也可以是URI。
mMediaPlayer.prepareAsync();异步加载。
至此就完成了播放
mediaplayer+surfaceview中mediaplayer不一定非得是meidaplayer,也可以是ijkplayer(bilibili开源视频框架,基于ffmpeg),exoplayer(yutube视频框架)。这两个比mediaplayer更加强大,使用时导入这两个框架即可,使用方法与mediaplayer基本一致。