- Home /
How to alternate two VideoPlayer objects to loop a video
Here below is a class I use to loop a video smoothly:
using System.Collections;
using UnityEngine;
using UnityEngine.Video;
public class MegaPlayer : MonoBehaviour
{
private VideoPlayer[] players;
public RenderTexture targetTexture;
public string url;
void Awake()
{
players = gameObject.GetComponentsInChildren<VideoPlayer>();
for (int i = 0; i < players.Length; i++) {
players[i].source = VideoSource.Url;
players[i].url = url;
players[i].playOnAwake = false;
players[i].waitForFirstFrame = true;
players[i].isLooping = false;
players[i].skipOnDrop = true;
players[i].targetTexture = targetTexture;
}
}
void Start()
{
StartCoroutine(Play(0));
}
IEnumerator Play(int activePlayer)
{
// wait until the video is ready
players[activePlayer].Prepare();
while (!players[activePlayer].isPrepared) {
yield return null;
}
// wait until the current video ends
while (players[activePlayer ^1].isPlaying) {
yield return null;
}
players[activePlayer].Play();
// wait until the current video has not finished
int nextPlayer = activePlayer ^ 1;
while (players[activePlayer].isPlaying) {
if (players[activePlayer].time >= (players[activePlayer].length / 2)) {
players[nextPlayer].time = 0f;
break;
}
yield return null;
}
StartCoroutine(Play(nextPlayer));
}
}
I use two VideoPlayer
that alternate in playing the same video to reproduce a smooth loop without the short break you hear when using the isLooping
property.
The coroutine works 2 times, i.e. each VideoPlayer
plays the video as expected... then, the third time, the image remains freezed at the first frame (but the video still works in the background as I hear the musing going). Then, the fourth time the video plays correctly again, and so on. Long story short, after the first two iterations that work fine, the video is played once yes and once no.
Answer by timehunter · Mar 04, 2021 at 06:53 AM
Finally I found where the problem was... I forgot to set the texture of the render area before I start the player at line 77. Here below is the working version:
#region References
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Video;
#endregion
/// <summary>
/// Provides functionality for playing videos in seamless loops.
/// </summary>
public class PlayerManager : MonoBehaviour
{
#region Fields
private RawImage renderArea;
private VideoPlayer[] players;
private double twoThirdOfTheWay;
public string url;
public float overlappingLength = .3f;
#endregion
#region Methods
/// <summary>
/// Called when this script instance is being loaded.
/// </summary>
void Awake()
{
Texture texture = GetComponent<RawImage>().texture;
RenderTexture targetTexture = new RenderTexture(texture.width, texture.height, 0);
Graphics.Blit(texture, targetTexture);
players = gameObject.GetComponentsInChildren<VideoPlayer>();
for (int i = 0; i < players.Length; i++) {
players[i].source = VideoSource.Url;
players[i].url = url;
players[i].playOnAwake = false;
players[i].waitForFirstFrame = true;
players[i].isLooping = false;
players[i].skipOnDrop = true;
players[i].targetTexture = targetTexture;
}
renderArea = GetComponent<RawImage>();
twoThirdOfTheWay = (players[0].length / 3d) * 2d;
}
/// <summary>
/// Called before the first frame update.
/// </summary>
void Start()
{
StartCoroutine(Play(0));
}
/// <summary>
/// Lets the specified player playback the video referenced by <see cref="url"/>.
/// </summary>
/// <param name="activePlayer">The player to start.</param>
IEnumerator Play(int activePlayer)
{
// wait until the video is ready
if (!players[activePlayer].isPrepared) {
players[activePlayer].Prepare();
while (!players[activePlayer].isPrepared) {
yield return null;
}
}
int otherPlayer = activePlayer ^ 1;
// wait until the previous playback reaches the overlapping interval
while (players[otherPlayer].isPlaying && players[otherPlayer].time < (players[otherPlayer].length - overlappingLength)) {
yield return null;
}
// associate the render area with the active player and start the playback
renderArea.texture = players[activePlayer].texture;
players[activePlayer].Play();
// let the previous playback end and stop the player
yield return new WaitForSeconds(overlappingLength);
players[otherPlayer].Stop();
// wait until the current playback is 2/3 of the way and then let the other player start
while (players[activePlayer].isPlaying) {
if (players[activePlayer].time >= twoThirdOfTheWay) {
players[otherPlayer].time = 0f;
break;
}
yield return null;
}
StartCoroutine(Play(otherPlayer));
}
#endregion
}
I hope it helps also someone else :-)
Your answer
Follow this Question
Related Questions
How do you prevent looping video from flashing at loop point? 2 Answers
Why does Video Player render black on Android with Multithreading Off? 0 Answers
Can handheld.PlayfullScreenMovie() work with Vr view to play 360 degree video using google vr sdk? 0 Answers
Cannot import video of any type in Ubuntu Unity 5.6.1xf1 1 Answer
How to loop a video seamless 1 Answer