diff options
| author | swurl <swurl@swurl.xyz> | 2025-05-31 02:33:02 -0400 |
|---|---|---|
| committer | swurl <swurl@swurl.xyz> | 2025-05-31 02:33:02 -0400 |
| commit | 6c655321e6b04b8648802e296bb5ca11d290ae68 (patch) | |
| tree | 5c906511e4a2910ce8b806bb9d763b524c28619e /externals/oboe/samples/RhythmGame/src/main/cpp/audio/NDKExtractor.cpp | |
| parent | c0cceff365f754f8859f4c9a0362ebdba7ea388b (diff) | |
Move dead submodules in-tree
Signed-off-by: swurl <swurl@swurl.xyz>
Diffstat (limited to 'externals/oboe/samples/RhythmGame/src/main/cpp/audio/NDKExtractor.cpp')
| -rw-r--r-- | externals/oboe/samples/RhythmGame/src/main/cpp/audio/NDKExtractor.cpp | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/externals/oboe/samples/RhythmGame/src/main/cpp/audio/NDKExtractor.cpp b/externals/oboe/samples/RhythmGame/src/main/cpp/audio/NDKExtractor.cpp new file mode 100644 index 0000000000..ac50940d91 --- /dev/null +++ b/externals/oboe/samples/RhythmGame/src/main/cpp/audio/NDKExtractor.cpp @@ -0,0 +1,199 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sys/types.h> + +#include <cstring> + +#include <media/NdkMediaExtractor.h> +#include <utils/logging.h> +#include <cinttypes> + +#include "NDKExtractor.h" + +int32_t NDKExtractor::decode(AAsset *asset, uint8_t *targetData, AudioProperties targetProperties) { + + LOGD("Using NDK decoder"); + + // open asset as file descriptor + off_t start, length; + int fd = AAsset_openFileDescriptor(asset, &start, &length); + + // Extract the audio frames + AMediaExtractor *extractor = AMediaExtractor_new(); + media_status_t amresult = AMediaExtractor_setDataSourceFd(extractor, fd, + static_cast<off64_t>(start), + static_cast<off64_t>(length)); + if (amresult != AMEDIA_OK){ + LOGE("Error setting extractor data source, err %d", amresult); + return 0; + } + + // Specify our desired output format by creating it from our source + AMediaFormat *format = AMediaExtractor_getTrackFormat(extractor, 0); + + int32_t sampleRate; + if (AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &sampleRate)){ + LOGD("Source sample rate %d", sampleRate); + if (sampleRate != targetProperties.sampleRate){ + LOGE("Input (%d) and output (%d) sample rates do not match. " + "NDK decoder does not support resampling.", + sampleRate, + targetProperties.sampleRate); + return 0; + } + } else { + LOGE("Failed to get sample rate"); + return 0; + }; + + int32_t channelCount; + if (AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &channelCount)){ + LOGD("Got channel count %d", channelCount); + if (channelCount != targetProperties.channelCount){ + LOGE("NDK decoder does not support different " + "input (%d) and output (%d) channel counts", + channelCount, + targetProperties.channelCount); + } + } else { + LOGE("Failed to get channel count"); + return 0; + } + + const char *formatStr = AMediaFormat_toString(format); + LOGD("Output format %s", formatStr); + + const char *mimeType; + if (AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mimeType)) { + LOGD("Got mime type %s", mimeType); + } else { + LOGE("Failed to get mime type"); + return 0; + } + + // Obtain the correct decoder + AMediaCodec *codec = nullptr; + AMediaExtractor_selectTrack(extractor, 0); + codec = AMediaCodec_createDecoderByType(mimeType); + AMediaCodec_configure(codec, format, nullptr, nullptr, 0); + AMediaCodec_start(codec); + + // DECODE + + bool isExtracting = true; + bool isDecoding = true; + int32_t bytesWritten = 0; + + while(isExtracting || isDecoding){ + + if (isExtracting){ + + // Obtain the index of the next available input buffer + ssize_t inputIndex = AMediaCodec_dequeueInputBuffer(codec, 2000); + //LOGV("Got input buffer %d", inputIndex); + + // The input index acts as a status if its negative + if (inputIndex < 0){ + if (inputIndex == AMEDIACODEC_INFO_TRY_AGAIN_LATER){ + // LOGV("Codec.dequeueInputBuffer try again later"); + } else { + LOGE("Codec.dequeueInputBuffer unknown error status"); + } + } else { + + // Obtain the actual buffer and read the encoded data into it + size_t inputSize; + uint8_t *inputBuffer = AMediaCodec_getInputBuffer(codec, inputIndex, &inputSize); + //LOGV("Sample size is: %d", inputSize); + + ssize_t sampleSize = AMediaExtractor_readSampleData(extractor, inputBuffer, inputSize); + auto presentationTimeUs = AMediaExtractor_getSampleTime(extractor); + + if (sampleSize > 0){ + + // Enqueue the encoded data + AMediaCodec_queueInputBuffer(codec, inputIndex, 0, sampleSize, + presentationTimeUs, + 0); + AMediaExtractor_advance(extractor); + + } else { + LOGD("End of extractor data stream"); + isExtracting = false; + + // We need to tell the codec that we've reached the end of the stream + AMediaCodec_queueInputBuffer(codec, inputIndex, 0, 0, + presentationTimeUs, + AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM); + } + } + } + + if (isDecoding){ + // Dequeue the decoded data + AMediaCodecBufferInfo info; + ssize_t outputIndex = AMediaCodec_dequeueOutputBuffer(codec, &info, 0); + + if (outputIndex >= 0){ + + // Check whether this is set earlier + if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM){ + LOGD("Reached end of decoding stream"); + isDecoding = false; + } + + // Valid index, acquire buffer + size_t outputSize; + uint8_t *outputBuffer = AMediaCodec_getOutputBuffer(codec, outputIndex, &outputSize); + + /*LOGV("Got output buffer index %d, buffer size: %d, info size: %d writing to pcm index %d", + outputIndex, + outputSize, + info.size, + m_writeIndex);*/ + + // copy the data out of the buffer + memcpy(targetData + bytesWritten, outputBuffer, info.size); + bytesWritten+=info.size; + AMediaCodec_releaseOutputBuffer(codec, outputIndex, false); + } else { + + // The outputIndex doubles as a status return if its value is < 0 + switch(outputIndex){ + case AMEDIACODEC_INFO_TRY_AGAIN_LATER: + LOGD("dequeueOutputBuffer: try again later"); + break; + case AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED: + LOGD("dequeueOutputBuffer: output buffers changed"); + break; + case AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED: + LOGD("dequeueOutputBuffer: output outputFormat changed"); + format = AMediaCodec_getOutputFormat(codec); + LOGD("outputFormat changed to: %s", AMediaFormat_toString(format)); + break; + } + } + } + } + + // Clean up + AMediaFormat_delete(format); + AMediaCodec_delete(codec); + AMediaExtractor_delete(extractor); + + return bytesWritten; +} |
