1# 基于AVCodec播放DRM节目(C/C++) 2<!--Kit: Drm Kit--> 3<!--Subsystem: Multimedia--> 4<!--Owner: @qin_wei_jie--> 5<!--Designer: @chris2981--> 6<!--Tester: @xdlinc--> 7<!--Adviser: @zengyawen--> 8## 功能介绍 9 10开发者可以调用DRM Kit的Native API接口,完成DRM节目播放。 11 12当前支持的解密能力如下: 13 14| 音频容器规格 | 音频解密类型 | 15|----------|:-------| 16| mp4 | AAC | 17 18| 视频容器规格 | 视频解密类型 | 19|----------|:------------| 20| ts | AVC(H.264) | 21| mp4 | AVC(H.264) | 22<!--RP1--><!--RP1End--> 23 24**适用场景** 25 26在创建DRM之前,需获取到DRM信息(参考[媒体数据解析](../avcodec/audio-video-demuxer.md#开发步骤)开发步骤第4步)。 27 28## 开发指导 29 30详细的API说明请参考[DRM API](../../reference/apis-drm-kit/capi-drm.md)。 31 32参考以下示例代码,完成DRM的全流程,包括:获取设备支持的DRM解决方案的名称和唯一标识的列表、创建MediaKeySystem、创建MediaKeySession、生成媒体密钥请求、处理媒体密钥响应、获取是否需要安全视频解码以及销毁资源。 33 34在应用开发过程中,开发者应按一定顺序调用方法,执行对应操作,否则系统可能会抛出异常或生成其他未定义的行为。具体顺序可参考下列开发步骤及对应说明。 35 36### 在 CMake 脚本中链接动态库 37 38``` cmake 39target_link_libraries(sample PUBLIC libnative_drm.so) 40``` 41 42> **说明:** 43> 44> 上述'sample'字样仅为示例,此处由调用者根据实际工程目录自定义。 45> 46 47## 开发步骤 48 491. 导入DRM Kit接口。 50 51 ```c++ 52 #include "multimedia/drm_framework/native_drm_common.h" 53 #include "multimedia/drm_framework/native_drm_err.h" 54 #include "multimedia/drm_framework/native_mediakeysession.h" 55 #include "multimedia/drm_framework/native_mediakeysystem.h" 56 ``` 57 582. 获取设备支持的DRM解决方案名称和唯一标识的列表。 59 60 ```c++ 61 uint32_t count = 3; // count是当前设备实际支持的DRM插件的个数,用户根据实际情况设置。 62 DRM_MediaKeySystemDescription descriptions[3]; 63 memset(descriptions, 0, sizeof(descriptions)); 64 Drm_ErrCode ret = OH_MediaKeySystem_GetMediaKeySystems(descriptions, &count); 65 if (ret != DRM_ERR_OK) { 66 printf("OH_MediaKeySystem_GetMediaKeySystems failed."); 67 } 68 ``` 69 70 获取到设备支持的DRM解决方案的名称和唯一标识的列表后,同DRM信息做匹配,创建对应的DRM解决方案。DRM信息可通过[媒体数据解析](../avcodec/audio-video-demuxer.md#开发步骤)开发步骤第4步获取, 71 72 或者直接解析媒体协议或媒体数据得到DRM解决方案唯一标识及pssh数据以生成DRM信息。 73 743. 创建MediaKeySystem实例。 75 76 ```c++ 77 MediaKeySystem *mediaKeySystem = nullptr; 78 ret = OH_MediaKeySystem_Create("com.clearplay.drm", &mediaKeySystem); 79 if (ret != DRM_ERR_OK || mediaKeySystem == nullptr) { 80 printf("OH_MediaKeySystem_Create failed."); 81 } 82 ``` 83 844. 创建MediaKeySession实例。 85 86 ```c++ 87 MediaKeySession *mediaKeySession = nullptr; 88 DRM_ContentProtectionLevel contentProtectionLevel = CONTENT_PROTECTION_LEVEL_SW_CRYPTO; // 依据设备支持的内容保护级别设置。 89 ret = OH_MediaKeySystem_CreateMediaKeySession(mediaKeySystem, &contentProtectionLevel, &mediaKeySession); 90 if (ret != DRM_ERR_OK || mediaKeySession == nullptr) { 91 printf("OH_MediaKeySystem_CreateMediaKeySession failed."); 92 } 93 ``` 94 955. 查询是否需要安全解码。 96 97 ```c++ 98 bool requireSecureDecoder; 99 ret = OH_MediaKeySession_RequireSecureDecoderModule(mediaKeySession, "video/avc", &requireSecureDecoder); 100 if (ret != DRM_ERR_OK) { 101 printf("OH_MediaKeySession_RequireSecureDecoderModule failed."); 102 } 103 ``` 104 1056. 生成媒体密钥请求与处理媒体密钥响应。 106 107 ```c++ 108 #define MAX_DRM_MEDIA_KEY_RESPONSE_BUF_SIZE 24576 // 24576: (2 * 12 * 1024) 109 DRM_MediaKeyRequest mediaKeyRequest; 110 DRM_MediaKeyRequestInfo info; 111 // initData对应码流中的pssh数据,请按实际数据填入。 112 unsigned char initData[512] = {0x00}; 113 memset(&info, 0, sizeof(DRM_MediaKeyRequestInfo)); 114 info.initDataLen = sizeof(initData); 115 info.type = MEDIA_KEY_TYPE_ONLINE; // MEDIA_KEY_TYPE_ONLINE: 在线媒体密钥请求类型; MEDIA_KEY_TYPE_OFFLINE: 离线媒体密钥请求类型。 116 if (sizeof("video/mp4") <= sizeof(info.mimeType)) { 117 memcpy(info.mimeType, "video/mp4", sizeof("video/mp4")); 118 } 119 if (info.initDataLen <= sizeof(info.initData)) { 120 memcpy(info.initData, initData, info.initDataLen); 121 } 122 if (sizeof("optionalDataName") <= sizeof(info.optionName[0])) { 123 memcpy(info.optionName[0], "optionalDataName", sizeof("optionalDataName")); 124 } 125 126 if (sizeof("optionalDataValue") <= sizeof(info.optionData[0])) { 127 memcpy(info.optionData[0], "optionalDataValue", sizeof("optionalDataValue")); 128 } 129 info.optionsCount = 1; 130 ret = OH_MediaKeySession_GenerateMediaKeyRequest(mediaKeySession, &info, &mediaKeyRequest); 131 if (ret != DRM_ERR_OK) { 132 printf("OH_MediaKeySession_GenerateMediaKeyRequest failed."); 133 } 134 /* 135 应用通过网络请求DRM服务,获取媒体密钥响应mediaKeyResponse,将响应传到OH_MediaKeySession_ProcessMediaKeyResponse, 136 若是离线媒体密钥响应处理,则返回离线媒体密钥标识mediaKeyId,请根据实际的数据和长度传入。 137 */ 138 unsigned char mediaKeyId[128] = {0x00}; 139 int32_t mediaKeyIdLen = 128; 140 // 媒体密钥响应长度最大为MAX_DRM_MEDIA_KEY_RESPONSE_BUF_SIZE,请按实际数据输入。 141 unsigned char mediaKeyResponse[MAX_DRM_MEDIA_KEY_RESPONSE_BUF_SIZE] = {0x00}; 142 int32_t mediaKeyResponseLen = MAX_DRM_MEDIA_KEY_RESPONSE_BUF_SIZE; 143 ret = OH_MediaKeySession_ProcessMediaKeyResponse(mediaKeySession, mediaKeyResponse, 144 mediaKeyResponseLen, mediaKeyId, &mediaKeyIdLen); 145 if (ret != DRM_ERR_OK) { 146 printf("OH_MediaKeySession_ProcessMediaKeyResponse failed."); 147 } 148 ``` 149 150 根据需要设置音频解密配置(详见[音频解码开发指南开发步骤](../avcodec/audio-decoding.md#开发步骤)第4步)、设置视频解密配置(详见[视频解码开发指南开发步骤Surface模式](../avcodec/video-decoding.md#surface模式)第4步或[Buffer模式](../avcodec/video-decoding.md#buffer模式)第4步),实现DRM内容解密。 151 1527. 销毁MediaKeySession实例。 153 154 ```c++ 155 ret = OH_MediaKeySession_Destroy(mediaKeySession); 156 if (ret != DRM_ERR_OK) { 157 printf("OH_MediaKeySession_Destroy failed."); 158 } 159 ``` 160 1618. 销毁MediaKeySystem实例。 162 163 ```c++ 164 ret = OH_MediaKeySystem_Destroy(mediaKeySystem); 165 if (ret != DRM_ERR_OK) { 166 printf("OH_MediaKeySystem_Destroy failed."); 167 } 168 ``` 169