☰
libva中的DRM模块
2026/10/23 4:03:48 网站建设 项目流程

主要内容

本文主要就libva中的DRM的流程进行简单说明,libva版本为libva-2.11.0(版本号为1.11.0),Digital Rights Management(DRM)指的是数字版权管理,用以保护具有版权的数字产品,包括视频,音乐,电子书等等。
关于Digital Rights Management(DRM)(数字版权管理)的基础内容,本文不做介绍,可以参考链接:
DRM基础介绍
AES加密原理
AES加密模式
RSA加密原理
数字签名和数字证书
X.509证书

目前常见的的DRM标准有以下几种:
PlayReady by Microsoft
FairPlay by Apple
Merlin by Sony
除此之外还有google的widewine

相关术语

DRM: Digital Rights Management, 数字版权管理
TEE: Trust Excute Environment,可信任执行环境
IHV: Independent Hardware Vendor,独立硬件厂商

相关接口和结构体

libva中的DRM接口从libva2.11引入,主要是在va_pro.h中。

VAProtectedSessionBuffer

typedef struct _VAProtectedSessionBuffer { //作为输入的buffer不使用该值,但是作为输出buffer,max_data_size可以输出driver所 //返回的输出buffer的数据量的最大值 uint32_t max_data_size; //作为输入bufferr使用,data_size指的是输入buffer的数据量大小 //作为输出bufferr使用,data_size指的是driver写入data的数据量大小 uint32_t data_size; //数据指针 void *data; //保留,未使用 uint32_t va_reserved[VA_PADDING_LOW]; } VAProtectedSessionBuffer;

VAProtectedSessionExecuteBuffer

typedef struct _VAProtectedSessionExecuteBuffer { //指定执行的功能,由IHV实现 uint32_t function_id; //输入buffer VAProtectedSessionBuffer input; //输出buffer VAProtectedSessionBuffer output; //返回函数执行结果,由IHV实现 uint32_t status; //保留,未使用 uint32_t va_reserved[VA_PADDING_LOW]; } VAProtectedSessionExecuteBuffer;

VAEncryptionSegmentInfo

typedef struct _VAEncryptionSegmentInfo { /** \brief The offset relative to the start of the bitstream input in * bytes of the start of the segment */ uint32_t segment_start_offset; /** \brief The length of the segments in bytes */ uint32_t segment_length; /** \brief The length in bytes of the remainder of an incomplete block * from a previous segment*/ uint32_t partial_aes_block_size; /** \brief The length in bytes of the initial clear data */ uint32_t init_byte_length; /** \brief This will be AES counter for secure decode and secure encode * when numSegments equals 1, valid size is specified by * \c key_blob_size */ uint8_t aes_cbc_iv_or_ctr[64]; /** \brief Reserved bytes for future use, must be zero */ uint32_t va_reserved[VA_PADDING_MEDIUM]; } VAEncryptionSegmentInfo;

VAEncryptionParameters

typedef struct _VAEncryptionParameters { /** \brief Encryption type, refer to \c VA_ENCRYPTION_TYPE_FULLSAMPLE_CTR, * \c VA_ENCRYPTION_TYPE_FULLSAMPLE_CBC, \c VA_ENCRYPTION_TYPE_SUBSAMPLE_CTR, * or \c VA_ENCRYPTION_TYPE_SUBSAMPLE_CBC */ uint32_t encryption_type; /** \brief The number of sengments */ uint32_t num_segments; /** \brief Pointer of segments */ VAEncryptionSegmentInfo *segment_info; /** \brief The status report index reserved for CENC fullsample workload. * The related structures and definitions are vendor specific. */ uint32_t status_report_index; /** \brief CENC counter length */ uint32_t size_of_length; /** \brief Wrapped decrypt blob (Snd)kb, valid size is specified by * \c key_blob_size */ uint8_t wrapped_decrypt_blob[64]; /** \brief Wrapped Key blob info (Sne)kb, valid size is specified by * \c key_blob_size */ uint8_t wrapped_encrypt_blob[64]; /** \brief key blob size * It could be \c VA_PC_BLOCK_SIZE_128, \c VA_PC_BLOCK_SIZE_192, or * \c VA_PC_BLOCK_SIZE_256 */ uint32_t key_blob_size; /** \brief Indicates the number of 16-byte BLOCKS that are encrypted in any * given encrypted region of segments. * If this value is zero: * 1. All bytes in encrypted region of segments are encrypted, i.e. the * CENC or CBC1 scheme is being used * 2. blocks_stripe_clear must also be zero. * If this value is non-zero, blocks_stripe_clear must also be non-zero. */ uint32_t blocks_stripe_encrypted; /** \brief Indicates the number of 16-byte BLOCKS that are clear in any given * encrypted region of segments, as defined by the CENS and CBCS schemes in * the common encryption spec. * If this value is zero, all bytes in encrypted region of segments are * encrypted, i.e. the CENC or CBC1 scheme is being used. */ uint32_t blocks_stripe_clear; /** \brief Reserved bytes for future use, must be zero */ uint32_t va_reserved[VA_PADDING_MEDIUM]; } VAEncryptionParameters;

配置

配置属性值其他
VAConfigAttribTEEType由厂商决定
VAConfigAttribTEETypeClient由厂商决定
VAConfigAttribProtectedContentCipherAlgorithmVA_PC_CIPHER_AES算法种类,目前只支持AES
VAConfigAttribProtectedContentCipherBlockSizeVA_PC_BLOCK_SIZE_128,VA_PC_BLOCK_SIZE_192,VA_PC_BLOCK_SIZE_256算法的大小,安全性越好,速度越慢
VAConfigAttribProtectedContentCipherModeVA_PC_CIPHER_MODE_ECB,VA_PC_CIPHER_MODE_CBC,VA_PC_CIPHER_MODE_CTRAES密钥模式,目前只支持三种
VAConfigAttribProtectedContentCipherSampleTypeVA_PC_SAMPLE_TYPE_FULLSAMPLE, VA_PC_SAMPLE_TYPE_SUBSAMPLE采样类型
VAConfigAttribProtectedContentUsageVA_PC_USAGE_DEFAULT, VA_PC_USAGE_WIDEVINE使用的DRM标准,默认或者widewine

API

API说明其他
vaCreateProtectedSession创建一个被保护的对话
vaDestroyProtectedSession销毁创建的对话
vaAttachProtectedSession附着对话到一个VA context中,使能加密保护
vaDetachProtectedSession游离context中附着的对话,失能加密保护
vaProtectedSessionExecute执行被保护的对话

使用流程

  1. 查询entrypoint是否支持Content protection
  2. 获取相关的配置属性
  3. 创建config对象
  4. 获取保护对话的buffer数据
  5. 附着session到相关的context上
  6. 按照正常的流程解码
  7. 游离context上的session
//查询相关的entrypoints VAEntrypoint entrypoints; int i, num_entrypoints, supportsProtectedContent = 0; num_entrypoints = vaMaxNumEntrypoints(); entrypoints = malloc(num_entrypoints sizeof(entrypoints[0]); vaQueryConfigEntrypoints(va_dpy, VAProfileProtected, entrypoints, &num_entrypoints); for (i = 0; !supportsProtectedContent && i < num_entrypoints; i++) { if (entrypoints[i] == VAEntrypointProtectedContent) supportsProtectedContent = 1; } //获取配置属性 VAConfigAttrib attribs; //获取密钥算法类型 attribs[0].type = VAConfigAttribProtectedContentCipherAlgorithm; //获取密钥算发支持的块的尺寸 attribs[1].type = VAConfigAttribProtectedContentCipherBlockSize; //获取密钥算法模式 attribs[2].type = VAConfigAttribProtectedContentCipherMode; //获取密钥采样类型 attribs[3].type = VAConfigAttribProtectedContentCipherSampleType; //获取使用DRM标准 attribs[4].type = VAConfigAttribProtectedContentUsage; vaGetConfigAttributes(va_dpy, VAProfileProtected, VAEntrypointProtectedContent, attribs, 5); if ((attribs[1].value & VA_PC_CIPHER_AES) == 0) { // not find desired cipher algorithm assert(0); } if ((attribs[2].value & VA_PC_BLOCK_SIZE_128) == 0) { // not find desired block size assert(0); } if ((attribs[3].value & VA_PC_CIPHER_MODE_CBC) == 0) { // not find desired counter mode assert(0); } if ((attribs[4].value & VA_PC_SAMPLE_TYPE_SUBSAMPLE) == 0) { // not find desired sample type assert(0); } if ((attribs[5].value & VA_PC_USAGE_WIDEVINE) == 0) { // not find desired usage assert(0); } //创建配置对象 VAConfigID config_id; attribs[0].value = VA_PC_CIPHER_AES; attribs[1].value = VA_PC_BLOCK_SIZE_128; attribs[2].value = VA_PC_CIPHER_MODE_CBC; attribs[3].value = VA_PC_SAMPLE_TYPE_SUBSAMPLE; attribs[4].value = VA_PC_USAGE_WIDEVINE; va_status = vaCreateConfig(va_dpy, VAProfileProtected, VAEntrypointProtectedContent, attribs, 5, &config_id); CHECK_VASTATUS(va_status, "vaCreateConfig"); //创建VAProtectedSessionExecuteBuffer 对象 uint32_t app_id = 0xFF; VABufferID buffer; VAProtectedSessionExecuteBuffer exec_buff = {0}; //GET_SESSION_ID只是函数的一种,driver实现的功能由IHV决定,可以实现很多功能 //指定不同的function_id来访问不同的功能 exec_buff.function_id = GET_SESSION_ID; exec_buff.input.data = nullptr; exec_buff.input.data_size = 0; exec_buff.output.data = &app_id; exec_buff.output.max_data_size = sizeof(app_id); va_status = vaCreateBuffer( va_dpy, crypto_session, (VABufferType) VAProtectedSessionExecuteBufferType, sizeof(exec_buff), 1, &exec_buff, &buffer); //执行对话sesson,传入或者获取数据,如content key va_status = vaProtectedSessionExecute(va_dpy, crypto_session, buffer); vaDestroyBuffer(va_dpy, buffer); //附着对话到session上 vaAttachProtectedSession(va_dpy, decode_ctx, crypto_session); foreach (iteration) { vaBeginPicture(va_dpy, decode_ctx, surface); ... vaRenderPicture(va_dpy, decode_ctx, &buf_id1, 1); vaRenderPicture(va_dpy, decode_ctx, &buf_id2, 1); // Buffer holding encryption parameters, i.e. VAEncryptionParameterBufferType buffer vaRenderPicture(va_dpy, decode_ctx, &buf_id_enc_param, 1); ... vaEndPicture(va_dpy, decode_ctx); } //游离context的对话 vaDetachProtectedSession(va_dpy, decode_ctx); foreach (iteration) { if (encrypted) vaAttachProtectedSession(va_dpy, decode_ctx, crypto_session); vaBeginPicture(va_dpy, decode_ctx, surface); ... vaRenderPicture(va_dpy, decode_ctx, &buf_id1, 1); vaRenderPicture(va_dpy, decode_ctx, &buf_id2, 1); // Buffer holding encryption parameters, i.e. VAEncryptionParameterBufferType buffer vaRenderPicture(va_dpy, decode_ctx, &buf_id_enc_param, 1); ... vaEndPicture(va_dpy, decode_ctx); if (encrypted) vaDetachProtectedSession(va_dpy, decode_ctx); // check encrypted variable for next frame }

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询