How to decode audio via FFmpeg in Android

2019-02-05 09:54发布

I am writing a player for Android with FFmpeg compiled for Android NDK.

I could open the file through FFmpeg and wrote this:

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

How can I now decode the audio and return it to the Java program? Maybe somebody could give me an example

EDIT: When using avcodec_decode_audio3 Get the following: 03-22 07:54:00.988: INFO / DEBUG (31): * ** * ** * ** * * * ** * ** * 03-22 07:54:00.988: INFO / DEBUG (31): Build fingerprint: '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 r2 81893210 r3 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 03-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: INFO / 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

Can I use avcodec_decode_audio2? I have in recent days has reached the following code:

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; 

In this case, when the avcodec_decode_audio2 I got -1. What I did wrong?

Note: When I drove int data_size = 417; then DEBUG does not appear and the function returns -1, but when I drive a: int data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE * 2; then vyskakievaet DEBUG in your function so in my own! How can this be solved?

EDIT2: My new code:


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

2条回答
乱世女痞
2楼-- · 2019-02-05 10:16

I could not post a comment, so am posting this as an answer.

I'm also trying to do play aac audio using ffmpeg but have a lot of questions on how to get it working.

I tried using http://code.google.com/p/aacplayer-android/ as a reference, but the author of the code is not using avcodec_decode_audio3 for decoding. The playback through AudioTrack stutters a lot and I assume that the buffer is not getting filled by the decoder fast enough for the audiotrack to play.

Is there any other way I can do this?

Once again, sorry for posting this as a answer.

查看更多
Juvenile、少年°
3楼-- · 2019-02-05 10:20

Use audiotrack class to do the work for you. You can do something like this.

JAVA side.

            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

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

On native Side : You need to read the frames and convert them into raw pcm format first and then start filling the audio buffer continuously. When the buffer is full, it will automatically play.

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

}

查看更多
登录 后发表回答