|
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using FFmpegOut;
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Threading;
|
|
|
|
|
|
using UnityEngine.UI;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
|
|
|
|
[RequireComponent(typeof(CameraCapture))]
|
|
|
|
|
|
[RequireComponent(typeof(AudioListenerRecorder))]
|
|
|
|
|
|
public class MovieRecorder : MonoBehaviour {
|
|
|
|
|
|
|
|
|
|
|
|
//the most important is FPS ,take care if u do not want the mistake what happen to the audio and capture is not have synchronization
|
|
|
|
|
|
|
|
|
|
|
|
private CameraCapture cameraCapture;
|
|
|
|
|
|
private AudioListenerRecorder audioListenerRecord;
|
|
|
|
|
|
private bool recording;
|
|
|
|
|
|
public bool IsRecord { get { return recording; } }
|
|
|
|
|
|
|
|
|
|
|
|
#region Editable properties
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
|
private string fileName;
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
|
FFmpegPipe.Codec _codec;
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
|
public SaveAudio.Savetype saveAudioType;
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
|
private float RecordTime;
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
|
private bool reservedOriginal;
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
private float StartRecordTime;
|
|
|
|
|
|
|
|
|
|
|
|
public delegate void RecordFinished();
|
|
|
|
|
|
public static event RecordFinished FinishedEvent;
|
|
|
|
|
|
|
|
|
|
|
|
#region UI
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
|
private RectTransform UIPanel;
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
|
private Text InputFileName;
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
|
private Text uiRecordTime;
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
|
private Toggle recordToggle;
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
|
private Dropdown mediaTypeDrop;
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
|
private Dropdown audioTypeDrop;
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
|
private Text InputWidth;
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
|
private Text InputHeight;
|
|
|
|
|
|
public string InputfileName { set { fileName = value; } }
|
|
|
|
|
|
private bool enableUI = false;
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
void Awake()
|
|
|
|
|
|
{
|
|
|
|
|
|
cameraCapture = GetComponent<CameraCapture>();
|
|
|
|
|
|
audioListenerRecord = GetComponent<AudioListenerRecorder>();
|
|
|
|
|
|
|
|
|
|
|
|
if(UIPanel == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
UIPanel = GameObject.Find("RecordUICanvas").transform.Find("Panel").GetComponent<RectTransform>();
|
|
|
|
|
|
}
|
|
|
|
|
|
if(UIPanel != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
InputFileName = UIPanel.transform.Find("FileName").Find("InputField").GetComponent<InputField>().textComponent;
|
|
|
|
|
|
uiRecordTime = UIPanel.transform.Find("RecordTime").GetChild(0).GetComponent<Text>();
|
|
|
|
|
|
recordToggle = UIPanel.transform.Find("RecordToggle").GetComponent<Toggle>();
|
|
|
|
|
|
mediaTypeDrop = UIPanel.transform.Find("MediaTypeDropdown").GetComponent<Dropdown>();
|
|
|
|
|
|
audioTypeDrop = UIPanel.transform.Find("AudioTypeDropdown").GetComponent<Dropdown>();
|
|
|
|
|
|
InputWidth = UIPanel.transform.Find("width").Find("InputField").GetComponent<InputField>().textComponent;
|
|
|
|
|
|
InputHeight = UIPanel.transform.Find("height").Find("InputField").GetComponent<InputField>().textComponent;
|
|
|
|
|
|
enableUI = false;
|
|
|
|
|
|
List<Dropdown.OptionData> mediaTypeOptions = new List<Dropdown.OptionData>();
|
|
|
|
|
|
for (int i=0;i< (int)Enum.GetValues(typeof(FFmpegPipe.Codec)).Cast<FFmpegPipe.Codec>().Max() + 1;i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
mediaTypeOptions.Add(new Dropdown.OptionData(((FFmpegPipe.Codec)i).ToString()));
|
|
|
|
|
|
}
|
|
|
|
|
|
mediaTypeDrop.AddOptions(mediaTypeOptions);
|
|
|
|
|
|
//mediaTypeDrop.onValueChanged.AddListener((v) => SetMediaType(v));
|
|
|
|
|
|
List<Dropdown.OptionData> audioTypeOptions = new List<Dropdown.OptionData>();
|
|
|
|
|
|
for (int i = 0; i < (int)Enum.GetValues(typeof(SaveAudio.Savetype)).Cast<SaveAudio.Savetype>().Max()+1; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
audioTypeOptions.Add(new Dropdown.OptionData(((SaveAudio.Savetype)i).ToString()));
|
|
|
|
|
|
}
|
|
|
|
|
|
audioTypeDrop.AddOptions(audioTypeOptions);
|
|
|
|
|
|
//audioTypeDrop.onValueChanged.AddListener((v) => SetAudioType(v));
|
|
|
|
|
|
}
|
|
|
|
|
|
UIPanel.gameObject.SetActive(enableUI);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Use this for initialization
|
|
|
|
|
|
void Start () {
|
|
|
|
|
|
recording = false;
|
|
|
|
|
|
FinishedEvent += ShowReocrdTime;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Update is called once per frame
|
|
|
|
|
|
void Update () {
|
|
|
|
|
|
|
|
|
|
|
|
if(Input.GetKeyDown(KeyCode.R))
|
|
|
|
|
|
{
|
|
|
|
|
|
if(!recording)
|
|
|
|
|
|
{
|
|
|
|
|
|
fileName = DateTime.Now.ToString("yyyy-MMdd-HHmmss");
|
|
|
|
|
|
StartRecord(fileName);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
StopRecord();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (Input.GetKeyDown(KeyCode.F2))
|
|
|
|
|
|
{
|
|
|
|
|
|
enableUI = !enableUI;
|
|
|
|
|
|
UIPanel.gameObject.SetActive(enableUI);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (recording)
|
|
|
|
|
|
{
|
|
|
|
|
|
CountRecordTime();
|
|
|
|
|
|
}
|
|
|
|
|
|
if(enableUI)
|
|
|
|
|
|
{
|
|
|
|
|
|
recordToggle.isOn = recording;
|
|
|
|
|
|
uiRecordTime.text = RecordTime.ToString();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CountRecordTime()
|
|
|
|
|
|
{
|
|
|
|
|
|
RecordTime = Time.time - StartRecordTime;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void StartRecord(string filename)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (recording)
|
|
|
|
|
|
return;
|
|
|
|
|
|
fileName = filename;
|
|
|
|
|
|
StartRecord();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void StartRecord()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (recording)
|
|
|
|
|
|
return;
|
|
|
|
|
|
if (enableUI)
|
|
|
|
|
|
{
|
|
|
|
|
|
fileName = InputFileName.text;
|
|
|
|
|
|
if(fileName == null || fileName == "")
|
|
|
|
|
|
fileName = DateTime.Now.ToString("yyyy-MMdd-HHmmss");
|
|
|
|
|
|
|
|
|
|
|
|
SetMediaType(mediaTypeDrop.value);
|
|
|
|
|
|
SetAudioType(audioTypeDrop.value);
|
|
|
|
|
|
int width;
|
|
|
|
|
|
int height;
|
|
|
|
|
|
if (Int32.TryParse(InputWidth.text, out width) && Int32.TryParse(InputHeight.text, out height))
|
|
|
|
|
|
{
|
|
|
|
|
|
cameraCapture.SetResolution(width, height);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
recording = true;
|
|
|
|
|
|
cameraCapture._codec = _codec;
|
|
|
|
|
|
audioListenerRecord.saveAudioType = saveAudioType;
|
|
|
|
|
|
cameraCapture.StartCapture("Tempmovie" + fileName);
|
|
|
|
|
|
audioListenerRecord.StartRecord("Tempaudio" + fileName);
|
|
|
|
|
|
StartRecordTime = Time.time;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void StopRecord()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!recording)
|
|
|
|
|
|
return;
|
|
|
|
|
|
CountRecordTime();
|
|
|
|
|
|
cameraCapture.StopCapture();
|
|
|
|
|
|
audioListenerRecord.StopRecord();
|
|
|
|
|
|
StartCoroutine(StartCombine());
|
|
|
|
|
|
recording = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void SetMediaType(int i)
|
|
|
|
|
|
{
|
|
|
|
|
|
_codec = (FFmpegPipe.Codec)i;
|
|
|
|
|
|
}
|
|
|
|
|
|
public void SetAudioType(int i)
|
|
|
|
|
|
{
|
|
|
|
|
|
saveAudioType = (SaveAudio.Savetype)i;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
IEnumerator StartCombine()
|
|
|
|
|
|
{
|
|
|
|
|
|
yield return new WaitForSeconds(0.5f);
|
|
|
|
|
|
|
|
|
|
|
|
string Arguments = "-i " + "Tempmovie" + fileName + FFmpegPipe.GetSuffix(_codec) +
|
|
|
|
|
|
" -i " + "Tempaudio" + fileName + "." + audioListenerRecord.saveAudioType.ToString() +
|
|
|
|
|
|
" -c copy -map 0:0 -map 1:0 -ar " + audioListenerRecord.outputRate.ToString() + " " + fileName + FFmpegPipe.GetSuffix(_codec);
|
|
|
|
|
|
if (_codec == FFmpegPipe.Codec.H264 && audioListenerRecord.saveAudioType == SaveAudio.Savetype.wav)
|
|
|
|
|
|
Arguments = "-i " + "Tempmovie" + fileName + FFmpegPipe.GetSuffix(_codec) +
|
|
|
|
|
|
" -i " + "Tempaudio" + fileName + "." + audioListenerRecord.saveAudioType.ToString() +
|
|
|
|
|
|
" -c copy -map 0:0 -map 1:0 -acodec mp3 -vcodec copy -ar " + audioListenerRecord.outputRate.ToString() + " " + fileName + FFmpegPipe.GetSuffix(_codec);
|
|
|
|
|
|
|
|
|
|
|
|
yield return ExcuteProcess(FFmpegConfig.BinaryPath, Arguments, (s, e) => print(e.Data));
|
|
|
|
|
|
|
|
|
|
|
|
if (!reservedOriginal)
|
|
|
|
|
|
{
|
|
|
|
|
|
File.Delete(Application.dataPath + "/../Tempmovie" + fileName + FFmpegPipe.GetSuffix(_codec));
|
|
|
|
|
|
File.Delete(Application.dataPath + "/../Tempaudio" + fileName + "." +audioListenerRecord.saveAudioType.ToString());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (FinishedEvent != null)
|
|
|
|
|
|
FinishedEvent();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ShowReocrdTime()
|
|
|
|
|
|
{
|
|
|
|
|
|
print("RecordTime:" + RecordTime);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IEnumerator ExcuteProcess(string fileName, string arg, DataReceivedEventHandler output)
|
|
|
|
|
|
{
|
|
|
|
|
|
Thread WriteThread = new Thread(() => _ExcuteProcess(fileName, arg, output));
|
|
|
|
|
|
WriteThread.Start();
|
|
|
|
|
|
|
|
|
|
|
|
while (WriteThread.IsAlive)
|
|
|
|
|
|
yield return null;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void _ExcuteProcess(string fileName, string arg, DataReceivedEventHandler output)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
using (var p = new Process())
|
|
|
|
|
|
{
|
|
|
|
|
|
p.StartInfo.FileName = fileName;
|
|
|
|
|
|
p.StartInfo.Arguments = arg;
|
|
|
|
|
|
p.StartInfo.UseShellExecute = false;
|
|
|
|
|
|
p.StartInfo.CreateNoWindow = true;
|
|
|
|
|
|
p.StartInfo.RedirectStandardError = true;
|
|
|
|
|
|
p.StartInfo.RedirectStandardOutput = true;
|
|
|
|
|
|
p.OutputDataReceived += output;
|
|
|
|
|
|
p.ErrorDataReceived += output;
|
|
|
|
|
|
p.Start();
|
|
|
|
|
|
p.BeginOutputReadLine();
|
|
|
|
|
|
p.BeginErrorReadLine();
|
|
|
|
|
|
p.WaitForExit();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|