1. 程式人生 > >android MediaCodec 音訊編解碼的實現

android MediaCodec 音訊編解碼的實現

從今天開始 每週不定期更新部落格,把這一週在工作與學習中遇到的問題做個總結。俗話說:好記性不如寫部落格,善於總結的人才能走的更遠。寫部落格這種利人利己的好處我就不一 一列舉了,總之,誰做誰知道,哈哈。在文章中如果有什麼問題或者錯誤,歡迎各位的討論和指正。好了,步入正題,來看看我們今天要講的MediaCodec

一、概述

由於專案的需要,需要將mp3檔案轉碼為aac音訊檔案,起初打算移植FFmpeg到專案中,無奈FFmpeg過於龐大,專案中的音訊轉碼只是一個輔助util,並不是主要功能。所以打算用MediaCodec來實現這一需求。網上關於MediaCodec的文章少的可憐,寫demo的過程中踩到了無數的坑。不過,在

http://blog.csdn.net/tn0521/article/details/44980183這篇文章的指引下,終於在耳機中聽到了那美妙的旋律,激動的我把這一首歌聽了一星期,因為他出自我的手。哈哈,開個玩笑!在此對這片文章的原創表示感謝,這也是我決定寫部落格的原因之一,利人利己。

二、轉碼實現原理

本篇文章以mp3轉碼成aac為例,轉碼實現原理:mp3->pcm->aac,首先將mp3解碼成PCM,再將PCM編碼成aac格式的音訊檔案。

PCM:可以將它理解為,未經過壓縮的數字訊號,mp3、aac等 理解為pcm壓縮後的檔案。播放器在播放mp3、aac等檔案時要先將mp3等檔案解碼成PCM資料,然後再將PCM送到底層去處理播放

此處就好比 我要將rar壓縮包內的檔案改用zip壓縮,->解壓rar-->檔案-->壓縮zip

三、遇到問題

1、編解碼過程中會卡主:此為引數設定引起的,下面程式碼中會提到

2、編碼的aac音訊不能播放:在編碼過程中需要為aac音訊新增ADTS  head,程式碼中有體現

3、最頭痛的,轉碼速度太慢,轉碼一首歌長達5分鐘。

      此問題究其原因,是由於MediaExtractor每次餵給MediaCodec的資料太少,每次只喂一幀的資料,通過列印的log發現size不到1k,嚴重影響效率,後來嘗試不用MediaExtractor去讀資料,直接開流 BufferInputStream設定200k ,每次迴圈餵給MediaCodec200k的資料 , 最終!!! 在三星手機上完美執行,一次轉碼由5分鐘,直接降到10多秒,但是,注意但是!!!  此方法在其他

測試機上全報錯,淚奔。

  無奈,開執行緒,將解碼和編碼分別放到兩個執行緒裡面去執行,並且讓MediaExtractor讀取多次資料後再交給MediaCodec去處理,此方法轉碼一首歌大約1分鐘左右(各位如果有好的方法不吝賜教,本人非常感激

四、程式碼實現

1)初始化解碼器

  MediaExtractor:可用於分離視訊檔案的音軌和視訊軌道,如果你只想要視訊,那麼用selectTrack方法選中視訊軌道,然後用readSampleData讀出資料,這樣你就得到了一個沒有聲音的視訊。此處我們傳入的是一個音訊檔案(mp3),所以也就只有一個軌道,音訊軌道

 mime:用來表示媒體檔案的格式 mp3為audio/mpeg;aac為audio/mp4a-latm;mp4為video/mp4v-es 此處注意字首 音訊字首為audio,視訊字首為video 我們可用此區別區分媒體檔案內的音訊軌道和視訊軌道

mime的各種型別定義在MediaFormat靜態常量中

  MediaCodec.createDecoderByType(mime) 建立對應格式的解碼器  要解碼mp3 那麼mime="audio/mpeg" 或者MediaFormat.MIMETYPE_AUDIO_MPEG其它同理

[java] view plain copy  print?
  1. /** 
  2.      * 初始化解碼器 
  3.      */
  4.     privatevoid initMediaDecode() {  
  5.         try {  
  6.             mediaExtractor=new MediaExtractor();//此類可分離視訊檔案的音軌和視訊軌道
  7.             mediaExtractor.setDataSource(srcPath);//媒體檔案的位置
  8.             for (int i = 0; i < mediaExtractor.getTrackCount(); i++) {//遍歷媒體軌道 此處我們傳入的是音訊檔案,所以也就只有一條軌道
  9.                 MediaFormat format = mediaExtractor.getTrackFormat(i);  
  10.                 String mime = format.getString(MediaFormat.KEY_MIME);  
  11.                 if (mime.startsWith("audio")) {//獲取音訊軌道
  12. //                    format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 200 * 1024);
  13.                     mediaExtractor.selectTrack(i);//選擇此音訊軌道
  14.                     mediaDecode = MediaCodec.createDecoderByType(mime);//建立Decode解碼器
  15.                     mediaDecode.configure(format, nullnull0);  
  16.                     break;  
  17.                 }  
  18.             }  
  19.         } catch (IOException e) {  
  20.             e.printStackTrace();  
  21.         }  
  22.         if (mediaDecode == null) {  
  23.             Log.e(TAG, "create mediaDecode failed");  
  24.             return;  
  25.         }  
  26.         mediaDecode.start();//啟動MediaCodec ,等待傳入資料
  27.         decodeInputBuffers=mediaDecode.getInputBuffers();//MediaCodec在此ByteBuffer[]中獲取輸入資料
  28.         decodeOutputBuffers=mediaDecode.getOutputBuffers();//MediaCodec將解碼後的資料放到此ByteBuffer[]中 我們可以直接在這裡面得到PCM資料
  29.         decodeBufferInfo=new MediaCodec.BufferInfo();//用於描述解碼得到的byte[]資料的相關資訊
  30.         showLog("buffers:" + decodeInputBuffers.length);  
  31.     }  

2)初始化編碼器 

編碼器的創建於解碼器的類似,只不過解碼器的MediaFormat直接在音訊檔案內獲取就可以了,編碼器的MediaFormat需要自己來建立

[java] view plain copy  print?
  1. /** 
  2.  * 初始化AAC編碼器 
  3.  */
  4. privatevoid initAACMediaEncode() {  
  5.     try {  
  6.         MediaFormat encodeFormat = MediaFormat.createAudioFormat(encodeType, 441002);//引數對應-> mime type、取樣率、聲道數
  7.         encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, 96000);//位元率
  8.         encodeFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);  
  9.         encodeFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 100 * 1024);//作用於inputBuffer的大小
  10.         mediaEncode = MediaCodec.createEncoderByType(encodeType);  
  11.         mediaEncode.configure(encodeFormat, nullnull, MediaCodec.CONFIGURE_FLAG_ENCODE);  
  12.     } catch (IOException e) {  
  13.         e.printStackTrace();  
  14.     }  
  15.     if (mediaEncode == null) {  
  16.         Log.e(TAG, "create mediaEncode failed");  
  17.         return;  
  18.     }  
  19.     mediaEncode.start();  
  20.     encodeInputBuffers=mediaEncode.getInputBuffers();  
  21.     encodeOutputBuffers=mediaEncode.getOutputBuffers();  
  22.     encodeBufferInfo=new MediaCodec.BufferInfo();  
  23. }  


3)解碼的實現

[java] view plain copy  print?
  1. /** 
  2.      * 解碼{@link #srcPath}音訊檔案 得到PCM資料塊 
  3.      * @return 是否解碼完所有資料 
  4.      */
  5.     privatevoid srcAudioFormatToPCM() {  
  6.         for (int i = 0; i < decodeInputBuffers.length-1; i++) {  
  7.         int inputIndex = mediaDecode.dequeueInputBuffer(-1);//獲取可用的inputBuffer -1代表一直等待,0表示不等待 建議-1,避免丟幀
  8.         if (inputIndex < 0) {  
  9.             codeOver =true;  
  10.             return;  
  11.         }  
  12.         ByteBuffer inputBuffer = decodeInputBuffers[inputIndex];//拿到inputBuffer
  13.         inputBuffer.clear();//清空之前傳入inputBuffer內的資料
  14.         int sampleSize = mediaExtractor.readSampleData(inputBuffer, 0);//MediaExtractor讀取資料到inputBuffer中
  15.         if (sampleSize <0) {//小於0 代表所有資料已讀取完成
  16.                 codeOver=true;  
  17.             }else {  
  18.                 mediaDecode.queueInputBuffer(inputIndex, 0, sampleSize, 00);//通知MediaDecode解碼剛剛傳入的資料
  19.                 mediaExtractor.advance();//MediaExtractor移動到下一取樣處
  20.                 decodeSize+=sampleSize;  
  21.             }  
  22.         }  
  23.         //獲取解碼得到的byte[]資料 引數BufferInfo上面已介紹 10000同樣為等待時間 同上-1代表一直等待,0代表不等待。此處單位為微秒
  24.         //此處建議不要填-1 有些時候並沒有資料輸出,那麼他就會一直卡在這 等待
  25.         int outputIndex = mediaDecode.dequeueOutputBuffer(decodeBufferInfo, 10000);  
  26. //        showLog("decodeOutIndex:" + outputIndex);
  27.         ByteBuffer outputBuffer;  
  28.         byte[] chunkPCM;  
  29. 相關推薦

    android MediaCodec 音訊解碼實現

    從今天開始 每週不定期更新部落格,把這一週在工作與學習中遇到的問題做個總結。俗話說:好記性不如寫部落格,善於總結的人才能走的更遠。寫部落格這種利人利己的好處我就不一 一列舉了,總之,誰做誰知道,哈哈。在文章中如果有什麼問題或者錯誤,歡迎各位的討論和指正。好了,步入正題,來看看我們今天要講的MediaC

    android MediaCodec 音訊解碼實現——轉碼

    從今天開始 每週不定期更新部落格,把這一週在工作與學習中遇到的問題做個總結。俗話說:好記性不如寫部落格,善於總結的人才能走的更遠。寫部落格這種利人利己的好處我就不一 一列舉了,總之,誰做誰知道,哈哈。在文章中如果有什麼問題或者錯誤,歡迎各位的討論和指正。好了,步入正題,來

    Android音視訊解碼MediaCodec

    MediaCodec類可用於訪問低階媒體編解碼器,即編碼器/解碼器元件。 它是Android低階多媒體支援基礎架構的一部分(通常與MediaExtractor,MediaSync,MediaMuxer,MediaCrypto,MediaDrm,Image,Surface和Au

    android 音訊解碼 混音 mp3編碼解碼 pcm編碼解碼

    特別提示:這裡所提供的原始碼真實有效,並且只是出售原始碼,不提供專案整合服務。如果覺得效果是自己想要的歡迎使用。(感謝各位慷慨資助,謝謝) 音訊編解碼,錄製鈴音,增加混音效果,目前只支援編解碼MP3格式檔案。將音訊檔案放到SDCard/RecordMixMp3/music下

    實現單晶片2400bps 音訊解碼方案

      終於按照朋友的需求,幫他開發了一款單晶片集音訊採集編碼傳送並接收解碼播放功能的方案,交給快遞公司郵寄給遠在鄭州的他.整個專案從開始定型到現在一個樣機送出,整整花了1個月時間,感覺挺有成就感,挺有意思,工作是辛苦的,結果卻是快樂的.現在將這中快樂的的心情與大家分享一下.

    Android視訊編輯器(五)音訊解碼、從視訊中分離音訊音訊混音、音訊音量調節等

    /** * 歸一化混音 * */ public static byte[] normalizationMix(byte[][] allAudioBytes){ if (allAudioBytes == null || allAudioBytes.length

    音訊解碼基礎(wav/aac/pcma/pcmu)

    技術在於交流、溝通,轉載請註明出處並保持作品的完整性。 原文:https://blog.csdn.net/hiwubihe/article/details/81258879 [音訊編解碼系列文章] 音訊編解碼基礎 FFMPEG實現音訊重取樣 FFMPEG實現PCM編

    即時通訊音視訊開發(六):如何開始音訊解碼技術的學習

    前言 即時通訊應用中的實時音視訊技術,幾乎是IM開發中的最後一道高牆。原因在於:實時音視訊技術 = 音視訊處理技術 + 網路傳輸技術 的橫向技術應用集合體,而公共網際網路不是為了實時通訊設計的。 系列文章 《即時通訊音視訊開發(四):視訊編解碼之預測技術介紹》 《即時通訊音

    [總結]視音訊解碼技術零基礎學習方法

                    一直想把視音訊編解碼技術做一個簡單的總結,可是苦於時間不充裕,一直沒能完成。今天有著很大的空閒,終於可以總結一個有關視音訊技術的入門教程,可以方便更多的人學習從零開始學習視音訊技術。需要注意的是,本文所說的視音訊技術,指的是理論層面的視音訊技術,並不涉及到程式設計相關的東西。0

    FPGA設計標準I2S協議音訊解碼

    FPGA設計標準I2S協議音訊編解碼器 --I2S基本介紹 --I2S取樣和處理過程 --I2S協議規範 --FPGA設計標準I2S音訊編解碼器 –I2S基本介紹 I2S(Inter-IC Sound)是飛利浦公司針對數字音訊裝置

    [總結]FFMPEG視音訊解碼零基礎學習方法

    郵箱:[email protected] 技術交流:QQ:931120780,註明csdn交流,白天較少回覆請留言。 部落格內錯誤之處,請您留言或郵件指明,不勝感激。近期發現一些錯誤,發現會及時修正。

    G711(PCM/PCMA/PCMU),G721,G723,G729音訊解碼

     G711,G721,G723音訊編解碼,G729音訊庫,Android G711(PCMA/PCMU)、G726、PCM音訊轉碼到AAC,ffmpeg接收g723音訊流,Android G726語音編解碼庫+除燥音演算法,g729音訊編解碼靜態庫,G723 G729 Gsm iLBC P

    g.729a 音訊解碼演算法

            g.729 spirit dsp定義:                                                                                      音訊壓縮編碼           1、什麼是語音

    webrtc-android平臺視訊解碼分析

    WebRTC是一個實時的視訊通訊功能,Android平臺上的Chrome也提供了支援,在Chrome 29之後WebRTC功能趨於穩定,所以在之後的版本中預設被開啟。也就是說不需要在”chrome://flags”中手動去開啟該功能。 本節主要介紹一下Android平臺

    音訊解碼標準G.711與G.729

    G.711和G.729協議是兩對用於語音壓縮的編碼方案,兩者具有一些相似之處,但不同於完全自由使用的G.711,使用G.729是需要付費的,而且,對於使用G.729的情況,CPU佔有時間大約為G.711的4倍,因此大多數情況下,G.711的使用要廣泛於G.729,但G.72

    FPGA音訊解碼驅動及I2C寫入程式碼

    FPGA音訊編解碼驅動及I2C寫入程式碼 使用音訊編解碼晶片為WM8731,其通過I2C對WM8731進行暫存器寫入,將需要寫入的資料放入例化的ROM塊中,通過狀態機控制資料的寫入;通過對50M和24M的時鐘分頻提供WM8731的主時鐘和位寫入時鐘,資料沒有進行

    音訊解碼總結

    主要的speech codec 有: G.711, G.723, G.726 , G.729, ILBC,QCELP, EVRC, AMR, SMV 主要的audiocodec 有: real audio, AAC,AC3, MP3, WMA, SBC等,各種編解碼

    音訊解碼faac

    音訊編解碼·實戰篇(1)WAV轉至AAC(AAC編碼) 這裡利用FAAC來實現AAC編碼。另外,WAV的資料段是PCM,程式碼會出現很多PCM縮寫。 1 下載安裝 FAAC 這裡的安裝過程是在 Mac 和 Linux 上實現的,Windows可以類似參考。 wget

    音訊解碼技術零基礎學習方法

    一直想把視音訊編解碼技術做一個簡單的總結,可是苦於時間不充裕,一直沒能完成。今天有著很大的空閒,終於可以總結一個有關視音訊技術的入門教程,可以方便更多的人學習從零開始學習視音訊技術。需要注意的是,本文所說的視音訊技術,指的是理論層面的視音訊技術,並不涉及到程式設計相關的東西

    ASN1解碼實現方法

    目 錄版本記錄 1目 錄 1第1章 概述 31.1 背景 31.2 ASN.1概念 31.3 TAG 4第2章 開發工具 42.1 開發庫 42.2 輔助工具 5第3章 JavaAsn1Compiler 63.1 定義ASN.1描述檔案 63.2 生成java程式碼 63.2