我有一个 arducam mini 2MP 相机连接到 ESP8266 (12-E) 模块,我试图在一个窗口内实现视频流,它周围有一些文本和控制按钮,所有这些都在同一个浏览器选项卡/页面中。我已经创建了两个 HTML 页面供服务器使用。第一个是没有图像流的主页,只是一个带有文本按钮和一些 CSS 的简单页面。第二个 HTML 页面为浏览器提供连续帧(流视频)以及一些文本和按钮。当主页被发送到浏览器时,一切都以我期望的方式显示。但是,当提供第二个 HTML 网页时,当浏览器(Firefox 或 Chrome)收到来自服务器(esp12-e)的回复时,会发生一些奇怪的事情。
通常,我希望有一个小窗口显示从相机拍摄的连续帧,该窗口上方有一些文本,下方有一些控制按钮。但是,不是发生了两件事。
- 浏览器选项卡中仅显示视频流窗口,但该窗口周围只有灰色背景色。没有按钮没有文字。当我打开 HTML Inspector 时,在“head”内部,有几行 HTML 代码创建了背景灰色和一些我没有在服务器中编写的 CSS 内容。浏览器以某种方式自动创建这行代码并将它们添加到我的原始 HTML 代码中。
- 在我的原始 HTML 代码中,在“body”中,连同流窗口的代码,我有将显示的文本和按钮元素的代码。但是在浏览器中,这些部分消失了。当我打开 Inspector 时,这些元素不存在!到目前为止,我已经尝试了各种方法来通过在浏览器选项卡中隔离/嵌入流窗口来避免这种情况。这些方法是:iframe、数据 URI、多部分/x 混合替换、表单。不幸的是,所有这些方法都出现了相同的结果(灰色背景、屏幕中间的流窗口以及消失的按钮和文本)。
我唯一知道的是,当浏览器“看到”来自服务器的传入图像时,它会产生这些副作用。当我仅使用文本和按钮创建 HTML 时,它显示得很好。我在这里做错了,但我找不到它是什么。
下面我附上 2 张我在浏览器选项卡中得到的图片以及我从 esp-12e 服务器发送的用于拍照的 HTML 代码
void serveWebpage(WiFiClient client){
String answer = "HTTP/1.1 200 OK\r\n";
answer += "Content-Type: text/html\r\n\r\n";
answer +="<!DOCTYPE HTML>\r\n";
answer += "<html>\r\n";
answer +="<head><title> Monitor </title></head>\r\n";
answer += "<body>\r\n";
answer += "<h1 style=\"position:relative; left:25px;\"> ⚓ Observation Panel ⚓</h1>\r\n"; // Header Text
answer += "<a href=\"/videoStream\"><button type=\"button\" style=\"position:absolute; top:340px;"; // First Button
answer += "left:95px; color:blue; height:70px; width:90px; font-weight: bold; border-style:outset;";
answer += "border-width:2px; border-color:black;\"> Video Stream </button></a>\r\n";
answer += "<a href=\"PhotoCapture\"><button type=\"button\" style=\"position:absolute; top:340px;"; // Second Button
answer += "left:195px; color:blue; height:70px; width:90px; font-weight: bold; border-style:outset;";
answer += "border-width:2px; border-color:black;\"> Video Stream </button></a>\r\n";
answer += "<div>\r\n";
answer += "<img src='data:image/jpeg; charset=utf-8; base64,"; // Here the image is wrapped with data URI to display it in the browser
myCAM.clear_fifo_flag(); // this part is taken from the arducam library exammples. It captures the image and sends it to browser
myCAM.start_capture();
while (!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK)); // wait here until capture has completed
size_t len = myCAM.read_fifo_length();
myCAM.CS_LOW();
myCAM.set_fifo_burst();
#if !(defined (ARDUCAM_SHIELD_V2) && defined (OV2640_CAM))
SPI.transfer(0xFF);
#endif
static const size_t bufferSize = 4096; //4096
static uint8_t buffer[bufferSize] = {0xFF};
while (len) {
size_t will_copy = (len < bufferSize) ? len : bufferSize;
SPI.transferBytes(&buffer[0], &buffer[0], will_copy);
if (!client.connected()) break;
client.write(&buffer[0], will_copy);
len -= will_copy;
}
myCAM.CS_HIGH();
answer +="9k=' />"; // closing the <img>
answer +="</div>\r\n";
answer +="</body>\r\n";
answer +="</html>\r\n\r\n";
client.print(answer);
}
我最终取得了一些进展,但不是 100%。我设法在 iframe 中显示 jpeg 图像,方法是在 iframe 元素内使用数据 URI 方法从图像嵌入 jpeg 格式的数据。
string = "<iframe srcdoc='<img src=\"data:html/text;base64,/9j/4AAQ..... \" > ' > ";
我的错误是我没有以正确的顺序使用引号,图像数据在浏览器中被解释为文本。然后我尝试用我用来将捕获的图像从相机发送到浏览器的函数做同样的事情。不幸的是,出现了同样的问题,这次我无法解决。当我向浏览器发送带有多个引号的字符串时会发生一些事情,因为它将它们解释为文本而不是像这样的 jpeg 数据格式:/9j/4AAQ......我从浏览器的检查器上传了一张图片(显示浏览器的当我使用相机发送的帧数据功能时收到的数据)以更容易地理解我的意思。对此有何想法?
这是对我迄今为止完成的内容的回顾。我创建了一个 HTML,其中包含一个 Iframe 和一些按钮。iframe 和按钮都在同一浏览器的选项卡中正确显示。现在,在 iframe 内部,我放置了 srcdoc 属性并将原始 jpeg 数据直接插入其中(示例 jpeg 图像),因为它们已被编码(base64),但浏览器将这些 jpeg 数据解释为纯文本并将它们作为文本显示在 iframe 中。然后我使用 srcdoc 中的图像标签将原始 jpeg 数据包装在 iframe 中。这在我对 iframe 字符串中的引号做了一些错误之后起作用了。然后我从图像标签中删除了原始 jpeg 数据,并将它们替换为从相机中获取 jpeg 数据的函数。我发送答案字符串的第一部分(打开 iframe 和 img 标签),然后我从相机发送数据,最后我发送答案字符串的第二部分(关闭 iframe 和 img 标签)。通常它应该可以工作,因为我遵循了与以前相同的程序。但是浏览器无法解释图像......再次。
下面,我添加了编码样本图像的代码部分(浏览器将其解释为图像),然后添加了相机功能(将它们解释为奇数字符而不是图像),以进行比较。两者都应该以相同的方式工作,但只有第一个工作。
编码示例图像:
answer = "<iframe srcdoc='<img src=\"data:image/jpeg;base64,/9j/4AAQS...0KDQo=\"> ' scrolling=\"no\" width=\"340\" height=\"340\" > <p> Error </p> </iframe>\r\n ";
相机函数sendFrame():
answer = "<iframe srcdoc=\"<img src='data:image/jpeg;base64,";
client.print(answer);
sendFrame();
answer ="' > \" > <p> Error </p> </iframe>\r\n ";
client.print(answer);
所以,我想我已经发现相机传入的 jpeg 数据出了什么问题相机功能将 jpeg 数据(到服务器,然后到客户端)以浏览器将其解释为文本或类似的格式,因为它包含奇怪的字符(检查我发布的最后一张图片)。
同样为了编写 html 代码,我使用引号 " 和 ' (或 " 和 \')来创建 iframe 代码以及 iframe 中的所有其他内容。
事情是这样的:因为一些相机的 jpeg 数据被浏览器解释为引号,它们与我放在 iframe 中的引号交互以包装 img 标签和来自相机的数据,这就是为什么它把一切都搞砸了在 iframe 中(我认为)
反正有没有将来自相机功能的图像数据转换为 base64,以便它们不与 iframe 和图像标签的包装引号交互?