android surfaceView+mediaPlayer 自定义视频播放器
16lz
2022-07-01
Android 视频播放一般分为两种(其实3种,还一种是调Android自带播放器):
1.使用Android自带View VideoView ,其中一些功能,已经都给实现好了(此view一般不满足自己的需求,比如:界面啊,控制啊,以及可能还有手势控制音量,手势控制亮度等等,那么就会选择第二种方式)
2.surfaceView+mediaPlayer 自定义播放器(这个可以制作自己想要任何功能以及界面的播放器,当然前提得自己实现)
主要就是
surfaceView:界面输出
mediaPlayer :媒体控制 :包括音量,暂停,播放,停止等等,还有视频各种状态的监听等等。
本片博文不对surfaceView和mediaPlayer 这两个类细解,如果你不了解这两个类的话,看本博文之前应该先去好好了解一下,不然很难看懂,在这里就不说了,直接看效果。
贴出代码:
package com.lcworld.videodemo;import android.content.Context;import android.content.pm.ActivityInfo;import android.content.res.Configuration;import android.media.AudioManager;import android.media.MediaPlayer;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.provider.Settings;import android.support.v7.app.AppCompatActivity;import android.util.DisplayMetrics;import android.util.Log;import android.view.KeyEvent;import android.view.MotionEvent;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import android.view.ViewGroup;import android.view.Window;import android.view.WindowManager;import android.widget.ImageButton;import android.widget.LinearLayout;import android.widget.ProgressBar;import android.widget.RelativeLayout;import android.widget.SeekBar;import android.widget.TextView;import java.io.IOException;import java.text.SimpleDateFormat;/** * 创建:dongshuaijun * 日期:2016/7/1 * 注释:视屏播放 */public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback, View.OnClickListener , SeekBar.OnSeekBarChangeListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener, MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnSeekCompleteListener { //surfaceView private SurfaceView surfaceView; //视频最外层layout private RelativeLayout videoLayout; //控制台layout private LinearLayout controlLayout; //播放、全屏button private ImageButton playBtn, screenBtn; //进度条 private SeekBar seekBar; //加载视频进度progressBar private ProgressBar progressBar; //当前时间,总时间 private TextView currTime, countTime; //surface holder private SurfaceHolder mHolder; //媒体控制 mediaPlayer private MediaPlayer mediaPlayer; //是否全屏 private boolean isFullScreen = false; //是否正在播放 private boolean isPlay = false; //控制台是否显示 private boolean isControl = false; //是否正在拖动seekBar private boolean isSetProgress = false; //是否播放完成 private boolean isPlayCom = false; //是否是第一次加载视频 private boolean isFirstLoadVideo = true; //是否销毁activity private boolean isOnDestroy = false; //是否可见 private boolean isPause = false; //媒体音量管理 private AudioManager audioManager; //点击纵坐标 private float dY = 0; //点击横坐标 private float dX = 0; //抬起纵坐标 private float uY = 0; //抬起横坐标 private float uX = 0; //屏幕当前亮度 private float f = 0; //手机当前亮度模式 0 1 private int countLight; //系统当前亮度 1-255 private int currLight; private static final int HIDE_CONTROL_LAYOUT = -1; //这个地址是我抓的某平台的,我发现这个地址是变化的,所以有可能不能使用,如果不能播放,换个正常的就可以运行了,不要用模拟器运行 private static final String VIDEO_URL = "http://vod.hcs.cmvideo.cn:8088/699056/20160330/16/2206381358/88401385/gx0308wx07sn_54.mp4.m3u8?msisdn=452046967&sid=2206381358×tamp=20160702163222&Channel_ID=305300090030000&preview=1&playseek=000000-001000&encrypt=61b1958423d270fb55606bb955f62d3a"; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == HIDE_CONTROL_LAYOUT) { refreshControlLayout(); } else { currTime.setText(formatTime(msg.what)); seekBar.setProgress(msg.what); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initVideoSize(); initSurface(); setListener(); } private void initView() { surfaceView = (SurfaceView) findViewById(R.id.surface_view); videoLayout = (RelativeLayout) findViewById(R.id.video_layout); controlLayout = (LinearLayout) findViewById(R.id.control_layout); playBtn = (ImageButton) findViewById(R.id.playBtn); screenBtn = (ImageButton) findViewById(R.id.screenBtn); seekBar = (SeekBar) findViewById(R.id.seekBar); progressBar = (ProgressBar) findViewById(R.id.load_bar); currTime = (TextView) findViewById(R.id.curr_time); countTime = (TextView) findViewById(R.id.count_time); mHolder = surfaceView.getHolder(); mediaPlayer = new MediaPlayer(); audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); initScreenLight(); refreshControlLayout(); } //初始化屏幕亮度 private void initScreenLight() { try { //获取亮度模式 0:手动 1:自动 countLight = Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE); //设置手动设置 Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL); //获取屏幕亮度,获取失败则返回255 currLight = android.provider.Settings.System.getInt(getContentResolver(), android.provider.Settings.System.SCREEN_BRIGHTNESS, 255); f = currLight / 255f; } catch (Settings.SettingNotFoundException e) { e.printStackTrace(); } } //刷新控制台 显示则隐藏 隐藏则显示 并5S之后隐藏 private void refreshControlLayout() { if (isControl) { controlLayout.setVisibility(View.INVISIBLE); isControl = false; } else { controlLayout.setVisibility(View.VISIBLE); isControl = true; handler.removeMessages(HIDE_CONTROL_LAYOUT); handler.sendEmptyMessageDelayed(HIDE_CONTROL_LAYOUT, 5000); } } private void setListener() { playBtn.setOnClickListener(this); screenBtn.setOnClickListener(this); seekBar.setOnSeekBarChangeListener(this); mediaPlayer.setOnCompletionListener(this); mediaPlayer.setOnErrorListener(this); mediaPlayer.setOnBufferingUpdateListener(this); mediaPlayer.setOnPreparedListener(this); mediaPlayer.setOnSeekCompleteListener(this); surfaceView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: dX = event.getX(); dY = event.getY(); refreshControlLayout(); break; case MotionEvent.ACTION_UP: break; case MotionEvent.ACTION_MOVE: if (isFullScreen) { uY = event.getY(); if (dX > getWidth() / 2) {//声音控制 if (Math.abs(uY - dY) > 25) setVolume(uY - dY); } else if (dX <= getWidth() / 2) {//亮度控制 setLight(dY - uY); } } break; } return true; } }); } //手势调节音量 private void setVolume(float vol) { if (vol < 0) {//增大音量 audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, AudioManager.FX_FOCUS_NAVIGATION_UP); } else if (vol > 0) {//降低音量 audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, AudioManager.FX_FOCUS_NAVIGATION_UP); } } /** * 手势设置屏幕亮度 * 设置当前的屏幕亮度值,及时生效 0.004-1 * 该方法仅对当前应用屏幕亮度生效 */ private void setLight(float vol) { Window localWindow = getWindow(); WindowManager.LayoutParams localLayoutParams = localWindow.getAttributes(); f += vol / getWidth(); if (f > 1) { f = 1f; } else if (f <= 0) { f = 0.004f; } localLayoutParams.screenBrightness = f; localWindow.setAttributes(localLayoutParams); } //初始化surfaceView private void initSurface() { //设置回调参数 mHolder.addCallback(this); //设置SurfaceView自己不管理的缓冲区 mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); //显示的分辨率,不设置为视频默认// mHolder.setFixedSize(320, 220); } private void playUrl(String url) { try { //使mediaPlayer重新进入ide状态 mediaPlayer.reset(); //设置媒体类型 mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); //将影像输出到surfaceView mediaPlayer.setDisplay(mHolder); //设置 视频资源 可以是本地视频 也可是网络资源// mediaPlayer.setDataSource("/storage/sdcard1/DCIM/Camera/VID_20160629_164144.mp4"); mediaPlayer.setDataSource(url); //同步准备// mediaPlayer.prepare(); //因为是网络视频 这里用异步准备 mediaPlayer.prepareAsync(); } catch (IOException e) { e.printStackTrace(); } } //初始化视频显示的大小 private void initVideoSize() { RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); params.height = getWidth() / 10 * 6; surfaceView.setLayoutParams(params); } //surfaceView创建完成 @Override public void surfaceCreated(SurfaceHolder holder) { Log.e("TAG", "surfaceCreated"); //等surfaceView创建完成再开始播放视频 if (!isPause) { playUrl(VIDEO_URL); } else { isPause = false; mediaPlayer.setDisplay(holder); if (isPlay) mediaPlayer.start(); } } //surfaceView改变 @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.e("TAG", "surfaceChanged"); } //surfaceView销毁 @Override public void surfaceDestroyed(SurfaceHolder holder) { Log.e("TAG", "surfaceDestroyed"); } @Override public void onClick(View v) { isControl = false; refreshControlLayout(); if (isFirstLoadVideo) { return; } switch (v.getId()) { case R.id.playBtn: if (mediaPlayer.isPlaying()) { mediaPlayer.pause(); isPlay = false; playBtn.setBackgroundResource(R.mipmap.play); } else if (isPlayCom) { mediaPlayer.seekTo(0); isPlay = true; isPlayCom = false; playBtn.setBackgroundResource(R.mipmap.pause); } else { mediaPlayer.start(); isPlay = true; playBtn.setBackgroundResource(R.mipmap.pause); } break; case R.id.screenBtn: if (isFullScreen) { smallScreen(); screenBtn.setBackgroundResource(R.mipmap.large_screen); } else { fullScreen(); screenBtn.setBackgroundResource(R.mipmap.small_screen); } break; } } //横竖屏切换 @Override public void onConfigurationChanged(Configuration newConfig) { if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { Log.e("TAG", "当前屏幕为横屏"); isFullScreen = true; fullScreen(); screenBtn.setBackgroundResource(R.mipmap.small_screen); } else { Log.e("TAG", "当前屏幕为竖屏"); isFullScreen = false; smallScreen(); screenBtn.setBackgroundResource(R.mipmap.large_screen); } super.onConfigurationChanged(newConfig); } //全屏 private void fullScreen() { getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//设置成全屏模式 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//强制为横屏 showFullSurface(); } //竖屏 private void smallScreen() { getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//强制为竖屏 showSmallSurface(); } private void showFullSurface() { RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); surfaceView.setLayoutParams(params); } private void showSmallSurface() { RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); params.height = getWidth() / 10 * 6; surfaceView.setLayoutParams(params); } //进度改变 @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { currTime.setText(formatTime(seekBar.getProgress())); if (isSetProgress) { Log.e("TAG", "onProgressChanged:refreshControlLayout"); isControl = false; refreshControlLayout(); } } //开始拖动 @Override public void onStartTrackingTouch(SeekBar seekBar) { currTime.setText(formatTime(seekBar.getProgress())); isSetProgress = true; isControl = false; refreshControlLayout(); } //停止拖动 @Override public void onStopTrackingTouch(SeekBar seekBar) { isSetProgress = false; isControl = false; refreshControlLayout(); if (isFirstLoadVideo) { return; } mediaPlayer.seekTo(seekBar.getProgress()); currTime.setText(formatTime(seekBar.getProgress())); } public int getWidth() { WindowManager manager = getWindowManager(); DisplayMetrics outMetrics = new DisplayMetrics(); manager.getDefaultDisplay().getMetrics(outMetrics); return outMetrics.widthPixels; } //更新进度 private void updateSeekBar() { new Thread(new Runnable() { @Override public void run() { while (!isOnDestroy) { //结束线程标示 if (isPlay && !isPause) { try { Message message = new Message(); message.what = mediaPlayer.getCurrentPosition(); handler.sendMessage(message); Log.e("TAG", "while"); Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } } } } }).start(); } //播放完成 @Override public void onCompletion(MediaPlayer mp) {// Log.e("TAG", "播放完成"); playBtn.setBackgroundResource(R.mipmap.play); isPlay = false; isPlayCom = true; isControl = false; Message message = new Message(); message.what = mediaPlayer.getDuration(); handler.sendMessage(message); refreshControlLayout(); } //播放出错 @Override public boolean onError(MediaPlayer mp, int what, int extra) { isPlay = false; return false; } private String formatTime(long time) { SimpleDateFormat format = new SimpleDateFormat("mm:ss"); return format.format(time); } @Override public void onBufferingUpdate(MediaPlayer mp, int percent) { Log.e("TAG", "onBufferingUpdate" + ",percent:" + percent); } //准备完成 @Override public void onPrepared(MediaPlayer mp) { //设置最大进度 seekBar.setMax(mediaPlayer.getDuration()); //设置按钮背景图片 playBtn.setBackgroundResource(R.mipmap.pause); //设置视频最大时间 countTime.setText(formatTime(mediaPlayer.getDuration())); //隐藏加载进度条 progressBar.setVisibility(View.INVISIBLE); //开始播放 mediaPlayer.start(); //更改播放状态 isPlay = true; //更改状态 if (isFirstLoadVideo) isFirstLoadVideo = false; //开启线程更新进度 updateSeekBar(); } @Override protected void onDestroy() { Log.e("TAG", "onDestroy"); isOnDestroy = true; if (mediaPlayer.isPlaying()) { mediaPlayer.stop(); isPlay = false; } mediaPlayer.release(); super.onDestroy(); } //seekTo()是异步的方法 在此监听是否执行完毕 @Override public void onSeekComplete(MediaPlayer mp) { Log.e("TAG", "onSeekComplete"); if (!isPlay) { mediaPlayer.pause(); } else { mediaPlayer.start(); } } //监听返回键 如果是全屏状态则返回竖屏 否则直接返回 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (isFullScreen) { smallScreen(); return false; } return super.onKeyDown(keyCode, event); } @Override protected void onPause() { Log.e("TAG", "onPause"); isPause = true; if (mediaPlayer.isPlaying()) { mediaPlayer.pause(); } super.onPause(); } @Override protected void onResume() { super.onResume(); if (isPause && isPlay && mHolder.getSurface().isValid()) { isPause = false; mediaPlayer.start(); } }}
demo下载地址: https://github.com/dongxiaoshuai/VideoDemo
更多相关文章
- android EditText设置不可写
- android“设置”里的版本号
- 在Fragment中设置控件点击方法,执行失败。
- Android(安卓)闹钟管理类的使用
- Android设置通知栏/状态栏透明改变通知栏颜色和app最上部分颜色
- android 设置中划线 下划线等
- Andorid Dialog 示例【慢慢更新】
- android图表ichartjs
- Android(安卓)闹钟管理类的使用