1e41f4b71Sopenharmony_ci# Video Decoding 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ciYou can call the native APIs provided by the VideoDecoder module to decode video, that is, to decode media data into a YUV file or render it. 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ci<!--RP3--><!--RP3End--> 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ciCurrently, the following decoding capabilities are supported: 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci| Video Hardware Decoding Type | Video Software Decoding Type | 10e41f4b71Sopenharmony_ci| --------------------- | ---------------- | 11e41f4b71Sopenharmony_ci| AVC (H.264) and HEVC (H.265)|AVC (H.264) and HEVC (H.265)| 12e41f4b71Sopenharmony_ci 13e41f4b71Sopenharmony_ciVideo software decoding and hardware decoding are different. When a decoder is created based on the MIME type, only H.264 (OH_AVCODEC_MIMETYPE_VIDEO_AVC) is supported for software decoding, and H.264 (OH_AVCODEC_MIMETYPE_VIDEO_AVC) and H.265 (OH_AVCODEC_MIMETYPE_VIDEO_HEVC) are supported for hardware decoding. 14e41f4b71Sopenharmony_ci 15e41f4b71Sopenharmony_ciYou can perform a [capability query](obtain-supported-codecs.md) to obtain the decoding capability range. 16e41f4b71Sopenharmony_ci 17e41f4b71Sopenharmony_ci<!--RP1--><!--RP1End--> 18e41f4b71Sopenharmony_ci 19e41f4b71Sopenharmony_ciThrough the VideoDecoder module, your application can implement the following key capabilities. 20e41f4b71Sopenharmony_ci 21e41f4b71Sopenharmony_ci| Capability | How to Configure | 22e41f4b71Sopenharmony_ci| --------------------------------------- | ---------------------------------------------------------------------------------- | 23e41f4b71Sopenharmony_ci| Variable resolution | The decoder supports the change of the input stream resolution. After the resolution is changed, the callback function **OnStreamChanged()** set by **OH_VideoDecoder_RegisterCallback** is triggered. For details, see step 4 in surface mode or step 3 in buffer mode. | 24e41f4b71Sopenharmony_ci| Dynamic surface switching | Call **OH_VideoDecoder_SetSurface** to configure this capability. It is supported only in surface mode. For details, see step 7 in surface mode. | 25e41f4b71Sopenharmony_ci| Low-latency decoding | Call **OH_VideoDecoder_Configure** to configure this capability. For details, see step 6 in surface mode or step 5 in buffer mode. | 26e41f4b71Sopenharmony_ci 27e41f4b71Sopenharmony_ci 28e41f4b71Sopenharmony_ci## Restrictions 29e41f4b71Sopenharmony_ci- The buffer mode does not support 10-bit image data. 30e41f4b71Sopenharmony_ci- After **flush()**, **reset()**, or **stop()** is called, the PPS/SPS must be transferred again in the **start()** call. For details about the example, see step 14 in [Surface Output](#surface-output). 31e41f4b71Sopenharmony_ci- Due to limited hardware decoder resources, you must call **OH_VideoDecoder_Destroy** to destroy every decoder instance when it is no longer needed. 32e41f4b71Sopenharmony_ci- The input streams for video decoding support only the AnnexB format, and the supported AnnexB format supports multiple slices. However, the slices of the same frame must be sent to the decoder at a time. 33e41f4b71Sopenharmony_ci- When **flush()**, **reset()**, or **stop()** is called, do not continue to operate the OH_AVBuffer obtained through the previous callback function. 34e41f4b71Sopenharmony_ci- The DRM decryption capability supports both non-secure and secure video channels in [surface mode](#surface-output), but only non-secure video channels in buffer mode (#buffer-output). 35e41f4b71Sopenharmony_ci- The buffer mode and surface mode use the same APIs. Therefore, the surface mode is described as an example. 36e41f4b71Sopenharmony_ci- In buffer mode, after obtaining the pointer to an OH_AVBuffer object through the callback function **OH_AVCodecOnNewOutputBuffer**, call **OH_VideoDecoder_FreeOutputBuffer** to notify the system that the buffer has been fully utilized. In this way, the system can write the subsequently decoded data to the corresponding location. If the OH_NativeBuffer object is obtained through **OH_AVBuffer_GetNativeBuffer** and its lifecycle extends beyond that of the OH_AVBuffer pointer object, you mut perform data duplication. In this case, you should manage the lifecycle of the newly generated OH_NativeBuffer object to ensure that the object can be correctly used and released. 37e41f4b71Sopenharmony_ci 38e41f4b71Sopenharmony_ci## Surface Output and Buffer Output 39e41f4b71Sopenharmony_ci 40e41f4b71Sopenharmony_ci- Surface output and buffer output differ in data output modes. 41e41f4b71Sopenharmony_ci- They are applicable to different scenarios. 42e41f4b71Sopenharmony_ci - Surface output indicates that the OHNativeWindow is used to transfer output data. It supports connection with other modules, such as the **XComponent**. 43e41f4b71Sopenharmony_ci - Buffer output indicates that decoded data is output in shared memory mode. 44e41f4b71Sopenharmony_ci 45e41f4b71Sopenharmony_ci- The two also differ slightly in the API calling modes: 46e41f4b71Sopenharmony_ci- In surface mode, the caller can choose to call **OH_VideoDecoder_FreeOutputBuffer** to free the output buffer (without rendering the data). In buffer mode, the caller must call **OH_VideoDecoder_FreeOutputBuffer** to free the output buffer. 47e41f4b71Sopenharmony_ci- In surface mode, the caller must call **OH_VideoDecoder_SetSurface** to set an OHNativeWindow before the decoder is ready and call **OH_VideoDecoder_RenderOutputBuffer** to render the decoded data after the decoder is started. 48e41f4b71Sopenharmony_ci - In buffer mode, an application can obtain the shared memory address and data from the output buffer. In surface mode, an application can obtain the data from the output buffer. 49e41f4b71Sopenharmony_ci 50e41f4b71Sopenharmony_ciFor details about the development procedure, see [Surface Output](#surface-output) and [Buffer Output](#buffer-output). 51e41f4b71Sopenharmony_ci 52e41f4b71Sopenharmony_ci## State Machine Interaction 53e41f4b71Sopenharmony_ciThe following figure shows the interaction between states. 54e41f4b71Sopenharmony_ci 55e41f4b71Sopenharmony_ci 56e41f4b71Sopenharmony_ci 57e41f4b71Sopenharmony_ci 58e41f4b71Sopenharmony_ci1. A decoder enters the Initialized state in either of the following ways: 59e41f4b71Sopenharmony_ci - When a decoder instance is initially created, the decoder enters the Initialized state. 60e41f4b71Sopenharmony_ci - When **OH_VideoDecoder_Reset** is called in any state, the decoder returns to the Initialized state. 61e41f4b71Sopenharmony_ci 62e41f4b71Sopenharmony_ci2. When the decoder is in the Initialized state, you can call **OH_VideoDecoder_Configure** to configure the decoder. After the configuration, the decoder enters the Configured state. 63e41f4b71Sopenharmony_ci3. When the decoder is in the Configured state, you can call **OH_VideoDecoder_Prepare** to switch it to the Prepared state. 64e41f4b71Sopenharmony_ci4. When the decoder is in the Prepared state, you can call **OH_VideoDecoder_Start** to switch it to the Executing state. 65e41f4b71Sopenharmony_ci - When the decoder is in the Executing state, you can call **OH_VideoDecoder_Stop** to switch it back to the Prepared state. 66e41f4b71Sopenharmony_ci 67e41f4b71Sopenharmony_ci5. In rare cases, the decoder may encounter an error and enter the Error state. If this is the case, an invalid value can be returned or an exception can be thrown through a queue operation. 68e41f4b71Sopenharmony_ci - When the decoder is in the Error state, you can either call **OH_VideoDecoder_Reset** to switch it to the Initialized state or call **OH_VideoDecoder_Destroy** to switch it to the Released state. 69e41f4b71Sopenharmony_ci 70e41f4b71Sopenharmony_ci6. The Executing state has three substates: Flushed, Running, and End-of-Stream. 71e41f4b71Sopenharmony_ci - After **OH_VideoDecoder_Start** is called, the decoder enters the Running substate immediately. 72e41f4b71Sopenharmony_ci - When the decoder is in the Executing state, you can call **OH_VideoDecoder_Flush** to switch it to the Flushed substate. 73e41f4b71Sopenharmony_ci - After all data to be processed is transferred to the decoder, the **AVCODEC_BUFFER_FLAGS_EOS** flag is added to the last input buffer in the input buffers queue. Once this flag is detected, the decoder transits to the End-of-Stream substate. In this state, the decoder does not accept new inputs, but continues to generate outputs until it reaches the tail frame. 74e41f4b71Sopenharmony_ci 75e41f4b71Sopenharmony_ci7. When the decoder is no longer needed, you must call **OH_VideoDecoder_Destroy** to destroy the decoder instance. Then the decoder enters the Released state. 76e41f4b71Sopenharmony_ci 77e41f4b71Sopenharmony_ci## How to Develop 78e41f4b71Sopenharmony_ci 79e41f4b71Sopenharmony_ciRead [VideoDecoder](../../reference/apis-avcodec-kit/_video_decoder.md) for the API reference. 80e41f4b71Sopenharmony_ci 81e41f4b71Sopenharmony_ciThe figure below shows the call relationship of video decoding. 82e41f4b71Sopenharmony_ci 83e41f4b71Sopenharmony_ci- The dotted line indicates an optional operation. 84e41f4b71Sopenharmony_ci 85e41f4b71Sopenharmony_ci- The solid line indicates a mandatory operation. 86e41f4b71Sopenharmony_ci 87e41f4b71Sopenharmony_ci 88e41f4b71Sopenharmony_ci 89e41f4b71Sopenharmony_ci### Linking the Dynamic Link Libraries in the CMake Script 90e41f4b71Sopenharmony_ci 91e41f4b71Sopenharmony_ci``` cmake 92e41f4b71Sopenharmony_citarget_link_libraries(sample PUBLIC libnative_media_codecbase.so) 93e41f4b71Sopenharmony_citarget_link_libraries(sample PUBLIC libnative_media_core.so) 94e41f4b71Sopenharmony_citarget_link_libraries(sample PUBLIC libnative_media_vdec.so) 95e41f4b71Sopenharmony_ci``` 96e41f4b71Sopenharmony_ci> **NOTE** 97e41f4b71Sopenharmony_ci> 98e41f4b71Sopenharmony_ci> The word 'sample' in the preceding code snippet is only an example. Use the actual project directory name. 99e41f4b71Sopenharmony_ci> 100e41f4b71Sopenharmony_ci 101e41f4b71Sopenharmony_ci### Surface Output 102e41f4b71Sopenharmony_ci 103e41f4b71Sopenharmony_ciThe following walks you through how to implement the entire video decoding process in surface mode. In this example, an H.264 stream file is input, decoded, and rendered. 104e41f4b71Sopenharmony_ci 105e41f4b71Sopenharmony_ciCurrently, the VideoDecoder module supports only data rotation in asynchronous mode. 106e41f4b71Sopenharmony_ci 107e41f4b71Sopenharmony_ci1. Add the header files. 108e41f4b71Sopenharmony_ci 109e41f4b71Sopenharmony_ci ```c++ 110e41f4b71Sopenharmony_ci #include <multimedia/player_framework/native_avcodec_videodecoder.h> 111e41f4b71Sopenharmony_ci #include <multimedia/player_framework/native_avcapability.h> 112e41f4b71Sopenharmony_ci #include <multimedia/player_framework/native_avcodec_base.h> 113e41f4b71Sopenharmony_ci #include <multimedia/player_framework/native_avformat.h> 114e41f4b71Sopenharmony_ci #include <multimedia/player_framework/native_avbuffer.h> 115e41f4b71Sopenharmony_ci #include <fstream> 116e41f4b71Sopenharmony_ci ``` 117e41f4b71Sopenharmony_ci2. Configure global variables. 118e41f4b71Sopenharmony_ci 119e41f4b71Sopenharmony_ci ```c++ 120e41f4b71Sopenharmony_ci // (Mandatory) Configure the video frame width. 121e41f4b71Sopenharmony_ci int32_t width = 320; 122e41f4b71Sopenharmony_ci // (Mandatory) Configure the video frame height. 123e41f4b71Sopenharmony_ci int32_t height = 240; 124e41f4b71Sopenharmony_ci // Configure the video pixel format. 125e41f4b71Sopenharmony_ci constexpr OH_AVPixelFormat DEFAULT_PIXELFORMAT = AV_PIXEL_FORMAT_NV12; 126e41f4b71Sopenharmony_ci int32_t widthStride = 0; 127e41f4b71Sopenharmony_ci int32_t heightStride = 0; 128e41f4b71Sopenharmony_ci ``` 129e41f4b71Sopenharmony_ci 130e41f4b71Sopenharmony_ci3. Create a decoder instance. 131e41f4b71Sopenharmony_ci 132e41f4b71Sopenharmony_ci You can create a decoder by name or MIME type. In the code snippet below, the following variables are used: 133e41f4b71Sopenharmony_ci 134e41f4b71Sopenharmony_ci - **videoDec**: pointer to the video decoder instance. 135e41f4b71Sopenharmony_ci - **capability**: pointer to the decoder's capability. 136e41f4b71Sopenharmony_ci - **OH_AVCODEC_MIMETYPE_VIDEO_AVC**: AVC video codec. 137e41f4b71Sopenharmony_ci 138e41f4b71Sopenharmony_ci ```c++ 139e41f4b71Sopenharmony_ci // To create a decoder by name, call OH_AVCapability_GetName to obtain the codec names available and then call OH_VideoDecoder_CreateByName. If your application has special requirements, for example, expecting a decoder that supports a certain resolution, you can call OH_AVCodec_GetCapability to query the capability first. 140e41f4b71Sopenharmony_ci OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, false); 141e41f4b71Sopenharmony_ci // Create hardware decoder instances. 142e41f4b71Sopenharmony_ci OH_AVCapability *capability= OH_AVCodec_GetCapabilityByCategory(OH_AVCODEC_MIMETYPE_VIDEO_AVC, false, HARDWARE); 143e41f4b71Sopenharmony_ci const char *name = OH_AVCapability_GetName(capability); 144e41f4b71Sopenharmony_ci OH_AVCodec *videoDec = OH_VideoDecoder_CreateByName(name); 145e41f4b71Sopenharmony_ci ``` 146e41f4b71Sopenharmony_ci 147e41f4b71Sopenharmony_ci ```c++ 148e41f4b71Sopenharmony_ci // Create a decoder by MIME type. Only specific codecs recommended by the system can be created in this way. 149e41f4b71Sopenharmony_ci // If multiple codecs need to be created, create hardware decoder instances first. If the hardware resources are insufficient, create software decoder instances. 150e41f4b71Sopenharmony_ci // Create an H.264 decoder for software/hardware decoding. 151e41f4b71Sopenharmony_ci OH_AVCodec *videoDec = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC); 152e41f4b71Sopenharmony_ci // Create an H.265 decoder for software/hardware decoding. 153e41f4b71Sopenharmony_ci OH_AVCodec *videoDec = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC); 154e41f4b71Sopenharmony_ci ``` 155e41f4b71Sopenharmony_ci 156e41f4b71Sopenharmony_ci4. Call **OH_VideoDecoder_RegisterCallback()** to register the callback functions. 157e41f4b71Sopenharmony_ci 158e41f4b71Sopenharmony_ci Register the **OH_AVCodecCallback** struct that defines the following callback function pointers: 159e41f4b71Sopenharmony_ci 160e41f4b71Sopenharmony_ci - **OH_AVCodecOnError**, a callback used to report a codec operation error. For details about the error codes, see [OH_AVCodecOnError](../../reference/apis-avcodec-kit/_codec_base.md#oh_avcodeconerror). 161e41f4b71Sopenharmony_ci - **OH_AVCodecOnStreamChanged**, a callback used to report a codec stream change, for example, stream width or height change. 162e41f4b71Sopenharmony_ci - **OH_AVCodecOnNeedInputBuffer**, a callback used to report input data required, which means that the decoder is ready for receiving data. 163e41f4b71Sopenharmony_ci - **OH_AVCodecOnNewOutputBuffer**, a callback used to report output data generated, which means that decoding is complete. (Note: The **buffer** parameter in surface mode is null.) 164e41f4b71Sopenharmony_ci 165e41f4b71Sopenharmony_ci You need to process the callback functions to ensure that the decoder runs properly. 166e41f4b71Sopenharmony_ci 167e41f4b71Sopenharmony_ci <!--RP2--><!--RP2End--> 168e41f4b71Sopenharmony_ci 169e41f4b71Sopenharmony_ci ```c++ 170e41f4b71Sopenharmony_ci // Implement the OH_AVCodecOnError callback function. 171e41f4b71Sopenharmony_ci static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) 172e41f4b71Sopenharmony_ci { 173e41f4b71Sopenharmony_ci // Process the error code in the callback. 174e41f4b71Sopenharmony_ci (void)codec; 175e41f4b71Sopenharmony_ci (void)errorCode; 176e41f4b71Sopenharmony_ci (void)userData; 177e41f4b71Sopenharmony_ci } 178e41f4b71Sopenharmony_ci 179e41f4b71Sopenharmony_ci // Implement the OH_AVCodecOnStreamChanged callback function. 180e41f4b71Sopenharmony_ci static void OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) 181e41f4b71Sopenharmony_ci { 182e41f4b71Sopenharmony_ci // The changed video width, height, and stride can be obtained through format. 183e41f4b71Sopenharmony_ci (void)codec; 184e41f4b71Sopenharmony_ci (void)userData; 185e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_WIDTH, &width); 186e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_HEIGHT, &height); 187e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_STRIDE, &widthStride); 188e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_SLICE_HEIGHT, &heightStride); 189e41f4b71Sopenharmony_ci } 190e41f4b71Sopenharmony_ci 191e41f4b71Sopenharmony_ci // Implement the OH_AVCodecOnNeedInputBuffer callback function. 192e41f4b71Sopenharmony_ci static void OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) 193e41f4b71Sopenharmony_ci { 194e41f4b71Sopenharmony_ci // The index of the input frame buffer is sent to InIndexQueue. 195e41f4b71Sopenharmony_ci // The input frame data (specified by buffer) is sent to InBufferQueue. 196e41f4b71Sopenharmony_ci // Process the data. 197e41f4b71Sopenharmony_ci // Write the stream to decode. 198e41f4b71Sopenharmony_ci } 199e41f4b71Sopenharmony_ci 200e41f4b71Sopenharmony_ci // Implement the OH_AVCodecOnNewOutputBuffer callback function. 201e41f4b71Sopenharmony_ci static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) 202e41f4b71Sopenharmony_ci { 203e41f4b71Sopenharmony_ci // The index of the output frame buffer is sent to outIndexQueue. 204e41f4b71Sopenharmony_ci // The output frame data (specified by buffer) is sent to outBufferQueue. 205e41f4b71Sopenharmony_ci // Process the data. 206e41f4b71Sopenharmony_ci // Display and release decoded frames. 207e41f4b71Sopenharmony_ci } 208e41f4b71Sopenharmony_ci // Call OH_VideoDecoder_RegisterCallback() to register the callback functions. 209e41f4b71Sopenharmony_ci OH_AVCodecCallback cb = {&OnError, &OnStreamChanged, &OnNeedInputBuffer, &OnNewOutputBuffer}; 210e41f4b71Sopenharmony_ci // Set the asynchronous callbacks. 211e41f4b71Sopenharmony_ci int32_t ret = OH_VideoDecoder_RegisterCallback(videoDec, cb, NULL); // NULL: userData is null. 212e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 213e41f4b71Sopenharmony_ci // Exception handling. 214e41f4b71Sopenharmony_ci } 215e41f4b71Sopenharmony_ci ``` 216e41f4b71Sopenharmony_ci > **NOTE** 217e41f4b71Sopenharmony_ci > 218e41f4b71Sopenharmony_ci > In the callback functions, pay attention to multi-thread synchronization for operations on the data queue. 219e41f4b71Sopenharmony_ci > 220e41f4b71Sopenharmony_ci 221e41f4b71Sopenharmony_ci5. (Optional) Call **OH_VideoDecoder_SetDecryptionConfig** to set the decryption configuration. Call this API after the media key system information is obtained and a media key is obtained but before **Prepare()** is called. For details about how to obtain such information, see step 3 in [Audio and Video Demuxing](audio-video-demuxer.md). In surface mode, the DRM decryption capability supports both secure and non-secure video channels. For details about DRM APIs, see [DRM](../../reference/apis-drm-kit/_drm.md). 222e41f4b71Sopenharmony_ci 223e41f4b71Sopenharmony_ci Add the header files. 224e41f4b71Sopenharmony_ci 225e41f4b71Sopenharmony_ci ```c++ 226e41f4b71Sopenharmony_ci #include <multimedia/drm_framework/native_mediakeysystem.h> 227e41f4b71Sopenharmony_ci #include <multimedia/drm_framework/native_mediakeysession.h> 228e41f4b71Sopenharmony_ci #include <multimedia/drm_framework/native_drm_err.h> 229e41f4b71Sopenharmony_ci #include <multimedia/drm_framework/native_drm_common.h> 230e41f4b71Sopenharmony_ci ``` 231e41f4b71Sopenharmony_ci Linking the Dynamic Libraries in the CMake Script 232e41f4b71Sopenharmony_ci 233e41f4b71Sopenharmony_ci ``` cmake 234e41f4b71Sopenharmony_ci target_link_libraries(sample PUBLIC libnative_drm.so) 235e41f4b71Sopenharmony_ci ``` 236e41f4b71Sopenharmony_ci 237e41f4b71Sopenharmony_ci <!--RP4-->The following is the sample code:<!--RP4End--> 238e41f4b71Sopenharmony_ci 239e41f4b71Sopenharmony_ci ```c++ 240e41f4b71Sopenharmony_ci // Create a media key system based on the media key system information. The following uses com.clearplay.drm as an example. 241e41f4b71Sopenharmony_ci MediaKeySystem *system = nullptr; 242e41f4b71Sopenharmony_ci int32_t ret = OH_MediaKeySystem_Create("com.clearplay.drm", &system); 243e41f4b71Sopenharmony_ci if (system == nullptr) { 244e41f4b71Sopenharmony_ci printf("create media key system failed"); 245e41f4b71Sopenharmony_ci return; 246e41f4b71Sopenharmony_ci } 247e41f4b71Sopenharmony_ci 248e41f4b71Sopenharmony_ci // Create a decryption session. If a secure video channel is used, create a MediaKeySession with the content protection level of CONTENT_PROTECTION_LEVEL_HW_CRYPTO or higher. 249e41f4b71Sopenharmony_ci // To use a non-secure video channel, create a MediaKeySession with the content protection level of CONTENT_PROTECTION_LEVEL_SW_CRYPTO or higher. 250e41f4b71Sopenharmony_ci MediaKeySession *session = nullptr; 251e41f4b71Sopenharmony_ci DRM_ContentProtectionLevel contentProtectionLevel = CONTENT_PROTECTION_LEVEL_SW_CRYPTO; 252e41f4b71Sopenharmony_ci ret = OH_MediaKeySystem_CreateMediaKeySession(system, &contentProtectionLevel, &session); 253e41f4b71Sopenharmony_ci if (ret != DRM_OK) { 254e41f4b71Sopenharmony_ci // If the creation fails, check the DRM interface document and logs. 255e41f4b71Sopenharmony_ci printf("create media key session failed."); 256e41f4b71Sopenharmony_ci return; 257e41f4b71Sopenharmony_ci } 258e41f4b71Sopenharmony_ci if (session == nullptr) { 259e41f4b71Sopenharmony_ci printf("media key session is nullptr."); 260e41f4b71Sopenharmony_ci return; 261e41f4b71Sopenharmony_ci } 262e41f4b71Sopenharmony_ci 263e41f4b71Sopenharmony_ci // Generate a media key request and set the response to the media key request. 264e41f4b71Sopenharmony_ci 265e41f4b71Sopenharmony_ci // Set the decryption configuration, that is, set the decryption session and secure video channel flag to the decoder. 266e41f4b71Sopenharmony_ci // If the DRM scheme supports a secure video channel, set secureVideoPath to true and create a secure decoder before using the channel. 267e41f4b71Sopenharmony_ci // That is, in step 3, call OH_VideoDecoder_CreateByName, with a decoder name followed by .secure (for example, [CodecName].secure) passed in, to create a secure decoder. 268e41f4b71Sopenharmony_ci bool secureVideoPath = false; 269e41f4b71Sopenharmony_ci ret = OH_VideoDecoder_SetDecryptionConfig(videoDec, session, secureVideoPath); 270e41f4b71Sopenharmony_ci ``` 271e41f4b71Sopenharmony_ci 272e41f4b71Sopenharmony_ci6. Call **OH_VideoDecoder_Configure()** to configure the decoder. 273e41f4b71Sopenharmony_ci 274e41f4b71Sopenharmony_ci For details about the configurable options, see [Video Dedicated Key-Value Paris](../../reference/apis-avcodec-kit/_codec_base.md#media-data-key-value-pairs). 275e41f4b71Sopenharmony_ci 276e41f4b71Sopenharmony_ci For details about the parameter verification rules, see [OH_VideoDecoder_Configure()](../../reference/apis-avcodec-kit/_video_decoder.md#oh_videodecoder_configure). 277e41f4b71Sopenharmony_ci 278e41f4b71Sopenharmony_ci The parameter value ranges can be obtained through the capability query interface. For details, see [Obtaining Supported Codecs](obtain-supported-codecs.md). 279e41f4b71Sopenharmony_ci 280e41f4b71Sopenharmony_ci Currently, the following options must be configured for all supported formats: video frame width, video frame height, and video pixel format. In the code snippet below, the following variables are used: 281e41f4b71Sopenharmony_ci 282e41f4b71Sopenharmony_ci - **DEFAULT_WIDTH**: 320 pixels 283e41f4b71Sopenharmony_ci - **DEFAULT_HEIGHT**: 240 pixels 284e41f4b71Sopenharmony_ci - **DEFAULT_PIXELFORMAT**: **AV_PIXEL_FORMAT_NV12** (the pixel format of the YUV file is NV12) 285e41f4b71Sopenharmony_ci 286e41f4b71Sopenharmony_ci ```c++ 287e41f4b71Sopenharmony_ci 288e41f4b71Sopenharmony_ci OH_AVFormat *format = OH_AVFormat_Create(); 289e41f4b71Sopenharmony_ci // Set the format. 290e41f4b71Sopenharmony_ci OH_AVFormat_SetIntValue (format, OH_MD_KEY_WIDTH, width); // Mandatory 291e41f4b71Sopenharmony_ci OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, height); // Mandatory 292e41f4b71Sopenharmony_ci OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, DEFAULT_PIXELFORMAT); 293e41f4b71Sopenharmony_ci // (Optional) Configure low-latency decoding. 294e41f4b71Sopenharmony_ci OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENABLE_LOW_LATENCY, 1); 295e41f4b71Sopenharmony_ci // Configure the decoder. 296e41f4b71Sopenharmony_ci int32_t ret = OH_VideoDecoder_Configure(videoDec, format); 297e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 298e41f4b71Sopenharmony_ci // Exception handling. 299e41f4b71Sopenharmony_ci } 300e41f4b71Sopenharmony_ci OH_AVFormat_Destroy(format); 301e41f4b71Sopenharmony_ci ``` 302e41f4b71Sopenharmony_ci 303e41f4b71Sopenharmony_ci7. Set the surface. The application obtains the native window from the **XComponent**. For details about the process, see [XComponent](../../reference/apis-arkui/arkui-ts/ts-basic-components-xcomponent.md). 304e41f4b71Sopenharmony_ci 305e41f4b71Sopenharmony_ci You perform this step during decoding, that is, dynamically switch the surface. 306e41f4b71Sopenharmony_ci 307e41f4b71Sopenharmony_ci ```c++ 308e41f4b71Sopenharmony_ci // Set the window parameters. 309e41f4b71Sopenharmony_ci int32_t ret = OH_VideoDecoder_SetSurface(videoDec, window); // Obtain the window from the XComponent. 310e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 311e41f4b71Sopenharmony_ci // Exception handling. 312e41f4b71Sopenharmony_ci } 313e41f4b71Sopenharmony_ci ``` 314e41f4b71Sopenharmony_ci 315e41f4b71Sopenharmony_ci8. (Optional) Call **OH_VideoDecoder_SetParameter()** to set the surface parameters of the decoder. 316e41f4b71Sopenharmony_ci 317e41f4b71Sopenharmony_ci For details about the configurable options, see [Video Dedicated Key-Value Paris](../../reference/apis-avcodec-kit/_codec_base.md#media-data-key-value-pairs). 318e41f4b71Sopenharmony_ci 319e41f4b71Sopenharmony_ci ```c++ 320e41f4b71Sopenharmony_ci OH_AVFormat *format = OH_AVFormat_Create(); 321e41f4b71Sopenharmony_ci // Configure the display rotation angle. 322e41f4b71Sopenharmony_ci OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, 90); 323e41f4b71Sopenharmony_ci // Configure the matching mode (scaling or cropping) between the video and the screen. 324e41f4b71Sopenharmony_ci OH_AVFormat_SetIntValue(format, OH_MD_KEY_SCALING_MODE, SCALING_MODE_SCALE_CROP); 325e41f4b71Sopenharmony_ci int32_t ret = OH_VideoDecoder_SetParameter(videoDec, format); 326e41f4b71Sopenharmony_ci OH_AVFormat_Destroy(format); 327e41f4b71Sopenharmony_ci ``` 328e41f4b71Sopenharmony_ci 329e41f4b71Sopenharmony_ci9. Call **OH_VideoDecoder_Prepare()** to prepare internal resources for the decoder. 330e41f4b71Sopenharmony_ci 331e41f4b71Sopenharmony_ci ```c++ 332e41f4b71Sopenharmony_ci ret = OH_VideoDecoder_Prepare(videoDec); 333e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 334e41f4b71Sopenharmony_ci // Exception handling. 335e41f4b71Sopenharmony_ci } 336e41f4b71Sopenharmony_ci ``` 337e41f4b71Sopenharmony_ci 338e41f4b71Sopenharmony_ci10. Call **OH_VideoDecoder_Start()** to start the decoder. 339e41f4b71Sopenharmony_ci 340e41f4b71Sopenharmony_ci ```c++ 341e41f4b71Sopenharmony_ci std::string_view inputFilePath = "/*yourpath*.h264"; 342e41f4b71Sopenharmony_ci std::unique_ptr<std::ifstream> inputFile = std::make_unique<std::ifstream>(); 343e41f4b71Sopenharmony_ci inputFile->open(inputFilePath.data(), std::ios::in | std::ios::binary); 344e41f4b71Sopenharmony_ci // Start the decoder. 345e41f4b71Sopenharmony_ci int32_t ret = OH_VideoDecoder_Start(videoDec); 346e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 347e41f4b71Sopenharmony_ci // Exception handling. 348e41f4b71Sopenharmony_ci } 349e41f4b71Sopenharmony_ci ``` 350e41f4b71Sopenharmony_ci 351e41f4b71Sopenharmony_ci11. (Optional) Call **OH_AVCencInfo_SetAVBuffer()** to set the Common Encryption Scheme (CENC) information. 352e41f4b71Sopenharmony_ci 353e41f4b71Sopenharmony_ci If the program to play is DRM encrypted and the application implements media demuxing instead of using the system's [demuxer](audio-video-demuxer.md), you must call **OH_AVCencInfo_SetAVBuffer()** to set the CENC information to the AVBuffer. In this way, the AVBuffer carries the data to be decrypted and CENC information, so that the media data in the AVBuffer can be decrypted. You do not need to call this API when the application uses the system's [demuxer](audio-video-demuxer.md). 354e41f4b71Sopenharmony_ci 355e41f4b71Sopenharmony_ci Add the header files. 356e41f4b71Sopenharmony_ci 357e41f4b71Sopenharmony_ci ```c++ 358e41f4b71Sopenharmony_ci #include <multimedia/player_framework/native_cencinfo.h> 359e41f4b71Sopenharmony_ci ``` 360e41f4b71Sopenharmony_ci Link the dynamic library in the CMake script. 361e41f4b71Sopenharmony_ci 362e41f4b71Sopenharmony_ci ``` cmake 363e41f4b71Sopenharmony_ci target_link_libraries(sample PUBLIC libnative_media_avcencinfo.so) 364e41f4b71Sopenharmony_ci ``` 365e41f4b71Sopenharmony_ci 366e41f4b71Sopenharmony_ci In the code snippet below, the following variable is used: 367e41f4b71Sopenharmony_ci - **buffer**: parameter passed by the callback function **OnNeedInputBuffer**. You can obtain the virtual address of the image by calling **OH_AVBuffer_GetAddr**. 368e41f4b71Sopenharmony_ci ```c++ 369e41f4b71Sopenharmony_ci uint32_t keyIdLen = DRM_KEY_ID_SIZE; 370e41f4b71Sopenharmony_ci uint8_t keyId[] = { 371e41f4b71Sopenharmony_ci 0xd4, 0xb2, 0x01, 0xe4, 0x61, 0xc8, 0x98, 0x96, 372e41f4b71Sopenharmony_ci 0xcf, 0x05, 0x22, 0x39, 0x8d, 0x09, 0xe6, 0x28}; 373e41f4b71Sopenharmony_ci uint32_t ivLen = DRM_KEY_IV_SIZE; 374e41f4b71Sopenharmony_ci uint8_t iv[] = { 375e41f4b71Sopenharmony_ci 0xbf, 0x77, 0xed, 0x51, 0x81, 0xde, 0x36, 0x3e, 376e41f4b71Sopenharmony_ci 0x52, 0xf7, 0x20, 0x4f, 0x72, 0x14, 0xa3, 0x95}; 377e41f4b71Sopenharmony_ci uint32_t encryptedBlockCount = 0; 378e41f4b71Sopenharmony_ci uint32_t skippedBlockCount = 0; 379e41f4b71Sopenharmony_ci uint32_t firstEncryptedOffset = 0; 380e41f4b71Sopenharmony_ci uint32_t subsampleCount = 1; 381e41f4b71Sopenharmony_ci DrmSubsample subsamples[1] = { {0x10, 0x16} }; 382e41f4b71Sopenharmony_ci // Create a CencInfo instance. 383e41f4b71Sopenharmony_ci OH_AVCencInfo *cencInfo = OH_AVCencInfo_Create(); 384e41f4b71Sopenharmony_ci if (cencInfo == nullptr) { 385e41f4b71Sopenharmony_ci // Exception handling. 386e41f4b71Sopenharmony_ci } 387e41f4b71Sopenharmony_ci // Set the decryption algorithm. 388e41f4b71Sopenharmony_ci OH_AVErrCode errNo = OH_AVCencInfo_SetAlgorithm(cencInfo, DRM_ALG_CENC_AES_CTR); 389e41f4b71Sopenharmony_ci if (errNo != AV_ERR_OK) { 390e41f4b71Sopenharmony_ci // Exception handling. 391e41f4b71Sopenharmony_ci } 392e41f4b71Sopenharmony_ci // Set KeyId and Iv. 393e41f4b71Sopenharmony_ci errNo = OH_AVCencInfo_SetKeyIdAndIv(cencInfo, keyId, keyIdLen, iv, ivLen); 394e41f4b71Sopenharmony_ci if (errNo != AV_ERR_OK) { 395e41f4b71Sopenharmony_ci // Exception handling. 396e41f4b71Sopenharmony_ci } 397e41f4b71Sopenharmony_ci // Set the sample information. 398e41f4b71Sopenharmony_ci errNo = OH_AVCencInfo_SetSubsampleInfo(cencInfo, encryptedBlockCount, skippedBlockCount, firstEncryptedOffset, 399e41f4b71Sopenharmony_ci subsampleCount, subsamples); 400e41f4b71Sopenharmony_ci if (errNo != AV_ERR_OK) { 401e41f4b71Sopenharmony_ci // Exception handling. 402e41f4b71Sopenharmony_ci } 403e41f4b71Sopenharmony_ci // Set the mode. KeyId, Iv, and SubSamples have been set. 404e41f4b71Sopenharmony_ci errNo = OH_AVCencInfo_SetMode(cencInfo, DRM_CENC_INFO_KEY_IV_SUBSAMPLES_SET); 405e41f4b71Sopenharmony_ci if (errNo != AV_ERR_OK) { 406e41f4b71Sopenharmony_ci // Exception handling. 407e41f4b71Sopenharmony_ci } 408e41f4b71Sopenharmony_ci // Set CencInfo to the AVBuffer. 409e41f4b71Sopenharmony_ci errNo = OH_AVCencInfo_SetAVBuffer(cencInfo, buffer); 410e41f4b71Sopenharmony_ci if (errNo != AV_ERR_OK) { 411e41f4b71Sopenharmony_ci // Exception handling. 412e41f4b71Sopenharmony_ci } 413e41f4b71Sopenharmony_ci // Destroy the CencInfo instance. 414e41f4b71Sopenharmony_ci errNo = OH_AVCencInfo_Destroy(cencInfo); 415e41f4b71Sopenharmony_ci if (errNo != AV_ERR_OK) { 416e41f4b71Sopenharmony_ci // Exception handling. 417e41f4b71Sopenharmony_ci } 418e41f4b71Sopenharmony_ci ``` 419e41f4b71Sopenharmony_ci 420e41f4b71Sopenharmony_ci12. Call **OH_VideoDecoder_PushInputBuffer()** to push the stream to the input buffer for decoding. 421e41f4b71Sopenharmony_ci 422e41f4b71Sopenharmony_ci In the code snippet below, the following variables are used: 423e41f4b71Sopenharmony_ci 424e41f4b71Sopenharmony_ci - **buffer**: parameter passed by the callback function **OnNeedInputBuffer**. In surface mode, you cannot obtain the virtual address of the image by calling **OH_AVBuffer_GetAddr**. 425e41f4b71Sopenharmony_ci - **index**: parameter passed by the callback function **OnNeedInputBuffer**, which uniquely corresponds to the buffer. 426e41f4b71Sopenharmony_ci - **size**, **offset**, and **pts**: size, offset, and timestamp. For details about how to obtain the information, see [Audio and Video Demuxing](./audio-video-demuxer.md). 427e41f4b71Sopenharmony_ci - **flags**: type of the buffer flag. For details, see [OH_AVCodecBufferFlags](../../reference/apis-avcodec-kit/_core.md#oh_avcodecbufferflags). 428e41f4b71Sopenharmony_ci 429e41f4b71Sopenharmony_ci ```c++ 430e41f4b71Sopenharmony_ci // Configure the size, offset, and timestamp of the frame data. 431e41f4b71Sopenharmony_ci OH_AVCodecBufferAttr info; 432e41f4b71Sopenharmony_ci info.size = size; 433e41f4b71Sopenharmony_ci info.offset = offset; 434e41f4b71Sopenharmony_ci info.pts = pts; 435e41f4b71Sopenharmony_ci info.flags = flags; 436e41f4b71Sopenharmony_ci // Write the information to the buffer. 437e41f4b71Sopenharmony_ci int32_t ret = OH_AVBuffer_SetBufferAttr(buffer, &info); 438e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 439e41f4b71Sopenharmony_ci // Exception handling. 440e41f4b71Sopenharmony_ci } 441e41f4b71Sopenharmony_ci // Send the data to the input buffer for decoding. index is the index of the buffer. 442e41f4b71Sopenharmony_ci ret = OH_VideoDecoder_PushInputBuffer(videoDec, index); 443e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 444e41f4b71Sopenharmony_ci // Exception handling. 445e41f4b71Sopenharmony_ci } 446e41f4b71Sopenharmony_ci ``` 447e41f4b71Sopenharmony_ci 448e41f4b71Sopenharmony_ci13. Call **OH_VideoDecoder_RenderOutputBuffer()** or **OH_VideoDecoder_RenderOutputBufferAtTime()** to render the data and free the output buffer, or call **OH_VideoDecoder_FreeOutputBuffer()** to directly free the output buffer. 449e41f4b71Sopenharmony_ci 450e41f4b71Sopenharmony_ci In the code snippet below, the following variables are used: 451e41f4b71Sopenharmony_ci 452e41f4b71Sopenharmony_ci - **index**: parameter passed by the callback function **OnNewOutputBuffer**, which uniquely corresponds to the buffer. 453e41f4b71Sopenharmony_ci - **buffer**: parameter passed by the callback function **OnNewOutputBuffer**. In surface mode, you cannot obtain the virtual address of the image by calling **OH_AVBuffer_GetAddr**. 454e41f4b71Sopenharmony_ci 455e41f4b71Sopenharmony_ci Add the header files. 456e41f4b71Sopenharmony_ci 457e41f4b71Sopenharmony_ci ```c++ 458e41f4b71Sopenharmony_ci #include <chrono> 459e41f4b71Sopenharmony_ci ``` 460e41f4b71Sopenharmony_ci 461e41f4b71Sopenharmony_ci ```c++ 462e41f4b71Sopenharmony_ci // Obtain the decoded information. 463e41f4b71Sopenharmony_ci OH_AVCodecBufferAttr info; 464e41f4b71Sopenharmony_ci int32_t ret = OH_AVBuffer_GetBufferAttr(buffer, &info); 465e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 466e41f4b71Sopenharmony_ci // Exception handling. 467e41f4b71Sopenharmony_ci } 468e41f4b71Sopenharmony_ci // The value is determined by the caller. 469e41f4b71Sopenharmony_ci bool isRender; 470e41f4b71Sopenharmony_ci bool isNeedRenderAtTime; 471e41f4b71Sopenharmony_ci if (isRender) { 472e41f4b71Sopenharmony_ci // Render the data and free the output buffer. index is the index of the buffer. 473e41f4b71Sopenharmony_ci if (isNeedRenderAtTime){ 474e41f4b71Sopenharmony_ci // Obtain the system absolute time, and call renderTimestamp to display the time based on service requirements. 475e41f4b71Sopenharmony_ci int64_t renderTimestamp = 476e41f4b71Sopenharmony_ci chrono::duration_cast<chrono::nanoseconds>(chrono::high_resolution_clock::now().time_since_epoch()).count(); 477e41f4b71Sopenharmony_ci ret = OH_VideoDecoder_RenderOutputBufferAtTime(videoDec, index, renderTimestamp); 478e41f4b71Sopenharmony_ci } else { 479e41f4b71Sopenharmony_ci ret = OH_VideoDecoder_RenderOutputBuffer(videoDec, index); 480e41f4b71Sopenharmony_ci } 481e41f4b71Sopenharmony_ci 482e41f4b71Sopenharmony_ci } else { 483e41f4b71Sopenharmony_ci // Free the output buffer. 484e41f4b71Sopenharmony_ci ret = OH_VideoDecoder_FreeOutputBuffer(videoDec, index); 485e41f4b71Sopenharmony_ci } 486e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 487e41f4b71Sopenharmony_ci // Exception handling. 488e41f4b71Sopenharmony_ci } 489e41f4b71Sopenharmony_ci ``` 490e41f4b71Sopenharmony_ci 491e41f4b71Sopenharmony_ci14. (Optional) Call **OH_VideoDecoder_Flush()** to refresh the decoder. 492e41f4b71Sopenharmony_ci 493e41f4b71Sopenharmony_ci After **OH_VideoDecoder_Flush** is called, the decoder remains in the Running state, but the input and output data and parameter set (such as the H.264 PPS/SPS) buffered in the decoder are cleared. 494e41f4b71Sopenharmony_ci 495e41f4b71Sopenharmony_ci To continue decoding, you must call **OH_VideoDecoder_Start** again. 496e41f4b71Sopenharmony_ci 497e41f4b71Sopenharmony_ci ```c++ 498e41f4b71Sopenharmony_ci // Refresh the decoder. 499e41f4b71Sopenharmony_ci int32_t ret = OH_VideoDecoder_Flush(videoDec); 500e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 501e41f4b71Sopenharmony_ci // Exception handling. 502e41f4b71Sopenharmony_ci } 503e41f4b71Sopenharmony_ci // Start decoding again. 504e41f4b71Sopenharmony_ci ret = OH_VideoDecoder_Start(videoDec); 505e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 506e41f4b71Sopenharmony_ci // Exception handling. 507e41f4b71Sopenharmony_ci } 508e41f4b71Sopenharmony_ci // Retransfer PPS/SPS. 509e41f4b71Sopenharmony_ci // Configure the frame PPS/SPS information. 510e41f4b71Sopenharmony_ci OH_AVCodecBufferAttr info; 511e41f4b71Sopenharmony_ci info.flags = AVCODEC_BUFFER_FLAG_CODEC_DATA; 512e41f4b71Sopenharmony_ci // Write the information to the buffer. 513e41f4b71Sopenharmony_ci int32_t ret = OH_AVBuffer_SetBufferAttr(buffer, &info); 514e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 515e41f4b71Sopenharmony_ci // Exception handling. 516e41f4b71Sopenharmony_ci } 517e41f4b71Sopenharmony_ci // Push the frame data to the decoder. index is the index of the corresponding queue. 518e41f4b71Sopenharmony_ci ret = OH_VideoDecoder_PushInputBuffer(videoDec, index); 519e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 520e41f4b71Sopenharmony_ci // Exception handling. 521e41f4b71Sopenharmony_ci } 522e41f4b71Sopenharmony_ci ``` 523e41f4b71Sopenharmony_ci > **NOTE** 524e41f4b71Sopenharmony_ci > 525e41f4b71Sopenharmony_ci > When **OH_VideoDecoder_Start** s called again after the flush operation, the PPS/SPS must be retransferred. 526e41f4b71Sopenharmony_ci 527e41f4b71Sopenharmony_ci 528e41f4b71Sopenharmony_ci15. (Optional) Call **OH_VideoDecoder_Reset()** to reset the decoder. 529e41f4b71Sopenharmony_ci 530e41f4b71Sopenharmony_ci After **OH_VideoDecoder_Reset** is called, the decoder returns to the Initialized state. To continue decoding, you must call **OH_VideoDecoder_Configure**, **OH_VideoDecoder_Prepare**, and **OH_VideoDecoder_SetSurface** in sequence. 531e41f4b71Sopenharmony_ci 532e41f4b71Sopenharmony_ci ```c++ 533e41f4b71Sopenharmony_ci // Reset the decoder. 534e41f4b71Sopenharmony_ci int32_t ret = OH_VideoDecoder_Reset(videoDec); 535e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 536e41f4b71Sopenharmony_ci // Exception handling. 537e41f4b71Sopenharmony_ci } 538e41f4b71Sopenharmony_ci // Reconfigure the decoder. 539e41f4b71Sopenharmony_ci ret = OH_VideoDecoder_Configure(videoDec, format); 540e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 541e41f4b71Sopenharmony_ci // Exception handling. 542e41f4b71Sopenharmony_ci } 543e41f4b71Sopenharmony_ci // The decoder is ready again. 544e41f4b71Sopenharmony_ci ret = OH_VideoDecoder_Prepare(videoDec); 545e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 546e41f4b71Sopenharmony_ci // Exception handling. 547e41f4b71Sopenharmony_ci } 548e41f4b71Sopenharmony_ci // Reconfigure the surface in surface mode. This is not required in buffer mode. 549e41f4b71Sopenharmony_ci ret = OH_VideoDecoder_SetSurface(videoDec, window); 550e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 551e41f4b71Sopenharmony_ci // Exception handling. 552e41f4b71Sopenharmony_ci } 553e41f4b71Sopenharmony_ci ``` 554e41f4b71Sopenharmony_ci 555e41f4b71Sopenharmony_ci16. (Optional) Call **OH_VideoDecoder_Stop()** to stop the decoder. 556e41f4b71Sopenharmony_ci 557e41f4b71Sopenharmony_ci After **OH_VideoDecoder_Stop()** is called, the decoder retains the decoding instance and releases the input and output buffers. You can directly call **OH_VideoDecoder_Start** to continue decoding. The first input buffer must carry the parameter set, starting from the IDR frame. 558e41f4b71Sopenharmony_ci 559e41f4b71Sopenharmony_ci ```c++ 560e41f4b71Sopenharmony_ci // Stop the decoder. 561e41f4b71Sopenharmony_ci int32_t ret = OH_VideoDecoder_Stop(videoDec); 562e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 563e41f4b71Sopenharmony_ci // Exception handling. 564e41f4b71Sopenharmony_ci } 565e41f4b71Sopenharmony_ci ``` 566e41f4b71Sopenharmony_ci 567e41f4b71Sopenharmony_ci17. Call **OH_VideoDecoder_Destroy()** to destroy the decoder instance and release resources. 568e41f4b71Sopenharmony_ci 569e41f4b71Sopenharmony_ci > **NOTE** 570e41f4b71Sopenharmony_ci > 571e41f4b71Sopenharmony_ci > This API cannot be called in the callback function. 572e41f4b71Sopenharmony_ci > After the call, you must set the decoder to NULL to prevent program errors caused by wild pointers. 573e41f4b71Sopenharmony_ci > 574e41f4b71Sopenharmony_ci 575e41f4b71Sopenharmony_ci ```c++ 576e41f4b71Sopenharmony_ci // Call OH_VideoDecoder_Destroy to destroy the decoder. 577e41f4b71Sopenharmony_ci if (videoDec != NULL) { 578e41f4b71Sopenharmony_ci int32_t ret = OH_VideoDecoder_Destroy(videoDec); 579e41f4b71Sopenharmony_ci videoDec = NULL; 580e41f4b71Sopenharmony_ci } 581e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 582e41f4b71Sopenharmony_ci // Exception handling. 583e41f4b71Sopenharmony_ci } 584e41f4b71Sopenharmony_ci ``` 585e41f4b71Sopenharmony_ci 586e41f4b71Sopenharmony_ci### Buffer Output 587e41f4b71Sopenharmony_ci 588e41f4b71Sopenharmony_ciThe following walks you through how to implement the entire video decoding process in buffer mode. In this example, an H.264 file is input and decoded into a YUV file. 589e41f4b71Sopenharmony_ciCurrently, the VideoDecoder module supports only data rotation in asynchronous mode. 590e41f4b71Sopenharmony_ci 591e41f4b71Sopenharmony_ci1. Add the header files. 592e41f4b71Sopenharmony_ci 593e41f4b71Sopenharmony_ci ```c++ 594e41f4b71Sopenharmony_ci #include <multimedia/player_framework/native_avcodec_videodecoder.h> 595e41f4b71Sopenharmony_ci #include <multimedia/player_framework/native_avcapability.h> 596e41f4b71Sopenharmony_ci #include <multimedia/player_framework/native_avcodec_base.h> 597e41f4b71Sopenharmony_ci #include <multimedia/player_framework/native_avformat.h> 598e41f4b71Sopenharmony_ci #include <multimedia/player_framework/native_avbuffer.h> 599e41f4b71Sopenharmony_ci #include <native_buffer/native_buffer.h> 600e41f4b71Sopenharmony_ci #include <fstream> 601e41f4b71Sopenharmony_ci ``` 602e41f4b71Sopenharmony_ci 603e41f4b71Sopenharmony_ci2. Create a decoder instance. 604e41f4b71Sopenharmony_ci 605e41f4b71Sopenharmony_ci The procedure is the same as that in surface mode and is not described here. 606e41f4b71Sopenharmony_ci 607e41f4b71Sopenharmony_ci ```c++ 608e41f4b71Sopenharmony_ci // To create a decoder by name, call OH_AVCapability_GetName to obtain the codec names available and then call OH_VideoDecoder_CreateByName. If your application has special requirements, for example, expecting a decoder that supports a certain resolution, you can call OH_AVCodec_GetCapability to query the capability first. 609e41f4b71Sopenharmony_ci OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, false); 610e41f4b71Sopenharmony_ci const char *name = OH_AVCapability_GetName(capability); 611e41f4b71Sopenharmony_ci OH_AVCodec *videoDec = OH_VideoDecoder_CreateByName(name); 612e41f4b71Sopenharmony_ci ``` 613e41f4b71Sopenharmony_ci 614e41f4b71Sopenharmony_ci ```c++ 615e41f4b71Sopenharmony_ci // Create a decoder by MIME type. Only specific codecs recommended by the system can be created in this way. 616e41f4b71Sopenharmony_ci // If multiple codecs need to be created, create hardware decoder instances first. If the hardware resources are insufficient, create software decoder instances. 617e41f4b71Sopenharmony_ci // Create an H.264 decoder for software/hardware decoding. 618e41f4b71Sopenharmony_ci OH_AVCodec *videoDec = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC); 619e41f4b71Sopenharmony_ci // Create an H.265 decoder for hardware decoding. 620e41f4b71Sopenharmony_ci OH_AVCodec *videoDec = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_HEVC); 621e41f4b71Sopenharmony_ci ``` 622e41f4b71Sopenharmony_ci 623e41f4b71Sopenharmony_ci3. Call **OH_VideoDecoder_RegisterCallback()** to register the callback functions. 624e41f4b71Sopenharmony_ci 625e41f4b71Sopenharmony_ci Register the **OH_AVCodecCallback** struct that defines the following callback function pointers: 626e41f4b71Sopenharmony_ci 627e41f4b71Sopenharmony_ci - **OH_AVCodecOnError**, a callback used to report a codec operation error. For details about the error codes, see [OH_AVCodecOnError](../../reference/apis-avcodec-kit/_codec_base.md#oh_avcodeconerror). 628e41f4b71Sopenharmony_ci - **OH_AVCodecOnStreamChanged**, a callback used to report a codec stream change, for example, stream width or height change. 629e41f4b71Sopenharmony_ci - **OH_AVCodecOnNeedInputBuffer**, a callback used to report input data required, which means that the decoder is ready for receiving data. 630e41f4b71Sopenharmony_ci - **OH_AVCodecOnNewOutputBuffer**, a callback used to report output data generated, which means that decoding is complete. 631e41f4b71Sopenharmony_ci 632e41f4b71Sopenharmony_ci You need to process the callback functions to ensure that the decoder runs properly. 633e41f4b71Sopenharmony_ci 634e41f4b71Sopenharmony_ci <!--RP2--><!--RP2End--> 635e41f4b71Sopenharmony_ci 636e41f4b71Sopenharmony_ci ```c++ 637e41f4b71Sopenharmony_ci int32_t cropTop = 0; 638e41f4b71Sopenharmony_ci int32_t cropBottom = 0; 639e41f4b71Sopenharmony_ci int32_t cropLeft = 0; 640e41f4b71Sopenharmony_ci int32_t cropRight = 0; 641e41f4b71Sopenharmony_ci bool isFirstFrame = true; 642e41f4b71Sopenharmony_ci // Implement the OH_AVCodecOnError callback function. 643e41f4b71Sopenharmony_ci static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) 644e41f4b71Sopenharmony_ci { 645e41f4b71Sopenharmony_ci // Process the error code in the callback. 646e41f4b71Sopenharmony_ci (void)codec; 647e41f4b71Sopenharmony_ci (void)errorCode; 648e41f4b71Sopenharmony_ci (void)userData; 649e41f4b71Sopenharmony_ci } 650e41f4b71Sopenharmony_ci 651e41f4b71Sopenharmony_ci // Implement the OH_AVCodecOnStreamChanged callback function. 652e41f4b71Sopenharmony_ci static void OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) 653e41f4b71Sopenharmony_ci { 654e41f4b71Sopenharmony_ci // Optional. Configure the data when you want to obtain the video width, height, and stride. 655e41f4b71Sopenharmony_ci // The changed video width, height, and stride can be obtained through format. 656e41f4b71Sopenharmony_ci (void)codec; 657e41f4b71Sopenharmony_ci (void)userData; 658e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_WIDTH, &width); 659e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_HEIGHT, &height); 660e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_STRIDE, &widthStride); 661e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_SLICE_HEIGHT, &heightStride); 662e41f4b71Sopenharmony_ci // (Optional) Obtain the cropped rectangle information. 663e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_CROP_TOP, &cropTop); 664e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_CROP_BOTTOM, &cropBottom); 665e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_CROP_LEFT, &cropLeft); 666e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_CROP_RIGHT, &cropRight); 667e41f4b71Sopenharmony_ci } 668e41f4b71Sopenharmony_ci 669e41f4b71Sopenharmony_ci // Implement the OH_AVCodecOnNeedInputBuffer callback function. 670e41f4b71Sopenharmony_ci static void OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) 671e41f4b71Sopenharmony_ci { 672e41f4b71Sopenharmony_ci // The index of the input frame buffer is sent to InIndexQueue. 673e41f4b71Sopenharmony_ci // The input frame data (specified by buffer) is sent to InBufferQueue. 674e41f4b71Sopenharmony_ci // Process the data. 675e41f4b71Sopenharmony_ci // Write the stream to decode. 676e41f4b71Sopenharmony_ci } 677e41f4b71Sopenharmony_ci 678e41f4b71Sopenharmony_ci // Implement the OH_AVCodecOnNewOutputBuffer callback function. 679e41f4b71Sopenharmony_ci static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) 680e41f4b71Sopenharmony_ci { 681e41f4b71Sopenharmony_ci // Optional. Configure the data when you want to obtain the video width, height, and stride. 682e41f4b71Sopenharmony_ci // The index of the output frame buffer is sent to outIndexQueue. 683e41f4b71Sopenharmony_ci // The output frame data (specified by buffer) is sent to outBufferQueue. 684e41f4b71Sopenharmony_ci // Obtain the video width, height, and stride. 685e41f4b71Sopenharmony_ci if (isFirstFrame) { 686e41f4b71Sopenharmony_ci OH_AVFormat *format = OH_VideoDecoder_GetOutputDescription(codec); 687e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_WIDTH, &width); 688e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_HEIGHT, &height); 689e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_STRIDE, &widthStride); 690e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_SLICE_HEIGHT, &heightStride); 691e41f4b71Sopenharmony_ci // (Optional) Obtain the cropped rectangle information. 692e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_CROP_TOP, &cropTop); 693e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_CROP_BOTTOM, &cropBottom); 694e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_CROP_LEFT, &cropLeft); 695e41f4b71Sopenharmony_ci OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_CROP_RIGHT, &cropRight); 696e41f4b71Sopenharmony_ci OH_AVFormat_Destroy(format); 697e41f4b71Sopenharmony_ci isFirstFrame = false; 698e41f4b71Sopenharmony_ci } 699e41f4b71Sopenharmony_ci // Process the data. 700e41f4b71Sopenharmony_ci // Release the decoded frame. 701e41f4b71Sopenharmony_ci } 702e41f4b71Sopenharmony_ci // Call OH_VideoDecoder_RegisterCallback() to register the callback functions. 703e41f4b71Sopenharmony_ci OH_AVCodecCallback cb = {&OnError, &OnStreamChanged, &OnNeedInputBuffer, &OnNewOutputBuffer}; 704e41f4b71Sopenharmony_ci // Set the asynchronous callbacks. 705e41f4b71Sopenharmony_ci int32_t ret = OH_VideoDecoder_RegisterCallback(videoDec, cb, NULL); // NULL: userData is null. 706e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 707e41f4b71Sopenharmony_ci // Exception handling. 708e41f4b71Sopenharmony_ci } 709e41f4b71Sopenharmony_ci ``` 710e41f4b71Sopenharmony_ci > **NOTE** 711e41f4b71Sopenharmony_ci > 712e41f4b71Sopenharmony_ci > In the callback functions, pay attention to multi-thread synchronization for operations on the data queue. 713e41f4b71Sopenharmony_ci > 714e41f4b71Sopenharmony_ci 715e41f4b71Sopenharmony_ci4. (Optional) Call **OH_VideoDecoder_SetDecryptionConfig** to set the decryption configuration. Call this API after the media key system information is obtained and a media key is obtained but before **Prepare()** is called. For details about how to obtain such information, see step 3 in [Audio and Video Demuxing](audio-video-demuxer.md). In buffer mode, the DRM decryption capability supports only non-secure video channels. For details about DRM APIs, see [DRM](../../reference/apis-drm-kit/_drm.md). 716e41f4b71Sopenharmony_ci 717e41f4b71Sopenharmony_ci Add the header files. 718e41f4b71Sopenharmony_ci 719e41f4b71Sopenharmony_ci ```c++ 720e41f4b71Sopenharmony_ci #include <multimedia/drm_framework/native_mediakeysystem.h> 721e41f4b71Sopenharmony_ci #include <multimedia/drm_framework/native_mediakeysession.h> 722e41f4b71Sopenharmony_ci #include <multimedia/drm_framework/native_drm_err.h> 723e41f4b71Sopenharmony_ci #include <multimedia/drm_framework/native_drm_common.h> 724e41f4b71Sopenharmony_ci ``` 725e41f4b71Sopenharmony_ci Link the dynamic library in the CMake script. 726e41f4b71Sopenharmony_ci 727e41f4b71Sopenharmony_ci ``` cmake 728e41f4b71Sopenharmony_ci target_link_libraries(sample PUBLIC libnative_drm.so) 729e41f4b71Sopenharmony_ci ``` 730e41f4b71Sopenharmony_ci 731e41f4b71Sopenharmony_ci The following is the sample code: 732e41f4b71Sopenharmony_ci ```c++ 733e41f4b71Sopenharmony_ci // Create a media key system based on the media key system information. The following uses com.clearplay.drm as an example. 734e41f4b71Sopenharmony_ci MediaKeySystem *system = nullptr; 735e41f4b71Sopenharmony_ci int32_t ret = OH_MediaKeySystem_Create("com.clearplay.drm", &system); 736e41f4b71Sopenharmony_ci if (system == nullptr) { 737e41f4b71Sopenharmony_ci printf("create media key system failed"); 738e41f4b71Sopenharmony_ci return; 739e41f4b71Sopenharmony_ci } 740e41f4b71Sopenharmony_ci 741e41f4b71Sopenharmony_ci // Create a media key session. 742e41f4b71Sopenharmony_ci // To use a non-secure video channel, create a MediaKeySession with the content protection level of CONTENT_PROTECTION_LEVEL_SW_CRYPTO or higher. 743e41f4b71Sopenharmony_ci MediaKeySession *session = nullptr; 744e41f4b71Sopenharmony_ci DRM_ContentProtectionLevel contentProtectionLevel = CONTENT_PROTECTION_LEVEL_SW_CRYPTO; 745e41f4b71Sopenharmony_ci ret = OH_MediaKeySystem_CreateMediaKeySession(system, &contentProtectionLevel, &session); 746e41f4b71Sopenharmony_ci if (ret != DRM_OK) { 747e41f4b71Sopenharmony_ci // If the creation fails, check the DRM interface document and logs. 748e41f4b71Sopenharmony_ci printf("create media key session failed."); 749e41f4b71Sopenharmony_ci return; 750e41f4b71Sopenharmony_ci } 751e41f4b71Sopenharmony_ci if (session == nullptr) { 752e41f4b71Sopenharmony_ci printf("media key session is nullptr."); 753e41f4b71Sopenharmony_ci return; 754e41f4b71Sopenharmony_ci } 755e41f4b71Sopenharmony_ci // Generate a media key request and set the response to the media key request. 756e41f4b71Sopenharmony_ci // Set the decryption configuration, that is, set the decryption session and secure video channel flag to the decoder. 757e41f4b71Sopenharmony_ci bool secureVideoPath = false; 758e41f4b71Sopenharmony_ci ret = OH_VideoDecoder_SetDecryptionConfig(videoDec, session, secureVideoPath); 759e41f4b71Sopenharmony_ci ``` 760e41f4b71Sopenharmony_ci 761e41f4b71Sopenharmony_ci5. Call **OH_VideoDecoder_Configure()** to configure the decoder. 762e41f4b71Sopenharmony_ci 763e41f4b71Sopenharmony_ci The procedure is the same as that in surface mode and is not described here. 764e41f4b71Sopenharmony_ci 765e41f4b71Sopenharmony_ci ```c++ 766e41f4b71Sopenharmony_ci OH_AVFormat *format = OH_AVFormat_Create(); 767e41f4b71Sopenharmony_ci // Set the format. 768e41f4b71Sopenharmony_ci OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, width); 769e41f4b71Sopenharmony_ci OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, height); 770e41f4b71Sopenharmony_ci OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, DEFAULT_PIXELFORMAT); 771e41f4b71Sopenharmony_ci // Configure the decoder. 772e41f4b71Sopenharmony_ci int32_t ret = OH_VideoDecoder_Configure(videoDec, format); 773e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 774e41f4b71Sopenharmony_ci // Exception handling. 775e41f4b71Sopenharmony_ci } 776e41f4b71Sopenharmony_ci OH_AVFormat_Destroy(format); 777e41f4b71Sopenharmony_ci ``` 778e41f4b71Sopenharmony_ci 779e41f4b71Sopenharmony_ci6. Call **OH_VideoDecoder_Prepare()** to prepare internal resources for the decoder. 780e41f4b71Sopenharmony_ci 781e41f4b71Sopenharmony_ci ```c++ 782e41f4b71Sopenharmony_ci int32_t ret = OH_VideoDecoder_Prepare(videoDec); 783e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 784e41f4b71Sopenharmony_ci // Exception handling. 785e41f4b71Sopenharmony_ci } 786e41f4b71Sopenharmony_ci ``` 787e41f4b71Sopenharmony_ci 788e41f4b71Sopenharmony_ci7. Call **OH_VideoDecoder_Start()** to start the decoder. 789e41f4b71Sopenharmony_ci 790e41f4b71Sopenharmony_ci ```c++ 791e41f4b71Sopenharmony_ci std::string_view inputFilePath = "/*yourpath*.h264"; 792e41f4b71Sopenharmony_ci std::string_view outputFilePath = "/*yourpath*.yuv"; 793e41f4b71Sopenharmony_ci std::unique_ptr<std::ifstream> inputFile = std::make_unique<std::ifstream>(); 794e41f4b71Sopenharmony_ci std::unique_ptr<std::ofstream> outputFile = std::make_unique<std::ofstream>(); 795e41f4b71Sopenharmony_ci inputFile->open(inputFilePath.data(), std::ios::in | std::ios::binary); 796e41f4b71Sopenharmony_ci outputFile->open(outputFilePath.data(), std::ios::out | std::ios::binary | std::ios::ate); 797e41f4b71Sopenharmony_ci // Start the decoder. 798e41f4b71Sopenharmony_ci int32_t ret = OH_VideoDecoder_Start(videoDec); 799e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 800e41f4b71Sopenharmony_ci // Exception handling. 801e41f4b71Sopenharmony_ci } 802e41f4b71Sopenharmony_ci ``` 803e41f4b71Sopenharmony_ci 804e41f4b71Sopenharmony_ci8. (Optional) Call **OH_AVCencInfo_SetAVBuffer()** to set the CENC information. 805e41f4b71Sopenharmony_ci 806e41f4b71Sopenharmony_ci The procedure is the same as that in surface mode and is not described here. 807e41f4b71Sopenharmony_ci 808e41f4b71Sopenharmony_ci The following is the sample code: 809e41f4b71Sopenharmony_ci ```c++ 810e41f4b71Sopenharmony_ci uint32_t keyIdLen = DRM_KEY_ID_SIZE; 811e41f4b71Sopenharmony_ci uint8_t keyId[] = { 812e41f4b71Sopenharmony_ci 0xd4, 0xb2, 0x01, 0xe4, 0x61, 0xc8, 0x98, 0x96, 813e41f4b71Sopenharmony_ci 0xcf, 0x05, 0x22, 0x39, 0x8d, 0x09, 0xe6, 0x28}; 814e41f4b71Sopenharmony_ci uint32_t ivLen = DRM_KEY_IV_SIZE; 815e41f4b71Sopenharmony_ci uint8_t iv[] = { 816e41f4b71Sopenharmony_ci 0xbf, 0x77, 0xed, 0x51, 0x81, 0xde, 0x36, 0x3e, 817e41f4b71Sopenharmony_ci 0x52, 0xf7, 0x20, 0x4f, 0x72, 0x14, 0xa3, 0x95}; 818e41f4b71Sopenharmony_ci uint32_t encryptedBlockCount = 0; 819e41f4b71Sopenharmony_ci uint32_t skippedBlockCount = 0; 820e41f4b71Sopenharmony_ci uint32_t firstEncryptedOffset = 0; 821e41f4b71Sopenharmony_ci uint32_t subsampleCount = 1; 822e41f4b71Sopenharmony_ci DrmSubsample subsamples[1] = { {0x10, 0x16} }; 823e41f4b71Sopenharmony_ci // Create a CencInfo instance. 824e41f4b71Sopenharmony_ci OH_AVCencInfo *cencInfo = OH_AVCencInfo_Create(); 825e41f4b71Sopenharmony_ci if (cencInfo == nullptr) { 826e41f4b71Sopenharmony_ci // Exception handling. 827e41f4b71Sopenharmony_ci } 828e41f4b71Sopenharmony_ci // Set the decryption algorithm. 829e41f4b71Sopenharmony_ci OH_AVErrCode errNo = OH_AVCencInfo_SetAlgorithm(cencInfo, DRM_ALG_CENC_AES_CTR); 830e41f4b71Sopenharmony_ci if (errNo != AV_ERR_OK) { 831e41f4b71Sopenharmony_ci // Exception handling. 832e41f4b71Sopenharmony_ci } 833e41f4b71Sopenharmony_ci // Set KeyId and Iv. 834e41f4b71Sopenharmony_ci errNo = OH_AVCencInfo_SetKeyIdAndIv(cencInfo, keyId, keyIdLen, iv, ivLen); 835e41f4b71Sopenharmony_ci if (errNo != AV_ERR_OK) { 836e41f4b71Sopenharmony_ci // Exception handling. 837e41f4b71Sopenharmony_ci } 838e41f4b71Sopenharmony_ci // Set the sample information. 839e41f4b71Sopenharmony_ci errNo = OH_AVCencInfo_SetSubsampleInfo(cencInfo, encryptedBlockCount, skippedBlockCount, firstEncryptedOffset, 840e41f4b71Sopenharmony_ci subsampleCount, subsamples); 841e41f4b71Sopenharmony_ci if (errNo != AV_ERR_OK) { 842e41f4b71Sopenharmony_ci // Exception handling. 843e41f4b71Sopenharmony_ci } 844e41f4b71Sopenharmony_ci // Set the mode. KeyId, Iv, and SubSamples have been set. 845e41f4b71Sopenharmony_ci errNo = OH_AVCencInfo_SetMode(cencInfo, DRM_CENC_INFO_KEY_IV_SUBSAMPLES_SET); 846e41f4b71Sopenharmony_ci if (errNo != AV_ERR_OK) { 847e41f4b71Sopenharmony_ci // Exception handling. 848e41f4b71Sopenharmony_ci } 849e41f4b71Sopenharmony_ci // Set CencInfo to the AVBuffer. 850e41f4b71Sopenharmony_ci errNo = OH_AVCencInfo_SetAVBuffer(cencInfo, buffer); 851e41f4b71Sopenharmony_ci if (errNo != AV_ERR_OK) { 852e41f4b71Sopenharmony_ci // Exception handling. 853e41f4b71Sopenharmony_ci } 854e41f4b71Sopenharmony_ci // Destroy the CencInfo instance. 855e41f4b71Sopenharmony_ci errNo = OH_AVCencInfo_Destroy(cencInfo); 856e41f4b71Sopenharmony_ci if (errNo != AV_ERR_OK) { 857e41f4b71Sopenharmony_ci // Exception handling. 858e41f4b71Sopenharmony_ci } 859e41f4b71Sopenharmony_ci ``` 860e41f4b71Sopenharmony_ci 861e41f4b71Sopenharmony_ci9. Call **OH_VideoDecoder_PushInputBuffer()** to push the stream to the input buffer for decoding. 862e41f4b71Sopenharmony_ci 863e41f4b71Sopenharmony_ci The procedure is the same as that in surface mode and is not described here. 864e41f4b71Sopenharmony_ci 865e41f4b71Sopenharmony_ci ```c++ 866e41f4b71Sopenharmony_ci // Configure the size, offset, and timestamp of the frame data. 867e41f4b71Sopenharmony_ci OH_AVCodecBufferAttr info; 868e41f4b71Sopenharmony_ci info.size = size; 869e41f4b71Sopenharmony_ci info.offset = offset; 870e41f4b71Sopenharmony_ci info.pts = pts; 871e41f4b71Sopenharmony_ci info.flags = flags; 872e41f4b71Sopenharmony_ci // Write the information to the buffer. 873e41f4b71Sopenharmony_ci ret = OH_AVBuffer_SetBufferAttr(buffer, &info); 874e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 875e41f4b71Sopenharmony_ci // Exception handling. 876e41f4b71Sopenharmony_ci } 877e41f4b71Sopenharmony_ci // Send the data to the input buffer for decoding. index is the index of the buffer. 878e41f4b71Sopenharmony_ci int32_t ret = OH_VideoDecoder_PushInputBuffer(videoDec, index); 879e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 880e41f4b71Sopenharmony_ci // Exception handling. 881e41f4b71Sopenharmony_ci } 882e41f4b71Sopenharmony_ci ``` 883e41f4b71Sopenharmony_ci 884e41f4b71Sopenharmony_ci10. Call **OH_VideoDecoder_FreeOutputBuffer()** to release decoded frames. 885e41f4b71Sopenharmony_ci 886e41f4b71Sopenharmony_ci In the code snippet below, the following variables are used: 887e41f4b71Sopenharmony_ci 888e41f4b71Sopenharmony_ci - **index**: parameter passed by the callback function **OnNewOutputBuffer**, which uniquely corresponds to the buffer. 889e41f4b71Sopenharmony_ci - **buffer**: parameter passed by the callback function **OnNewOutputBuffer**. You can obtain the virtual address of the image by calling **OH_AVBuffer_GetAddr**. 890e41f4b71Sopenharmony_ci 891e41f4b71Sopenharmony_ci ```c++ 892e41f4b71Sopenharmony_ci // Obtain the decoded information. 893e41f4b71Sopenharmony_ci OH_AVCodecBufferAttr info; 894e41f4b71Sopenharmony_ci int32_t ret = OH_AVBuffer_GetBufferAttr(buffer, &info); 895e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 896e41f4b71Sopenharmony_ci // Exception handling. 897e41f4b71Sopenharmony_ci } 898e41f4b71Sopenharmony_ci // Write the decoded data (specified by data) to the output file. 899e41f4b71Sopenharmony_ci outputFile->write(reinterpret_cast<char *>(OH_AVBuffer_GetAddr(buffer)), info.size); 900e41f4b71Sopenharmony_ci // Free the buffer that stores the output data. index is the index of the buffer. 901e41f4b71Sopenharmony_ci ret = OH_VideoDecoder_FreeOutputBuffer(videoDec, index); 902e41f4b71Sopenharmony_ci if (ret != AV_ERR_OK) { 903e41f4b71Sopenharmony_ci // Exception handling. 904e41f4b71Sopenharmony_ci } 905e41f4b71Sopenharmony_ci ``` 906e41f4b71Sopenharmony_ci 907e41f4b71Sopenharmony_ci To copy the Y, U, and V components of an NV12 or NV21 image to another buffer in sequence, perform the following steps (taking an NV12 image as an example), presenting the image layout of **width**, **height**, **wStride**, and **hStride**. 908e41f4b71Sopenharmony_ci 909e41f4b71Sopenharmony_ci - **OH_MD_KEY_VIDEO_PIC_WIDTH** corresponds to **width**. 910e41f4b71Sopenharmony_ci - **OH_MD_KEY_VIDEO_PIC_HEIGHT** corresponds to **height**. 911e41f4b71Sopenharmony_ci - **OH_MD_KEY_VIDEO_STRIDE** corresponds to **wStride**. 912e41f4b71Sopenharmony_ci - **OH_MD_KEY_VIDEO_SLICE_HEIGHT** corresponds to **hStride**. 913e41f4b71Sopenharmony_ci 914e41f4b71Sopenharmony_ci  915e41f4b71Sopenharmony_ci 916e41f4b71Sopenharmony_ci Add the header files. 917e41f4b71Sopenharmony_ci 918e41f4b71Sopenharmony_ci ```c++ 919e41f4b71Sopenharmony_ci #include <string.h> 920e41f4b71Sopenharmony_ci ``` 921e41f4b71Sopenharmony_ci The following is the sample code: 922e41f4b71Sopenharmony_ci 923e41f4b71Sopenharmony_ci ```c++ 924e41f4b71Sopenharmony_ci struct Rect // Width and height of the source buffer. They are obtained by calling OnNewOutputBuffer. 925e41f4b71Sopenharmony_ci { 926e41f4b71Sopenharmony_ci int32_t width; 927e41f4b71Sopenharmony_ci int32_t height; 928e41f4b71Sopenharmony_ci }; 929e41f4b71Sopenharmony_ci 930e41f4b71Sopenharmony_ci struct DstRect // Width stride and height stride of the destination buffer. They are set by the caller. 931e41f4b71Sopenharmony_ci { 932e41f4b71Sopenharmony_ci int32_t wStride; 933e41f4b71Sopenharmony_ci int32_t hStride; 934e41f4b71Sopenharmony_ci }; 935e41f4b71Sopenharmony_ci 936e41f4b71Sopenharmony_ci struct SrcRect // Width stride and height stride of the source buffer. They are obtained by calling OnNewOutputBuffer. 937e41f4b71Sopenharmony_ci { 938e41f4b71Sopenharmony_ci int32_t wStride; 939e41f4b71Sopenharmony_ci int32_t hStride; 940e41f4b71Sopenharmony_ci }; 941e41f4b71Sopenharmony_ci 942e41f4b71Sopenharmony_ci Rect rect = {320, 240}; 943e41f4b71Sopenharmony_ci DstRect dstRect = {320, 250}; 944e41f4b71Sopenharmony_ci SrcRect srcRect = {320, 250}; 945e41f4b71Sopenharmony_ci uint8_t* dst = new uint8_t[dstRect.hStride * dstRect.wStride]; // Pointer to the target memory area. 946e41f4b71Sopenharmony_ci uint8_t* src = new uint8_t[srcRect.hStride * srcRect.wStride]; // Pointer to the source memory area. 947e41f4b71Sopenharmony_ci 948e41f4b71Sopenharmony_ci // Y: Copy the source data in the Y region to the target data in another region. 949e41f4b71Sopenharmony_ci for (int32_t i = 0; i < rect.height; ++i) { 950e41f4b71Sopenharmony_ci // Copy a row of data from the source to a row of the target. 951e41f4b71Sopenharmony_ci memcpy_s(dst, src, rect.width); 952e41f4b71Sopenharmony_ci // Update the pointers to the source data and target data to copy the next row. The pointers to the source data and target data are moved downwards by one wStride each time the source data and target data are updated. 953e41f4b71Sopenharmony_ci dst += dstRect.wStride; 954e41f4b71Sopenharmony_ci src += srcRect.wStride; 955e41f4b71Sopenharmony_ci } 956e41f4b71Sopenharmony_ci // padding 957e41f4b71Sopenharmony_ci // Update the pointers to the source data and target data. The pointers move downwards by one padding. 958e41f4b71Sopenharmony_ci dst += (dstRect.hStride - rect.height) * dstRect.wStride; 959e41f4b71Sopenharmony_ci src += (srcRect.hStride - rect.height) * srcRect.wStride; 960e41f4b71Sopenharmony_ci rect.height >>= 1; 961e41f4b71Sopenharmony_ci // UV: Copy the source data in the UV region to the target data in another region. 962e41f4b71Sopenharmony_ci for (int32_t i = 0; i < rect.height; ++i) { 963e41f4b71Sopenharmony_ci memcpy_s(dst, src, rect.width); 964e41f4b71Sopenharmony_ci dst += dstRect.wStride; 965e41f4b71Sopenharmony_ci src += srcRect.wStride; 966e41f4b71Sopenharmony_ci } 967e41f4b71Sopenharmony_ci 968e41f4b71Sopenharmony_ci delete[] dst; 969e41f4b71Sopenharmony_ci dst = nullptr; 970e41f4b71Sopenharmony_ci delete[] src; 971e41f4b71Sopenharmony_ci src = nullptr; 972e41f4b71Sopenharmony_ci ``` 973e41f4b71Sopenharmony_ci 974e41f4b71Sopenharmony_ci When processing buffer data (before releasing data) during hardware decoding, the output callback AVBuffer receives the image data after width and height alignment. Generally, copy the image width, height, stride, and pixel format to ensure correct processing of the decoded data. For details, see step 3 in [Buffer Output](#buffer-output). 975e41f4b71Sopenharmony_ci 976e41f4b71Sopenharmony_ciThe subsequent processes (including refreshing, resetting, stopping, and destroying the decoder) are basically the same as those in surface mode. For details, see steps 14-17 in [Surface Output](#surface-output). 977e41f4b71Sopenharmony_ci 978e41f4b71Sopenharmony_ci<!--RP5--> 979e41f4b71Sopenharmony_ci<!--RP5End--> 980