Android 音視頻深入 十一 FFmpeg和AudioTrack播放聲音(附源碼下載)

來源:互聯網
上載者:User

標籤:UI   java   tps   tcl   view   sizeof   dex   函數   object   

項目地址,求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();//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) {}

設定緩衝區,儲存解碼前後的資料

//申請avpakcet,裝解碼前的資料AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));//申請avframe,裝解碼後的資料AVFrame *frame = av_frame_alloc();

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

//得到SwrContext ,進行重採樣,具體參考http://blog.csdn.net/jammg/article/details/52688506SwrContext *swrContext = swr_alloc();//緩衝區uint8_t *out_buffer = (uint8_t *) av_malloc(44100 * 2);

//輸出的聲道布局(立體聲)
uint64_t out_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----pcm frame
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播放聲音(附源碼下載)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.