2013-01-24 1 views
2

J'ai un flux vidéo qui m'envoie de l'audio en utilisant le codec ADPCM. Cependant, Android ne supporte que le format PCM. Comment puis-je convertir le flux audio ADPCM en un flux audio PCM?Comment convertir ADPCM en PCM en utilisant FFmpeg?

La réponse à cette question peut être similaire à la réponse à this question.

J'ai réussi à décoder le cadre avec ce code:

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

est le secret ici d'utiliser une fonction inverse encode?

Voici ce que j'ai jusqu'à présent dans ma fonction de décodage audio:

<!-- 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); 
     } 

Répondre

2

Il s'avère que les fonctions audio_decode_ retournent le format PCM 16 bits, et que je ne savais pas comment y accéder correctement.

Voici le code modifié à l'intérieur de la boucle de paquets qui lit l'audio basé sur 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); 
} 
0

Vous pouvez voir un exemple de code à http://ffmpeg.org/doxygen/trunk/doc_2examples_2decoding_encoding_8c-example.html

Voir audio_encode_example fonction.

+0

L'exemple montre seulement comment encoder de l'audio aléatoire dans un paquet et le retourner dans un fichier. Le problème que j'ai est que je peux décoder avec succès l'ADPCM, mais je ne sais pas comment le ré-encoder en PCM Frame pour écrire sur un AudioTrack Android. Avez-vous un exemple plus spécifique? – mystafer

Questions connexes