2012-11-21 146 views
2

我已經建立的ffmpeg 0.8.12(愛)在Ubuntu了Android NDK(R8C)。 然後我通過JNI在另一個android應用程序中使用生成的庫。解碼AAC與ffmpeg的PCM在Android

本質上,我想要做的就是將一個字節流從Java傳遞給我的c jni函數,並使用ffmpeg將它解碼爲一個PCM音頻緩衝區,然後將其傳回到java,使用Android的AudioTrack進行播放。我可以成功地通過到JNI傳遞緩衝液(已檢查的值)和FFMPEG似乎正常初始化,但是,當它試圖在第一幀進行解碼,它引發在aacdec.c「信道元件的aac_decode_frame_int方法的誤差0.0不分配」。 aac文件播放正常並且有效。

這裏是我的JNI代碼來執行解碼

jint Java_com_example_testffmpeg_MainActivity_decodeAacBytes(JNIEnv * env, 
     jobject this, jbyteArray input, jint numBytes) { 

    //copy bytes from java 
    jbyte* bufferPtr = (*env)->GetByteArrayElements(env, input, NULL); 
    uint8_t inputBytes[numBytes + FF_INPUT_BUFFER_PADDING_SIZE]; 
    memset(inputBytes, 0, numBytes + FF_INPUT_BUFFER_PADDING_SIZE); 
    memcpy(inputBytes, bufferPtr, numBytes); 
    (*env)->ReleaseByteArrayElements(env, input, bufferPtr, 0); 

    av_register_all(); 

    AVCodec *codec = avcodec_find_decoder(CODEC_ID_AAC); 

    if (codec == NULL) { 
     LOGE("Cant find AAC codec\n"); 
     return 0; 
    } 
    LOGI("AAC codec found\n"); 

    AVCodecContext *avCtx = avcodec_alloc_context(); 

    if (avCtx == NULL) { 
     LOGE("Could not allocate codec context\n"); 
     return 0; 
    } 
    LOGI("codec context allocated\n"); 

    if (avcodec_open2(avCtx, codec, NULL) < 0) { 
     LOGE("Could not open codec\n"); 
     return 0; 
    } 
    LOGI("AAC codec opened"); 

    //the input buffer 
    AVPacket avPacket; 
    av_init_packet(&avPacket); 

    LOGI("AVPacket initialised\n"); 

    avPacket.size = numBytes; //input buffer size 
    avPacket.data = inputBytes; // the input buffer 

    int outSize; 
    int len; 
    uint8_t *outbuf = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); 

    while (avPacket.size > 0) { 
     outSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; 
     len = avcodec_decode_audio3(avCtx, (short *) outbuf, &outSize, 
       &avPacket); 

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

     if (outSize > 0) { 
      LOGI("Decoded some stuff\n"); 
     } 

     avPacket.size -= len; 
     avPacket.data += len; 
    } 

    LOGI("Freeing memory\n"); 

    av_free_packet(&avPacket); 
    avcodec_close(avCtx); 
    av_free(avCtx); 

    return 0; 
} 

發生在通話中的問題avcodec_decode_audio3,當解碼第一次出現。我已經通過了ffmpeg代碼,但找不到問題。任何幫助將不勝感激!

+0

您是否嘗試解碼主機上的文件?它是由ffmpeg解碼的嗎?那麼SoX呢,它能夠做到這一點,還能規範化,淡入/淡出,改變音量等? – rraallvv

+0

我還沒有嘗試通過在控制檯中使用ffmpeg來解碼文件 - 我試圖從我的應用程序代碼中進行解碼,因此無論如何這都無濟於事。該文件在我手機上的任何播放器上都能正確播放,因此它不會損壞。 – JeffG

+1

我的意思是與NDK編譯SoX,請參閱[此鏈接](http://stackoverflow.com/questions/8582765/android-ndk-linking-problems)。 – rraallvv

回答

4

打電話avcodec_open2之前,您必須爲AVCodecContext一些額外的設置。

我通常設置這些需要的設置(變量與 'K' 開頭的意思是預定義constatns):

avCtx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; 
avCtx->codec_type = AVMEDIA_TYPE_AUDIO; 
avCtx->channels = kChannelsCount; // for example, 2 
avCtx->sample_fmt = kSampleFmt; // AV_SAMPLE_FMT_S16 
avCtx->sample_rate = kSampleRate; // 44100 
avCtx->channel_layout = kSampleLayout; // 3 
const AVRational timeBase = {1, avCtx->sample_rate}; 
avCtx->time_base = timeBase; 

UPD

對不起,我寫了必須設置的參數音頻編碼。 對於音頻解碼通常足以設置avCtx->channelsctx->sample_rate或設置avCtx->extrdataavCtx->extradata_size

要找到錯誤的原因,嘗試看看ffmpeg的輸出。如果在設備上很難做到,您可以重定向ffmpeg輸出並通過自己的回調執行日誌記錄。例如:

// initialize: 
    ::av_log_set_callback(&my_ffmpeg_log); 

    // callback 
    void my_ffmpeg_log(void *ptr, int level, const char *fmt, va_list vl) 
    { 
     /// Here you can set a more detailed level 
     if (level < AV_LOG_VERBOSE) 
     { 
     static char message[8192]; 
     const char *module = NULL; 

     if (ptr) 
     { 
      AVClass *avc = *(AVClass**) ptr; 
      if (avc->item_name) 
      module = avc->item_name(ptr); 
     } 
     vsnprintf(message, sizeof message, fmt, vl); 
     // you can set own function here, for example LOGI, as you have in your example 
     std::cout << "ffmpeg message : " << module << " " << level << " " << message; 
     } 
    } 
+0

感謝您的信息。我想這一點,但我得到了同樣的錯誤:(你有任何其他建議 – JeffG

+1

見更新我的回答 – pogorskiy

+0

感謝您的代碼來獲取註銷 - 唯一的日誌是一個錯誤「未分配的信道單元0.0」。不幸的是,設置你所提到的attrib並沒有幫助,我正在解碼的aac是在一個m4a容器中(這應該不重要).ffmpeg文檔表示extradata可以包含全局標題,但它們也可以位於字節流中,它們是:( – JeffG

相關問題