1. 程式人生 > >通過Android實現VR視訊的播放

通過Android實現VR視訊的播放

實現VR視訊的播放和前面寫過的VR全景圖的展示差不多,改變的也只是庫檔案的不同,資源目錄下的資源不同而已。下面就來說一下步驟。

先展示一下效果圖這裡寫圖片描述
完成步驟:
1.以匯入Moudle的方式匯入庫檔案。(videowidget,common,commonwidget)資源獲取連結:https://github.com/googlevr/gvr-android-sdk/
2.在main下新建資產目錄asstes,放入視訊資源
3.在清單檔案application中提高警報許可權android:largeHeap=”true”
4.在Moudlede的 build.grable檔案裡dependencies中新增
compile ‘com.google.android.exoplayer:exoplayer:r1.5.10’
compile ‘com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7’
5.關聯匯入的依賴庫
6完成xml中的佈局,video.VrVideoView,AppCompatSeekBar,TextView
7.使用非同步任務AsyncTask,(或EventBus技術)載入視訊
8.利用執行緒進行VR優化。
9.設定VR的監聽效果

具體方法:
1.以匯入Moudle的方式匯入庫檔案
這裡寫圖片描述

2.新增資產目錄。在main新建asstes目錄,將VR資源放入
這裡寫圖片描述
3在清單檔案下的application新增 android:largeHeap=”true”的屬下節點
這裡寫圖片描述

4.在Module的build.gradle檔案裡dependencie中加入
compile ‘com.google.android.exoplayer:exoplayer:r1.5.10’
compile ‘com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7’
獲取方式:在你下載的VR資原始檔路徑下(xxxx\gvr-android-sdk-master\samples\sdk-simplevideowidget)build.gradle檔案中拷取。
這裡寫圖片描述

5.關聯你的庫檔案:ctrl+alt+shift+s在開啟的對話方塊中,選擇你原本的專案Moudle,選擇Dependencise,點選右上角”+”,選擇第三個Module dependency,在開啟的對話方塊中,選擇之前匯入的庫檔案。
這裡寫圖片描述

6.xml中的程式碼:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.zhiyuan3g.vrvideo.MainActivity"> <com.google.vr.sdk.widgets.video.VrVideoView android:layout_width="match_parent" android:layout_height="250dp" android:id="@+id/vr_video"> </com.google.vr.sdk.widgets.video.VrVideoView> <android.support.v7.widget.AppCompatSeekBar android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/seek_bar"/> <TextView android:id="@+id/tv_progress" android:textSize="20dp" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout>

7、8,9步中所有的程式碼都在這了
MainActivity中的程式碼:

這裡寫程式碼片import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import com.google.vr.sdk.widgets.common.VrWidgetView;
import com.google.vr.sdk.widgets.video.VrVideoEventListener;
import com.google.vr.sdk.widgets.video.VrVideoView;

import java.io.IOException;

public class MainActivity extends AppCompatActivity {

    private VrVideoView vr_video;
    private SeekBar seek_bar;// 進度條
    private TextView tv_progress;
    private VideoLoadTask mVideoLoadTask;// 非同步任務

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // A初始化控制元件
        vr_video = (VrVideoView) findViewById(R.id.vr_video);
        seek_bar = (SeekBar) findViewById(R.id.seek_bar);
        tv_progress = (TextView) findViewById(R.id.tv_progress);

        // 隱藏VR效果左下角資訊按鈕顯示
        vr_video.setInfoButtonEnabled(false);
        // 切換VR模式 引數:VrVideoView.DisplayMode.FULLSCREEN_STEREO:裝置模式(手機橫著放試試)
        //                 VrVideoView.DisplayMode..FULLSCREEN_MONO手機模式
        vr_video.setDisplayMode(VrVideoView.DisplayMode.FULLSCREEN_STEREO);

        //  對VR視訊進行事件監聽
        vr_video.setEventListener(new MyEventListener() );

        // 播放VR效果,只需要執行非同步任務即可
        mVideoLoadTask = new VideoLoadTask();
        mVideoLoadTask.execute("congo_2048.mp4");
    }

    // B 由於VR資源資料量很大,獲取需要時間,故把載入視訊放到子執行緒中進行,主執行緒來顯示,可以使用非同步任務AsyncTask,或EventBus技術

    // 自定義一個類繼承AsyncTask,只使用我們需要的方法,完成在子執行緒載入視訊資源,在主執行緒顯示
    private class  VideoLoadTask extends AsyncTask<String,Void,Void>{
        // B該方法在子執行緒執行,從本地檔案中把資源載入到記憶體中
        @Override
        protected Void doInBackground(String... params) {

            // 建立VrVideoView.Options物件,決定VR是普通的效果,還是立體效果
            VrVideoView.Options options = new VrVideoView.Options();
            // 立體模式
            options.inputType = VrVideoView.Options.TYPE_STEREO_OVER_UNDER;
            // 處理載入的視訊格式
            // FORMAT_DEFAULT:預設格式(SD卡或assets)
            // FORMAT_HLS:流媒體資料格式(直播)
            options.inputFormat = VrVideoView.Options.FORMAT_DEFAULT;

            try {
                //提示:視訊載入的方法還做了把視訊讀取到記憶體中的操作,所以它會有一個矛盾,呼叫該方法是在主執行緒還是在子執行緒(一般我們放在子執行緒去呼叫該方法)
                // 使用VR控制元件物件,從資產目錄載入視訊資料,顯示效果, 引數1。params物件,2.VrVideoView.Options物件,決定顯示的效果
                vr_video.loadVideoFromAsset(params[0],options);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

    }
    // C因為VR很佔用記憶體,所以當介面進入OnPause狀態,暫停VR檢視顯示,
    // 進入OnResume狀態,繼續VR檢視顯示,進入OnDestroy狀態,殺死VR
    // 當我們失去焦點,回撥
    @Override
    protected void onPause() {
        super.onPause();
        // 暫停渲染和顯示
        vr_video.pauseRendering();
    }

    // 當獲取焦點時,回撥

    @Override
    protected void onResume() {
        super.onResume();
        vr_video.resumeRendering();

    }
    // 當Activity銷燬時,回撥

    @Override
    protected void onDestroy() {
        super.onDestroy();

        vr_video.shutdown();
        // 在退出Activity時,如果非同步任務沒有取消,則取消
        if (mVideoLoadTask!=null){
            if (!mVideoLoadTask.isCancelled()){
                mVideoLoadTask.cancel(true);
            }
        }
    }
    // 對VR執行狀態監聽類,自定義一個類,繼承VrVideoEventListener,複寫裡面需要的方法
    private class MyEventListener extends VrVideoEventListener{

        // 當VR視訊載入成功的時候回撥  什麼是回撥:當你的程式到達符合某個條件時,
        // 自動呼叫某段程式碼或執行某個方法
        @Override
        public void onLoadSuccess() {
            super.onLoadSuccess();
            // 獲取視訊長度
            long max = vr_video.getDuration();
            // 設定seekbar的進度最大值
            seek_bar.setMax((int)max);
        }

        // 當VR檢視載入失敗的時候 回撥
        @Override
        public void onLoadError(String errorMessage) {
            super.onLoadError(errorMessage);
            Toast.makeText(MainActivity.this, "播放失敗", Toast.LENGTH_SHORT).show();
        }

        // 當視訊開始播放,每次進入下一幀的時候,回撥這個方法(就是播放時,會不停的回撥該方法)
        @Override
        public void onNewFrame() {
            super.onNewFrame();
            // 獲取當前視訊的播放時間位置
            int currentPosition = (int) vr_video.getCurrentPosition();
            // 設定seekVar的進度條
            seek_bar.setProgress(currentPosition);
            // 顯示播放的進度數字
            tv_progress.setText("播放進度:"+String.format("%.2f",currentPosition/1000.f)+String.format("%.2f",vr_video.getDuration()/1000f));
        }

        // 當視訊播放結束後的回到方法
        @Override
        public void onCompletion() {
            super.onCompletion();
            // 讓視訊回到0點
            vr_video.seekTo(0);
            // 讓視訊停止
            vr_video.pauseVideo();
            // 同時讓進度條回到0點
            seek_bar.setProgress(0);

            // 播放完成後,重新設定標籤true,暫停播放
            isPaused = true;
        }

        // 設定一個視訊播放狀態的標籤
        private boolean isPaused = false;

        // 重寫點選檢視的方法,使視訊被點選時播放或者暫停
        @Override
        public void onClick() {
            super.onClick();
            Log.d("jzs","點選");

            // 根據標籤判斷當前視訊的狀態,標籤false,播放則暫停,標籤true,暫停播放
            // true代表視訊正處於暫停狀態
            if (isPaused){
                // 視訊播放
                vr_video.playVideo();
            }else{// false代表視訊正在播放的狀態
                vr_video.pauseVideo();
            }
            // 對標籤操做一次後,進行取反
            isPaused = !isPaused;
        }
    }
}

共勉!!!!!