En esta página, se explica cómo encriptar el contenido de una transmisión en vivo. La API de Live Stream no crea ni administra claves de encriptación ni licencias directamente. En su lugar, debes usar un proveedor de administración de derechos digitales (DRM) de terceros para estas funciones. Después de crear las claves de encriptación para tu contenido multimedia, pásalas a la API de Live Stream con Secret Manager.
La configuración de encriptación se especifica en la configuración Channel
. Una vez que comienza la transmisión, la canalización de video de la API de Live Stream comienza a encriptar tu contenido. El manifiesto de salida incluye información necesaria para desencriptar el contenido dentro del reproductor multimedia que elijas.
Configuraciones admitidas
Protocolo de transmisión | Contenedor | Sistema DRM | Esquema de encriptación |
---|---|---|---|
HLS | TS | ClearKey | aes128 |
HLS | TS | ClearKey | sampleAes |
HLS | TS | FairPlay | sampleAes |
HLS | fMP4 | FairPlay | Solo cbcs de mpegCenc |
MPEG‐DASH | fMP4 | ClearKey | mpegCenc cenc o cbcs |
MPEG‐DASH | fMP4 | Widevine | mpegCenc cenc o cbcs |
HLS | fMP4 | Widevine | mpegCenc cenc o cbcs |
MPEG‐DASH | fMP4 | PlayReady | mpegCenc cenc o cbcs |
HLS | fMP4 | PlayReady | mpegCenc cenc o cbcs |
Agrega la clave de encriptación a Secret Manager
Antes de comenzar, crea tus claves de encriptación con el proveedor de DRM de terceros que prefieras.
La API de Live Stream requiere que tu secreto contenga la clave de encriptación en el siguiente formato JSON, junto con otra información necesaria.
Consulta la documentación del protocolo DRM para obtener una descripción de cada campo. Ten en cuenta que debes convertir el formato snake case a camel case para el formato JSON.
Ejemplo 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.
}
]
}
Si tu configuración de encriptación (por ejemplo, FairPlay) requiere un vector de inicialización explícito (IV), pero no está incluido, la API usará el valor de keyId
para el valor de iv
.
Para agregar tu clave de encriptación, realiza una de las siguientes acciones:
Agrega y configura claves de forma manual. Usa los datos JSON anteriores, agrega tu clave de encriptación a Secret Manager mediante los pasos que se indican en Crea un secreto.
Implementa un
key publisher
que obtenga las claves de encriptación necesarias y las escriba en Secret Manager como versiones de secretos. Consulta una implementación de muestra que se ejecuta como Cloud Functions.
Luego, sigue estos pasos para configurar tu clave de encriptación:
- Configura los permisos de IAM en tu secreto para que la API de Live Stream pueda acceder al contenido del secreto. Para ello, otorga la función
secretmanager.secretAccessor
a la cuenta de servicioservice-PROJECT_NUMBER@gcp-sa-livestream.iam.gserviceaccount.com
(esto es similar a cómo la cuenta de servicio tiene acceso a tus buckets de Cloud Storage). - Busca el nombre del recurso de la versión del secreto que creaste (por ejemplo,
projects/PROJECT_NUMBER/secrets/SECRET_ID/versions/VERSION_ID
). Necesitas este nombre para configurar el canal.
Configura el canal
La configuración de encriptación se especifica mediante objetos en el arreglo encryptions
en el nivel Channel
. Se asigna un identificador único (id
) a cada configuración diferente. Cada muxStream
usa un identificador para indicar qué configuración de encriptación usar, o bien omite ese campo para permanecer sin encriptar.
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.
}
Ejemplo (ClearKey)
En el siguiente ejemplo, se configuran muxStreams AES-128 y SAMPLE-AES en manifiestos HLS, y muxStreams MPEG-CENC (cenc y cbcs) en manifiestos de 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
}
]
Ejemplo (FP/PR/Widevine)
En el siguiente ejemplo, se configuran los muxStreams FairPlay/SAMPLE-AES, Widevine/MPEG-CENC (cenc y cbcs) y PlayReady/MPEG-CENC (cenc y cbcs). Los muxStreams Widevine y PlayReady se incluyen en los manifiestos de HLS y 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
}
]
Una vez que sepas qué configuración JSON deseas usar, crea un canal como de costumbre.
Inicia la transmisión
Una vez creado el canal, inicia el canal y envía el flujo de entrada.
Cuando se inicia el canal, la API de Live Stream recupera la clave de encriptación que identificó secretVersion
de Secret Manager. Si la API de Live Stream no puede recuperar la clave o la clave está en un formato irreconocible, el estado del canal será STREAMING_ERROR
. Si la clave se recupera correctamente, el estado del canal se vuelve AWAITING_INPUT
como de costumbre.
Una vez que comienza la transmisión, la API de Live Stream comienza a encriptar el contenido de salida según la configuración proporcionada en el momento de la creación.
Supervisa el resultado
Las transmisiones de salida encriptadas contienen manifiestos modificados con la información necesaria para desencriptar el contenido que se reproducirá.
Ejemplos de manifiestos
En los siguientes manifiestos, se muestra la información necesaria para desencriptar el contenido asociado.
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
AES DE MUESTRA DE HLS/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>
Jugadores recomendados
Se recomiendan los jugadores basados en HLS.js
para la desencriptación HLS/TS. Se recomiendan los jugadores basados en Shaka Player para la desencriptación DASH/fMP4.
El esquema "cenc" de PlayReady es compatible con máquinas físicas que ejecutan Windows 10 con el navegador Microsoft Edge, Xbox One (versión 1703 o anterior) y algunos dispositivos que no son de Windows (por ejemplo, smart TVs). El esquema "cbcs" de PlayReady solo es compatible con Xbox One versión 1709 o posterior. Para obtener más información, consulta Modos de encriptación de contenido de PlayReady.
Actualiza la clave de encriptación
Para cambiar un canal a una clave de encriptación nueva, haz lo siguiente: