它是一个专注视频播放的Unity插件,可以发布到多个平台。
该插件做了一些优化,本人用skybox播放vr视频,只有40帧,换成该插件fps升到70帧。
参考上一篇:
播放全景视频【一】:用unity Video Player视频播放器来播放360全景视频
1、下一个吧,【github】:https://github.com/RenderHeads/UnityPlugin-AVProVideo
2、800美元买一个吧,【Unity assets stores】:https://assetstore.unity.com/packages/tools/video/avpro-video-ultra-edition-184294
3、从别人的工程里面刨一个吧,或者邻居借一个
一共挂载三个物体,如下图所示(1,2,3):
常用设置:
1、MediaSource,资源的加载方式,【路径加载】还是【引用加载】
2、Auto Play,自动播放
3、Loop,循环播放
4、Muted,静音
android里面的apk包,有大小限制,具体查看官网。
当build的apk太大时,如果祖坟葬得好可以跑几个步骤,如果祖坟葬的有点歪,可能启动就黑屏,甚至花屏。所以啊,把video资源从streamingasset或者resources里面剥离出来就显得比较重要了!
app要访问本地的资源,是需要许可,那么在哪里设置呢?
【Project Settings】/【OtherSettings】/【Configuration】
[Install Location = Force Internal]
[Write Permission = Internal]
设置资源从路径加载:
///
/// Unity获取Android的内存共享文件夹目录
///
///
public static string GetMoviesFolder()
{
/*
Found a way, to get the internal download or movies... folder without an native plugin. Tho its a bit hackerish.
You need to set:
BuildSettings->PlayerSettings->Android->OtherSettings->InstallLocation to "ForceInternal"
Than create an static string in your script:
*/
string[] temp = (Application.persistentDataPath.Replace("Android", "")).Split(new string[] { "//" }, System.StringSplitOptions.None);
return (temp[0] + "/Movies");
}
///
/// 播放存储空间中的mp4视频
///
/// 视频文件名
void PlayVideoFromSD(string name)
{
try
{
myMediaPlayer.OpenMedia(MediaPathType.AbsolutePathOrURL, $"{GetMoviesFolder()}/{name}", true);
myMediaPlayer.Rewind(true);
myMediaPlayer.Play();
}
catch (Exception ex)
{
Debug.Log($"播放视频出错,请参考出错信息:{ex.Message}");
}
}
作者已经提供了Events的接口了,如下图所示:
那么怎么侦听【播放结束】的事件呢?作者也提供了,如下图所示:
自己手动添加侦听,一旦检测到【播放结束】,那就切下一首~~~这就是循环播放
myMediaPlayer.Events.AddListener((MediaPlayer mp, MediaPlayerEvent.EventType eventType, ErrorCode errorCode) =>
{
switch (eventType)
{
//case MediaPlayerEvent.EventType.MetaDataReady:
// break;
//case MediaPlayerEvent.EventType.ReadyToPlay:
// Debug.Log("ReadyToPlay状态");
// break;
//case MediaPlayerEvent.EventType.Started:
// Debug.Log("Started状态");
// break;
//case MediaPlayerEvent.EventType.FirstFrameReady:
// Debug.Log("第一帧准备完成");
// if (displayUGUI != null)
// displayUGUI.color = new Color(255, 255, 255);
// break;
case MediaPlayerEvent.EventType.FinishedPlaying: //视频播放完毕
Debug.Log("视频播放完毕,即将播放下一条!!!");
var nextVideo = GetNext(videosList, currentVideo);
PlayVideoFromSD(nextVideo);
break;
default:
break;
}
});
using Pvr_UnitySDKAPI;
using RenderHeads.Media.AVProVideo;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using Cysharp.Threading.Tasks;
///
/// 播放android上的视频资源
///
public class PlayVideoFromAndroid : MonoBehaviour
{
///
/// 视频文件列表
///
[Header("视频文件列表")]
[SerializeField]
public List<string> videosList = new List<string>();
///
/// 挂载视频播放组件的物体
///
public GameObject videoPlayObj;
///
/// 当前播放的视频
///
private string currentVideo;
///
/// MediaPlayer对象
///
private MediaPlayer myMediaPlayer;
private void Awake()
{
myMediaPlayer = videoPlayObj.GetComponent<MediaPlayer>();
}
// Start is called before the first frame update
void Start()
{
#region ======普通初始化======begin
PlayFirstVideo();
#endregion ======普通初始化======end
#region ======事件绑定======begin
myMediaPlayer.Events.AddListener((MediaPlayer mp, MediaPlayerEvent.EventType eventType, ErrorCode errorCode) =>
{
switch (eventType)
{
//case MediaPlayerEvent.EventType.MetaDataReady:
// break;
//case MediaPlayerEvent.EventType.ReadyToPlay:
// Debug.Log("ReadyToPlay状态");
// break;
//case MediaPlayerEvent.EventType.Started:
// Debug.Log("Started状态");
// break;
//case MediaPlayerEvent.EventType.FirstFrameReady:
// Debug.Log("第一帧准备完成");
// if (displayUGUI != null)
// displayUGUI.color = new Color(255, 255, 255);
// break;
case MediaPlayerEvent.EventType.FinishedPlaying: //视频播放完毕
Debug.Log("视频播放完毕,即将播放下一条!!!");
var nextVideo = GetNext(videosList, currentVideo);
PlayVideoFromSD(nextVideo);
break;
default:
break;
}
});
#endregion ======事件绑定======end
}
private async UniTask PlayFirstVideo()
{
await UniTask.DelayFrame(2,cancellationToken:this.GetCancellationTokenOnDestroy()); //延时2帧,等待初始化
myMediaPlayer.AudioMuted = true;
currentVideo = videosList[0];
PlayVideoFromSD(currentVideo);
}
///
/// 播放存储空间中的mp4视频
///
/// 视频文件名
void PlayVideoFromSD(string name)
{
try
{
myMediaPlayer.OpenMedia(MediaPathType.AbsolutePathOrURL, $"{GetMoviesFolder()}/{name}", true);
myMediaPlayer.Rewind(true);
myMediaPlayer.Play();
}
catch (Exception ex)
{
Debug.Log($"播放视频出错,请参考出错信息:{ex.Message}");
}
}
///
/// Unity获取Android的内存共享文件夹目录
///
///
public static string GetMoviesFolder()
{
/*
Found a way, to get the internal download or movies... folder without an native plugin. Tho its a bit hackerish.
You need to set:
BuildSettings->PlayerSettings->Android->OtherSettings->InstallLocation to "ForceInternal"
Than create an static string in your script:
*/
string[] temp = (Application.persistentDataPath.Replace("Android", "")).Split(new string[] { "//" }, System.StringSplitOptions.None);
return (temp[0] + "/Movies");
}
private void Update()
{
//播放下一个视频,just for testing
//if (Controller.UPvr_GetKeyDown(0, Pvr_KeyCode.TRIGGER) || Controller.UPvr_GetKeyDown(0, Pvr_KeyCode.TRIGGER) || Input.GetKeyDown(KeyCode.Mouse0))
//{
// currentVideo = GetNext(videosList, currentVideo);
// PlayVideoFromSD(currentVideo);
//}
}
///
/// 在一个列表中,获取【给定元素】的下一个元素,如果【给定元素】是最末尾的元素,【下一个元素】为列表的第一个元素
///
///
///
///
///
public static T GetNext<T>(List<T> list, T t)
{
var subList = list.SkipWhile(x => !x.Equals(t)).Skip(1);//SkipWhile——凡是满足给定条件的item都会被忽略
return subList.Count() == 0 ? list[0] : subList.First();
}
private void OnDestroy()
{
myMediaPlayer.Stop();
myMediaPlayer = null;
myMediaPlayer.Events.RemoveAllListeners();
}
}