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

1. 简介

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

学习内容

本实验将引导我们通过 Media CDN (CDN) + Cloud Media Live Streaming API(直播视频转码)+ Cloud Storage(视频存储空间)+ Video Player(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 信息中心,以直观呈现 Media CDN 的活动。

构建内容

在本实验中,我们将根据以下架构设置环境:

de33cb3e75d52549.png

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

  • 创建一个 Google Cloud Storage (GCS) 存储分区来存储转码后的直播视频
  • 配置 Live Streaming API 以将视频转码为多种格式:HLS + MPEG DASH、标清和高清
  • 设置直播组件:输入/频道
  • 启动直播频道
  • 将 GCS 存储分区设置为源站,以便设置媒体 CDN
  • 设置 FFmpeg 以馈送直播频道
  • 使用视频播放器流式传输转码后的直播画面
  • 设置 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. 启用所需的 Service API

1. 设置环境变量

在本实验中,我们将使用一些变量运行 gcloudcurl 命令。我们需要配置以下环境变量。

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

项目 ID 和用户名

这些环境变量通常在 Cloud Shell 中预先配置。我们将使用 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.png

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

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

我们将在稍后的实验中创建以下资源:

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

8. 创建和配置输入端点

创建 input.json 文件

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

命令

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

创建输入端点

在本实验室撰写之时,gcloud 不支持 Live Stream API。我们将使用 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。您可以在以 "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. 创建和配置直播频道

我们来创建一个与上一部分中刚刚创建的输入端点关联的直播频道。以下示例创建了一个频道,用于生成由单个高清 (1280x720) 版本组成的 HLS 直播流。该渠道将与输入端点以及我们之前创建的存储分区相关联。

创建 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。我们将在本演示中使用它。我们将使用 Media 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 地址是否显示在主机列表中。

此时,Edge Cache Service 实例将接受将 "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 终端名称旁边的“+”号。系统会打开一个额外的 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 来描述该通道。我们应该会在输出中看到 streamingState 从 "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。

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

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

在本部分中,我们将验证 Edge Cache 服务实例是否按预期运行。为此,我们将尝试使用边缘缓存服务的 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

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

现在,我们将对 m3u8 文件发出多个请求,如果所有配置均正确无误,Media 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。如果您在输出中看到缓存命中,则表示 Media 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 Media Edge 服务运行正常。

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.png

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

如需播放视频,请前往“文件”/“打开网络”:

f85565301f7c68dc.png

使用以下命令进行设置:

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

然后点击“打开”。您应该会看到转码后的直播视频开始播放。视频将如以下屏幕截图所示。屏幕上的计数器将以 1 为单位递增,您应该会听到连续的提示音。

这是 FFmpeg 生成的基本 RTMP 测试直播信号,由 Live Streaming API 转码为 HLS,并通过媒体 CDN 缓存进行传送:

28fc359b49d44ec2.png

您可以使用任何其他 HLS 和 MPEG DASH 播放器。以下是一些您可以考虑的播放器:

  • Quicktime 播放器 - 默认安装在 Mac 上。这里也是一样:打开与 http://34.104.36.157/main.m3u8 的网络连接,将 IP 地址替换为您的 Edge Cache 服务实例的 IP 地址。

17. 监控媒体 CDN

SME 团队创建了媒体 CDN 信息中心模板 - 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)")