Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android播放視頻之VideoView

Android播放視頻之VideoView

編輯:關於Android編程

目前很多app都會有短視頻內容,這裡就來講一下android中播放視頻的幾種方式。

Android播放視頻有三種方式:

1,調用系統已有的播放軟件播放視頻。

2,使用android提供的VideoView控件定制自己的視頻播放器。

3,使用MediaPlayer和SurfaceView定制自己的視頻播放器。

第一種方式最簡單了:

 

 //調用系統自帶的播放器
        Uri uri = Uri.parse("/storage/emulated/0/DCIM/Camera/VID_20161103_105921.mp4");
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(uri, "video/mp4");
        startActivity(intent);

就android4.2.2的源碼來看 ,系統自帶的播放器程序是Gallery2

 

/packages/apps/Gallery2

通過清單文件,可以知道處理該intent的activity:

\

看一下這個MovieActivity.java

 

 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

      。。
        setContentView(R.layout.movie_view);
        View rootView = findViewById(R.id.movie_view_root);

        setSystemUiVisibility(rootView);

        Intent intent = getIntent();
      。。。
        mPlayer = new MoviePlayer(rootView, this, intent.getData(), savedInstanceState,
                !mFinishOnCompletion) {
            @Override
            public void onCompletion() {
                if (mFinishOnCompletion) {
                    finish();
                }
            }
        };

主要用到MoviePlayer,看一下這個MoviePlayer類做了啥

 

 public MoviePlayer(View rootView, final MovieActivity movieActivity,
            Uri videoUri, Bundle savedInstance, boolean canReplay) {
        mContext = movieActivity.getApplicationContext();
        mRootView = rootView;
        mVideoView = (VideoView) rootView.findViewById(R.id.surface_view);
        mBookmarker = new Bookmarker(movieActivity);
        mUri = videoUri;

        mController = new MovieControllerOverlay(mContext);
        ((ViewGroup)rootView).addView(mController.getView());
        mController.setListener(this);
        mController.setCanReplay(canReplay);

        mVideoView.setOnErrorListener(this);
        mVideoView.setOnCompletionListener(this);
        mVideoView.setVideoURI(mUri);
        mVideoView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                mController.show();
                return true;
            }
        });

        // The SurfaceView is transparent before drawing the first frame.
        // This makes the UI flashing when open a video. (black -> old screen
        // -> video) However, we have no way to know the timing of the first
        // frame. So, we hide the VideoView for a while to make sure the
        // video has been drawn on it.
        mVideoView.postDelayed(new Runnable() {
            @Override
            public void run() {
                mVideoView.setVisibility(View.VISIBLE);

這個mVideoView是VideoView類型

 

 


    

所以通過上面代碼可以知道,android自帶的播放器也是使用VideoView這個控件來實現的。

 

那麼接著就講一下第二種方式,使用VideoView定制自己的視頻播放器

VideoView看名字應該是View的子類

\

 

VideoView的直接父類是SurfaceView .關於SurfaceView前面Android視圖SurfaceView的使用一文已做簡單介紹。

SurfaceView可以用來顯示相機的預覽界面,也可以用來顯示視頻的數據。

下面就來看一下如何使用VideoView。

使用VideoView播放視頻也有兩種方式:

一種是只使用VideoView進行播放視頻,自己自定義播放進度,播放狀態的布局,然後自己控制播放

另一種就是VideoView結合MediaController播放視頻,這種方式不需要自己寫布局去控制播放。

下面先看第一方式:

結合代碼和效果圖一起分析下是如何實現播放視頻的:

用手機拍攝了一段視頻,然後用寫的應用程序來播放這段視頻(真機測試的)

\

 

啟動應用看到界面如上:

看一下布局文件:

 


<framelayout android:id="@+id/activity_main" android:layout_height="match_parent" android:layout_width="match_parent" tools:context="cj.com.videoviewdemo2.MainActivity" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">

    
    
    <framelayout android:alpha="0" android:id="@+id/cover" android:layout_height="match_parent" android:layout_width="match_parent"></framelayout>
    
    
        
        
        
    

</framelayout>

MyVideoView是用來播放視頻的,ImageView是用來顯示視頻的縮略圖的(還未開始播放,先顯示縮略圖,覆蓋VideoView那塊區域,因為一開始VideoView那塊區域是黑色的),cover (FrameLayout)是用來控制 CheckBox 和 LinearLayout 隱藏與顯示,CheckBox是控制播放與停止,LinearLayout就是顯示播放進度的布局,兩個TextView分別是顯示當前播放的時間和總時間,SeekBar就是顯示進度,可以拖曳到任意位置播放。

 

下面的代碼片段就是設置視頻預覽圖片

 

 private void initVideoView() {
        Log.d(TAG,"initVideoView ");
        Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(PATH, MINI_KIND);
        if(bitmap != null){
            preview.setImageBitmap(bitmap);
        }
        videoView.setVideoURI(Uri.parse(PATH));
    }
這裡用到了ThumbnailUtils這個工具,參考官方文檔:https://developer.android.com/reference/android/media/ThumbnailUtils.html

 

VideoView播放視頻,需要傳入視頻資源,傳入方式有以下幾種:

\

關於VideoView官方文檔:https://developer.android.com/reference/android/widget/VideoView.html

我這裡播放本地視頻,當然也可以播放網絡視頻。

點擊CheckBox進行播放,看一下播放效果:

\

\

 

看一下代碼:

 

 playOrPause.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Log.d(TAG,"onCheckedChanged  isChecked="+isChecked);
                if(isChecked){//暫停
                    videoView.pause();
                    positon = videoView.getCurrentPosition();

                }else{//播放
                    videoView.seekTo(positon);
                    videoView.start();
                    playOrPause.setVisibility(View.GONE);
                    preview.setVisibility(View.GONE);
                }
            }
        });

播放視頻的話直接調用VideoView 的start()函數即可,seekTo()函數設置從哪個位置開始播放。

 

pasue()暫停播放,getCurrentPosition()獲取播放到哪個位置了 時間毫秒。

看一下控制播放進度消息的代碼:

 

@Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.cover:
                Log.d(TAG,"click cover ");
                int currentPosition = videoView.getCurrentPosition();
                int duration = videoView.getDuration();
                Log.d(TAG,"currentPosition = "+currentPosition+"duration = "+duration);

                if(currentPosition>0){//說明已經播放了,不管現在是暫停還是播放中

                    if(playOrPause.getVisibility() == View.VISIBLE){
                        playOrPause.setVisibility(View.GONE);
                    }else {
                        playOrPause.setVisibility(View.VISIBLE);
                    }
                    if(progressLayout.getVisibility() == View.VISIBLE){
                        myHandler.removeCallbacks(runnable);
                        progressLayout.setVisibility(View.GONE);
                    }else {
                        progressLayout.setVisibility(View.VISIBLE);
                        currentTime.setText((currentPosition/1000)/60%60/10+""+(currentPosition/1000)/60%60%10+":"
                                +(currentPosition/1000)%60/10+""+(currentPosition/1000)%60%10);
                        sumTime.setText((duration/1000)/60%60/10+""+(duration/1000)/60%60%10+":"
                                +(duration/1000)%60/10+""+(duration/1000)%60%10);
                        progressBar.setMax(duration);
                        progressBar.setProgress(currentPosition);

                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                while(progressLayout.getVisibility()==View.VISIBLE){
                                    myHandler.sendEmptyMessage(0);
                                    try {
                                        Thread.sleep(1000);
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }
                                }

                            }
                        }).start();
                        myHandler.postDelayed(runnable,3000);
                    }
                }
                break;
            default:
                break;
        }
    }
    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            playOrPause.setVisibility(View.GONE);
            progressLayout.setVisibility(View.GONE);
        }
    };

下載該demo源碼點擊這裡

 

 

接著看一下VideoView結合MediaController來播放視頻,就簡單幾句代碼就可以了:

 

 

  videoView = (MyVideoView) findViewById(R.id.video_view);
        videoView.setVideoURI(Uri.parse(PATH));
        MediaController mediaController = new MediaController(this);
        videoView.setMediaController(mediaController);
布局文件

<framelayout android:id="@+id/activity_main" android:layout_height="match_parent" android:layout_width="match_parent" tools:context="cj.com.videoviewdemo3.MainActivity" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">

    
</framelayout>
效果圖如下:

 

\

 

可以直接控制視頻的播放了。

這裡來簡單看一下VideoView的源碼。

源碼位置:frameworks/base/core/java/android/widget/VideoView.java

 

public VideoView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
        initVideoView();
    }
private void initVideoView() {
        mVideoWidth = 0;
        mVideoHeight = 0;
        getHolder().addCallback(mSHCallback);
        getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        setFocusable(true);
        setFocusableInTouchMode(true);
        requestFocus();
        mCurrentState = STATE_IDLE;
        mTargetState  = STATE_IDLE;
    }
  public void setVideoURI(Uri uri) {
        setVideoURI(uri, null);
    }
 public void setVideoURI(Uri uri, Map headers) {
        mUri = uri;
        mHeaders = headers;
        mSeekWhenPrepared = 0;
        openVideo();
        requestLayout();
        invalidate();
    }

private void openVideo() {
        if (mUri == null || mSurfaceHolder == null) {
            // not ready for playback just yet, will try again later
            return;
        }
        // Tell the music playback service to pause
        // TODO: these constants need to be published somewhere in the framework.
        Intent i = new Intent("com.android.music.musicservicecommand");
        i.putExtra("command", "pause");
        mContext.sendBroadcast(i);

        // we shouldn't clear the target state, because somebody might have
        // called start() previously
        release(false);
        try {
            mMediaPlayer = new MediaPlayer();
            mMediaPlayer.setOnPreparedListener(mPreparedListener);
            mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
            mMediaPlayer.setOnCompletionListener(mCompletionListener);
            mMediaPlayer.setOnErrorListener(mErrorListener);
            mMediaPlayer.setOnInfoListener(mOnInfoListener);
            mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
            mCurrentBufferPercentage = 0;
            mMediaPlayer.setDataSource(mContext, mUri, mHeaders);
            mMediaPlayer.setDisplay(mSurfaceHolder);
            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mMediaPlayer.setScreenOnWhilePlaying(true);
            mMediaPlayer.prepareAsync();
            // we don't set the target state here either, but preserve the
            // target state that was there before.
            mCurrentState = STATE_PREPARING;
            attachMediaController();
        } catch (IOException ex) {
            Log.w(TAG, "Unable to open content: " + mUri, ex);
            mCurrentState = STATE_ERROR;
            mTargetState = STATE_ERROR;
            mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
            return;
        } catch (IllegalArgumentException ex) {
            Log.w(TAG, "Unable to open content: " + mUri, ex);
            mCurrentState = STATE_ERROR;
            mTargetState = STATE_ERROR;
            mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
            return;
        }
    }

public void start() {
        if (isInPlaybackState()) {
            mMediaPlayer.start();
            mCurrentState = STATE_PLAYING;
        }
        mTargetState = STATE_PLAYING;
    }

通過上面幾個關鍵的函數可以看出,VideoView播放播放視頻是通過SurfaceView(VideoView本身就是SurfaceView)加上MediaPlayer(VideoView封裝該類)這個類來實現的。這也是後面要講的第三種播放視頻的方式------------使用MediaPlayer和SurfaceView定制自己的視頻播放器。

 

看一下MediaController這個類


\

它是一個視圖,VideoView通過setMediaController(MediaControllercontroller)函數添加MediaController其實就是添加一個視圖,該視圖容器裡有控件來控制視頻的播放

 

public void setMediaController(MediaController controller) {
        if (mMediaController != null) {
            mMediaController.hide();
        }
        mMediaController = controller;
        attachMediaController();
    }

    private void attachMediaController() {
        if (mMediaPlayer != null && mMediaController != null) {
            mMediaController.setMediaPlayer(this);
            View anchorView = this.getParent() instanceof View ?
                    (View)this.getParent() : this;
            mMediaController.setAnchorView(anchorView);
            mMediaController.setEnabled(isInPlaybackState());
        }
    }

看一下Mediacontroller的源碼,路徑在frameworks/base/core/java/android/widget/MediaController.java

 

 

 public void setAnchorView(View view) {
        if (mAnchor != null) {
            mAnchor.removeOnLayoutChangeListener(mLayoutChangeListener);
        }
        mAnchor = view;
        if (mAnchor != null) {
            mAnchor.addOnLayoutChangeListener(mLayoutChangeListener);
        }

        FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
        );

        removeAllViews();
        View v = makeControllerView();
        addView(v, frameParams);
    }

    /**
     * Create the view that holds the widgets that control playback.
     * Derived classes can override this to create their own.
     * @return The controller view.
     * @hide This doesn't work as advertised
     */
    protected View makeControllerView() {
        LayoutInflater inflate = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mRoot = inflate.inflate(com.android.internal.R.layout.media_controller, null);

        initControllerView(mRoot);

        return mRoot;
    }

看一下它的布局結構

 

frameworks/base/core/res/res/layout/media_controller.xml

 






    

        
        
        
        
        

    

    

        

        

        
    


上面兩個類的源碼就沒有詳細分析了。

 

關於VideoView播放視頻就講這些了,demo是運行在真機上的。

後面文章講一下使用MediaPlayer和SurfaceView來播放視頻。
 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved