streamlit-webrtc
姊妹项目:streamlit-fesion
,用于在浏览器中使用Wasm执行视频滤镜。
示例
⚡️包含以下示例及更多内容的展示:🎈在线演示
- 物体检测
- OpenCV滤镜
- 单向视频流
- 音频处理
⚡️实时语音转文字:🎈在线演示
它可以实时将你的语音转换为文字。 这个应用是自包含的;它不依赖任何外部API。
⚡️实时视频风格迁移:🎈在线演示
它可以将各种风格迁移滤镜应用于实时视频流。
⚡️视频聊天
(在线演示不可用)
你可以用约100行Python代码创建视频聊天应用。
⚡️东京2020奥运会图标:🎈在线演示
使用MediaPipe进行姿势估计。
安装
$ pip install -U streamlit-webrtc
快速教程
另请参阅示例页面,pages/*.py
,其中包含各种用法。
另请参阅"使用Streamlit快速开发基于Web的实时视频/音频处理应用"。
创建app.py
,内容如下。
from streamlit_webrtc import webrtc_streamer
webrtc_streamer(key="sample")
与其他Streamlit组件不同,webrtc_streamer()
需要key
参数作为唯一标识符。为其设置一个任意字符串。
然后用Streamlit运行它并打开http://localhost:8501/。
$ streamlit run app.py
你会看到应用视图,点击"START"按钮。
然后,视频和音频流开始。如果被要求允许访问摄像头和麦克风,请允许。
接下来,编辑app.py
如下并再次运行。
from streamlit_webrtc import webrtc_streamer
import av
def video_frame_callback(frame):
img = frame.to_ndarray(format="bgr24")
flipped = img[::-1,:,:]
return av.VideoFrame.from_ndarray(flipped, format="bgr24")
webrtc_streamer(key="example", video_frame_callback=video_frame_callback)
现在视频垂直翻转了。
如上面的示例所示,你可以通过定义一个接收和返回帧的回调函数,并将其传递给video_frame_callback
参数(或用于音频操作的audio_frame_callback
)来编辑视频帧。
输入和输出帧是PyAV
库的av.VideoFrame
(或处理音频时的av.AudioFrame
)实例。
你可以在回调函数中注入任何类型的图像(或音频)处理。 查看上面的示例以了解更多应用。
向回调传递参数
你也可以向回调传递参数。
在下面的示例中,使用了一个布尔型flip
标志来开启/关闭图像翻转。
import streamlit as st
from streamlit_webrtc import webrtc_streamer
import av
flip = st.checkbox("翻转")
def video_frame_callback(frame):
img = frame.to_ndarray(format="bgr24")
flipped = img[::-1,:,:] if flip else img
return av.VideoFrame.from_ndarray(flipped, format="bgr24")
webrtc_streamer(key="example", video_frame_callback=video_frame_callback)
从回调中获取值
有时我们想要从外部作用域读取回调中生成的值。
请注意,回调是在独立于主脚本运行的分叉线程中执行的,所以我们必须注意以下几点,并需要一些技巧来实现,如下面的示例(另请参阅下面关于由于多线程导致的回调中的一些限制的部分)。
- 线程安全
- 在回调内部和外部之间传递值必须是线程安全的。
- 使用循环来轮询值
- 在媒体流传输期间,当回调继续被调用时,主脚本执行会像往常一样在底部停止。所以我们需要使用一个循环来保持主脚本运行,并在外部作用域中从回调获取值。
以下示例是将图像帧从回调传递到外部作用域,并在循环中持续处理它。在此示例中,对图像帧进行了简单的图像分析(计算直方图,如这个OpenCV教程)。
threading.Lock
是一种标准方法,用于控制跨线程的变量访问。
这里的dict对象img_container
是一个由回调和外部作用域共享的可变容器,lock
对象用于在为容器分配和读取值时确保线程安全。
import threading
import cv2
import streamlit as st
from matplotlib import pyplot as plt
from streamlit_webrtc import webrtc_streamer
lock = threading.Lock()
img_container = {"img": None}
def video_frame_callback(frame):
img = frame.to_ndarray(format="bgr24")
with lock:
img_container["img"] = img
return frame
ctx = webrtc_streamer(key="example", video_frame_callback=video_frame_callback)
fig_place = st.empty()
fig, ax = plt.subplots(1, 1)
while ctx.state.playing:
with lock:
img = img_container["img"]
if img is None:
continue
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ax.cla()
ax.hist(gray.ravel(), 256, [0, 256])
fig_place.pyplot(fig)
回调限制
回调在不同于主线程的分叉线程中执行,因此存在一些限制:
- Streamlit方法(
st.*
如st.write()
)在回调内部不起作用。 - 无法从外部直接引用回调内部的变量。
global
关键字在回调中不会按预期工作。- 在从外部和回调内部访问相同对象时,您必须注意线程安全性,如上一节所述。
基于类的回调
直到v0.37版本,基于类的回调是标准做法。 关于它的信息,请参阅README的旧版本。
从远程主机提供服务
将应用程序部署到远程服务器时,需要注意一些事项。 简而言之,
- 需要HTTPS才能访问本地媒体设备。
- 需要STUN/TURN服务器来建立媒体流连接。
请参阅以下部分。
HTTPS
streamlit-webrtc
使用getUserMedia()
API来访问本地媒体设备,而这个方法在不安全的上下文中不起作用。
这篇文档说
安全上下文简而言之是使用HTTPS或file:///URL方案加载的页面,或从localhost加载的页面。
因此,当在远程服务器上托管您的应用程序时,如果您的应用程序使用网络摄像头或麦克风,则必须通过HTTPS提供服务。 如果不这样做,在开始使用设备时会遇到错误。例如,在Chrome上会出现类似以下的错误。
错误:navigator.mediaDevices未定义。似乎当前文档未安全加载。
Streamlit Community Cloud是推荐的HTTPS服务方式。您可以轻松地使用它部署Streamlit应用程序,最重要的是,它默认自动通过HTTPS提供应用程序服务。
出于开发目的,有时suyashkumar/ssl-proxy
是一个方便的工具,可以通过HTTPS提供您的应用程序服务。
$ streamlit run your_app.py # 假设您的应用程序在http://localhost:8501上运行
# 然后,从上面的GitHub页面下载二进制文件到./ssl-proxy后,
$ ./ssl-proxy -from 0.0.0.0:8000 -to 127.0.0.1:8501 # 通过HTTPS将HTTP页面从端口8501代理到端口8000
# 然后访问https://localhost:8000
配置STUN服务器
要将应用程序部署到云端,我们必须通过webrtc_streamer()
上的rtc_configuration
参数配置STUN服务器,如下所示。
webrtc_streamer(
# ...
rtc_configuration={ # 添加此配置
"iceServers": [{"urls": ["stun:stun.l.google.com:19302"]}]
}
# ...
)
当服务器在远程主机上时,此配置对于建立媒体流连接是必要的。
:warning: 在某些环境中,包括Streamlit Community Cloud,您可能还需要设置TURN服务器。另请参阅下一节。
streamlit_webrtc
使用WebRTC进行视频和音频流传输。它必须访问全球网络中的"STUN服务器",以便远程对等点(准确地说,NAT后的对等点)建立WebRTC连接。
由于我们在这里不详细介绍STUN服务器,如果感兴趣,请用STUN、TURN或NAT遍历等关键词进行搜索,或阅读这些文章(1, 2, 3)。
上面的示例配置使用stun.l.google.com:19302
,这是Google提供的免费STUN服务器。
您也可以使用任何其他STUN服务器。 例如,一位用户报告在中国网络中使用Google的STUN服务器时出现了巨大延迟,通过更改STUN服务器解决了这个问题。
对于了解浏览器WebRTC API的人来说:rtc_configuration参数的值将传递给前端的RTCPeerConnection
构造函数。
必要时配置TURN服务器
即使正确配置了STUN服务器,在某些网络环境中,无论是从服务器还是从客户端,媒体流传输可能都无法工作。 例如,如果服务器托管在代理后面,或者如果客户端在防火墙后面的办公网络中,WebRTC数据包可能会被阻止(Streamlit Community Cloud就是这种情况)。这篇文章总结了可能出现的情况。 在这种环境下,需要使用 TURN 服务器。
设置 TURN 服务器有以下几种选择:
- Twilio 网络穿透服务(推荐)是一个稳定且易用的解决方案。这是一项付费服务,但你可以从免费试用开始,有一定数量的额度。
你只需将网络穿透服务令牌 API 响应中的
ice_servers
字段传递给webrtc_streamer()
的rtc_configuration
参数中的iceServers
字段即可。
社区云上托管的 WebRTC 示例应用使用了这个选项。查看它如何从 Twilio API 获取 ICE 服务器信息以及如何在应用中使用它。## 此示例代码来自 https://www.twilio.com/docs/stun-turn/api # 从 https://www.twilio.com/docs/python/install 下载辅助库 import os from twilio.rest import Client # 在 twilio.com/console 找到你的 Account SID 和 Auth Token # 并设置环境变量。参见 http://twil.io/secure account_sid = os.environ['TWILIO_ACCOUNT_SID'] auth_token = os.environ['TWILIO_AUTH_TOKEN'] client = Client(account_sid, auth_token) token = client.tokens.create() # 然后,将 ICE 服务器信息传递给 webrtc_streamer()。 webrtc_streamer( # ... rtc_configuration={ "iceServers": token.ice_servers } # ... )
- Open Relay 项目提供了一个免费的 TURN 服务器。但是,它似乎不够稳定,经常宕机。
- 自托管 TURN 服务器也是一个选择。参见 https://github.com/whitphx/streamlit-webrtc/issues/335#issuecomment-897326755。
日志记录
对于日志记录,该库使用标准的 logging
模块,并遵循官方日志教程中描述的实践。因此,日志记录器名称与模块名称相同 - streamlit_webrtc
或 streamlit_webrtc.*
。
你可以通过 logging.getLogger("streamlit_webrtc")
获取日志记录器实例,通过它可以控制来自该库的日志。
例如,如果你想将此库的日志记录器级别设置为 WARNING,可以使用以下代码:
st_webrtc_logger = logging.getLogger("streamlit_webrtc")
st_webrtc_logger.setLevel(logging.WARNING)
实际上,该库内部使用的第三方包 aiortc
也会发出许多 INFO 级别的日志,你可能也想控制它的日志。
你可以用同样的方式做到这一点,如下所示:
aioice_logger = logging.getLogger("aioice")
aioice_logger.setLevel(logging.WARNING)
API 变更
目前还没有关于接口的文档。请参考 ./pages/*.py 中的示例了解使用方法。 API 尚未最终确定,在未来的版本中可能会在没有向后兼容性的情况下进行更改,直到 v1.0 版本。
对于使用 <0.20
版本的用户
VideoTransformerBase
及其 transform
方法在 v0.20.0 中已被标记为已弃用。请改用 VideoProcessorBase#recv()
。
请注意,recv
方法的签名与 transform
不同,recv
必须返回 av.VideoFrame
或 av.AudioFrame
的实例。
另外,webrtc_streamer()
的 video_transformer_factory
和 async_transform
参数也已弃用,请分别使用 video_processor_factory
和 async_processing
。
有关它们的用法,请参见 app.py 中的示例。
资源
- 使用 Streamlit 快速开发基于 Web 的实时视频/音频处理应用
- 一个使用
streamlit-webrtc
进行实时视频应用开发的教程。 - 在 dev.to 上的交叉发布:https://dev.to/whitphx/developing-web-based-real-time-videoaudio-processing-apps-quickly-with-streamlit-4k89
- 一个使用
- 新组件:streamlit-webrtc,处理实时媒体流的新方法(Streamlit 社区)
- 这是一个论坛主题,介绍和讨论了
streamlit-webrtc
。
- 这是一个论坛主题,介绍和讨论了