Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Capture Audio & Video gameplay in Unity Editor

Discussion in 'Audio & Video' started by Verusoft, Mar 18, 2017.

  1. Verusoft

    Verusoft

    Joined:
    Jan 4, 2016
    Posts:
    6
    Hello, I'm trying to capture lossless video and audio gameplay in unity editor. I'm using
    Time.captureFramerate to slows game playback time to get stable framerate and Application.CaptureScreenshot() to save every frame as png file. So far it works fine. Then I used OnAudioFilterRead() to capture also audio and I saved audio output to wav file. Unfortunately, audio is out of sync with png sequence when captureFramerate is set. If captureFramerate is not set, audio and video are in sync but fps is not stable so I can't capture smooth gameplay.
    Do you know any solution on workaround how to solve this issue?
     
  2. Verusoft

    Verusoft

    Joined:
    Jan 4, 2016
    Posts:
    6
    Source code:

    Code (CSharp):
    1. #if UNITY_EDITOR
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using System.IO; // for FileStream
    6. using System; // for BitConverter and Byte Type
    7.  
    8. public class MyRecorder : MonoBehaviour {
    9.     private int bufferSize;
    10.     private int numBuffers;
    11.     private int outputRate = 44100;
    12.     private string fileName = "audio.wav";
    13.     private string workingDirectory = "";
    14.     private int headerSize = 44; //default for uncompressed wav
    15.  
    16.     bool recOutput = false;
    17.     FileStream fileStream;
    18.     int screenshotInt;
    19.  
    20.  
    21.     void Awake() {
    22.         DontDestroyOnLoad (gameObject);
    23.         AudioSettings.outputSampleRate = outputRate;
    24.     }
    25.  
    26.     // Use this for initialization
    27.     void Start () {
    28.         AudioSettings.GetDSPBufferSize(out bufferSize,out numBuffers);
    29.     }
    30.  
    31.     // Update is called once per frame
    32.     void Update () {
    33.         if (Input.GetKeyDown (KeyCode.R)) {
    34.             if(recOutput == false)
    35.             {
    36.                 Debug.Log("RECORDING START");
    37.                 workingDirectory = "RECORDING/" + DateTime.Now.ToString ("MM.dd_hh:mm");
    38.                 Directory.CreateDirectory (workingDirectory);
    39.  
    40.                 StartWriting(workingDirectory + "/" + fileName);
    41.                 recOutput = true;
    42.                 Time.captureFramerate = 30;
    43.                 screenshotInt = 0;
    44.             }
    45.             else
    46.             {
    47.                 Debug.Log("RECORDING STOP");
    48.                 recOutput = false;
    49.                 WriteHeader();  
    50.             }  
    51.         }
    52.  
    53.  
    54.         if (recOutput) {
    55.             Application.CaptureScreenshot(string.Format("{0}/{1:D8}.png",workingDirectory,(screenshotInt++)),1);
    56.         }
    57.     }
    58.  
    59.     void StartWriting(string name)
    60.     {
    61.         fileStream = new FileStream(name, FileMode.Create);
    62.         byte emptyByte = new byte();
    63.  
    64.         for(int i = 0; i<headerSize; i++) //preparing the header
    65.         {
    66.             fileStream.WriteByte(emptyByte);
    67.         }
    68.     }
    69.  
    70.     void OnAudioFilterRead(float[] data, int channels)
    71.     {
    72.         if(recOutput)
    73.         {
    74.             ConvertAndWrite(data); //audio data is interlaced
    75.         }
    76.     }
    77.  
    78.     void ConvertAndWrite(float [] dataSource)
    79.     {
    80.  
    81.         Int16[] intData = new Int16[dataSource.Length];
    82.         //converting in 2 steps : float[] to Int16[], //then Int16[] to Byte[]
    83.  
    84.         Byte[] bytesData = new Byte[dataSource.Length*2];
    85.         //bytesData array is twice the size of
    86.         //dataSource array because a float converted in Int16 is 2 bytes.
    87.  
    88.         int rescaleFactor = 32767; //to convert float to Int16
    89.  
    90.         for (int i = 0; i<dataSource.Length;i++)
    91.         {
    92.             intData[i] = (short)(dataSource[i]*rescaleFactor);
    93.             Byte[] byteArr = new Byte[2];
    94.             byteArr = BitConverter.GetBytes(intData[i]);
    95.             byteArr.CopyTo(bytesData,i*2);
    96.         }
    97.  
    98.         fileStream.Write(bytesData,0,bytesData.Length);
    99.     }
    100.  
    101.     void WriteHeader()
    102.     {
    103.  
    104.         fileStream.Seek(0,SeekOrigin.Begin);
    105.  
    106.         Byte[] riff = System.Text.Encoding.UTF8.GetBytes("RIFF");
    107.         fileStream.Write(riff,0,4);
    108.  
    109.         Byte[] chunkSize = BitConverter.GetBytes(fileStream.Length-8);
    110.         fileStream.Write(chunkSize,0,4);
    111.  
    112.         Byte[] wave = System.Text.Encoding.UTF8.GetBytes("WAVE");
    113.         fileStream.Write(wave,0,4);
    114.  
    115.         Byte[] fmt = System.Text.Encoding.UTF8.GetBytes("fmt ");
    116.         fileStream.Write(fmt,0,4);
    117.  
    118.         Byte[] subChunk1 = BitConverter.GetBytes(16);
    119.         fileStream.Write(subChunk1,0,4);
    120.  
    121.         UInt16 two = 2;
    122.         UInt16 one = 1;
    123.  
    124.         Byte[] audioFormat = BitConverter.GetBytes(one);
    125.         fileStream.Write(audioFormat,0,2);
    126.  
    127.         Byte[] numChannels = BitConverter.GetBytes(two);
    128.         fileStream.Write(numChannels,0,2);
    129.  
    130.         Byte[] sampleRate = BitConverter.GetBytes(outputRate);
    131.         fileStream.Write(sampleRate,0,4);
    132.  
    133.         Byte[] byteRate = BitConverter.GetBytes(outputRate*4);
    134.         // sampleRate * bytesPerSample*number of channels, here 44100*2*2
    135.  
    136.         fileStream.Write(byteRate,0,4);
    137.  
    138.         UInt16 four  = 4;
    139.         Byte[] blockAlign = BitConverter.GetBytes(four);
    140.         fileStream.Write(blockAlign,0,2);
    141.  
    142.         UInt16 sixteen  = 16;
    143.         Byte[] bitsPerSample = BitConverter.GetBytes(sixteen);
    144.         fileStream.Write(bitsPerSample,0,2);
    145.  
    146.         Byte[] dataString = System.Text.Encoding.UTF8.GetBytes("data");
    147.         fileStream.Write(dataString,0,4);
    148.  
    149.         Byte[] subChunk2 = BitConverter.GetBytes(fileStream.Length-headerSize);
    150.         fileStream.Write(subChunk2,0,4);
    151.  
    152.         fileStream.Close();
    153.     }
    154.  
    155. }
    156. #endif
    157.