在ESP32上运行的免费视频流服务

2020-08-15 02:52:58

发现自己在大流行期间被困在室内?为什么不建立一个开源的机顶盒,并连接到唯一的微控制器驱动的视频流服务?

ESPFLIX设计为在Arduino IDE框架内的ESP32上运行。与ESP_8_BIT类似,该原理图非常简单:

-|25|->;视频输出|18|--/\/\/->;音频输出||1k|-|ESP32|-10nf|v GND|3.3V<;--+-+IR接收器||GND。--|)TSOP4838等|0|-+-->;AppleTV遥控器。

您还需要一个AppleTV遥控器或类似的遥控器。在易趣上花几美元就可以买到很多兼容的遥控器。调整其他远程设备非常容易,有关详细信息,请参阅ir_input.h。

第一次启动时,选择WiFi接入点并输入密码。如果您稍后需要更改接入点,请在闪屏期间按住Menu键返回接入点选择屏幕。

进入顶层菜单后,向左和向右滚动以选择要观看的内容。在播放时,遥控器上的左侧和右侧将快进/快退。向上和向下将向前和向后跳跃30秒。菜单将保存当前内容的位置并返回到选择屏幕。

好的,这是一个比Netflix略小的收藏,但仍然是有趣/愉快/有趣的东西。向才华横溢的尼娜·佩利致敬,感谢她所做的一切出色的工作。

在为ESP_8_BIT创建的NTSC/PAL软件视频输出的基础上,ESPFLIX添加了视频和音频编解码器以及AWS流服务,以提供Netflix的开源拼贴。

1993年,推出了光盘数字视频。使用MPEG1视频编解码器,它在CD上压缩了74分钟。当年早些时候,旅行者公司使用Quicktime和Cinepak软件编解码器制作了有史以来第一部发行CD-ROM的电影:披头士的艰难日子之夜(the Beatle‘s Hard Days Night)。

虽然编解码器在其间的几十年中有所改进,但MPEG1编解码器使用了许多与现代编解码器相同的技术:变换编码、运动估计和预测残差的可变长度编码仍然是像H264这样的现代编解码器的基础。

352x240(NTSC)或352x288(PAL)的标准MPEG1分辨率似乎与我们的ESP32视频输出分辨率非常匹配。由于MPEG1可以对帧(预测帧或预测帧)之间的差异进行编码,因此您需要在此分辨率下使用2个帧缓冲区。MPEG1通常还对过去和将来的帧(双向预测帧或帧)之间的差异进行编码,因此这意味着3个缓冲器。

对这些帧缓冲区(每个都以YUV4:1:1颜色空间编码)的大小进行简单的数学运算就会得到352×288×31.5=456192,这比ESP32必须提供的内存大得多。所以我们需要做出一些让步。我们可以在没有B帧的情况下生活:它们提高了整体编码性能,但是没有它们也很容易创建出好看的视频。我们也可以降低垂直分辨率:1993年仍然是一个4:3的世界,352x192对于2020年代来说是一个很好的宽高比。

尽管352*192*2*1.5=202752似乎更易于管理,但是获得一个MPEG1软件编解码器Be Performant仍然有它的挑战。您不能仅仅在ESP32上一块地malloc这样大小的连续缓冲区。它们需要被分解成条带,并且执行半像素运动补偿的编解码器的所有内部都必须进行相应的调整。这些内存中的大部分需要从一个一次只能寻址32位的池中分配,从而使需要尽可能快地运行的代码进一步复杂化。如果MPEG1解码器的实现看起来很奇怪,那通常是因为它试图处理帧缓冲区的对齐访问和分块分配。

SBC是蓝牙特殊兴趣小组(SIG)为高级音频分发配置文件(A2DP)指定的低复杂度子带编解码器。与通常与MPEG1视频一起使用的MP2编解码器不同,SBC使用极小的128个采样缓冲区(与MP2的1152个不同)。这听起来可能不是很多,但由于可用内存如此之少,它带来了天壤之别。

我最初为Cortex M0编写了这个实现:它在内存有限且没有硬件分频器的小型设备上工作得很好。由于SBC音频编解码器与视频NTSC/PAL编码、IP堆栈和Delta-Sigma调制器一起运行在ESP32的内核1上,因此其复杂度很低。

我喜欢Delta-Sigma调制器。尽管对于正确的名称顺序性存在激烈的争论,但它们是一种可用于高性能ADC和DAC的多功能工具。在https://www.beis.de/Elektronik/DeltaSigma/DeltaSigma.html.上可以找到一个很好的介绍

ESP32在I2S0中内置了一个。遗憾的是,我们正在使用I2S0进行视频生成,因此我们将不得不在软件中生成我们的信号。要将一个48 kHz、16位的单声道PCM流转换成过采样的单比特流,我们必须选择一个具有良好噪声特性的调制器,该调制器的速度足以在已经很忙的微控制器上运行。

对于这个设计,我选择了一个运行在32倍过采样率下的二阶级联谐振器,反馈形式(CRFB)Δsigma调制器。32x通常比人们希望的要低(64x更典型),但是考虑到对缓冲和计算已经很严格的约束,这似乎是一个公平的权衡。噪声整形足够好,可以在频谱中将量化能量推得更高,从而使音频引脚上的RC滤波器能够有效地完成其工作。对于每个16位PCM样本,我们产生32位,我们将其插入I2S外围设备,就像它是48 kHz立体声PCM流一样。由此产生的1.5Mbit调制信号经过滤波后听起来相当不错。

原来大多数电视都有内置的滤波器,直接连接数字音频输出引脚而不带RC滤波器通常听起来很好,只是不要在显微镜上看它。

我使用乌尔姆大学托管的伟大工具来设计滤波器并计算系数,以获得所需的噪声整形特性:https://www.sigma-delta.de/。

视频显示类似于ESP_8_BIT,但有一些不同。因为我们有两个帧缓冲区,所以我们可以在绘制另一个的同时显示另一个,或者我们可以在垂直消隐期间在它们之间平滑地滚动。

值得注意的是,用于显示视频的DAC为8位/3.3V。我们只使用足够的位数来获得视频所需的~1V范围。分压器将允许我们在视频上有更大的动态范围,但需要更多的组装。在某种程度上,我将添加一个选项,以使用此方法获得稍微更好的视频质量。

这一切都有赖于出色的AWS基础设施。因为我们的内存非常紧张(视频运行后还剩约10K),所以我们没有太多的内存用于缓冲。Netflix使用了许多兆字节的缓冲,像VideoCD这样的MPEG1系统至少需要50K,我们有6K的空间可供支配。ESP32使用的LwIP堆栈并未真正针对流媒体进行优化。如果服务器距离足够远,TCP AIMD算法永远没有机会打开足够多的窗口来获得合理的吞吐量。为了克服这一限制,我将通过AWS CloudFront提供这项服务,只要我负担得起,我就会尝试并优化那些摆弄它的人的体验。

视频文件本身以大约1.5兆比特的速度用ffmpeg编码。速率控制模型/多路复用器不能真正与微小的缓冲区一起工作,因此您的里程数可能会有所不同。尽管一切都不合时宜,但在很大程度上,音频和视频在大致正确的时间出现。

该系统还产生用于平滑快进和快退的特技模式流,以及允许将时间从一个流映射到另一个流的索引。这个索引无法放入内存,但是通过使用http范围请求,我们可以查找索引的任何片段,而无需加载整个索引。

ESP32是一个很棒的小设备。令人惊讶的是,你可以用比遥控器更低的价格创建一个机顶盒,而像AWS这样的平台只需很少的时间/金钱就能实现这样的流媒体服务。