簡體   English   中英

協程導致統一崩潰

[英]Coroutine causes crash in unity

我在我的腳本中添加了以下 function 並導致統一崩潰。

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);
        }

    }

}

我在更新 function 的 if 語句中將此稱為 function。 看:

void Update()
{
    _currentsframe = Time.frameCount;

    if (recordingButtonHasBeenPressed)
    {
        if (!videoBasicFileHasBeenCreated)
        {
            CreateVideoBasicFile();
        }

        if (!_addFrameFunctionHasBeenCalled)
        {
            AddCurrentFrameToVideo();
        }

    }

}

我還通過按鈕OnClick()在另一個腳本中控制了recordingButtonHasBeenPressed變量。 看:

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);
    }

它也會導致團結崩潰。

我應該怎么辦? 它出什么問題了?

這個

    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和多個 controller 標志bool s,一旦在此處調用方法,您似乎會立即再次重置,我寧願在調用按鈕時驅動整個代碼事件並調用一次 這將防止意外運行並發例程,並使整個事情更好地閱讀和維護。

我不知道你的完整代碼,但它可能看起來像

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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM