你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
在 Azure IoT 操作中,使用媒体连接器(预览版)可访问媒体源(如边缘附加相机)中的媒体。 本文介绍如何使用媒体连接器执行如下任务:
- 将映像快照发送到 MQTT 代理。
- 将视频流保存到本地文件系统。
媒体连接器:
使用资产终结点来访问媒体源。 资产终结点定义与媒体源(例如相机)的连接。 资产终结点配置包括媒体源的 URL、媒体源的类型以及访问媒体源所需的任何凭据。
使用资产来表示媒体源(例如相机)。 资产定义媒体源(例如相机)的功能和属性。
先决条件
Azure IoT 操作的已部署实例。 如果还没有实例,请参阅快速入门:使用 K3s 在 GitHub Codespaces 中运行 Azure IoT 操作。
连接到网络并可从 Azure IoT 操作群集访问的相机。 相机必须支持视频流的实时流协议。 还需要相机的用户名和密码来进行身份验证。
部署媒体连接器
若要部署连接器的预览版本,可以在部署 Azure IoT作实例时启用它们,也可以在部署实例后启用它们。
若要在部署 Azure IoT 操作实例时启用预览连接器,请执行以下步骤。
- Azure 门户
- Azure CLI
在“安装 Azure IoT 操作 基本信息”页的“连接器”部分中选择“ONVIF 连接器和媒体连接器(预览版)”:>
若要在部署 Azure IoT Operations 实例后启用预览连接器,请执行以下操作:
- Azure 门户
- Azure CLI
在 Azure 门户中转到 Azure IoT 操作实例。
启用预览连接器:
重要
如果未启用预览功能,则在尝试使用媒体或 ONVIF 连接器时,aio-supervisor-...
Pod 日志中会显示以下错误消息:No connector configuration present for AssetEndpointProfile: <AssetEndpointProfileName>
。
部署媒体服务器
如果使用媒体连接器流式传输实时视频,则需要安装自己的媒体服务器。 若要部署用于媒体连接器的示例媒体服务器,请运行以下命令:
kubectl create namespace media-server
kubectl apply -f https://raw.githubusercontent.com/Azure-Samples/explore-iot-operations/refs/heads/main/samples/media-server/media-server-deployment.yaml
kubectl apply -f https://raw.githubusercontent.com/Azure-Samples/explore-iot-operations/refs/heads/main/samples/media-server/media-server-service.yaml
kubectl apply -f https://raw.githubusercontent.com/Azure-Samples/explore-iot-operations/refs/heads/main/samples/media-server/media-server-service-public.yaml
重要
此媒体服务器仅适用于测试和开发目的。 在生产环境中,需要提供自己的媒体服务器。
若要发现此媒体服务器的群集 IP 地址,请运行以下命令:
kubectl get service media-server-public --namespace media-server
记下 CLUSTER-IP 值,稍后使用它来访问媒体服务器。
资产终结点配置
若要配置媒体连接器,请先创建一个资产终结点,用于定义与媒体源的连接。 资产终结点包括媒体源的 URL、媒体源的类型以及访问媒体源所需的任何凭据。
如果相机需要身份验证,请在 Kubernetes 群集中创建一个用于存储相机用户名和密码的机密。 媒体连接器使用此机密通过相机进行身份验证:
创建包含以下内容的名为 contoso-secrets.yaml 的 YAML 文件。 将占位符替换为以 base64 编码的相机用户名和密码:
apiVersion: v1 kind: Secret metadata: name: contoso-secrets type: Opaque data: username: "<YOUR CAMERA USERNAME BASE64 ENCODED>" password: "<YOUR CAMERA PASSWORD BASE64 ENCODED>"
提示
若要在 Bash 提示符下对 base64 中的用户名和密码进行编码,请使用以下命令:
echo -n "<STRING TO ENCODE>" | base64
若要将机密添加到默认 Azure IoT作命名空间中的群集,请运行以下命令:
kubectl apply -f contoso-secrets.yaml -n azure-iot-operations
使用 Bicep 文件创建资产终结点:
设置以下环境变量:
SUBSCRIPTION_ID="<YOUR SUBSCRIPTION ID>" RESOURCE_GROUP="<YOUR AZURE IOT OPERATIONS RESOURCE GROUP>" TARGET_ADDRESS="<YOUR CAMERA RTSP ADDRESS>" AEP_NAME="contoso-rtsp-aep" SECRET_NAME="contoso-secrets"
运行以下脚本:
# Download the Bicep file wget https://raw.githubusercontent.com/Azure-Samples/explore-iot-operations/main/samples/media-connector-bicep/aep-media-connector.bicep -O aep-media-connector.bicep # Find the name of your custom ___location CUSTOM_LOCATION_NAME=$(az iot ops list -g $RESOURCE_GROUP --query "[0].extendedLocation.name" -o tsv) # Use the Bicep file to deploy the asset endpoint az deployment group create --subscription $SUBSCRIPTION_ID --resource-group $RESOURCE_GROUP --template-file aep-media-connector.bicep --parameters targetAddress=$TARGET_ADDRESS customLocationName=$CUSTOM_LOCATION_NAME aepName=$AEP_NAME secretName=$SECRET_NAME
以下代码片段显示用于创建资产终结点的 Bicep 文件:
metadata description = 'Asset endpoint profile for media connector'
@description('The RTSP endpoint for the media stream.')
param targetAddress string
@description('The name of the custom ___location you are using.')
param customLocationName string
@description('Specifies the name of the asset endpoint resource to create.')
param aepName string
@description('The name of the Kubernetes secret you are using to store the camera credentials.')
param secretName string
/*****************************************************************************/
/* Asset endpoint profile */
/*****************************************************************************/
resource assetEndpoint 'Microsoft.DeviceRegistry/assetEndpointProfiles@2024-11-01' = {
name: aepName
___location: resourceGroup().___location
extendedLocation: {
type: 'CustomLocation'
name: customLocationName
}
properties: {
targetAddress: targetAddress
endpointProfileType: 'Microsoft.Media'
#disable-next-line no-hardcoded-env-urls //Schema required during public preview
additionalConfiguration: '{"@schema":"https://aiobrokers.blob.core.windows.net/aio-media-connector/1.0.0.json"}'
authentication: {
method: 'UsernamePassword'
usernamePasswordCredentials: {
passwordSecretName: '${secretName}/password'
usernameSecretName: '${secretName}/username'
}
}
}
}
前面的示例将资产终结点配置为使用用户名和密码通过相机进行身份验证。 在 Bicep 文件中,所创建资产终结点的身份验证部分如以下示例所示:
authentication: {
method: 'UsernamePassword'
usernamePasswordCredentials: {
passwordSecretName: '${secretName}/password'
usernameSecretName: '${secretName}/username'
}
如果相机不需要用户名和密码,请配置匿名身份验证,如以下示例所示:
authentication: {
method: 'Anonymous'
}
资产配置
配置资产时,datasets.DataPoints
参数指定媒体连接器对资产执行的操作。 相机资产支持以下任务类型:
任务类型 | 说明 |
---|---|
snapshot-to-mqtt |
从相机捕获快照并将其发布到 MQTT 主题。 |
snapshot-to-fs |
从相机捕获快照并将其保存到本地文件系统。 |
clip-to-fs |
从相机捕获视频剪辑并将其保存到本地文件系统。 |
stream-to-rtsp |
将实时视频流从相机发送到媒体服务器。 |
可以使用以下设置来配置单个任务:
autostart
:任务是否在资产启动时自动启动。realtime
:任务是否实时运行。loop
:任务是否连续运行。format
:媒体文件的格式。fps
:媒体文件的每秒帧数。audioEnabled
:是否为媒体文件启用音频。duration
:媒体文件的持续时间。
以下示例演示如何为每个任务类型部署资产。
提示
直到部署使用媒体连接器的资产时,才会在 Kubernetes 中创建媒体 Pod。 如果尝试在部署资产之前运行 kubectl get pods
命令,则不会看到任何媒体 Pod。
快照到 MQTT
若要配置一个从相机捕获快照并将其发布到 MQTT 主题的技术组件,请执行以下步骤:
设置以下环境变量:
SUBSCRIPTION_ID="<YOUR SUBSCRIPTION ID>" RESOURCE_GROUP="<YOUR AZURE IOT OPERATIONS RESOURCE GROUP>" AEP_NAME="contoso-rtsp-aep"
运行以下脚本:
# Download the Bicep file wget https://raw.githubusercontent.com/Azure-Samples/explore-iot-operations/main/samples/media-connector-bicep/asset-snapshot-to-mqtt.bicep -O asset-snapshot-to-mqtt.bicep # Find the name of your custom ___location CUSTOM_LOCATION_NAME=$(az iot ops list -g $RESOURCE_GROUP --query "[0].extendedLocation.name" -o tsv) # Use the Bicep file to deploy the asset az deployment group create --subscription $SUBSCRIPTION_ID --resource-group $RESOURCE_GROUP --template-file asset-snapshot-to-mqtt.bicep --parameters customLocationName=$CUSTOM_LOCATION_NAME aepName=$AEP_NAME
以下代码片段显示用于创建资产的 bicep 文件:
metadata description = 'Media asset that publishes snapshots to MQTT.'
@description('The name of the custom ___location you are using.')
param customLocationName string
@description('Specifies the name of the asset endpoint resource to use.')
param aepName string
@description('The name of the asset you are creating.')
param assetName string = 'asset-snapshot-to-mqtt'
/*****************************************************************************/
/* Asset */
/*****************************************************************************/
resource asset 'Microsoft.DeviceRegistry/assets@2024-11-01' = {
name: assetName
___location: resourceGroup().___location
extendedLocation: {
type: 'CustomLocation'
name: customLocationName
}
properties: {
assetEndpointProfileRef: aepName
datasets: [
{
name: 'dataset1'
dataPoints: [
{
name: 'snapshot-to-mqtt'
dataSource: 'snapshot-to-mqtt'
dataPointConfiguration: '{"taskType":"snapshot-to-mqtt","autostart":true,"realtime":true,"loop":true,"format":"jpeg","fps":1}'
}
]
}
]
}
}
若要验证快照是否发布到 MQTT 代理,请使用 mosquitto_sub 工具。 在此示例中,你将在 Kubernetes 群集的一个 Pod 中运行 mosquitto_sub 工具:
运行以下命令来部署包含 mosquitto_pub 和 mosquitto_sub 工具的 Pod,这些工具可用于与群集中的 MQTT 代理交互:
kubectl apply -f https://raw.githubusercontent.com/Azure-Samples/explore-iot-operations/main/samples/quickstarts/mqtt-client.yaml
注意
此配置是不安全的。 请勿在生产环境中使用此配置。
运行 mqtt-client pod 时,请运行以下命令以在所创建的 Pod 中创建 shell 环境:
kubectl exec --stdin --tty mqtt-client -n azure-iot-operations -- sh
在 mqtt-client pod 中的 Bash shell 中,运行以下命令,使用订阅 主题的 mosquitto_sub
azure-iot-operations/data
工具连接到 MQTT 代理:mosquitto_sub --host aio-broker --port 18883 --topic "azure-iot-operations/data/#" -V 5 -F '%p' -C 1 --cafile /var/run/certs/ca.crt -D CONNECT authentication-method 'K8S-SAT' -D CONNECT authentication-data $(cat /var/run/secrets/tokens/broker-sat) > image.jpeg
此命令可从单个消息中捕获原始有效负载,并将其保存到 pod 文件系统内名为 image.jpeg 的文件中。 若要退出 pod 的 shell 环境,请键入
exit
。若要将图像文件从 pod 复制到本地计算机,请运行以下命令:
kubectl cp azure-iot-operations/mqtt-client:image.jpeg image.jpeg
完成资产测试后,可以通过运行以下命令将其删除:
az iot ops asset delete -n asset-snapshot-to-mqtt -g $RESOURCE_GROUP
快照到文件系统
若要配置一个资产,用于从相机捕获快照并将其保存为文件:
设置以下环境变量:
SUBSCRIPTION_ID="<YOUR SUBSCRIPTION ID>" RESOURCE_GROUP="<YOUR AZURE IOT OPERATIONS RESOURCE GROUP>" AEP_NAME="contoso-rtsp-aep"
运行以下脚本:
# Download the Bicep file wget https://raw.githubusercontent.com/Azure-Samples/explore-iot-operations/main/samples/media-connector-bicep/asset-snapshot-to-fs.bicep -O asset-snapshot-to-fs.bicep # Find the name of your custom ___location CUSTOM_LOCATION_NAME=$(az iot ops list -g $RESOURCE_GROUP --query "[0].extendedLocation.name" -o tsv) # Use the Bicep file to deploy the asset az deployment group create --subscription $SUBSCRIPTION_ID --resource-group $RESOURCE_GROUP --template-file asset-snapshot-to-fs.bicep --parameters customLocationName=$CUSTOM_LOCATION_NAME aepName=$AEP_NAME
以下代码片段显示用于创建资产的 bicep 文件:
metadata description = 'Media asset that saves snapshots to the file system.'
@description('The name of the custom ___location you are using.')
param customLocationName string
@description('Specifies the name of the asset endpoint resource to use.')
param aepName string
@description('The name of the asset you are creating.')
param assetName string = 'asset-snapshot-to-fs'
/*****************************************************************************/
/* Asset */
/*****************************************************************************/
resource asset 'Microsoft.DeviceRegistry/assets@2024-11-01' = {
name: assetName
___location: resourceGroup().___location
extendedLocation: {
type: 'CustomLocation'
name: customLocationName
}
properties: {
assetEndpointProfileRef: aepName
datasets: [
{
name: 'dataset1'
dataPoints: [
{
name: 'snapshot-to-fs'
dataSource: 'snapshot-to-fs'
dataPointConfiguration: '{"taskType":"snapshot-to-fs","autostart":true,"realtime":true,"loop":true,"format":"jpeg","fps":1}'
}
]
}
]
}
}
这些文件保存在 opc-media-1-...
Pod 的文件系统中。 若要查找 Pod 的全名,请运行以下命令。 以下命令使用默认的 Azure IoT 操作命名空间:
kubectl get pods -n azure-iot-operations
若要查看文件,请在 ls
Pod 中运行命令。 在以下命令中使用 Pod 的全名:
kubectl exec aio-opc-media-1-... -n azure-iot-operations -- ls /tmp/azure-iot-operations/data/asset-snapshot-to-fs/snapshots/
完成资产测试后,可以通过运行以下命令将其删除:
az iot ops asset delete -n asset-snapshot-to-fs -g $RESOURCE_GROUP
剪辑到文件系统
若要配置从相机捕获剪辑并将其保存为文件的资产:
设置以下环境变量:
SUBSCRIPTION_ID="<YOUR SUBSCRIPTION ID>" RESOURCE_GROUP="<YOUR AZURE IOT OPERATIONS RESOURCE GROUP>" AEP_NAME="contoso-rtsp-aep"
运行以下脚本:
# Download the Bicep file wget https://raw.githubusercontent.com/Azure-Samples/explore-iot-operations/main/samples/media-connector-bicep/asset-clip-to-fs.bicep -O asset-clip-to-fs.bicep # Find the name of your custom ___location CUSTOM_LOCATION_NAME=$(az iot ops list -g $RESOURCE_GROUP --query "[0].extendedLocation.name" -o tsv) # Use the Bicep file to deploy the asset az deployment group create --subscription $SUBSCRIPTION_ID --resource-group $RESOURCE_GROUP --template-file asset-clip-to-fs.bicep --parameters customLocationName=$CUSTOM_LOCATION_NAME aepName=$AEP_NAME
以下代码片段显示用于创建资产的 bicep 文件:
metadata description = 'Media asset that saves clips to the file system.'
@description('The name of the custom ___location you are using.')
param customLocationName string
@description('Specifies the name of the asset endpoint resource to use.')
param aepName string
@description('The name of the asset you are creating.')
param assetName string = 'asset-clip-to-fs'
/*****************************************************************************/
/* Asset */
/*****************************************************************************/
resource asset 'Microsoft.DeviceRegistry/assets@2024-11-01' = {
name: assetName
___location: resourceGroup().___location
extendedLocation: {
type: 'CustomLocation'
name: customLocationName
}
properties: {
assetEndpointProfileRef: aepName
datasets: [
{
name: 'dataset1'
dataPoints: [
{
name: 'clip-to-fs'
dataSource: 'clip-to-fs'
dataPointConfiguration: '{"taskType":"clip-to-fs","autostart":true,"realtime":true,"loop":true,"format":"avi","duration":3}'
}
]
}
]
}
}
这些文件保存在 opc-media-1-...
Pod 的文件系统中。 若要查找 Pod 的全名,请运行以下命令。 以下命令使用默认的 Azure IoT 操作命名空间:
kubectl get pods -n azure-iot-operations
若要查看文件,请在 ls
Pod 中运行命令。 在以下命令中使用 Pod 的全名:
kubectl exec aio-opc-media-1-... -n azure-iot-operations -- ls /tmp/azure-iot-operations/data/asset-clip-to-fs/clips/
完成资产测试后,可以通过运行以下命令将其删除:
az iot ops asset delete -n asset-clip-to-fs -g $RESOURCE_GROUP
流式传输到 RTSP
若要配置将视频流从相机转发到媒体服务器的资产,请执行以下作:
在上一步中部署媒体服务器的 IP 地址时,你记下了该地址。
设置以下环境变量:
SUBSCRIPTION_ID="<YOUR SUBSCRIPTION ID>" RESOURCE_GROUP="<YOUR AZURE IOT OPERATIONS RESOURCE GROUP>" MEDIA_SERVER_ADDRESS="<YOUR MEDIA SERVER IP ADDRESS>" AEP_NAME="contoso-rtsp-aep"
运行以下脚本:
# Download the Bicep file wget https://raw.githubusercontent.com/Azure-Samples/explore-iot-operations/main/samples/media-connector-bicep/asset-stream-to-rtsp.bicep -O asset-stream-to-rtsp.bicep # Find the name of your custom ___location CUSTOM_LOCATION_NAME=$(az iot ops list -g $RESOURCE_GROUP --query "[0].extendedLocation.name" -o tsv) # Use the Bicep file to deploy the asset az deployment group create --subscription $SUBSCRIPTION_ID --resource-group $RESOURCE_GROUP --template-file asset-stream-to-rtsp.bicep --parameters customLocationName=$CUSTOM_LOCATION_NAME aepName=$AEP_NAME mediaServerAddress=$MEDIA_SERVER_ADDRESS
以下代码片段显示用于创建资产的 bicep 文件:
metadata description = 'Media asset that streams RTSP to a media server.'
@description('The name of the custom ___location you are using.')
param customLocationName string
@description('Specifies the name of the asset endpoint resource to use.')
param aepName string
@description('The name of the asset you are creating.')
param assetName string = 'asset-stream-to-rtsp'
@description('The IP address of your media server.')
param mediaServerAddress string
/*****************************************************************************/
/* Asset */
/*****************************************************************************/
resource asset 'Microsoft.DeviceRegistry/assets@2024-11-01' = {
name: assetName
___location: resourceGroup().___location
extendedLocation: {
type: 'CustomLocation'
name: customLocationName
}
properties: {
assetEndpointProfileRef: aepName
datasets: [
{
name: 'dataset1'
dataPoints: [
{
name: 'stream-to-rtsp'
dataSource: 'stream-to-rtsp'
dataPointConfiguration: '{"taskType":"stream-to-rtsp","autostart":true,"realtime":true,"loop":true,"media_server_address":"${mediaServerAddress}"}'
}
]
}
]
}
}
若要查看媒体流,请使用如下所示的 URL:http://<YOUR KUBERNETES CLUSTER IP ADDRESS>:8888/azure-iot-operations/data/asset-stream-to-rtsp
。
提示
如果在 Codespaces 中运行 Azure IoT 操作,请运行以下命令,将媒体服务器转发到本地计算机:kubectl port-forward service/media-server-public 8888:8888 -n media-server
。
提示
如果您在虚拟机中运行 Azure IoT 操作,请确保防火墙中端口 8888 已打开,以允许入站访问。
媒体服务器记录来自资产的连接和流的创建:
2025/02/20 15:31:10 INF [RTSP] [conn <INTERNAL IP ADDRESS OF ASSET>:41384] opened
2025/02/20 15:31:10 INF [RTSP] [session 180ce9ad] created by <INTERNAL IP ADDRESS OF ASSET>:41384
2025/02/20 15:31:10 INF [RTSP] [session 180ce9ad] is publishing to path 'azure-iot-operations/data/asset-stream-to-rtsp', 2 tracks (H264, LPCM)
2025/02/20 15:31:18 INF [HLS] [muxer azure-iot-operations/data/asset-stream-to-rtsp] created (requested by <IP ADDRESS OF EXTERNAL CLIENT>:16831)
2025/02/20 15:31:18 WAR [HLS] [muxer azure-iot-operations/data/asset-stream-to-rtsp] skipping track 2 (LPCM)
2025/02/20 15:31:18 INF [HLS] [muxer azure-iot-operations/data/asset-stream-to-rtsp] is converting into HLS, 1 track (H264)
完成资产测试后,可以通过运行以下命令将其删除:
az iot ops asset delete -n asset-stream-to-rtsp -g $RESOURCE_GROUP