我在脚本中添加了以下功能,这会导致整体崩溃。
public void AddCurrentFrameToVideo()
{
_addFrameFunctionHasBeenCalled = true;
using (var encoder = new MediaEncoder(encodedFilePath, videoAttr, audioAttr))
using (var audioBuffer = new NativeArray<float>(sampleFramesPerVideoFrame, Allocator.Temp))
{
IEnumerator SetFrame()
{
yield return new WaitForSeconds(0.3f);
encoder.AddFrame(tex);
encoder.AddSamples(audioBuffer);
if (recordingButtonHasBeenPressed)
{
yield return StartCoroutine(SetFrame());
}
else
{
yield return null;
yield break;
}
}
IEnumerator mycoroutine;
mycoroutine = SetFrame();
if (recordingButtonHasBeenPressed)
{
StartCoroutine(mycoroutine);
}
else
{
StopCoroutine(mycoroutine);
}
}
}
我在Update函数的if语句中调用此函数。看到:
void Update()
{
_currentsframe = Time.frameCount;
if (recordingButtonHasBeenPressed)
{
if (!videoBasicFileHasBeenCreated)
{
CreateVideoBasicFile();
}
if (!_addFrameFunctionHasBeenCalled)
{
AddCurrentFrameToVideo();
}
}
}
我还通过按钮recordingButtonHasBeenPressed
控制了另一个脚本中的OnClick()
变量。看到:
public void RecordVideo_OnClick()
{
if (videoIsRecording)
{
videoIsRecording = false;
videoRecordButton.image.sprite = videoButtonIsNotRecordingSprite;
_myRecorderSc.recordingButtonHasBeenPressed = false;
_myRecorderSc.videoBasicFileHasBeenCreated = false;
}
else
{
videoRecordButton.image.sprite = videoButtonIsRecordingSprite;
_myRecorderSc.recordingButtonHasBeenPressed = true;
_myRecorderSc.videoBasicFileHasBeenCreated = false;
videoIsRecording = true;
}
}
我不知道为什么它会崩溃。我不认为这是无限循环。
我还测试了DO-While
循环而不是使用Croutine
。看到:
using (var encoder = new MediaEncoder(encodedFilePath, videoAttr, audioAttr))
using (var audioBuffer = new NativeArray<float>(sampleFramesPerVideoFrame, Allocator.Temp))
{
do
{
encoder.AddFrame(tex);
encoder.AddSamples(audioBuffer);
} while (recordingButtonHasBeenPressed);
}
它也会导致统一崩溃。
我该怎么办?怎么了?
答案 0 :(得分:2)
此
IEnumerator SetFrame()
{
yield return new WaitForSeconds(0.3f);
encoder.AddFrame(tex);
encoder.AddSamples(audioBuffer);
if (recordingButtonHasBeenPressed)
{
yield return StartCoroutine(SetFrame());
}
}
是一个递归调用,其中您再次yield return
再次使用同一例程(内部yield return
再次使用相同的例程,依此类推),因此它将等待直到所有嵌套子例程都完成为止=>因此,在某些时候,您将得到一个StackOverflow!
这绝对是一个闭合的永不结束的while循环
using (var audioBuffer = new NativeArray<float>(sampleFramesPerVideoFrame, Allocator.Temp))
{
do
{
encoder.AddFrame(tex);
encoder.AddSamples(audioBuffer);
} while (recordingButtonHasBeenPressed);
}
在循环中,recordingButtonHasBeenPressed
的值将从不更改,并且Unity /您的应用立即永久冻结!
您想要做的将是像协程这样的
IEnumerator SetFrame()
{
// initially wait once
yield return new WaitForSeconds(0.3f);
// simply continue to execute the routine until the record shall be stopped
while(recordingButtonHasBeenPressed)
{
encoder.AddFrame(tex);
encoder.AddSamples(audioBuffer);
// yield the next frames for 0.3 seconds before checking
// recordingButtonHasBeenPressed again
yield return new WaitForSeconds(0.3f);
}
}
您甚至不需要主动停止它。您需要做的就是启动它,然后为了中断它,只需将recordingButtonHasBeenPressed
设置为false
。
由事件驱动吗
现在,通常不再使用Update
和多个控制器标志bool
,而是在这里调用方法后立即立即重设,我宁愿使整个代码成为事件驱动,并在调用按钮时调用一次。这样可以防止并发例程意外运行,并使整个方法更易于阅读和维护。
我不知道您的完整代码,但可能看起来像
public void RecordVideo_OnClick()
{
// invert the toggle flag
videoIsRecording = !videoIsRecording;
// depending on the new flag value chose the sprite
videoRecordButton.image.sprite = videoIsRecording ? videoButtonIsRecordingSprite : videoButtonIsNotRecordingSprite;
if (!videoIsRecording)
{
_myRecorderSc.StopRecording();
}
else
{
_myRecorderSc.StartRecoring();
}
}
,然后在记录器脚本中,您只需要
public void StartRecording()
{
if(!recording)
{
StartCoroutine(RecorderRoutine);
}
}
public void StopRecording()
{
recording = false;
}
// flag to interrupt running record
private bool recording;
private IEnumerator RecorderRoutine()
{
// Just in case prevent concurrent routines
if(recording) yield break;
recording = true;
// initialize your file
CreateVideoBasicFile();
// initially wait once
yield return new WaitForSeconds(0.3f);
using (var encoder = new MediaEncoder(encodedFilePath, videoAttr, audioAttr))
using (var audioBuffer = new NativeArray<float>(sampleFramesPerVideoFrame, Allocator.Temp))
{
// simply continue to execute the routine until the record shall be stopped
while(recording)
{
encoder.AddFrame(tex);
encoder.AddSamples(audioBuffer);
// yield the next frames for 0.3 seconds before checking
// recordingButtonHasBeenPressed again
yield return new WaitForSeconds(0.3f);
}
}
recording = false;
}