react-native-audio-api 0.9.0 → 0.10.0-nightly-971a6b4-20251010

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/android/src/main/cpp/audioapi/android/core/{AudioDecoder.cpp → utils/AudioDecoder.cpp} +79 -75
  2. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +124 -43
  3. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp +1 -101
  4. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +0 -3
  5. package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.cpp +133 -0
  6. package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.h +28 -0
  7. package/common/cpp/audioapi/HostObjects/utils/AudioStretcherHostObject.cpp +58 -0
  8. package/common/cpp/audioapi/HostObjects/utils/AudioStretcherHostObject.h +26 -0
  9. package/common/cpp/audioapi/core/AudioContext.cpp +0 -2
  10. package/common/cpp/audioapi/core/BaseAudioContext.cpp +0 -35
  11. package/common/cpp/audioapi/core/BaseAudioContext.h +4 -12
  12. package/common/cpp/audioapi/core/OfflineAudioContext.cpp +0 -2
  13. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +0 -4
  14. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +0 -1
  15. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +0 -2
  16. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +0 -4
  17. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +0 -1
  18. package/common/cpp/audioapi/core/types/AudioFormat.h +16 -0
  19. package/common/cpp/audioapi/core/utils/AudioDecoder.h +36 -91
  20. package/common/cpp/audioapi/core/utils/AudioStretcher.cpp +75 -0
  21. package/common/cpp/audioapi/core/utils/AudioStretcher.h +30 -0
  22. package/common/cpp/audioapi/core/utils/Constants.h +4 -0
  23. package/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp +5 -1
  24. package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp +241 -282
  25. package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.h +57 -19
  26. package/common/cpp/test/CMakeLists.txt +1 -1
  27. package/ios/audioapi/ios/core/utils/AudioDecoder.mm +160 -0
  28. package/lib/commonjs/api.js +21 -1
  29. package/lib/commonjs/api.js.map +1 -1
  30. package/lib/commonjs/core/AudioDecoder.js +48 -0
  31. package/lib/commonjs/core/AudioDecoder.js.map +1 -0
  32. package/lib/commonjs/core/AudioStretcher.js +31 -0
  33. package/lib/commonjs/core/AudioStretcher.js.map +1 -0
  34. package/lib/commonjs/core/BaseAudioContext.js +11 -18
  35. package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
  36. package/lib/module/api.js +3 -1
  37. package/lib/module/api.js.map +1 -1
  38. package/lib/module/core/AudioDecoder.js +42 -0
  39. package/lib/module/core/AudioDecoder.js.map +1 -0
  40. package/lib/module/core/AudioStretcher.js +26 -0
  41. package/lib/module/core/AudioStretcher.js.map +1 -0
  42. package/lib/module/core/BaseAudioContext.js +11 -18
  43. package/lib/module/core/BaseAudioContext.js.map +1 -1
  44. package/lib/typescript/api.d.ts +5 -1
  45. package/lib/typescript/api.d.ts.map +1 -1
  46. package/lib/typescript/core/AudioDecoder.d.ts +4 -0
  47. package/lib/typescript/core/AudioDecoder.d.ts.map +1 -0
  48. package/lib/typescript/core/AudioStretcher.d.ts +3 -0
  49. package/lib/typescript/core/AudioStretcher.d.ts.map +1 -0
  50. package/lib/typescript/core/BaseAudioContext.d.ts +3 -6
  51. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  52. package/lib/typescript/interfaces.d.ts +10 -3
  53. package/lib/typescript/interfaces.d.ts.map +1 -1
  54. package/package.json +1 -1
  55. package/src/api.ts +10 -0
  56. package/src/core/AudioDecoder.ts +78 -0
  57. package/src/core/AudioStretcher.ts +43 -0
  58. package/src/core/BaseAudioContext.ts +26 -29
  59. package/src/interfaces.ts +26 -6
  60. package/ios/audioapi/ios/core/AudioDecoder.mm +0 -156
@@ -1,16 +1,20 @@
1
1
  /*
2
- * This file dynamically links to the FFmpeg library, which is licensed under the
3
- * GNU Lesser General Public License (LGPL) version 2.1 or later.
2
+ * This file dynamically links to the FFmpeg library, which is licensed under
3
+ * the GNU Lesser General Public License (LGPL) version 2.1 or later.
4
4
  *
5
- * Our own code in this file is licensed under the MIT License and dynamic linking
6
- * allows you to use this code without your entire project being subject to the
7
- * terms of the LGPL. However, note that if you link statically to FFmpeg, you must
8
- * comply with the terms of the LGPL for FFmpeg itself.
5
+ * Our own code in this file is licensed under the MIT License and dynamic
6
+ * linking allows you to use this code without your entire project being subject
7
+ * to the terms of the LGPL. However, note that if you link statically to
8
+ * FFmpeg, you must comply with the terms of the LGPL for FFmpeg itself.
9
9
  */
10
10
 
11
- #include "FFmpegDecoding.h"
11
+ #include <audioapi/core/sources/AudioBuffer.h>
12
+ #include <audioapi/libs/ffmpeg/FFmpegDecoding.h>
13
+ #include <audioapi/utils/AudioArray.h>
14
+ #include <audioapi/utils/AudioBus.h>
15
+ #include <functional>
12
16
 
13
- namespace audioapi::ffmpegdecoding {
17
+ namespace audioapi::ffmpegdecoder {
14
18
 
15
19
  int read_packet(void *opaque, uint8_t *buf, int buf_size) {
16
20
  MemoryIOContext *ctx = static_cast<MemoryIOContext *>(opaque);
@@ -51,42 +55,87 @@ int64_t seek_packet(void *opaque, int64_t offset, int whence) {
51
55
  return ctx->pos;
52
56
  }
53
57
 
54
- std::vector<int16_t> readAllPcmFrames(
58
+ void convertFrameToBuffer(
59
+ SwrContext *swr,
60
+ AVFrame *frame,
61
+ int output_channel_count,
62
+ std::vector<float> &buffer,
63
+ size_t &framesRead,
64
+ uint8_t **&resampled_data,
65
+ int &max_resampled_samples) {
66
+ const int out_samples = swr_get_out_samples(swr, frame->nb_samples);
67
+ if (out_samples > max_resampled_samples) {
68
+ av_freep(&resampled_data[0]);
69
+ av_freep(&resampled_data);
70
+ max_resampled_samples = out_samples;
71
+
72
+ if (av_samples_alloc_array_and_samples(
73
+ &resampled_data,
74
+ nullptr,
75
+ output_channel_count,
76
+ max_resampled_samples,
77
+ AV_SAMPLE_FMT_FLT,
78
+ 0) < 0) {
79
+ return;
80
+ }
81
+ }
82
+
83
+ int converted_samples = swr_convert(
84
+ swr,
85
+ resampled_data,
86
+ max_resampled_samples,
87
+ const_cast<const uint8_t **>(frame->data),
88
+ frame->nb_samples);
89
+
90
+ if (converted_samples > 0) {
91
+ const size_t current_size = buffer.size();
92
+ const size_t new_samples =
93
+ static_cast<size_t>(converted_samples) * output_channel_count;
94
+ buffer.resize(current_size + new_samples);
95
+ memcpy(
96
+ buffer.data() + current_size,
97
+ resampled_data[0],
98
+ new_samples * sizeof(float));
99
+ framesRead += converted_samples;
100
+ }
101
+ }
102
+
103
+ std::vector<float> readAllPcmFrames(
55
104
  AVFormatContext *fmt_ctx,
56
105
  AVCodecContext *codec_ctx,
57
106
  int out_sample_rate,
107
+ int output_channel_count,
58
108
  int audio_stream_index,
59
- int channels,
60
109
  size_t &framesRead) {
61
- std::vector<int16_t> buffer;
62
- SwrContext *swr_ctx = swr_alloc();
63
- if (swr_ctx == nullptr) {
110
+ framesRead = 0;
111
+ std::vector<float> buffer;
112
+ auto swr = std::unique_ptr<SwrContext, std::function<void(SwrContext *)>>(
113
+ swr_alloc(), [](SwrContext *ctx) { swr_free(&ctx); });
114
+
115
+ if (swr == nullptr)
64
116
  return buffer;
65
- }
66
117
 
67
- av_opt_set_chlayout(swr_ctx, "in_chlayout", &codec_ctx->ch_layout, 0);
68
- av_opt_set_int(swr_ctx, "in_sample_rate", codec_ctx->sample_rate, 0);
69
- av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", codec_ctx->sample_fmt, 0);
118
+ av_opt_set_chlayout(swr.get(), "in_chlayout", &codec_ctx->ch_layout, 0);
119
+ av_opt_set_int(swr.get(), "in_sample_rate", codec_ctx->sample_rate, 0);
120
+ av_opt_set_sample_fmt(swr.get(), "in_sample_fmt", codec_ctx->sample_fmt, 0);
70
121
 
71
122
  AVChannelLayout out_ch_layout;
72
- av_channel_layout_default(&out_ch_layout, channels);
73
- av_opt_set_chlayout(swr_ctx, "out_chlayout", &out_ch_layout, 0);
74
- av_opt_set_int(swr_ctx, "out_sample_rate", out_sample_rate, 0);
75
- av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
123
+ av_channel_layout_default(&out_ch_layout, output_channel_count);
124
+ av_opt_set_chlayout(swr.get(), "out_chlayout", &out_ch_layout, 0);
125
+ av_opt_set_int(swr.get(), "out_sample_rate", out_sample_rate, 0);
126
+ av_opt_set_sample_fmt(swr.get(), "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
76
127
 
77
- if (swr_init(swr_ctx) < 0) {
78
- swr_free(&swr_ctx);
128
+ if (swr_init(swr.get()) < 0) {
79
129
  av_channel_layout_uninit(&out_ch_layout);
80
130
  return buffer;
81
131
  }
82
132
 
83
- AVPacket *packet = av_packet_alloc();
84
- AVFrame *frame = av_frame_alloc();
85
-
133
+ auto packet = std::unique_ptr<AVPacket, std::function<void(AVPacket *)>>(
134
+ av_packet_alloc(), [](AVPacket *p) { av_packet_free(&p); });
135
+ auto frame = std::unique_ptr<AVFrame, std::function<void(AVFrame *)>>(
136
+ av_frame_alloc(), [](AVFrame *p) { av_frame_free(&p); });
137
+
86
138
  if (packet == nullptr || frame == nullptr) {
87
- if (packet != nullptr) av_packet_free(&packet);
88
- if (frame != nullptr) av_frame_free(&frame);
89
- swr_free(&swr_ctx);
90
139
  av_channel_layout_uninit(&out_ch_layout);
91
140
  return buffer;
92
141
  }
@@ -94,312 +143,222 @@ std::vector<int16_t> readAllPcmFrames(
94
143
  // Allocate buffer for resampled data
95
144
  uint8_t **resampled_data = nullptr;
96
145
  int max_resampled_samples = 4096; // Initial size
97
- int ret = av_samples_alloc_array_and_samples(
98
- &resampled_data,
99
- nullptr,
100
- channels,
101
- max_resampled_samples,
102
- AV_SAMPLE_FMT_S16,
103
- 0);
104
-
105
- if (ret < 0) {
106
- av_frame_free(&frame);
107
- av_packet_free(&packet);
108
- swr_free(&swr_ctx);
146
+ if (av_samples_alloc_array_and_samples(
147
+ &resampled_data,
148
+ nullptr,
149
+ output_channel_count,
150
+ max_resampled_samples,
151
+ AV_SAMPLE_FMT_FLT,
152
+ 0) < 0) {
109
153
  av_channel_layout_uninit(&out_ch_layout);
110
154
  return buffer;
111
155
  }
112
156
 
113
- framesRead = 0;
114
-
115
- while (av_read_frame(fmt_ctx, packet) >= 0) {
157
+ while (av_read_frame(fmt_ctx, packet.get()) >= 0) {
116
158
  if (packet->stream_index == audio_stream_index) {
117
- if (avcodec_send_packet(codec_ctx, packet) == 0) {
118
- while (avcodec_receive_frame(codec_ctx, frame) == 0) {
119
- // Check if we need more buffer space
120
- int out_samples = swr_get_out_samples(swr_ctx, frame->nb_samples);
121
- if (out_samples > max_resampled_samples) {
122
- if (resampled_data != nullptr) {
123
- av_freep(&resampled_data[0]);
124
- av_freep(&resampled_data);
125
- }
126
-
127
- max_resampled_samples = out_samples;
128
- ret = av_samples_alloc_array_and_samples(
129
- &resampled_data,
130
- nullptr,
131
- channels,
132
- max_resampled_samples,
133
- AV_SAMPLE_FMT_S16,
134
- 0);
135
-
136
- if (ret < 0) {
137
- break; // Exit on allocation failure
138
- }
139
- }
140
-
141
- int converted_samples = swr_convert(
142
- swr_ctx,
159
+ if (avcodec_send_packet(codec_ctx, packet.get()) == 0) {
160
+ while (avcodec_receive_frame(codec_ctx, frame.get()) == 0) {
161
+ convertFrameToBuffer(
162
+ swr.get(),
163
+ frame.get(),
164
+ output_channel_count,
165
+ buffer,
166
+ framesRead,
143
167
  resampled_data,
144
- max_resampled_samples,
145
- (const uint8_t **)frame->data,
146
- frame->nb_samples);
147
-
148
- if (converted_samples > 0) {
149
- size_t current_size = buffer.size();
150
- size_t new_samples = converted_samples * channels;
151
- buffer.resize(current_size + new_samples);
152
- memcpy(
153
- buffer.data() + current_size,
154
- resampled_data[0],
155
- new_samples * sizeof(int16_t));
156
-
157
- framesRead += converted_samples;
158
- }
168
+ max_resampled_samples);
159
169
  }
160
170
  }
161
171
  }
162
- av_packet_unref(packet);
172
+ av_packet_unref(packet.get());
163
173
  }
164
174
 
165
175
  // Flush decoder
166
176
  avcodec_send_packet(codec_ctx, nullptr);
167
- while (avcodec_receive_frame(codec_ctx, frame) == 0) {
168
- int out_samples = swr_get_out_samples(swr_ctx, frame->nb_samples);
169
- if (out_samples > max_resampled_samples) {
170
- if (resampled_data != nullptr) {
171
- av_freep(&resampled_data[0]);
172
- av_freep(&resampled_data);
173
- }
174
-
175
- max_resampled_samples = out_samples;
176
- ret = av_samples_alloc_array_and_samples(
177
- &resampled_data,
178
- nullptr,
179
- channels,
180
- max_resampled_samples,
181
- AV_SAMPLE_FMT_S16,
182
- 0);
183
-
184
- if (ret < 0) {
185
- break;
186
- }
187
- }
188
-
189
- int converted_samples = swr_convert(
190
- swr_ctx,
177
+ while (avcodec_receive_frame(codec_ctx, frame.get()) == 0) {
178
+ convertFrameToBuffer(
179
+ swr.get(),
180
+ frame.get(),
181
+ output_channel_count,
182
+ buffer,
183
+ framesRead,
191
184
  resampled_data,
192
- max_resampled_samples,
193
- (const uint8_t **)frame->data,
194
- frame->nb_samples);
195
-
196
- if (converted_samples > 0) {
197
- size_t current_size = buffer.size();
198
- size_t new_samples = converted_samples * channels;
199
- buffer.resize(current_size + new_samples);
200
- memcpy(
201
- buffer.data() + current_size,
202
- resampled_data[0],
203
- new_samples * sizeof(int16_t));
204
-
205
- framesRead += converted_samples;
206
- }
185
+ max_resampled_samples);
207
186
  }
208
187
 
209
- if (resampled_data != nullptr) {
210
- av_freep(&resampled_data[0]);
211
- av_freep(&resampled_data);
212
- }
213
- swr_free(&swr_ctx);
188
+ av_freep(&resampled_data[0]);
189
+ av_freep(&resampled_data);
214
190
  av_channel_layout_uninit(&out_ch_layout);
215
- av_frame_free(&frame);
216
- av_packet_free(&packet);
217
191
 
218
192
  return buffer;
219
193
  }
220
194
 
221
- std::vector<int16_t> decodeWithMemoryBlock(const void *data, size_t size, const int channel_count, int sample_rate) {
222
- if (data == nullptr || size == 0) {
223
- return {};
224
- }
225
-
226
- MemoryIOContext io_ctx;
227
- io_ctx.data = static_cast<const uint8_t *>(data);
228
- io_ctx.size = size;
229
- io_ctx.pos = 0;
230
-
231
- constexpr size_t buffer_size = 4096;
232
- uint8_t *io_buffer = static_cast<uint8_t *>(av_malloc(buffer_size));
233
- if (io_buffer == nullptr) {
234
- return {};
195
+ inline int findAudioStreamIndex(AVFormatContext *fmt_ctx) {
196
+ for (int i = 0; i < fmt_ctx->nb_streams; i++) {
197
+ if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
198
+ return i;
235
199
  }
200
+ }
201
+ return -1;
202
+ }
236
203
 
237
- AVIOContext *avio_ctx = avio_alloc_context(
238
- io_buffer, buffer_size, 0, &io_ctx, read_packet, nullptr, seek_packet);
239
-
240
- if (avio_ctx == nullptr) {
241
- av_free(io_buffer);
242
- return {};
243
- }
204
+ bool setupDecoderContext(
205
+ AVFormatContext *fmt_ctx,
206
+ int &audio_stream_index,
207
+ std::unique_ptr<AVCodecContext, std::function<void(AVCodecContext *)>>
208
+ &codec_ctx) {
209
+ audio_stream_index = findAudioStreamIndex(fmt_ctx);
210
+ if (audio_stream_index == -1) {
211
+ return false;
212
+ }
244
213
 
245
- // Create format context and set custom IO
246
- AVFormatContext *fmt_ctx = avformat_alloc_context();
247
- if (fmt_ctx == nullptr) {
248
- avio_context_free(&avio_ctx);
249
- return {};
250
- }
251
-
252
- fmt_ctx->pb = avio_ctx;
253
-
254
- // Open input from memory
255
- if (avformat_open_input(&fmt_ctx, nullptr, nullptr, nullptr) < 0) {
256
- avformat_free_context(fmt_ctx);
257
- avio_context_free(&avio_ctx);
258
- return {};
259
- }
214
+ AVCodecParameters *codecpar = fmt_ctx->streams[audio_stream_index]->codecpar;
215
+ const AVCodec *codec = avcodec_find_decoder(codecpar->codec_id);
216
+ if (codec == nullptr) {
217
+ return false;
218
+ }
260
219
 
261
- // Find stream info
262
- if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
263
- avformat_close_input(&fmt_ctx);
264
- avio_context_free(&avio_ctx);
265
- return {};
266
- }
220
+ AVCodecContext *raw_codec_ctx = avcodec_alloc_context3(codec);
221
+ if (raw_codec_ctx == nullptr) {
222
+ return false;
223
+ }
267
224
 
268
- int audio_stream_index = -1;
269
- for (int i = 0; i < fmt_ctx->nb_streams; i++) {
270
- if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
271
- audio_stream_index = i;
272
- break;
273
- }
274
- }
225
+ codec_ctx.reset(raw_codec_ctx);
226
+ if (avcodec_parameters_to_context(codec_ctx.get(), codecpar) < 0) {
227
+ return false;
228
+ }
229
+ if (avcodec_open2(codec_ctx.get(), codec, nullptr) < 0) {
230
+ return false;
231
+ }
275
232
 
276
- if (audio_stream_index == -1) {
277
- avformat_close_input(&fmt_ctx);
278
- avio_context_free(&avio_ctx);
279
- return {};
280
- }
233
+ return true;
234
+ }
281
235
 
282
- AVCodecParameters *codecpar = fmt_ctx->streams[audio_stream_index]->codecpar;
236
+ std::shared_ptr<AudioBuffer> decodeAudioFrames(
237
+ AVFormatContext *fmt_ctx,
238
+ AVCodecContext *codec_ctx,
239
+ int audio_stream_index,
240
+ int sample_rate) {
241
+ size_t framesRead = 0;
242
+ int output_sample_rate =
243
+ (sample_rate > 0) ? sample_rate : codec_ctx->sample_rate;
244
+ int output_channel_count = codec_ctx->ch_layout.nb_channels;
245
+
246
+ std::vector<float> decoded_buffer = readAllPcmFrames(
247
+ fmt_ctx,
248
+ codec_ctx,
249
+ output_sample_rate,
250
+ output_channel_count,
251
+ audio_stream_index,
252
+ framesRead);
283
253
 
284
- // Find decoder
285
- const AVCodec *codec = avcodec_find_decoder(codecpar->codec_id);
286
- if (codec == nullptr) {
287
- avformat_close_input(&fmt_ctx);
288
- avio_context_free(&avio_ctx);
289
- return {};
290
- }
254
+ if (framesRead == 0 || decoded_buffer.empty()) {
255
+ return nullptr;
256
+ }
291
257
 
292
- // Allocate and setup codec context
293
- AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
294
- if (codec_ctx == nullptr) {
295
- avformat_close_input(&fmt_ctx);
296
- avio_context_free(&avio_ctx);
297
- return {};
298
- }
258
+ auto outputFrames = decoded_buffer.size() / output_channel_count;
259
+ auto audioBus = std::make_shared<AudioBus>(
260
+ outputFrames, output_channel_count, output_sample_rate);
299
261
 
300
- if (avcodec_parameters_to_context(codec_ctx, codecpar) < 0) {
301
- avcodec_free_context(&codec_ctx);
302
- avformat_close_input(&fmt_ctx);
303
- avio_context_free(&avio_ctx);
304
- return {};
262
+ for (int ch = 0; ch < output_channel_count; ++ch) {
263
+ auto channelData = audioBus->getChannel(ch)->getData();
264
+ for (int i = 0; i < outputFrames; ++i) {
265
+ channelData[i] = decoded_buffer[i * output_channel_count + ch];
305
266
  }
267
+ }
268
+ return std::make_shared<AudioBuffer>(audioBus);
269
+ }
306
270
 
307
- if (avcodec_open2(codec_ctx, codec, nullptr) < 0) {
308
- avcodec_free_context(&codec_ctx);
309
- avformat_close_input(&fmt_ctx);
310
- avio_context_free(&avio_ctx);
311
- return {};
312
- }
271
+ std::shared_ptr<AudioBuffer>
272
+ decodeWithMemoryBlock(const void *data, size_t size, int sample_rate) {
273
+ if (data == nullptr || size == 0) {
274
+ return nullptr;
275
+ }
313
276
 
314
- // Get actual channel count from the decoded stream
315
- int actual_channels = codec_ctx->ch_layout.nb_channels;
277
+ MemoryIOContext io_ctx{static_cast<const uint8_t *>(data), size, 0};
316
278
 
317
- // Validate channel count
318
- if (actual_channels <= 0 || actual_channels > 8) {
319
- avcodec_free_context(&codec_ctx);
320
- avformat_close_input(&fmt_ctx);
321
- avio_context_free(&avio_ctx);
322
- return {};
323
- }
279
+ constexpr size_t buffer_size = 4096;
280
+ auto io_buffer = std::unique_ptr<uint8_t, decltype(&av_free)>(
281
+ static_cast<uint8_t *>(av_malloc(buffer_size)), &av_free);
282
+ if (io_buffer == nullptr) {
283
+ return nullptr;
284
+ }
324
285
 
325
- // Decode all frames
326
- size_t framesRead = 0;
327
- std::vector<int16_t> decoded_buffer = readAllPcmFrames(
328
- fmt_ctx, codec_ctx, sample_rate, audio_stream_index, channel_count, framesRead);
286
+ auto avio_ctx =
287
+ std::unique_ptr<AVIOContext, std::function<void(AVIOContext *)>>(
288
+ avio_alloc_context(
289
+ io_buffer.get(),
290
+ buffer_size,
291
+ 0,
292
+ &io_ctx,
293
+ read_packet,
294
+ nullptr,
295
+ seek_packet),
296
+ [](AVIOContext *ctx) { avio_context_free(&ctx); });
297
+ if (avio_ctx == nullptr) {
298
+ return nullptr;
299
+ }
329
300
 
330
- // Cleanup - Note: avio_context_free will free the io_buffer
331
- avcodec_free_context(&codec_ctx);
332
- avformat_close_input(&fmt_ctx);
333
- avio_context_free(&avio_ctx);
301
+ AVFormatContext *raw_fmt_ctx = avformat_alloc_context();
302
+ if (raw_fmt_ctx == nullptr) {
303
+ return nullptr;
304
+ }
305
+ raw_fmt_ctx->pb = avio_ctx.get();
334
306
 
335
- if (framesRead == 0 || decoded_buffer.empty()) {
336
- return {};
337
- }
307
+ if (avformat_open_input(&raw_fmt_ctx, nullptr, nullptr, nullptr) < 0) {
308
+ avformat_free_context(raw_fmt_ctx);
309
+ return nullptr;
310
+ }
338
311
 
339
- return decoded_buffer;
340
- }
312
+ auto fmt_ctx =
313
+ std::unique_ptr<AVFormatContext, decltype(&avformat_free_context)>(
314
+ raw_fmt_ctx, &avformat_free_context);
341
315
 
342
- std::vector<int16_t> decodeWithFilePath(const std::string &path, const int channel_count, int sample_rate) {
343
- if (path.empty()) {
344
- return {};
316
+ if (avformat_find_stream_info(fmt_ctx.get(), nullptr) < 0) {
317
+ return nullptr;
345
318
  }
346
319
 
347
- AVFormatContext *fmt_ctx = nullptr;
348
- if (avformat_open_input(&fmt_ctx, path.c_str(), nullptr, nullptr) < 0) {
349
- return {};
350
- }
351
- if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
352
- avformat_close_input(&fmt_ctx);
353
- return {};
354
- }
320
+ auto codec_ctx =
321
+ std::unique_ptr<AVCodecContext, std::function<void(AVCodecContext *)>>(
322
+ nullptr, [](AVCodecContext *ctx) { avcodec_free_context(&ctx); });
355
323
  int audio_stream_index = -1;
356
- for (int i = 0; i < fmt_ctx->nb_streams; i++) {
357
- if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
358
- audio_stream_index = i;
359
- break;
360
- }
361
- }
362
- if (audio_stream_index == -1) {
363
- avformat_close_input(&fmt_ctx);
364
- return {};
324
+ if (!setupDecoderContext(fmt_ctx.get(), audio_stream_index, codec_ctx)) {
325
+ return nullptr;
365
326
  }
366
327
 
367
- AVCodecParameters *codecpar = fmt_ctx->streams[audio_stream_index]->codecpar;
368
- const AVCodec *codec = avcodec_find_decoder(codecpar->codec_id);
369
- if (codec == nullptr) {
370
- avformat_close_input(&fmt_ctx);
371
- return {};
372
- }
373
- AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
374
- if (codec_ctx == nullptr) {
375
- avformat_close_input(&fmt_ctx);
376
- return {};
377
- }
328
+ return decodeAudioFrames(
329
+ fmt_ctx.get(), codec_ctx.get(), audio_stream_index, sample_rate);
330
+ }
378
331
 
379
- if (avcodec_parameters_to_context(codec_ctx, codecpar) < 0) {
380
- avcodec_free_context(&codec_ctx);
381
- avformat_close_input(&fmt_ctx);
382
- return {};
332
+ std::shared_ptr<AudioBuffer> decodeWithFilePath(
333
+ const std::string &path,
334
+ int sample_rate) {
335
+ if (path.empty()) {
336
+ return nullptr;
383
337
  }
384
338
 
385
- if (avcodec_open2(codec_ctx, codec, nullptr) < 0) {
386
- avcodec_free_context(&codec_ctx);
387
- avformat_close_input(&fmt_ctx);
388
- return {};
389
- }
339
+ AVFormatContext *raw_fmt_ctx = nullptr;
340
+ if (avformat_open_input(&raw_fmt_ctx, path.c_str(), nullptr, nullptr) < 0)
341
+ return nullptr;
390
342
 
391
- size_t framesRead = 0;
392
- std::vector<int16_t> decoded_buffer = readAllPcmFrames(
393
- fmt_ctx, codec_ctx, sample_rate, audio_stream_index, channel_count, framesRead);
343
+ auto fmt_ctx =
344
+ std::unique_ptr<AVFormatContext, std::function<void(AVFormatContext *)>>(
345
+ raw_fmt_ctx,
346
+ [](AVFormatContext *ctx) { avformat_close_input(&ctx); });
394
347
 
395
- avcodec_free_context(&codec_ctx);
396
- avformat_close_input(&fmt_ctx);
348
+ if (avformat_find_stream_info(fmt_ctx.get(), nullptr) < 0) {
349
+ return nullptr;
350
+ }
397
351
 
398
- if (framesRead == 0 || decoded_buffer.empty()) {
399
- return {};
352
+ auto codec_ctx =
353
+ std::unique_ptr<AVCodecContext, std::function<void(AVCodecContext *)>>(
354
+ nullptr, [](AVCodecContext *ctx) { avcodec_free_context(&ctx); });
355
+ int audio_stream_index = -1;
356
+ if (!setupDecoderContext(fmt_ctx.get(), audio_stream_index, codec_ctx)) {
357
+ return nullptr;
400
358
  }
401
359
 
402
- return decoded_buffer;
360
+ return decodeAudioFrames(
361
+ fmt_ctx.get(), codec_ctx.get(), audio_stream_index, sample_rate);
403
362
  }
404
363
 
405
364
  } // namespace audioapi::ffmpegdecoder