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.
- package/android/src/main/cpp/audioapi/android/core/{AudioDecoder.cpp → utils/AudioDecoder.cpp} +79 -75
- package/common/cpp/audioapi/AudioAPIModuleInstaller.h +124 -43
- package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp +1 -101
- package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +0 -3
- package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.cpp +133 -0
- package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.h +28 -0
- package/common/cpp/audioapi/HostObjects/utils/AudioStretcherHostObject.cpp +58 -0
- package/common/cpp/audioapi/HostObjects/utils/AudioStretcherHostObject.h +26 -0
- package/common/cpp/audioapi/core/AudioContext.cpp +0 -2
- package/common/cpp/audioapi/core/BaseAudioContext.cpp +0 -35
- package/common/cpp/audioapi/core/BaseAudioContext.h +4 -12
- package/common/cpp/audioapi/core/OfflineAudioContext.cpp +0 -2
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +0 -4
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +0 -1
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +0 -2
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +0 -4
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +0 -1
- package/common/cpp/audioapi/core/types/AudioFormat.h +16 -0
- package/common/cpp/audioapi/core/utils/AudioDecoder.h +36 -91
- package/common/cpp/audioapi/core/utils/AudioStretcher.cpp +75 -0
- package/common/cpp/audioapi/core/utils/AudioStretcher.h +30 -0
- package/common/cpp/audioapi/core/utils/Constants.h +4 -0
- package/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp +5 -1
- package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp +241 -282
- package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.h +57 -19
- package/common/cpp/test/CMakeLists.txt +1 -1
- package/ios/audioapi/ios/core/utils/AudioDecoder.mm +160 -0
- package/lib/commonjs/api.js +21 -1
- package/lib/commonjs/api.js.map +1 -1
- package/lib/commonjs/core/AudioDecoder.js +48 -0
- package/lib/commonjs/core/AudioDecoder.js.map +1 -0
- package/lib/commonjs/core/AudioStretcher.js +31 -0
- package/lib/commonjs/core/AudioStretcher.js.map +1 -0
- package/lib/commonjs/core/BaseAudioContext.js +11 -18
- package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
- package/lib/module/api.js +3 -1
- package/lib/module/api.js.map +1 -1
- package/lib/module/core/AudioDecoder.js +42 -0
- package/lib/module/core/AudioDecoder.js.map +1 -0
- package/lib/module/core/AudioStretcher.js +26 -0
- package/lib/module/core/AudioStretcher.js.map +1 -0
- package/lib/module/core/BaseAudioContext.js +11 -18
- package/lib/module/core/BaseAudioContext.js.map +1 -1
- package/lib/typescript/api.d.ts +5 -1
- package/lib/typescript/api.d.ts.map +1 -1
- package/lib/typescript/core/AudioDecoder.d.ts +4 -0
- package/lib/typescript/core/AudioDecoder.d.ts.map +1 -0
- package/lib/typescript/core/AudioStretcher.d.ts +3 -0
- package/lib/typescript/core/AudioStretcher.d.ts.map +1 -0
- package/lib/typescript/core/BaseAudioContext.d.ts +3 -6
- package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/interfaces.d.ts +10 -3
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/api.ts +10 -0
- package/src/core/AudioDecoder.ts +78 -0
- package/src/core/AudioStretcher.ts +43 -0
- package/src/core/BaseAudioContext.ts +26 -29
- package/src/interfaces.ts +26 -6
- 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
|
|
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
|
|
6
|
-
* allows you to use this code without your entire project being subject
|
|
7
|
-
* terms of the LGPL. However, note that if you link statically to
|
|
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
|
|
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::
|
|
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
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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(
|
|
68
|
-
av_opt_set_int(
|
|
69
|
-
av_opt_set_sample_fmt(
|
|
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,
|
|
73
|
-
av_opt_set_chlayout(
|
|
74
|
-
av_opt_set_int(
|
|
75
|
-
av_opt_set_sample_fmt(
|
|
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(
|
|
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
|
-
|
|
84
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
|
|
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
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
210
|
-
|
|
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
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
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
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
-
|
|
277
|
-
|
|
278
|
-
avio_context_free(&avio_ctx);
|
|
279
|
-
return {};
|
|
280
|
-
}
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
281
235
|
|
|
282
|
-
|
|
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
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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
|
-
|
|
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
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
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
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
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
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
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
|
-
|
|
336
|
-
|
|
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
|
-
|
|
340
|
-
|
|
312
|
+
auto fmt_ctx =
|
|
313
|
+
std::unique_ptr<AVFormatContext, decltype(&avformat_free_context)>(
|
|
314
|
+
raw_fmt_ctx, &avformat_free_context);
|
|
341
315
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
return {};
|
|
316
|
+
if (avformat_find_stream_info(fmt_ctx.get(), nullptr) < 0) {
|
|
317
|
+
return nullptr;
|
|
345
318
|
}
|
|
346
319
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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
|
-
|
|
357
|
-
|
|
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
|
-
|
|
368
|
-
|
|
369
|
-
|
|
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
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
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
|
-
|
|
386
|
-
|
|
387
|
-
|
|
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
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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
|
-
|
|
396
|
-
|
|
348
|
+
if (avformat_find_stream_info(fmt_ctx.get(), nullptr) < 0) {
|
|
349
|
+
return nullptr;
|
|
350
|
+
}
|
|
397
351
|
|
|
398
|
-
|
|
399
|
-
|
|
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
|
|
360
|
+
return decodeAudioFrames(
|
|
361
|
+
fmt_ctx.get(), codec_ctx.get(), audio_stream_index, sample_rate);
|
|
403
362
|
}
|
|
404
363
|
|
|
405
364
|
} // namespace audioapi::ffmpegdecoder
|