多媒体开发---视频播放器开发(android)

android中在实际的视频开发中多用即成的框架,或者自己封装相关的Manager来实现;下面介绍一个简单的android视频开发的过程:
1.实现网络和本地视频播放
2.点击控制播放,暂停
3.支持进度条的拖动,实时跟新进度,时间
4.支持横竖屏切换
5.在横屏状态下,音量键显示并且可调节
6.支持手势触摸,即:上下滑动左半屏,弹出dialog,控制屏幕亮度,并且显示进度条;上下滑动右半屏,弹出dialog,控制声音大小,并且显示进度条;
下面看效果图(模拟器不能显示亮度,真机可以;由于模拟器的局限性会细微的视觉落差):
这里写图片描述
由于csdn上传gif动图有限制,所以不能太长时间……ok下面来看下代码的实现:

1.

首先demo是基于videoView为基础,当然简单的开发,没有过多要求可以用原生的控制器可以可以解决,在这里控制都是自定义;首先为保证横竖屏幕的宽高不适配,需要自定义vieoView重写测量方法:

public class AlpshVideo extends VideoView {
    public AlpshVideo(Context context) {
        super(context);
    }

    public AlpshVideo(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AlpshVideo(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //我们重新计算高度
        int width = getDefaultSize(0, widthMeasureSpec);
        int height = getDefaultSize(0, heightMeasureSpec);
        setMeasuredDimension(width, height);
    }
}

接着xml中嵌入自定义的vieoView:

<com.example.video.customView.AlpshVideo
            android:id="@+id/videoView"
            android:layout_width="match_parent"
            android:layout_height="240dp"
            />

在MainActivity中加载本地或者网络视频:

 //加载本地
        mVideoView.setVideoPath("android.resource://"+getPackageName()+"/"+R.raw.welcome);
        mVideoView.start();

        //加载网络url
        //mVideoView.setVideoURI(Uri.parse("xxxx"));
    我们这里以本地为例;ok这样videoView就可以开始比方视频;

2.

自定义控制器—->布局
这里写图片描述

接下来看代码,xml比较简单,仅展示代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/fr_video"
        android:layout_width="match_parent"
        android:layout_height="240dp">

        <com.example.video.customView.AlpshVideo
            android:id="@+id/videoView"
            android:layout_width="match_parent"
            android:layout_height="240dp"
            />

        <LinearLayout
            android:orientation="vertical"
            android:layout_gravity="bottom"
            android:layout_width="match_parent"
            android:layout_height="50dp">

            <SeekBar
                android:id="@+id/media_progress"
                android:thumb="@null"
                android:progressDrawable="@drawable/seekbar_style2"
                android:max="100"
                android:progress="20"
                android:indeterminate="false"
                android:layout_width="match_parent"
                android:layout_height="5dp"
                android:layout_marginLeft="-20dp"
                android:layout_marginRight="-20dp"/>

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="#101010"
                android:gravity="center_vertical">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:gravity="center_vertical">


                    <ImageView
                        android:id="@+id/media_actions"
                        android:layout_marginLeft="15dp"
                        android:layout_width="20dp"
                        android:layout_height="match_parent"
                        android:src="@drawable/stop_btn"/>

                    <TextView
                        android:id="@+id/media_time"
                        android:layout_marginLeft="30dp"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="00:00:00"
                        android:textColor="#fff"
                        android:textSize="12sp"/>

                    <TextView
                        android:layout_marginLeft="5dp"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="/"
                        android:textColor="#fff"
                        android:textSize="12sp"/>

                    <TextView
                        android:id="@+id/media_total_time"
                        android:layout_marginLeft="5dp"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="00:00:00"
                        android:textColor="#fff"
                        android:textSize="12sp"/>

                    <ImageView
                        android:id="@+id/media_sounds"
                        android:visibility="gone"
                        android:layout_marginLeft="100dp"
                        android:layout_width="20dp"
                        android:layout_height="match_parent"
                        android:src="@drawable/icon_sounds"/>


                    <SeekBar
                        android:visibility="gone"
                        android:id="@+id/media_sounds_progress"
                        android:thumb="@null"
                        android:progressDrawable="@drawable/seekbar_style"
                        android:max="100"
                        android:progress="20"
                        android:indeterminate="false"
                        android:layout_width="100dp"
                        android:layout_height="5dp"
                        android:layout_marginLeft="-10dp"
                        />
                </LinearLayout>

                <ImageView
                    android:id="@+id/media_full_screen"
                    android:layout_marginRight="15dp"
                    android:layout_alignParentRight="true"
                    android:layout_centerVertical="true"
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:src="@drawable/ic_full_screen"/>
            </RelativeLayout>
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center">
            <include layout="@layout/dialog"
                android:visibility="gone"/>
        </LinearLayout>

    </FrameLayout>
</RelativeLayout>

3.

控制器中播放暂停按钮的实现

初始化音量进度条:

//获取音频管理器
        mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
        int streamMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        int streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);

        mMediaSoundsProgress.setMax(streamMaxVolume);
        mMediaSoundsProgress.setProgress(streamVolume);
    点击事件的普片切换比较简单,通过按钮的图形化切换来控制videoView的开始和暂停:在播放过程中要实时更新播放时间和进度,这里用handler来实现:
 private void setPlayer() {
        mMediaActions.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mVideoView.isPlaying()){
                    mMediaActions.setImageResource(R.drawable.play_btn);
                    mVideoView.pause();
                    mHandler.removeMessages(UpDate);
                }else {
                    mMediaActions.setImageResource(R.drawable.stop_btn);
                    mVideoView.start();
                    mHandler.sendEmptyMessage(UpDate);
                }
            }
        });
    }

在上面代码中看到,由播放状态改变为暂停状态,实时跟新的hanler停止,切换为播放再次开启;下面看下线程中实时更新的代码:

   private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == UpDate){
                //当前时间
                int currentPosition = mVideoView.getCurrentPosition();

                //总时间
                int duration = mVideoView.getDuration();
                //设置时间
                updateTime(mMediaTime,currentPosition);
                updateTime(mMediaTotalTime,duration);
                //设置进度
                mMediaProgress.setMax(duration);
                mMediaProgress.setProgress(currentPosition);

                mHandler.sendEmptyMessageDelayed(UpDate,500);

            }


        }
    };

到这一步,视频可以播放,播放进度条实时跟新,播放时间可以实时更新;

当然在一个视频播放器中,必须实现进度条的拖动来实现进度的控制(就是快进和快退);那么需要监听播放进度条的拖动事件:

private void setScrollSeek() {
        //播放器的进度条监听
        mMediaProgress.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean b) {
                updateTime(mMediaTime,progress);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                mHandler.removeMessages(UpDate);
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                int progress = seekBar.getProgress();
                mVideoView.seekTo(progress);
                mHandler.sendEmptyMessage(UpDate);
            }
        });

4.

当然横竖屏切换时必须的;
4.1

手机翻转然后横竖屏自由切换,当然在第一步中有提到自定义videoView重新测量,也是为了横竖屏切换时候做准备,防止半屏显示不全的出现:首先在清单文件中配置:(而且切换横屏之后音量键开始显示)

  <activity
            android:configChanges="orientation|screenSize|keyboard|keyboardHidden"
            android:name=".MainActivity"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

这样设置之后可以全屏,但是videoView并不可以适配,所以需要MainActivity中重写onConfigurationChanged:

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        //当为横屏时候
        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
            setConfigWh(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);
            isFull = true;

            //音量键的显示
            mMediaSounds.setVisibility(View.VISIBLE);
            mMediaSoundsProgress.setVisibility(View.VISIBLE);
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

        }else{
        //当为竖屏时候
            setConfigWh(ViewGroup.LayoutParams.MATCH_PARENT, DensityUtil.dp2px(this,240));
            isFull = false;

            mMediaSounds.setVisibility(View.GONE);
            mMediaSoundsProgress.setVisibility(View.GONE);
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
        }
    }

4.2

在竖屏状态下,点击右下角的全屏按钮 也会显示横屏,所以需要设置其点击事件:

  private void setFullScreen() {
        //设置全屏播放
        mMediaFullScreen.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (isFull){
                    //此时是全屏
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

                }else {
                    //此时是半屏
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

                }
            }
        });
    }

当这里横竖屏切换和适配就可以正常显示了

5

切换到横屏之后音量键显示,则需要显示器控制音量的功能:

 //声音调节进度条
        mMediaSoundsProgress.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean b) {
                mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC,progress,0);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
            }
        });

当这里一个简单的播放器基本完备

6

接下来来添加手势

大概策略是这样:横屏状态下(需要添加boolean判断来限定横屏之下触发):当上下滑动屏幕左半边,亮度改变,弹出一个类似dialog显示连读进度条的改变,结束触摸,则弹窗消失;当上下滑动屏幕右半边,声音改变,弹出一个类似dialog显示连读进度条的改变,结束触摸,则弹窗消失,在这个过程中控制台区域的声音进度条也会实时改变;
6.1

先来看手势的添加:

 private void setScrollScreen() {
        mVideoView.setOnTouchListener(new View.OnTouchListener() {




            @Override
            public boolean onTouch(View view, MotionEvent event) {
                float x = event.getX();
                float y = event.getY();
                switch (event.getAction()){
                    case MotionEvent.ACTION_DOWN:
                        lastX = x;
                        lastY = y;
                        break;
                    case MotionEvent.ACTION_MOVE:
                        //获取屏幕宽和高
                        widthPixels = getResources().getDisplayMetrics().widthPixels;
                        heightPixels = getResources().getDisplayMetrics().heightPixels;
                        //偏移量的记录
                        float dx = x - lastX;
                        float dy = y - lastY;
                        float absX = Math.abs(dx);
                        float absY = Math.abs(dy);

                        if (absX > trueshold && absY > trueshold){
                            if (absX >= absY){
                                isadjust = false;
                            }else if (absY > absX){
                                isadjust = true;
                            }
                        }else if (absX >= trueshold && absY < trueshold){
                            isadjust = false;
                        }else if(absX < trueshold && absY >= trueshold){
                            isadjust = true;
                        }

                        //开始判断 音量调节 和 亮度调节
                        if (isadjust){
                            //Log.i("==widthPixels",x + "");
                            if (x > widthPixels/2){
                                //声音
                                if (dy > 0){
                                    //降低声音
                                }else {
                                    //增大声音
                                }
                                //改变声音
                                changeVoice(-dy);

                            }else if(x < widthPixels/2){
                                //亮度
                                if (dy > 0){
                                    //降低亮度
                                    //Log.i("==降低亮度",dy + "");
                                }else {
                                    //增大亮度
                                    //Log.i("==增大亮度",dy + "");
                                }

                                //改变亮度
                                changeBrightness(-dy);
                            }
                        }
                        lastX = x;
                        lastY = y;
                        break;
                    case MotionEvent.ACTION_UP:
                        mDialogLl.setVisibility(View.GONE);
                        break;
                }
                return true;
            }
        });
    }

就是一个onTouch的触摸事件,首先判断手势是否合法,规定一个偏移量,当,当dx dy全部超过偏移量,dy>dx 手势触发 isadjust = true;
当dx<偏移量,dy大于偏移量手势触发 isadjust = true;
触发之后判断 当x > widthPixels/2,在屏幕右半边,触发音量控制
当当x < widthPixels/2,在屏幕左半边,触发屏幕亮度控制

ok~接下来看屏幕亮度变化的代码:


    //控制亮度
    public void changeBrightness(float absY){
        mDialogLl.setVisibility(View.VISIBLE);

        WindowManager.LayoutParams attributes = getWindow().getAttributes();
        mScreenBrightness = attributes.screenBrightness;
        float index = absY / heightPixels;
        mScreenBrightness += index;
        //进行判断
        if (mScreenBrightness > 1.0f){
            mScreenBrightness = 1.0f;
        }else if (mScreenBrightness < 0.01f){
            mScreenBrightness = 0.01f;
        }
        attributes.screenBrightness = mScreenBrightness;
        getWindow().setAttributes(attributes);


        //设置弹窗
        mDialogPic.setImageResource(R.drawable.icon_media_screen);
        mDialogProgress.setMax(10);
        mDialogProgress.setProgress((int)(mScreenBrightness * 10));
        Log.i("==mScreenBrightness",mScreenBrightness * 100 + "");

    }
    声音变化的代码:
//控制声音
    public void changeVoice(float absY){

        mDialogLl.setVisibility(View.VISIBLE);

        int maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        int volume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);

        int dVoice = (int) (absY / heightPixels * maxVolume * 3);
        int max = Math.max(dVoice + volume, 0);
        //设置声音
        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC,max,0);
        mMediaSoundsProgress.setProgress(max);


        //设置弹窗
        mDialogPic.setImageResource(R.drawable.icon_media_sounds);
        mDialogProgress.setMax(maxVolume);
        mDialogProgress.setProgress(max);


    }

这样就实现声音,屏幕亮度和手势的交互;当然不要忘了结束触摸要隐藏dialog窗口:

     case MotionEvent.ACTION_UP:
                        mDialogLl.setVisibility(View.GONE);
                        break;

到此为止,一个横竖屏切换自如,快进快退可实现,手势和声音,屏幕亮度可以实时交互,播放信息实时更新的android播放器就完成,多谢支持,会尽快更新一下视频框架的博文,让我们一起进步

猜你喜欢

转载自blog.csdn.net/soullines/article/details/76595602