1# Audio and Video Demuxing (C/C++) 2 3You can call the native APIs provided by the **AVDemuxer** module to demux audio and video, that is, to extract audio and video frame data from bit stream data. 4 5Currently, two data input types are supported: remote connection (over HTTP) and File Descriptor (FD). 6 7The following demuxing formats are supported: 8 9| Media Format | Muxing Format | Stream Format | 10| -------- | :----------------------------| :----------------------------| 11| Audio/Video | mp4 |Video stream: AVC (H.264); audio stream: AAC and MPEG (MP3)| 12| Audio/Video | mkv |Video stream: AVC (H.264); audio stream: AAC, MPEG (MP3), and OPUS| 13| Audio/Video | mpeg-ts |Video stream: AVC (H.264); audio stream: AAC and MPEG (MP3)| 14| Audio | m4a |Audio stream: AAC| 15| Audio | aac |Audio stream: AAC| 16| Audio | mp3 |Audio stream: MPEG (MP3)| 17| Audio | ogg |Audio stream: OGG| 18| Audio | flac |Audio stream: FLAC| 19| Audio | wav |Audio stream: PCM| 20| Audio | amr |Audio stream: AMR (AMR-NB and AMR-WB)| 21 22**Usage Scenario** 23 24- Audio and video playback 25 26 Demux audio and video streams, decode the frame data obtained through demuxing, and play the decoded data. 27 28- Audio and video editing 29 30 Demux audio and video streams, and edit the specified frames. 31 32- Media file format conversion 33 34 Demux audio and video streams, and encapsulate them into a new file format. 35 36## How to Develop 37 38Read [AVDemuxer](../reference/apis-avcodec-kit/_a_v_demuxer.md) and [AVSource](../reference/apis-avcodec-kit/_a_v_source.md) for the API reference. 39 40> **NOTE** 41> 42> - To call the demuxing APIs to parse a network playback path, declare the **ohos.permission.INTERNET** permission by following the instructions provided in [Declaring Permissions](../security/AccessToken/declare-permissions.md). 43> - To call the demuxer APIs to write a local file, request the **ohos.permission.READ_MEDIA** permission by following the instructions provided in [Requesting User Authorization](../security/AccessToken/request-user-authorization.md). 44> - You can also use **ResourceManager.getRawFd** to obtain the FD of a file packed in the HAP file. For details, see [ResourceManager API Reference](../reference/apis-localization-kit/js-apis-resource-manager.md#getrawfd9). 45 46### Linking the Dynamic Library in the CMake Script 47 48``` cmake 49target_link_libraries(sample PUBLIC libnative_media_avdemuxer.so) 50target_link_libraries(sample PUBLIC libnative_media_avsource.so) 51target_link_libraries(sample PUBLIC libnative_media_core.so) 52``` 53 54### How to Develop 55 561. Add the header files. 57 58 ```c++ 59 #include <multimedia/player_framework/native_avdemuxer.h> 60 #include <multimedia/player_framework/native_avsource.h> 61 #include <multimedia/player_framework/native_avcodec_base.h> 62 #include <multimedia/player_framework/native_avformat.h> 63 #include <multimedia/player_framework/native_avbuffer.h> 64 ``` 65 662. Create a demuxer instance. 67 68 ```c++ 69 // Create the FD. You must have the read permission on the file handle when opening the file. (filePath indicates the path of the file to be demuxed. The file must exist.) 70 std::string filePath = "test.mp4"; 71 int fd = open(filePath.c_str(), O_RDONLY); 72 struct stat fileStatus {}; 73 size_t fileSize = 0; 74 if (stat(filePath.c_str(), &fileStatus) == 0) { 75 fileSize = static_cast<size_t>(fileStatus.st_size); 76 } else { 77 printf("get stat failed"); 78 return; 79 } 80 // Create a source resource object for the FD resource file. If offset is not the start position of the file or size is not the actual file size, the data obtained may be incomplete. Consequently, the source resource object may fail to create or subsequent demuxing may fail. 81 OH_AVSource *source = OH_AVSource_CreateWithFD(fd, 0, fileSize); 82 if (source == nullptr) { 83 printf("create source failed"); 84 return; 85 } 86 // (Optional) Create a source resource object for the URI resource file. 87 // OH_AVSource *source = OH_AVSource_CreateWithURI(uri); 88 ``` 89 90 ```c++ 91 // Create a demuxer for the resource object. 92 OH_AVDemuxer *demuxer = OH_AVDemuxer_CreateWithSource(source); 93 if (demuxer == nullptr) { 94 printf("create demuxer failed"); 95 return; 96 } 97 ``` 983. (Optional) Register a [callback to obtain the media key system information](../reference/apis-drm-kit/_drm.md#drm_mediakeysysteminfocallback). If the stream is not a DRM stream or the [media key system information](../reference/apis-drm-kit/_drm.md#drm_mediakeysysteminfo) has been obtained, you can skip this step. 99 100 Import the header file. 101 ```c++ 102 #include <multimedia/drm_framework/native_drm_common.h> 103 ``` 104 Link the dynamic library in the cmake script. 105 106 ``` cmake 107 target_link_libraries(sample PUBLIC libnative_drm.so) 108 ``` 109 110 The following is the sample code: 111 ```c++ 112 // Implement the OnDrmInfoChanged callback. 113 static void OnDrmInfoChanged(DRM_MediaKeySystemInfo *drmInfo) 114 { 115 // Parse the media key system information, including the quantity, DRM type, and corresponding PSSH. 116 } 117 118 // Set the asynchronous callbacks. 119 DRM_MediaKeySystemInfoCallback callback = &OnDrmInfoChanged; 120 int32_t ret = OH_AVDemuxer_SetMediaKeySystemInfoCallback(demuxer, callback); 121 122 // After the callback is invoked, you can call the API to proactively obtain the media key system information. 123 DRM_MediaKeySystemInfo mediaKeySystemInfo; 124 OH_AVDemuxer_GetMediaKeySystemInfo(demuxer, &mediaKeySystemInfo); 125 ``` 126 1274. (Optional) Obtain the number of tracks. If you know the track information, skip this step. 128 129 ```c++ 130 // Obtain the number of tracks from the file source information. 131 OH_AVFormat *sourceFormat = OH_AVSource_GetSourceFormat(source); 132 if (sourceFormat == nullptr) { 133 printf("get source format failed"); 134 return; 135 } 136 int32_t trackCount = 0; 137 OH_AVFormat_GetIntValue(sourceFormat, OH_MD_KEY_TRACK_COUNT, &trackCount); 138 OH_AVFormat_Destroy(sourceFormat); 139 ``` 140 1415. (Optional) Obtain the track index and format. If you know the track information, skip this step. 142 143 ```c++ 144 uint32_t audioTrackIndex = 0; 145 uint32_t videoTrackIndex = 0; 146 int32_t w = 0; 147 int32_t h = 0; 148 int32_t trackType; 149 for (uint32_t index = 0; index < (static_cast<uint32_t>(trackCount)); index++) { 150 // Obtain the track format. 151 OH_AVFormat *trackFormat = OH_AVSource_GetTrackFormat(source, index); 152 if (trackFormat == nullptr) { 153 printf("get track format failed"); 154 return; 155 } 156 OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_TRACK_TYPE, &trackType); 157 static_cast<OH_MediaType>(trackType) == OH_MediaType::MEDIA_TYPE_AUD ? audioTrackIndex = index : videoTrackIndex = index; 158 // Obtain the width and height of the video track. 159 if (trackType == OH_MediaType::MEDIA_TYPE_VID) { 160 OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_WIDTH, &w); 161 OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_HEIGHT, &h); 162 } 163 OH_AVFormat_Destroy(trackFormat); 164 } 165 ``` 166 1676. Select a track, from which the demuxer reads data. 168 169 ```c++ 170 if(OH_AVDemuxer_SelectTrackByID(demuxer, audioTrackIndex) != AV_ERR_OK){ 171 printf("select audio track failed: %d", audioTrackIndex); 172 return; 173 } 174 if(OH_AVDemuxer_SelectTrackByID(demuxer, videoTrackIndex) != AV_ERR_OK){ 175 printf("select video track failed: %d", videoTrackIndex); 176 return; 177 } 178 // (Optional) Deselect the track. 179 // OH_AVDemuxer_UnselectTrackByID(demuxer, audioTrackIndex); 180 ``` 181 1827. (Optional) Seek to the specified time for the selected track. 183 184 ```c++ 185 // Demuxing is performed from this time. 186 // Note: 187 // 1. If OH_AVDemuxer_SeekToTime is called for an MPEG TS file, the target position may be a non-key frame. You can then call OH_AVDemuxer_ReadSampleBuffer to check whether the current frame is a key frame based on the obtained OH_AVCodecBufferAttr. If it is a non-key frame, which causes display issues on the application side, cyclically read the frames until you reach the first key frame, where you can perform processing such as decoding. 188 // 2. If OH_AVDemuxer_SeekToTime is called for an OGG file, the file seeks to the start of the time interval (second) where the input parameter millisecond is located, which may cause a certain number of frame errors. 189 OH_AVDemuxer_SeekToTime(demuxer, 0, OH_AVSeekMode::SEEK_MODE_CLOSEST_SYNC); 190 ``` 191 1928. Start demuxing and cyclically obtain frame data. The code snippet below uses a file that contains audio and video tracks as an example. 193 194 ```c++ 195 // Create a buffer to store the data obtained after demuxing. 196 OH_AVBuffer *buffer = OH_AVBuffer_Create(w * h * 3 >> 1); 197 if (buffer == nullptr) { 198 printf("build buffer failed"); 199 return; 200 } 201 OH_AVCodecBufferAttr info; 202 bool videoIsEnd = false; 203 bool audioIsEnd = false; 204 int32_t ret; 205 while (!audioIsEnd || !videoIsEnd) { 206 // Before calling OH_AVDemuxer_ReadSampleBuffer, call OH_AVDemuxer_SelectTrackByID to select the track from which the demuxer reads data. 207 // Obtain audio frame data. 208 if(!audioIsEnd) { 209 ret = OH_AVDemuxer_ReadSampleBuffer(demuxer, audioTrackIndex, buffer); 210 if (ret == AV_ERR_OK) { 211 // Obtain the process the audio frame data in the buffer. 212 OH_AVBuffer_GetBufferAttr(buffer, &info); 213 printf("audio info.size: %d\n", info.size); 214 if (info.flags == OH_AVCodecBufferFlags::AVCODEC_BUFFER_FLAGS_EOS) { 215 audioIsEnd = true; 216 } 217 } 218 } 219 if(!videoIsEnd) { 220 ret = OH_AVDemuxer_ReadSampleBuffer(demuxer, videoTrackIndex, buffer); 221 if (ret == AV_ERR_OK) { 222 // Obtain the process the video frame data in the buffer. 223 OH_AVBuffer_GetBufferAttr(buffer, &info); 224 printf("video info.size: %d\n", info.size); 225 if (info.flags == OH_AVCodecBufferFlags::AVCODEC_BUFFER_FLAGS_EOS) { 226 videoIsEnd = true; 227 } 228 } 229 } 230 } 231 OH_AVBuffer_Destroy(buffer); 232 ``` 233 2349. Destroy the demuxer instance. 235 236 ```c++ 237 // Manually set the instance to NULL after OH_AVSource_Destroy is called. Do not call this API repeatedly for the same instance; otherwise, a program error occurs. 238 if (OH_AVSource_Destroy(source) != AV_ERR_OK) { 239 printf("destroy source pointer error"); 240 } 241 source = NULL; 242 // Manually set the instance to NULL after OH_AVDemuxer_Destroy is called. Do not call this API repeatedly for the same instance; otherwise, a program error occurs. 243 if (OH_AVDemuxer_Destroy(demuxer) != AV_ERR_OK) { 244 printf("destroy demuxer pointer error"); 245 } 246 demuxer = NULL; 247 close(fd); 248 ``` 249