unity5.6.1 videoPlayer
unity5.6开始增加了videoPlayer,使得视频播放相对比较简单,项目需求进行了一下研究应用,也遇到很多坑,Google 百度一下发现确实有这些问题,一些简单问题如下:
1)播放无声音
2)通过slider控制播放进度
3)视频截图(texture->texture2d)
4)视频结束时事件激活
基本上无太大问题,以上四个问题解决方案在下文红色文字区域,先介绍一下video Player应用,后续对这四个问题进行解决(代码之后有更新)。
(一)新建video Player 可以在ui下田间video Play组建,也可以直接右键-video-videoplayer,添加后可以看到如下图所示的组件
本文主要重点说一下一下参数:source有两种模式clip模式和url模式,clip则可以直接通过videoClip进行播放,url则可以通过url进行播放。renderMode为渲染模式,既可以为camera,material等,如果是使用ui播放的选用render texture,本文采用此模式。audioOutputMode有三种,none模式,direct模式(没尝试)和audiosource模式,本文采用audiosource模式,采用此模式时只需要将audiosource组建拖入上图中videoPlayer中的audiosource参数槽中即可,不需要任何处理,但有时会出现拖入后videoPlayer中的audiosource参数槽消失,且无声音播放,所以一般采用代码添加,如下所示:
//代码添加
videoPlayer = gameObject.AddComponent<VideoPlayer>();
//videoPlayer = gameObject.GetComponent<VideoPlayer>();
audioSource = gameObject.AddComponent<AudioSource>();
//audioSource = gameObject.GetComponent<AudioSource>();
videoPlayer.playOnAwake = false;
audioSource.playOnAwake = false;
audioSource.Pause();
(二)视频播放的控制与音频/动画播放类似,videoPlayer有play/pause等方法,具体可以参见后面完整代码。
在调用视频播放结束时事件loopPointReached(此处为借鉴别人称呼,此事件其实并不是视频播放结束时的事件),顾名思义,此事件为达到视频播放循环点时的事件,即当videoplay 的isLooping属性为true(即循环播放视频)时,视频结束时调用此方法,所以当视频非循环播放时,此事件在视频结束时调用不到。要想调用此方法可以把视频设置为循环播放,在loopPointReached指定的事件中停止播放视频
(三)关于视频播放的ui选择问题,选用render texture时需要指定target texture。
1)在project面板上create-renderTexture,并把新建的renderTexture拖到videoplayer相应的参数槽上
2)在Hierarchy面板上新建ui-RawImage,并把上一步新建的renderTexture拖到RawImage的texture上即可。
其实可以不用这么处理,videoPlayer有texture变量,直接在update里面把texture值赋给RawImage的texture即可,代码如下
rawImage.texture = videoPlayer.texture;
视频截图时可以通过videoPlayer.texture,把图像保存下来不过需要把texture转变为texture2d,虽然后者继承在前者,但是无法强制转货回去,转换以及存储图片代码如下:
private void SaveRenderTextureToPNG(Texture inputTex, string file)
{
RenderTexture temp = RenderTexture.GetTemporary(inputTex.width, inputTex.height, , RenderTextureFormat.ARGB32);
Graphics.Blit(inputTex, temp);
Texture2D tex2D = GetRTPixels(temp);
RenderTexture.ReleaseTemporary(temp);
File.WriteAllBytes(file, tex2D.EncodeToPNG());
} private Texture2D GetRTPixels(RenderTexture rt)
{
RenderTexture currentActiveRT = RenderTexture.active;
RenderTexture.active = rt;
Texture2D tex = new Texture2D(rt.width, rt.height);
tex.ReadPixels(new Rect(, , tex.width, tex.height), , );
RenderTexture.active = currentActiveRT;
return tex;
}
最后说一下通过slider控制视频播放进度的问题,
通过slider控制视频播放存在两个问题,一方面在update实时把videoPlayer.time 赋值给slider,一方面需要把slider的value反馈给time,如果用slider的OnValueChanged(float value) 方法则存在矛盾,导致问题。所以可以通过UI事件的BeginDrag和EndDrag事件
事件进行,即当BeginDrag时,停止给slider赋值,当EndDrag时重新开始赋值。如下图所示
全代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Video; public class VideoController : MonoBehaviour {
public GameObject screen;
public Text videoLength;
public Text currentLength;
public Slider volumeSlider;
public Slider videoSlider; private string video1Url;
private string video2Url;
private VideoPlayer videoPlayer;
private AudioSource audioSource;
private RawImage videoScreen;
private float lastCountTime = ;
private float totalPlayTime = ;
private float totalVideoLength = ; private bool b_firstVideo = true;
private bool b_adjustVideo = false;
private bool b_skip = false;
private bool b_capture = false; private string imageDir =@"D:\test\Test\bwadmRe"; // Use this for initialization
void Start () {
videoScreen = screen.GetComponent<RawImage>();
string dir = Path.Combine(Application.streamingAssetsPath,"Test");
video1Url = Path.Combine(dir, "01.mp4");
video2Url = Path.Combine(dir, "02.mp4"); //代码添加
videoPlayer = gameObject.AddComponent<VideoPlayer>();
//videoPlayer = gameObject.GetComponent<VideoPlayer>();
audioSource = gameObject.AddComponent<AudioSource>();
//audioSource = gameObject.GetComponent<AudioSource>();
videoPlayer.playOnAwake = false;
audioSource.playOnAwake = false;
audioSource.Pause(); videoPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource;
videoPlayer.SetTargetAudioSource(, audioSource); VideoInfoInit(video1Url);
videoPlayer.loopPointReached += OnFinish;
} #region private method
private void VideoInfoInit(string url)
{
videoPlayer.source = VideoSource.Url;
videoPlayer.url = url; videoPlayer.prepareCompleted += OnPrepared;
videoPlayer.isLooping = true; videoPlayer.Prepare();
} private void OnPrepared(VideoPlayer player)
{
player.Play();
totalVideoLength = videoPlayer.frameCount / videoPlayer.frameRate;
videoSlider.maxValue = totalVideoLength;
videoLength.text = FloatToTime(totalVideoLength); lastCountTime = ;
totalPlayTime = ;
} private string FloatToTime(float time)
{
int hour = (int)time / ;
int min = (int)(time - hour * ) / ;
int sec = (int)(int)(time - hour * ) % ;
string text = string.Format("{0:D2}:{1:D2}:{2:D2}", hour, min, sec);
return text;
} private IEnumerator PlayTime(int count)
{
for(int i=;i<count;i++)
{
yield return null;
}
videoSlider.value = (float)videoPlayer.time;
//videoSlider.value = videoSlider.maxValue * (time / totalVideoLength);
} private void OnFinish(VideoPlayer player)
{
Debug.Log("finished");
} private void SaveRenderTextureToPNG(Texture inputTex, string file)
{
RenderTexture temp = RenderTexture.GetTemporary(inputTex.width, inputTex.height, , RenderTextureFormat.ARGB32);
Graphics.Blit(inputTex, temp);
Texture2D tex2D = GetRTPixels(temp);
RenderTexture.ReleaseTemporary(temp);
File.WriteAllBytes(file, tex2D.EncodeToPNG());
} private Texture2D GetRTPixels(RenderTexture rt)
{
RenderTexture currentActiveRT = RenderTexture.active;
RenderTexture.active = rt;
Texture2D tex = new Texture2D(rt.width, rt.height);
tex.ReadPixels(new Rect(, , tex.width, tex.height), , );
RenderTexture.active = currentActiveRT;
return tex;
}
#endregion #region public method
//开始
public void OnStart()
{
videoPlayer.Play();
}
//暂停
public void OnPause()
{
videoPlayer.Pause();
}
//下一个
public void OnNext()
{
string nextUrl = b_firstVideo ? video2Url : video1Url;
b_firstVideo = !b_firstVideo; videoSlider.value = ;
VideoInfoInit(nextUrl);
}
//音量控制
public void OnVolumeChanged(float value)
{
audioSource.volume = value;
}
//视频控制
public void OnVideoChanged(float value)
{
//videoPlayer.time = value;
//print(value);
//print(value);
}
public void OnPointerDown()
{
b_adjustVideo = true;
b_skip = true;
videoPlayer.Pause();
//OnVideoChanged();
//print("down");
}
public void OnPointerUp()
{
videoPlayer.time = videoSlider.value; videoPlayer.Play();
b_adjustVideo = false;
//print("up");
}
public void OnCapture()
{
b_capture = true;
}
#endregion // Update is called once per frame
void Update () {
if (videoPlayer.isPlaying)
{
videoScreen.texture = videoPlayer.texture;
float time = (float)videoPlayer.time;
currentLength.text = FloatToTime(time); if(b_capture)
{
string name = DateTime.Now.Minute.ToString() + "_" + DateTime.Now.Second.ToString() + ".png";
SaveRenderTextureToPNG(videoPlayer.texture,Path.Combine(imageDir,name));
b_capture = false;
} if(!b_adjustVideo)
{
totalPlayTime += Time.deltaTime;
if (!b_skip)
{
videoSlider.value = (float)videoPlayer.time;
lastCountTime = totalPlayTime;
}
if (totalPlayTime - lastCountTime >= 0.8f)
{
b_skip = false;
}
}
//StartCoroutine(PlayTime(15)); }
}
}
如果使用插件AVPro Video所有问题不是问题
//-----------------------------------------2018_11_29-----------------------------------------------//
版本为2018.2.14,在新版本中videoplayer已经不存在上述问题。
通过下述两个事件可以添加时间时间和帧时间,但是帧事件要设置sendFrameReadyEvents=true
public event TimeEventHandler clockResyncOccurred;
public event FrameReadyEventHandler frameReady;
代码更新
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.Video;
using UnityEngine;
using UnityEngine.EventSystems;
/// <summary>
/// 视频播放控制脚本
/// </summary>
public class CustomerVideoPlayer : MonoBehaviour
{
public RawImage rawImage;
public Button btnPlay;
public Button btnPause;
public Button btnFornt;
public Button btnBack;
public Button btnNext;
public Slider sliderVolume;
public Slider sliderVideo;
public Text txtVolume;
public Text txtProgress;
public Text txtCurrentProgress; //需要添加播放器的物体
public GameObject obj;
//是否拿到视频总时长
public bool isShow;
//前进后退的大小
public float numBer = 20f; //时 分的转换
private int hour, min;
private float time;
private float time_Count;
private float time_Current;
private bool isVideo;
private VideoPlayer vPlayer;
private AudioSource source;
private string urlNetWork = @"D:\001.mp4"; void Start()
{
//一定要动态添加这两个组件,要不然会没声音
vPlayer = obj.AddComponent<VideoPlayer>();
source = obj.AddComponent<AudioSource>(); vPlayer.playOnAwake = false;
source.playOnAwake = false;
source.Pause(); btnPlay.onClick.AddListener(delegate { OnClick(); });
btnPause.onClick.AddListener(delegate { OnClick(); });
btnFornt.onClick.AddListener(delegate { OnClick(); });
btnBack.onClick.AddListener(delegate { OnClick(); });
btnNext.onClick.AddListener(delegate { OnClick(); }); sliderVolume.value = source.volume; txtVolume.text = string.Format("{0:0}%", source.volume * ); Init(urlNetWork);
} /// <summary>
/// 初始化信息
/// </summary>
/// <param name="url"></param>
private void Init(string url)
{
isVideo = true;
isShow = true; time_Count = ;
time_Current = ;
sliderVideo.value = ; //设置为URL模式
vPlayer.source = VideoSource.Url;
vPlayer.url = url;
vPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource;
vPlayer.SetTargetAudioSource(, source); vPlayer.prepareCompleted += OnPrepared; vPlayer.Prepare();
} /// <summary>
/// 声音设置
/// </summary>
/// <param name="value"></param>
public void AdjustVolume(float value)
{
source.volume = value;
txtVolume.text = string.Format("{0:0}%", value * );
} /// <summary>
/// 调整进度
/// </summary>
/// <param name="value"></param>
public void AdjustVideoProgress(float value)
{
if (vPlayer.isPrepared)
{
vPlayer.time = (long)value;
time = (float)vPlayer.time;
hour = (int)time / ;
min = (int)time % ; txtProgress.text = string.Format("{0:D2}:{1:D2}", hour.ToString(), min.ToString());
}
} /// <summary>
/// 视频控制
/// </summary>
/// <param name="num"></param>
private void OnClick(int num)
{
switch (num)
{
case :
vPlayer.Play();
Time.timeScale = ;
break;
case :
vPlayer.Pause();
Time.timeScale = ;
break;
case :
sliderVideo.value = sliderVideo.value + numBer;
break;
case :
sliderVideo.value = sliderVideo.value - numBer;
break;
case :
vPlayer.Stop();
Init(urlNetWork);
break;
default:
break;
}
} void OnPrepared(VideoPlayer player)
{
player.Play();
sliderVideo.onValueChanged.AddListener(delegate { AdjustVideoProgress(sliderVideo.value); });
} void Update()
{
if (vPlayer.isPlaying && isShow)
{
rawImage.texture = vPlayer.texture;
//帧数/帧速率=总时长 如果是本地直接赋值的视频,我们可以通过VideoClip.length获取总时长
sliderVideo.maxValue = vPlayer.frameCount / vPlayer.frameRate; time = sliderVideo.maxValue;
hour = (int)time / ;
min = (int)time % ;
txtCurrentProgress.text = string.Format("/ {0:D2}:{1:D2}", hour.ToString(), min.ToString()); //sliderVideo.onValueChanged.AddListener(delegate { ChangeVideo(sliderVideo.value); });
isShow = !isShow;
} if (Mathf.Abs((int)vPlayer.time - (int)sliderVideo.maxValue) == )
{ vPlayer.frame = (long)vPlayer.frameCount;
vPlayer.Stop();
isVideo = false;
return;
}
else if(isVideo && vPlayer.isPlaying)
{
time_Count += Time.deltaTime; if ((time_Count - time_Current) >= )
{
sliderVideo.value += ;
time_Current = time_Count;
}
}
}
}
unity5.6.1 videoPlayer的更多相关文章
- VideoPlayer播放
播放网络视频.本地视频:可以暂停.前后拖动.快进.快退.音量调节.下一个视频 环境:Unity5.6以上 Unity正式发布了5.6版本后,作为5.x版本的最后一版还是有不少给力的更新的.其中新加入了 ...
- 被Unity5坑惨了
各种不明所以的crash,导致crash率从0.5%瞬间暴涨到10%. Unity5还是非常不稳定,慎入慎入...
- Unity5中WebGL平台封装的一些技巧
最近在接触unity的WebGL平台,其实这个平台作为Web Player的替代品,已经能满足大部分的开发需求,而且不需要额外的插件支持,确实方便了不少,但开发中依旧遇到了不少问题,在这里记录和共享一 ...
- 解决Unity5+Vuforia+Network本地联机发布到Android上白屏的问题
Unity5+Vuforia+Network本地联机,在Android下点击联机,然后识别模型就出现白屏,点击屏幕上相应位置的按钮(已白屏,但点击该看不见的按钮)还是能起作用,如跳转到其他场景正常. ...
- [自学总结] Unity5.3 API 之 Audio Mixer
unity5.3 - API - class AudioMixer 和 class AudioMixerGrou问题:之前版本声音的渐入渐出太生硬,声音的特效需要自己手动编写.分析:5.0版本重大更新 ...
- unity5.3 安卓广告插件打包出错的理解
今天打包带广告插件的安卓包,出现了问题 ,上网找了很多解决的办法.整理一下. 1,有的说法是unity5的BUG 因为同一个项目 用unity4.6打包就没问题 到5就出问题,当然 姑且可以这么认为 ...
- Unity5中的MetaPass
前些天烘焙lightmap的时候发现用自己写的Shader的模型在烘焙时候不会烘焙效果不对,它不会产生对周围物体的间接光照,但是我放到了unity4.x中就是没问题的.查了一番,发现Unity5中加了 ...
- unity5.0新功能-布料、动画系统
原作者:只待苍霞 这一章讲一下布料系统, 这次的布料系统有很大的改良.Unity4中, 需要对SkinnedMeshRenderer使用SkinnedCloth, 或者对Cloth Renderer使 ...
- unity5.0新功能
原作者 只待苍霞 章节1: 先来两个最关心的新功能, 第一章先讲PBS, 第二章讲光影GI.说到PBS, 首先应该想到的是Unity自带的两个新的Shader, 分别是Standard以及Standa ...
随机推荐
- python连接数据库查询
import sqlite3 as db conn = db.connect(r'D:/data/test.db') print ('Opend database successfully \n') ...
- 初识PE文件结构
前言 目前网络上有关PE文件结构说明的文章太多了,自己的这篇文章只是单纯的记录自己对PE文件结构的学习.理解和总结. 基础概念 PE(Portable Executable:可移植的执行体)是Win3 ...
- Janus安装教程,ubuntu18.04系统
Janus安装教程,ubuntu18.04系统 本文介绍Jansu如何安装,操作系统为Ubuntu 18.04. (1)安装git 执行命令:“sudo apt-get install ...
- Java 基础篇之异常
异常 异常层次 Error:Java 运行时系统的内部错误和资源耗尽错误.应用程序不应该抛出这种类型的对象.如果出现了这样的内部错误,除了通告给用户,并尽力使程序安全地终止之外,再也无能为力了. Ex ...
- 洛谷:P3950 部落冲突
原题地址:https://www.luogu.org/problemnew/show/P3950 题目简述 给定一棵树,每次给定一个操作,有如下两种: 将某条边染黑 2.询问给定的u,v两点间是否有边 ...
- vue-cli 脚手架安装
1.安装node;选择适合自己系统的文件,下载一路next , a安装成功后,打开运行输入cmd 进入命令行: 在命令行工具中输入 npm -v 检查版本号 如果出现 则安装成功:(npm为node ...
- WordPress 使用本地化的 emoji 表情包
WordPress 结合使用 Native Emoji 和 WP Local Emoji 两个插件,可以达到使用本地化的 emoji 表情包的目的. 安装好上述两个插件并且启用: 为了使 Native ...
- ef core实现无感知软删除
很多web程序一般的偶不会设计真的物理删除了. 基本上都是在在数据库加一个标记,就得当作已经删除了.同时在查询的时候,过滤已经标记删除的数据 ef core实现软删除是非常简单的,直接在OnModel ...
- 基于 H5 WebGL 的 3D 室内定位及电子围栏
前言 现代工业化的推进在极大加速现代化进程的同时也带来的相应的安全隐患,在传统的可视化监控领域,一般都是基于 Web SCADA 的前端技术来实现 2D 可视化监控,本系统采用 Hightopo 的 ...
- 纯CSS焦点轮播效果-功能可扩展
个人博客: http://mcchen.club 纯CSS3实现模拟焦点轮播效果,支持JQ等扩展各项功能.废话少说,直接贴代码. <!DOCTYPE html> <html> ...