目的
通过FFMPEG解码音频的码流,得到PCM的音频采样数据并用AudioTraker播放
步骤
1.注册所有组件
av_register_all();
2.拿到封装格式上下文
AVFormatContext *avFormatContext = avformat_alloc_context();
3 打开文件
if (avformat_open_input(&avFormatContext, src_cstr, NULL, NULL) < 0) {
LOGE("%s", "打开文件失败");
return;
}
4.查找流信息
avformat_find_stream_info(avFormatContext, NULL)
5.拿到解码器
avcodec_find_decoder(avCodecCtx->codec_id)
6.打开解码器
avcodec_open2(avCodecCtx, aVCodec, NULL)
7.读取一帧一帧的压缩音频数据
av_read_frame(avFormatContext, aVPacket)
8.开始解码
vcodec_decode_audio4(avCodecCtx, aVFrame, &got_frame_ptr,aVPacket)
9.解码得到的Frame数据,转成PCM
swr_convert(swrCtx, &outBuffer, MAX_AUDIO_FRME_SIZE,
aVFrame->data, aVFrame->nb_samples)
10.调用java端的方法,获取到AudioTraker对象
//java代码
public AudioTrack createAudio() {
int sampleRateInHz = 44100;
int channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int minBufferSize = AudioTrack.getMinBufferSize(sampleRateInHz,
channelConfig, audioFormat);
AudioTrack audio = new AudioTrack(AudioManager.STREAM_MUSIC, // 指定流的类型
sampleRateInHz, // 设置音频数据的采样率 32k,如果是44.1k就是44100
channelConfig, // 设置输出声道为双声道立体声,而CHANNEL_OUT_MONO类型是单声道
audioFormat, // 设置音频数据块是8位还是16位,这里设置为16位。好像现在绝大多数的音频都是16位的了
minBufferSize, AudioTrack.MODE_STREAM // 设置模式类型,在这里设置为流类型,另外一种MODE_STATIC貌似没有什么效果
);
// audio.play(); // 启动音频设备,下面就可以真正开始音频数据的播放了
return audio;
}
// jni调用createAudio
jclass player_class = (*env)->GetObjectClass(env, jthis);
jmethodID createAudioMId = (*env)->GetMethodID(env, player_class,
"createAudio", "()Landroid/media/AudioTrack;");
//JNIEnv*, jobject, jmethodID, ...
jobject audioTraker = (*env)->CallObjectMethod(env, jthis, createAudioMId);
11.调用AudioTrack.paly(),write()播放解码后的音频数据
javap反编译可以得到方法签名
// 调用play
jclass audio_class = (*env)->GetObjectClass(env, audioTraker);
jmethodID playMId = (*env)->GetMethodID(env, audio_class, "play", "()V");
(*env)->CallVoidMethod(env, audioTraker, playMId);
jmethodID writeMId = (*env)->GetMethodID(env, aud