preface

Based on theAndroid NDK development journey 33–FFmpeg video playbackIn this article, we have learned the basic process of video decoding. This article will analyze the audio decoding.
Audio decoding and video decoding routine is basically the same, otherwise how can achieve audio and video synchronous playback?

1. Analysis of FFmpeg audio visual decoding process

Refer to video decoding process to get audio decoding process

Refer to the video decoding process

1.1. Register all components


av_register_all(a);Copy the code

This function registers all supported containers and their corresponding CoDecs.

1.2. Open the input audio file


AVFormatContext *pFormatCtx = avformat_alloc_context(a);avformat_open_input(&pFormatCtx, input_cstr, NULL.NULL) 
Copy the code

1.3. Obtain audio file information


avformat_find_stream_info(pFormatCtx, NULL)
Copy the code

    // Get the audio stream index position
    int i = 0, audio_stream_idx = - 1;
    for (; i < pFormatCtx->nb_streams; i++) {
        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
            audio_stream_idx = i;
            break; }}if (audio_stream_idx == - 1)
    {
        LOGI("%s"."Unable to find audio stream");
        return;
    }
Copy the code

1.4. Find the decoder according to the encoding ID in the codec context


    // Get the decoder
    AVCodecContext *pCodeCtx = pFormatCtx->streams[audio_stream_idx]->codec;
    AVCodec *codec = avcodec_find_decoder(pCodeCtx->codec_id);
Copy the code

1.5. Open the decoder


avcodec_open2(pCodeCtx, codec, NULL)
Copy the code

AVFormatContext, AVStream, AVCodecContext, AVCodec

1.6. Set audio parameters


    // Enter the sample rate format
    enum AVSampleFormat in_sample_fmt = pCodeCtx->sample_fmt;
    // Output sampling rate in 16bit PCM format
    enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;
    // Enter the sampling rate
    int in_sample_rate = pCodeCtx->sample_rate;
    // Output the sampling rate
    int out_sample_rate = 44100;
    // Get the input channel layout
    // Get the default sound track layout based on the number of tracks (2 tracks, default stereo)
    //av_get_default_channel_layout(pCodeCtx->channels);
    uint64_t in_ch_layout = pCodeCtx->channel_layout;
    // Output channel layout
    uint64_t out_ch_layout = AV_CH_LAYOUT_STEREO;

    swr_alloc_set_opts(swrCtx, out_ch_layout, out_sample_fmt, out_sample_rate, in_ch_layout, in_sample_fmt, in_sample_rate, 0.NULL);

    swr_init(swrCtx);
Copy the code

1.7. Read compressed audio data AVPacket frame by frame


while (av_read_frame(pFormatCtx, packet) >= 0) {omit... }Copy the code

1.8. Decode a frame of audio data AVPacket->AVFrame


avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet)
Copy the code

2. Key code

VideoUtils.class

package com.haocai.ffmpegtest;

public class VideoUtils {

    // Audio decoding
    public native void audioDecode(String input,String output);

    static{
        System.loadLibrary("avutil-54");
        System.loadLibrary("swresample-1");
        System.loadLibrary("avcodec-56");
        System.loadLibrary("avformat-56");
        System.loadLibrary("swscale-3");
        System.loadLibrary("postproc-53");
        System.loadLibrary("avfilter-5");
        System.loadLibrary("avdevice-56");
        System.loadLibrary("myffmpeg"); }}Copy the code
MainActivity.class

    /**
     * 音频解码
     */
    public void doAudioDecode(a){
        String input = new File(Environment.getExternalStorageDirectory(),"Say goodbye. Mp3").getAbsolutePath(a); String output =new File(Environment.getExternalStorageDirectory(),"Let it go. PCM.").getAbsolutePath(a); VideoUtils player =new VideoUtils(a); player.audioDecode(input, output);
        Toast.makeText(this."Decoding...",Toast.LENGTH_SHORT).show(a); }Copy the code
ffmpeg_voicer.c

#include <com_haocai_ffmpegtest_VideoUtils.h>
#include <android/log.h>
#include <android/native_window_jni.h>
#include <android/native_window.h>
#include <stdio.h>
/ / decoding
#include "include/libavcodec/avcodec.h"
// Encapsulate format processing
#include "include/libavformat/avformat.h"
// Pixel processing
#include "include/libswscale/swscale.h"
/ / re-sampling
#include "include/libswresample/swresample.h"


#define  LOG_TAG    "ffmpegandroidplayer"
#define  LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,FORMAT,##__VA_ARGS__);
#define  LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,FORMAT,##__VA_ARGS__);
#define  LOGD(FORMAT,...)  __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG,FORMAT, ##__VA_ARGS__)

// Audio decoding sampling rate of the new version can reach 48000 * 4
#define MAX_AUDIO_FRME_SIZE  2 * 44100

// Audio decoding
JNIEXPORT void JNICALL Java_com_haocai_ffmpegtest_VideoUtils_audioDecode
(JNIEnv *env, jobject jobj, jstring input_jstr, jstring output_jstr) {
    const char* input_cstr = (*env)->GetStringUTFChars(env, input_jstr, NULL);
    const char* output_cstr = (*env)->GetStringUTFChars(env, output_jstr, NULL);
    LOGI("%s"."init");
    // Register the component
    av_register_all(a); AVFormatContext *pFormatCtx =avformat_alloc_context(a);// Open the audio file
    if (avformat_open_input(&pFormatCtx, input_cstr, NULL.NULL) != 0) {
        LOGI("%s"."Unable to open audio file");
        return;
    }
    // Get input file information
    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
        LOGI("%s"."Unable to get input file information");
        return;
    }
    // Get the audio stream index position
    int i = 0, audio_stream_idx = - 1;
    for (; i < pFormatCtx->nb_streams; i++) {
        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
            audio_stream_idx = i;
            break; }}if (audio_stream_idx == - 1)
    {
        LOGI("%s"."Unable to find audio stream");
        return;
    }
    // Get the decoder
    AVCodecContext *pCodeCtx = pFormatCtx->streams[audio_stream_idx]->codec;
    AVCodec *codec = avcodec_find_decoder(pCodeCtx->codec_id);
    if (codec == NULL) {
        LOGI("%s"."Unable to obtain the coder");
        return;
    }
    // Open the decoder
    if (avcodec_open2(pCodeCtx, codec, NULL) < 0) {
        LOGI("%s"."Unable to open decoder");
        return;
    }

    // Compress data
    AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));
    // Decompress the data
    AVFrame *frame = av_frame_alloc(a);Frame ->16bit 44100 PCM Unified audio sampling format and sampling rate
    SwrContext *swrCtx = swr_alloc(a);// Resampling Settings parameter --------------start
    // Enter the sample rate format
    enum AVSampleFormat in_sample_fmt = pCodeCtx->sample_fmt;
    // Output sampling rate in 16bit PCM format
    enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;
    // Enter the sampling rate
    int in_sample_rate = pCodeCtx->sample_rate;
    // Output the sampling rate
    int out_sample_rate = 44100;
    // Get the input channel layout
    // Get the default sound track layout based on the number of tracks (2 tracks, default stereo)
    //av_get_default_channel_layout(pCodeCtx->channels);
    uint64_t in_ch_layout = pCodeCtx->channel_layout;
    // Output channel layout
    uint64_t out_ch_layout = AV_CH_LAYOUT_STEREO;


    swr_alloc_set_opts(swrCtx, out_ch_layout, out_sample_fmt, out_sample_rate, in_ch_layout, in_sample_fmt, in_sample_rate, 0.NULL);


    swr_init(swrCtx);

    // Get the number of input and output channels
    int out_channel_nb = av_get_channel_layout_nb_channels(out_ch_layout);
    LOGI("out_count:%d", out_channel_nb);
    // Resampling Settings parameter --------------end

    //16bit 44100 PCM data
    uint8_t *out_buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRME_SIZE);

    FILE *fp_pcm = fopen(output_cstr, "wb");
    int got_frame = 0, framecount = 0, ret;
    //6. Read compressed audio data AVPacket frame by frame
    while (av_read_frame(pFormatCtx, packet) >= 0) {
        if (packet->stream_index == audio_stream_idx) {
            / / decoding
            ret = avcodec_decode_audio4(pCodeCtx, frame, &got_frame, packet);

            if (ret < 0) {
                LOGI("%s"."Decoding completed");
                break;
            }
            // Non-zero, decoding
            if (got_frame > 0) {
                LOGI("Decoding: %d", framecount++);
                swr_convert(swrCtx, &out_buffer, MAX_AUDIO_FRME_SIZE, frame->data, frame->nb_samples);
                // Get the sample size
                int out_buffer_size = av_samples_get_buffer_size(NULL, out_channel_nb, frame->nb_samples, out_sample_fmt, 1);


                fwrite(out_buffer, 1, out_buffer_size, fp_pcm); }}av_free_packet(packet);
    }
    fclose(fp_pcm);
    av_frame_free(&frame);
    av_free(out_buffer);
    swr_free(&swrCtx);
    avcodec_close(pCodeCtx);
    avformat_close_input(&pFormatCtx);

    (*env)->ReleaseStringUTFChars(env, input_jstr, input_cstr);
    (*env)->ReleaseStringUTFChars(env, output_jstr, output_cstr);


}
Copy the code
Note: Other video formats are also supported

3. Output the result

3.1 the Log output


12- 12 14:23:40.733 15985- 15985./com.haocai.ffmpegtest I/ffmpegandroidplayer: init
12- 12 14:23:40.803 15985- 15985./com.haocai.ffmpegtest I/ffmpegandroidplayer: out_count:2
12- 12 14:23:40.843 15985- 15985./com.haocai. ffmpegTest I/ ffmpegAndroidPlayer: decode:0
12- 12 14:23:40.843 15985- 15985./com.haocai. ffmpegTest I/ ffmpegAndroidPlayer: decode:1
12- 12 14:23:40.843 15985- 15985./com.haocai. ffmpegTest I/ ffmpegAndroidPlayer: decode:2
Copy the code

3.1. Decode mp3 format to generate. PCM format data