1# Media Data Demultiplexing 2 3<!--Kit: AVCodec Kit--> 4<!--Subsystem: Multimedia--> 5<!--Owner: @zhanghongran--> 6<!--Designer: @dpy2650---> 7<!--Tester: @cyakee--> 8<!--Adviser: @zengyawen--> 9 10You can call native APIs 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). 11 12Currently, two data input types are supported: remote connection (over HTTP) and File Descriptor (FD). 13 14For details about the supported demultiplexing formats, see [AVCodec Supported Formats](avcodec-support-formats.md#media-data-demultiplexing). 15 16**When to Use** 17 18- Audio and video playback 19 20 Demultiplex media streams, decode the samples obtained through demultiplexing, and play the samples. 21 22- Audio and video editing 23 24 Demultiplex media streams, and edit the specified samples. 25 26- Media file format conversion 27 28 Demultiplex media streams, and encapsulate them into a new file format. 29 30## Development Guidelines 31 32Read [AVDemuxer](../../reference/apis-avcodec-kit/_a_v_demuxer.md) and [AVSource](../../reference/apis-avcodec-kit/_a_v_source.md) for the API reference. 33 34> **NOTE** 35> 36> - 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). 37> - 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). 38> - 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). 39 40### Linking the Dynamic Libraries in the CMake Script 41 42``` cmake 43target_link_libraries(sample PUBLIC libnative_media_codecbase.so) 44target_link_libraries(sample PUBLIC libnative_media_avdemuxer.so) 45target_link_libraries(sample PUBLIC libnative_media_avsource.so) 46target_link_libraries(sample PUBLIC libnative_media_core.so) 47``` 48 49> **NOTE** 50> 51> The word **sample** in the preceding code snippet is only an example. Use the actual project directory name. 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 #include <fcntl.h> 65 #include <sys/stat.h> 66 #include <string> 67 ``` 68 692. Create a resource instance. 70 71 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. 72 73 ```c++ 74 // 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.) 75 std::string filePath = "test.mp4"; 76 int32_t fd = open(filePath.c_str(), O_RDONLY); 77 struct stat fileStatus {}; 78 int64_t fileSize = 0; 79 if (stat(filePath.c_str(), &fileStatus) == 0) { 80 fileSize = static_cast<int64_t>(fileStatus.st_size); 81 } else { 82 printf("get stat failed"); 83 return; 84 } 85 // 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. 86 OH_AVSource *source = OH_AVSource_CreateWithFD(fd, 0, fileSize); 87 if (source == nullptr) { 88 printf("create source failed"); 89 return; 90 } 91 // (Optional) Create a source resource instance for the URI resource file. 92 // OH_AVSource *source = OH_AVSource_CreateWithURI(uri); 93 94 // (Optional) Create a source resource instance for the custom data source. Before the operation, you must implement AVSourceReadAt. 95 // Add g_filePath when OH_AVSource_CreateWithDataSource is used. 96 // g_filePath = filePath ; 97 // OH_AVDataSource dataSource = {fileSize, AVSourceReadAt}; 98 // OH_AVSource *source = OH_AVSource_CreateWithDataSource(&dataSource); 99 ``` 100 101 Implement the **AVSourceReadAt** API before creating the resource instance. 102 103 ```c++ 104 // Add the header file. 105 #include <fstream> 106 ``` 107 108 ```c++ 109 static std::string g_filePath; 110 111 enum MediaDataSourceError : int32_t { 112 SOURCE_ERROR_IO = -2, 113 SOURCE_ERROR_EOF = -1 114 }; 115 116 int32_t AVSourceReadAt(OH_AVBuffer *data, int32_t length, int64_t pos) 117 { 118 if (data == nullptr) { 119 printf("AVSourceReadAt : data is nullptr!\n"); 120 return MediaDataSourceError::SOURCE_ERROR_IO; 121 } 122 123 std::ifstream infile(g_filePath, std::ofstream::binary); 124 if (!infile.is_open()) { 125 printf("AVSourceReadAt : open file failed! file:%s\n", g_filePath.c_str()); 126 return MediaDataSourceError::SOURCE_ERROR_IO; // Failed to open the file. 127 } 128 129 infile.seekg(0, std::ios::end); 130 int64_t fileSize = infile.tellg(); 131 if (pos >= fileSize) { 132 printf("AVSourceReadAt : pos over or equals file size!\n"); 133 return MediaDataSourceError::SOURCE_ERROR_EOF; // pos is already at the end of the file and cannot be read. 134 } 135 136 if (pos + length > fileSize) { 137 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. 138 } 139 140 infile.seekg(pos, std::ios::beg); 141 if (length <= 0) { 142 printf("AVSourceReadAt : raed length less than zero!\n"); 143 return MediaDataSourceError::SOURCE_ERROR_IO; 144 } 145 char* buffer = new char[length]; 146 infile.read(buffer, length); 147 infile.close(); 148 149 memcpy(reinterpret_cast<char *>(OH_AVBuffer_GetAddr(data)), 150 buffer, length); 151 delete[] buffer; 152 153 return length; 154 } 155 ``` 1563. Create a demuxer instance. 157 ```c++ 158 // Create a demuxer for the resource instance. 159 OH_AVDemuxer *demuxer = OH_AVDemuxer_CreateWithSource(source); 160 if (demuxer == nullptr) { 161 printf("create demuxer failed"); 162 return; 163 } 164 ``` 1654. (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/capi-drm-drm-mediakeysysteminfo.md) has been obtained, you can skip this step. 166 167 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. 168 169 ```c++ 170 // Implement the OnDrmInfoChangedWithObj callback. 171 static void OnDrmInfoChangedWithObj(OH_AVDemuxer *demuxer, DRM_MediaKeySystemInfo *drmInfo) 172 { 173 // Parse the media key system information, including the quantity, DRM type, and corresponding PSSH. 174 } 175 176 Demuxer_MediaKeySystemInfoCallback callback = &OnDrmInfoChangedWithObj; 177 Drm_ErrCode ret = OH_AVDemuxer_SetDemuxerMediaKeySystemInfoCallback(demuxer, callback); 178 ``` 179 After the callback is invoked, you can call the API to proactively obtain the media key system information (UUID and corresponding PSSH). 180 181 ```c++ 182 DRM_MediaKeySystemInfo mediaKeySystemInfo; 183 OH_AVDemuxer_GetMediaKeySystemInfo(demuxer, &mediaKeySystemInfo); 184 ``` 185 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 Mode in Video Decoding](video-decoding.md#surface-mode) or step 4 in [Buffer Mode in Video Decoding](video-decoding.md#buffer-mode). 186 1875. Obtain file information. 188 189 ```c++ 190 // (Optional) Obtain custom file attributes. If custom file attributes are not required, skip this step. 191 // Obtain custom attributes from the source file. 192 OH_AVFormat *customMetadataFormat = OH_AVSource_GetCustomMetadataFormat(source); 193 if (customMetadataFormat == nullptr) { 194 // Release resources from the previous steps. For details, see step 10. 195 printf("get custom metadata format failed"); 196 return; 197 } 198 // Precautions: 199 // 1. customKey must exactly match the key used during multiplexing (including the complete naming hierarchy). 200 // The example key is for demonstration only. Replace it with the actual custom string. 201 // For example, if the key used during multiplexing is com.openharmony.custom.meta.abc.efg, 202 // you must use the full key. Using a truncated key like com.openharmony.custom.meta.abc will fail. 203 // 2. The value type must match the data type used during multiplexing. In this example, it is a string. For other types, use the right API. The types ints and floats are supported. Starting from API version 20, the type buffer is also supported. 204 const char *customKey = "com.openharmony.custom.meta.string"; // Replace it with the actual key used during multiplexing. 205 const char *customValue; 206 if (!OH_AVFormat_GetStringValue(customMetadataFormat, customKey, &customValue)) { 207 printf("get custom metadata from custom metadata format failed"); 208 } 209 OH_AVFormat_Destroy(customMetadataFormat); 210 customMetadataFormat = nullptr; 211 212 // (Optional) Obtain the number of tracks. If you know the track information, skip this step. 213 // 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. 214 OH_AVFormat *sourceFormat = OH_AVSource_GetSourceFormat(source); 215 if (sourceFormat == nullptr) { 216 // Release resources from the previous steps. For details, see step 10. 217 printf("get source format failed"); 218 return; 219 } 220 int32_t trackCount = 0; 221 if (!OH_AVFormat_GetIntValue(sourceFormat, OH_MD_KEY_TRACK_COUNT, &trackCount)) { 222 printf("get track count from source format failed"); 223 } 224 if (trackCount == 0) { 225 // If the file does not contain any track, perform other operations based on the service. 226 printf("no track"); 227 } 228 OH_AVFormat_Destroy(sourceFormat); 229 sourceFormat = nullptr; 230 ``` 231 2326. (Optional) Obtain the track index and format. If you know the track information, skip this step. 233 234 ```c++ 235 uint32_t audioTrackIndex = 0; 236 uint32_t videoTrackIndex = 0; 237 int32_t w = 0; 238 int32_t h = 0; 239 int64_t bitRate = 0; // Configure the bit rate, in bit/s. 240 double frameRate = 0.0; 241 const char* mimetype = nullptr; 242 uint8_t *codecConfig = nullptr; 243 size_t bufferSize = 0; 244 int32_t trackType; 245 for (uint32_t index = 0; index < (static_cast<uint32_t>(trackCount)); index++) { 246 // Obtain the track information. You can call the API to obtain track-level attributes. For details, see Table 2 in Appendix. 247 OH_AVFormat *trackFormat = OH_AVSource_GetTrackFormat(source, index); 248 if (trackFormat == nullptr) { 249 printf("get track format failed"); 250 return; 251 } 252 if (!OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_TRACK_TYPE, &trackType)) { 253 printf("get track type from track format failed"); 254 return; 255 } 256 if (trackType == OH_MediaType::MEDIA_TYPE_AUXILIARY) { 257 const char *referenceType; 258 if (!OH_AVFormat_GetStringValue(trackFormat, OH_MD_KEY_TRACK_REFERENCE_TYPE, &referenceType)) { 259 printf("get reference type from auxiliary track failed"); 260 } 261 int32_t* referenceIds; 262 size_t referenceIdsCount; 263 if (!OH_AVFormat_GetIntBuffer(trackFormat, OH_MD_KEY_TRACK_REFERENCE_TYPE, &referenceIds, &referenceIdsCount)) { 264 printf("get reference track ids from auxiliary track failed"); 265 } 266 // Process the track reference relationship based on the auxiliary track type. 267 } 268 static_cast<OH_MediaType>(trackType) == OH_MediaType::MEDIA_TYPE_AUD ? audioTrackIndex = index : videoTrackIndex = index; 269 // Obtain the width and height of the video track. 270 if (trackType == OH_MediaType::MEDIA_TYPE_VID) { 271 if (!OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_WIDTH, &w)) { 272 printf("get track width from track format failed"); 273 return; 274 } 275 if (!OH_AVFormat_GetIntValue(trackFormat, OH_MD_KEY_HEIGHT, &h)) { 276 printf("get track height from track format failed"); 277 return; 278 } 279 if (!OH_AVFormat_GetLongValue(trackFormat, OH_MD_KEY_BITRATE, &bitRate)) { 280 printf("get track bitRate from track format failed"); 281 return; 282 } 283 if (!OH_AVFormat_GetDoubleValue(trackFormat, OH_MD_KEY_FRAME_RATE, &frameRate)) { 284 printf("get track frameRate from track format failed"); 285 return; 286 } 287 if (!OH_AVFormat_GetStringValue(trackFormat, OH_MD_KEY_CODEC_MIME, &mimetype)) { 288 printf("get track mimetype from track format failed"); 289 return; 290 } 291 if (!OH_AVFormat_GetBuffer(trackFormat, OH_MD_KEY_CODEC_CONFIG, &codecConfig, &bufferSize)) { 292 printf("get track codecConfig from track format failed"); 293 return; 294 } 295 printf(" track width%d, track height: %d, track bitRate: %ld, track frameRate: %f, track mimetype: %s\n", w, h, bitRate, frameRate, mimetype); 296 } 297 OH_AVFormat_Destroy(trackFormat); 298 trackFormat = nullptr; 299 } 300 ``` 301 3027. Select a track, from which the demuxer reads data. 303 304 ```c++ 305 if(OH_AVDemuxer_SelectTrackByID(demuxer, audioTrackIndex) != AV_ERR_OK){ 306 printf("select audio track failed: %d", audioTrackIndex); 307 return; 308 } 309 if(OH_AVDemuxer_SelectTrackByID(demuxer, videoTrackIndex) != AV_ERR_OK){ 310 printf("select video track failed: %d", videoTrackIndex); 311 return; 312 } 313 // (Optional) Deselect the track. 314 // OH_AVDemuxer_UnselectTrackByID(demuxer, audioTrackIndex); 315 ``` 316 3178. (Optional) Seek to the specified time for the selected track. 318 319 ```c++ 320 // Demultiplexing is performed from this time. 321 // Note: 322 // 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. 323 // 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. 324 // 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. 325 OH_AVDemuxer_SeekToTime(demuxer, 0, OH_AVSeekMode::SEEK_MODE_CLOSEST_SYNC); 326 ``` 327 3289. Start demultiplexing and cyclically obtain samples. The code snippet below uses a file that contains audio and video tracks as an example. 329 330 A BufferAttr object contains the following attributes. 331 - **size**: sample size. 332 - **offset**: offset of the data in the AVBuffer. The value is generally 0. 333 - **pts**: timestamp when the file is multiplexed. 334 - **flags**: sample attributes. 335 336 | flag | Description| 337 | -------- | -------- | 338 | AVCODEC_BUFFER_FLAGS_NONE | Default value.| 339 | AVCODEC_BUFFER_FLAGS_EOS | End of Stream (EOS). The data is empty.| 340 | AVCODEC_BUFFER_FLAGS_SYNC_FRAME | IDR frame or I-frame.| 341 | AVCODEC_BUFFER_FLAGS_INCOMPLETE_FRAME | Incomplete sample. Generally, a complete sample fails to be copied because the buffer is too small.| 342 | AVCODEC_BUFFER_FLAGS_CODEC_DATA | Frame containing parameter set information.| 343 | AVCODEC_BUFFER_FLAGS_DISCARD | Frames that can be discarded.| 344 345 The **OH_AVDemuxer_ReadSampleBuffer** function can be time-consuming, particularly due to file I/O operations. You are advised to call this function in asynchronous mode. 346 ```c++ 347 // Define a processing function for each thread. 348 void ReadTrackSamples(OH_AVFormatDemuxer *demuxer, uint32_t trackIndex, int buffer_size, 349 std::atomic<bool>& isEnd, std::atomic<bool>& threadFinished) 350 { 351 // Create a buffer. 352 OH_AVBuffer *buffer = OH_AVBuffer_Create(buffer_size); 353 if (buffer == nullptr) { 354 printf("Create buffer failed for track %d\n", trackIndex); 355 threadFinished.store(true); 356 return; 357 } 358 OH_AVCodecBufferAttr info; 359 int32_t ret; 360 361 while (!isEnd.load()) { 362 ret = OH_AVDemuxer_ReadSampleBuffer(demuxer, trackIndex, buffer); 363 if (ret == AV_ERR_OK) { 364 OH_AVBuffer_GetBufferAttr(buffer, &info); 365 printf("Track %d sample size: %d\n", trackIndex, info.size); 366 // Check the EOS flag. 367 if (info.flags == OH_AVCodecBufferFlags::AVCODEC_BUFFER_FLAGS_EOS) { 368 isEnd.store(true); 369 } 370 // Process the buffer data (decode the data as required). 371 } else { 372 printf("Read sample failed for track %d\n", trackIndex); 373 break; 374 } 375 } 376 // Destroy the buffer. 377 OH_AVBuffer_Destroy(buffer); 378 buffer = nullptr; 379 threadFinished.store(true); 380 } 381 382 // Calculate the buffer size based on your requirements. 383 int audioBufferSize = 4096; // Typical audio buffer size. 384 int videoBufferSize = w * h * 3 >> 1; // Raw video buffer size. 385 386 // Create atomic variables for thread communication. 387 std::atomic<bool> audioIsEnd{false}, videoIsEnd{false}; // Specify whether the stream ends. 388 std::atomic<bool> audioThreadFinished{false}, videoThreadFinished{false}; // Specify whether the thread is paused. 389 390 // Create a thread. 391 std::thread audioThread(ReadTrackSamples, demuxer, audioTrackIndex, audioBufferSize, 392 std::ref(audioIsEnd), std::ref(audioThreadFinished)); 393 std::thread videoThread(ReadTrackSamples, demuxer, videoTrackIndex, videoBufferSize, 394 std::ref(videoIsEnd), std::ref(videoThreadFinished)); 395 audioThread.join(); 396 videoThread.join(); 397 ``` 398 39910. Destroy the demuxer instance. 400 ```c++ 401 // Manually set the instance to nullptr after OH_AVSource_Destroy is called. Do not call this API repeatedly for the same instance; otherwise, a program error occurs. 402 if (OH_AVSource_Destroy(source) != AV_ERR_OK) { 403 printf("destroy source pointer error"); 404 } 405 source = nullptr; 406 // Manually set the instance to nullptr after OH_AVDemuxer_Destroy is called. Do not call this API repeatedly for the same instance; otherwise, a program error occurs. 407 if (OH_AVDemuxer_Destroy(demuxer) != AV_ERR_OK) { 408 printf("destroy demuxer pointer error"); 409 } 410 demuxer = nullptr; 411 close(fd); 412 ``` 413 414## Appendix 415### Supported File-Level Attributes 416 417> **NOTE** 418> 419> 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. 420> 421> 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). 422> 423> 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). 424 425**Table 1** Supported file-level attributes 426| Name| Description| 427| -- | -- | 428|OH_MD_KEY_TITLE|Title.| 429|OH_MD_KEY_ARTIST|Artist.| 430|OH_MD_KEY_ALBUM|Album.| 431|OH_MD_KEY_ALBUM_ARTIST|Album artist.| 432|OH_MD_KEY_DATE|Date.| 433|OH_MD_KEY_COMMENT|Comment.| 434|OH_MD_KEY_GENRE|Genre.| 435|OH_MD_KEY_COPYRIGHT|Copyright.| 436|OH_MD_KEY_LANGUAGE|Language.| 437|OH_MD_KEY_DESCRIPTION|Description.| 438|OH_MD_KEY_LYRICS|Lyrics.| 439|OH_MD_KEY_TRACK_COUNT|Track count.| 440|OH_MD_KEY_DURATION|Duration.| 441|OH_MD_KEY_START_TIME|Start time.| 442 443### Supported Track-Level Attributes 444 445> **NOTE** 446> 447> 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. 448> The supported attributes of the auxiliary track must match the actual media type (audio or video). 449> 450> 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). 451 452**Table 2** Supported track-level attributes 453| Name| Description| Supported by Video Tracks| Supported by Audio Tracks| Supported by Subtitle Tracks| Supported by Auxiliary Tracks| 454| -- | -- | -- | -- | -- | -- | 455|OH_MD_KEY_CODEC_MIME|Stream codec type.|Supported|Supported|Supported|Supported| 456|OH_MD_KEY_TRACK_TYPE|Stream track type.|Supported|Supported|Supported|Supported| 457|OH_MD_KEY_TRACK_START_TIME|Start time of the stream.|Supported|Supported|Supported|Supported| 458|OH_MD_KEY_BITRATE|Stream bit rate.|Supported|Supported|Not supported|Supported| 459|OH_MD_KEY_LANGUAGE|Stream language type.|Supported|Supported|Not supported|Supported| 460|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|Supported| 461|OH_MD_KEY_WIDTH|Video stream width.|Supported|Not supported|Not supported|Supported| 462|OH_MD_KEY_HEIGHT|Video stream height.|Supported|Not supported|Not supported|Supported| 463|OH_MD_KEY_FRAME_RATE|Video stream frame rate.|Supported|Not supported|Not supported|Supported| 464|OH_MD_KEY_ROTATION|Rotation angle of the video stream.|Supported|Not supported|Not supported|Supported| 465|OH_MD_KEY_VIDEO_SAR|Aspect ratio of the video stream sample.|Supported|Not supported|Not supported|Supported| 466|OH_MD_KEY_PROFILE|Encoding profile of the video stream. This key is valid only for H.265 streams.|Supported|Not supported|Not supported|Supported| 467|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|Supported| 468|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|Supported| 469|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|Supported| 470|OH_MD_KEY_MATRIX_COEFFICIENTS|Video matrix coefficient. This key is valid only for H.265 streams.|Supported|Not supported|Not supported|Supported| 471|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|Supported| 472|OH_MD_KEY_AUD_SAMPLE_RATE|Audio stream sample rate.|Not supported|Supported|Not supported|Supported| 473|OH_MD_KEY_AUD_CHANNEL_COUNT|Number of audio stream channels.|Not supported|Supported|Not supported|Supported| 474|OH_MD_KEY_CHANNEL_LAYOUT|Encoding channel layout required by the audio stream.|Not supported|Supported|Not supported|Supported| 475|OH_MD_KEY_AUDIO_SAMPLE_FORMAT|Audio stream sample format.|Not supported|Supported|Not supported|Supported| 476|OH_MD_KEY_AAC_IS_ADTS|AAC format. This key is valid only for AAC streams.|Not supported|Supported|Not supported|Supported| 477|OH_MD_KEY_BITS_PER_CODED_SAMPLE|Number of bits per coded sample in the audio stream.|Not supported|Supported|Not supported|Supported| 478|OH_MD_KEY_REFERENCE_TRACK_IDS|Reference relationship between media file tracks.|Supported|Supported|Supported|Supported| 479|OH_MD_KEY_TRACK_REFERENCE_TYPE|Auxiliary track type of the media file.|Not supported|Not supported|Not supported|Supported| 480|OH_MD_KEY_TRACK_DESCRIPTION|Description of the auxiliary track of the media file.|Not supported|Not supported|Not supported|Supported| 481