话不多说,先上图(眼睛模式)

参考的开源库——传送门 MD360Player4Android
在开源库的基础上,做了菜单和播放器逻辑。
VR功能的部分通过依赖vrlib来实现,视频播放的部分集成ijkPlayer


这里对MD360Player4Android中的一些代码做解释。
初始化VR播放器

    @Overrideprotected MDVRLibrary createVRLibrary() {return MDVRLibrary.with(this).displayMode(MDVRLibrary.DISPLAY_MODE_NORMAL) //默认360度全景.interactiveMode(MDVRLibrary.INTERACTIVE_MODE_MOTION_WITH_TOUCH)//触摸和重力.asVideo(new MDVRLibrary.IOnSurfaceReadyCallback() {@Overridepublic void onSurfaceReady(Surface surface) {mMediaPlayerWrapper.setSurface(surface);}}).ifNotSupport(new MDVRLibrary.INotSupportCallback() {@Overridepublic void onNotSupport(int mode) {String tip = mode == MDVRLibrary.INTERACTIVE_MODE_MOTION? "onNotSupport:MOTION" : "onNotSupport:" + String.valueOf(mode);Toast.makeText(VrPlayerActivity.this, tip, Toast.LENGTH_SHORT).show();}}).pinchConfig(new MDPinchConfig().setMin(1.0f).setMax(8.0f).setDefaultValue(0.1f)).pinchEnabled(true).directorFactory(new MD360DirectorFactory() {@Overridepublic MD360Director createDirector(int index) {return MD360Director.builder().setPitch(90).build();}}).projectionFactory(new CustomProjectionFactory()).listenGesture(new MDVRLibrary.IGestureListener() {@Overridepublic void onClick(MotionEvent e) {touchRl.setVisibility(View.VISIBLE);if(mMediaPlayerWrapper.getPlayer().isPlaying()){img_start_vr.setVisibility(View.GONE);img_stop_vr.setVisibility(View.VISIBLE);}else {img_start_vr.setVisibility(View.VISIBLE);img_stop_vr.setVisibility(View.GONE);}mHandler.sendEmptyMessage(MESSAGE_SHOW_PROGRESS);hasMenuAction();verticalSeekBar.setProgress(audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) * 100 / mMaxVolume);}}).barrelDistortionConfig(new BarrelDistortionConfig().setDefaultEnabled(false).setScale(0.95f)).build(findViewById(R.id.gl_view));}

主要的设置有displayMode——眼睛模式和全景模式,interactiveMode——这个字面上理解是交互模式,可以设置重力感应,触摸,或者禁止重力感应,禁止触摸等。
其实在M360PlayerActivity中,各种设置选项已经陈列出来了

public abstract class M360PlayerActivity extends AppCompatActivity {private static final SparseArray<String> sDisplayMode = new SparseArray<>();private static final SparseArray<String> sInteractiveMode = new SparseArray<>();private static final SparseArray<String> sProjectionMode = new SparseArray<>();private static final SparseArray<String> sAntiDistortion = new SparseArray<>();private static final SparseArray<String> sPitchFilter = new SparseArray<>();private static final SparseArray<String> sFlingEnabled = new SparseArray<>();static {sDisplayMode.put(MDVRLibrary.DISPLAY_MODE_NORMAL,"NORMAL");sDisplayMode.put(MDVRLibrary.DISPLAY_MODE_GLASS,"GLASS");sInteractiveMode.put(MDVRLibrary.INTERACTIVE_MODE_MOTION,"MOTION");sInteractiveMode.put(MDVRLibrary.INTERACTIVE_MODE_TOUCH,"TOUCH");sInteractiveMode.put(MDVRLibrary.INTERACTIVE_MODE_MOTION_WITH_TOUCH,"M & T");sInteractiveMode.put(MDVRLibrary.INTERACTIVE_MODE_CARDBORAD_MOTION,"CARDBOARD M");sInteractiveMode.put(MDVRLibrary.INTERACTIVE_MODE_CARDBORAD_MOTION_WITH_TOUCH,"CARDBOARD M&T");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_SPHERE,"SPHERE");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_DOME180,"DOME 180");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_DOME230,"DOME 230");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_DOME180_UPPER,"DOME 180 UPPER");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_DOME230_UPPER,"DOME 230 UPPER");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_STEREO_SPHERE_HORIZONTAL,"STEREO H SPHERE");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_STEREO_SPHERE_VERTICAL,"STEREO V SPHERE");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_PLANE_FIT,"PLANE FIT");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_PLANE_CROP,"PLANE CROP");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_PLANE_FULL,"PLANE FULL");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_MULTI_FISH_EYE_HORIZONTAL,"MULTI FISH EYE HORIZONTAL");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_MULTI_FISH_EYE_VERTICAL,"MULTI FISH EYE VERTICAL");sAntiDistortion.put(1,"ANTI-ENABLE");sAntiDistortion.put(0,"ANTI-DISABLE");sPitchFilter.put(1,"FILTER PITCH");sPitchFilter.put(0,"FILTER NOP");sFlingEnabled.put(1, "FLING ENABLED");sFlingEnabled.put(0, "FLING DISABLED");}
}

在onSurfaceReady(Surface surface)的回调中,调用了 mMediaPlayerWrapper.setSurface(surface); 这里的MediaPlayerWrapper是一个封住了ijkPlayer的播放器。这里可以理解成在VR功能接入完毕后,又把视频的处理交还给了ijkPlayer。而ijkPlayer的使用,跟VR功能就没关系了。(理解有点生硬,完全是看单词翻译的有木有- -!)
项目实现大概就是这样,形容确切一点,就是一个具有VR功能的ijjPlayer
页面布局activity_md_using_surface_view.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:layout_width="match_parent"android:layout_height="match_parent"><FrameLayout
       android:id="@+id/framelayout_gl"android:orientation="horizontal"android:layout_width="match_parent"android:layout_height="match_parent"><android.opengl.GLSurfaceView
          android:id="@+id/gl_view"android:layout_width="match_parent"android:layout_height="match_parent" /></FrameLayout><!--视频菜单--><include layout="@layout/include_menu"/><ProgressBar
       android:layout_centerInParent="true"android:id="@+id/progress"android:layout_width="wrap_content"android:layout_height="wrap_content" /></RelativeLayout>

菜单布局include_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/rl_touch_menu"android:background="#33000000"android:layout_width="match_parent"android:layout_height="match_parent"android:visibility="gone"><LinearLayout
        android:layout_width="wrap_content"android:layout_height="44dp"android:orientation="horizontal"android:gravity="center_vertical"><ImageView
            android:id="@+id/img_back"android:layout_marginLeft="15dp"android:src="@drawable/back_normal"android:layout_width="wrap_content"android:layout_height="wrap_content" /><TextView
            android:layout_marginLeft="26dp"android:gravity="center_vertical"android:id="@+id/tv_vr_title"android:textSize="16sp"android:text="视频名字哦"android:textColor="#ffffff"android:layout_width="wrap_content"android:layout_height="match_parent" /></LinearLayout><LinearLayout
        android:layout_marginTop="13dp"android:layout_alignParentRight="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"android:gravity="center_vertical"android:layout_marginRight="18dp"><Button
            android:id="@+id/btn_vr_nor"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="360°全景" /><Button
            android:id="@+id/btn_vr_glass"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="眼睛模式" /></LinearLayout><LinearLayout
        android:layout_centerVertical="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"android:gravity="center_horizontal"><RelativeLayout
            android:id="@+id/rl_voice_add"android:padding="7dp"android:layout_width="wrap_content"android:layout_height="wrap_content"><TextView
                android:textColor="@color/white"android:text="音量+"android:layout_width="wrap_content"android:layout_height="wrap_content" /></RelativeLayout><com.vrplayerdemo.view.VerticalSeekBar
            android:layout_marginTop="15dp"android:id="@+id/seekbar_voice"android:layout_width="100dp"android:layout_height="160dp" /><RelativeLayout
            android:layout_marginTop="15dp"android:id="@+id/rl_voice_sub"android:padding="7dp"android:layout_width="wrap_content"android:layout_height="wrap_content"><TextView
                android:textColor="@color/white"android:text="音量-"android:layout_width="wrap_content"android:layout_height="wrap_content" /></RelativeLayout></LinearLayout><ImageView
        android:clickable="true"android:layout_marginRight="45dp"android:layout_centerVertical="true"android:layout_alignParentRight="true"android:id="@+id/img_next_video"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/vr_next_nor"/><ImageView
        android:id="@+id/img_stop_vr"android:src="@drawable/btn_vr_stop"android:layout_centerInParent="true"android:layout_width="wrap_content"android:layout_height="wrap_content" /><ImageView
        android:id="@+id/img_start_vr"android:src="@drawable/btn_vr_start_nor"android:layout_centerInParent="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:visibility="gone"/><LinearLayout
        android:layout_marginLeft="28dp"android:layout_marginRight="28dp"android:layout_marginBottom="17dp"android:layout_alignParentBottom="true"android:layout_width="match_parent"android:layout_height="wrap_content"><TextView
            android:id="@+id/tv_current_play_time"android:text="00:00"android:textColor="#FFFFFF"android:textSize="14sp"android:layout_width="wrap_content"android:layout_height="wrap_content" /><SeekBar
            style="@style/SeekBarAppTheme"android:layout_marginLeft="15dp"android:layout_marginRight="15dp"android:id="@+id/seekbar_play_video"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="1"/><TextView
            android:id="@+id/tv_end_play_time"android:text="12:05"android:textColor="#FFFFFF"android:textSize="14sp"android:layout_width="wrap_content"android:layout_height="wrap_content" /></LinearLayout></RelativeLayout>

M360PlayerActivity代码

package com.vrplayerdemo.view;import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.SparseArray;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;import com.asha.vrlib.MDDirectorCamUpdate;
import com.asha.vrlib.MDVRLibrary;
import com.asha.vrlib.plugins.hotspot.IMDHotspot;
import com.asha.vrlib.texture.MD360BitmapTexture;
import com.vrplayerdemo.R;
import com.vrplayerdemo.VrPlayerActivity;
import com.vrplayerdemo.model.VideoModel;import java.io.FileNotFoundException;/*** using MD360Renderer** Created by hzqiujiadi on 16/1/22.* hzqiujiadi ashqalcn@gmail.com*/
public abstract class M360PlayerActivity extends AppCompatActivity {private static final SparseArray<String> sDisplayMode = new SparseArray<>();private static final SparseArray<String> sInteractiveMode = new SparseArray<>();private static final SparseArray<String> sProjectionMode = new SparseArray<>();private static final SparseArray<String> sAntiDistortion = new SparseArray<>();private static final SparseArray<String> sPitchFilter = new SparseArray<>();private static final SparseArray<String> sFlingEnabled = new SparseArray<>();static {sDisplayMode.put(MDVRLibrary.DISPLAY_MODE_NORMAL,"NORMAL");sDisplayMode.put(MDVRLibrary.DISPLAY_MODE_GLASS,"GLASS");sInteractiveMode.put(MDVRLibrary.INTERACTIVE_MODE_MOTION,"MOTION");sInteractiveMode.put(MDVRLibrary.INTERACTIVE_MODE_TOUCH,"TOUCH");sInteractiveMode.put(MDVRLibrary.INTERACTIVE_MODE_MOTION_WITH_TOUCH,"M & T");sInteractiveMode.put(MDVRLibrary.INTERACTIVE_MODE_CARDBORAD_MOTION,"CARDBOARD M");sInteractiveMode.put(MDVRLibrary.INTERACTIVE_MODE_CARDBORAD_MOTION_WITH_TOUCH,"CARDBOARD M&T");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_SPHERE,"SPHERE");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_DOME180,"DOME 180");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_DOME230,"DOME 230");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_DOME180_UPPER,"DOME 180 UPPER");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_DOME230_UPPER,"DOME 230 UPPER");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_STEREO_SPHERE_HORIZONTAL,"STEREO H SPHERE");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_STEREO_SPHERE_VERTICAL,"STEREO V SPHERE");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_PLANE_FIT,"PLANE FIT");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_PLANE_CROP,"PLANE CROP");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_PLANE_FULL,"PLANE FULL");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_MULTI_FISH_EYE_HORIZONTAL,"MULTI FISH EYE HORIZONTAL");sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_MULTI_FISH_EYE_VERTICAL,"MULTI FISH EYE VERTICAL");sAntiDistortion.put(1,"ANTI-ENABLE");sAntiDistortion.put(0,"ANTI-DISABLE");sPitchFilter.put(1,"FILTER PITCH");sPitchFilter.put(0,"FILTER NOP");sFlingEnabled.put(1, "FLING ENABLED");sFlingEnabled.put(0, "FLING DISABLED");}//    public static void startVideo(Context context, Uri uri){//        start(context, uri,VideoPlayerActivity.class);
//    }// uri在userAlbumModel里,不是本地数据,不需要Uri格式public static void startVideo(Context context, VideoModel videoModel, int playType){start(context,videoModel,playType, VrPlayerActivity.class);}
//    public static void startBitmap(Context context, Uri uri){//        start(context, uri, BitmapPlayerActivity.class);
//    }private static void start(Context context,VideoModel videoModel,int playType,Class<? extends Activity> clz){Intent i = new Intent(context,clz);
//        i.setData(uri);i.putExtra("videoModel",videoModel);i.putExtra("playType",playType);context.startActivity(i);}private MDVRLibrary mVRLibrary;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// no titlerequestWindowFeature(Window.FEATURE_NO_TITLE);// full screengetWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);// set content viewsetContentView(R.layout.activity_md_using_surface_view);// init VR LibrarymVRLibrary = createVRLibrary();final Activity activity = this;getVRLibrary().setEyePickChangedListener(new MDVRLibrary.IEyePickListener() {@Overridepublic void onHotspotHit(IMDHotspot hotspot, long hitTimestamp) {if (System.currentTimeMillis() - hitTimestamp > 5000){getVRLibrary().resetEyePick();}}});}private ValueAnimator animator;private void startCameraAnimation(final MDDirectorCamUpdate cameraUpdate, PropertyValuesHolder... values){if (animator != null){animator.cancel();}animator = ValueAnimator.ofPropertyValuesHolder(values).setDuration(2000);animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float near = (float) animation.getAnimatedValue("near");float eyeZ = (float) animation.getAnimatedValue("eyeZ");float pitch = (float) animation.getAnimatedValue("pitch");float yaw = (float) animation.getAnimatedValue("yaw");float roll = (float) animation.getAnimatedValue("roll");cameraUpdate.setEyeZ(eyeZ).setNearScale(near).setPitch(pitch).setYaw(yaw).setRoll(roll);}});animator.start();}abstract protected MDVRLibrary createVRLibrary();public MDVRLibrary getVRLibrary() {return mVRLibrary;}@Overrideprotected void onResume() {super.onResume();mVRLibrary.onResume(this);}@Overrideprotected void onPause() {super.onPause();mVRLibrary.onPause(this);}@Overrideprotected void onDestroy() {super.onDestroy();mVRLibrary.onDestroy();}@Overridepublic void onConfigurationChanged(Configuration newConfig) {super.onConfigurationChanged(newConfig);mVRLibrary.onOrientationChanged(this);}protected Uri getUri() {Intent i = getIntent();if (i == null || i.getData() == null){return null;}return i.getData();}public void cancelBusy(){findViewById(R.id.progress).setVisibility(View.GONE);}public void busy(){findViewById(R.id.progress).setVisibility(View.VISIBLE);}// android implprivate class AndroidProvider implements MDVRLibrary.IImageLoadProvider {Activity activity;public AndroidProvider(Activity activity) {this.activity = activity;}@Overridepublic void onProvideBitmap(Uri uri, MD360BitmapTexture.Callback callback) {try {Bitmap bitmap = BitmapFactory.decodeStream(activity.getContentResolver().openInputStream(uri));callback.texture(bitmap);} catch (FileNotFoundException e) {e.printStackTrace();}}}
}

最后就是我们页面的主要逻辑,也是区别于MD360Player4Android,自己做的页面逻辑,让demo更像实际开发的项目。这里页面风格主要仿照尤果圈。

package com.vrplayerdemo;import android.content.Context;
import android.graphics.Color;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;import com.asha.vrlib.MD360Director;
import com.asha.vrlib.MD360DirectorFactory;
import com.asha.vrlib.MDVRLibrary;
import com.asha.vrlib.model.BarrelDistortionConfig;
import com.asha.vrlib.model.MDPinchConfig;
import com.vrplayerdemo.model.VideoModel;
import com.vrplayerdemo.view.CustomProjectionFactory;
import com.vrplayerdemo.view.M360PlayerActivity;
import com.vrplayerdemo.view.MediaPlayerWrapper;
import com.vrplayerdemo.view.VerticalSeekBar;import tv.danmaku.ijk.media.player.IMediaPlayer;public class VrPlayerActivity extends M360PlayerActivity implements View.OnClickListener{/*** 是否在拖动进度条中,默认为停止拖动,true为在拖动中,false为停止拖动*/private boolean isDragging;/*** 播放缓冲监听*/private int mCurrentBufferPercentage=0;/*** 同步进度*/private static final int MESSAGE_SHOW_PROGRESS = 1;/*** 5秒菜单操作,隐藏菜单面板*/private static final int MESSAGE_TOUCH_MENU = 3;/*** 开启倒计时*/private static final int MESSAGE_START_COUNTDOWN = 4;/*** 重新播放*/private static final int MESSAGE_PLAY_NEXT = 5;private MediaPlayerWrapper mMediaPlayerWrapper = new MediaPlayerWrapper();//显示菜单的全屏区域private RelativeLayout touchRl;//音量的seekbarprivate VerticalSeekBar verticalSeekBar;private RelativeLayout addVoice;private RelativeLayout subVoice;private Button btn_vr_nor;//全景模式private Button btn_vr_glass; //眼镜模式private ImageView img_stop_vr; //停止vr按钮private ImageView img_start_vr;//继续vr按钮private TextView endTimeTv; //总时长private TextView currentTimeTv; //当前时长private SeekBar playSeekbar; //视频播放进度private TextView titleTv;  //视频标题private ImageView img_back; //返回键private ImageView img_next_video; //下一部视频//当前声音大小private int volume;//设备最大音量private int mMaxVolume;//音频管理器private AudioManager audioManager;/*** 播放总时长*/private VideoModel videoModel;private int playType=MDVRLibrary.DISPLAY_MODE_NORMAL;private boolean isFirstGlass;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);videoModel= (VideoModel) getIntent().getSerializableExtra("videoModel");playType =getIntent().getIntExtra("playType",MDVRLibrary.DISPLAY_MODE_NORMAL);initView();//初始化页面动画touchRl.setVisibility(View.VISIBLE);initMediaPlayer();mHandler.sendEmptyMessage(MESSAGE_SHOW_PROGRESS);}//初始化播放器private void initMediaPlayer() {mMediaPlayerWrapper.init();mMediaPlayerWrapper.setPreparedListener(new IMediaPlayer.OnPreparedListener() {@Overridepublic void onPrepared(IMediaPlayer mp) {cancelBusy();if (getVRLibrary() != null){getVRLibrary().notifyPlayerChanged();}if(isFirstGlass){isFirstGlass=false;mMediaPlayerWrapper.pause();}}});mMediaPlayerWrapper.getPlayer().setOnErrorListener(new IMediaPlayer.OnErrorListener() {@Overridepublic boolean onError(IMediaPlayer mp, int what, int extra) {String error = String.format("Play Error what=%d extra=%d",what,extra);Toast.makeText(VrPlayerActivity.this, error, Toast.LENGTH_SHORT).show();return true;}});mMediaPlayerWrapper.getPlayer().setOnVideoSizeChangedListener(new IMediaPlayer.OnVideoSizeChangedListener() {@Overridepublic void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sar_num, int sar_den) {getVRLibrary().onTextureResize(width, height);}});if(videoModel.getVideoUrl()!=null){mMediaPlayerWrapper.openRemoteFile(videoModel.getVideoUrl());mMediaPlayerWrapper.prepare();}mMediaPlayerWrapper.getPlayer().setOnBufferingUpdateListener(new IMediaPlayer.OnBufferingUpdateListener() {@Overridepublic void onBufferingUpdate(IMediaPlayer iMediaPlayer, int percent) {mCurrentBufferPercentage = percent;}});mMediaPlayerWrapper.getPlayer().setOnCompletionListener(new IMediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(IMediaPlayer iMediaPlayer) {mHandler.sendEmptyMessage(MESSAGE_START_COUNTDOWN);}});}//初始化页面菜单功能private void initView() {img_back= (ImageView) findViewById(R.id.img_back);img_back.setOnClickListener(this);touchRl= (RelativeLayout) findViewById(R.id.rl_touch_menu);touchRl.setOnClickListener(this);verticalSeekBar= (VerticalSeekBar) findViewById(R.id.seekbar_voice);addVoice= (RelativeLayout) findViewById(R.id.rl_voice_add);subVoice= (RelativeLayout) findViewById(R.id.rl_voice_sub);addVoice.setOnClickListener(this);subVoice.setOnClickListener(this);//不要显示进度球verticalSeekBar.setThumbSize(1,1);verticalSeekBar.setUnSelectColor(Color.parseColor("#ff707070"));verticalSeekBar.setSelectColor(Color.parseColor("#ffffffff"));//单位pxverticalSeekBar.setmInnerProgressWidth(3);verticalSeekBar.setOnSlideChangeListener(slideChangeListener);titleTv= (TextView) findViewById(R.id.tv_vr_title);titleTv.setText(videoModel.getName());btn_vr_nor= (Button) findViewById(R.id.btn_vr_nor);btn_vr_glass= (Button) findViewById(R.id.btn_vr_glass);btn_vr_nor.setOnClickListener(this);btn_vr_glass.setOnClickListener(this);img_stop_vr= (ImageView) findViewById(R.id.img_stop_vr);img_start_vr= (ImageView) findViewById(R.id.img_start_vr);img_stop_vr.setOnClickListener(this);img_start_vr.setOnClickListener(this);endTimeTv = (TextView) findViewById(R.id.tv_end_play_time);currentTimeTv = (TextView) findViewById(R.id.tv_current_play_time);img_next_video= (ImageView) findViewById(R.id.img_next_video);img_next_video.setOnClickListener(this);audioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);mMaxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);verticalSeekBar.setProgress(audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) * 100 / mMaxVolume);playSeekbar= (SeekBar) findViewById(R.id.seekbar_play_video);playSeekbar.setMax(1000);playSeekbar.setOnSeekBarChangeListener(mSeekListener);if(playType==MDVRLibrary.DISPLAY_MODE_GLASS){//因为默认是360全景,所有只有当playType为眼镜模式时,才需要改变默认.在M360PlayerActivity中,createVRLibrary带不过参数,所有是先设置全景,再改变changeToglass();}}@Overrideprotected MDVRLibrary createVRLibrary() {return MDVRLibrary.with(this).displayMode(MDVRLibrary.DISPLAY_MODE_NORMAL) //默认360度全景.interactiveMode(MDVRLibrary.INTERACTIVE_MODE_MOTION_WITH_TOUCH)//触摸和重力.asVideo(new MDVRLibrary.IOnSurfaceReadyCallback() {@Overridepublic void onSurfaceReady(Surface surface) {mMediaPlayerWrapper.setSurface(surface);}}).ifNotSupport(new MDVRLibrary.INotSupportCallback() {@Overridepublic void onNotSupport(int mode) {String tip = mode == MDVRLibrary.INTERACTIVE_MODE_MOTION? "onNotSupport:MOTION" : "onNotSupport:" + String.valueOf(mode);Toast.makeText(VrPlayerActivity.this, tip, Toast.LENGTH_SHORT).show();}}).pinchConfig(new MDPinchConfig().setMin(1.0f).setMax(8.0f).setDefaultValue(0.1f)).pinchEnabled(true).directorFactory(new MD360DirectorFactory() {@Overridepublic MD360Director createDirector(int index) {return MD360Director.builder().setPitch(90).build();}}).projectionFactory(new CustomProjectionFactory()).listenGesture(new MDVRLibrary.IGestureListener() {@Overridepublic void onClick(MotionEvent e) {touchRl.setVisibility(View.VISIBLE);if(mMediaPlayerWrapper.getPlayer().isPlaying()){img_start_vr.setVisibility(View.GONE);img_stop_vr.setVisibility(View.VISIBLE);}else {img_start_vr.setVisibility(View.VISIBLE);img_stop_vr.setVisibility(View.GONE);}mHandler.sendEmptyMessage(MESSAGE_SHOW_PROGRESS);hasMenuAction();verticalSeekBar.setProgress(audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) * 100 / mMaxVolume);}}).barrelDistortionConfig(new BarrelDistortionConfig().setDefaultEnabled(false).setScale(0.95f)).build(findViewById(R.id.gl_view));}@Overrideprotected void onDestroy() {super.onDestroy();mHandler.removeMessages(MESSAGE_SHOW_PROGRESS);mMediaPlayerWrapper.destroy();}@Overrideprotected void onPause() {super.onPause();mMediaPlayerWrapper.pause();}@Overrideprotected void onResume() {super.onResume();
//        mMediaPlayerWrapper.resume();}int curProgress;@Overridepublic void onClick(View v) {switch (v.getId()){case R.id.rl_touch_menu://点击菜单无点击事件的区域,菜单消失touchRl.setVisibility(View.GONE);mHandler.removeMessages(MESSAGE_TOUCH_MENU);break;case R.id.rl_voice_add://增加音量curProgress=verticalSeekBar.getProgress();Log.d("vrdemo","音量增加="+verticalSeekBar.getProgress());if(curProgress<100){curProgress=curProgress+5;verticalSeekBar.setProgress(curProgress);}volume = (int) (mMaxVolume * curProgress * 0.01);audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);hasMenuAction();break;case R.id.rl_voice_sub://减少音量Log.d("vrdemo","音量减少="+verticalSeekBar.getProgress());curProgress=verticalSeekBar.getProgress();if(curProgress>0){curProgress=curProgress-5;verticalSeekBar.setProgress(curProgress);}volume = (int) (mMaxVolume * curProgress * 0.01);audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);hasMenuAction();break;case R.id.btn_vr_nor://360全景模式if(playType!=MDVRLibrary.DISPLAY_MODE_NORMAL){changeTo360nor();}hasMenuAction();break;case R.id.btn_vr_glass://眼镜模式if(playType!=MDVRLibrary.DISPLAY_MODE_GLASS){changeToglass();}hasMenuAction();break;case R.id.img_stop_vr://暂停img_stop_vr.setVisibility(View.GONE);img_start_vr.setVisibility(View.VISIBLE);mMediaPlayerWrapper.pause();mHandler.removeMessages(MESSAGE_TOUCH_MENU);break;case R.id.img_start_vr://继续播放img_start_vr.setVisibility(View.GONE);img_stop_vr.setVisibility(View.VISIBLE);mMediaPlayerWrapper.resume();hasMenuAction();break;case R.id.img_back://返回finish();break;case R.id.img_next_video://下一部playNext();break;}}private void playNext() {//获取下一步内容//TODO 获取新片资源if(videoModel.getId()==15){videoModel=MainActivity.videoModels.get(0);}else {videoModel=MainActivity.videoModels.get(videoModel.getId());}titleTv.setText(videoModel.getName());mMediaPlayerWrapper.pause();mMediaPlayerWrapper.destroy();mMediaPlayerWrapper.init();mMediaPlayerWrapper.openRemoteFile(videoModel.getVideoUrl());mMediaPlayerWrapper.prepare();}//切换成360全景模式public void changeTo360nor(){playType=MDVRLibrary.DISPLAY_MODE_NORMAL;getVRLibrary().switchDisplayMode(VrPlayerActivity.this, MDVRLibrary.DISPLAY_MODE_NORMAL);}public void changeToglass(){playType=MDVRLibrary.DISPLAY_MODE_GLASS;getVRLibrary().switchDisplayMode(VrPlayerActivity.this, MDVRLibrary.DISPLAY_MODE_GLASS);}private VerticalSeekBar.SlideChangeListener slideChangeListener=new VerticalSeekBar.SlideChangeListener() {@Overridepublic void onStart(VerticalSeekBar slideView, int progress) {}@Overridepublic void onProgress(VerticalSeekBar slideView, int progress) {volume= (int) (mMaxVolume * progress * 0.01);if (volume > mMaxVolume)volume = mMaxVolume;else if (volume < 0)volume = 0;// 变更声音audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);}@Overridepublic void onStop(VerticalSeekBar slideView, int progress) {}};/*** 时长格式化显示*/private String generateTime(long time) {int totalSeconds = (int) (time / 1000);int seconds = totalSeconds % 60;int minutes = (totalSeconds / 60) % 60;int hours = totalSeconds / 3600;return hours > 0 ? String.format("%02d:%02d:%02d", hours, minutes, seconds) : String.format("%02d:%02d", minutes, seconds);}/*** 进度条滑动监听*/private final SeekBar.OnSeekBarChangeListener mSeekListener = new SeekBar.OnSeekBarChangeListener() {/**数值的改变*/@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {long duration = mMediaPlayerWrapper.getPlayer().getDuration();int position = (int) ((duration * progress * 1.0) / 1000);String time = generateTime(position);currentTimeTv.setText(time);}/**开始拖动*/@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {isDragging = true;mHandler.removeMessages(MESSAGE_SHOW_PROGRESS);}/**停止拖动*/@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {long duration = mMediaPlayerWrapper.getPlayer().getDuration();mMediaPlayerWrapper.getPlayer().seekTo((int) ((duration * seekBar.getProgress() * 1.0) / 1000));mHandler.removeMessages(MESSAGE_SHOW_PROGRESS);isDragging = false;mHandler.sendEmptyMessageDelayed(MESSAGE_SHOW_PROGRESS, 1000);hasMenuAction();}};/*** 消息处理*/private Handler mHandler = new Handler(Looper.getMainLooper()) {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {/**滑动中,同步播放进度*/case MESSAGE_SHOW_PROGRESS:long pos = syncProgress();if (!isDragging) {msg = obtainMessage(MESSAGE_SHOW_PROGRESS);sendMessageDelayed(msg, 1000 - (pos % 1000));}break;/**隐藏菜单面板*/case MESSAGE_TOUCH_MENU:touchRl.setVisibility(View.GONE);//防止点触面引起的显示冲突break;case MESSAGE_PLAY_NEXT:playNext();break;case MESSAGE_START_COUNTDOWN://播放完成时,开始倒计时,抛出handler是不明确完成时是否有线程安全问题playNext();break;}}};/*** 同步进度*/private long syncProgress() {if (isDragging) {return 0;}long position = mMediaPlayerWrapper.getPlayer().getCurrentPosition();long duration = mMediaPlayerWrapper.getPlayer().getDuration();if (playSeekbar != null) {if (duration > 0) {long pos = 1000L * position / duration;playSeekbar.setProgress((int) pos);}int percent =mCurrentBufferPercentage;playSeekbar.setSecondaryProgress(percent * 10);}currentTimeTv.setText(generateTime(position));endTimeTv.setText(generateTime(duration));verticalSeekBar.setProgress(audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) * 100 / mMaxVolume);return position;}//有菜单操作public void hasMenuAction(){if(isDragging){mHandler.removeMessages(MESSAGE_TOUCH_MENU);}else {mHandler.removeMessages(MESSAGE_TOUCH_MENU);mHandler.sendEmptyMessageDelayed(MESSAGE_TOUCH_MENU, 5000);}}}

代码中用到的VideoModel是一个视频资源的model,可以根据实际项目需求传入,大致可以有标题,视频的url,封面图片,视频时长等字段。
这里讲下普通视频资源跟VR视频资源。拍摄VR视频的时候,是那种360°的机器,拍出来的视频就是360°的,如果你在浏览器上放VR视频,看到的一个很长的视频,你把VR视频用VR播放器播放,就相当于把长视频又卷到一个球上,而观看者在球中间。
demo中放置的几个测试url都是普通视频的url,所以看起来想过就很畸形了。

代码传送门

https://download.csdn.net/download/qq_31390699/10610824

Android VR视频相关推荐

  1. 一、初识GVR ---- Android VR视频/Google VR for Android /VR Pano/VR Video

    原文链接: http://blog.csdn.net/qq_24889075/article/details/52118633 http://www.jianshu.com/p/09c0822b9d1 ...

  2. 五、VR视频播放器开发 ---- Android VR视频/Google VR for Android /VR Pano/VR Video

    simplevideowidget 如果没有看上一篇文章的请先看完再来看这一篇吧,有写重复的就不介绍了 AndroidManifest 上一篇文章有提到,其实这里也没有什么特别的 build.grad ...

  3. 三、VR视频播放器开发 ---- Android VR视频/Google VR for Android /VR Pano/VR Video

    原文地址: http://blog.csdn.net/qq_24889075/article/details/52133170 http://www.jianshu.com/p/82163453ed3 ...

  4. 二、VR全景图显示器开发 ---- Android VR视频/Google VR for Android /VR Pano/VR Video

    原文地址: http://blog.csdn.net/qq_24889075/article/details/52128463 http://www.jianshu.com/p/104251a3153 ...

  5. Android Studio如何建立VR视频

     所需要的VR运行库可在https://github.com/googlevr/gvr-android-sdk/下载 新建项目后: 1. 在项目main文件夹下新建资产目录 assets并把视频放入该 ...

  6. Android VR Player(全景视频播放器) [10]: VR全景视频渲染播放的实现(exoplayer,glsurfaceview,opengl es)

    前言 此博客的大部分内容来自我的毕业设计论文,因此语言上会偏正式一点,如果您有任何问题或建议,欢迎留言.在此感谢实验室的聂师兄,全景视频render部分的代码设计主要参考了他所编写的代码来完成,他对视 ...

  7. Android VR Player(全景视频播放器) [7]:视频列表的实现-网络视频

    Android VR Player(全景视频播放器) [7]:视频列表的实现-网络视频 前期准备 在之前的博文,Android VR Player(全景视频播放器) [6]:视频列表的实现-本地视频 ...

  8. Android VR Player(全景视频播放器) [6]:视频列表的实现-本地视频

    Android VR Player(全景视频播放器) [6]:视频列表的实现-本地视频 (本篇博客参考<Android第一行代码(第二版)>中关于RecyclerView的部分) 列表的实 ...

  9. 通过Android实现VR视频的播放

    实现VR视频的播放和前面写过的VR全景图的展示差不多,改变的也只是库文件的不同,资源目录下的资源不同而已.下面就来说一下步骤. 先展示一下效果图 完成步骤: 1.以导入Moudle的方式导入库文件.( ...

最新文章

  1. spring根据名称获取bean_带你从零开始手写 spring ioc 框架,深入学习 spring 源码
  2. Nature Reviews:全新的益生元定义和范围
  3. JAVA——prepareStatement中SQL语句中占位符(?)替换表名和字段名
  4. Uiautomator--Uiselector元素定位
  5. 巧用VC工程下的rc文件
  6. 微软Visual Studio 2012软件功能介绍
  7. zookeeper删除节点的权限_Zookeeper使用超级用户删除带权限的节点
  8. 调查|73%的公司正使用存在漏洞的超期服役设备
  9. border-collapse 关于继承问题
  10. Google Ads支付宝付款功能正式上线
  11. Java基础篇之返回值
  12. python 爬虫之路教程
  13. 【Keras中文文档】Layer Convolutional网址
  14. 转载:等比数列的求和公式,及其推导过程
  15. 从键盘输入一个字符串a,并在串a中的最大元素后面插入字符串b(b[]=“ab”),输出字符串a。
  16. 基于QT实现西克sick激光LMS系列单线激光数据读取及显示
  17. JS 中 TDZ 的理解
  18. -1-2 java 面向对象基本概念 封装继承多态 变量 this super static 静态变量 匿名对象 值传递 初始化过程 代码块 final关键字 抽象类 接口
  19. 你所不知道的VR全景拍摄地拍步骤和细节
  20. php 分割验证码,动态验证码字符完美分割(附算法)

热门文章

  1. 陈进:乘风破浪会有时(8.31)
  2. canvas截图中图片空白(跨域 导致)
  3. openlayer拖动图标消失以及绘线穿越地图问题
  4. 01hibernate初印象
  5. Sentinel入门
  6. 【科创人XTGO】别被《人月神话》毒害,“组织越大效率越低”是误区
  7. 常用的 50 sql示例语句
  8. 【C语言】交换两个变量的值 的n种方法
  9. c# picturebox图片上画框框或圈圈
  10. 蒲公英串口服务器接显示器,蒲公英虚拟串口功能使用帮助