88using OpenCVForUnity . UnityUtils . Helper ;
99using System ;
1010using System . Collections ;
11+ using System . Threading ;
12+ using System . Threading . Tasks ;
1113using UnityEngine ;
1214using UnityEngine . SceneManagement ;
1315using UnityEngine . UI ;
@@ -128,8 +130,9 @@ public class VideoRecordingExample : MonoBehaviour
128130
129131 IClock recordingClock ;
130132
131- const float MAX_RECORDING_TIME = 10f ;
132- // Seconds
133+ CancellationTokenSource cancellationTokenSource ;
134+
135+ const int MAX_RECORDING_TIME = 10 ; // Seconds
133136
134137 string videoPath = "" ;
135138
@@ -139,6 +142,8 @@ public class VideoRecordingExample : MonoBehaviour
139142
140143 bool isVideoRecording ;
141144
145+ bool isFinishWriting ;
146+
142147 int frameCount ;
143148
144149 int recordEveryNthFrame ;
@@ -253,7 +258,7 @@ public void OnWebCamTextureToMatHelperDisposed()
253258 {
254259 Debug . Log ( "OnWebCamTextureToMatHelperDisposed" ) ;
255260
256- StopRecording ( ) ;
261+ CancelRecording ( ) ;
257262 StopVideo ( ) ;
258263
259264 if ( texture != null )
@@ -283,7 +288,7 @@ void Update()
283288 if ( applyComicFilter )
284289 comicFilter . Process ( rgbaMat , rgbaMat ) ;
285290
286- if ( isVideoRecording )
291+ if ( isVideoRecording && ! isFinishWriting )
287292 {
288293 textPos . x = 5 ;
289294 textPos . y = rgbaMat . rows ( ) - 70 ;
@@ -313,7 +318,7 @@ void Update()
313318 Utils . fastMatToTexture2D ( rgbaMat , texture ) ;
314319
315320 // Record frames
316- if ( videoRecorder != null && isVideoRecording && frameCount ++ % recordEveryNthFrame == 0 )
321+ if ( videoRecorder != null && ( isVideoRecording && ! isFinishWriting ) && frameCount ++ % recordEveryNthFrame == 0 )
317322 {
318323 videoRecorder . CommitFrame ( ( IntPtr ) rgbaMat . dataAddr ( ) , recordingClock . timestamp ) ;
319324 }
@@ -325,9 +330,9 @@ void Update()
325330 }
326331 }
327332
328- private void StartRecording ( )
333+ private async Task StartRecording ( )
329334 {
330- if ( isVideoPlaying || isVideoRecording )
335+ if ( isVideoPlaying || isVideoRecording || isFinishWriting )
331336 return ;
332337
333338 Debug . Log ( "StartRecording ()" ) ;
@@ -344,7 +349,7 @@ private void StartRecording()
344349 videoBitrate = ( int ) ( 960 * 540 * 11.4f ) ;
345350 frameDuration = 0.1f ;
346351
347- // Start recording
352+ // Create video recorder
348353 recordingClock = new RealtimeClock ( ) ;
349354 if ( container == ContainerPreset . MP4 )
350355 {
@@ -387,73 +392,125 @@ private void StartRecording()
387392 }
388393 frameCount = 0 ;
389394
395+
396+
397+ // Start recording
398+ isVideoRecording = true ;
399+
400+ HideAllVideoUI ( ) ;
401+ recordVideoButton . interactable = true ;
402+ recordVideoButton . GetComponentInChildren < UnityEngine . UI . Text > ( ) . color = Color . red ;
403+
404+ CreateSettingInfo ( ) ;
405+
390406 // Start microphone and create audio input
391407 if ( recordMicrophoneAudio )
392408 {
393- StartMicrophone ( ) ;
409+ await StartMicrophone ( ) ;
394410 audioInput = new AudioInput ( videoRecorder , recordingClock , microphoneSource , true ) ;
395411 }
396412
397- StartCoroutine ( "Countdown" ) ;
413+ // Start countdown
414+ cancellationTokenSource = new CancellationTokenSource ( ) ;
415+ try
416+ {
417+ Debug . Log ( "Countdown start." ) ;
418+ await CountdownAsync (
419+ sec =>
420+ {
421+ string str = "Recording" ;
422+ for ( int i = 0 ; i < sec ; i ++ )
423+ {
424+ str += "." ;
425+ }
398426
399- HideAllVideoUI ( ) ;
400- recordVideoButton . interactable = true ;
401- recordVideoButton . GetComponentInChildren < UnityEngine . UI . Text > ( ) . color = Color . red ;
427+ if ( fpsMonitor != null ) fpsMonitor . consoleText = str ;
402428
403- CreateSettingInfo ( ) ;
429+ } , MAX_RECORDING_TIME , cancellationTokenSource . Token ) ;
430+ Debug . Log ( "Countdown end." ) ;
431+ }
432+ catch ( OperationCanceledException e )
433+ {
434+ if ( e . CancellationToken == cancellationTokenSource . Token )
435+ {
436+ Debug . Log ( "Countdown canceled." ) ;
437+ }
438+ }
439+ cancellationTokenSource . Dispose ( ) ;
440+ cancellationTokenSource = null ;
404441
405- isVideoRecording = true ;
442+ if ( this != null && isActiveAndEnabled )
443+ await FinishRecording ( ) ;
406444 }
407445
408- private void StartMicrophone ( )
446+ private void CancelRecording ( )
409447 {
410- // Create a microphone clip
411- microphoneSource . loop = true ;
412- microphoneSource . bypassEffects =
413- microphoneSource . bypassListenerEffects = false ;
414- microphoneSource . clip = Microphone . Start ( null , true , ( int ) MAX_RECORDING_TIME , ( int ) microphoneFrequency ) ;
415- while ( Microphone . GetPosition ( null ) <= 0 ) { }
416- microphoneSource . Play ( ) ;
448+ if ( ! isVideoRecording || isFinishWriting )
449+ return ;
450+
451+ if ( cancellationTokenSource != null )
452+ cancellationTokenSource . Cancel ( true ) ;
417453 }
418454
419- private async void StopRecording ( )
455+ private async Task FinishRecording ( )
420456 {
421- if ( ! isVideoRecording )
457+ if ( ! isVideoRecording || isFinishWriting )
422458 return ;
423459
424- isVideoRecording = false ;
425-
426- Debug . Log ( "StopRecording ()" ) ;
427-
428- StopCoroutine ( "Countdown" ) ;
429- if ( fpsMonitor != null )
430- {
431- fpsMonitor . consoleText = "" ;
432- }
433-
434460 // Stop the microphone if we used it for recording
435461 if ( recordMicrophoneAudio )
436462 {
437463 StopMicrophone ( ) ;
438464 audioInput . Dispose ( ) ;
439465 }
440466
467+ if ( fpsMonitor != null ) fpsMonitor . consoleText = "FinishWriting..." ;
468+
441469 // Stop recording
470+ isFinishWriting = true ;
442471 try
443472 {
444473 var path = await videoRecorder . FinishWriting ( ) ;
445474 videoPath = path ;
446475 Debug . Log ( "Saved recording to: " + videoPath ) ;
447476 savePathInputField . text = videoPath ;
448477 }
449- catch ( Exception e )
478+ catch ( ApplicationException e )
450479 {
451480 Debug . Log ( e . Message ) ;
452481 savePathInputField . text = e . Message ;
453482 }
483+ isFinishWriting = false ;
484+
485+ if ( fpsMonitor != null ) fpsMonitor . consoleText = "" ;
454486
455487 ShowAllVideoUI ( ) ;
456488 recordVideoButton . GetComponentInChildren < UnityEngine . UI . Text > ( ) . color = Color . black ;
489+
490+ isVideoRecording = false ;
491+ }
492+
493+ private Task < bool > StartMicrophone ( )
494+ {
495+ var task = new TaskCompletionSource < bool > ( ) ;
496+ StartCoroutine ( CreateMicrophone ( granted =>
497+ {
498+ microphoneSource . Play ( ) ;
499+ task . SetResult ( granted ) ;
500+ } ) ) ;
501+
502+ return task . Task ;
503+ }
504+
505+ private IEnumerator CreateMicrophone ( Action < bool > completionHandler )
506+ {
507+ // Create a microphone clip
508+ microphoneSource . loop = true ;
509+ microphoneSource . bypassEffects =
510+ microphoneSource . bypassListenerEffects = false ;
511+ microphoneSource . clip = Microphone . Start ( null , true , MAX_RECORDING_TIME , ( int ) microphoneFrequency ) ;
512+ yield return new WaitUntil ( ( ) => Microphone . GetPosition ( null ) > 0 ) ;
513+ completionHandler ( true ) ;
457514 }
458515
459516 private void StopMicrophone ( )
@@ -463,31 +520,22 @@ private void StopMicrophone()
463520 Microphone . End ( null ) ;
464521 }
465522
466- private IEnumerator Countdown ( )
523+ private async Task CountdownAsync ( Action < int > countdownHandler , int sec = 10 , CancellationToken cancellationToken = default ( CancellationToken ) )
467524 {
468- float startTime = Time . time ;
469- while ( ( Time . time - startTime ) < MAX_RECORDING_TIME )
525+ for ( int i = sec ; i > 0 ; i -- )
470526 {
471-
472- if ( fpsMonitor != null )
473- {
474- string str = "Recording" ;
475- for ( int i = 0 ; i < ( int ) ( MAX_RECORDING_TIME - ( Time . time - startTime ) ) ; i ++ )
476- {
477- str += "." ;
478- }
479- fpsMonitor . consoleText = str ;
480- }
481-
482- yield return new WaitForSeconds ( 0.5f ) ;
527+ cancellationToken . ThrowIfCancellationRequested ( ) ;
528+ countdownHandler ( i ) ;
529+ await Task . Delay ( 1000 , cancellationToken ) ;
483530 }
484-
485- StopRecording ( ) ;
531+ cancellationToken . ThrowIfCancellationRequested ( ) ;
532+ countdownHandler ( 0 ) ;
486533 }
487534
535+
488536 private void PlayVideo ( string path )
489537 {
490- if ( isVideoPlaying || isVideoRecording || string . IsNullOrEmpty ( path ) )
538+ if ( isVideoPlaying || isVideoRecording || isFinishWriting || string . IsNullOrEmpty ( path ) )
491539 return ;
492540
493541 Debug . Log ( "PlayVideo ()" ) ;
@@ -517,7 +565,7 @@ private void PlayVideo(string path)
517565
518566 private void PrepareCompleted ( VideoPlayer vp )
519567 {
520- Debug . Log ( "PrepareCompleted" ) ;
568+ Debug . Log ( "PrepareCompleted () " ) ;
521569
522570 vp . prepareCompleted -= PrepareCompleted ;
523571
@@ -528,9 +576,7 @@ private void PrepareCompleted(VideoPlayer vp)
528576
529577 private void EndReached ( VideoPlayer vp )
530578 {
531- Debug . Log ( "EndReached" ) ;
532-
533- videoPlayer . loopPointReached -= EndReached ;
579+ Debug . Log ( "EndReached ()" ) ;
534580
535581 StopVideo ( ) ;
536582 }
@@ -542,16 +588,19 @@ private void StopVideo()
542588
543589 Debug . Log ( "StopVideo ()" ) ;
544590
591+ videoPlayer . loopPointReached -= EndReached ;
592+
545593 if ( videoPlayer . isPlaying )
546594 videoPlayer . Stop ( ) ;
547595
548- gameObject . GetComponent < Renderer > ( ) . sharedMaterial . mainTexture = texture ;
549-
550- webCamTextureToMatHelper . Play ( ) ;
551-
552596 isVideoPlaying = false ;
553597
554- ShowAllVideoUI ( ) ;
598+ if ( this != null && isActiveAndEnabled )
599+ {
600+ gameObject . GetComponent < Renderer > ( ) . sharedMaterial . mainTexture = texture ;
601+ webCamTextureToMatHelper . Play ( ) ;
602+ ShowAllVideoUI ( ) ;
603+ }
555604 }
556605
557606 private void ShowAllVideoUI ( )
@@ -717,20 +766,20 @@ public void OnRecordMicrophoneAudioToggleValueChanged()
717766 /// <summary>
718767 /// Raises the record video button click event.
719768 /// </summary>
720- public void OnRecordVideoButtonClick ( )
769+ public async void OnRecordVideoButtonClick ( )
721770 {
722771 Debug . Log ( "OnRecordVideoButtonClick ()" ) ;
723772
724773 if ( isVideoPlaying )
725774 return ;
726775
727- if ( isVideoRecording )
776+ if ( ! isVideoRecording && ! isFinishWriting )
728777 {
729- StopRecording ( ) ;
778+ await StartRecording ( ) ;
730779 }
731780 else
732781 {
733- StartRecording ( ) ;
782+ CancelRecording ( ) ;
734783 }
735784 }
736785
@@ -741,7 +790,7 @@ public void OnPlayVideoButtonClick()
741790 {
742791 Debug . Log ( "OnPlayVideoButtonClick ()" ) ;
743792
744- if ( isVideoPlaying || isVideoRecording || string . IsNullOrEmpty ( videoPath ) )
793+ if ( isVideoPlaying || isVideoRecording || isFinishWriting || string . IsNullOrEmpty ( videoPath ) )
745794 return ;
746795
747796 if ( System . IO . Path . GetExtension ( videoPath ) == ".gif" )
@@ -767,7 +816,7 @@ public void OnPlayVideoFullScreenButtonClick()
767816 {
768817 Debug . Log ( "OnPlayVideoFullScreenButtonClick ()" ) ;
769818
770- if ( isVideoPlaying || isVideoRecording || string . IsNullOrEmpty ( videoPath ) )
819+ if ( isVideoPlaying || isVideoRecording || isFinishWriting || string . IsNullOrEmpty ( videoPath ) )
771820 return ;
772821
773822 // Playback the video
@@ -788,7 +837,7 @@ public void OnShareButtonClick()
788837 {
789838 Debug . Log ( "OnShareButtonClick ()" ) ;
790839
791- if ( isVideoPlaying || isVideoRecording || string . IsNullOrEmpty ( videoPath ) )
840+ if ( isVideoPlaying || isVideoRecording || isFinishWriting || string . IsNullOrEmpty ( videoPath ) )
792841 return ;
793842
794843 using ( var payload = new SharePayload ( "NatCorderWithOpenCVForUnityExample" ,
@@ -810,7 +859,7 @@ public void OnSaveToCameraRollButtonClick()
810859 {
811860 Debug . Log ( "OnSaveToCameraRollButtonClick ()" ) ;
812861
813- if ( isVideoPlaying || isVideoRecording || string . IsNullOrEmpty ( videoPath ) )
862+ if ( isVideoPlaying || isVideoRecording || isFinishWriting || string . IsNullOrEmpty ( videoPath ) )
814863 return ;
815864
816865 using ( var payload = new SavePayload ( "NatCorderWithOpenCVForUnityExample" ,
0 commit comments