使用 Media CDN 和 Live Streaming API 在 Google Cloud 上进行直播

1. 简介

内容分发网络 (CDN) 通过以下方式提升用户性能:在更靠近最终用户的位置缓存经常访问的内容、终止更靠近客户端的连接、重复使用与源站的连接,以及采用现代网络协议和自定义。对于用户(和我们的客户)来说,这意味着延迟时间更短、可靠性更高并降低成本,从而改善销售和网络体验,并净增加用户体验。如今,很少有现代网站和视频在线播放平台不依靠 CDN 来运营。

学习内容

本实验将引导我们完成以下操作步骤,使用 Media CDN (CDN) + Cloud Media Live Streaming API(实时视频转码)+ Cloud Storage(视频存储)+ 视频播放器(VLC、Google Shaka Player 等 - HLS + MPEG-DASH 播放器)部署直播工作流环境。

我们将设置 Live Streaming API 组件(输入、频道),并使用 FFmpeg 启动输入/频道的直播 Feed(FFmpeg 可生成直播测试信号)。Live Streaming API 会对直播 Feed 进行转码。转码后的视频清单和片段将存储在 Cloud Storage 存储分区中。然后,我们将设置以直播视频 Cloud Storage 存储分区作为来源的媒体 CDN。最后,VLC 播放器将用于播放通过媒体 CDN 缓存的直播内容。我们还将设置一个 Cloud Monitoring 信息中心,用来直观呈现媒体 CDN 的活动。

构建内容

在本实验中,我们将使用以下架构来设置环境:

de33cb3e75d52549.png

在本实验中,我们将设置以下组件并执行以下任务:

  • 创建 Google Cloud Storage (GCS) 存储分区,用于存储经过实时转码的视频
  • 配置 Live Streaming API 将视频转码为多种格式:HLS + MPEG DASH、SD 和 HD
  • 设置直播组件:输入/频道
  • 开设直播频道
  • 以 GCS 存储分区作为来源设置媒体 CDN
  • 设置 FFmpeg 来馈送直播频道
  • 使用视频播放器流式传输已转码的直播 Feed
  • 设置 Cloud Monitoring 信息中心以监控媒体 CDN 活动(延迟时间、缓存命中、缓存未命中等)

注意:在本实验中,我们假设用户有权访问 Google Cloud 控制台,且已设置项目。我们还假定用户开始使用全新环境,且未针对此演示进行任何设置。

所有配置操作都将通过 Cloud Shell 中的命令行完成。我们随时可以在控制台中通过命令行检查配置的组件。在整个实验中,我们会看到指向 Google Cloud 控制台的指针。

2. 准备工作

媒体 CDN 访问权限受到限制。如需使用媒体 CDN,请与您的客户支持团队联系。他们可以代表您创建访问权限请求。如果您是 Google 员工,并且想要测试使用媒体 CDN 进行实时流式传输的功能,请与媒体 CDN 的 PM 联系,申请对媒体 CDN 的访问权限。

3. 设置和要求

启动 Cloud Shell

虽然可以通过笔记本电脑对 Google Cloud 进行远程操作,但在此 Codelab 中,您将使用 Google Cloud Shell,这是一个在云端运行的命令行环境。

Google Cloud 控制台 中,点击右上角工具栏中的 Cloud Shell 图标:

55efc1aaa7a4d3ad.png

预配和连接到环境应该只需要片刻时间。完成后,您应该会看到如下内容:

7ffe5cbb04455448.png

这个虚拟机已加载了您需要的所有开发工具。它提供了一个持久的 5 GB 主目录,并且在 Google Cloud 中运行,大大增强了网络性能和身份验证功能。您在此 Codelab 中的所有工作都可以在浏览器中完成。您无需安装任何程序。

4. Google Cloud SDK 版本

在撰写本文时,408.0.0 是最新的 Google Cloud SDK 版本。本实验中的所有命令均使用最新版 Google Cloud SDK 进行了测试。在继续操作之前,请确保 Cloud Shell 使用的是最新版本的 SDK。

检查 SDK 版本

我们将使用 gcloud version 命令检查 SDK 版本。

命令

gcloud version | grep "Google Cloud SDK"

输出示例

Google Cloud SDK 408.0.0

后续步骤

  1. 如果 SDK 版本为 408.0.0 或更高版本,请跳至下一部分。
  2. 如果 SDK 版本低于 408.0.0,请运行下面列出的命令来更新 SDK。
sudo apt-get update && sudo apt-get install google-cloud-sdk

5. 前提条件

在开始配置 GCP 资源之前,我们需要执行以下操作:

  1. 设置环境变量
  2. 启用所需的服务 API

1. 设置环境变量

在本实验中,我们将运行带有几个变量的 gcloudcurl 命令。我们需要配置以下环境变量。

  • 项目 ID
  • 项目编号
  • 用户名
  • 区域
  • 输入 ID
  • 频道 ID

项目 ID 和用户名

这些环境变量通常在 Cloudshell 中预先配置。我们将使用 env 命令进行验证。

命令

env | grep -E 'DEVSHELL_PROJECT_ID=|LOGNAME'

输出示例

DEVSHELL_PROJECT_ID=<YOUR_PROJECT_ID>
LOGNAME=<YOUR_USERNAME>

创建 env_variables 文件

使用 cat 命令创建 env_variables.txt 文件。以下命令将在用户的主目录中创建文件 env_variables.txt

命令

cat > ~/env_variables.txt << EOF
export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
export LOCATION=us-west2
export INPUT_ID=lab-live-input
export CHANNEL_ID=lab-live-channel
EOF

设置环境变量

我们将使用 source 命令设置环境变量

命令

source ~/env_variables.txt

验证是否已设置变量

我们来验证一下是否设置了所有必需的环境变量。我们应该会在输出中看到总共 6 个环境变量。

命令

env | grep -E 'DEVSHELL_PROJECT_ID=|LOGNAME|PROJECT_NUMBER|LOCATION|INPUT_ID|CHANNEL_ID'

输出示例

LOCATION=us-west2
DEVSHELL_PROJECT_ID=<YOUR_PROJECT_ID>
LOGNAME=<YOUR_USERNAME>
PROJECT_NUMBER=<YOUR_PROJECT_NUMBER>
INPUT_ID=lab-live-input
CHANNEL_ID=lab-live-channel

2. 启用必需的服务 API

我们需要确保在项目中启用以下 API。

  • Network Services API
  • Certificate Manager API
  • Livestream API
  • Media CDN Edge Cache API

启用 Network Services API

如需启用 Network Services API,请运行以下命令:

命令

gcloud services enable networkservices.googleapis.com

启用 Certificate Manager API

如需启用 Certificate Manager API,请运行以下命令:

命令

gcloud services enable certificatemanager.googleapis.com

启用 Live Stream API

如需启用 Live Stream API,请运行以下命令:

命令

gcloud services enable livestream.googleapis.com

启用 Media CDN Edge Cache API

如需启用 Media CDN Edge Cache API,请运行以下命令:

命令

gcloud services enable edgecache.googleapis.com

验证 API 是否已启用

运行 gcloud services list 命令以列出所有已启用的 API。我们应该会在输出中看到 4 个 API。

命令

gcloud services list | grep -E 'networkservices|certificatemanager|livestream|edgecache'

输出示例

NAME: certificatemanager.googleapis.com
NAME: livestream.googleapis.com
NAME: networkservices.googleapis.com
NAME: edgecache.googleapis.com

6. 创建 Cloud Storage 存储分区

在本节中,我们将执行以下操作:

  1. 创建 Cloud Storage 存储桶
  2. 将存储分区设为可公开访问

在本实验的后面部分,我们将使用此存储分区来存储转码后的视频文件。此存储分区还将用作媒体 CDN 服务的源存储空间。

1. 创建存储桶

我们将使用 gsutil mb 命令创建存储分区:

命令

gsutil mb gs://live-streaming-storage-$LOGNAME

2. 将存储分区设为可公开访问

我们将使用 gsutil iam 命令公开这些文件:

命令

gsutil iam ch allUsers:objectViewer gs://live-streaming-storage-$LOGNAME

7. 设置 Live Streaming API 环境

Live Streaming API 链的组件架构如下所示:

96b5d26aedeb89a6

我们在上一部分中创建了 Cloud Storage 存储分区 live-streaming-storage-$LOGNAME。在接下来的两部分中,我们将创建以下资源:

  • 直播输入:输入端点是指编码器将输入流发送到的端点。您可以使用输入端点来指定视频流的配置,例如输入分辨率、输入类型和视频剪裁。
  • 直播频道:频道是一种资源,可通过输入端点提取输入流,将输入流转码为多种呈现方式,并在指定位置以特定格式发布输出直播视频流。您可以在同一频道中添加主输入流和备用输入流。

在本实验的后面部分,我们将创建以下资源:

  • 编码器:编码器是用于发送输入流的程序。在本实验中,我们将使用 FFmpeg。

8. 创建和配置输入端点

创建 input.json 文件

我们将创建一个 input.json 文件来指定直播信号类型。在本实验中,我们使用的是 RTMP 实时信号。

命令

cat > input.json << EOF
{
  "type": "RTMP_PUSH"
}
EOF

创建输入端点

截至本实验编写时,尚未针对 Live Stream API 提供 gcloud 支持。我们将使用 curl 命令进行 API 调用。

命令

curl -X POST \
-H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
-H "Content-Type: application/json; charset=utf-8" \
-d @input.json \
"https://livestream.googleapis.com/v1/projects/$PROJECT_NUMBER/locations/$LOCATION/inputs?inputId=$INPUT_ID"

输出示例

{
  "name": "projects/PROJECT_NUMBER/locations/us-west2/operations/operation-1661405972853-5e70a38d6f27f-79100d00-310671b4",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.video.livestream.v1.OperationMetadata",
    "createTime": "2022-08-25T05:39:32.884030164Z",
    "target": "projects/PROJECT_NUMBER/locations/us-west2/inputs/lab-live-input",
    "verb": "create",
    "requestedCancellation": false,
    "apiVersion": "v1"
  },
  "done": false
}

输出中包含很多有用的信息,但此时我们需要关注两个字段:

  • 操作 ID:复制输出中的操作 ID 并记下其 ID。以下是输出示例中的操作 ID。您可以在输出行中找到以 "name" 开头的名称。"operation-1661405972853-5e70a38d6f27f-79100d00-310671b4"
  • 状态:我们需要等待状态从“"done": false”变为“"done": true

查看状态

在继续下一步之前,我们需要检查输入端点是否已成功创建并准备就绪。

在下面的命令中,将 <OPERATION> 替换为上面刚刚获取的操作的 ID。在此示例中为 "operation-1661405972853-5e70a38d6f27f-79100d00-310671b4"

命令

export OPERATION_ID_1=<OPERATION>

命令

curl -X GET \
-H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
"https://livestream.googleapis.com/v1/projects/$PROJECT_NUMBER/locations/$LOCATION/operations/$OPERATION_ID_1"

输出示例

{
  "name": "projects/PROJECT_NUMBER/locations/us-west2/operations/operation-1661408816982-5e70ae25cea49-617844f0-8fdcb4a1",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.video.livestream.v1.OperationMetadata",
    "createTime": "2022-08-25T06:26:57.001530499Z",
    "endTime": "2022-08-25T06:26:57.043623522Z",
    "target": "projects/PROJECT_NUMBER/locations/us-west2/inputs/lab-live-input",
    "verb": "create",
    "requestedCancellation": false,
    "apiVersion": "v1"
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.cloud.video.livestream.v1.Input",
    "name": "projects/PROJECT_ID/locations/us-west2/inputs/lab-live-input",
    "createTime": "2022-08-25T06:26:56.997623672Z",
    "updateTime": "2022-08-25T06:26:56.997623672Z",
    "type": "RTMP_PUSH",
    "uri": "rtmp://34.94.97.220/live/4b7846a1-4a67-44ed-bfd0-d98281b6464a",
    "tier": "HD"
  }
}

重新运行该命令,直到您看到 "done:true" 表明输入端点已创建并准备就绪。

保存 URI

在本实验的后面部分,我们将使用上一个输出中的 URI。此时,我们为 URI 设置环境变量。

命令

export URI=<uri>

<uri> 替换为您在上文中记下的 URI。您还可以选择使用 GET 方法检索 URI

命令

curl -s -X GET -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) "https://livestream.googleapis.com/v1/projects/$PROJECT_NUMBER/locations/$LOCATION/inputs/$INPUT_ID" | jq .uri

9. 创建与配置直播频道

我们来创建直播频道,并将其与刚刚在上一节中创建的输入端点相关联。以下示例将创建一个频道,此 HLS 直播包含一次高清 (1280x720) 呈现内容。该通道将与输入端点以及我们之前创建的存储分区相关联。

创建 channel.json 文件

在 Cloud Shell 终端中,输入以下命令以创建 "channel.json" 文件:

命令

cat > channel.json << EOF
{
  "inputAttachments": [
    {
      "key": "my-input",
      "input": "projects/$PROJECT_NUMBER/locations/$LOCATION/inputs/$INPUT_ID"
    }
  ],
  "output": {
    "uri": "gs://live-streaming-storage-$LOGNAME"
  },
  "elementaryStreams": [
    {
      "key": "es_video",
      "videoStream": {
        "h264": {
          "profile": "high",
          "widthPixels": 1280,
          "heightPixels": 720,
          "bitrateBps": 3000000,
          "frameRate": 30
        }
      }
    },
    {
      "key": "es_audio",
      "audioStream": {
        "codec": "aac",
        "channelCount": 2,
        "bitrateBps": 160000
      }
    }
  ],
  "muxStreams": [
    {
      "key": "mux_video_ts",
      "container": "ts",
      "elementaryStreams": ["es_video", "es_audio"],
      "segmentSettings": { "segmentDuration": "2s" }
    }
  ],
  "manifests": [
    {
      "fileName": "main.m3u8",
      "type": "HLS",
      "muxStreams": [
        "mux_video_ts"
      ],
      "maxSegmentCount": 5
    }
  ]
}
EOF

创建频道

运行以下 curl 命令以创建渠道:

命令

curl -X POST \
-H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
-H "Content-Type: application/json; charset=utf-8" \
-d @channel.json \
"https://livestream.googleapis.com/v1/projects/$PROJECT_NUMBER/locations/$LOCATION/channels?channelId=$CHANNEL_ID"

输出示例

{
  "name": "projects/PROJECT_NUMBER/locations/us-west2/operations/operation-1661405972853-5e70a38d6f27f-79100d00-310671b4",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.video.livestream.v1.OperationMetadata",
    "createTime": "2022-08-25T05:39:32.884030164Z",
    "target": "projects/PROJECT_NUMBER/locations/us-west2/channels/lab-live-channel",
    "verb": "create",
    "requestedCancellation": false,
    "apiVersion": "v1"
  },
  "done": false
}

请记下并复制操作 ID。我们会在后续步骤中用到它。您可以在输出行中找到以 "name" 开头的名称。

查看状态

在继续下一步之前,我们需要检查该频道是否已成功创建并准备就绪。

在下面的命令中,将 <OPERATION> 替换为上面刚刚获取的操作的 ID。在此示例中为 operation-1661405972853-5e70a38d6f27f-79100d00-310671b4

命令

export OPERATION_ID_2=<OPERATION>

命令

curl -s -X GET \
-H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
"https://livestream.googleapis.com/v1/projects/$PROJECT_NUMBER/locations/$LOCATION/operations/$OPERATION_ID_2"

输出示例

  "name": "projects/PROJECT_NUMBER/locations/us-west2/operations/operation-1668666801461-5eda4c3f31852-a4d2229f-0efeef9e",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.video.livestream.v1.OperationMetadata",
    "createTime": "2022-11-17T06:33:21.500841488Z",
    "endTime": "2022-11-17T06:33:21.529311112Z",
    "target": "projects/PROJECT_NUMBER/locations/us-west2/channels/lab-live-channel",
    "verb": "create",
    "requestedCancellation": false,
    "apiVersion": "v1"
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.cloud.video.livestream.v1.Channel",
    "name": "projects/PROJECT_NAME/locations/us-west2/channels/lab-live-channel",
    "createTime": "2022-11-17T06:33:21.497818033Z",
    "updateTime": "2022-11-17T06:33:21.497818033Z",
    "activeInput": "my-input",
    "output": {
      "uri": "gs://live-streaming-storage-LOGNAME"
    },
    "elementaryStreams": [
      {
        "videoStream": {
          "h264": {
            "widthPixels": 1280,
            "heightPixels": 720,
            "frameRate": 30,
            "bitrateBps": 3000000,
            "gopDuration": "2s",
            "vbvSizeBits": 3000000,
            "vbvFullnessBits": 2700000,
            "entropyCoder": "cabac",
            "profile": "high"
          }
        },
        "key": "es_video"
      },
      {
        "audioStream": {
          "codec": "aac",
          "bitrateBps": 160000,
          "channelCount": 2,
          "sampleRateHertz": 48000
        },
        "key": "es_audio"
      }
    ],
    "muxStreams": [
      {
        "key": "mux_video_ts",
        "container": "ts",
        "elementaryStreams": [
          "es_video",
          "es_audio"
        ],
        "segmentSettings": {
          "segmentDuration": "2s"
        }
      }
    ],
    "manifests": [
      {
        "fileName": "main.m3u8",
        "type": "HLS",
        "muxStreams": [
          "mux_video_ts"
        ],
        "maxSegmentCount": 5,
        "segmentKeepDuration": "60s"
      }
    ],
    "streamingState": "STOPPED",
    "inputAttachments": [
      {
        "key": "my-input",
        "input": "projects/PROJECT_NUMBER/locations/us-west2/inputs/lab-live-input"
      }
    ],
    "logConfig": {
      "logSeverity": "OFF"
    }
  }
}

重新运行该命令,直到您看到 "done:true" 表明输入端点已创建并准备就绪。

请注意,"streamingState" 当前为 "STOPPED";我们将在下一部分创建该频道

10. 开设直播频道

现在我们已经创建了直播频道,下面我们开始创建该频道。在本部分,我们将执行以下操作:

  1. 开通直播频道
  2. 检查频道的状态,我们需要确保 streamingState"AWAITING INPUT"

1. 开创频道

在 Cloud Shell 中,运行以下 curl 命令来启动该通道:

命令

curl -X POST \
-H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
-H "Content-Type: application/json; charset=utf-8" \
-d "" \
"https://livestream.googleapis.com/v1/projects/$PROJECT_NUMBER/locations/$LOCATION/channels/$CHANNEL_ID:start"

输出示例

{
  "name": "projects/PROJECT_NUMBER/locations/LOCATION/operations/operation-1661405972853-5e70a38d6f27f-79100d00-310671b4",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.video.livestream.v1.OperationMetadata",
    "createTime": "2022-08-25T05:39:32.884030164Z",
    "target": "projects/PROJECT_NUMBER/locations/us-west2/channels/lab-live-channel",
    "verb": "start",
    "requestedCancellation": false,
    "apiVersion": "v1"
  },
  "done": false
}

2. 查看频道状态

运行以下 curl 命令以获取渠道的状态:

命令

curl -s -X GET -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) "https://livestream.googleapis.com/v1/projects/$PROJECT_NUMBER/locations/$LOCATION/channels/$CHANNEL_ID" | grep "streamingState"

输出示例

"streamingState": "AWAITING_INPUT",

重新运行该命令,直到您看到“AWAITING_INPUT”为止表示频道正在运行,并准备好接收信号。

11. 配置媒体 CDN

在本部分中,我们将部署媒体 CDN,也就是 CDN 基础架构。我们将创建以下资源:

  1. 边缘缓存来源
  2. 边缘缓存服务

1. 创建边缘缓存来源

边缘缓存来源表示内容位置,例如 Cloud Storage 存储分区、第三方存储位置或负载平衡器。用 CDN 的术语来说,源服务器(或源服务器)是我们要分发内容的源所在的位置,例如所有 CSS、JavaScript、HTML、图片等。在本实验中,我们将创建一个源,它映射到我们在本实验开始时创建的 Cloud Storage 存储分区。我们将边缘缓存来源命名为 cme-origin。CDN 的来源是指在分发到边缘缓存服务器之前,所有来源内容存储在此处的位置。

我们将使用 gcloud edge-cache origins create 命令创建源站。该命令需要几分钟才能完成。

命令

gcloud edge-cache origins create cme-origin \
--origin-address="gs://live-streaming-storage-$LOGNAME"

输出示例

Create request issued for: cme-origin
Waiting for operation [projects/my-project/locations/global/operations/operation-1612121774168-5ba3759af1919-
3fdcd7b1-99f59223] to complete...done
Created origin cme-origin

2. 创建边缘缓存服务

现在我们已经设置好了边缘缓存来源,接下来就可以创建边缘缓存服务本身了。

创建 cme-demo.yaml 文件

边缘缓存服务配置通过 YAML 文件完成。在 Cloud Shell 中,创建一个名为 cme-demo.yaml 的本地文件。使用 vinano 或任何其他编辑器,并将以下行粘贴到 YAML 文件中:

name: cme-demo
routing:
  hostRules:
    - hosts:
        - demo.cme.com
      pathMatcher: routes
  pathMatchers:
    - name: routes
      routeRules:
        - headerAction:
            responseHeadersToAdd:
              - headerName: x-cache-status
                headerValue: "{cdn_cache_status}"
          matchRules:
            - prefixMatch: /
          origin: cme-origin
          priority: 100
          routeAction:
            cdnPolicy:
              cacheKeyPolicy: {}
              cacheMode: FORCE_CACHE_ALL
              defaultTtl: 3600s
              signedRequestMode: DISABLED
        - headerAction:
            responseHeadersToAdd:
              - headerName: x-cache-status
                headerValue: "{cdn_cache_status}"
          matchRules:
            - pathTemplateMatch: /**.m3u8
          origin: cme-origin
          priority: 25
          routeAction:
            cdnPolicy:
              cacheKeyPolicy: {}
              cacheMode: FORCE_CACHE_ALL
              defaultTtl: 1s
              signedRequestMode: DISABLED
        - headerAction: {}
          matchRules:
            - pathTemplateMatch: /**.ts
          origin: cme-origin
          priority: 50
          routeAction:
            cdnPolicy:
              cacheKeyPolicy: {}
              cacheMode: FORCE_CACHE_ALL
              defaultTtl: 2s
              signedRequestMode: DISABLED

保留所有边缘缓存服务配置默认值。上述文件中有 3 个用户可能需要更新的字段值:

  • name:媒体 CDN 实例的名称 - 此处:cme-demo
  • hosts: 表示将由此媒体 CDN 服务解析的域名列表 - 此处为:demo.cme.com。我们将在本演示中用到它。我们将使用媒体 CDN 实例的 IP 地址。
  • Origin:,这是我们刚刚在上一步中创建的边缘缓存来源。请将该值设置为 cme-origin - 媒体 CDN 来源的名称。

如需详细了解可在 YAML 文件中使用的不同变量,请参阅边缘缓存服务配置指南

创建边缘缓存服务

我们将在边缘缓存来源 cme-origin 上创建一个名为 cme-demo 的边缘缓存服务,其主机为 demo.cme.com。如需创建服务,请在 Cloud Shell 中运行以下命令:

命令

gcloud edge-cache services import cme-demo \
    --source=cme-demo.yaml

创建边缘缓存服务可能需要几分钟的时间。

输出示例

Request issued for: [cme-demo]
Waiting for operation [projects/PROJECT_ID/locations/global/operations/operation-1670476252264-5ef4a0f9f36ce-dd380af5-321be9a0] to complete...done.     
createTime: '2022-12-07T18:08:54.403446942Z'
ipv4Addresses:
- 34.104.35.152
ipv6Addresses:
- '2600:1900:4110:d18::'
name: projects/PROJECT_ID/locations/global/edgeCacheServices/cme-demo
routing:
  hostRules:
  - hosts:
    - demo.cme.com
    - 34.104.35.152
    pathMatcher: routes
  pathMatchers:
  - name: routes
    routeRules:
    - headerAction:
        responseHeadersToAdd:
        - headerName: x-cache-status
          headerValue: '{cdn_cache_status}'
      matchRules:
      - prefixMatch: /
      origin: projects/123456789/locations/global/edgeCacheOrigins/cme-origin
      priority: '100'
      routeAction:
        cdnPolicy:
          cacheKeyPolicy: {}
          cacheMode: FORCE_CACHE_ALL
          defaultTtl: 3600s
          signedRequestMode: DISABLED
    - headerAction:
        responseHeadersToAdd:
        - headerName: x-cache-status
          headerValue: '{cdn_cache_status}'
      matchRules:
      - pathTemplateMatch: /**.m3u8
      origin: projects/123456789/locations/global/edgeCacheOrigins/cme-origin
      priority: '25'
      routeAction:
        cdnPolicy:
          cacheKeyPolicy: {}
          cacheMode: FORCE_CACHE_ALL
          defaultTtl: 1s
          signedRequestMode: DISABLED
    - headerAction: {}
      matchRules:
      - pathTemplateMatch: /**.ts
      origin: projects/123456789/locations/global/edgeCacheOrigins/cme-origin
      priority: '50'
      routeAction:
        cdnPolicy:
          cacheKeyPolicy: {}
          cacheMode: FORCE_CACHE_ALL
          defaultTtl: 2s
          signedRequestMode: DISABLED
updateTime: '2022-12-08T05:11:31.598744308Z'

记下并复制边缘缓存服务实例的 ipv4Addresses - 此处为 34.104.36.157。我们将使用它来更新 cme-demo.yaml 文件,并在稍后流式传输经过转码的视频。

更新边缘缓存服务

此时,最好更新边缘缓存服务配置,以便稍后能够使用该服务的 IP 流式传输视频。我们可以使用边缘缓存服务 YAML 文件列出边缘缓存服务将接受其请求的所有主机名/IP。此时,我们仅将 demo.cme.com 指定为主机。如需为此网域提供名称解析,您可以配置 DNS 区域。不过,更简单的解决方案是将 IP 地址添加到 yaml 文件的主机列表中。再次修改 YAML 文件,使其如下所示:

name: cme-demo
routing:
  hostRules:
    - hosts:
        - demo.cme.com
        - IPADDRESS
      pathMatcher: routes
  pathMatchers:
    - name: routes
      routeRules:
        - headerAction:
            responseHeadersToAdd:
              - headerName: x-cache-status
                headerValue: "{cdn_cache_status}"
          matchRules:
            - prefixMatch: /
          origin: cme-origin
          priority: 100
          routeAction:
            cdnPolicy:
              cacheKeyPolicy: {}
              cacheMode: FORCE_CACHE_ALL
              defaultTtl: 3600s
              signedRequestMode: DISABLED
        - headerAction:
            responseHeadersToAdd:
              - headerName: x-cache-status
                headerValue: "{cdn_cache_status}"
          matchRules:
            - pathTemplateMatch: /**.m3u8
          origin: cme-origin
          priority: 25
          routeAction:
            cdnPolicy:
              cacheKeyPolicy: {}
              cacheMode: FORCE_CACHE_ALL
              defaultTtl: 1s
              signedRequestMode: DISABLED
        - headerAction: {}
          matchRules:
            - pathTemplateMatch: /**.ts
          origin: cme-origin
          priority: 50
          routeAction:
            cdnPolicy:
              cacheKeyPolicy: {}
              cacheMode: FORCE_CACHE_ALL
              defaultTtl: 2s
              signedRequestMode: DISABLED

为了反映这些更改,我们只需重新导入 YAML 文件即可。在 Cloud Shell 终端中,运行以下命令:

命令

gcloud edge-cache services import cme-demo \
    --source=cme-demo.yaml

检查命令的输出,并验证 IP 是否显示在主机列表中。

此时,边缘缓存服务实例将接受使用 "demo.cme.com" 或 IP 地址作为主机的请求。

12. 生成输入信号

现在,我们已经配置了所有必需的服务,接下来我们生成直播输入信号。在本部分,我们将执行以下操作:

  1. 安装 FFmpeg,这是一款免费的开源软件
  2. 向输入/频道发送测试直播信号

1. 安装 FFmpeg

FFmpeg 是一个免费的开源软件项目,包含一套用于处理视频、音频以及其他多媒体文件和流的库和程序。在 Cloud Shell 终端中,使用以下命令安装 FFmpeg:

命令

sudo apt install ffmpeg -y

安装完成后,我们通过检查 FFmpeg 的版本来验证其是否正确:

命令

ffmpeg -version

输出示例

ffmpeg version 4.3.4-0+deb11u1 Copyright (c) 2000-2021 the FFmpeg developers
built with gcc 10 (Debian 10.2.1-6)
...

FFmpeg 已正确安装。

2. 启动向输入/频道发送直播信号

安装 FFmpeg 后,我们将向输入端点发送测试输入流,以生成直播视频流。

在 Cloud Shell 终端中,使用我们在“创建和配置输入端点”中创建的 URI 环境变量运行以下命令部分。

命令

ffmpeg -re -f lavfi -i "testsrc=size=1280x720 [out0]; sine=frequency=500 [out1]" \
  -acodec aac -vcodec h264 -f flv $URI

您应该会看到 FFmpeg 发送测试实时信号。该命令不会返回提示。信号会一直生成,直到您停止它为止。在本实验的剩余步骤中,您需要打开一个新的 Cloud Shell 窗口。

13. 打开新的 Cloud Shell

此时,您需要打开一个新的 Cloud Shell 窗口以继续本实验,因为 FFmpeg 会永久运行,直到您按 <CTRL+C>命令来停止它,从而停止生成实时信号。

点击“+”号。这将再打开一个 Cloud Shell 窗口。

b3c7b0be6276c194.png

在新打开的 Cloud Shell 窗口中运行本实验的其余部分。

设置环境变量

由于这是一个新的 CloudShell,因此我们需要再次设置环境变量。我们将使用 source 命令设置环境变量。

命令

source ~/env_variables.txt

验证是否已设置变量

我们来验证一下是否设置了所有必需的环境变量。我们应该会在输出中看到总共 6 个环境变量。

命令

env | grep -E 'DEVSHELL_PROJECT_ID=|LOGNAME|PROJECT_NUMBER|LOCATION|INPUT_ID|CHANNEL_ID'

输出示例

LOCATION=us-west2
DEVSHELL_PROJECT_ID=<YOUR_PROJECT_ID>
LOGNAME=<YOUR_USERNAME>
PROJECT_NUMBER=<YOUR_PROJECT_NUMBER>
INPUT_ID=lab-live-input
CHANNEL_ID=lab-live-channel

14. 验证实时信号是否正在接受转码

我们将运行一个 curl 来描述该频道。我们应该会在输出中看到 streamState 从 "AWAITING_INPUT" 更改为 "STREAMING"

命令

curl -s -X GET -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) "https://livestream.googleapis.com/v1/projects/$PROJECT_NUMBER/locations/$LOCATION/channels/$CHANNEL_ID" | grep "streamingState"

在 JSON 输出文件响应中,您应该会看到 "streamingState": "STREAMING",这表示相应频道正在进行直播,并且直播信号正在进行转码。

我们还需要验证一下存储分区的内容,该存储分区应该在其中看到清单文件和多个 TS 视频片段。在 Cloud Shell 中运行以下命令,以列出我们在实验开始时创建的存储分区的内容,供 Live Streaming API 用来输出经过转码的直播信号清单和 TS 视频片段:

命令

gcloud storage ls --recursive gs://live-streaming-storage-$LOGNAME/**

输出示例

gs://live-streaming-storage-$LOGNAME/
gs://live-streaming-storage-$LOGNAME/main.m3u8
gs://live-streaming-storage-$LOGNAME/mux_video_ts/index-1.m3u8
gs://live-streaming-storage-$LOGNAME/mux_video_ts/segment-0000000016.ts
gs://live-streaming-storage-$LOGNAME/mux_video_ts/segment-0000000017.ts
gs://live-streaming-storage-$LOGNAME/mux_video_ts/segment-0000000018.ts
gs://live-streaming-storage-$LOGNAME/mux_video_ts/segment-0000000019.ts
gs://live-streaming-storage-$LOGNAME/mux_video_ts/segment-0000000020.ts
gs://live-streaming-storage-$LOGNAME/mux_video_ts/segment-0000000021.ts
gs://live-streaming-storage-$LOGNAME/mux_video_ts/segment-0000000022.ts
...

您应该会看到:

  • HLS 清单文件:main.m3u8
  • 相应的 TS 视频片段:一系列带编号的文件 segment-000000000X.ts

此时,我们已完成以下内容:

  • Live Streaming API:直播信号通过 Live Streaming API 生成并转码到存储分区中
  • 媒体 CDN:配置了媒体 CDN,并将直播存储分区配置为媒体 CDN 的来源。

在接下来的部分中,我们将验证边缘缓存服务,然后使用媒体 CDN 任播 IP 地址流式传输经过转码的视频。

15. 验证边缘缓存服务实例是否正常运行

在本部分中,我们将验证边缘缓存服务实例是否按预期运行。为此,我们将尝试使用边缘缓存服务的 IP 地址从边缘缓存服务实例访问文件。首次访问对象时,对象尚未缓存。我们应该观察到一个缓存 MISS。对于第一个请求,对象将从起点读取并缓存在边缘。以下所有尝试访问同一文件的尝试都将返回缓存 HIT,因为对象现在已缓存在边缘。我们将验证此行为:

在 Cloud Shell 中运行以下 curl 命令,以访问存储在边缘缓存来源中的转码视频清单文件:

命令

curl -svo /dev/null --resolve demo.cme.com:80:<Replace_With_Edge_Cache_IP> \
"http://demo.cme.com/main.m3u8"

请注意解析,我们使用边缘缓存服务实例的 IP 地址来解析其名称。请使用 demo.cme.com:<IP>,其中 IP 是我们刚刚创建的边缘缓存服务实例的 IP。

在输出中查找 x-cache-status 标头。

输出示例

Added demo.cme.com:80:34.104.35.152 to DNS cache
* Hostname demo.cme.com was found in DNS cache
*   Trying 34.104.35.152:80...
* Connected to demo.cme.com (34.104.35.152) port 80 (#0)
> GET /main.m3u8 HTTP/1.1
> Host: demo.cme.com
> User-Agent: curl/7.74.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< x-guploader-uploadid: ADPycdtKtflWt4Kha5YxXNNRwO-Eu6fGSPs-T-XY4HJmNMo46VJyWlD4EAk-8a6SegxjWq3o1gTPqZbpkU_sjW__HPAdDw
< date: Wed, 07 Dec 2022 18:23:46 GMT
< last-modified: Wed, 07 Dec 2022 18:23:45 GMT
< etag: "6bff620ccca4a9849ba4e17fa7c521fb"
< x-goog-generation: 1670437425805400
< x-goog-metageneration: 1
< x-goog-stored-content-encoding: identity
< x-goog-stored-content-length: 193
< content-type: application/x-mpegURL
< x-goog-hash: crc32c=sPO3zw==
< x-goog-hash: md5=a/9iDMykqYSbpOF/p8Uh+w==
< x-goog-storage-class: STANDARD
< accept-ranges: bytes
< content-length: 193
< server: Google-Edge-Cache
< x-request-id: fd25285b-fc1a-4fd4-981a-c50ead2c85ed
< x-xss-protection: 0
< x-frame-options: SAMEORIGIN
< x-cache-status: den;miss
< cache-control: public,max-age=3600
<
{ [193 bytes data]
* Connection #0 to host demo.cme.com left intact

请注意,缓存 miss,因为对象尚未缓存,而是从源站读取。

现在,我们将针对 m3u8 文件发出多个请求,如果一切都正确配置,媒体 CDN 应开始从其缓存中提供内容。以下命令将发出 10 个 curl 请求,并且仅输出 x-cache-status 标头。

命令

for i in {1..10};do curl -Is --resolve demo.cme.com:80:<Replace_With_Edge_Cache_IP> "http://demo.cme.com/main.m3u8" | grep x-cache-status;done

输出应混合使用缓存 hitmiss。如果您在输出中看到缓存命中,则表示媒体 CDN 按预期运行。

输出示例

x-cache-status: den;miss
x-cache-status: den;hit
x-cache-status: den;hit
x-cache-status: den;hit
x-cache-status: den;hit
x-cache-status: den;hit
x-cache-status: den;hit
x-cache-status: den;hit
x-cache-status: den;hit
x-cache-status: den;hit

请注意缓存命中,因为对象现在缓存在边缘。Cloud Medie Edge Service 运行正常。

16. 使用 VLC 在线播放经过转码的实时信号视频

在这一部分,我们将各个环节串联起来,并将迄今为止我们一直在做的所有步骤关联起来:

  • 我们创建了一个名为 live-streaming-storage-$LOGNAME 的存储分区,用于接收 Live Streaming API 将直播信号转码为 HLS 内容的结果。
  • 我们设置了 Live Streaming API。
  • 我们使用 FFmpeg 启动了一个 RTMP 直播信号,该信号可馈送 Live Streaming API 的输入/频道。
  • 我们确认直播信号已馈送到频道,并验证频道处于 streaming 模式。
  • 我们验证了生成的转码文件(清单 + TS 片段)已生成并存储在存储分区“live-streaming-storage-$LOGNAME”中。
  • 设置了一个名为 cme-origin 的边缘缓存来源,并以 GCS 存储分区 live-streaming-storage-$LOGNAME 作为来源。
  • 已设置一个名为 cme-demo 的边缘缓存实例,并以 cme-origin 作为其来源。
  • 我们验证了边缘缓存服务实例的行为(缓存未命中、缓存命中)。

现在,我们可以使用视频播放器通过媒体 CDN 缓存来流式传输已转码的直播信号。为此,我们将使用 VLC 播放器。VLC 播放器是一款免费的开源跨平台多媒体播放器和框架,可播放大多数多媒体文件。可播放自适应媒体格式(例如 DASH 和 HLS)。它采用自适应在线播放的原则,即播放器会根据网络连接质量和可用带宽来调整所播放视频的质量。进行刚才的转码作业时,我们使用默认的预设值,并“仅”生成两种画质:标清和高清。当我们开始在播放器中播放视频时,您应该看到视频开始播放标清格式,如果网络连接状况良好,应该可以快速切换到高清格式。

我们将流式传输经过 HLS(广泛支持的 Apple 视频格式)转码的实时信号。相应的文件称为 main.m3u8,即 HLS 清单。该清单指向 TS 视频片段。

要使用 VLC 播放器,请访问 https://www.videolan.org/vlc/ 并下载适用于您笔记本电脑操作系统的播放器版本。VLC 适用于 Windows、MacOSX、Linux、Android 和 iOS 系统。

2a2d19abe728d222

在笔记本电脑上安装并启动 Player。在接下来的几个步骤中,我们将使用 MacOSX 版播放器。

要播放视频,请转到“文件”/“开放网络”:

f85565301f7c68dc.png

设置:

  • 网址:http://&lt;Replace_With_Edge_Cache_IP&gt;/main.m3u8。这是我们要流式传输的视频的网址。请注意:
  • 媒体 CDN 实例的 IP:34.105.35.246。请替换为您部署的 Cloud Media Service 的 IP 地址。
  • 指向清单视频文件的路径:“/”。这是我们在 live-streaming-storage-$LOGNAME 存储分区中用于存储转码的实时信号文件的路径。路径为根路径:“/”。
  • 清单视频文件的名称:HLS 清单文件 main.m3u8

然后点击“打开”。您应该会看到已转码的直播视频开始播放。该视频将如以下屏幕截图所示。屏幕上的计数器将以 1 为增量运行,您应该能听到连续的哔哔声。

它是 FFmpeg 生成的基本 RTMP 测试实时信号,由 Live Streaming API 转码为 HLS,并通过媒体 CDN 缓存提供:

28fc359b49d44ec2

如果您愿意,可以使用任何其他 HLS 和 MPEG DASH 播放器。您可以考虑以下几个方面:

  • Quicktime Player - Mac 上默认安装。同样:打开指向 http://34.104.36.157/main.m3u8 的网络连接 - 将 IP 地址替换为您的某个边缘缓存服务实例。

17. 监控媒体 CDN

媒体 CDN 信息中心模板由 SME 团队创建:https://gist.github.com/elithrar/1c511d00f5cd3736fb2a3897867209c1

如需安装该工具,请在 Cloud Shell 窗口中运行以下命令:

下载 YAML 文件:

curl https://gist.githubusercontent.com/elithrar/1c511d00f5cd3736fb2a3897867209c1/raw/3cb70855304f29e5c06b8d63063196354db0dec3/media-edge-20210208-dashboard --output media-edge-20210208-dashboard.yaml

为 Cloud Monitoring 创建信息中心:

gcloud monitoring dashboards create --config-from-file media-edge-20210208-dashboard.yaml

设置过程可能需要几分钟的时间。转到 Google Cloud 控制台,然后点击三个横杠 >运维 >监控 >信息中心。您应该会看到一个名为“Media Edge Metrics”的信息中心。点击该按钮,您将看到以下指标:

d0821d84a88a928d.png

18. 清理实验环境

恭喜您完成本实验。在本部分中,我们将删除在整个实验过程中创建的所有资源。

停止 FFmpeg 信号

在运行 FFmpeg 的 Cloud Shell 终端上点击 <CTRL+C>

停止直播频道:

命令

curl -X POST \
-H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
-H "Content-Type: application/json; charset=utf-8" \
-d "" \
"https://livestream.googleapis.com/v1/projects/$PROJECT_NUMBER/locations/$LOCATION/channels/$CHANNEL_ID:stop"

删除直播频道:

命令

curl -X DELETE -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) "https://livestream.googleapis.com/v1/projects/$PROJECT_NUMBER/locations/$LOCATION/channels/$CHANNEL_ID"

删除直播输入端点:

命令

curl -X DELETE \
-H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
"https://livestream.googleapis.com/v1/projects/$PROJECT_NUMBER/locations/$LOCATION/inputs/$INPUT_ID"

删除 GCS 存储分区

命令

gsutil rm -r gs://live-streaming-storage-$LOGNAME

删除边缘缓存服务实例

命令

gcloud edge-cache services delete cme-demo

输入“Y”以确认删除出现提示时

删除边缘缓存来源

命令

gcloud edge-cache origins delete cme-origin

输入“Y”以确认删除出现提示时

删除自定义信息中心

命令

gcloud monitoring dashboards delete $(gcloud monitoring dashboards list --filter="displayName:Media Edge Metrics" --format="value(name)")