我正在编写一个使用AudioRecord
录制用户音频的应用程序。我将原始PCM位保存到short[]
数组(因为我的编码是16位PCM)。录制完成后,我想压缩此音频数据并将其保存到文件中。我想知道Android SDK中是否有一些高级API可以帮助我解决这个问题。
目前,我正在尝试使用MediaCodec
并将其保存为AAC格式。首先,我使用以下代码
ByteBuffer
// allocating the array with length 2 * length of the byte array because we are creating a
// ByteBuffer.
final ByteBuffer byteBuffer = ByteBuffer.allocate(mDataArray.length * 2);
// putting value in the ByteBuffer ..
for(short elem : mDataArray) {
byteBuffer.putShort(elem);
}
因为,我想支持API级别16,我想我必须使用已弃用的一组函数(在此link中使用使用缓冲区数组进行同步处理(不建议使用)) 。这是正确的前进方式吗?
我看到的另一个问题是如何将编码的缓冲区保存到文件中。
答案 0 :(得分:0)
您可以使用非常简单的 MediaRecorder API,并且自 API 1 以来已得到不同程度的支持。
否则,已弃用的缓冲区数组与标准同步方法之间的差异实际上非常小。我和你的情况一样,想支持 API 16,但我不能使用 MediaRecorder。
我创建了填充和排空缓冲区的例程:
private void fillCodecInputBuffer(ByteBuffer inputBuffer, int bufferId) {
... code to fill input buffer ...
}
private void drainCodecOutputBuffer(ByteBuffer outputBuffer, int bufferId) {
... code to drain output buffer ...
}
...然后我从一个单独的例程中为棒棒糖前和棒棒糖后平台调用这些。通过这种方式,较新的平台可以更有效地编码(如果使用已弃用的方法,它们就不能)。
棒棒糖前:
ByteBuffer[] encoderOutputBuffers = encoder.getOutputBuffers();;
ByteBuffer[] encoderInputBuffers = encoder.getInputBuffers();
private void processEncoderKitKat() {
/* uses old pre-LOLLIPOP (v5) method */
final int ENCODER_TIMEOUT_US = 0; /* we poll only - was 10000 */
int inputBufferId = encoder.dequeueInputBuffer(ENCODER_TIMEOUT_US);
if (inputBufferId >= 0) {
fillCodecInputBuffer(encoderInputBuffers[inputBufferId], inputBufferId);
}
int outputBufferId = encoder.dequeueOutputBuffer(encoderBuffer, ENCODER_TIMEOUT_US);
if (outputBufferId >= 0) {
drainCodecOutputBuffer(encoderOutputBuffers[outputBufferId], outputBufferId);
} else if (outputBufferId == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
encoderOutputBuffers = encoder.getOutputBuffers();
}
if ((encoderBuffer.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0)
isFullyEncoded = true;
}
...请注意,这个旧方法可能需要通知您输出缓冲区已更改,您需要重置数组以适应。
棒棒糖后:
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void processEncoderLollipop() {
/* uses post LOLLIPOP (v5) method */
final int ENCODER_TIMEOUT_US = 0; /* we poll only */
int inputBufferId = encoder.dequeueInputBuffer(ENCODER_TIMEOUT_US);
if (inputBufferId >= 0) {
fillCodecInputBuffer(encoder.getInputBuffer(inputBufferId), inputBufferId);
}
int outputBufferId = encoder.dequeueOutputBuffer(encoderBuffer, ENCODER_TIMEOUT_US);
if (outputBufferId >= 0) {
drainCodecOutputBuffer(encoder.getOutputBuffer(outputBufferId), outputBufferId);
}
if ((encoderBuffer.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0)
isFullyEncoded = true;
}
我很确定您也可以构建(推荐的)异步方式来调用填充/排出例程,但我还没有尝试过。