Nesta página, explicamos como criptografar o conteúdo de transmissão ao vivo. A API Live Stream não cria nem gerencia chaves de criptografia ou licenças diretamente. Em vez disso, use um provedor terceirizado de gerenciamento de direitos digitais (DRM, na sigla em inglês) para esses recursos. Depois de criar as chaves de criptografia para a mídia, transmita-as para a API Live Stream usando o Secret Manager.
As configurações de criptografia são especificadas nas
configurações
Channel
. Quando o streaming começa, o pipeline de vídeo da API Live Stream
começa a criptografar seu conteúdo. O manifesto de saída inclui as informações
necessárias para descriptografar o conteúdo no player de mídia de sua escolha.
Configurações compatíveis
Protocolo de streaming | Contêiner | sistema DRM | Esquema de criptografia |
---|---|---|---|
HLS | TS | ClearKey | aes128 |
HLS | TS | ClearKey | sampleAes |
HLS | TS | FairPlay | sampleAes |
HLS | fMP4 | FairPlay | Somente cbcs mpegCenc |
MPEG-DASH | fMP4 | ClearKey | mpegCenc cenc ou cbcs |
MPEG-DASH | fMP4 | Widevine | mpegCenc cenc ou cbcs |
HLS | fMP4 | Widevine | mpegCenc cenc ou cbcs |
MPEG-DASH | fMP4 | PlayReady | mpegCenc cenc ou cbcs |
HLS | fMP4 | PlayReady | mpegCenc cenc ou cbcs |
Adicionar a chave de criptografia ao Secret Manager
Antes de começar, crie suas chaves de criptografia usando o provedor de DRM terceirizado de sua preferência.
A API Live Stream exige que seu secret contenha a chave de criptografia no formato JSON a seguir, junto com outras informações necessárias.
Consulte a documentação do protocolo DRM para ver a descrição de cada campo. É necessário converter o Snake-Case para o CamelCase no formato JSON.
Exemplo de JSON
{
"encryptionKeys": [
{
// Key for FairPlay configuration.
"keyId": "d569cb35bd0548c7a99d92feb381df13",
"key": "f1967daca83e81f38d80aa741e7b32c2",
"iv": "8d80aa741e7b32c2f1967daca83e81f3",
"keyUri": "skd://d569cb35bd0548c7a99d92feb381df13",
"matchers": [
{
"muxStreams": ["ts_fairplay"]
}
]
},
{
// Key for Widevine configurations.
"keyId": "44ec248b048c43a6a6ee58a752c6f9f8",
"key": "f1967daca83e81f38d80aa741e7b32c2",
"keyUri": "skd://44ec248b048c43a6a6ee58a752c6f9f8",
"matchers": [
{
"muxStreams": [
"fmp4_widevine_cenc_video",
"fmp4_widevine_cenc_audio",
"fmp4_widevine_cbcs_video",
"fmp4_widevine_cbcs_audio"
]
}
]
},
{
// Key for PlayReady configurations.
"keyId": "8beed229709f480bb6004ec0f33e82d1",
"key": "ad20cd838f354dcc8a77c443d08ff09f",
"keyUri": "skd://8beed229709f480bb6004ec0f33e82d1",
"matchers": [
{
"muxStreams": [
"fmp4_playready_cenc_video",
"fmp4_playready_cenc_audio",
"fmp4_playready_cbcs_video",
"fmp4_playready_cbcs_audio"
]
}
]
},
{
// Key for all ClearKey configurations.
"keyId": "3d9dccb479c64adbb6e514790caa7822",
"key": "f1967daca83e81f38d80aa741e7b32c2",
"keyUri": "https://example.com/keys/3d9dccb479c64adbb6e514790caa7822.bin",
"iv": "8d80aa741e7b32c2f1967daca83e81f3"
// No `matchers` field. This is the default key to use when none of the keys above match.
}
]
}
Se a configuração de criptografia (por exemplo, FairPlay) exigir um
vetor de inicialização explícito (IV), mas não estiver incluído, a API vai usar o valor de
keyId
como o valor de iv
.
Para adicionar a chave de criptografia, siga um destes procedimentos:
Adicione e configure as chaves manualmente. Use os dados JSON anteriores e adicione sua chave de criptografia ao Secret Manager seguindo as etapas em Criar um secret.
Implemente um
key publisher
que receba as chaves de criptografia necessárias e as grave no Secret Manager como versões do secret. Veja um exemplo de implementação que é executado como um Cloud Functions.
Em seguida, faça o seguinte para configurar sua chave de criptografia:
- Configure as permissões de IAM no secret para que a API Live Stream
possa acessar o conteúdo do secret. Para fazer isso, conceda o
papel
secretmanager.secretAccessor
à conta de serviçoservice-PROJECT_NUMBER@gcp-sa-livestream.iam.gserviceaccount.com
. Isso é semelhante a como a conta de serviço tem acesso aos seus buckets do Cloud Storage. - Encontre o nome do recurso da versão do secret que você criou (por exemplo,
projects/PROJECT_NUMBER/secrets/SECRET_ID/versions/VERSION_ID
). Esse nome é necessário para configurar o canal.
Configurar o canal
As configurações de criptografia são especificadas por objetos na matriz
encryptions
no nível Channel
. Um identificador exclusivo
(id
)
é atribuído a cada configuração diferente. Cada muxStream
usa um
identificador para indicar qual configuração de criptografia usar ou omite esse
campo para permanecer não criptografado.
Formato JSON
{
// other channel settings …
"encryptions": [
{
// Identifier for this encryption configuration, to be specified in muxStream(s).
"id": string,
// Configuration for secrets stored in Google Secret Manager.
"secretManagerKeySource": {
// The name of the Secret Version containing the encryption key.
// `projects/{project}/secrets/{secret_id}/versions/{version_number}`
// Using {version_number} of `latest` is not supported.
"secretVersion": string
},
// DRM system(s) that will be used. At least one must be specified. If a DRM system
// is omitted, it will be considered disabled.
"drmSystems": {
// Widevine configuration.
"widevine": {},
// FairPlay configuration.
"fairplay": {},
// PlayReady configuration.
"playready": {},
// ClearKey configuration.
"clearkey": {}
},
// Union field encryption_mode can be only one of the following:
// Configuration for HLS AES-128 encryption.
"aes128": {},
// Configuration for HLS SAMPLE-AES encryption.
"sampleAes": {},
// Configuration for MPEG-DASH Common Encryption (MPEG-CENC).
"mpegCenc": {
// Specify the encryption scheme. Supported schemes:
// - `cenc` - AES-CTR subsample
// - `cbcs`- AES-CBC subsample pattern
"scheme": string
}
// End of list of possible types for union field encryption_mode.
}
// Any other encryption configurations.
],
"muxStreams": [
{
// Unique identifier for the muxStream.
"key": string,
// Identifier of the encryption configuration for the muxStream.
"encryptionId": string
// … other muxStream settings.
}
// Other muxStreams.
],
// Other channel settings.
}
Exemplo (ClearKey)
O exemplo a seguir configura muxStreams AES-128 e cliente Descoberta-AES em manifestos HLS, e muxStreams MPEG-CENC (cenc e cbcs) em manifestos DASH:
"elementaryStreams": [
{
"key": "es_video",
"videoStream": {
"h264": {
"profile": "main",
"heightPixels": 600,
"widthPixels": 800,
"bitrateBps": 1000000,
"frameRate": 60,
},
},
},
{
"key": "es_audio",
"audioStream": {
"codec": "aac",
"channelCount": 2,
"bitrateBps": 160000
}
}
],
"encryptions": [
{
"id": "aes-128",
"secretManagerKeySource": {
"secretVersion": "projects/12345/secrets/key-1/versions/1"
},
"drmSystems": {"clearkey": {}},
"aes128": {}
},
{
"id": "sample-aes",
"secretManagerKeySource": {
"secretVersion": "projects/12345/secrets/key-1/versions/1"
},
"drmSystems": {"clearkey": {}},
"sampleAes": {}
},
{
"id": "cenc",
"secretManagerKeySource": {
"secretVersion": "projects/12345/secrets/key-1/versions/1"
},
"drmSystems": {"clearkey": {}},
"mpegCenc": {
"scheme": "cenc"
}
},
{
"id": "cbcs",
"secretManagerKeySource": {
"secretVersion": "projects/12345/secrets/key-1/versions/1"
},
"drmSystems": {"clearkey": {}},
"mpegCenc": {
"scheme": "cbcs"
}
}
],
"muxStreams": [
{
"key": "ts_aes128",
"container": "ts",
"elementaryStreams": ["es_video", "es_audio"],
"segmentSettings": {"segmentDuration": "2s"},
"encryptionId": "aes-128"
},
{
"key": "ts_sampleaes",
"container": "ts",
"elementaryStreams": ["es_video", "es_audio"],
"segmentSettings": {"segmentDuration": "2s"},
"encryptionId": "sample-aes"
},
{
"key": "fmp4_cenc_video",
"container": "fmp4",
"elementaryStreams": ["es_video"],
"segmentSettings": {"segmentDuration": "2s"},
"encryptionId": "cenc"
},
{
"key": "fmp4_cenc_audio",
"container": "fmp4",
"elementaryStreams": ["es_audio"],
"segmentSettings": {"segmentDuration": "2s"},
"encryptionId": "cenc"
},
{
"key": "fmp4_cbcs_video",
"container": "fmp4",
"elementaryStreams": ["es_video"],
"segmentSettings": {"segmentDuration": "2s"},
"encryptionId": "cbcs"
},
{
"key": "fmp4_cbcs_audio",
"container": "fmp4",
"elementaryStreams": ["es_audio"],
"segmentSettings": {"segmentDuration": "2s"},
"encryptionId": "cbcs"
}
],
"manifests": [
{
"fileName": "manifest_aes128.m3u8",
"type": "HLS",
"muxStreams": ["ts_aes128"],
"maxSegmentCount": 10
},
{
"fileName": "manifest_sampleaes.m3u8",
"type": "HLS",
"muxStreams": ["ts_sampleaes"],
"maxSegmentCount": 10
},
{
"fileName": "manifest_cenc.mpd",
"type": "DASH",
"muxStreams": ["fmp4_cenc_video", "fmp4_cenc_audio"],
"maxSegmentCount": 10
},
{
"fileName": "manifest_cbcs.mpd",
"type": "DASH",
"muxStreams": ["fmp4_cbcs_video", "fmp4_cbcs_audio"],
"maxSegmentCount": 10
}
]
Exemplo (FP/PR/Widevine)
O exemplo a seguir configura os muxStreams FairPlay/LOWER-AES, Widevine/MPEG-CENC (cenc e cbcs) e PlayReady/MPEG-CENC (cenc e cbcs). Os muxStreams Widevine e PlayReady estão incluídos nos manifestos HLS e DASH.
"elementaryStreams": [
{
"key": "es_video",
"videoStream": {
"h264": {
"profile": "main",
"heightPixels": 600,
"widthPixels": 800,
"bitrateBps": 1000000,
"frameRate": 60,
},
},
},
{
"key": "es_audio",
"audioStream": {
"codec": "aac",
"channelCount": 2,
"bitrateBps": 160000
}
}
],
"encryptions": [
{
"id": "fairplay",
"secretManagerKeySource": {
"secretVersion": "projects/12345/secrets/key-1/versions/1"
},
"drmSystems": {"fairplay": {}},
"sampleAes": {}
},
{
"id": "widevine-cenc",
"secretManagerKeySource": {
"secretVersion": "projects/12345/secrets/key-1/versions/1"
},
"drmSystems": {"widevine": {}},
"mpegCenc": {
"scheme": "cenc"
}
},
{
"id": "widevine-cbcs",
"secretManagerKeySource": {
"secretVersion": "projects/12345/secrets/key-1/versions/1"
},
"drmSystems": {"widevine": {}},
"mpegCenc": {
"scheme": "cbcs"
}
},
{
"id": "playready-cenc",
"secretManagerKeySource": {
"secretVersion": "projects/12345/secrets/key-1/versions/1"
},
"drmSystems": {"playready": {}},
"mpegCenc": {
"scheme": "cenc"
}
},
{
"id": "playready-cbcs",
"secretManagerKeySource": {
"secretVersion": "projects/12345/secrets/key-1/versions/1"
},
"drmSystems": {"playready": {}},
"mpegCenc": {
"scheme": "cbcs"
}
}
],
"muxStreams": [
{
"key": "ts_fairplay",
"container": "ts",
"elementaryStreams": ["es_video", "es_audio"],
"segmentSettings": {"segmentDuration": "2s"},
"encryptionId": "fairplay"
},
{
"key": "fmp4_widevine_cenc_video",
"container": "fmp4",
"elementaryStreams": ["es_video"],
"segmentSettings": {"segmentDuration": "2s"},
"encryptionId": "widevine-cenc"
},
{
"key": "fmp4_widevine_cenc_audio",
"container": "fmp4",
"elementaryStreams": ["es_audio"],
"segmentSettings": {"segmentDuration": "2s"},
"encryptionId": "widevine-cenc"
},
{
"key": "fmp4_widevine_cbcs_video",
"container": "fmp4",
"elementaryStreams": ["es_video"],
"segmentSettings": {"segmentDuration": "2s"},
"encryptionId": "widevine-cbcs"
},
{
"key": "fmp4_widevine_cbcs_audio",
"container": "fmp4",
"elementaryStreams": ["es_audio"],
"segmentSettings": {"segmentDuration": "2s"},
"encryptionId": "widevine-cbcs"
},
{
"key": "fmp4_playready_cenc_video",
"container": "fmp4",
"elementaryStreams": ["es_video"],
"segmentSettings": {"segmentDuration": "2s"},
"encryptionId": "playready-cenc"
},
{
"key": "fmp4_playready_cenc_audio",
"container": "fmp4",
"elementaryStreams": ["es_audio"],
"segmentSettings": {"segmentDuration": "2s"},
"encryptionId": "playready-cenc"
},
{
"key": "fmp4_playready_cbcs_video",
"container": "fmp4",
"elementaryStreams": ["es_video"],
"segmentSettings": {"segmentDuration": "2s"},
"encryptionId": "playready-cbcs"
},
{
"key": "fmp4_playready_cbcs_audio",
"container": "fmp4",
"elementaryStreams": ["es_audio"],
"segmentSettings": {"segmentDuration": "2s"},
"encryptionId": "playready-cbcs"
}
],
"manifests": [
{
"fileName": "manifest_fairplay.m3u8",
"type": "HLS",
"muxStreams": ["ts_fairplay"],
"maxSegmentCount": 10
},
{
"fileName": "manifest_widevine_cenc.m3u8",
"type": "HLS",
"muxStreams": ["fmp4_widevine_cenc_video", "fmp4_widevine_cenc_audio"],
"maxSegmentCount": 10
},
{
"fileName": "manifest_widevine_cbcs.m3u8",
"type": "HLS",
"muxStreams": ["fmp4_widevine_cbcs_video", "fmp4_widevine_cbcs_audio"],
"maxSegmentCount": 10
},
{
"fileName": "manifest_widevine_cenc.mpd",
"type": "DASH",
"muxStreams": ["fmp4_widevine_cenc_video", "fmp4_widevine_cenc_audio"],
"maxSegmentCount": 10
},
{
"fileName": "manifest_widevine_cbcs.mpd",
"type": "DASH",
"muxStreams": ["fmp4_widevine_cbcs_video", "fmp4_widevine_cbcs_audio"],
"maxSegmentCount": 10
},
{
"fileName": "manifest_playready_cenc.m3u8",
"type": "HLS",
"muxStreams": ["fmp4_playready_cenc_video", "fmp4_playready_cenc_audio"],
"maxSegmentCount": 10
},
{
"fileName": "manifest_playready_cbcs.m3u8",
"type": "HLS",
"muxStreams": ["fmp4_playready_cbcs_video", "fmp4_playready_cbcs_audio"],
"maxSegmentCount": 10
},
{
"fileName": "manifest_playready_cenc.mpd",
"type": "DASH",
"muxStreams": ["fmp4_playready_cenc_video", "fmp4_playready_cenc_audio"],
"maxSegmentCount": 10
},
{
"fileName": "manifest_playready_cbcs.mpd",
"type": "DASH",
"muxStreams": ["fmp4_playready_cbcs_video", "fmp4_playready_cbcs_audio"],
"maxSegmentCount": 10
}
]
Depois de definir a configuração JSON que você quer usar, crie um canal normalmente.
Iniciar streaming
Depois que o canal for criado, inicie-o e envie o stream de entrada.
Quando o canal começa, a API Live Stream busca a chave de criptografia
identificada por secretVersion
do Secret Manager. Se a
API Live Stream não conseguir buscar a chave ou ela estiver em um
formato irreconhecível, o estado do canal se tornará STREAMING_ERROR
. Se a chave
for buscada, o estado do canal se tornará AWAITING_INPUT
, como de costume.
Quando o streaming começa, a API Live Stream começa a criptografar o conteúdo de saída de acordo com a configuração fornecida no momento da criação.
Monitorar a saída
Os streams de saída criptografados contêm manifestos modificados com as informações necessárias para descriptografar o conteúdo para reprodução.
Exemplos de manifesto
Os manifestos a seguir mostram as informações necessárias para descriptografar o conteúdo associado.
HLS AES-128/ClearKey
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-DISCONTINUITY-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="https://example.com/keys/3d9dccb479c64adbb6e514790caa7822.bin",IV=0x8d80aa741e7b32c2f1967daca83e81f3
#EXT-X-PROGRAM-DATE-TIME:2022-10-12T20:08:22.870Z
#EXTINF:2.576778
segment-0000000000.ts
#EXT-X-PROGRAM-DATE-TIME:2022-10-12T20:08:25.447Z
#EXTINF:2.000000
segment-0000000001.ts
#EXT-X-PROGRAM-DATE-TIME:2022-10-12T20:08:27.447Z
#EXTINF:2.000000
segment-0000000002.ts
#EXT-X-PROGRAM-DATE-TIME:2022-10-12T20:08:29.447Z
#EXTINF:2.000000
segment-0000000003.ts
HLS SUMMARY-AES/FairPlay
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-DISCONTINUITY-SEQUENCE:0
#EXT-X-KEY:METHOD=SAMPLE-AES,URI="skd://d569cb35bd0548c7a99d92feb381df13",KEYFORMAT="com.apple.streamingkeydelivery",KEYFORMATVERSIONS="1"
#EXT-X-PROGRAM-DATE-TIME:2022-10-12T20:08:22.870Z
#EXTINF:2.576778
segment-0000000000.ts
#EXT-X-PROGRAM-DATE-TIME:2022-10-12T20:08:25.447Z
#EXTINF:2.000000
segment-0000000001.ts
#EXT-X-PROGRAM-DATE-TIME:2022-10-12T20:08:27.447Z
#EXTINF:2.000000
segment-0000000002.ts
#EXT-X-PROGRAM-DATE-TIME:2022-10-12T20:08:29.447Z
#EXTINF:2.000000
segment-0000000003.ts
HLS MPEG-CENC/Widevine
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-DISCONTINUITY-SEQUENCE:0
#EXT-X-KEY:METHOD=SAMPLE-AES-CTR,URI="data:text/plain;base64,AAAAOHBzc2gAAAAA7e+LqXnWSs6jyCfSEAB3Gcrj/8kFtioyiVbJMh9I49yVmwY=",KEYFORMAT="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed",KEYFORMATVERSIONS="1"
#EXT-X-MAP:URI="segment-initialization_segment_0000000000.m4s"
#EXT-X-PROGRAM-DATE-TIME:2022-10-12T20:08:22.870Z
#EXTINF:2.576778
segment-0000000000.m4s
#EXT-X-PROGRAM-DATE-TIME:2022-10-12T20:08:25.447Z
#EXTINF:2.000000
segment-0000000001.m4s
#EXT-X-PROGRAM-DATE-TIME:2022-10-12T20:08:27.447Z
#EXTINF:2.000000
segment-0000000002.m4s
#EXT-X-PROGRAM-DATE-TIME:2022-10-12T20:08:29.447Z
#EXTINF:2.000000
segment-0000000003.m4s
DASH MPEG-CENC/Widevine
<AdaptationSet segmentAlignment="true" maxWidth="800" maxHeight="600">
<Representation mimeType="video/mp4" id="fmp4_widevine_cenc_video" codecs="avc1.4d001f">
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="44ec248b-048c-43a6-a6ee-58a752c6f9f8"/>
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed" value="Widevine">
<cenc:pssh>AAAAOHBzc2gAAAAA7e+LqXnWSs6jCfc1R0h7QAAABgSEAB3Gcrj/8kFklokiVbJMh9VmwY=</cenc:pssh>
</ContentProtection>
</Representation>
</AdaptationSet>
<AdaptationSet segmentAlignment="true" mimeType="audio/mp4" id="1" label="fmp4_widevine_cenc_audio">
<Representation id="fmp4_widevine_cenc_audio" codecs="mp4a.40.2">
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="44ec248b-048c-43a6-a6ee-58a752c6f9f8"/>
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed" value="Widevine">
<cenc:pssh>AAAAOHBzc2gAAAAA7e+LqXnWSs6jCfc1R0h7QAAABgSEAB3Gcrj/8kFklokiVbJMh9VmwY=</cenc:pssh>
</ContentProtection>
</Representation>
</AdaptationSet>
Jogadores recomendados
Os jogadores baseados em HLS.js
são recomendados
para a descriptografia HLS/TS. Jogadores baseados no
Shaka Player são recomendados
para a descriptografia DASH/fMP4.
O esquema "cenc" do PlayReady é compatível com máquinas físicas que executam o Windows 10 com o navegador Microsoft Edge, Xbox One (versão 1703 ou anterior) e alguns dispositivos que não são Windows (por exemplo, smart TVs). O esquema "cbcs" do PlayReady é compatível apenas com o Xbox One versão 1709 ou mais recente. Consulte Modos de criptografia de conteúdo PlayReady para mais informações.
Atualizar a chave de criptografia
Para mudar um canal para uma nova chave de criptografia, faça o seguinte: