一:引言
首先住册,今天有了一個(gè)想法拣帽。所以我決定制作一個(gè)VR播放器。純手工打造痰驱,24K金不敢說亡蓉,100%真心晕翠。
導(dǎo)入資源神馬的不說了,直接上代碼砍濒。而且也沒有人制作過淋肾,所以有壓力,不過動(dòng)力更大爸邢。(Ps:2016-12-31,12:31)
二:關(guān)于視頻播放要知道的一些事
三:Unity自帶了兩種播放API
1- MovieTexture(視頻紋理)
優(yōu)點(diǎn):簡(jiǎn)單樊卓,高效的快速完成播放
缺點(diǎn):此種方法無(wú)法應(yīng)用于移動(dòng)端。movietexture只能播放OGG和OVG
轉(zhuǎn)碼可以使用:
Theora Converter .NET
ffmpeg將視頻轉(zhuǎn)成.ogv
ffmpeg - i “文件路徑/文件名.格式” -s 3000x1500(分辨率) -r 25 (幀率) -b:v 8782(碼率杠河,默認(rèn)單位為Bit/s) "輸出文件路徑/輸出文件名.格式"
2-Handheld(標(biāo)準(zhǔn)的視頻播放接口)
缺點(diǎn):
可操作性非常差碌尔,幾乎達(dá)不到我們想要的結(jié)果,而且也只支持全屏的普通視頻的播放券敌。
注意點(diǎn):
將視頻文件放置在Assets/StreamingAssets/路徑下唾戚,經(jīng)測(cè)試.MP4可用。
MoveTexture
1. 在游戲?qū)ο笾胁シ排惆祝秃帽仍谟螒蚴澜缰袆?chuàng)建一個(gè)Plane面對(duì)象,攝像機(jī)直直的照射在這個(gè)面上
在新建的一個(gè)plane平面膳灶,將其紋理綁定為電影紋理即可
//設(shè)置當(dāng)前對(duì)象的主紋理為電影紋理
renderer.material.mainTexture = movTexture;
//設(shè)置電影紋理播放模式為循環(huán)
movTexture.loop = true;
并可通過
movTexture.Play();
movTexture.Pause();
movTexture.Stop();
mov Texturu.pitch = 1f 正常播放 2f兩倍速度
來(lái)進(jìn)得播放控制咱士。
此時(shí)可以通過直接縮放plane平面來(lái)達(dá)到縮放視頻的目的
至于MovieTexture的賦值,在4.6x/5.0x版本上是無(wú)法通過將視頻拖入Project視頻來(lái)自動(dòng)造成紋理的
2. 在GUI層面播放轧钓。它其實(shí)和貼圖非常相像序厉,因?yàn)椴シ乓曨l用到的MovieTexture屬于貼圖Texture的子類。
//繪制電影紋理
GUI.DrawTexture (new Rect (0,0, Screen.width,Screen.height),movTexture,ScaleMode.StretchToFill);
播放視頻的大小是屏幕的寬高毕箍,如果想動(dòng)態(tài)的修改視頻的寬或高直接修改new Rect()視頻顯示區(qū)域即可
Handheld
url_movie = "http://dl.nbrom.cn/17051/c3e408229342723fbdf62d0bcf1d549c.mp4?fsname=Criminal_Minds_S01E01.mp4";
Handheld.PlayFullScreenMovie(url_movie, Color.black, FullScreenMovieControlMode.Full);
Handheld.PlayFullScreenMovie("test.mp4", Color.black, FullScreenMovieControlMode.CancelOnInput);
將視頻文件放置在Assets/StreamingAssets/路徑下
上面的方法在移動(dòng)端是邊下載邊播放網(wǎng)絡(luò)視頻的弛房,屬于在線播放,不好的地方就是而柑,再次觀看還需要再次加載文捶『沙眩可能在播放的時(shí)候判斷是否已下載到本地如果在本地就可以播放本地,如果沒有再?gòu)木W(wǎng)上下載到本地
注意:
1. 將視頻資源拷貝到外置存儲(chǔ)(如sd卡)粹排,通過外置存儲(chǔ)絕對(duì)路徑調(diào)用
string path = Application.persistentDataPath + "xxx.mp4";
2. 在Build Apk的時(shí)候种远,將視頻資源放在StreamingAssets子目錄下,通過視頻名字調(diào)用
string path = "xxx.mp4";
四:視頻播放插件
第三方插件:進(jìn)行播放
GitHub有大量的視頻播放插件,自己去搜索.
EasyMovieTexture
MobileMovieTexture
MobilePlayer
Mobile movie texture for android :利用開源視頻編解碼庫(kù)Theora進(jìn)行視頻解碼顽耳,然后通過Unity Texture實(shí)現(xiàn)顯示坠敷。
1-使用插件
由于CardBoard中VR播放不能使用自帶的兩種方式所以下面的項(xiàng)目中,直接使用插件射富,此處不再啰嗦介紹
2-項(xiàng)目準(zhǔn)備
一段視頻膝迎,N張圖片,一個(gè)夢(mèng)幻的場(chǎng)景胰耗,各種好聽的音樂限次,那么導(dǎo)入資源。此處使用視頻插件Easy Movie Texture
選中平臺(tái)設(shè)置
3-播放代碼
關(guān)于視頻播放的代碼宪郊,設(shè)置暫停掂恕,停止,加載弛槐,全屏等
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class Test_Movie_Player : MonoBehaviour {
public Text totalTime;
public Text movieTime;
public Slider movieSlider;
public Material renderMaterial;
public int movieSpeed = 1000;
private MediaPlayerCtrl mediaPlayerCtrl;
private RawImage movieRawImage;
private Vector2 reducteOffsetMax;
private bool isFinish = false;
private bool isPlay = false;
private bool isCtrlMovie = false;
private int fastbackTemp = 0;
private int totaltime = 0;
void Start()
{
Init();
mediaPlayerCtrl.OnEnd += OnEnd;
}
/// <summary>
/// 初始化函數(shù)
/// </summary>
public void Init()
{
mediaPlayerCtrl = this.transform.GetComponent<MediaPlayerCtrl>();
movieRawImage = this.transform.GetComponent<RawImage>();
mediaPlayerCtrl.m_bAutoPlay = false;
if (movieRawImage.material == null)
movieRawImage.material = renderMaterial;
reducteOffsetMax = movieRawImage.rectTransform.offsetMax;
}
void Update()
{
UpdateMovieSlider();
UpdateMovieTime();
UpdateTotalTime();
}
/// <summary>
/// 更新視頻進(jìn)度條
/// </summary>
public void UpdateMovieSlider()
{
if (mediaPlayerCtrl.GetSeekPosition() != 0 && !isCtrlMovie)
{
float slider = (float)mediaPlayerCtrl.GetSeekPosition() / (float)mediaPlayerCtrl.GetDuration();
movieSlider.value = slider;
}
}
/// <summary>
/// 更新視頻總時(shí)間
/// </summary>
public void UpdateTotalTime()
{
if (this.totalTime.text != null && isPlay)
{
if (totaltime != mediaPlayerCtrl.GetDuration() / 1000)
{
totaltime = mediaPlayerCtrl.GetDuration() / 1000;
int min = totaltime / 60;
int seconds = totaltime - min * 60;
this.totalTime.text = " / " + min + ":" + seconds;
}
}
}
/// <summary>
/// 更新視頻時(shí)間
/// </summary>
public void UpdateMovieTime()
{
if (this.movieTime.text != null && isPlay)
{
int movieTime = mediaPlayerCtrl.GetSeekPosition() / 1000;
int min = movieTime / 60;
int seconds = movieTime - min * 60;
this.movieTime.text = min + ":" + seconds;
}
}
/// <summary>
/// 視頻播放
/// </summary>
public void MoviePlay()
{
mediaPlayerCtrl.Play();
isPlay = true;
isFinish = false;
}
/// <summary>
/// 視頻暫停
/// </summary>
public void MoviePause()
{
isPlay = false;
mediaPlayerCtrl.Pause();
}
/// <summary>
/// 視頻停止
/// </summary>
public void MovieStop()
{
isPlay = false;
mediaPlayerCtrl.Stop();
}
/// <summary>
/// 讀取視頻
/// </summary>
/// <param name="namePtah">讀取視頻的路徑</param>
public void MovieLoad(string namePtah)
{
mediaPlayerCtrl.Load(namePtah);
mediaPlayerCtrl.m_bAutoPlay = false;
isPlay = false;
isFinish = false;
}
/// <summary>
/// 視頻設(shè)置循環(huán)播放
/// </summary>
public void MovieLoop()
{
mediaPlayerCtrl.m_bLoop = !mediaPlayerCtrl.m_bLoop;
}
/// <summary>
/// 視頻全屏顯示
/// </summary>
public void OnClickFullScreen()
{
if (mediaPlayerCtrl.m_bFullScreen)
{
mediaPlayerCtrl.m_bFullScreen = false;
movieRawImage.rectTransform.offsetMax = reducteOffsetMax;
movieRawImage.rectTransform.offsetMin = -reducteOffsetMax;
}
else
{
mediaPlayerCtrl.m_bFullScreen = true;
movieRawImage.rectTransform.offsetMax = new Vector2(0, 0);
movieRawImage.rectTransform.offsetMin = new Vector2(0, 0);
}
}
/// <summary>
/// 關(guān)閉視頻界面
/// </summary>
public void OnClickClose()
{
mediaPlayerCtrl.Stop();
movieRawImage.gameObject.SetActive(false);
}
/// <summary>
/// 移動(dòng)視頻進(jìn)度條
/// </summary>
public void OnDragSlider()
{
if (!isPlay)
return;
int seekPos = (int)(movieSlider.value * mediaPlayerCtrl.GetDuration());
mediaPlayerCtrl.SeekTo(seekPos);
}
/// <summary>
/// 按下視頻進(jìn)度條
/// </summary>
public void OnPoniterDownSlider()
{
if (!isPlay)
return;
MoviePause();
isCtrlMovie = true;
int seekPos = (int)(movieSlider.value * mediaPlayerCtrl.GetDuration());
mediaPlayerCtrl.SeekTo(seekPos);
}
/// <summary>
/// 彈起視頻進(jìn)度條
/// </summary>
public void OnPoniterUpSlider()
{
if (!isPlay)
return;
MoviePlay();
isCtrlMovie = false;
}
public bool GetIsFullScreen()
{
return mediaPlayerCtrl.m_bFullScreen;
}
public bool GetIsLoop()
{
return mediaPlayerCtrl.m_bLoop;
}
void OnEnd()
{
isFinish = true;
}
}
全景視頻播放
全景視頻跟著頭部移動(dòng)的方法懊亡,看到sphere對(duì)象上掛在了GvrViewer.cs腳本,然后把VRModelEnabled屬性設(shè)置為false乎串,這樣就調(diào)整配置文件就可以全景視頻跟著頭部移動(dòng)而觀看視頻效果了
調(diào)整配置文件
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unity3d.player"
android:installLocation="preferExternal"
android:theme="@android:style/Theme.NoTitleBar"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="22" />
<uses-feature android:name="android.hardware.camera" />
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"
android:anyDensity="true"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:glEsVersion="0x00020000" />
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true"/>
<uses-feature android:name="android.hardware.sensor.gyroscope" android:required="true"/>
<uses-permission android:name="android.permission.NFC"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<!-- VR feature tags. -->
<uses-feature android:name="android.software.vr.mode" android:required="false"/>
<uses-feature android:name="android.hardware.vr.high_performance" android:required="false"/>
<application
android:icon="@drawable/app_icon"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:debuggable="false">
<activity android:name="com.unity3d.player.UnityPlayerNativeActivity"
android:label="@string/app_name"
android:screenOrientation="landscape"
android:launchMode="singleTask"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="com.google.intent.category.CARDBOARD" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
<meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="false" />
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
</activity>
<activity android:name="com.unity3d.player.VideoPlayer"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen">
</activity>
<activity android:name="com.google.unity.GoogleUnityActivity"
android:label="@string/app_name"
android:screenOrientation="landscape"
android:launchMode="singleTask"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale">
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
</activity>
<meta-data android:name="IMMERSIVE_MODE" android:value="true" />
<!--
To support devices using the TI S3D library for stereo mode we must
add the following library.
Devices that require this are: ODG X6
-->
<uses-library android:name="com.ti.s3d" android:required="false" />
<!--
To support the ODG R7 in stereo mode we must add the following library.
-->
<uses-library android:name="com.osterhoutgroup.api.ext" android:required="false" />
</application>
</manifest>
<!-- android:installLocation="preferExternal" -->