1# Media Data Demultiplexing 2 3You can call the native APIs provided by the AVDemuxer module to demultiplex media data. The demultiplexing involves extracting media samples such as audio, video, and subtitles from bit stream data, and obtaining information related to Digital Rights Management (DRM). 4 5Currently, two data input types are supported: remote connection (over HTTP) and File Descriptor (FD). 6 7For details about the supported demultiplexing formats, see [AVCodec Supported Formats](avcodec-support-formats.md#media-data-demultiplexing). 8 9**Usage Scenario** 10 11- Audio and video playback 12 13 Demultiplex media streams, decode the samples obtained through demultiplexing, and play the samples. 14 15- Audio and video editing 16 17 Demultiplex media streams, and edit the specified samples. 18 19- Media file format conversion 20 21 Demultiplex media streams, and encapsulate them into a new file format. 22 23## How to Develop 24 25Read [AVDemuxer](../../reference/apis-avcodec-kit/_a_v_demuxer.md) and [AVSource](../../reference/apis-avcodec-kit/_a_v_source.md) for the API reference. 26 27> **NOTE** 28> 29> - To call the demuxer 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). 30> - 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). 31> - 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). 32 33### Linking the Dynamic Libraries in the CMake Script 34 35``` cmake 36target_link_libraries(sample PUBLIC libnative_media_codecbase.so) 37target_link_libraries(sample PUBLIC libnative_media_avdemuxer.so) 38target_link_libraries(sample PUBLIC libnative_media_avsource.so) 39target_link_libraries(sample PUBLIC libnative_media_core.so) 40``` 41 42> **NOTE** 43> 44> The word **sample** in the preceding code snippet is only an example. Use the actual project directory name. 45> 46 47### How to Develop 48 491. Add the header files. 50 51 ```c++ 52 #include <multimedia/player_framework/native_avdemuxer.h> 53 #include <multimedia/player_framework/native_avsource.h> 54 #include <multimedia/player_framework/native_avcodec_base.h> 55 #include <multimedia/player_framework/native_avformat.h> 56 #include <multimedia/player_framework/native_avbuffer.h> 57 #include <fcntl.h> 58 #include <sys/stat.h> 59 ``` 60 612. Create a resource instance. 62 63 When using **open** to obtain the FD, convert the value of **filepath** to a [sandbox path](../../file-management/app-sandbox-directory.md#mappings-between-application-sandbox-paths-and-physical-paths) to obtain sandbox resources. 64 65 ```c++ 66 // Create the FD. You must have the read permission on the file instance to open the file. (filePath indicates the path of the file to be demultiplexed. The file must exist.) 67 std::string filePath = "test.mp4"; 68 int fd = open(filePath.c_str(), O_RDONLY); 69 struct stat fileStatus {}; 70 size_t fileSize = 0; 71 if (stat(filePath.c_str(), &fileStatus) == 0) { 72 fileSize = static_cast<size_t>(fileStatus.st_size); 73 } else { 74 printf("get stat failed"); 75 return; 76 } 77 // Create a source resource instance 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 demultiplexing may fail. 78 OH_AVSource *source = OH_AVSource_CreateWithFD(fd, 0, fileSize); 79 if (source == nullptr) { 80 printf("create source failed"); 81 return; 82 } 83 // (Optional) Create a source resource instance for the URI resource file. 84 // OH_AVSource *source = OH_AVSource_CreateWithURI(uri); 85 86 // (Optional) Create a source resource instance for the custom data source. Before the operation, you must implement AVSourceReadAt. 87 // Add g_filePath when OH_AVSource_CreateWithDataSource is used. 88 // g_filePath = filePath ; 89 // OH_AVDataSource dataSource = {fileSize, AVSourceReadAt}; 90 // OH_AVSource *source = OH_AVSource_CreateWithDataSource(&dataSource); 91 ``` 92 93 Implement the **AVSourceReadAt** API before creating the resource instance. 94 95 ```c++ 96 // Add the header file. 97 #include <fstream> 98 ``` 99 100 ```c++ 101 static std::string g_filePath; 102 103 enum MediaDataSourceError : int32_t { 104 SOURCE_ERROR_IO = -2, 105 SOURCE_ERROR_EOF = -1 106 }; 107 108 int32_t AVSourceReadAt(OH_AVBuffer *data, int32_t length, int64_t pos) 109 { 110 if (data == nullptr) { 111 printf("AVSourceReadAt : data is nullptr!\n"); 112 return MediaDataSourceError::SOURCE_ERROR_IO; 113 } 114 115 std::ifstream infile(g_filePath, std::ofstream::binary); 116 if (!infile.is_open()) { 117 printf("AVSourceReadAt : open file failed! file:%s\n", g_filePath.c_str()); 118 return MediaDataSourceError::SOURCE_ERROR_IO; // Failed to open the file. 119 } 120 121 infile.seekg(0, std::ios::end); 122 int64_t fileSize = infile.tellg(); 123 if (pos >= fileSize) { 124 printf("AVSourceReadAt : pos over or equals file size!\n"); 125 return MediaDataSourceError::SOURCE_ERROR_EOF; // pos is already at the end of the file and cannot be read. 126 } 127 128 if (pos + length > fileSize) { 129 length of length = fileSize - pos; // When the sum of pos and length exceeds the file size, the data from pos to the end of the file is read. 130 } 131 132 infile.seekg(pos, std::ios::beg); 133 if (length <= 0) { 134 printf("AVSourceReadAt : raed length less than zero!\n"); 135 return MediaDataSourceError::SOURCE_ERROR_IO; 136 } 137 char* buffer = new char[length]; 138 infile.read(buffer, length); 139 infile.close(); 140 141 memcpy(reinterpret_cast<char *>(OH_AVBuffer_GetAddr(data)), 142 buffer, length); 143 delete[] buffer; 144 145 return length; 146 } 147 ``` 1483. Create a demuxer instance. 149 ```c++ 150 // Create a demuxer for the resource instance. 151 OH_AVDemuxer *demuxer = OH_AVDemuxer_CreateWithSource(source); 152 if (demuxer == nullptr) { 153 printf("create demuxer failed"); 154 return; 155 } 156 ``` 1574. (Optional) Register a [callback to obtain the media key system information](../../reference/apis-avcodec-kit/_a_v_demuxer.md#demuxer_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. 158 159 In the API for setting DRM information listeners, the callback function can return a demuxer instance. It is suitable for the scenario where multiple demuxer instances are used. 160 161 ```c++ 162 // Implement the OnDrmInfoChangedWithObj callback. 163 static void OnDrmInfoChangedWithObj(OH_AVDemuxer *demuxer, DRM_MediaKeySystemInfo *drmInfo) 164 { 165 // Parse the media key system information, including the quantity, DRM type, and corresponding PSSH. 166 } 167 168 Demuxer_MediaKeySystemInfoCallback callback = &OnDrmInfoChangedWithObj; 169 Drm_ErrCode ret = OH_AVDemuxer_SetDemuxerMediaKeySystemInfoCallback(demuxer, callback); 170 ``` 171 After the callback is invoked, you can call the API to proactively obtain the media key system information (UUID and corresponding PSSH). 172 173 ```c++ 174 DRM_MediaKeySystemInfo mediaKeySystemInfo; 175 OH_AVDemuxer_GetMediaKeySystemInfo(demuxer, &mediaKeySystemInfo); 176 ``` 177 After obtaining and parsing DRM information, create [MediaKeySystem and MediaKeySession](../drm/drm-c-dev-guide.md) instances of the corresponding DRM scheme to obtain a media key. If required, set the audio decryption configuration by following step 4 in [Audio Decoding](audio-decoding.md#how-to-develop), and set the video decryption configuration by following step 5 in [Surface Output in Video Decoding](video-decoding.md#surface-mode) or step 4 in [Buffer Output in Video Decoding](video-decoding.md#buffer-mode). 178 1795. Obtain file information. 180 181 ```c++ 182 // (Optional) Obtain custom file attributes. If custom file attributes are not required, skip this step. 183 // Obtain custom attributes from the source file. 184 OH_AVFormat *customMetadataFormat = OH_AVSource_GetCustomMetadataFormat(source); 185 if (customMetadataFormat == nullptr) { 186 printf("get custom metadata format failed"); 187 return; 188 } 189 // Precautions: 190 // 1. customKey must exactly match the key used during multiplexing (including the complete naming hierarchy). 191 // The example key is for demonstration only. Replace it with the actual custom string. 192 // For example, if the key used during multiplexing is com.openharmony.custom.meta.abc.efg, 193 // you must use the full key. Using a truncated key like com.openharmony.custom.meta.abc will fail. 194 // 2. The type of value must match the data type used during multiplexing. (The example uses a string type. For int or float, use the corresponding interface.) 195 const char *customKey = "com.openharmony.custom.meta.string"; // Replace it with the actual key used during multiplexing. 196 const char *customValue; 197 if (!OH_AVFormat_GetStringValue(customMetadataFormat, customKey, &customValue)) { 198 printf("get custom metadata from custom metadata format failed"); 199 return; 200 } 201 OH_AVFormat_Destroy(customMetadataFormat); 202 203 // (Optional) Obtain the number of tracks. If you know the track information, skip this step. 204 // Obtain the number of tracks from the file source information. You can call the API to obtain file-level attributes. For details, see Table 1 in Appendix 1. 205 OH_AVFormat *sourceFormat = OH_AVSource_GetSourceFormat(source); 206 if (sourceFormat == nullptr) { 207 printf("get source format failed"); 208 return; 209 } 210 int32_t trackCount = 0; 211 if (!OH_AVFormat_GetIntValue(sourceFormat, OH_MD_KEY_TRACK_COUNT, &trackCount)) { 212 printf("get track count from source format failed"); 213 return; 214 } 215 OH_AVFormat_Destroy(sourceFormat); 216 ``` 217 2186. (Optional) Obtain the track index and format. If you know the track information, skip this step. 219 220 ```c++ 221 uint32_t audioTrackIndex = 0; 222 uint32_t videoTrackIndex = 0; 223 int32_t w = 0; 224 int32_t h = 0; 225 int32_t trackType; 226 for (uint32_t index = 0; index < (static_cast<uint32_t>(trackCount)); index++) { 227 // Obtain the track information. You can call the API to obtain track-level attributes. For details, see Table 2 in Appendix. 228 OH_AVFormat *trackFormat = OH_AVSource_GetTrackFormat(source, index); 229 if (trackFormat == nullptr) { 230 printf("get track format failed"); 231 return; 232 } 233 if (!OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_TRACK_TYPE, &trackType)) { 234 printf("get track type from track format failed"); 235 return; 236 } 237 static_cast<OH_MediaType>(trackType) == OH_MediaType::MEDIA_TYPE_AUD ? audioTrackIndex = index : videoTrackIndex = index; 238 // Obtain the width and height of the video track. 239 if (trackType == OH_MediaType::MEDIA_TYPE_VID) { 240 if (!OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_WIDTH, &w)) { 241 printf("get track width from track format failed"); 242 return; 243 } 244 if (!OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_HEIGHT, &h)) { 245 printf("get track height from track format failed"); 246 return; 247 } 248 } 249 OH_AVFormat_Destroy(trackFormat); 250 } 251 ``` 252 2537. Select a track, from which the demuxer reads data. 254 255 ```c++ 256 if(OH_AVDemuxer_SelectTrackByID(demuxer, audioTrackIndex) != AV_ERR_OK){ 257 printf("select audio track failed: %d", audioTrackIndex); 258 return; 259 } 260 if(OH_AVDemuxer_SelectTrackByID(demuxer, videoTrackIndex) != AV_ERR_OK){ 261 printf("select video track failed: %d", videoTrackIndex); 262 return; 263 } 264 // (Optional) Deselect the track. 265 // OH_AVDemuxer_UnselectTrackByID(demuxer, audioTrackIndex); 266 ``` 267 2688. (Optional) Seek to the specified time for the selected track. 269 270 ```c++ 271 // Demultiplexing is performed from this time. 272 // Note: 273 // 1. If OH_AVDemuxer_SeekToTime is called for an MPEG TS or MPG 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. 274 // 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. 275 // 3. The seek operation of the demuxer is performed only on streams with consistent decoding behavior. If a stream requires the decoder to reconfigure or re-input parameter data after seeking to decode correctly, it may result in artifacts or decoder freezing. 276 OH_AVDemuxer_SeekToTime(demuxer, 0, OH_AVSeekMode::SEEK_MODE_CLOSEST_SYNC); 277 ``` 278 2799. Start demultiplexing and cyclically obtain samples. The code snippet below uses a file that contains audio and video tracks as an example. 280 281 A **BufferAttr** object contains the following attributes. 282 - **size**: sample size. 283 - **offset**: offset of the data in the AVBuffer. The value is generally 0. 284 - **pts**: timestamp when the file is multiplexed. 285 - **flags**: sample attributes. 286 287 | flag | Description| 288 | -------- | -------- | 289 | AVCODEC_BUFFER_FLAGS_NONE | Default value.| 290 | AVCODEC_BUFFER_FLAGS_EOS | End of Stream (EOS). The data is empty.| 291 | AVCODEC_BUFFER_FLAGS_SYNC_FRAME | IDR frame or I-frame.| 292 | AVCODEC_BUFFER_FLAGS_INCOMPLETE_FRAME | Incomplete sample. Generally, a complete sample fails to be copied because the buffer is too small.| 293 | AVCODEC_BUFFER_FLAGS_CODEC_DATA | Frame containing parameter set information.| 294 | AVCODEC_BUFFER_FLAGS_DISCARD | Frames that can be discarded.| 295 296 ```c++ 297 // Create a buffer based on the specified size to store the data obtained after demultiplexing. 298 // It is recommended that the buffer size be greater than the size of the stream to be obtained. In the example, the buffer size is set to the size of a single frame. 299 OH_AVBuffer *buffer = OH_AVBuffer_Create(w * h * 3 >> 1); 300 if (buffer == nullptr) { 301 printf("build buffer failed"); 302 return; 303 } 304 OH_AVCodecBufferAttr info; 305 bool videoIsEnd = false; 306 bool audioIsEnd = false; 307 int32_t ret; 308 while (!audioIsEnd || !videoIsEnd) { 309 // Before calling OH_AVDemuxer_ReadSampleBuffer, call OH_AVDemuxer_SelectTrackByID to select the track from which the demuxer reads data. 310 // Note: 311 // For AVI format, since the container standard does not support encapsulating timestamp information, the demultiplexed frames do not contain PTS information. The caller needs to calculate display timestamps based on the frame rate and the display order of the decoded frames. 312 // Obtain the audio sample. 313 if(!audioIsEnd) { 314 ret = OH_AVDemuxer_ReadSampleBuffer(demuxer, audioTrackIndex, buffer); 315 if (ret == AV_ERR_OK) { 316 // Obtain and process the audio sample in the buffer. 317 OH_AVBuffer_GetBufferAttr(buffer, &info); 318 printf("audio info.size: %d\n", info.size); 319 if (info.flags == OH_AVCodecBufferFlags::AVCODEC_BUFFER_FLAGS_EOS) { 320 audioIsEnd = true; 321 } 322 } 323 } 324 if(!videoIsEnd) { 325 ret = OH_AVDemuxer_ReadSampleBuffer(demuxer, videoTrackIndex, buffer); 326 if (ret == AV_ERR_OK) { 327 // Obtain and process the video sample in the buffer. 328 OH_AVBuffer_GetBufferAttr(buffer, &info); 329 printf("video info.size: %d\n", info.size); 330 if (info.flags == OH_AVCodecBufferFlags::AVCODEC_BUFFER_FLAGS_EOS) { 331 videoIsEnd = true; 332 } 333 } 334 } 335 } 336 OH_AVBuffer_Destroy(buffer); 337 ``` 338 33910. Destroy the demuxer instance. 340 ```c++ 341 // Manually set the instance to a null pointer after OH_AVSource_Destroy is called. Do not call this API repeatedly for the same instance; otherwise, a program error occurs. 342 if (OH_AVSource_Destroy(source) != AV_ERR_OK) { 343 printf("destroy source pointer error"); 344 } 345 source = nullptr; 346 // Manually set the instance to a null pointer after OH_AVDemuxer_Destroy is called. Do not call this API repeatedly for the same instance; otherwise, a program error occurs. 347 if (OH_AVDemuxer_Destroy(demuxer) != AV_ERR_OK) { 348 printf("destroy demuxer pointer error"); 349 } 350 demuxer = nullptr; 351 close(fd); 352 ``` 353 354## Appendix 355### Supported File-Level Attributes 356 357> **NOTE** 358> 359> Attribute data can be obtained only when the file is parsed normally. If the file information is incorrect or missing, the parsing is abnormal and the corresponding data cannot be obtained. 360> 361> Currently, data in the GBK character set is converted to UTF-8. If other character sets need to be converted to UTF-8, you must handle the conversion. For details, see [icu4c](../../reference/native-lib/icu4c.md). 362> 363> For details about the data type and value range, see [Media Data Key-Value Pairs](../../reference/apis-avcodec-kit/_codec_base.md#media-data-key-value-pairs). 364 365**Table 1** Supported file-level attributes 366| Name| Description| 367| -- | -- | 368|OH_MD_KEY_TITLE|Title.| 369|OH_MD_KEY_ARTIST|Artist.| 370|OH_MD_KEY_ALBUM|Album.| 371|OH_MD_KEY_ALBUM_ARTIST|Album artist.| 372|OH_MD_KEY_DATE|Date.| 373|OH_MD_KEY_COMMENT|Comment.| 374|OH_MD_KEY_GENRE|Genre.| 375|OH_MD_KEY_COPYRIGHT|Copyright.| 376|OH_MD_KEY_LANGUAGE|Language.| 377|OH_MD_KEY_DESCRIPTION|Description.| 378|OH_MD_KEY_LYRICS|Lyrics.| 379|OH_MD_KEY_TRACK_COUNT|Track count.| 380|OH_MD_KEY_DURATION|Duration.| 381|OH_MD_KEY_START_TIME|Start time.| 382 383### Supported Track-Level Attributes 384 385> **NOTE** 386> 387> Attribute data can be obtained only when the file is parsed normally. If the file information is incorrect or missing, the parsing is abnormal and the corresponding data cannot be obtained. 388> 389> For details about the data type and value range, see [Media Data Key-Value Pairs](../../reference/apis-avcodec-kit/_codec_base.md#media-data-key-value-pairs). 390 391**Table 2** Supported track-level attributes 392| Name| Description| Supported by Video Tracks| Supported by Audio Tracks| Supported by Subtitle Tracks| 393| -- | -- | -- | -- | -- | 394|OH_MD_KEY_CODEC_MIME|Stream codec type.|Supported|Supported|Supported| 395|OH_MD_KEY_TRACK_TYPE|Stream track type.|Supported|Supported|Supported| 396|OH_MD_KEY_TRACK_START_TIME|Start time of the stream.|Supported|Supported|Supported| 397|OH_MD_KEY_BITRATE|Stream bit rate.|Supported|Supported|Not supported| 398|OH_MD_KEY_LANGUAGE|Stream language type.|Supported|Supported|Not supported| 399|OH_MD_KEY_CODEC_CONFIG|Codec-specific data. In the case of video, a parameter set is transferred. In the case of audio, parameter configuration information of the decoder is transferred.|Supported|Supported|Not supported| 400|OH_MD_KEY_WIDTH|Video stream width.|Supported|Not supported|Not supported| 401|OH_MD_KEY_HEIGHT|Video stream height.|Supported|Not supported|Not supported| 402|OH_MD_KEY_FRAME_RATE|Video stream frame rate.|Supported|Not supported|Not supported| 403|OH_MD_KEY_ROTATION|Rotation angle of the video stream.|Supported|Not supported|Not supported| 404|OH_MD_KEY_VIDEO_SAR|Aspect ratio of the video stream sample.|Supported|Not supported|Not supported| 405|OH_MD_KEY_PROFILE|Encoding profile of the video stream. This key is valid only for H.265 streams.|Supported|Not supported|Not supported| 406|OH_MD_KEY_RANGE_FLAG|Video YUV value range flag of the video stream. This key is valid only for H.265 streams.|Supported|Not supported|Not supported| 407|OH_MD_KEY_COLOR_PRIMARIES|Video primary color of the video stream. This key is valid only for H.265 streams.|Supported|Not supported|Not supported| 408|OH_MD_KEY_TRANSFER_CHARACTERISTICS|Video transfer characteristics of the video stream. This key is valid only for H.265 streams.|Supported|Not supported|Not supported| 409|OH_MD_KEY_MATRIX_COEFFICIENTS|Video matrix coefficient. This key is valid only for H.265 streams.|Supported|Not supported|Not supported| 410|OH_MD_KEY_VIDEO_IS_HDR_VIVID|Flag indicating whether the video stream is HDR Vivid. This key is valid only for HDR Vivid streams.|Supported|Not supported|Not supported| 411|OH_MD_KEY_AUD_SAMPLE_RATE|Audio stream sampling rate.|Not supported|Supported|Not supported| 412|OH_MD_KEY_AUD_CHANNEL_COUNT|Number of audio stream channels.|Not supported|Supported|Not supported| 413|OH_MD_KEY_CHANNEL_LAYOUT|Encoding channel layout required by the audio stream.|Not supported|Supported|Not supported| 414|OH_MD_KEY_AUDIO_SAMPLE_FORMAT|Audio stream sample format.|Not supported|Supported|Not supported| 415|OH_MD_KEY_AAC_IS_ADTS|AAC format. This key is valid only for AAC streams.|Not supported|Supported|Not supported| 416|OH_MD_KEY_BITS_PER_CODED_SAMPLE|Number of bits per coded sample in the audio stream.|Not supported|Supported|Not supported| 417