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