Skip to content

Commit fa895a4

Browse files
authored
fix: use vector for decoded data (#32)
1 parent 44e2742 commit fa895a4

File tree

3 files changed

+54
-111
lines changed

3 files changed

+54
-111
lines changed

android/src/main/cpp/audio/AAssetDataSource.cpp

+4-15
Original file line numberDiff line numberDiff line change
@@ -22,36 +22,25 @@
2222

2323
#include "NDKExtractor.h"
2424

25-
constexpr int kMaxCompressionRatio { 12 };
26-
2725
NewFromCompressedAssetResult
2826
AAssetDataSource::newFromCompressedAsset(int fd, int offset,
2927
int length, AudioProperties targetProperties) {
3028

31-
32-
// Allocate memory to store the decompressed audio. We don't know the exact
33-
// size of the decoded data until after decoding so we make an assumption about the
34-
// maximum compression ratio and the decoded sample format (float for FFmpeg, int16 for NDK).
35-
const long maximumDataSizeInBytes = kMaxCompressionRatio * length * sizeof(int16_t);
36-
auto decodedData = new uint8_t[maximumDataSizeInBytes];
37-
38-
auto decodeResult = NDKExtractor::decodeFileDescriptor(fd, offset, length, decodedData, targetProperties);
29+
auto decodeResult = NDKExtractor::decodeFileDescriptor(fd, offset, length, targetProperties);
3930
if(decodeResult.error) {
4031
return {.dataSource = nullptr, .error = decodeResult.error };
4132
}
4233

43-
auto numSamples = decodeResult.bytesRead / sizeof(int16_t);
34+
auto numSamples = decodeResult.data->size() / sizeof(int16_t);
4435

4536
// Now we know the exact number of samples we can create a float array to hold the audio data
4637
auto outputBuffer = std::make_unique<float[]>(numSamples);
4738

4839
// The NDK decoder can only decode to int16, we need to convert to floats
4940
oboe::convertPcm16ToFloat(
50-
reinterpret_cast<int16_t*>(decodedData),
41+
reinterpret_cast<int16_t*>(decodeResult.data->data()),
5142
outputBuffer.get(),
52-
decodeResult.bytesRead / sizeof(int16_t));
53-
54-
delete[] decodedData;
43+
static_cast<int32_t>(numSamples));
5544

5645
return {
5746
.dataSource = new AAssetDataSource(std::move(outputBuffer),

android/src/main/cpp/audio/NDKExtractor.cpp

+48-94
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,23 @@
2525

2626
#include "NDKExtractor.h"
2727

28-
DecodeFileDescriptorResult NDKExtractor::decodeFileDescriptor(int fd, int offset, int length, uint8_t* targetData, AudioProperties targetProperties) {
29-
LOGD("Using NDK decoder");
30-
31-
// Extract the audio frames
32-
AMediaExtractor *extractor = AMediaExtractor_new();
33-
media_status_t amresult = AMediaExtractor_setDataSourceFd(extractor, fd,
34-
static_cast<off64_t>(offset),
35-
static_cast<off64_t>(length));
36-
if (amresult != AMEDIA_OK){
37-
LOGE("Error setting extractor data source, err %d", amresult);
38-
return {.bytesRead = 0, .error = "Decoding sound file failed"};
28+
DecodeFileDescriptorResult NDKExtractor::decodeFileDescriptor(int fd, int offset, int length, AudioProperties targetProperties) {
29+
auto extractor = AMediaExtractor_new();
30+
auto amResult = AMediaExtractor_setDataSourceFd(
31+
extractor,
32+
fd,
33+
static_cast<off64_t>(offset),
34+
static_cast<off64_t>(length));
35+
36+
if (amResult != AMEDIA_OK){
37+
return {.error = "Decoding sound file failed"};
3938
}
4039

4140
// Specify our desired output format by creating it from our source
42-
AMediaFormat *format = AMediaExtractor_getTrackFormat(extractor, 0);
41+
auto format = AMediaExtractor_getTrackFormat(extractor, 0);
4342

4443
int32_t sampleRate;
4544
if (AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &sampleRate)){
46-
LOGD("File sample rate: %d", sampleRate);
4745
if (sampleRate != targetProperties.sampleRate){
4846
std::stringstream error;
4947
error
@@ -53,15 +51,14 @@ DecodeFileDescriptorResult NDKExtractor::decodeFileDescriptor(int fd, int offset
5351
<< ", doesn't match the sample rate of the stream, "
5452
<< targetProperties.sampleRate << ".";
5553

56-
return {.bytesRead = 0, .error = error.str()};
54+
return {.error = error.str()};
5755
}
5856
} else {
59-
return {.bytesRead = 0, .error = "Failed to load sound file: could not determine sample rate"};
57+
return {.error = "Failed to load sound file: could not determine sample rate"};
6058
};
6159

6260
int32_t channelCount;
6361
if (AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &channelCount)){
64-
LOGD("File channel count: %d", channelCount);
6562
if (channelCount != targetProperties.channelCount){
6663
std::stringstream error;
6764
error
@@ -70,113 +67,70 @@ DecodeFileDescriptorResult NDKExtractor::decodeFileDescriptor(int fd, int offset
7067
<< ", doesn't match the channel count of the stream, "
7168
<< targetProperties.channelCount << ".";
7269

73-
return {.bytesRead = 0, .error = error.str()};
70+
return {.error = error.str()};
7471
}
7572
} else {
76-
return {.bytesRead = 0, .error = "Failed to load sound file: could not determine channel count"};
73+
return {.error = "Failed to load sound file: could not determine channel count"};
7774
}
7875

7976
const char *mimeType;
80-
if (AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mimeType)) {
81-
LOGD("File mime type: %s", mimeType);
82-
} else {
83-
return {.bytesRead = 0, .error = "Failed to load sound file: could not determine mimeType"};
77+
if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mimeType)) {
78+
return {.error = "Failed to load sound file: could not determine mimeType"};
8479
}
8580

8681
// Obtain the correct decoder
87-
AMediaCodec *codec = nullptr;
8882
AMediaExtractor_selectTrack(extractor, 0);
89-
codec = AMediaCodec_createDecoderByType(mimeType);
83+
auto codec = AMediaCodec_createDecoderByType(mimeType);
9084
AMediaCodec_configure(codec, format, nullptr, nullptr, 0);
9185
AMediaCodec_start(codec);
9286

87+
std::vector<uint8_t> data{};
9388
// DECODE
9489

9590
bool isExtracting = true;
9691
bool isDecoding = true;
97-
int32_t bytesWritten = 0;
9892

9993
while(isExtracting || isDecoding){
10094

10195
if (isExtracting){
10296

103-
// Obtain the index of the next available input buffer
104-
ssize_t inputIndex = AMediaCodec_dequeueInputBuffer(codec, 2000);
105-
//LOGV("Got input buffer %d", inputIndex);
97+
auto inputIndex = AMediaCodec_dequeueInputBuffer(codec, 2000);
10698

107-
// The input index acts as a status if its negative
108-
if (inputIndex < 0){
109-
if (inputIndex == AMEDIACODEC_INFO_TRY_AGAIN_LATER){
110-
// LOGV("Codec.dequeueInputBuffer try again later");
111-
} else {
112-
LOGE("Codec.dequeueInputBuffer unknown error status");
113-
}
114-
} else {
99+
if(inputIndex >= 0) {
115100

116101
// Obtain the actual buffer and read the encoded data into it
117-
size_t inputSize;
118-
uint8_t *inputBuffer = AMediaCodec_getInputBuffer(codec, inputIndex, &inputSize);
119-
120-
ssize_t sampleSize = AMediaExtractor_readSampleData(extractor, inputBuffer, inputSize);
121-
auto presentationTimeUs = AMediaExtractor_getSampleTime(extractor);
122-
123-
if (sampleSize > 0){
124-
125-
// Enqueue the encoded data
126-
AMediaCodec_queueInputBuffer(codec, inputIndex, 0, sampleSize,
127-
presentationTimeUs,
128-
0);
129-
AMediaExtractor_advance(extractor);
130-
131-
} else {
132-
LOGD("End of extractor data stream");
133-
isExtracting = false;
134-
135-
// We need to tell the codec that we've reached the end of the stream
136-
AMediaCodec_queueInputBuffer(codec, inputIndex, 0, 0,
137-
presentationTimeUs,
138-
AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
102+
size_t inputSize {};
103+
auto inputBuffer = AMediaCodec_getInputBuffer(codec, inputIndex, &inputSize);
104+
105+
if(inputBuffer) {
106+
auto sampleSize = AMediaExtractor_readSampleData(extractor, inputBuffer, inputSize);
107+
auto presentationTimeUs = AMediaExtractor_getSampleTime(extractor);
108+
109+
if (sampleSize > 0){
110+
AMediaCodec_queueInputBuffer(codec, inputIndex, 0, sampleSize, presentationTimeUs, 0);
111+
AMediaExtractor_advance(extractor);
112+
} else {
113+
isExtracting = false;
114+
AMediaCodec_queueInputBuffer(codec, inputIndex, 0, 0, presentationTimeUs, AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
115+
}
139116
}
140117
}
141118
}
142119

143-
if (isDecoding){
144-
// Dequeue the decoded data
145-
AMediaCodecBufferInfo info;
146-
ssize_t outputIndex = AMediaCodec_dequeueOutputBuffer(codec, &info, 0);
147-
148-
if (outputIndex >= 0){
149-
150-
// Check whether this is set earlier
151-
if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM){
152-
LOGD("Reached end of decoding stream");
153-
isDecoding = false;
120+
if(isDecoding) {
121+
AMediaCodecBufferInfo bufferInfo{};
122+
auto outputIndex = AMediaCodec_dequeueOutputBuffer(codec, &bufferInfo, 2000);
123+
while(outputIndex >= 0) {
124+
auto outputBuffer = AMediaCodec_getOutputBuffer(codec, outputIndex, nullptr);
125+
if(outputBuffer) {
126+
data.insert(data.end(), outputBuffer, outputBuffer + bufferInfo.size);
154127
}
155-
156-
// Valid index, acquire buffer
157-
size_t outputSize;
158-
uint8_t *outputBuffer = AMediaCodec_getOutputBuffer(codec, outputIndex, &outputSize);
159-
160-
// copy the data out of the buffer
161-
memcpy(targetData + bytesWritten, outputBuffer, info.size);
162-
bytesWritten+=info.size;
163128
AMediaCodec_releaseOutputBuffer(codec, outputIndex, false);
164-
} else {
165-
166-
// The outputIndex doubles as a status return if its value is < 0
167-
switch(outputIndex){
168-
case AMEDIACODEC_INFO_TRY_AGAIN_LATER:
169-
LOGD("dequeueOutputBuffer: try again later");
170-
break;
171-
case AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED:
172-
LOGD("dequeueOutputBuffer: output buffers changed");
173-
break;
174-
case AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED:
175-
LOGD("dequeueOutputBuffer: output outputFormat changed");
176-
format = AMediaCodec_getOutputFormat(codec);
177-
LOGD("outputFormat changed to: %s", AMediaFormat_toString(format));
178-
break;
179-
}
129+
outputIndex = AMediaCodec_dequeueOutputBuffer(codec, &bufferInfo, 0);
130+
}
131+
132+
if(bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
133+
isDecoding = false;
180134
}
181135
}
182136
}
@@ -186,6 +140,6 @@ DecodeFileDescriptorResult NDKExtractor::decodeFileDescriptor(int fd, int offset
186140
AMediaCodec_delete(codec);
187141
AMediaExtractor_delete(extractor);
188142

189-
return {.bytesRead = bytesWritten, .error = std::nullopt};
143+
return {.data = data};
190144
}
191145

android/src/main/cpp/audio/NDKExtractor.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@
2424
#include "utils/logging.h"
2525

2626
struct DecodeFileDescriptorResult {
27-
int32_t bytesRead;
27+
std::optional<std::vector<uint8_t>> data;
2828
std::optional<std::string> error;
2929
};
3030

3131

3232
class NDKExtractor {
3333
public:
34-
static DecodeFileDescriptorResult decodeFileDescriptor(int fd, int offset, int length, uint8_t *targetData, AudioProperties targetProperties);
34+
static DecodeFileDescriptorResult decodeFileDescriptor(int fd, int offset, int length, AudioProperties targetProperties);
3535
};
3636

3737
#endif //AUDIOPLAYBACK_NDKMEDIAEXTRACTOR_H

0 commit comments

Comments
 (0)