当前位置:   article > 正文

Unity录屏实现(一)_unity 压缩视频

unity 压缩视频

几天前下载到一个安卓工程,可以把图片合成视频,突然想开坑做一个Unity录屏功能,然后就开始了。

Android代码:

  1. package cn.net.xuefei.unityrec;
  2. import static com.googlecode.javacv.cpp.opencv_highgui.cvLoadImage;
  3. import java.io.File;
  4. import java.io.FileNotFoundException;
  5. import java.io.FileOutputStream;
  6. import java.io.IOException;
  7. import java.io.OutputStream;
  8. import com.googlecode.javacv.FFmpegFrameRecorder;
  9. import com.googlecode.javacv.FrameRecorder.Exception;
  10. import com.googlecode.javacv.cpp.opencv_core;
  11. import com.unity3d.player.UnityPlayer;
  12. import com.unity3d.player.UnityPlayerActivity;
  13. import android.graphics.Bitmap;
  14. import android.graphics.BitmapFactory;
  15. import android.os.Bundle;
  16. import android.os.Environment;
  17. import android.util.Log;
  18. public class MainActivity extends UnityPlayerActivity {
  19. private static MainActivity ma;
  20. @Override
  21. protected void onCreate(Bundle savedInstanceState) {
  22. super.onCreate(savedInstanceState);
  23. ma = this;
  24. }
  25. public static void StartFusionVideo(final String videoName, final String frameCount, final String vidoeLength) {
  26. ma.runOnUiThread(new Runnable() {
  27. public void run() { //
  28. if (!isStarted()) {
  29. int fc = Integer.parseInt(frameCount);
  30. long vl = Long.parseLong(vidoeLength);
  31. start(videoName, fc, vl);
  32. }
  33. }
  34. });
  35. }
  36. public static void PauseFusionVideo() {
  37. pause();
  38. }
  39. public static void StopFusionVideo() {
  40. stop();
  41. }
  42. private static int switcher = 0;// 录像键
  43. private static boolean isPaused = false;// 暂停键
  44. private static String filename = null;
  45. public static int INDEX_MAX = 21;
  46. private static String filePathRoot = Environment.getExternalStorageDirectory()
  47. + "/Android/data/cn.net.xuefei.unityrec/files/";
  48. private static Bitmap frame;
  49. private static Bitmap testBitmap;
  50. public static void start(final String videoName, final int frameCount, final long vidoeLength) {
  51. Log.e("start参数:", "videoName:" + videoName + " frameCount:" + frameCount + " vidoeLength:" + vidoeLength);
  52. INDEX_MAX = frameCount - 1;
  53. frame = Bitmap.createBitmap(1080, 1920, Bitmap.Config.RGB_565);
  54. testBitmap = Bitmap.createBitmap(1080, 1920, Bitmap.Config.RGB_565);
  55. switcher = 1;
  56. new Thread() {
  57. public void run() {
  58. OutputStream os = null;
  59. filename = videoName + ".mp4";
  60. testBitmap = getFrameBitmap(filePathRoot + "0.jpg");
  61. FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(filePathRoot + filename, 1080, 1920);
  62. recorder.setFormat("mp4");
  63. // recorder.setFrameRate(30f);//录像帧率
  64. Log.e("录像帧率 ", (frameCount / (vidoeLength / 1000)) + "");
  65. Log.e("录像时长 ", vidoeLength + "");
  66. Log.e("frameCount", frameCount + "");
  67. recorder.setFrameRate(frameCount / (vidoeLength / 1000));// 录像帧率
  68. // recorder.setTimestamp(vidoeLength);
  69. try {
  70. recorder.start();
  71. } catch (Exception e) {
  72. // TODO Auto-generated catch block
  73. e.printStackTrace();
  74. }
  75. int index = 0;
  76. while (switcher != 0) {
  77. if (!isPaused) {
  78. File file = new File(filePathRoot + "video.jpg");
  79. if (!file.exists()) {
  80. file.getParentFile().mkdirs();
  81. try {
  82. file.createNewFile();
  83. } catch (IOException e) {
  84. // TODO Auto-generated catch block
  85. e.printStackTrace();
  86. }
  87. } else {
  88. file = new File(filePathRoot + "video.jpg");
  89. }
  90. try {
  91. os = new FileOutputStream(file);
  92. } catch (FileNotFoundException e) {
  93. // TODO Auto-generated catch block
  94. e.printStackTrace();
  95. }
  96. frame = getFrameBitmap(filePathRoot + index + ".jpg");
  97. frame.compress(Bitmap.CompressFormat.JPEG, 100, os);
  98. try {
  99. os.flush();
  100. } catch (IOException e) {
  101. // TODO Auto-generated catch block
  102. e.printStackTrace();
  103. }
  104. try {
  105. os.close();
  106. } catch (IOException e) {
  107. // TODO Auto-generated catch block
  108. e.printStackTrace();
  109. }
  110. // frame.recycle();
  111. // frame = null;
  112. opencv_core.IplImage image = cvLoadImage(filePathRoot + "video.jpg");
  113. try {
  114. recorder.record(image);
  115. } catch (Exception e) {
  116. // TODO Auto-generated catch block
  117. e.printStackTrace();
  118. }
  119. }
  120. if (index + 1 > INDEX_MAX) {
  121. // index = 1;
  122. try {
  123. recorder.stop();
  124. } catch (Exception e) {
  125. // TODO Auto-generated catch block
  126. e.printStackTrace();
  127. }
  128. UnityPlayer.UnitySendMessage("UnityREC", "FusionOver", videoName);
  129. } else {
  130. index++;
  131. }
  132. try {
  133. recorder.stop();
  134. } catch (Exception e) {
  135. // TODO Auto-generated catch block
  136. e.printStackTrace();
  137. }
  138. UnityPlayer.UnitySendMessage("UnityREC", "FusionOver", videoName);
  139. }
  140. }
  141. }.start();
  142. }
  143. public static void stop() {
  144. switcher = 0;
  145. isPaused = false;
  146. }
  147. public static void pause() {
  148. if (switcher == 1) {
  149. isPaused = true;
  150. }
  151. }
  152. public static void restart() {
  153. if (switcher == 1) {
  154. isPaused = false;
  155. }
  156. }
  157. public static boolean isStarted() {
  158. if (switcher == 1) {
  159. return true;
  160. } else {
  161. return false;
  162. }
  163. }
  164. public static boolean isPaused() {
  165. return isPaused;
  166. }
  167. static Bitmap image = null;
  168. private static Bitmap getFrameBitmap(String filename) {
  169. image = BitmapFactory.decodeFile(filename);
  170. return image;
  171. }
  172. }

Unity代码:

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.IO;
  4. using System;
  5. using System.Diagnostics;
  6. using System.Collections.Generic;
  7. public class UnityREC : MonoBehaviour
  8. {
  9. Texture2D tex;
  10. int width;
  11. int height;
  12. Queue<byte[]> imageBytes = new Queue<byte[]>();
  13. bool isREC = false;
  14. int index = 0;
  15. private Rect CutRect = new Rect(0, 0, 1, 1);
  16. private RenderTexture rt;
  17. // Use this for initialization
  18. void Start()
  19. {
  20. width = Screen.width;
  21. height = Screen.height;
  22. tex = new Texture2D(width, height, TextureFormat.RGB24, false);
  23. rt = new RenderTexture(width, height, 2, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default);
  24. Camera.main.pixelRect = new Rect(0, 0, width, height);
  25. Camera.main.targetTexture = rt;
  26. //StartCoroutine(StartREC());
  27. }
  28. // Update is called once per frame
  29. void Update()
  30. {
  31. if (isREC && Time.time > nextFire)
  32. {
  33. //StartCoroutine(StartREC());
  34. StartRec();
  35. }
  36. }
  37. float startTime = 0;
  38. float videoLength = 0;
  39. void OnGUI()
  40. {
  41. if (GUI.Button(new Rect(0, 0, 300, 300), "开始截屏"))
  42. {
  43. if (isREC)
  44. {
  45. isREC = false;
  46. videoLength = Time.time - startTime;
  47. return;
  48. }
  49. else
  50. {
  51. isREC = true;
  52. startTime = Time.time;
  53. index = 0;
  54. return;
  55. }
  56. }
  57. if (GUI.Button(new Rect(0, 300, 300, 300), "合成视频"))
  58. {
  59. #if UNITY_ANDROID
  60. AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
  61. AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
  62. jo.CallStatic("StartFusionVideo", new object[] { DateTime.Now.ToFileTime().ToString(), index + "", Convert.ToInt32(videoLength * 1000).ToString() });
  63. #elif UNITY_IPHONE
  64. #endif
  65. }
  66. }
  67. void FixedUpdate()
  68. {
  69. if (imageBytes.Count > 0)
  70. {
  71. File.WriteAllBytes(Application.persistentDataPath + "/" + index + ".jpg", imageBytes.Dequeue());
  72. index++;
  73. }
  74. }
  75. byte[] imagebytes;
  76. float fireRate = 0.02F;
  77. float nextFire = 0.0F;
  78. IEnumerator StartREC()
  79. {
  80. nextFire = Time.time + fireRate;
  81. yield return new WaitForEndOfFrame();
  82. tex.ReadPixels(new Rect(0, 0, width, height), 0, 0, false);
  83. //tex.Compress(false);//对屏幕缓存进行压缩
  84. imagebytes = tex.EncodeToJPG(50);//转化为jpg图
  85. //float t = Time.time;
  86. //Stopwatch sw = new Stopwatch();
  87. //sw.Start();
  88. //UnityEngine.Debug.Log(string.Format("total: {0} ms", Time.time - t));
  89. imageBytes.Enqueue(imagebytes);
  90. // sw.Stop();
  91. //UnityEngine.Debug.Log(string.Format("total: {0} ms", sw.ElapsedMilliseconds));
  92. }
  93. void StartRec()
  94. {
  95. nextFire = Time.time + fireRate;
  96. float t = Time.time;
  97. Stopwatch sw = new Stopwatch();
  98. sw.Start();
  99. UnityEngine.Debug.Log(string.Format("total: {0} ms", Time.time - t));
  100. Camera.main.Render();
  101. RenderTexture.active = rt;
  102. tex.ReadPixels(new Rect(width * CutRect.x, width * CutRect.y, width * CutRect.width, height * CutRect.height), 0, 0);
  103. Camera.main.targetTexture = null;
  104. RenderTexture.active = null;
  105. imagebytes = tex.EncodeToJPG();
  106. imageBytes.Enqueue(imagebytes);
  107. sw.Stop();
  108. UnityEngine.Debug.Log(string.Format("total: {0} ms", sw.ElapsedMilliseconds));
  109. }
  110. public void FusionOver(string videoName)
  111. {
  112. UnityEngine.Debug.Log("videoName:" + videoName);
  113. }
  114. }


现在的结果是,截图实现了,但是很卡……

卡到截取一帧耗时300多毫秒……


合成视频调用失败:

不知道万能的博友有什么建议……


点击这里下载工程

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/728925
推荐阅读
相关标签
  

闽ICP备14008679号