• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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