Android VR视频

news/2024/11/24 11:44:23/

话不多说,先上图(眼睛模式)
这里写图片描述
参考的开源库——传送门 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


http://www.ppmy.cn/news/467197.html

相关文章

Unity 手机VR GoogleVR 详细配置教程

一 Unity环境配置 1.首先导入GoogleVRForUnity_1.200.1.unitypackage 下载地址 2.点击File\BuildSettings,导入当前场景,选择安卓/IOS 3.点击PlayerSettings,在Player中找到XRSettings,点击Virtual Reality Supported,点击选择Cardboard 4.同样在PlayerSettings这个界面…

android手机 不显示本地视频,Android手机,如何使用VR观看本地视频?

全部展开 需要准备两个工具: 第一个是VR眼镜手机本地视频播放器&#xff0c;可以在市场上购买或购买. 第二个是VR软件&#xff0c;它是用于播放VR视频的软件&#xff0c;例如3D广播&#xff0c;Orange VR等. 以下是通过3D广播进行操作的步骤: 1. 打开3D广播软件&#xff0c;单击…

[Flutter]理解Widget-Key的作用

这里主要是理解在Widget中key的作用/用途。 import dart:math;import package:flutter/material.dart;/// 这里主要是理解在Widget中key的作用/用途。 void main() {runApp(const MyApp()); }class MyApp extends StatelessWidget {const MyApp({super.key});overrideWidget b…

如何知识变现?介绍几个变现途径

哈喽&#xff0c;大家好&#xff0c;我是海哥&#xff0c;知识付费变现创业教练&#xff0c;教育公司培训总监&#xff0c;从事知识付费变现咨询10年&#xff0c;已助力3000人实现知识付费变现。 在互联网时代&#xff0c;所有线下的产业都可以在线上再做一遍&#xff0c;知识产…

【机器学习】——神经网络与深度学习

目录 引入 一、神经网络及其主要算法 1、前馈神经网络 2、感知器 3、三层前馈网络&#xff08;多层感知器MLP&#xff09; 4、反向传播算法 二、深度学习 1、自编码算法AutorEncoder 2、自组织编码深度网络 ①栈式AutorEncoder自动编码器 ②Sparse Coding稀疏编码 …

canvas绘制星空底图

canvas的初始化就没写了&#xff0c;仅写地图实现过程&#xff0c;长宽均为420 //星空图底图function drawBaseSky(tempcxt){tempcxt.clearRect(0,0,420,420);//清空画布var RADIUS 180;//半径var yuandian 195;//半径tempcxt.save(); //保存状态tempcxt.translate(15,15);/…

202302|读书笔记——国图点滴

杂志剪影|看一本赚一本系列 anywhere 随心而行随心而动&#xff0c;极简相生复古文艺 热情洋溢 色彩斑斓 极致优雅 深邃魅力 新生绽放 灿若星空 异彩纷呈含苞待放 惊艳绽放 爱在云端 空中婚礼 暗夜浪漫 策马逐梦橘影相映 浆果红唇 梦幻无暇 永无止境浮光掠影 微酥清风低调奢华…

开放式运动耳机排行榜,盘点几款最适合运动的开放式耳机

随着刘耕宏带领的全民运动健身风的盛起&#xff0c;大多数人在响应下纷纷加入了健身的队伍&#xff0c;而在运动健身的过程中人们大多都是佩戴着耳机&#xff0c;靠着耳机内部的音乐来将运动所产生的孤单感一一化解&#xff0c;但对于运动耳机选择就让很多小白犯了难&#xff0…