2011-03-20 45 views
1

我正在爲Android爲Android NDK編寫FFmpeg編寫播放器。如何在Android中通過FFmpeg解碼音頻

我可以通過FFmpeg的打開文件,並寫了這個:

av_register_all(); 

char* str = (*env) -> GetStringUTFChars(env, argv, 0); 
__android_log_print(ANDROID_LOG_INFO, "HelloNDK!", str, str); 

if (av_open_input_file (&pFormatCtx, str, NULL, 0, NULL) != 0) 
    return -2; // Couldn't open file 

// Retrieve stream information 
if (av_find_stream_info(pFormatCtx) < 0) 
    return -3; // Couldn't find stream information 

// Dump information about file onto standard error 
dump_format(pFormatCtx, 0, argv, 0); 

// Find the first video stream 
videoStream =- 1; 
audioStream =- 1; 
for (i = 0; i < pFormatCtx->nb_streams; i++) { 
    if (pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO && audioStream <0) { 
     audioStream = i; 
    } 
} 

if (audioStream == -1) 
    return -5; 

aCodecCtx = pFormatCtx->streams[audioStream]->codec; 
// Set audio settings from codec info 

aCodec = avcodec_find_decoder(aCodecCtx->codec_id); 

if (!aCodec) { 
    fprintf (stderr, "Unsupported codec! \n"); 
    return -1; 
} 

avcodec_open (aCodecCtx, aCodec); 

如何我現在可以解碼音頻,並返回到Java程序?也許有人可以給我一個例子

編輯: 當使用avcodec_decode_audio3 得到如下: 七月3日至22日:54:00.988:信息/ DEBUG(31):* * * * * * * * * * * * ** * * * * 03-22 07:54:00.988:INFO/DEBUG(31):構建指紋:'generic/sdk/generic /:2.2/FRF91/43546:eng/test-keys' 03-22 07:54:00.988 :INFO/DEBUG(31):pid:435,tid:435 >>> org.libsdl.app < < < < 03-22 07:54:00.998:INFO/DEBUG(1931):signal 11(SIGSEGV),fault addr 00000000 03-22 07:54:00.998:INFO/DEBUG(1931):r0 00000000 r1 00000000 rr3 00000000 03-22 07:54:01.008:INFO/DEBUG(1931):r4 8189324c r5 818931d0 r6 00000000 r7 00000000 03-22 07:54:01.008:INFO/DEBUG(1931):r8 00000200 r9 00000600 10 00000300 00000500 fp 03-22 07:54:01.019:INFO/DEBUG(1931):ip 81350868 sp bef4c438 lr 8112cb3b pc 8112cb6c cpsr 80000030 0 3-22 07:54:01.369:INFO/DEBUG(31):#00 pc 0012cb6c/data/data/org.libsdl.app/lib/libtest.so 03-22 07:54:01.369:INFO/DEBUG 31):#01 pc 0012db46/data/data/org.libsdl.app/lib/libtest.so 03-22 07:54:01.379:INFO/DEBUG(31):#02 pc 0013052e/data/data/org .libsdl.app/lib/libtest.so 03-22 07:54:01.379:INFO/DEBUG(31):#03 pc 00132142/data/data/org.libsdl.app/lib/libtest.so 03- 22 07:54:01.389:INFO/DEBUG(31):#04 pc 001a2836/data/data/org.libsdl.app/lib/libtest.so 03-22 07:54:01.399:INFO/DEBUG(31) :#05 pc 00024ee6/data/data/org.libsdl.app/lib/libtest.so 03-22 07:54:01.399:INFO/DEBUG(31):#06 pc 00013974/system/lib/libdvm.so 03-22 07:54:01.409:INFO/DEBUG(31):#07 pc 0003de3c/system/lib/libdvm.so 03-22 07:54:01.409:INFO/DEBUG(31):#08 pc 00037216/system/lib/libdvm.so 03-22 07:54:01.419:INFO/DEBUG 31):#09 pc 000432ec/system/lib/libdvm.so 03-22 07:54:01.419:INFO/DEBUG(31):#10 pc 00018714/system/lib/libdvm.so 03-22 07: 54:01.439:INFO/DEBUG(31):#11 pc 0001e8c4/system/lib/libdvm.so 03-22 07:54:01.439:INFO/DEBUG(31):#12 pc 0001d790/system/lib/libdvm .so 03-22 07:54:01.439:INFO/DEBUG(31):#13 pc 0005408e/system/lib/libdvm.so 03-22 07:54:01.449:INFO/DEBUG(31):#14 pc 0005bde2/system/lib/libdvm.so 03-22 07:54:01.449:INFO/DEBUG(31):#15 pc 00018714/system/lib/libdvm.so 03-22 07:54:01.459:INF O/DEBUG(31):#16 pc 0001e8c4/system/lib/libdvm.so 03-22 07:54:01.469:INFO/DEBUG(31):#17 PC 0001d790/system/lib/libdvm.so 03 -22 07:54:01.469:INFO/DEBUG(31):#18 pc 00053eec/system/lib/libdvm.so 03-22 07:54:01。479:INFO/DEBUG(31):#19 pc 0004072c/system/lib/libdvm.so 03-22 07:54:01.479:INFO/DEBUG(31):#20 pc 00034454/system/lib/libdvm.so 03-22 07:54:01.489:INFO/DEBUG(31):#21 pc 0002c930/system/lib/libandroid_runtime.so 03-22 07:54:01.489:INFO/DEBUG(31):#22 pc 0002d85c/system/lib/libandroid_runtime.so 03-22 07:54:01.499:INFO/DEBUG(31):#23 pc 00008c86/system/bin/app_process 03-22 07:54:01.519:INFO/DEBUG(31 ):#24 pc 0000d362/system/lib/libc.so

我可以使用avcodec_decode_audio2嗎? 我在最近幾天已經達到了下面的代碼:

AVFormatContext * pFormatCtx; 
int i, videoStream, audioStream; 
AVCodecContext * pCodecCtx; 
AVCodec * pCodec; 
AVFrame * pFrame; 
AVPacket packet; 
int frameFinished; 
float aspect_ratio; 

AVCodecContext * aCodecCtx; 
AVCodec * aCodec; 


AVCodecContext * c = NULL; 
int out_size, len; 
int16_t * audio_buf; 
uint8_t * outbuf; 
uint8_t inbuf [AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE]; 



av_register_all(); 

char * str = (* env) -> GetStringUTFChars (env, argv, 0); 


if (av_open_input_file (& pFormatCtx, str, NULL, 0, NULL)! = 0) 
return -150; 


if (av_find_stream_info (pFormatCtx) nb_streams; i + +) { 

if (pFormatCtx-> streams [i] -> codec-> codec_type == CODEC_TYPE_VIDEO & & videoStream streams [i] -> codec-> codec_type == CODEC_TYPE_AUDIO & & audioStream streams [audioStream] -> codec; 



aCodec = avcodec_find_decoder (aCodecCtx-> codec_id); 
if (! aCodec) { 
fprintf (stderr, "Unsupported codec! \ n"); 
return -45; 
} 

avcodec_open (aCodecCtx, aCodec); 
c = avcodec_alloc_context(); 
packet_queue_init (& audioq); 
while (av_read_frame (pFormatCtx, & packet)> = 0) { 


if (packet.stream_index == videoStream) { 

} Else if (packet.stream_index == audioStream) { 

packet_queue_put (& audioq, & packet); 
int len1, data_size; 
data_size = 417; 

len1 = avcodec_decode_audio2 (aCodecCtx, (int16_t *) audio_buf, & data_size, 
packet.data, packet.size); 
return packet.size; 
} Else { 
av_free_packet (& packet); 
} 



} 



return 0; 

在這種情況下,當avcodec_decode_audio2我-1。我做錯了什麼?

說明: 當我驅車int data_size = 417;那麼DEBUG不會出現,函數返回-1,但是當我驅動一個:int data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE * 2;然後vyskakievaet DEBUG在你的功能,所以在我自己的!這怎麼解決?

EDIT2: 我的新代碼:


JNIEXPORT jint JNICALL Java_org_libsdl_app_SDLActivity_main(JNIEnv* env, jobject obj, int argc, jstring argv, jbyteArray array) { 
     AVFormatContext *pFormatCtx; 
     int    i, videoStream, audioStream; 
     AVCodecContext *pCodecCtx; 
     AVCodec   *pCodec; 
     AVFrame   *pFrame; 
     AVPacket  packet; 
     int    frameFinished; 
     float   aspect_ratio; 

     AVCodecContext *aCodecCtx; 
     AVCodec   *aCodec; 

     SDL_Overlay  *bmp; 
     SDL_Surface  *screen; 
     SDL_Rect  rect; 
     SDL_Event  event; 
     SDL_AudioSpec wanted_spec, spec; 
     AVCodecContext *c= NULL; 
     int out_size, len; 
     int16_t *audio_buf; 
     uint8_t *outbuf; 
     uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE]; 
     char *pAudioBuffer = (char *) av_malloc (AVCODEC_MAX_AUDIO_FRAME_SIZE * 2); 




     av_register_all(); 

     char *str = (*env)->GetStringUTFChars(env, argv, 0); 


     if(av_open_input_file(&pFormatCtx, str, NULL, 0, NULL)!=0) 
     return -150; // Couldn't open file 


     if(av_find_stream_info(pFormatCtx)nb_streams; i++) { 
     if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO && 
      videoStream streams[i]->codec->codec_type==CODEC_TYPE_AUDIO && 
      audioStream streams[audioStream]->codec; 



     aCodec = avcodec_find_decoder(aCodecCtx->codec_id); 
     if(!aCodec) { 
     fprintf(stderr, "Unsupported codec!\n"); 
     return -45; 
     } 

     avcodec_open(aCodecCtx, aCodec); 
     c=avcodec_alloc_context(); 
     packet_queue_init(&audioq); 
     while (av_read_frame(pFormatCtx, &packet)>= 0) { 
      if (aCodecCtx->codec_type == AVMEDIA_TYPE_AUDIO) { 
         int data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE * 2; 
         int size=packet.size; 
         while(size > 0) { 
           int len = avcodec_decode_audio3(aCodecCtx, (int16_t *) pAudioBuffer, &data_size, &packet); 

           jbyte *bytes = (*env)->GetByteArrayElements(env, array, NULL); 
           memcpy(bytes, (int16_t *) pAudioBuffer, size); 
           (*env)->ReleaseByteArrayElements(env, array, bytes, 0); 


           size = packet.size-len; 
           } 
      } 

    } 










return 5; 
} 
+0

你能解釋爲什麼你在memcpy中使用「size」而不是len? 據我所知,我們從「pAudioBuffer」複製到長度爲「size」的「bytes」。但size是avpacket的大小,而pAudioBuffer已經解碼了長度爲「len」的數據。那是對的嗎? (我不是C專業人士 - 試圖學習) – 2011-10-25 08:36:37

回答

4

使用audiotrack類做的工作適合你。你可以做這樣的事情。

JAVA方面。

  AudioTrack track; 

      int bufSize = AudioTrack.getMinBufferSize(44100,        AudioFormat.CHANNEL_CONFIGURATION_MONO, 
          AudioFormat.ENCODING_PCM_16BIT); 


      track = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, 
         AudioFormat.ENCODING_PCM_16BIT, bufSize, AudioTrack.MODE_STREAM); 

      track.play(); 

      while(true){ 
      readBufferFromNative(); //update buffer from native code 

        .................... 
        .................... 
        } 

本地端:您需要先讀取幀並將其轉換爲原始pcm格式,然後開始連續填充音頻緩衝區。當緩衝區滿時,它會自動播放。

JNIEXPORT int JNICALL Java_com_ffmpeg_Main_jniMainEntry(JNIEnv* env, jobject obj, jstring input) { 

    const char * pszFileName = (*env)->GetStringUTFChars(env, input, 0); 
    AVFormatContext * m_fc; 
    int err; 
    AVPacket pkt; 
    char * pAudioBuffer = (char *) av_malloc (AVCODEC_MAX_AUDIO_FRAME_SIZE * 2); 
    int i; 

    avcodec_register_all(); 
    avdevice_register_all(); 
    av_register_all(); 

    err = av_open_input_file(&m_fc, pszFileName, 0, 0, 0); 
    err = av_find_stream_info(m_fc); 
    for(i = 0; i<m_fc->nb_streams; i++) { 
    if((m_fc->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) || (m_fc->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)) { 
    AVCodec *codec = avcodec_find_decoder(m_fc->streams[i]->codec->codec_id); 

    if (codec == 0) 
      continue; 
    err = avcodec_open(m_fc->streams[i]->codec, codec); 
    if (err <0) 
      continue; 
    } 
} 
    while (av_read_frame(m_fc, &pkt)>= 0) { 
      if (m_fc-> streams[pkt.stream_index]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { 
        int data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE * 2; 
        int size=pkt->size; 
        while(size > 0) { 
          int len = avcodec_decode_audio3(m_fc->streams[pkt.stream_index]->codec, (int16_t *) pAudioBuffer, &data_size, &pkt); 
          LOGD("data_size %d len %d", data_size, len); 
          size = pkt->size-len; 
          } 
      } 
} 

}

+0

我更新了問題。請再看一遍。有一個問題。 – Kyborg2011 2011-03-22 08:04:03

+0

我已經編輯了上面的代碼,並且我試過了我的機器人,avcodec_decode_audio3總是返回它使用的字節,並且總是一個正值。我對上面的代碼沒有任何問題。嘗試將malloc更改爲av_malloc。有時候這會做。 – 2011-03-22 16:39:57

+0

你的代碼我沒有編譯(沒有找到函數avdevice_register_all),但我升級了我的代碼,現在返回一些必要的東西。問題是:如何處理我收到的緩衝區?我明白 - 它應該傳輸Java程序。但是如何?我希望它不難:) P.S.我可以通過電子郵件聯繫您嗎?因此,如果不是太困難,它可能會幫助別的地方。 – Kyborg2011 2011-03-22 17:47:55

0

我不能發表評論,所以我張貼此作爲一個答案。

我也試圖使用ffmpeg來播放aac音頻,但在如何讓它工作方面有很多問題。

我嘗試使用http://code.google.com/p/aacplayer-android/作爲參考,但該代碼的作者未使用avcodec_decode_audio3進行解碼。通過AudioTrack的回放會造成很多困難,並且我認爲緩衝區沒有被解碼器充滿足夠快的速度以便audiotrack播放。

有沒有其他辦法可以做到這一點?

再次,抱歉發佈這個答案。

+0

在什麼設備上你正在測試它?它在模擬器上該死的太慢了,我在機器人上試了一樣,這很好,讓我知道如果你不是在模擬器上試試 – 2011-03-22 14:29:05

+0

我已經在Droid和HTC Hero上進行了測試。兩者的播放都相同。 – HariKJ 2011-03-22 23:45:53