Unity 在WebGL上錄制視頻和截圖

最近有個(gè)項(xiàng)目需要發(fā)布到web平臺(tái),項(xiàng)目中需要視頻錄制和截圖,嘗試了一些插件,在iOS和Android還可以,WebGL上沒(méi)有找到合適的。網(wǎng)上查了下,WebGL2.0已經(jīng)原生的支持視頻錄制和截圖了,于是研究了下,目前已經(jīng)應(yīng)用在項(xiàng)目中了,現(xiàn)在把Unity在WebGL上視頻錄制和截圖整理成一個(gè)Unity項(xiàng)目分享出來(lái),以饗各位有興趣的朋友。

1.WebGL中錄制視頻和截圖

這個(gè)直接去官網(wǎng)找例子,不多說(shuō)了,直接貼代碼:

/** WebGLRecoder.js
**  WebGL錄制視頻和截圖
*/
let mediaRecorder;
let recordedBlobs;
let canvas;
let stream;

//截圖
function ScreenShot(fileName) {
    console.log('ScreenShot', fileName);
    canvas = document.querySelector('canvas');
    console.log(typeof(canvas));
    console.log(canvas);
    var dataURL = canvas.toDataURL('image/png');
        //直接下載
    var a = document.createElement("a");
    a.style.display = 'none';
    a.href = dataURL;
    a.download = fileName;
    document.body.appendChild(a);
    a.click();
    setTimeout(() =>{
        document.body.removeChild(a);
        //window.URL.revokeObjectURL(url);
    },
    100);
    console.log('ScreenShot', dataURL);
}

function handleDataAvailable (event) {
    if (event.data && event.data.size > 0) {
        recordedBlobs.push(event.data);
    }
}

function handleStop (event) {
    console.log('Recorder stopped: ', event);
}

//開(kāi)始錄制
function StartRecording () {
    canvas = document.querySelector('canvas');
    stream = canvas.captureStream(); // frames per second
    let options = {mimeType: 'video/webm'};
    recordedBlobs = [];
    try {
        mediaRecorder = new MediaRecorder(stream, options);
    } catch(e0) {
        console.log('Unable to create MediaRecorder with options Object: ', e0);
        try {
            options = {
                mimeType: 'video/webm,codecs=vp9'
            };
            mediaRecorder = new MediaRecorder(stream, options);
        } catch(e1) {
            console.log('Unable to create MediaRecorder with options Object: ', e1);
            try {
                options = 'video/vp8'; // Chrome 47
                mediaRecorder = new MediaRecorder(stream, options);
            } catch(e2) {
                alert('MediaRecorder is not supported by this browser.\n\n' + 'Try Firefox 29 or later, or Chrome 47 or later, ' + 'with Enable experimental Web Platform features enabled from chrome://flags.');
                console.error('Exception while creating MediaRecorder:', e2);
                return;
            }
        }
    }
    console.log('Created MediaRecorder', mediaRecorder, 'with MIME_TYPE', options);
    mediaRecorder.onstop = handleStop;
    mediaRecorder.ondataavailable = handleDataAvailable;
    mediaRecorder.start(100); // collect 100ms of data
    console.log('MediaRecorder started', mediaRecorder);
}

//完成錄制
function StopRecording () {
    console.log("WebGLRecoder: Stopping recording"),
    mediaRecorder.stop();
}

//下載
function RecordDownload (fileName) {
    console.log('RecordDownload');
    const blob = new Blob(recordedBlobs, {
        type: 'video/webm'
    });
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = url;
    //a.download = 'test.webm';
    a.download = fileName;
    document.body.appendChild(a);
    a.click();
    setTimeout(() =>{
        document.body.removeChild(a);
        window.URL.revokeObjectURL(url);
    },
    100);
}

2.基于jslib的Unity與WebGL跨平臺(tái)通信

在瀏覽器中,調(diào)用JavaScript的推薦方法是將JavaScript源添加到項(xiàng)目中,然后直接從腳本代碼中調(diào)用這些函數(shù),Unity有自己在WebGL中實(shí)現(xiàn)的庫(kù),而且Unity最終會(huì)使用emscripten將源代碼從C / C ++代碼編譯為JavaScript。
其做法就是在Assets/Plugins/WebGL中新建一個(gè).jslib的文件:

// WebGLRecoder.jslib
const WebGLRecoder = {
    $sharedInstance: {
        
    },
    WebGLScreenShot: function(fileName) {
        console.log('ScreenShot', Pointer_stringify(fileName));
        ScreenShot(Pointer_stringify(fileName));
    },
    WebGLStartRecording: function() {
        StartRecording();
    },
    WebGLStopRecording: function(obj) {
        console.log("WebGLRecoder: Stopping recording");
        StopRecording();
        Runtime.dynCall('v', obj, 0);
    },
    WebGLRecordDownload: function(fileName) {
        console.log('RecordDownload: ', Pointer_stringify(fileName));
        RecordDownload(Pointer_stringify(fileName));
    },
    WebGLGetStudentName: function(){
        var name = getStudentNameFromLocal();
        console.log('name:'+name);
        //Get size of the string
        var bufferSize = lengthBytesUTF8(name) + 1;
        //Allocate memory space
        var buffer = _malloc(bufferSize);
        //Copy old data to the new one then return it
        stringToUTF8(name, buffer, bufferSize);
        return buffer;
    },
    WebGLGetStudentNo: function(){
        var no = getStudentNoFromLocal();
        console.log('no:'+no);
        //Get size of the string
        var bufferSize = lengthBytesUTF8(no) + 1;
        //Allocate memory space
        var buffer = _malloc(bufferSize);
        //Copy old data to the new one then return it
        stringToUTF8(no, buffer, bufferSize);
        return buffer;
    },
    WebGLIsLogin: function(){
       if(hasLogin()){
            return 1;
       }else{
            return 0;
        }
    },
    WebGLLogin: function(){
        console.log('login');
        Login();
    },
    WebGLGetServerHost: function(){
        var host =  getServerHost();
        console.log('host:'+host);
        //Get size of the string
        var bufferSize = lengthBytesUTF8(host) + 1;
        //Allocate memory space
        var buffer = _malloc(bufferSize);
        //Copy old data to the new one then return it
        stringToUTF8(host, buffer, bufferSize);
        return buffer;
    },
    WebGLGetFileServerHost: function(){
        var host = getFileServerHost();
        console.log('host:'+host);
        //Get size of the string
        var bufferSize = lengthBytesUTF8(host) + 1;
        //Allocate memory space
        var buffer = _malloc(bufferSize);
        //Copy old data to the new one then return it
        stringToUTF8(host, buffer, bufferSize);
        return buffer;
    }
};
autoAddDeps(WebGLRecoder, "$sharedInstance"),
mergeInto(LibraryManager.library, WebGLRecoder);

這個(gè)jslib調(diào)用上述js中的方法,并且提供接口給C#調(diào)用:


using AOT;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
public class WebGLManager : SingletonMonoNewGO<WebGLManager>
{
   /// <summary>
   /// C#-->WebGLRecoder.jslib-->WebGLRecoder.js(index.html <script src="js/WebGLRecoder.js"></script>)
   /// </summary>
   /// <param name="fileName"></param>
#if UNITY_WEBGL && !UNITY_EDITOR
   [DllImport(@"__Internal")]
   public static extern void WebGLScreenShot(string fileName);
   [DllImport(@"__Internal")]
   public static extern void WebGLStartRecording();
   [DllImport(@"__Internal")]
   public static extern void WebGLStopRecording(Action callback);
   [DllImport(@"__Internal")]
   public static extern void WebGLRecordDownload(string fileName); 
#endif
   public void ScreenShot(string fileName)
   {
#if UNITY_WEBGL && !UNITY_EDITOR
       WebGLScreenShot(fileName);
#endif
   }

   public void StartRecording()
   {
#if UNITY_WEBGL && !UNITY_EDITOR
       WebGLStartRecording();
#endif
   }

   /// <summary>
   /// 停止錄屏
   /// </summary>
   /// <param name="callback">該回調(diào)一定是靜態(tài)方法</param>
   public void StopRecording(Action callback)
   {
#if UNITY_WEBGL && !UNITY_EDITOR
       WebGLStopRecording(callback);
#endif
   }

   public void RecordDownload(string fileName)
   {
#if UNITY_WEBGL && !UNITY_EDITOR
       WebGLRecordDownload(fileName);
#endif
   }
}

3.發(fā)布WebGL,在html導(dǎo)入相關(guān)js

完成C#與jslib的對(duì)接后,就可以發(fā)布webgl工程了,


WebGL工程結(jié)構(gòu)

這里我已經(jīng)將第一步編寫(xiě)的錄制視頻和截圖的WebGLRecoder.js文件放到j(luò)s目錄下(沒(méi)有就創(chuàng)建一個(gè)),index.html中導(dǎo)入js文件

<!DOCTYPE html>
<html lang="en-us">
<head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Unity WebGL Player | Holder-Hander</title>
    <link rel="shortcut icon" href="TemplateData/favicon.ico">
    <link rel="stylesheet" href="TemplateData/style.css">
    <script src="TemplateData/UnityProgress.js"></script>
    <script src="Build/UnityLoader.js"></script>
    <!-- 錄制和截圖js-->
    <script src="js/WebGLRecoder.js"></script>
    <script>
        var gameInstance = UnityLoader.instantiate("gameContainer", "Build/webgl.json", {
            onProgress: UnityProgress,
            Module: {
                webglContextAttributes: {"preserveDrawingBuffer": true},
            }
        });
    </script>
</head>
<body>
<div class="webgl-content">
    <div id="gameContainer" style="width: 960px; height: 600px"></div>
    <div class="footer">
        <div class="fullscreen" onclick="gameInstance.SetFullscreen(1)"></div>
    </div>
</div>
</body>
</html>

還有要注意WebGL必須要部署到一個(gè)web服務(wù)器上才能打開(kāi),不能直接通過(guò)瀏覽器打開(kāi)。
到此終于,可以開(kāi)心的去開(kāi)發(fā)業(yè)務(wù)功能了。
項(xiàng)目我已經(jīng)整理出來(lái)了,github地址:https://github.com/eangulee/UnityWebGLRecoder
好了,最近研究了下AR環(huán)境下的手勢(shì)識(shí)別,demo已經(jīng)上傳到github,有興趣的可以去筆者的github中找一下,有空再寫(xiě)篇文章介紹下吧。
哈哈哈哈哈,國(guó)慶要去浪了~~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 構(gòu)建和運(yùn)行WebGL項(xiàng)目 當(dāng)您構(gòu)建(buil)WebGL項(xiàng)目時(shí),Unity將創(chuàng)建一個(gè)包含以下文件的文件夾: 一個(gè)i...
    tackor閱讀 4,518評(píng)論 0 2
  • WebGL:與瀏覽器腳本進(jìn)行交互 在為網(wǎng)絡(luò)構(gòu)建內(nèi)容時(shí),您可能需要與網(wǎng)頁(yè)上的其他元素進(jìn)行通信?;蛘吣赡芟M褂肬n...
    tackor閱讀 2,443評(píng)論 0 0
  • 文/葉老巫 || 每天絮絮叨叨,堅(jiān)持日更, 今天是第 120 篇 1、 寫(xiě)作就是談戀愛(ài),和你心愛(ài)的人,一生在拍拖。...
    葉兩步閱讀 1,048評(píng)論 4 28
  • 文字/攝影:若木菡 花面翻卷更美艷 花心花蕊盡展顏 多子多孫多福氣 大地遍開(kāi)黃卷丹
    若木菡閱讀 866評(píng)論 22 19
  • 在Windows下使用Nginx,我們需要掌握一些基本的操作命令,比如:?jiǎn)?dòng)、停止Nginx服務(wù),重新載入Ngin...
    凡凡的小web閱讀 298評(píng)論 0 0

友情鏈接更多精彩內(nèi)容