日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android 音视频深入 十一 FFmpeg和AudioTrack播放声音(附源码下载)

發(fā)布時間:2025/3/20 Android 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android 音视频深入 十一 FFmpeg和AudioTrack播放声音(附源码下载) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

項目地址,求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++里調(diào)用java函數(shù),下面就是關(guān)于c++使用AudioTrack的代碼

private AudioTrack audioTrack;// 這個方法 是C進行調(diào)用 通道數(shù)public void createTrack(int sampleRateInHz,int nb_channals) {int channaleConfig;//通道數(shù)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傳入音頻數(shù)據(jù)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();//openif (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) {}


設置緩存區(qū),保存解碼前后的數(shù)據(jù)

//申請avpakcet,裝解碼前的數(shù)據(jù)AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));//申請avframe,裝解碼后的數(shù)據(jù)AVFrame *frame = av_frame_alloc();

設置解碼出的聲音一系列的屬性,比如:單聲道、雙聲道、采集點大小、采集率,還可以在這里對聲音添加特效,
?

//得到SwrContext ,進行重采樣,具體參考http://blog.csdn.net/jammg/article/details/52688506SwrContext *swrContext = swr_alloc();//緩存區(qū)uint8_t *out_buffer = (uint8_t *) av_malloc(44100 * 2); //輸出的聲道布局(立體聲)uint64_t out_ch_layout=AV_CH_LAYOUT_STEREO; //輸出采樣位數(shù) 16位enum AVSampleFormat out_formart=AV_SAMPLE_FMT_S16; //輸出的采樣率必須與輸入相同int out_sample_rate = pCodecCtx->sample_rate;//swr_alloc_set_opts將PCM源文件的采樣格式轉(zhuǎn)換為自己希望的采樣格式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); // 獲取通道數(shù) 2int out_channer_nb = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);

通過反射能夠運行java函數(shù)

// 反射得到Class類型jclass david_player = env->GetObjectClass(instance); // 反射得到createAudio方法jmethodID createAudio = env->GetMethodID(david_player, "createTrack", "(II)V"); // 反射調(diào)用createAudioenv->CallVoidMethod(instance, createAudio, 44100, out_channer_nb);jmethodID audio_write = env->GetMethodID(david_player, "playTrack", "([BI)V");


在一邊解碼的時候一邊給數(shù)據(jù)給AudioTrack播放

while (av_read_frame(pFormatCtx, packet) >= 0) {if (packet->stream_index == audio_stream_idx) { // 解碼 mp3 編碼格式frame----pcm frameavcodec_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); // 緩沖區(qū)的大小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也能播放聲音,這個后面說

下一次就是說如何將視頻的聲音給聽換掉,也就是將音視頻的解碼和編碼都來搞一次

?

轉(zhuǎn)載于:https://www.cnblogs.com/jianpanwuzhe/p/8427415.html

總結(jié)

以上是生活随笔為你收集整理的Android 音视频深入 十一 FFmpeg和AudioTrack播放声音(附源码下载)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。