1. 程式人生 > >筆記——android實現VR視訊顯示和優化

筆記——android實現VR視訊顯示和優化

1.谷歌官網提供的VR資源下載
2.因為使用VR的資源很小號記憶體,所以我們為了避免OOM的問題,在清單檔案中新增 android:largeHeap="true",提高警報線。 清單檔案程式碼: <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:largeHeap="true" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> 3..由於低版本要用高版本的東西,在Gradle檔案中新增 compile 'com.google.android.exoplayer:exoplayer:r1.5.10' compile 'com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7' 4.匯入三個庫檔案common,commonwidget,videowidget 目錄為gvr-android-sdk-master\libraries下的三個檔案

再新增到moudle中,Ctrl+Alt+Shift+S,選擇你的moudle,點選右上角加號,匯入需要的三個庫檔案;

5.編譯構造版本太低,2.0後的studio沒辦法匯入此model.
會爆出這個異常,解決的辦法是進入檔案裡,修改build.gradle檔案
6.在佈局檔案中新增VR控制元件和進度條控制元件: 程式碼: <com.google.vr.sdk.widgets.video.VrVideoView android:id="@+id/vr_video" android:layout_width="match_parent" android:layout_height="250dp"> </com.google.vr.sdk.widgets.video.VrVideoView> <android.support.v7.widget.AppCompatSeekBar android:id="@+id/seek_bar" android:layout_width="match_parent" android:layout_height="wrap_content"/> 7.初始化VrPanoramaView控制元件

8.在src資料夾下的main資料夾下建立一個資產檔案assets,存放VR動畫;
9.由於VR資源資料量大,獲取需要時間,故把載入圖片放到子執行緒中進行,主執行緒來顯示圖片,可以使用一個非同步執行緒AsyncTask或EventBus技術完成; 建立一個子執行緒,繼承自AsyncTask<String,Void,Void>,並建立複寫方法,將從本地檔案中把資源和顯示效果載入到記憶體中。 程式碼如下: private class vrLoadTask extends AsyncTask<String,Void,Void>{ @Override protected Void doInBackground(String... params) { //建立 VrVideoView.Options,決定顯示的效果 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物件,決定顯示的效果。 mVr_video.loadVideoFromAsset(params[0],options); } catch (IOException e) { e.printStackTrace(); } return null; } } 10.在OnCreat方法中使用自定義的AsyncTask,播放VR效果

11.優化VR,因為VR很佔用記憶體,所以當介面進入onPause狀態,暫停VR檢視顯示,進入onResume狀態,繼續VR檢視顯示,進入onDestroy狀態,殺死VR,關閉非同步任務。當銷燬Activity時判斷ImagerLoaderTask是否為空,讓不為空的時候再判斷activity非同步任務是否取消。 建立onPause,onResume和onDestroy等方法;(回撥:當觸動某個方法是自動呼叫;) //因為VR很佔用記憶體,所以當介面進入onPanuse狀態,暫停VR檢視顯示,進入OnResume狀態,繼續VR檢視顯示,進入OnDestroy狀態,殺死VR檢視 //當我們失去焦點,回撥 @Override protected void onPause() { //暫停渲染和顯示 mVr_video.pauseRendering(); super.onPause(); } //當我們獲取焦點,回撥 @Override protected void onResume() { //繼續渲染和顯示 mVr_video.resumeRendering(); super.onResume(); } //當我們銷燬焦點,回撥 @Override protected void onDestroy() { //關閉渲染和顯示 mVr_video.shutdown(); if(mVrLoadTask!=null){ if(!mVrLoadTask.isCancelled()){ mVrLoadTask.cancel(true); } } super.onDestroy(); } 12.VR的優化,實現隱藏左下角的資訊按鈕,和對視訊新增播放,暫停和進度條。 (1)//隱藏VR效果左下角資訊按鈕顯示 vrVideoView.setInfoButtonEnabled(false); (2) //切換VR模式 引數:VrVideoView.DisplayMode.FULLSCREEN_STEREO裝置模式(手機橫放) VrVideoView.DisplayMode.FULLSCREEN_MONO手機模式 vrVideoView.setDisplayMode(VrVideoView.DisplayMode.FULLSCREEN_STEREO); (3)//對VR視訊進行事件監聽 vrVideoView.setEventListener(new MyEventListener()); (4)對VR執行狀態監聽類,自定義一個類繼承VrVideoEventListener,複寫裡面需要的方法 ①//當VR視訊載入成功的時候回撥 @Override public void onLoadSuccess() { super.onLoadSuccess(); //獲取視訊長度; long max = vrVideoView.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) vrVideoView.getCurrentPosition(); //設定seekbar的進度條 seek_bar.setProgress(currentPosition); //顯示播放的進度數字 tv_text.setText("播放進度:" + String.format("%.2f", currentPosition / 1000.f) +"/"+ String.format("%.2f", vrVideoView.getDuration() / 1000f)); } ④//當視訊播放結束後的回撥 @Override public void onCompletion() { super.onCompletion(); //讓視訊回到0點 vrVideoView.seekTo(0); //讓視訊停止播放 vrVideoView.pauseVideo(); //讓進度條也設定到0點 seek_bar.setProgress(0); //播放完成後,重新設定標籤,標籤為true,暫停播放 isPaused = true; } ⑤//設定一個視訊播放狀態的標籤 private boolean isPaused = false; ⑥//重寫點選檢視的方法,使視訊被點選時,播放或暫停 @Override public void onClick() { super.onClick(); //根據標籤,判斷當前視訊的狀態,標籤false,播放則暫停,標籤true,暫停則播放 if (isPaused) { vrVideoView.playVideo(); } else { vrVideoView.pauseVideo(); } //對標籤操作一次後要進行取反。 isPaused = !isPaused; }
MainActivity程式碼:
public class MainActivity extends AppCompatActivity {

    private VrVideoView vrVideoView;
    private SeekBar seek_bar;
    private TextView tv_text;
    private VideoLoadTask mVideoLoadTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //A.進行控制元件初始化
        vrVideoView = (VrVideoView) findViewById(R.id.vr_video);
        seek_bar = (SeekBar) findViewById(R.id.seek_bar);
        tv_text = (TextView) findViewById(R.id.tv_text);
        //B.播放VR的效果,只需要執行非同步任務。
        mVideoLoadTask = new VideoLoadTask();
        mVideoLoadTask.execute("congo_2048.mp4");
    //D.  VR的優化,實現隱藏左下角的資訊按鈕,和對視訊新增播放,暫停和進度條。
        //隱藏VR效果左下角資訊按鈕顯示
        vrVideoView.setInfoButtonEnabled(false);
        //切換VR模式 引數:VrVideoView.DisplayMode.FULLSCREEN_STEREO裝置模式(手機橫放)   VrVideoView.DisplayMode.FULLSCREEN_MONO手機模式
        vrVideoView.setDisplayMode(VrVideoView.DisplayMode.FULLSCREEN_STEREO);
        //對VR視訊進行事件監聽
        vrVideoView.setEventListener(new MyEventListener());
    }

    //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.String物件   2.VrVideoView.options物件,決定顯示的效果
                vrVideoView.loadVideoFromAsset(params[0], options);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    //C.因為VR很佔用記憶體,所以當介面進入onPause狀態,暫停VR檢視顯示,進入onResume狀態,繼續VR檢視顯示,進入onDestory狀態,殺死VR,關閉非同步狀態。

    //當我們失去焦點回調
    @Override
    protected void onPause() {
        super.onPause();
        //暫停渲染和顯示
        vrVideoView.pauseRendering();
    }

    //當獲取焦點時回撥
    @Override
    protected void onResume() {
        super.onResume();
        //繼續渲染和顯示
        vrVideoView.resumeRendering();
    }

    //當銷燬焦點時回撥

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //關閉渲染和顯示
        vrVideoView.shutdown();
        //在退出Activity時,如果非同步任務沒有取消,則取消
        if (mVideoLoadTask != null) {
            if (!mVideoLoadTask.isCancelled()) {
                mVideoLoadTask.cancel(true);
            }
        }
    }

    //D.對VR執行狀態監聽類,自定義一個類繼承VrVideoEventListener,複寫裡面需要的方法
    private class MyEventListener extends VrVideoEventListener {
        //當VR視訊載入成功的時候回撥
        @Override
        public void onLoadSuccess() {
            super.onLoadSuccess();
            //獲取視訊長度;
            long max = vrVideoView.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) vrVideoView.getCurrentPosition();
            //設定seekbar的進度條
            seek_bar.setProgress(currentPosition);
            //顯示播放的進度數字
            tv_text.setText("播放進度:" + String.format("%.2f", currentPosition / 1000.f) +"/"+ String.format("%.2f", vrVideoView.getDuration() / 1000f));
        }
        //當視訊播放結束後的回撥

        @Override
        public void onCompletion() {
            super.onCompletion();
            //讓視訊回到0點
            vrVideoView.seekTo(0);
            //讓視訊停止播放
            vrVideoView.pauseVideo();
            //讓進度條也設定到0點
            seek_bar.setProgress(0);
            //播放完成後,重新設定標籤,標籤為true,暫停播放
            isPaused = true;
        }

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

        //重寫點選檢視的方法,使視訊被點選時,播放或暫停
        @Override
        public void onClick() {
            super.onClick();
            //根據標籤,判斷當前視訊的狀態,標籤false,播放則暫停,標籤true,暫停則播放
            if (isPaused) {
                vrVideoView.playVideo();
            } else {
                vrVideoView.pauseVideo();
            }
            //對標籤操作一次後要進行取反。
            isPaused = !isPaused;
        }
    }
}