#android #c #audio #resampling #oboe
#Android #c #Аудио #повторная дискретизация #гобой
Вопрос:
Я использую oboe для воспроизведения звуковых файлов на Android. У меня есть файлы с частотой 44,1 кГц и 48 кГц, которые я хочу иметь возможность воспроизводить в одном и том же аудиопотоке, поэтому мне нужно выполнить повторную выборку.
Декодирование и воспроизведение файлов работает нормально, но поскольку у меня две разные частоты дискретизации, мне нужно выполнить повторную дискретизацию (в настоящее время я пытаюсь выполнить с 44,1 до 48, поскольку мой аудиопоток составляет 48 кГц.)
Итак, я пытаюсь выполнить передискретизацию с помощью передискретизатора oboe, но я не совсем понимаю, как это сделать. Следуя руководству readme по преобразованию фиксированного количества входных кадров (я предполагаю, что это то, что я должен сделать?), Я попытался реализовать следующим образом. Первая часть кода получает декодированное и возвращает, если частоты дискретизации равны (эта часть работает так, как задумано), во второй части я пытаюсь выполнить повторную выборку при необходимости:
StorageDataSource *StorageDataSource::newFromStorageAsset(AMediaExtractor amp;extractor,
const char *fileName,
AudioProperties targetProperties) {
std::ifstream stream;
stream.open(fileName, std::ifstream::in | std::ifstream::binary);
stream.seekg(0, std::ios::end);
long size = stream.tellg();
stream.close();
constexpr int kMaxCompressionRatio{12};
const long maximumDataSizeInBytes =
kMaxCompressionRatio * (size) * sizeof(int16_t);
auto decodedData = new uint8_t[maximumDataSizeInBytes];
int32_t rate = NDKExtractor::getSampleRate(extractor);
int32_t *inputSampleRate = amp;rate;
int64_t bytesDecoded = NDKExtractor::decode(extractor, decodedData, targetProperties);
auto numSamples = bytesDecoded / sizeof(int16_t);
auto outputBuffer = std::make_unique<float[]>(numSamples);
// The NDK decoder can only decode to int16, we need to convert to floats
oboe::convertPcm16ToFloat(
reinterpret_cast<int16_t *>(decodedData),
outputBuffer.get(),
bytesDecoded / sizeof(int16_t));
if (*inputSampleRate == targetProperties.sampleRate) {
return new StorageDataSource(std::move(outputBuffer),
numSamples,
targetProperties);
} else {
// this is where I try to convert the sample rate
float *inputBuffer;
inputBuffer = reinterpret_cast<float *>(decodedData); // is this correct?
float *outputBuffer2; // multi-channel buffer to be filled, TODO improve name
int numInputFrames; // number of frames of input
// TODO is this correct?
numInputFrames = numSamples / 2;
int numOutputFrames = 0;
int channelCount = 2;
resampler::MultiChannelResampler *mResampler = resampler::MultiChannelResampler::make(
2, // channel count
44100, // input sampleRate
48000, // output sampleRate
resampler::MultiChannelResampler::Quality::Best); // conversion quality
int inputFramesLeft = numInputFrames;
while (inputFramesLeft > 0) {
if (mResampler->isWriteNeeded()) {
mResampler->writeNextFrame(inputBuffer);
inputBuffer = channelCount;
inputFramesLeft--;
} else {
mResampler->readNextFrame(outputBuffer2);
outputBuffer2 = channelCount;
numOutputFrames ;
}
}
delete mResampler;
// return is missing!
}
// returning the original data since above code doesn't work properly yet
return new StorageDataSource(std::move(outputBuffer),
numSamples,
targetProperties);
}
Повторная дискретизация завершается сбоем с SIGSEV
:
A: signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x7fe69c7000
A: x0 0000007c0e3d1e00 x1 0000007fe69c7000 x2 0000007bb77dd198 x3 0000007bf5432140
A: x4 0000000000000021 x5 8080800000000000 x6 fefeff7b976e0667 x7 7f7f7f7fff7f7f7f
A: x8 0000000000000660 x9 0000000000000660 x10 0000000000000000 x11 0000007bf5435840
A: x12 0000007bb77dd118 x13 0000000000000008 x14 0000007bf54321c0 x15 0000000000000008
A: x16 0000007bf5432200 x17 0000000000000000 x18 0000007fe69bf7ba x19 0000007c14e14c00
A: x20 0000000000000000 x21 0000007c14e14c00 x22 0000007fe69c0d70 x23 0000007bfc6e5dc7
A: x24 0000000000000008 x25 0000007c9b7705f8 x26 0000007c14e14ca0 x27 0000000000000002
A: x28 0000007fe69c0aa0 x29 0000007fe69c0420
A: sp 0000007fe69c0400 lr 0000007bf94f61f0 pc 0000007bf9501b5c
A: backtrace:
A: #00 pc 0000000000078b5c /data/app/myapp-G-GmPWmPgOGfffk-qHsQxw==/lib/arm64/libnative-lib.so (resampler::PolyphaseResamplerStereo::readFrame(float*) 684)
A: #01 pc 000000000006d1ec /data/app/myapp-G-GmPWmPgOGfffk-qHsQxw==/lib/arm64/libnative-lib.so (resampler::MultiChannelResampler::readNextFrame(float*) 44)
A: #02 pc 000000000006c84c /data/app/myapp-G-GmPWmPgOGfffk-qHsQxw==/lib/arm64/libnative-lib.so (StorageDataSource::newFromStorageAsset(AMediaExtractoramp;, char const*, AudioProperties) 1316)
A: #03 pc 78bbcdd7f9b20dbe <unknown>
Вот мои основные проблемы:
Во-первых, как мне правильно определить количество кадров на моем входе? Как именно фреймы работают с аудиоданными? Я исследовал это, и я все еще не уверен, что понял это? Является ли это постоянным числом? Как я могу рассчитать количество кадров. Как это соотносится с сэмплами, частотой дискретизации и скоростью передачи битов?
Во-вторых, использую ли я вообще правильные входные данные? Я использую свое decodedData
значение, поскольку это то, что я получаю обратно от декодера, и только reinterpret_cast
это float*
означает.
Поскольку у меня довольно мало опыта работы с C , я не уверен, правильно ли то, что я делаю, и, возможно, я привожу несколько ошибок в этот фрагмент кода.
Редактировать: Поскольку я пытаюсь выполнить повторную выборку моего декодированного вывода, я предполагаю, что эта часть информации об PCM из here объясняет, что здесь подразумевается под фреймами:
For encodings like PCM, a frame consists of the set of samples for all channels at a given point in time, and so the size of a frame (in bytes) is always equal to the size of a sample (in bytes) times the number of channels.
Правильно ли это в моем случае? Это означало бы, что я могу вычесть количество кадров из количества сэмплов, длины моего звукового бита и количества каналов?
Комментарии:
1. К сожалению, я не могу ответить на все вопросы, но я хочу попытаться немного помочь с пониманием кадров. «Как я могу рассчитать количество кадров». — для формата PCM (*.wav) общее количество кадров равно «длительности в секундах * частоте кадров». Допустим, у вас есть аудио с частотой кадров 44100 (44,1 кГц) и длительностью 5 секунд. Это означает, что количество кадров будет равно 44100 * 5.
2. То есть это означает, что кадр содержит информацию для всех каналов этого файла за определенный момент времени, как указано выше? Итак, если у меня есть файл PCM 44100Hz и я знаю его размер, могу ли я также каким-то образом узнать продолжительность? Какова связь между размером файла и длительностью?
3. @michpohl ты заставил это работать? Мне нужна похожая вещь
4. К сожалению, нет, я этого не делал. Поскольку это было более удобно для меня, я в конечном итоге пропустил это.