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![Invoking relationship of state](figures/state-invocation.png)
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![Call relationship of video decoding](figures/video-decode.png)
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    ![copy by line](figures/copy-by-line.png)
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