Google Cloud 直播服务 Live Stream API 已经在2022年6月 GA。用户可以使用这个托管服务创建和管理直播流,并利用谷歌的全球高速网络,向各地的主播和观众提供高质量的推流和拉流体验。这个服务主要包含 RTMP 推流、直播转码、HLS 或 MPEG-DASH 切片等功能,可以将转码后的流媒体文件输出到 Google Cloud 存储桶,通过 Google Cloud CDN 来下载播放。本文通过一个示例,介绍如何使用该服务,搭建一个直播流。

创建直播频道
测试直播流
给直播拉流配置 CDN 加速
参考资料
创建直播频道
首先用 gcloud 命令开启直播服务。
gcloud services enable livestream.googleapis.com |
后面的所有 API 调用都需要使用一个服务账号鉴权。可以给用到的服务账号配置以下角色。
Live Stream > Live Stream Editor
根据测试需要,配置以下环境变量,主要用于后面创建的各个资源的命名。
PROJECT_ID=youzhi-lab LOCATION=asia-east2 INPUT_ID=input-endpoint-hkg-1 CHANNEL_ID=channel-hkg-1 BUCKET=hk-publish |
创建 Google Cloud 对象存储桶,用来存放直播流转码后的切片和播放列表文件。
gsutil mb -l $LOCATION gs://$BUCKET |
创建一个直播推流端点,即 Input Endpoint。注意调用时用到了一个配置文件,里面注明了推流类型为 RTMP。
cat > create_input_request.json << 'EOF' { "type": "RTMP_PUSH" } EOF
curl -X POST \\ -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \\ -H "Content-Type: application/json; charset=utf-8" \\ -d @create_input_request.json \\ "https://livestream.googleapis.com/v1/projects/$PROJECT_ID/locations/$LOCATION/inputs?inputId=$INPUT_ID"
返回结果: { "name": "projects/youzhi-lab/locations/asia-east2/operations/operation-1656396606764-5e27be35a73ec-f31fccba-e3fb0a0b", "metadata": { "@type": "type.googleapis.com/google.cloud.video.livestream.v1.OperationMetadata", "createTime": "2022-06-28T06:10:08.232687431Z", "target": "projects/youzhi-lab/locations/asia-east2/inputs/input-endpoint-hkg-1", "verb": "create", "requestedCancellation": false, "apiVersion": "v1" }, "done": false } |
上面和下面的一些操作是异步操作,可以用 Operations API 来查看其完成状态。
curl -X GET \\ -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \\ "https://livestream.googleapis.com/v1/projects/youzhi-lab/locations/asia-east2/operations/operation-1656396606764-5e27be35a73ec-f31fccba-e3fb0a0b"
{ "name": "projects/youzhi-lab/locations/asia-east2/operations/operation-1656396606764-5e27be35a73ec-f31fccba-e3fb0a0b", "metadata": { "@type": "type.googleapis.com/google.cloud.video.livestream.v1.OperationMetadata", "createTime": "2022-06-28T06:10:08.232687431Z", "target": "projects/youzhi-lab/locations/asia-east2/inputs/input-endpoint-hkg-1, "verb": "create", "requestedCancellation": false, "apiVersion": "v1" }, "done": false } |
创建一个直播频道(Channel)配置文件。其中包含了输入端点、输出存储桶以及转码配置等信息。
cat > create_channel_request.json << EOF { "inputAttachments": [ { "key": "my-input", "input": "projects/$PROJECT_ID/locations/$LOCATION/inputs/$INPUT_ID" } ], "output": { "uri": "gs://$BUCKET" }, "elementaryStreams": [ { "key": "es_video_high", "videoStream": { "h264": { "profile": "high", "widthPixels": 1280, "heightPixels": 720, "bitrateBps": 3000000, "frameRate": 30 } } }, { "key": "es_video_main", "videoStream": { "h264": { "profile": "main", "widthPixels": 480, "heightPixels": 270, "bitrateBps": 300000, "frameRate": 30 } } }, { "key": "es_audio", "audioStream": { "codec": "aac", "channelCount": 2, "bitrateBps": 160000 } } ], "muxStreams": [ { "key": "mux_video_hd_ts", "container": "ts", "elementaryStreams": ["es_video_high", "es_audio"], "segmentSettings": { "segmentDuration": "2s" } }, { "key": "mux_video_sd_ts", "container": "ts", "elementaryStreams": ["es_video_main", "es_audio"], "segmentSettings": { "segmentDuration": "2s" } } ], "manifests": [ { "fileName": "main.m3u8", "type": "HLS", "muxStreams": [ "mux_video_hd_ts", "mux_video_sd_ts" ], "maxSegmentCount": 5 } ] } EOF |
创建直播频道,使用上面的配置文件。
curl -X POST \\ -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \\ -H "Content-Type: application/json; charset=utf-8" \\ -d @create_channel_request.json \\ "https://livestream.googleapis.com/v1/projects/$PROJECT_ID/locations/$LOCATION/channels?channelId=$CHANNEL_ID" |
可以通过 Operations 接口查询创建进度,在完成后,可以启动频道。
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_ID/locations/$LOCATION/channels/$CHANNEL_ID:start" |
如果调用成功,直播频道已经准备就绪,可以开始推流和拉流了。
注意,如果上面调用返回如下的404错误,可以尝试在控制台 Cloud Shell 里执行一遍。如果 Cloud Shell 里不报错,则有可能是本地环境的防火墙或者 VPN 网关导致的错误。 <p>The requested URL<code>/v1/projects/youzhi-lab/locations/asia-east2/channels/channel-hkg-1</code> was not found on this server.
|
测试直播流
首先查询推流端点地址,可以用 inputs 接口列表一下现有的输入端点,找到刚刚创建的推流输入端点。
curl -X GET \\ -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \\ -H "Content-Type: application/json; charset=utf-8" \\ "https://livestream.googleapis.com/v1/projects/$PROJECT_ID/locations/$LOCATION/inputs"
输出: { "inputs": [ { "name": "projects/youzhi-lab/locations/asia-east2/inputs/input-endpoint-hkg-1", "createTime": "2022-06-28T06:10:08.229369763Z", "updateTime": "2022-06-28T06:12:29.642499099Z", "type": "RTMP_PUSH", "uri": "rtmp://34.96.142.152/live/e559cc2c-9fce-4d4b-ab13-3e72fa356af9", "tier": "HD" } ] } |
返回的内容中的“uri”字段即为推流的地址,是一个标准的 RTMP 地址。
我们使用 ffmpeg 来推一个测试流到该地址。
INPUT_STREAM_URI=rtmp://34.96.142.152/live/e559cc2c-9fce-4d4b-ab13-3e72fa356af9
ffmpeg -re -f lavfi \\ -i "testsrc=size=1280x720 [out0]; sine=frequency=500 [out1]" \\ -acodec aac -vcodec h264 -f flv $INPUT_STREAM_URI |
如果 ffmpeg 执行不报错,等待几秒,可以看到存储桶中增加了 main.m3u8 文件,以及两个子目录,分别存放了两个不同码率的转码输出切片和播放列表。每个子目录里保留最新的35个(70秒)切片文件,更老的切片文件会被自动删除。为了能让外部播放器能播放这些文件,需要将存储桶设为公开可访问,并且配置跨域规则。
gsutil iam ch allUsers:objectViewer gs://$BUCKET
cat > cors.json << 'EOF' [ { "origin": ["https://shaka-player-demo.appspot.com/"], "responseHeader": ["Content-Type", "Range"], "method": ["GET", "HEAD"], "maxAgeSeconds": 86400 } ] EOF
gsutil cors set cors.json gs://$BUCKET |
此时可以把存储桶根目录的 main.m3u8 文件公开访问地址拷贝下来,在 HLS 播放器中播放。比如
https://storage.googleapis.com/hk-publish/main.m3u8
在浏览器里常用的 HLS 播放器包括 Shaka 播放器 Native HLS Player 播放器。
https://shaka-player-demo.appspot.com/
https://chrome.google.com/webstore/detail/native-hls-playback/emnphkkblegpebimobpbekeedfgemhof
下面是该测试流在 Shaka 播放器中的播放画面。可以看到码率选择中有720P 和270P 两个码率,支持自适应码率选择或者手动选择。这与频道配置的转码配置一致。
如果要用第三方推流软件,比如 OBS 来推流,可以在推流配置中输入推流地址,注意 Stream Key 要输入推流地址中 live 字段后面的 UUID。

给直播拉流配置 CDN 加速
为了给直播流观看加速,可以配置 Cloud CDN,在边缘节点缓存直播切片,并将其源站指向直播转码输出存储桶。注意我们配置了直播流每2秒生成一个新切片,所以直播的播放列表文件应该不缓存,或者缓存 TTL 不超过2秒。而切片文件可以缓存更长时间。在下面的 CDN 配置里,缓存配置是遵循源站,即 GCS 默认配置。在默认配置中,播放列表的缓存标头是 no-store,而切片 TS 文件的缓存 TTL 是3600秒。
gcloud compute backend-buckets create backend-bucket-$BUCKET \\ --gcs-bucket-name=$BUCKET \\ --enable-cdn \\ --cache-mode=USE_ORIGIN_HEADERS
gcloud compute url-maps create http-lb-$BUCKET \\ --default-backend-bucket=backend-bucket-$BUCKET
gcloud compute target-http-proxies create http-lb-proxy-$BUCKET \\ --url-map=http-lb-$BUCKET
gcloud compute forwarding-rules create http-lb-forwarding-rule-$BUCKET \\ --load-balancing-scheme=EXTERNAL \\ --network-tier=PREMIUM \\ --global \\ --target-http-proxy=http-lb-proxy-$BUCKET \\ --ports=80 |
配置完成后,可以获取 Cloud CDN 的访问地址。
gcloud compute forwarding-rules describe http-lb-forwarding-rule-$BUCKET --global
输出: IPAddress: 34.160.246.50 IPProtocol: TCP creationTimestamp: '2022-07-05T19:28:47.026-07:00' description: '' ... |
可以通过以下地址来播放直播流。
http://34.160.246.50/main.m3u8
参考资料
[1] Overview of the Live Stream API
[2] Live Stream API Reference
[3] Live Stream API Locations