Unity錄屏實現(一)

幾天前下載到一個安卓工程,可以把圖片合成視頻,突然想開坑做一個Unity錄屏功能,然後就開始了。

Android代碼:

package cn.net.xuefei.unityrec;

import static com.googlecode.javacv.cpp.opencv_highgui.cvLoadImage;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import com.googlecode.javacv.FFmpegFrameRecorder;
import com.googlecode.javacv.FrameRecorder.Exception;
import com.googlecode.javacv.cpp.opencv_core;
import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;

public class MainActivity extends UnityPlayerActivity {
	private static MainActivity ma;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		ma = this;
	}

	public static void StartFusionVideo(final String videoName, final String frameCount, final String vidoeLength) {
		ma.runOnUiThread(new Runnable() {
			public void run() { //
				if (!isStarted()) {
					int fc = Integer.parseInt(frameCount);
					long vl = Long.parseLong(vidoeLength);
					start(videoName, fc, vl);
				}
			}
		});
	}

	public static void PauseFusionVideo() {
		pause();
	}

	public static void StopFusionVideo() {
		stop();
	}

	private static int switcher = 0;// 錄像鍵
	private static boolean isPaused = false;// 暫停鍵
	private static String filename = null;
	public static int INDEX_MAX = 21;

	private static String filePathRoot = Environment.getExternalStorageDirectory()
			+ "/Android/data/cn.net.xuefei.unityrec/files/";
	private static Bitmap frame;
	private static Bitmap testBitmap;

	public static void start(final String videoName, final int frameCount, final long vidoeLength) {
		Log.e("start參數:", "videoName:" + videoName + " frameCount:" + frameCount + " vidoeLength:" + vidoeLength);
		INDEX_MAX = frameCount - 1;
		frame = Bitmap.createBitmap(1080, 1920, Bitmap.Config.RGB_565);
		testBitmap = Bitmap.createBitmap(1080, 1920, Bitmap.Config.RGB_565);
		switcher = 1;
		new Thread() {
			public void run() {

				OutputStream os = null;

				filename = videoName + ".mp4";
				testBitmap = getFrameBitmap(filePathRoot + "0.jpg");

				FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(filePathRoot + filename, 1080, 1920);

				recorder.setFormat("mp4");
				// recorder.setFrameRate(30f);//錄像幀率
				Log.e("錄像幀率 ", (frameCount / (vidoeLength / 1000)) + "");
				Log.e("錄像時長 ", vidoeLength + "");
				Log.e("frameCount", frameCount + "");
				recorder.setFrameRate(frameCount / (vidoeLength / 1000));// 錄像幀率
				// recorder.setTimestamp(vidoeLength);
				try {
					recorder.start();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

				int index = 0;
				while (switcher != 0) {
					if (!isPaused) {
						File file = new File(filePathRoot + "video.jpg");
						if (!file.exists()) {
							file.getParentFile().mkdirs();
							try {
								file.createNewFile();
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						} else {
							file = new File(filePathRoot + "video.jpg");
						}
						try {
							os = new FileOutputStream(file);
						} catch (FileNotFoundException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						frame = getFrameBitmap(filePathRoot + index + ".jpg");
						frame.compress(Bitmap.CompressFormat.JPEG, 100, os);

						try {
							os.flush();
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						try {
							os.close();
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						// frame.recycle();
						// frame = null;
						opencv_core.IplImage image = cvLoadImage(filePathRoot + "video.jpg");
						try {
							recorder.record(image);
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}

					}
					if (index + 1 > INDEX_MAX) {
						// index = 1;
						try {
							recorder.stop();
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						UnityPlayer.UnitySendMessage("UnityREC", "FusionOver", videoName);
					} else {
						index++;
					}
					try {
						recorder.stop();
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					UnityPlayer.UnitySendMessage("UnityREC", "FusionOver", videoName);
				}
			}
		}.start();
	}

	public static void stop() {
		switcher = 0;
		isPaused = false;
	}

	public static void pause() {
		if (switcher == 1) {
			isPaused = true;
		}
	}

	public static void restart() {
		if (switcher == 1) {
			isPaused = false;
		}
	}

	public static boolean isStarted() {
		if (switcher == 1) {
			return true;
		} else {
			return false;
		}
	}

	public static boolean isPaused() {
		return isPaused;
	}

	static Bitmap image = null;

	private static Bitmap getFrameBitmap(String filename) {
		image = BitmapFactory.decodeFile(filename);
		return image;
	}
}

Unity代碼:

using UnityEngine;
using System.Collections;
using System.IO;
using System;
using System.Diagnostics;
using System.Collections.Generic;

public class UnityREC : MonoBehaviour
{
    Texture2D tex;
    int width;
    int height;
    Queue<byte[]> imageBytes = new Queue<byte[]>();
    bool isREC = false;
    int index = 0;

    private Rect CutRect = new Rect(0, 0, 1, 1);
    private RenderTexture rt;
    // Use this for initialization
    void Start()
    {
        width = Screen.width;
        height = Screen.height;
        tex = new Texture2D(width, height, TextureFormat.RGB24, false);
        rt = new RenderTexture(width, height, 2, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default);
        Camera.main.pixelRect = new Rect(0, 0, width, height);
        Camera.main.targetTexture = rt;
        //StartCoroutine(StartREC());
    }

    // Update is called once per frame
    void Update()
    {
        if (isREC && Time.time > nextFire)
        {
            //StartCoroutine(StartREC());
            StartRec();
        }
    }

    float startTime = 0;
    float videoLength = 0;

    void OnGUI()
    {
        if (GUI.Button(new Rect(0, 0, 300, 300), "開始截屏"))
        {
            if (isREC)
            {
                isREC = false;
                videoLength = Time.time - startTime;
                return;
            }
            else
            {
                isREC = true;
                startTime = Time.time;
                index = 0;
                return;
            }
        }

        if (GUI.Button(new Rect(0, 300, 300, 300), "合成視頻"))
        {
#if UNITY_ANDROID
            AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
            AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
            jo.CallStatic("StartFusionVideo", new object[] { DateTime.Now.ToFileTime().ToString(), index + "", Convert.ToInt32(videoLength * 1000).ToString() });
#elif  UNITY_IPHONE
		 
#endif
        }
    }

    void FixedUpdate()
    {
        if (imageBytes.Count > 0)
        {
            File.WriteAllBytes(Application.persistentDataPath + "/" + index + ".jpg", imageBytes.Dequeue());
            index++;
        }
    }


    byte[] imagebytes;
    float fireRate = 0.02F;
    float nextFire = 0.0F;
    IEnumerator StartREC()
    {
        nextFire = Time.time + fireRate;
        yield return new WaitForEndOfFrame();
        tex.ReadPixels(new Rect(0, 0, width, height), 0, 0, false);
        //tex.Compress(false);//對屏幕緩存進行壓縮 
        imagebytes = tex.EncodeToJPG(50);//轉化爲jpg圖  
        //float t = Time.time;
        //Stopwatch sw = new Stopwatch();
        //sw.Start();
        //UnityEngine.Debug.Log(string.Format("total: {0} ms", Time.time - t));

        imageBytes.Enqueue(imagebytes);

        // sw.Stop();
        //UnityEngine.Debug.Log(string.Format("total: {0} ms", sw.ElapsedMilliseconds)); 
    }

    void StartRec()
    {
        nextFire = Time.time + fireRate;
        float t = Time.time;
        Stopwatch sw = new Stopwatch();
        sw.Start();
        UnityEngine.Debug.Log(string.Format("total: {0} ms", Time.time - t));
        Camera.main.Render();
        RenderTexture.active = rt;
        tex.ReadPixels(new Rect(width * CutRect.x, width * CutRect.y, width * CutRect.width, height * CutRect.height), 0, 0);
        Camera.main.targetTexture = null;
        RenderTexture.active = null;
        imagebytes = tex.EncodeToJPG();
        imageBytes.Enqueue(imagebytes);
        sw.Stop();
        UnityEngine.Debug.Log(string.Format("total: {0} ms", sw.ElapsedMilliseconds));
    }

    public void FusionOver(string videoName)
    {
        UnityEngine.Debug.Log("videoName:" + videoName);
    }


}


現在的結果是,截圖實現了,但是很卡……

卡到截取一幀耗時300多毫秒……


合成視頻調用失敗:

不知道萬能的博友有什麼建議……


點擊這裏下載工程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章