• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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