Questions about VideoPlayer - unity3d

Why does video player's frame count change at the end of playback? How can I determine the end of playback? Can only be implemented in the following way?
if ((ulong)GetComponent<VideoPlayer>().frame >= GetComponent<VideoPlayer>().frameCount-1)
{
Debug.Log("VideoPlayer play完毕");
}
When it starts playing
Warning message:
First video frame not zero: 2 (0.066667s). Result may be out of sync. Please make sure tracks all start at 0 in D:/xxx.mp4

You can reliably check if videoplayer is playing by querying its .isPlaying property
IEnumerator VideoPlayerCheck()
{
var vp=GetComponent<VideoPlayer>();
vp.Play();
while (!vp.isPlaying)
{
Debug.Log("Playback not started");
yield return null;
}
while (vp.isPlaying)
{
Debug.Log("Playing");
yield return null;
}
Debug.Log("Playback stopped");
}

Related

Web audio playback contains clicks

I am trying to build a midi player using web audio API. I used tonejs to parse midi file into JSON. I am using mp3 files to play notes. Following are the relevant parts of the code:
//create audio samples
static async setupSample(audioContext, filepath) {
const response = await fetch(filepath);
const arrayBuffer = await response.arrayBuffer();
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
return audioBuffer;
}
//play a single sample
static playSample(audioContext, audioBuffer, time) {
const sampleSource = new AudioBufferSourceNode(audioContext, {
buffer: audioBuffer,
playbackRate: 1,
});
sampleSource.connect(audioContext.destination);
sampleSource.start(time);
return sampleSource;
}
Scheduling samples:
async start() {
this.startTime = this.audioCtx.currentTime;
this.play();
}
play() {
let nextNote = this.notes[this.noteIndex];
//schedule samples
while ((nextNote.time + this.startTime) - this.audioCtx.currentTime <= 0.250) {
let s = Audio.playSample(this.audioCtx, this.samples[nextNote.midi], this.startTime + nextNote.time);
s.stop(this.startTime + nextNote.time + nextNote.duration);
this.noteIndex++;
if (this.noteIndex == this.notes.length) {
break;
}
nextNote = this.notes[this.noteIndex];
}
if (this.noteIndex == this.notes.length) {
return;
}
requestAnimationFrame(() => {
this.play();
});
}
I am testing code with a midi file which contains C major scale. I have tested the midi file using timidity and it is fine.
The code does play the midi file correctly execpet a small problem: I hear some clicking sounds during playback. The clicking increases with increasing tempo but does not completely go away even with tempo as small as 50bpm. Any ideas what could be going wrong?
Full code can be viewed at : https://test.meedee.in/
Nothing is "wrong". You are observing a phenomenon intrinsic to the physics of audio.
Chopping audio samples arbitrarily like this creates clicks at the transitions. Any instantaneous change in level is heard as a click. To get rid of the clicks, apply an envelope to the sample, blend adjacent notes, or apply a low-pass filter.

Cant get video progress time in Flutter better player

I am building a video player app in flutter with better video player. All things are working fine with better player except that i cant get the video player progress(time of how much the video has been played) in better player and i also want to get the total time of the video too. Does anyone has any idea of how to get the video progress with it.. it will be helpfull with an example.
You can set the listener in BetterPlayerConfiguration, than you can get video duration and progress using event.parameters. Please, see the example below:
BetterPlayerConfiguration get _betterPlayerConfiguration => BetterPlayerConfiguration(
eventListener: _onPlayerEvent,
);
void _onPlayerEvent(BetterPlayerEvent event) {
if (_checkIfCanProcessPlayerEvent(event)) {
Duration progress = event.parameters!['progress'];
Duration duration = event.parameters!['duration'];
}
}
bool _checkIfCanProcessPlayerEvent(BetterPlayerEvent event) {
return
event.betterPlayerEventType == BetterPlayerEventType.progress &&
event.parameters != null &&
event.parameters!['progress'] != null &&
event.parameters!['duration'] != null;
}
you can get control of all events in better player after you create betterplayercontroller like this
_betterPlayerController!.addEventsListener((event) {
if (event.betterPlayerEventType == BetterPlayerEventType.finished) {
LessonRepo.completeVideo(lessonID: lessonID);
}
});
Duration myProgress;
_betterPlayerController.addEventsListener((event) => {
if (event.betterPlayerEventType == BetterPlayerEventType.progress) {
myProgress = event.parameters['progress']
},
}

UnityWebRequest does not complete [duplicate]

I'm trying to use a cloud TTS within my Unity game.
With the newer versions (I am using 2019.1), they have deprecated WWW in favour of UnityWebRequest(s) within the API.
I have tried the Unity Documentation, but that didn't work for me.
I have also tried other threads and they use WWW which is deprecated for my Unity version.
void Start()
{
StartCoroutine(PlayTTS());
}
IEnumerator PlayTTS()
{
using (UnityWebRequestMultimedia wr = new UnityWebRequestMultimedia.GetAudioClip(
"https://example.com/tts?text=Sample%20Text&voice=Male",
AudioType.OGGVORBIS)
)
{
yield return wr.Send();
if (wr.isNetworkError)
{
Debug.LogWarning(wr.error);
}
else
{
//AudioClip ttsClip = DownloadHandlerAudioClip.GetContent(wr);
}
}
}
The URL in a browser (I used Firefox) successfully loaded the audio clip allowing me to play it.
What I want it to do is play the TTS when something happens in the game, it has been done within the "void Start" for testing purposes.
Where am I going wrong?
Thanks in advance
Josh
UnityWebRequestMultimedia.GetAudioClip automatically adds a default DownloadHandlerAudioClip which has a property streamAudio.
Set this to true and add a check for UnityWebRequest.downloadedBytes in order to delay the playback before starting.
Something like
public AudioSource source;
IEnumerator PlayTTS()
{
using (var wr = new UnityWebRequestMultimedia.GetAudioClip(
"https://example.com/tts?text=Sample%20Text&voice=Male",
AudioType.OGGVORBIS)
)
{
((DownloadHandlerAudioClip)wr.downloadHandler).streamAudio = true;
wr.Send();
while(!wr.isNetworkError && wr.downloadedBytes <= someThreshold)
{
yield return null;
}
if (wr.isNetworkError)
{
Debug.LogWarning(wr.error);
}
else
{
// Here I'm not sure if you would use
source.PlayOneShot(DownloadHandlerAudioClip.GetContent(wr));
// or rather
source.PlayOneShot((DownloadHandlerAudioClip)wr.downloadHandler).audioClip);
}
}
}
Typed on smartphone so no warranty but I hope you get the idea

Unity: LoadScene does not work when fired from timer

in my game, when the player dies, a dying sound is played and once the sound is over, the scene is supposed to be reloaded when the user still has enough lives.
Before I had the sound, the play died instantly upon calling the death() function:
public static void Death()
{
AddCoinScript.coinCounter = 0;
LivesScript.livesCounter--;
if (LivesScript.livesCounter > -1)//to get 0 live
{
Debug.Log("TIMER");
var currentScene = SceneManager.GetActiveScene();
SceneManager.LoadScene(currentScene.name);
}
else
{
//TO DO GameOver
}
}
This worked like a charm.
But now I added a death sound to it. Unfortunately, unity doesnt provide an event handler for when the sound is done playing (I want the scene to be reloaded not instantly anymore, but after the death sound is done playing), so I have decided to take it upon myself to just build a timer. The timer fires right after the death sound is over. This is what this function has become:
public static void Death()
{
AddCoinScript.coinCounter = 0;
LivesScript.livesCounter--;
PlayDeathSound();
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = aSDeath.clip.length * 1000;
timer.Start();
timer.Elapsed += delegate
{
timer.Stop();
if (LivesScript.livesCounter > -1)//to get 0 live
{
Debug.Log("TIMER");
var currentScene = SceneManager.GetActiveScene();
SceneManager.LoadScene(currentScene.name);
}
else
{
//TO DO GameOver
}
};
}
As you can see, to make sure the timer REALLY fires, I set up a "debug.Log("TIMER")" to see, if it really works. And guess what: it does. The debug now shows "TIMER" in its console. But you know what doesnt work anymore? The two lines of code right beneath that.
var currentScene = SceneManager.GetActiveScene();
SceneManager.LoadScene(currentScene.name);
It's the same exact lines that worked just before - but when fired from the timer, they just get ignored? How is this even possible?
When I change it all back, it works again. Only when the timer fires the two lines, they get ignored.
This is totally odd or am I missing something? Thank you!
Okay I am not an expert on C# and delegate but apparently it creates a separate thread and you can only use SceneManager.GetActiveScene on main thread.
Since i am not so sure about delegate i will offer an easier solution. You can use a coroutine since you know how much you have to wait like this:
public void Death()
{
StartCoroutine(DeathCoroutine());
}
IEnumerator DeathCoroutine()
{
AddCoinScript.coinCounter = 0;
LivesScript.livesCounter--;
PlayDeathSound();
// wait for duration of the clip than continue executing rest of the code
yield return new WaitForSeconds(aSDeath.clip.length);
if (LivesScript.livesCounter > -1)//to get 0 live
{
Debug.Log("TIMER");
var currentScene = SceneManager.GetActiveScene();
SceneManager.LoadScene(currentScene.name);
}
else
{
//TO DO GameOver
}
}
What about using a coroutine ? You just start it when the player dies, and yield while your sound is still playing.

Can't stop audio playback on iOS with Codename One

My Codename One app features audio playback in the background when the user taps the screen. The audio I use is an mp3. Here is how I use the Media playback :
public static void playSound(boolean stop) {
sound.reset(); // The input stream needs to go back to the beginning
Media myClip = MediaManager.createMedia(sound, "audio/mp3", () -> {
// If there is no order to stop playback, we keep playing when it has completed (looping)
playSound(false);
});
if (!stop) {
myClip.play();
} else {
myClip.cleanup();
}
}
So hen the user taps the screen components change and I pass true to playSound method. On Android the current playback stops not on iOS with an iPhone 4.
Please note that when the app gets minimized (center button pressed) the playback stops (even if I don't call cleanup() on the Media which I do on Android to stop the playback when the app is minimized).
How can I stop the playback on iPhone ?
Any help appreciated,
#Shai pointed me to the right direction so here is the code finally used :
Media myClip = null;
public static void playSound(boolean stop) {
sound.reset(); // The input stream needs to go back to the beginning
/**
* If the media is playing we don't create it
* otherwise we would have several media in the wild
* that could not be stopped
*/
if (myClip == null || !myClip.isPlaying()) {
myClip = MediaManager.createMedia(sound, "audio/mp3", () -> {
// If there is no order to stop playback, we keep playing when it has completed (looping)
playSound(false);
});
}
if (!stop) {
myClip.play();
} else {
myClip.cleanup();
}
}