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 ...
随机推荐
- Flutter免费(视频)教程汇总
Flutter学习导航 Flutter简介: Flutter可以轻松快速地构建漂亮的移动应用程序. Flutter是谷歌的移动应用SDK,用于短时间内在iOS和Android上制作高质量的原生界面应用 ...
- HTML5-常用正则表达式
有关H5正则表达式的一些常用式子,希望热爱编程的同学们多多指教,还有也希望可以关注收藏本站哦!❤^_^❤ 一.校验数字的表达式 1. 数字:^[0-9]*$ 2. n位的数字:^\d{n}$ 3. 至 ...
- <<构建之法第三版>>读书遇到的5个问题
1.书中第4章4.5节所说的结对编程让我感觉有一点困惑,书中书写的是结对编程,说实话我是第一次接触这个词汇,我能感到这种方式的新特之处,但是对比我现实的编程经历,我很难想象在一般的企业开发中这样的行为 ...
- Spark 学习笔记之 aggregateByKey
aggregateByKey: import org.apache.spark.SparkContext import org.apache.spark.rdd.RDD import org.apac ...
- Java 学习笔记之 线程Yield
线程Yield: yield()方法的作用是放弃当前的CPU资源,将它让给其他的任务去占用CPU执行时间,但放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片. public class Yie ...
- liunx下安装MySQL
1.安装依赖包:yum -y install gcc gcc-c++ ncurses ncurses-devel cmake bisonyum install -y perl-Module-Insta ...
- python编程基础之十七
字符串:str1 = '123' str2 ="123" str3 = """123""" str4 = '''123' ...
- GDB使用总结
1. GDB概述 GNU发布的调试器,可以查看程序如何运行或崩溃时的状态. 主要功能: 启动程序,可以按照自定义的要求运行程序. 可让被调试的程序在你所指定的断点处停住. 当程序被停住时,可以检查此时 ...
- 古剑奇谭三已取消该页导航,B站版本无法登陆
最近登陆古剑三突然出现这个问题 怎么重开也无法登陆 最后发现是Ie设置问题 解决方法 点中间这个圆形图标打开 小娜 搜索“ie” 点击打开ie之后点右上角的小齿轮 选择“internet选项” 连接- ...
- Tomcat基本知识(一)
顶层架构先上一张Tomcat的顶层结构图(图A),如下: Tomcat中最顶层的容器是Server,代表着整个服务器,从上图中可以看出,一个Server可以包含至少一个Service,用于具体提供服务 ...