Criptografar uma transmissão ao vivo

Nesta página, explicamos como criptografar o conteúdo da transmissão ao vivo. O A API Live Stream não cria nem gerencia chaves de criptografia ou licenças diretamente. Em vez disso, use um provedor de gerenciamento de direitos digitais (DRM) de terceiros para esses recursos. Depois de criar as chaves de criptografia mídia, transmita essas chaves para a API Live Stream usando Secret Manager

As configurações de criptografia são especificadas no Channel configurações. Quando a transmissão começa, o pipeline de vídeo da API Live Stream começa a criptografar seu conteúdo. O manifesto de saída inclui informações necessárias para descriptografar o conteúdo no player de mídia de sua escolha.

Configurações aceitas

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 as chaves de criptografia usando o provedor de DRM de terceiros de sua preferência.

A API Live Stream exige que o segredo contenha a chave de criptografia no formato JSON abaixo, além de outras informações necessárias.

Consulte a documentação do protocolo DRM para conferir uma descrição de cada campo. Você precisa converter do Snake Case em letras concatenadas para o 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 sua configuração de criptografia (por exemplo, FairPlay) exigir uma de inicialização (IV), mas não estiver incluído, a API usará o valor de keyId para o valor de iv.

Para adicionar sua chave de criptografia, siga um destes procedimentos:

Em seguida, faça o seguinte para configurar a chave de criptografia:

  1. Configure as permissões do IAM no secret para que a API Live Stream possa acessar o conteúdo secreto. Para isso, conceda o papel secretmanager.secretAccessor à conta de serviço service-PROJECT_NUMBER@gcp-sa-livestream.iam.gserviceaccount.com, de forma semelhante ao acesso da conta de serviço aos seus buckets do Cloud Storage.
  2. Encontre o nome do recurso da versão do secret que você criou (por exemplo, projects/PROJECT_NUMBER/secrets/SECRET_ID/versions/VERSION_ID). Você precisa desse nome para configurar o canal.

Configurar o canal

As configurações de criptografia são especificadas usando 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 que ele permaneça sem criptografia.

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 SAMPLE-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": [
  {
    "key": "manifest_aes128_hls",
    "fileName": "manifest_aes128.m3u8",
    "type": "HLS",
    "muxStreams": ["ts_aes128"],
    "maxSegmentCount": 10
  },
  {
    "key": "manifest_sampleaes_hls",
    "fileName": "manifest_sampleaes.m3u8",
    "type": "HLS",
    "muxStreams": ["ts_sampleaes"],
    "maxSegmentCount": 10
  },
  {
    "key": "manifest_cenc_dash",
    "fileName": "manifest_cenc.mpd",
    "type": "DASH",
    "muxStreams": ["fmp4_cenc_video", "fmp4_cenc_audio"],
    "maxSegmentCount": 10
  },
  {
    "key": "manifest_cbcs_dash",
    "fileName": "manifest_cbcs.mpd",
    "type": "DASH",
    "muxStreams": ["fmp4_cbcs_video", "fmp4_cbcs_audio"],
    "maxSegmentCount": 10
  }
]

Exemplo (FP/PR/Widevine)

O exemplo a seguir configura FairPlay/SAMPLE-AES, Widevine/MPEG-CENC (cenc e cbcs) e os muxStreams PlayReady/MPEG-CENC (cenc e cbcs. Os muxStreams Widevine e PlayReady estão incluídos em HLS e DASH manifestos.

"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": [
  {
    "key": "manifest_fairplay_hls",
    "fileName": "manifest_fairplay.m3u8",
    "type": "HLS",
    "muxStreams": ["ts_fairplay"],
    "maxSegmentCount": 10
  },
  {
    "key": "manifest_widevine_cenc_hls",
    "fileName": "manifest_widevine_cenc.m3u8",
    "type": "HLS",
    "muxStreams": ["fmp4_widevine_cenc_video", "fmp4_widevine_cenc_audio"],
    "maxSegmentCount": 10
  },
  {
    "key": "manifest_widevine_cbcs_hls",
    "fileName": "manifest_widevine_cbcs.m3u8",
    "type": "HLS",
    "muxStreams": ["fmp4_widevine_cbcs_video", "fmp4_widevine_cbcs_audio"],
    "maxSegmentCount": 10
  },
  {
    "key": "manifest_widevine_cenc_dash",
    "fileName": "manifest_widevine_cenc.mpd",
    "type": "DASH",
    "muxStreams": ["fmp4_widevine_cenc_video", "fmp4_widevine_cenc_audio"],
    "maxSegmentCount": 10
  },
  {
    "key": "manifest_widevine_cbcs_dash",
    "fileName": "manifest_widevine_cbcs.mpd",
    "type": "DASH",
    "muxStreams": ["fmp4_widevine_cbcs_video", "fmp4_widevine_cbcs_audio"],
    "maxSegmentCount": 10
  },
  {
    "key": "manifest_playready_cenc_hls",
    "fileName": "manifest_playready_cenc.m3u8",
    "type": "HLS",
    "muxStreams": ["fmp4_playready_cenc_video", "fmp4_playready_cenc_audio"],
    "maxSegmentCount": 10
  },
  {
    "key": "manifest_playready_cbcs_hls",
    "fileName": "manifest_playready_cbcs.m3u8",
    "type": "HLS",
    "muxStreams": ["fmp4_playready_cbcs_video", "fmp4_playready_cbcs_audio"],
    "maxSegmentCount": 10
  },
  {
    "key": "manifest_playready_cenc_dash",
    "fileName": "manifest_playready_cenc.mpd",
    "type": "DASH",
    "muxStreams": ["fmp4_playready_cenc_video", "fmp4_playready_cenc_audio"],
    "maxSegmentCount": 10
  },
  {
    "key": "manifest_playready_cbcs_dash",
    "fileName": "manifest_playready_cbcs.mpd",
    "type": "DASH",
    "muxStreams": ["fmp4_playready_cbcs_video", "fmp4_playready_cbcs_audio"],
    "maxSegmentCount": 10
  }
]

Depois de saber a configuração JSON que quer usar, criar um canal como normais.

Iniciar streaming

Depois que o canal for criado, inicie-o e envie o stream de entrada.

Quando o canal é iniciado, 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 se ela estiver em um formato não reconhecido, o estado do canal vai ser STREAMING_ERROR. Se a chave for buscada com sucesso, o estado do canal vai se tornar AWAITING_INPUT como de costume.

Quando o streaming começa, a API Live Stream começa a criptografar a saída conteúdo 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 SAMPLE-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>

Recomendamos players baseados em HLS.js para descriptografia HLS/TS. Jogadores baseados em Recomendamos o Shaka Player. para descriptografia DASH/fMP4.

O esquema "cenc" do PlayReady tem suporte em máquinas físicas com o Windows 10 e o navegador Microsoft Edge, Xbox One (versão 1703 ou anterior) e alguns dispositivos que não são do Windows (por exemplo, smart TVs). O esquema "cbcs" do PlayReady só é compatível com o Xbox One versão 1709 ou mais recente. Consulte Modos de criptografia de conteúdo 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:

  1. Interrompa o canal.
  2. Atualize as configurações de criptografia no canal.
  3. Iniciar o canal.