我在我的脚本中添加了以下函数,但它在unity中导致崩溃。
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;
}
}
我不知道为什么会让unity崩溃. 我不认为这是一个无限循环.此外,我还测试了一个。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);
}
它也会导致unity崩溃.
我应该怎么办?它有什么问题?
这个
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你的应用会立即永远冻结。
你想做的是像Coroutine这样的程序。
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;
}