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 ...
随机推荐
- 数据分析--pandas的基本使用
一.pandas概述 1.pandas是一个强大的Python数据分析的工具包,是基于NumPy构建的. 2.pandas的主要功能 具备对其功能的数据结构DataFrame.Series 集成时间序 ...
- C#刷遍Leetcode面试题系列连载(1) - 入门与工具简介
目录 为什么要刷LeetCode 刷LeetCode有哪些好处? LeetCode vs 传统的 OJ LeetCode刷题时的心态建设 C#如何刷遍LeetCode 选项1: VS本地Debug + ...
- windows下配置多个tomcat步骤
步骤如下: 1.使用压缩版的tomcat不能使用安装版的.2.第一个tomcat的配置不变.3.增加环境变量CATALINA_HOME2,值为新的tomcat的地址:增加环境变量CATALINA_BA ...
- git 查看分支
1.查看本地分支 git branch 2.查看所有分支 git branch -a 2.查看所有分支及对应版本信息 git branch -va
- Python3编码解码url
python2和python3对于url的解码和编码 某天做爬虫时遇到一个post请求的参数是编码过的字符串如下,看不懂,初步判断可能是url编码 str = "%7B%22Shopping ...
- .Net Core 商城微服务项目系列(十三):搭建Log4net+ELK+Kafka日志框架
之前是使用NLog直接将日志发送到了ELK,本篇将会使用Docker搭建ELK和kafka,同时替换NLog为Log4net. 一.搭建kafka 1.拉取镜像 //下载zookeeper docke ...
- 文件操作——RandomAccessFile
文件操作——RandomAccessFile 构建RandomAccessFileJava提供了一个可以对文件随机访问的操作,访问包括读和写操作.该类名为RandomAccessFile.该类的读 ...
- Linux被中断的系统调用
慢系统调用,指的是可能永远无法返回,从而使进程永远阻塞的系统调用,比如无客户连接时的accept.无输入时的read都属于慢速系统调用. 在Linux中,当阻塞于某个慢系统调用的进程捕获一个信号,则该 ...
- 利用shell脚本个性化运行jar任务
利用shell脚本可以个性化运行jar任务,废话不多说,直接上代码: #!/bin/bash APP_PATH=/root/bigdata/jars/data_migration_from_sqlse ...
- java第1天:简介,入门程序,变量,常量
1 java语言简介 美国的SUN公司开发的静态面向对象的编程语言,后来被甲骨文公司收购,现在也是全球范围内最受欢迎的编程语言. *** 2 计算机进制的相互转换 进制 英文代号 2进制 bin 8进 ...