android surfaceView+mediaPlayer 自定义视频播放器

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

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值