男儿欲遂平生志,五经勤向窗前读。这篇文章主要讲述Android音视频深入十一FFmpeg和AudioTrack播放声音(附源码下载)相关的知识,希望能为你提供帮助。
项目地址,求star
https://github.com/979451341/AudioVideoStudyCodeTwo/tree/master/FFmpeg%E6%92%AD%E6%94%BE%E9%9F%B3%E4%B9%90%EF%BC%88%E4%BF%9D%E7%A8%8B%E5%BA%8F%E4%B8%8D%E6%AD%BB%EF%BC%89
这个是FFmpeg解码出音频,给AudioTrack播放,这回才算是java与c语言之间合作
这回我们将会从c++里调用java函数,下面就是关于c++使用AudioTrack的代码
private AudioTrack audioTrack;
//这个方法是C进行调用通道数
public void createTrack(int sampleRateInHz,int nb_channals) {int channaleConfig;
//通道数
if (nb_channals == 1) {
channaleConfig = AudioFormat.CHANNEL_OUT_MONO;
} else if (nb_channals == 2) {
channaleConfig = AudioFormat.CHANNEL_OUT_STEREO;
}else {
channaleConfig = AudioFormat.CHANNEL_OUT_MONO;
}
int buffersize=AudioTrack.getMinBufferSize(sampleRateInHz,
channaleConfig, AudioFormat.ENCODING_PCM_16BIT);
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,sampleRateInHz,channaleConfig,
AudioFormat.ENCODING_PCM_16BIT,buffersize,AudioTrack.MODE_STREAM);
audioTrack.play();
}//C传入音频数据
public void playTrack(byte[] buffer, int lenth) {
if (audioTrack != null &
&
audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
audioTrack.write(buffer, 0, lenth);
}
}
我们再来看看c++的代码
首先注册组件,然后得到音频流
av_register_all();
AVFormatContext *pFormatCtx = avformat_alloc_context();
//open
if (avformat_open_input(&
pFormatCtx, input, NULL, NULL) != 0) {
LOGE("%s","打开输入视频文件失败");
return;
}
//获取视频信息
if(avformat_find_stream_info(pFormatCtx,NULL) <
0){
LOGE("%s","获取视频信息失败");
return;
}
int audio_stream_idx=-1;
int i=0;
for (int i = 0;
i <
pFormatCtx->
nb_streams;
++i) {
if (pFormatCtx->
streams[i]->
codec->
codec_type == AVMEDIA_TYPE_AUDIO) {
LOGE("找到音频id %d", pFormatCtx->
streams[i]->
codec->
codec_type);
audio_stream_idx=i;
break;
}
}
获取解码器
//获取解码器上下文
AVCodecContext *pCodecCtx=pFormatCtx->
streams[audio_stream_idx]->
codec;
//获取解码器
AVCodec *pCodex = avcodec_find_decoder(pCodecCtx->
codec_id);
//打开解码器
if (avcodec_open2(pCodecCtx, pCodex, NULL)<
0) {
}
设置缓存区,保存解码前后的数据
//申请avpakcet,装解码前的数据
AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));
//申请avframe,装解码后的数据
AVFrame *frame = av_frame_alloc();
设置解码出的声音一系列的属性,比如:单声道、双声道、采集点大小、采集率,还可以在这里对声音添加特效,
//得到SwrContext ,进行重采样,具体参考http://blog.csdn.net/jammg/article/details/52688506
SwrContext *swrContext = swr_alloc();
//缓存区
uint8_t *out_buffer = (uint8_t *) av_malloc(44100 * 2);
//输出的声道布局(立体声)
uint64_tout_ch_layout=AV_CH_LAYOUT_STEREO;
//输出采样位数16位
enum AVSampleFormat out_formart=AV_SAMPLE_FMT_S16;
//输出的采样率必须与输入相同
int out_sample_rate = pCodecCtx-> sample_rate;
//swr_alloc_set_opts将PCM源文件的采样格式转换为自己希望的采样格式
swr_alloc_set_opts(swrContext, out_ch_layout, out_formart, out_sample_rate,
pCodecCtx-> channel_layout, pCodecCtx-> sample_fmt, pCodecCtx-> sample_rate, 0,
NULL);
swr_init(swrContext);
//获取通道数2
int out_channer_nb = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
通过反射能够运行java函数
//反射得到Class类型
jclass david_player = env-> GetObjectClass(instance);
//反射得到createAudio方法
jmethodID createAudio = env-> GetMethodID(david_player, " createTrack" , " (II)V" );
//反射调用createAudio
env-> CallVoidMethod(instance, createAudio, 44100, out_channer_nb);
jmethodID audio_write = env-> GetMethodID(david_player, " playTrack" , " ([BI)V" );
在一边解码的时候一边给数据给AudioTrack播放
while (av_read_frame(pFormatCtx, packet) >
= 0) {
if (packet->
stream_index == audio_stream_idx) {
//解码mp3编码格式frame----pcmframe
avcodec_decode_audio4(pCodecCtx, frame, & got_frame, packet);
if (got_frame) {
LOGE(" 解码" );
swr_convert(swrContext, & out_buffer, 44100 * 2, (const uint8_t *) frame-> data, frame-> nb_samples);
//缓冲区的大小
int size = av_samples_get_buffer_size(NULL, out_channer_nb, frame-> nb_samples,
AV_SAMPLE_FMT_S16, 1);
jbyteArray audio_sample_array = env-> NewByteArray(size);
env-> SetByteArrayRegion(audio_sample_array, 0, size, (const jbyte ) out_buffer);
env-> CallVoidMethod(instance, audio_write, audio_sample_array, size);
env-> DeleteLocalRef(audio_sample_array);
}
}
}
释放资源
av_frame_free(&
frame);
swr_free(&
swrContext);
avcodec_close(pCodecCtx);
avformat_close_input(&
pFormatCtx);
env->
ReleaseStringUTFChars(input_, input);
FFmpeg只是音视频处理的工具,他没有播放视频和音频的能力,所以我们需要SurfaceView显示视频,AudioTrack播放声音,而且OpenGLES也能播放声音,这个后面说
【Android音视频深入十一FFmpeg和AudioTrack播放声音(附源码下载)】下一次就是说如何将视频的声音给听换掉,也就是将音视频的解码和编码都来搞一次
推荐阅读
- Android音视频深入十二FFmpeg视频替换声音(附源码下载)
- monkey-获取app包名
- 如何让A20,android开机自动启动C程序
- RULES OF SURVIVAL 1.115153.115248 Full Apk + Data for Android
- 利用微信公众号快速推广APP应用
- APP垂直市场应用趋势(女性APP)
- Android7.0手机程序保活(附源码下载)
- bzoj2127: happiness
- Docker与Android Studio的冲突问题