【问题标题】:How do I convert ADPCM to PCM using FFmpeg?如何使用 FFmpeg 将 ADPCM 转换为 PCM?
【发布时间】:2013-01-07 16:44:26
【问题描述】:

我有一个视频源,它使用 ADPCM 编解码器向我发送音频。但是,android 只支持 PCM 格式。如何将 ADPCM 音频输入转换为 PCM 音频输入?

这个问题的答案可能和this question的答案类似。

我已经用这段代码成功解码了帧:

int len = avcodec_decode_audio4(pAudioCodecCtx, pAudioFrame, &frameFinished, &packet);

这里有使用反向encode函数的秘诀吗?

这是我目前的音频解码功能:

<!-- language: c -->
if(packet_queue_get(env, javaThread, pAudioPacketQueue, &packet, 1) < 0) {
    LOGE("audio - after get packet failed");
    return;
}
LOGD("Dequeued audio packet");

// calculate frame size
int frameSize;
if (pPcmAudioCodecCtx->frame_size) {
    frameSize = pPcmAudioCodecCtx->frame_size;
} else {
    /* if frame_size is not set, the number of samples must be
     * calculated from the buffer size */
    int64_t nb_samples = (int64_t)AUDIO_PCM_OUTBUFF_SIZE * 8 /
            (av_get_bits_per_sample(pPcmAudioCodecCtx->codec_id) *
                    pPcmAudioCodecCtx->channels);
    frameSize = nb_samples;
}

int pcmBytesPerSample = av_get_bytes_per_sample(pPcmAudioCodecCtx->sample_fmt);
int pcmFrameBytes = frameSize * pcmBytesPerSample * pPcmAudioCodecCtx->channels;

uint8_t *pDataStart = packet.data;
while(packet.size > 0) {
    int len = avcodec_decode_audio4(pAudioCodecCtx, pAudioFrame, &frameFinished, &packet);
    LOGD("Decoded ADPCM frame");

    if (len < 0) {
        LOGE("Error while decoding audio");
        return;
    }

    if (frameFinished) {
        // store frame data in FIFO buffer
        uint8_t *inputBuffer = pAudioFrame->data[0];
        int inputBufferSize = pAudioFrame->linesize[0];
        av_fifo_generic_write(fifoBuffer, inputBuffer, inputBufferSize, NULL);
        LOGD("Added ADPCM frame to FIFO buffer");

        // check if fifo buffer has enough data for a PCM frame
        while (av_fifo_size(fifoBuffer) >= pcmFrameBytes) {
            LOGI("PCM frame data in FIFO buffer");

            // read frame's worth of data from FIFO buffer
            av_fifo_generic_read(fifoBuffer, pAudioPcmOutBuffer, pcmFrameBytes, NULL);
            LOGD("Read data from FIFO buffer into pcm frame");


            avcodec_get_frame_defaults(pPcmAudioFrame);
            LOGD("Got frame defaults");

            pPcmAudioFrame->nb_samples = pcmFrameBytes / (pPcmAudioCodecCtx->channels *
                    pcmBytesPerSample);

            avcodec_fill_audio_frame(pPcmAudioFrame, pPcmAudioCodecCtx->channels,
                    pPcmAudioCodecCtx->sample_fmt,
                    pAudioPcmOutBuffer, pcmFrameBytes, 1);
            LOGD("Filled frame audio with data");

            // fill audio play buffer
            int dataSize = pPcmAudioFrame->linesize[0];
            LOGD("Data to output: %d", dataSize);
            jbyteArray audioPlayBuffer = (jbyteArray) env->GetObjectField(ffmpegCtx, env->GetFieldID(cls, "audioPlayBuffer", "[B"));
            jbyte *bytes = env->GetByteArrayElements(audioPlayBuffer, NULL);
            memcpy(bytes, pPcmAudioFrame->data[0], dataSize);
            env->ReleaseByteArrayElements(audioPlayBuffer, bytes, 0);
            LOGD("Copied data into Java array");

            env->CallVoidMethod(player, env->GetMethodID(playerCls, "updateAudio", "(I)V"), dataSize);
        }

【问题讨论】:

    标签: audio android-ndk ffmpeg pcm


    【解决方案1】:

    原来audio_decode_ 函数返回 16 位 PCM 格式,而我只是不知道如何正确访问它。

    这是在基于avcodec_decode_audio4 播放音频的数据包循环内更改的代码。

    int len = avcodec_decode_audio4(pAudioCodecCtx, pAudioFrame, &frameFinished, &packet);
    
    if (len < 0) {
        LOGE("Error while decoding audio");
        return;
    }
    
    if (frameFinished) {
        int planeSize;
        uint8_t *pcmBuffer = pAudioFrame->extended_data[0];
        int dataSize = av_samples_get_buffer_size(&planeSize, pAudioCodecCtx->channels,
                                                           pAudioFrame->nb_samples,
                                                           pAudioCodecCtx->sample_fmt, 1);
        // fill audio play buffer
        jbyteArray audioPlayBuffer = (jbyteArray) env->GetObjectField(ffmpegCtx, env->GetFieldID(cls, "audioPlayBuffer", "[B"));
        jbyte *bytes = env->GetByteArrayElements(audioPlayBuffer, NULL);
        memcpy(bytes, pcmBuffer, dataSize);
        env->ReleaseByteArrayElements(audioPlayBuffer, bytes, 0);
        env->CallVoidMethod(player, env->GetMethodID(playerCls, "updateAudio", "(I)V"), dataSize);
    }
    

    【讨论】:

      【解决方案2】:

      您可以在http://ffmpeg.org/doxygen/trunk/doc_2examples_2decoding_encoding_8c-example.html查看示例代码

      audio_encode_example函数。

      【讨论】:

      • 这个例子只展示了如何将随机音频编码成一个数据包并输出回一个文件。我遇到的问题是我可以成功解码 ADPCM,但我不知道如何将其重新编码为 PCM 帧以写入 Android AudioTrack。你有更具体的例子吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-26
      • 1970-01-01
      • 2010-11-18
      • 2012-12-31
      • 2015-11-08
      • 1970-01-01
      • 2012-08-12
      相关资源
      最近更新 更多