首页 > 解决方案 > 来自网络摄像头的 WebRTC 快照并将其保存到 PHP 中的服务器:iPhone Safari 在分辨率高于 2096 时崩溃

问题描述

我有一个工作代码可以从网络摄像头拍摄快照并通过 ajax 将其保存在 PHP 中......但是当我尝试使用高于 2000 的分辨率时,iPhone 上的 safari mobile 崩溃,为什么以及如何解决这个问题?

在这里,如果我这样做getUserMedia({ video:{width: { ideal: 2096=> 没关系

但是如果我 fo getUserMedia({ video:{width: { ideal: 3096=> 它会崩溃:(

HTML

<video id="precam" playsinline="true" muted autoplay style="max-width:90%;" ></video>
<canvas id="canvax" ></canvas>
<div onclick="sendToServer('ajaxanswer');">SAVE</div>
<div onclick="webcamFRONT();">SWITCH TO FRONT CAM</div>
<div id="ajaxanswer" ></div>

JAVASCRIPT

<script>
const videoPlayer = document.querySelector("#precam"); 
const canvas = document.querySelector("#canvax");

function webcamREAR () {
    navigator.mediaDevices.getUserMedia({ video:{width: { ideal: 2096 },facingMode: "environment"}, audio:false })
        .then(stream => videoPlayer.srcObject = stream)
        .catch(error => {console.error(error);});
}

function webcamFRONT () {
    navigator.mediaDevices.getUserMedia({ video:{width: { ideal: 2096 },facingMode: "user"}, audio:false })
        .then(stream => videoPlayer.srcObject = stream)
        .catch(error => {console.error(error);});
}
        
function wcanvasim () { 
    canvas.width = videoPlayer.videoWidth; canvas.height = videoPlayer.videoHeight;
    canvas.getContext("2d").drawImage(videoPlayer, 0, 0, canvas.width, canvas.height);
}

webcamREAR();

function sendToServer (divID) {
    var pcache = (Math.floor(Math.random() * 100000000) + 1);
    var params = "divID="+encodeURIComponent(divID)+"&canvablob="+encodeURIComponent(canvas.toDataURL());
    var xhr = new XMLHttpRequest(); xhr.open("POST", "/file.php?pcache="+pcache, true);
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    xhr.onreadystatechange = function(e) { if (xhr.readyState == 4) { $("#"+divID).html(e.currentTarget.responseText) ; } }
    xhr.send(params);
}
</script>

PHP

<?php

$whereTOdeBlob = '/path/to/server/'.mt_rand().'.png';
$canvablob = ( $_REQUEST['canvablob'] ?? '' ) ;
$canva64 = explode('base64,',$canvablob)[1] ?? '';
file_put_contents(INCLUDE_PATH_ROOT.$whereTOdeBlob,base64_decode($canva64));

// CONVERT TO JPG
// ADD TO DATABASE
// ANY STUFF YOU WANT ;)

echo '<img src="'.$canvablob.'" />';

?>

******* 问题是:为什么大分辨率会导致 safari mobile 崩溃?

标签: iphoneajaxwebrtcmobile-safarigetusermedia

解决方案


您可以.toDataURL()将那个巨大的图像编码为无损 .png 文件。这可能会生成一个您尝试发布的数兆字节字符串。Safari 可能会在分配或垃圾收集时耗尽连续的 RAM和 gack。您的 POST 的有效负载大小也可能超过 php 的最大值

尝试.toDataURL('image/jpeg', 0.3)获取低质量的JPEG 图像,这将生成更小的字符串。如果可行,请提高质量(0.3 到 0.4、0.5 等)。

或者,更好的是,将您的画布转换为二进制 Blob,然后发布。它将比数据 URL 占用更少的空间。像这样的东西。不,重复不,调试。

function sendToServer (divID) {
    var pcache = (Math.floor(Math.random() * 100000000) + 1)
    canvas.toBlob (function (blob) {
      var xhr = new XMLHttpRequest()
      xhr.open("POST", "/file.php?pcache="+pcache, true);
      xhr.onreadystatechange = function (e) { 
        if (xhr.readyState == 4) 
           $("#"+divID).html(e.currentTarget.responseText) 
      }

      var fd = new FormData();
      fd.append('divID', divID)
      fd.append('canvaBlob', blob)
      xhr.send(fd)
    }, 'image/jpeg', 0.8)
}

此外,尝试限制图像的高度和宽度。如果您的相机处于纵向模式并且您要求 2K 宽度,如果您让.getUserMedia()选择它想要的任何高度,您可能会得到 4K 高度;它遵循默认的纵横比。

最后,在实际意义上,分辨率如此之高的图像通常必须在使用之前进行下采样。较低分辨率的 JPEG 图像通常可以满足实际需求。因此,只需捕获较低分辨率的图像。(如果您是一名摄影师,拍摄照片以在光面杂志上打印,那么您已经知道 iPhone 相机的局限性。)


推荐阅读