CaptureBase.cs 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549
  1. #if UNITY_5_4_OR_NEWER || (UNITY_5 && !UNITY_5_0 && !UNITY_5_1)
  2. #define AVPRO_MOVIECAPTURE_GLISSUEEVENT_52
  3. #endif
  4. #if UNITY_5_4_OR_NEWER || UNITY_5
  5. #define AVPRO_MOVIECAPTURE_DEFERREDSHADING
  6. #endif
  7. using UnityEngine;
  8. using System.IO;
  9. using System;
  10. using System.Runtime.InteropServices;
  11. //-----------------------------------------------------------------------------
  12. // Copyright 2012-2017 RenderHeads Ltd. All rights reserved.
  13. //-----------------------------------------------------------------------------
  14. namespace RenderHeads.Media.AVProMovieCapture
  15. {
  16. /// <summary>
  17. /// Base class wrapping common capture functionality
  18. /// </summary>
  19. public class CaptureBase : MonoBehaviour
  20. {
  21. public enum FrameRate
  22. {
  23. One = 1,
  24. Ten = 10,
  25. Fifteen = 15,
  26. TwentyFour = 24,
  27. TwentyFive = 25,
  28. Thirty = 30,
  29. Fifty = 50,
  30. Sixty = 60,
  31. SeventyFive = 75,
  32. Ninety = 90,
  33. OneTwenty = 120,
  34. }
  35. public enum Resolution
  36. {
  37. POW2_8192x8192,
  38. POW2_8192x4096,
  39. POW2_4096x4096,
  40. POW2_4096x2048,
  41. POW2_2048x4096,
  42. UHD_3840x2160,
  43. UHD_3840x2048,
  44. UHD_3840x1920,
  45. POW2_2048x2048,
  46. POW2_2048x1024,
  47. HD_1920x1080,
  48. HD_1280x720,
  49. SD_1024x768,
  50. SD_800x600,
  51. SD_800x450,
  52. SD_640x480,
  53. SD_640x360,
  54. SD_320x240,
  55. Original,
  56. Custom,
  57. }
  58. public enum CubemapDepth
  59. {
  60. Depth_24 = 24,
  61. Depth_16 = 16,
  62. Depth_Zero = 0,
  63. }
  64. public enum CubemapResolution
  65. {
  66. POW2_4096 = 4096,
  67. POW2_2048 = 2048,
  68. POW2_1024 = 1024,
  69. POW2_512 = 512,
  70. POW2_256 = 256,
  71. }
  72. public enum AntiAliasingLevel
  73. {
  74. UseCurrent,
  75. ForceNone,
  76. ForceSample2,
  77. ForceSample4,
  78. ForceSample8,
  79. }
  80. public enum DownScale
  81. {
  82. Original = 1,
  83. Half = 2,
  84. Quarter = 4,
  85. Eighth = 8,
  86. Sixteenth = 16,
  87. Custom = 100,
  88. }
  89. public enum OutputPath
  90. {
  91. RelativeToProject,
  92. RelativeToPeristentData,
  93. Absolute,
  94. }
  95. public enum OutputExtension
  96. {
  97. AVI,
  98. MP4,
  99. PNG,
  100. Custom = 100,
  101. }
  102. public enum OutputType
  103. {
  104. VideoFile,
  105. NamedPipe,
  106. }
  107. // General options
  108. public KeyCode _captureKey = KeyCode.None;
  109. public bool _captureOnStart = false;
  110. public bool _startPaused = false;
  111. public bool _listVideoCodecsOnStart = false;
  112. public bool _isRealTime = true;
  113. // Stop options
  114. public StopMode _stopMode = StopMode.None;
  115. // TODO: add option to pause instread of stop?
  116. public int _stopFrames = 0;
  117. public float _stopSeconds = 0f;
  118. // Video options
  119. public bool _useMediaFoundationH264 = false;
  120. public string[] _videoCodecPriority = { "Lagarith Lossless Codec",
  121. "x264vfw - H.264/MPEG-4 AVC codec",
  122. "Xvid MPEG-4 Codec" };
  123. public FrameRate _frameRate = FrameRate.Thirty;
  124. public DownScale _downScale = DownScale.Original;
  125. public Vector2 _maxVideoSize = Vector2.zero;
  126. public int _forceVideoCodecIndex = -1;
  127. public bool _flipVertically = false;
  128. public bool _supportAlpha = false;
  129. // Audio options
  130. public bool _noAudio = true;
  131. public string[] _audioCodecPriority = { };
  132. public int _forceAudioCodecIndex = -1;
  133. public int _forceAudioDeviceIndex = -1;
  134. public UnityAudioCapture _audioCapture;
  135. // Output options
  136. public bool _autoGenerateFilename = true;
  137. public OutputPath _outputFolderType = OutputPath.RelativeToProject;
  138. public string _outputFolderPath;
  139. public string _autoFilenamePrefix = "MovieCapture";
  140. public string _autoFilenameExtension = "avi";
  141. public string _forceFilename = "movie.avi";
  142. public OutputType _outputType = OutputType.VideoFile;
  143. // Camera specific options
  144. public Resolution _renderResolution = Resolution.Original;
  145. public Vector2 _renderSize = Vector2.one;
  146. public int _renderAntiAliasing = -1;
  147. // Motion blur options
  148. public bool _useMotionBlur = false;
  149. [Range(0, 64)]
  150. public int _motionBlurSamples = 16;
  151. public Camera[] _motionBlurCameras;
  152. protected MotionBlur _motionBlur;
  153. // Performance options
  154. public bool _allowVSyncDisable = true;
  155. [SerializeField]
  156. protected bool _supportTextureRecreate = false;
  157. //public bool _allowFrameRateChange = true;
  158. // Cursor options
  159. public bool _captureMouseCursor = false;
  160. public MouseCursor _mouseCursor;
  161. [System.NonSerialized]
  162. public string _codecName = "uncompressed";
  163. [System.NonSerialized]
  164. public int _codecIndex = -1;
  165. [System.NonSerialized]
  166. public string _audioCodecName = "uncompressed";
  167. [System.NonSerialized]
  168. public int _audioCodecIndex = -1;
  169. [System.NonSerialized]
  170. public string _audioDeviceName = "Unity";
  171. [System.NonSerialized]
  172. public int _audioDeviceIndex = -1;
  173. [System.NonSerialized]
  174. public int _unityAudioSampleRate = -1;
  175. [System.NonSerialized]
  176. public int _unityAudioChannelCount = -1;
  177. protected Texture2D _texture;
  178. protected int _handle = -1;
  179. protected int _targetWidth, _targetHeight;
  180. protected bool _capturing = false;
  181. protected bool _paused = false;
  182. protected string _filePath;
  183. protected FileInfo _fileInfo;
  184. protected NativePlugin.PixelFormat _pixelFormat = NativePlugin.PixelFormat.YCbCr422_YUY2;
  185. private int _oldVSyncCount = 0;
  186. //private int _oldTargetFrameRate = -1;
  187. private float _oldFixedDeltaTime = 0f;
  188. protected bool _isTopDown = true;
  189. protected bool _isDirectX11 = false;
  190. private bool _queuedStartCapture = false;
  191. private bool _queuedStopCapture = false;
  192. private float _captureStartTime = 0f;
  193. private float _timeSinceLastFrame = 0f;
  194. public string LastFilePath
  195. {
  196. get { return _filePath; }
  197. }
  198. // Other options
  199. public int _minimumDiskSpaceMB = -1;
  200. private long _freeDiskSpaceMB;
  201. // Stats
  202. private uint _numDroppedFrames;
  203. private uint _numDroppedEncoderFrames;
  204. private uint _numEncodedFrames;
  205. private uint _totalEncodedSeconds;
  206. #if AVPRO_MOVIECAPTURE_GLISSUEEVENT_52
  207. protected System.IntPtr _renderEventFunction = System.IntPtr.Zero;
  208. protected System.IntPtr _freeEventFunction = System.IntPtr.Zero;
  209. #endif
  210. public uint NumDroppedFrames
  211. {
  212. get { return _numDroppedFrames; }
  213. }
  214. public uint NumDroppedEncoderFrames
  215. {
  216. get { return _numDroppedEncoderFrames; }
  217. }
  218. public uint NumEncodedFrames
  219. {
  220. get { return _numEncodedFrames; }
  221. }
  222. public uint TotalEncodedSeconds
  223. {
  224. get { return _totalEncodedSeconds; }
  225. }
  226. protected virtual void Awake()
  227. {
  228. try
  229. {
  230. float pluginVersion = NativePlugin.GetPluginVersion();
  231. bool isTrial = NativePlugin.IsTrialVersion();
  232. string pluginVersionString = pluginVersion.ToString("F2");
  233. if (isTrial)
  234. {
  235. pluginVersionString += "t";
  236. }
  237. // Check that the plugin version number is not too old
  238. if (pluginVersion.ToString("F2") != NativePlugin.ExpectedPluginVersion)
  239. {
  240. Debug.LogWarning("[AVProMovieCapture] Plugin version number " + pluginVersionString + " doesn't match the expected version number " + NativePlugin.ExpectedPluginVersion + ". It looks like the plugin didn't upgrade correctly. To resolve this please restart Unity and try to upgrade the package again.");
  241. }
  242. if (NativePlugin.Init())
  243. {
  244. Debug.Log("[AVProMovieCapture] Init plugin version: " + pluginVersionString + " (script v" + NativePlugin.ScriptVersion +") with GPU " + SystemInfo.graphicsDeviceName + " " + SystemInfo.graphicsDeviceVersion);
  245. #if AVPRO_MOVIECAPTURE_GLISSUEEVENT_52
  246. _renderEventFunction = NativePlugin.GetRenderEventFunc();
  247. _freeEventFunction = NativePlugin.GetFreeResourcesEventFunc();
  248. Debug.Assert(_renderEventFunction != System.IntPtr.Zero);
  249. Debug.Assert(_freeEventFunction != System.IntPtr.Zero);
  250. #endif
  251. }
  252. else
  253. {
  254. Debug.LogError("[AVProMovieCapture] Failed to initialise plugin version: " + pluginVersionString + " (script v" + NativePlugin.ScriptVersion + ") with GPU " + SystemInfo.graphicsDeviceName + " " + SystemInfo.graphicsDeviceVersion);
  255. }
  256. }
  257. catch (DllNotFoundException e)
  258. {
  259. string missingDllMessage = string.Empty;
  260. #if (UNITY_5 || UNITY_5_4_OR_NEWER)
  261. missingDllMessage = "Unity couldn't find the plugin DLL. Please select the native plugin files in 'Plugins/RenderHeads/AVProMovieCapture/Plugins' folder and select the correct platform in the Inspector.";
  262. #else
  263. missingDllMessage = "Unity couldn't find the plugin DLL, Unity 4.x requires the 'Plugins' folder to be at the root of your project. Please move the contents of the 'Plugins' folder (in Plugins/RenderHeads/AVProMovieCapture/Plugins) to the 'Plugins' folder in the root of your project.";
  264. #endif
  265. Debug.LogError("[AVProMovieCapture] " + missingDllMessage);
  266. #if UNITY_EDITOR
  267. UnityEditor.EditorUtility.DisplayDialog("Plugin files not found", missingDllMessage, "Ok");
  268. #endif
  269. throw e;
  270. }
  271. _isDirectX11 = SystemInfo.graphicsDeviceVersion.StartsWith("Direct3D 11");
  272. SelectCodec(_listVideoCodecsOnStart);
  273. SelectAudioCodec(_listVideoCodecsOnStart);
  274. SelectAudioDevice(_listVideoCodecsOnStart);
  275. }
  276. public virtual void Start()
  277. {
  278. Application.runInBackground = true;
  279. if (_captureOnStart)
  280. {
  281. StartCapture();
  282. }
  283. }
  284. public void SelectCodec(bool listCodecs)
  285. {
  286. // Enumerate video codecs
  287. int numVideoCodecs = NativePlugin.GetNumAVIVideoCodecs();
  288. if (listCodecs)
  289. {
  290. for (int i = 0; i < numVideoCodecs; i++)
  291. {
  292. Debug.Log("VideoCodec " + i + ": " + NativePlugin.GetAVIVideoCodecName(i));
  293. }
  294. }
  295. _codecIndex = -1;
  296. if (_useMediaFoundationH264)
  297. {
  298. _codecName = "Media Foundation H.264(MP4)";
  299. }
  300. else
  301. {
  302. // The user has specified their own codec index
  303. if (_forceVideoCodecIndex >= 0)
  304. {
  305. if (_forceVideoCodecIndex < numVideoCodecs)
  306. {
  307. _codecName = NativePlugin.GetAVIVideoCodecName(_forceVideoCodecIndex);
  308. _codecIndex = _forceVideoCodecIndex;
  309. }
  310. if (_codecIndex < 0)
  311. {
  312. _codecName = "Uncompressed";
  313. Debug.LogWarning("[AVProMovieCapture] Video codec not found. Video will be uncompressed.");
  314. }
  315. }
  316. else
  317. {
  318. // Try to find the codec based on the priority list
  319. if (_videoCodecPriority != null && _videoCodecPriority.Length > 0)
  320. {
  321. foreach (string codec in _videoCodecPriority)
  322. {
  323. string codecName = codec.Trim();
  324. // Empty string means uncompressed
  325. if (string.IsNullOrEmpty(codecName))
  326. break;
  327. for (int i = 0; i < numVideoCodecs; i++)
  328. {
  329. if (codecName == NativePlugin.GetAVIVideoCodecName(i))
  330. {
  331. _codecName = codecName;
  332. _codecIndex = i;
  333. break;
  334. }
  335. }
  336. if (_codecIndex >= 0)
  337. break;
  338. }
  339. if (_codecIndex < 0)
  340. {
  341. _codecName = "Uncompressed";
  342. Debug.LogWarning("[AVProMovieCapture] Video codec not found. Video will be uncompressed.");
  343. }
  344. }
  345. }
  346. }
  347. }
  348. public void SelectAudioCodec(bool listCodecs)
  349. {
  350. // Enumerate audio codecs
  351. int numAudioCodecs = NativePlugin.GetNumAVIAudioCodecs();
  352. if (listCodecs)
  353. {
  354. for (int i = 0; i < numAudioCodecs; i++)
  355. {
  356. Debug.Log("AudioCodec " + i + ": " + NativePlugin.GetAVIAudioCodecName(i));
  357. }
  358. }
  359. _audioCodecIndex = -1;
  360. // The user has specified their own codec index
  361. if (_forceAudioCodecIndex >= 0)
  362. {
  363. if (_forceAudioCodecIndex < numAudioCodecs)
  364. {
  365. _audioCodecName = NativePlugin.GetAVIAudioCodecName(_forceAudioCodecIndex);
  366. _audioCodecIndex = _forceAudioCodecIndex;
  367. }
  368. if (_audioCodecIndex < 0)
  369. {
  370. _audioCodecName = "Uncompressed";
  371. Debug.LogWarning("[AVProMovieCapture] Audio codec not found. Audio will be uncompressed.");
  372. }
  373. }
  374. else
  375. {
  376. // Try to find the codec based on the priority list
  377. if (_audioCodecPriority != null && _audioCodecPriority.Length > 0)
  378. {
  379. foreach (string codec in _audioCodecPriority)
  380. {
  381. string codecName = codec.Trim();
  382. // Empty string means uncompressed
  383. if (string.IsNullOrEmpty(codecName))
  384. break;
  385. for (int i = 0; i < numAudioCodecs; i++)
  386. {
  387. if (codecName == NativePlugin.GetAVIAudioCodecName(i))
  388. {
  389. _audioCodecName = codecName;
  390. _audioCodecIndex = i;
  391. break;
  392. }
  393. }
  394. if (_audioCodecIndex >= 0)
  395. break;
  396. }
  397. if (_audioCodecIndex < 0)
  398. {
  399. _audioCodecName = "Uncompressed";
  400. Debug.LogWarning("[AVProMovieCapture] Codec not found. Audio will be uncompressed.");
  401. }
  402. }
  403. }
  404. }
  405. public void SelectAudioDevice(bool display)
  406. {
  407. // Enumerate
  408. int num = NativePlugin.GetNumAVIAudioInputDevices();
  409. if (display)
  410. {
  411. for (int i = 0; i < num; i++)
  412. {
  413. Debug.Log("AudioDevice " + i + ": " + NativePlugin.GetAVIAudioInputDeviceName(i));
  414. }
  415. }
  416. // The user has specified their own device index
  417. if (_forceAudioDeviceIndex >= 0)
  418. {
  419. if (_forceAudioDeviceIndex < num)
  420. {
  421. _audioDeviceName = NativePlugin.GetAVIAudioInputDeviceName(_forceAudioDeviceIndex);
  422. _audioDeviceIndex = _forceAudioDeviceIndex;
  423. }
  424. }
  425. else
  426. {
  427. /*_audioDeviceIndex = -1;
  428. // Try to find one of the loopback devices
  429. for (int i = 0; i < num; i++)
  430. {
  431. StringBuilder sbName = new StringBuilder(512);
  432. if (AVProMovieCapturePlugin.GetAVIAudioInputDeviceName(i, sbName))
  433. {
  434. string[] loopbackNames = { "Stereo Mix", "What U Hear", "What You Hear", "Waveout Mix", "Mixed Output" };
  435. for (int j = 0; j < loopbackNames.Length; j++)
  436. {
  437. if (sbName.ToString().Contains(loopbackNames[j]))
  438. {
  439. _audioDeviceIndex = i;
  440. _audioDeviceName = sbName.ToString();
  441. }
  442. }
  443. }
  444. if (_audioDeviceIndex >= 0)
  445. break;
  446. }
  447. if (_audioDeviceIndex < 0)
  448. {
  449. // Resort to the no recording device
  450. _audioDeviceName = "Unity";
  451. _audioDeviceIndex = -1;
  452. }*/
  453. _audioDeviceName = "Unity";
  454. _audioDeviceIndex = -1;
  455. }
  456. }
  457. public static Vector2 GetRecordingResolution(int width, int height, DownScale downscale, Vector2 maxVideoSize)
  458. {
  459. int targetWidth = width;
  460. int targetHeight = height;
  461. if (downscale != DownScale.Custom)
  462. {
  463. targetWidth /= (int)downscale;
  464. targetHeight /= (int)downscale;
  465. }
  466. else
  467. {
  468. if (maxVideoSize.x >= 1.0f && maxVideoSize.y >= 1.0f)
  469. {
  470. targetWidth = Mathf.FloorToInt(maxVideoSize.x);
  471. targetHeight = Mathf.FloorToInt(maxVideoSize.y);
  472. }
  473. }
  474. // Some codecs like Lagarith in YUY2 mode need size to be multiple of 4
  475. targetWidth = NextMultipleOf4(targetWidth);
  476. targetHeight = NextMultipleOf4(targetHeight);
  477. return new Vector2(targetWidth, targetHeight);
  478. }
  479. public void SelectRecordingResolution(int width, int height)
  480. {
  481. _targetWidth = width;
  482. _targetHeight = height;
  483. if (_downScale != DownScale.Custom)
  484. {
  485. _targetWidth /= (int)_downScale;
  486. _targetHeight /= (int)_downScale;
  487. }
  488. else
  489. {
  490. if (_maxVideoSize.x >= 1.0f && _maxVideoSize.y >= 1.0f)
  491. {
  492. _targetWidth = Mathf.FloorToInt(_maxVideoSize.x);
  493. _targetHeight = Mathf.FloorToInt(_maxVideoSize.y);
  494. }
  495. }
  496. // Some codecs like Lagarith in YUY2 mode need size to be multiple of 4
  497. _targetWidth = NextMultipleOf4(_targetWidth);
  498. _targetHeight = NextMultipleOf4(_targetHeight);
  499. }
  500. public virtual void OnDestroy()
  501. {
  502. StopCapture();
  503. NativePlugin.Deinit();
  504. }
  505. private void OnApplicationQuit()
  506. {
  507. StopCapture();
  508. NativePlugin.Deinit();
  509. }
  510. protected void EncodeTexture(Texture2D texture)
  511. {
  512. Color32[] bytes = texture.GetPixels32();
  513. GCHandle _frameHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
  514. EncodePointer(_frameHandle.AddrOfPinnedObject());
  515. if (_frameHandle.IsAllocated)
  516. {
  517. _frameHandle.Free();
  518. }
  519. }
  520. protected bool IsUsingUnityAudio()
  521. {
  522. return (_isRealTime && !_noAudio && _audioDeviceIndex < 0 && _audioCapture != null);
  523. }
  524. protected bool IsRecordingUnityAudio()
  525. {
  526. return (IsUsingUnityAudio() && _audioCapture.isActiveAndEnabled);
  527. }
  528. protected bool IsUsingMotionBlur()
  529. {
  530. return (_useMotionBlur && !_isRealTime && _motionBlur != null);
  531. }
  532. public virtual void EncodePointer(System.IntPtr ptr)
  533. {
  534. if (!IsRecordingUnityAudio())
  535. {
  536. NativePlugin.EncodeFrame(_handle, ptr);
  537. }
  538. else
  539. {
  540. int audioDataLength = 0;
  541. System.IntPtr audioDataPtr = _audioCapture.ReadData(out audioDataLength);
  542. if (audioDataLength > 0)
  543. {
  544. NativePlugin.EncodeFrameWithAudio(_handle, ptr, audioDataPtr, (uint)audioDataLength);
  545. }
  546. else
  547. {
  548. NativePlugin.EncodeFrame(_handle, ptr);
  549. }
  550. }
  551. }
  552. public bool IsCapturing()
  553. {
  554. return _capturing;
  555. }
  556. public bool IsPaused()
  557. {
  558. return _paused;
  559. }
  560. public int GetRecordingWidth()
  561. {
  562. return _targetWidth;
  563. }
  564. public int GetRecordingHeight()
  565. {
  566. return _targetHeight;
  567. }
  568. protected virtual string GenerateTimestampedFilename(string filenamePrefix, string filenameExtension)
  569. {
  570. TimeSpan span = (DateTime.Now - DateTime.Now.Date);
  571. return string.Format("{0}-{1}-{2}-{3}-{4}s-{5}x{6}.{7}", filenamePrefix, DateTime.Now.Year, DateTime.Now.Month.ToString("D2"), DateTime.Now.Day.ToString("D2"), ((int)(span.TotalSeconds)).ToString(), _targetWidth, _targetHeight, filenameExtension);
  572. }
  573. private static string GetFolder(OutputPath outputPathType, string path)
  574. {
  575. string fileFolder = string.Empty;
  576. if (outputPathType == OutputPath.RelativeToProject)
  577. {
  578. string projectFolder = System.IO.Path.GetFullPath(System.IO.Path.Combine(Application.dataPath, ".."));
  579. fileFolder = System.IO.Path.Combine(projectFolder, path);
  580. }
  581. else if (outputPathType == OutputPath.RelativeToPeristentData)
  582. {
  583. string projectFolder = System.IO.Path.GetFullPath(Application.persistentDataPath);
  584. fileFolder = System.IO.Path.Combine(projectFolder, path);
  585. }
  586. else if (outputPathType == OutputPath.Absolute)
  587. {
  588. fileFolder = path;
  589. }
  590. return fileFolder;
  591. }
  592. private static string AutoGenerateFilename(OutputPath outputPathType, string path, string filename)
  593. {
  594. // Create folder
  595. string fileFolder = GetFolder(outputPathType, path);
  596. // Combine path and filename
  597. return System.IO.Path.Combine(fileFolder, filename);
  598. }
  599. private static string ManualGenerateFilename(OutputPath outputPathType, string path, string filename)
  600. {
  601. string result = GetFolder(outputPathType, path);
  602. if (System.IO.Path.IsPathRooted(filename))
  603. {
  604. result = filename;
  605. }
  606. else
  607. {
  608. result = System.IO.Path.Combine(result, filename);
  609. }
  610. return result;
  611. }
  612. /*[ContextMenu("Debug GenerateFilename")]
  613. public void DebugGenereateFilename()
  614. {
  615. GenerateFilename();
  616. Debug.Log("PATH: " + _filePath);
  617. }*/
  618. protected void GenerateFilename()
  619. {
  620. if (_outputType == OutputType.VideoFile)
  621. {
  622. if (_autoGenerateFilename || string.IsNullOrEmpty(_forceFilename))
  623. {
  624. string filename = GenerateTimestampedFilename(_autoFilenamePrefix, _autoFilenameExtension);
  625. _filePath = AutoGenerateFilename(_outputFolderType, _outputFolderPath, filename);
  626. }
  627. else
  628. {
  629. _filePath = ManualGenerateFilename(_outputFolderType, _outputFolderPath, _forceFilename);
  630. }
  631. if (_useMediaFoundationH264 && !_filePath.EndsWith(".mp4", StringComparison.OrdinalIgnoreCase))
  632. {
  633. Debug.LogError("[AVProMovieCapture] Media Foundation H.264 MP4 Encoder selected but file extension is not set to 'mp4'");
  634. }
  635. // Create target directory if doesn't exist
  636. String directory = Path.GetDirectoryName(_filePath);
  637. if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
  638. {
  639. Directory.CreateDirectory(directory);
  640. }
  641. }
  642. else
  643. {
  644. _filePath = _forceFilename;
  645. }
  646. }
  647. public virtual bool PrepareCapture()
  648. {
  649. // Delete file if it already exists
  650. if (_outputType == OutputType.VideoFile && File.Exists(_filePath))
  651. {
  652. File.Delete(_filePath);
  653. }
  654. _numDroppedFrames = 0;
  655. _numDroppedEncoderFrames = 0;
  656. _numEncodedFrames = 0;
  657. _totalEncodedSeconds = 0;
  658. #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
  659. if (_minimumDiskSpaceMB > 0 && _outputType == OutputType.VideoFile)
  660. {
  661. ulong freespace = 0;
  662. if (Utils.DriveFreeBytes(System.IO.Path.GetPathRoot(_filePath), out freespace))
  663. {
  664. _freeDiskSpaceMB = (long)(freespace / (1024 * 1024));
  665. }
  666. if (!IsEnoughDiskSpace())
  667. {
  668. Debug.LogError("[AVProMovieCapture] Not enough free space to start capture. Stopping capture.");
  669. return false;
  670. }
  671. }
  672. #endif
  673. if (_isRealTime)
  674. {
  675. /*if (_allowFrameRateChange)
  676. {
  677. _oldTargetFrameRate = Application.targetFrameRate;
  678. Application.targetFrameRate = (int)_frameRate;
  679. }*/
  680. }
  681. else
  682. {
  683. // Disable vsync
  684. if (_allowVSyncDisable && !Screen.fullScreen && QualitySettings.vSyncCount > 0)
  685. {
  686. _oldVSyncCount = QualitySettings.vSyncCount;
  687. QualitySettings.vSyncCount = 0;
  688. }
  689. if (_useMotionBlur && _motionBlurSamples > 1)
  690. {
  691. Time.captureFramerate = _motionBlurSamples * (int)_frameRate;
  692. // FromTexture and FromCamera360 captures don't require a camera for rendering, so set up the motion blur component differently
  693. if (this is CaptureFromTexture || this is CaptureFromCamera360 || this is CaptureFromCamera360ODS)
  694. {
  695. if (_motionBlur == null)
  696. {
  697. _motionBlur = this.GetComponent<MotionBlur>();
  698. }
  699. if (_motionBlur == null)
  700. {
  701. _motionBlur = this.gameObject.AddComponent<MotionBlur>();
  702. }
  703. if (_motionBlur != null)
  704. {
  705. _motionBlur.NumSamples = _motionBlurSamples;
  706. _motionBlur.SetTargetSize(_targetWidth, _targetHeight);
  707. _motionBlur.enabled = false;
  708. }
  709. }
  710. // FromCamera and FromScreen use this path
  711. else if (_motionBlurCameras.Length > 0)
  712. {
  713. // Setup the motion blur filters where cameras are used
  714. foreach (Camera camera in _motionBlurCameras)
  715. {
  716. MotionBlur mb = camera.GetComponent<MotionBlur>();
  717. if (mb == null)
  718. {
  719. mb = camera.gameObject.AddComponent<MotionBlur>();
  720. }
  721. if (mb != null)
  722. {
  723. mb.NumSamples = _motionBlurSamples;
  724. mb.enabled = true;
  725. _motionBlur = mb;
  726. }
  727. }
  728. }
  729. }
  730. else
  731. {
  732. Time.captureFramerate = (int)_frameRate;
  733. }
  734. // Change physics update speed
  735. _oldFixedDeltaTime = Time.fixedDeltaTime;
  736. Time.fixedDeltaTime = 1.0f / Time.captureFramerate;
  737. }
  738. int audioDeviceIndex = _audioDeviceIndex;
  739. int audioCodecIndex = _audioCodecIndex;
  740. bool noAudio = _noAudio;
  741. if (!_isRealTime)
  742. {
  743. noAudio = true;
  744. }
  745. if (_mouseCursor != null)
  746. {
  747. _mouseCursor.enabled = _captureMouseCursor;
  748. }
  749. // We if try to capture audio from Unity but there isn't an UnityAudioCapture component set
  750. if (!noAudio && _audioCapture == null && _audioDeviceIndex < 0)
  751. {
  752. // Try to find it locally
  753. _audioCapture = this.GetComponent<UnityAudioCapture>();
  754. if (_audioCapture == null)
  755. {
  756. // Try to find it globally
  757. _audioCapture = GameObject.FindObjectOfType<UnityAudioCapture>();
  758. }
  759. if (_audioCapture == null)
  760. {
  761. // Find an AudioListener to attach the UnityAudioCapture component to
  762. AudioListener audioListener = this.GetComponent<AudioListener>();
  763. if (audioListener == null)
  764. {
  765. audioListener = GameObject.FindObjectOfType<AudioListener>();
  766. }
  767. if (audioListener != null)
  768. {
  769. _audioCapture = audioListener.gameObject.AddComponent<UnityAudioCapture>();
  770. Debug.LogWarning("[AVProMovieCapture] Capturing audio from Unity without an UnityAudioCapture assigned so we had to create one manually (very slow). Consider adding a UnityAudioCapture component to your scene and assigned it to this MovieCapture component.");
  771. }
  772. else
  773. {
  774. noAudio = true;
  775. Debug.LogWarning("[AVProMovieCapture] No audio listener found in scene. Unable to capture audio from Untiy.");
  776. }
  777. }
  778. else
  779. {
  780. Debug.LogWarning("[AVProMovieCapture] Capturing audio from Unity without an UnityAudioCapture assigned so we had to search for one manually (very slow)");
  781. }
  782. }
  783. if (noAudio || (_audioCapture == null && _audioDeviceIndex < 0))
  784. {
  785. audioCodecIndex = audioDeviceIndex = -1;
  786. _audioDeviceName = "none";
  787. noAudio = true;
  788. }
  789. _unityAudioSampleRate = -1;
  790. _unityAudioChannelCount = -1;
  791. if (IsUsingUnityAudio())
  792. {
  793. if (!_audioCapture.enabled)
  794. {
  795. _audioCapture.enabled = true;
  796. }
  797. _unityAudioSampleRate = AudioSettings.outputSampleRate;
  798. _unityAudioChannelCount = _audioCapture.NumChannels;
  799. }
  800. string info = string.Format("{0}x{1} @ {2}fps [{3}]", _targetWidth, _targetHeight, ((int)_frameRate).ToString(), _pixelFormat.ToString());
  801. if (_outputType == OutputType.VideoFile)
  802. {
  803. if (!_useMediaFoundationH264)
  804. {
  805. info += string.Format(" vcodec:'{0}'", _codecName);
  806. }
  807. else
  808. {
  809. info += " vcodec:'Media Founndation H.264'";
  810. }
  811. if (!noAudio)
  812. {
  813. if (_audioDeviceIndex >= 0)
  814. {
  815. info += string.Format(" audio device:'{0}'", _audioDeviceName);
  816. }
  817. else
  818. {
  819. info += string.Format(" audio device:'Unity' {0}hz {1} channels", _unityAudioSampleRate, _unityAudioChannelCount);
  820. }
  821. info += string.Format(" acodec:'{0}'", _audioCodecName);
  822. }
  823. info += string.Format(" to file: '{0}'", _filePath);
  824. }
  825. else if (_outputType == OutputType.NamedPipe)
  826. {
  827. info += string.Format(" to pipe: '{0}'", _filePath);
  828. }
  829. // If the user has overriden the vertical flip
  830. if (_flipVertically)
  831. _isTopDown = !_isTopDown;
  832. if (_outputType == OutputType.VideoFile)
  833. {
  834. // TOOD: make _frameRate floating point, or add timeLapse time system
  835. Debug.Log("[AVProMovieCapture] Start File Capture: " + info);
  836. _handle = NativePlugin.CreateRecorderAVI(_filePath, (uint)_targetWidth, (uint)_targetHeight, (int)_frameRate,
  837. (int)(_pixelFormat), _isTopDown, _codecIndex, !noAudio, _unityAudioSampleRate, _unityAudioChannelCount, audioDeviceIndex, audioCodecIndex, _isRealTime, _useMediaFoundationH264, _supportAlpha);
  838. }
  839. else if (_outputType == OutputType.NamedPipe)
  840. {
  841. Debug.Log("[AVProMovieCapture] Start Pipe Capture: " + info);
  842. _handle = NativePlugin.CreateRecorderPipe(_filePath, (uint)_targetWidth, (uint)_targetHeight, (int)_frameRate,
  843. (int)(_pixelFormat), _isTopDown, _supportAlpha);
  844. }
  845. if (_handle < 0)
  846. {
  847. Debug.LogError("[AVProMovieCapture] Failed to create recorder");
  848. if (!_filePath.ToLower().EndsWith(".mp4") && _useMediaFoundationH264)
  849. {
  850. Debug.LogError("[AVProMovieCapture] When using MF H.264 codec the MP4 extension must be used");
  851. }
  852. if (_filePath.ToLower().EndsWith(".mp4") && !_useMediaFoundationH264 || _codecIndex == 0)
  853. {
  854. Debug.LogError("[AVProMovieCapture] Uncompressed video codec not supported with MP4 extension, use AVI instead for uncompressed");
  855. }
  856. StopCapture();
  857. }
  858. return (_handle >= 0);
  859. }
  860. public void QueueStartCapture()
  861. {
  862. _queuedStartCapture = true;
  863. }
  864. public bool StartCapture()
  865. {
  866. if (_capturing)
  867. {
  868. return false;
  869. }
  870. if (_handle < 0)
  871. {
  872. if (!PrepareCapture())
  873. {
  874. return false;
  875. }
  876. }
  877. if (_handle >= 0)
  878. {
  879. if (IsUsingUnityAudio())
  880. {
  881. _audioCapture.FlushBuffer();
  882. }
  883. if (!NativePlugin.Start(_handle))
  884. {
  885. StopCapture(true);
  886. return false;
  887. }
  888. ResetFPS();
  889. _captureStartTime = Time.realtimeSinceStartup;
  890. // NOTE: We set this to the elapsed time so that the first frame is captured immediately
  891. float secondsPerFrame = 1f / (float)((int)_frameRate);
  892. _timeSinceLastFrame = secondsPerFrame;
  893. _capturing = true;
  894. _paused = false;
  895. }
  896. if (_startPaused)
  897. {
  898. PauseCapture();
  899. }
  900. return _capturing;
  901. }
  902. public void PauseCapture()
  903. {
  904. if (_capturing && !_paused)
  905. {
  906. if (IsUsingUnityAudio())
  907. {
  908. _audioCapture.enabled = false;
  909. }
  910. NativePlugin.Pause(_handle);
  911. if (!_isRealTime)
  912. {
  913. // TODO: should be store the timeScale value and restore it instead of assuming timeScale == 1.0?
  914. Time.timeScale = 0f;
  915. }
  916. _paused = true;
  917. ResetFPS();
  918. }
  919. }
  920. public void ResumeCapture()
  921. {
  922. if (_capturing && _paused)
  923. {
  924. if (IsUsingUnityAudio())
  925. {
  926. _audioCapture.FlushBuffer();
  927. _audioCapture.enabled = true;
  928. }
  929. NativePlugin.Start(_handle);
  930. if (!_isRealTime)
  931. {
  932. Time.timeScale = 1f;
  933. }
  934. _paused = false;
  935. if (_startPaused)
  936. {
  937. _captureStartTime = Time.realtimeSinceStartup;
  938. _startPaused = false;
  939. }
  940. }
  941. }
  942. public void CancelCapture()
  943. {
  944. StopCapture(true);
  945. // Delete file
  946. if (_outputType == OutputType.VideoFile && File.Exists(_filePath))
  947. {
  948. File.Delete(_filePath);
  949. }
  950. }
  951. public virtual void UnprepareCapture()
  952. {
  953. if (_mouseCursor != null)
  954. {
  955. _mouseCursor.enabled = false;
  956. }
  957. }
  958. #if UNITY_EDITOR
  959. public static string LastFileSaved
  960. {
  961. get
  962. {
  963. return UnityEditor.EditorPrefs.GetString("AVProMovieCapture-LastSavedFile", string.Empty);
  964. }
  965. set
  966. {
  967. UnityEditor.EditorPrefs.SetString("AVProMovieCapture-LastSavedFile", value);
  968. }
  969. }
  970. #endif
  971. protected void RenderThreadEvent(NativePlugin.PluginEvent renderEvent)
  972. {
  973. if (renderEvent == NativePlugin.PluginEvent.CaptureFrameBuffer)
  974. {
  975. #if AVPRO_MOVIECAPTURE_GLISSUEEVENT_52
  976. GL.IssuePluginEvent(_renderEventFunction, NativePlugin.PluginID | (int)renderEvent | _handle);
  977. #else
  978. GL.IssuePluginEvent(NativePlugin.PluginID | (int)renderEvent | _handle);
  979. #endif
  980. }
  981. else if (renderEvent == NativePlugin.PluginEvent.FreeResources)
  982. {
  983. #if AVPRO_MOVIECAPTURE_GLISSUEEVENT_52
  984. GL.IssuePluginEvent(_freeEventFunction, NativePlugin.PluginID | (int)renderEvent);
  985. #else
  986. GL.IssuePluginEvent(NativePlugin.PluginID | (int)renderEvent);
  987. #endif
  988. }
  989. }
  990. public virtual void StopCapture(bool skipPendingFrames = false)
  991. {
  992. UnprepareCapture();
  993. if (_capturing)
  994. {
  995. Debug.Log("[AVProMovieCapture] Stopping capture " + _handle);
  996. _capturing = false;
  997. }
  998. RenderThreadEvent(NativePlugin.PluginEvent.FreeResources);
  999. if (_handle >= 0)
  1000. {
  1001. NativePlugin.Stop(_handle, skipPendingFrames);
  1002. //System.Threading.Thread.Sleep(100);
  1003. NativePlugin.FreeRecorder(_handle);
  1004. _handle = -1;
  1005. #if UNITY_EDITOR
  1006. if (_outputType == OutputType.VideoFile && !skipPendingFrames && !string.IsNullOrEmpty(_filePath))
  1007. {
  1008. LastFileSaved = _filePath;
  1009. }
  1010. #endif
  1011. }
  1012. _fileInfo = null;
  1013. if (_audioCapture)
  1014. {
  1015. _audioCapture.enabled = false;
  1016. }
  1017. if (_motionBlur)
  1018. {
  1019. _motionBlur.enabled = false;
  1020. }
  1021. // Restore Unity timing
  1022. Time.captureFramerate = 0;
  1023. //Application.targetFrameRate = _oldTargetFrameRate;
  1024. //_oldTargetFrameRate = -1;
  1025. if (_oldFixedDeltaTime > 0f)
  1026. {
  1027. Time.fixedDeltaTime = _oldFixedDeltaTime;
  1028. }
  1029. _oldFixedDeltaTime = 0f;
  1030. if (_oldVSyncCount > 0)
  1031. {
  1032. QualitySettings.vSyncCount = _oldVSyncCount;
  1033. _oldVSyncCount = 0;
  1034. }
  1035. _motionBlur = null;
  1036. if (_texture != null)
  1037. {
  1038. Destroy(_texture);
  1039. _texture = null;
  1040. }
  1041. }
  1042. private void ToggleCapture()
  1043. {
  1044. if (_capturing)
  1045. {
  1046. //_queuedStopCapture = true;
  1047. //_queuedStartCapture = false;
  1048. StopCapture();
  1049. }
  1050. else
  1051. {
  1052. //_queuedStartCapture = true;
  1053. //_queuedStopCapture = false;
  1054. StartCapture();
  1055. }
  1056. }
  1057. private bool IsEnoughDiskSpace()
  1058. {
  1059. bool result = true;
  1060. #if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
  1061. long fileSizeMB = GetCaptureFileSize() / (1024 * 1024);
  1062. if ((_freeDiskSpaceMB - fileSizeMB) < _minimumDiskSpaceMB)
  1063. {
  1064. result = false;
  1065. }
  1066. #endif
  1067. return result;
  1068. }
  1069. private void Update()
  1070. {
  1071. if (_handle >= 0 && !_paused)
  1072. {
  1073. CheckFreeDiskSpace();
  1074. }
  1075. UpdateFrame();
  1076. }
  1077. private void CheckFreeDiskSpace()
  1078. {
  1079. if (_minimumDiskSpaceMB > 0)
  1080. {
  1081. if (!IsEnoughDiskSpace())
  1082. {
  1083. Debug.LogWarning("[AVProMovieCapture] Free disk space getting too low. Stopping capture.");
  1084. StopCapture(true);
  1085. }
  1086. }
  1087. }
  1088. protected bool IsProgressComplete()
  1089. {
  1090. bool result = false;
  1091. if (_stopMode != StopMode.None)
  1092. {
  1093. switch (_stopMode)
  1094. {
  1095. case StopMode.FramesEncoded:
  1096. result = (_numEncodedFrames >= _stopFrames);
  1097. break;
  1098. case StopMode.SecondsEncoded:
  1099. result = (_totalEncodedSeconds >= _stopSeconds);
  1100. break;
  1101. case StopMode.SecondsElapsed:
  1102. if (!_startPaused && !_paused)
  1103. {
  1104. result = ((Time.realtimeSinceStartup - _captureStartTime) >= _stopSeconds);
  1105. }
  1106. break;
  1107. }
  1108. }
  1109. return result;
  1110. }
  1111. public float GetProgress()
  1112. {
  1113. float result = 0f;
  1114. if (_stopMode != StopMode.None)
  1115. {
  1116. switch (_stopMode)
  1117. {
  1118. case StopMode.FramesEncoded:
  1119. result = (_numEncodedFrames / (float)_stopFrames);
  1120. break;
  1121. case StopMode.SecondsEncoded:
  1122. result = ((_numEncodedFrames / (float)_frameRate) / _stopSeconds);
  1123. break;
  1124. case StopMode.SecondsElapsed:
  1125. if (!_startPaused && !_paused)
  1126. {
  1127. result = ((Time.realtimeSinceStartup - _captureStartTime) / _stopSeconds);
  1128. }
  1129. break;
  1130. }
  1131. }
  1132. return result;
  1133. }
  1134. protected bool CanOutputFrame()
  1135. {
  1136. bool result = false;
  1137. if (_handle >= 0)
  1138. {
  1139. if (_isRealTime)
  1140. {
  1141. if (NativePlugin.IsNewFrameDue(_handle))
  1142. {
  1143. float secondsPerFrame = 1f / (float)((int)_frameRate);
  1144. result = (_timeSinceLastFrame >= secondsPerFrame);
  1145. //result = true;
  1146. }
  1147. }
  1148. else
  1149. {
  1150. const int WatchDogLimit = 2000;
  1151. int watchdog = 0;
  1152. if (_outputType != OutputType.NamedPipe)
  1153. {
  1154. // Wait for the encoder to have an available buffer
  1155. // The watchdog prevents an infinite while loop
  1156. while (_handle >= 0 && !NativePlugin.IsNewFrameDue(_handle) && watchdog < WatchDogLimit)
  1157. {
  1158. System.Threading.Thread.Sleep(1);
  1159. watchdog++;
  1160. }
  1161. }
  1162. // Return handle status as it may have closed elsewhere
  1163. result = (_handle >= 0) && (watchdog < WatchDogLimit);
  1164. }
  1165. }
  1166. return result;
  1167. }
  1168. protected void TickFrameTimer()
  1169. {
  1170. _timeSinceLastFrame += Time.unscaledDeltaTime;
  1171. }
  1172. protected void RenormTimer()
  1173. {
  1174. float secondsPerFrame = 1f / (float)((int)_frameRate);
  1175. if (_timeSinceLastFrame >= secondsPerFrame)
  1176. {
  1177. _timeSinceLastFrame = _timeSinceLastFrame - secondsPerFrame;
  1178. }
  1179. }
  1180. public virtual Texture GetPreviewTexture()
  1181. {
  1182. return null;
  1183. }
  1184. public virtual void UpdateFrame()
  1185. {
  1186. if (Input.GetKeyDown(_captureKey))
  1187. {
  1188. ToggleCapture();
  1189. }
  1190. if (_handle >= 0 && !_paused)
  1191. {
  1192. _numDroppedFrames = NativePlugin.GetNumDroppedFrames(_handle);
  1193. _numDroppedEncoderFrames = NativePlugin.GetNumDroppedEncoderFrames(_handle);
  1194. _numEncodedFrames = NativePlugin.GetNumEncodedFrames(_handle);
  1195. _totalEncodedSeconds = NativePlugin.GetEncodedSeconds(_handle);
  1196. if (IsProgressComplete())
  1197. {
  1198. _queuedStopCapture = true;
  1199. }
  1200. }
  1201. if (_queuedStopCapture)
  1202. {
  1203. _queuedStopCapture = false;
  1204. _queuedStartCapture = false;
  1205. StopCapture();
  1206. }
  1207. if (_queuedStartCapture)
  1208. {
  1209. _queuedStartCapture = false;
  1210. StartCapture();
  1211. }
  1212. }
  1213. private float _fps;
  1214. private int _frameTotal;
  1215. public float FPS { get { return _fps; } }
  1216. public float FramesTotal { get { return _frameTotal; } }
  1217. private int _frameCount;
  1218. private float _startFrameTime;
  1219. protected void ResetFPS()
  1220. {
  1221. _frameCount = 0;
  1222. _frameTotal = 0;
  1223. _fps = 0.0f;
  1224. _startFrameTime = 0.0f;
  1225. }
  1226. public void UpdateFPS()
  1227. {
  1228. _frameCount++;
  1229. _frameTotal++;
  1230. float timeNow = Time.realtimeSinceStartup;
  1231. float timeDelta = timeNow - _startFrameTime;
  1232. if (timeDelta >= 1.0f)
  1233. {
  1234. _fps = (float)_frameCount / timeDelta;
  1235. _frameCount = 0;
  1236. _startFrameTime = timeNow;
  1237. }
  1238. }
  1239. protected int GetCameraAntiAliasingLevel(Camera camera)
  1240. {
  1241. int aaLevel = QualitySettings.antiAliasing;
  1242. if (aaLevel == 0)
  1243. {
  1244. aaLevel = 1;
  1245. }
  1246. if (_renderAntiAliasing > 0)
  1247. {
  1248. aaLevel = _renderAntiAliasing;
  1249. }
  1250. if (aaLevel != 1 && aaLevel != 2 && aaLevel != 4 && aaLevel != 8)
  1251. {
  1252. Debug.LogError("[AVProMovieCapture] Invalid antialiasing value, must be 1, 2, 4 or 8. Defaulting to 1. >> " + aaLevel);
  1253. aaLevel = 1;
  1254. }
  1255. if (aaLevel != 1)
  1256. {
  1257. if (camera.actualRenderingPath == RenderingPath.DeferredLighting
  1258. #if AVPRO_MOVIECAPTURE_DEFERREDSHADING
  1259. || camera.actualRenderingPath == RenderingPath.DeferredShading
  1260. #endif
  1261. )
  1262. {
  1263. Debug.LogWarning("[AVProMovieCapture] Not using antialiasing because MSAA is not supported by camera render path " + camera.actualRenderingPath);
  1264. aaLevel = 1;
  1265. }
  1266. }
  1267. return aaLevel;
  1268. }
  1269. private void ConfigureCodec()
  1270. {
  1271. NativePlugin.Init();
  1272. SelectCodec(false);
  1273. if (_codecIndex >= 0)
  1274. {
  1275. NativePlugin.ConfigureVideoCodec(_codecIndex);
  1276. }
  1277. //AVProMovieCapture.Deinit();
  1278. }
  1279. public long GetCaptureFileSize()
  1280. {
  1281. long result = 0;
  1282. #if !UNITY_WEBPLAYER
  1283. if (_handle >= 0 && _outputType == OutputType.VideoFile)
  1284. {
  1285. if (_fileInfo == null && File.Exists(_filePath))
  1286. {
  1287. _fileInfo = new System.IO.FileInfo(_filePath);
  1288. }
  1289. if (_fileInfo != null)
  1290. {
  1291. _fileInfo.Refresh();
  1292. result = _fileInfo.Length;
  1293. }
  1294. }
  1295. #endif
  1296. return result;
  1297. }
  1298. public static void GetResolution(Resolution res, ref int width, ref int height)
  1299. {
  1300. switch (res)
  1301. {
  1302. case Resolution.POW2_8192x8192:
  1303. width = 8192; height = 8192;
  1304. break;
  1305. case Resolution.POW2_8192x4096:
  1306. width = 8192; height = 4096;
  1307. break;
  1308. case Resolution.POW2_4096x4096:
  1309. width = 4096; height = 4096;
  1310. break;
  1311. case Resolution.POW2_4096x2048:
  1312. width = 4096; height = 2048;
  1313. break;
  1314. case Resolution.POW2_2048x4096:
  1315. width = 2048; height = 4096;
  1316. break;
  1317. case Resolution.UHD_3840x2160:
  1318. width = 3840; height = 2160;
  1319. break;
  1320. case Resolution.UHD_3840x2048:
  1321. width = 3840; height = 2048;
  1322. break;
  1323. case Resolution.UHD_3840x1920:
  1324. width = 3840; height = 1920;
  1325. break;
  1326. case Resolution.POW2_2048x2048:
  1327. width = 2048; height = 2048;
  1328. break;
  1329. case Resolution.POW2_2048x1024:
  1330. width = 2048; height = 1024;
  1331. break;
  1332. case Resolution.HD_1920x1080:
  1333. width = 1920; height = 1080;
  1334. break;
  1335. case Resolution.HD_1280x720:
  1336. width = 1280; height = 720;
  1337. break;
  1338. case Resolution.SD_1024x768:
  1339. width = 1024; height = 768;
  1340. break;
  1341. case Resolution.SD_800x600:
  1342. width = 800; height = 600;
  1343. break;
  1344. case Resolution.SD_800x450:
  1345. width = 800; height = 450;
  1346. break;
  1347. case Resolution.SD_640x480:
  1348. width = 640; height = 480;
  1349. break;
  1350. case Resolution.SD_640x360:
  1351. width = 640; height = 360;
  1352. break;
  1353. case Resolution.SD_320x240:
  1354. width = 320; height = 240;
  1355. break;
  1356. }
  1357. }
  1358. // Returns the next multiple of 4 or the same value if it's already a multiple of 4
  1359. protected static int NextMultipleOf4(int value)
  1360. {
  1361. return (value + 3) & ~0x03;
  1362. }
  1363. }
  1364. }