2011-03-20 49 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