用MediaCodec實現多段視音訊的擷取與拼接
轉自:http://blog.csdn.net/mouse_1894/article/details/34448563
視音訊編輯中,對多段媒體素材進行擷取和拼接是非常常見的操作。擷取和拼接實際上是對媒體檔案資料重新進行組合的過程。
要實現這些功能,就需要對媒體檔案進行編解碼操作,即先解碼要處理的媒體檔案資料,然後再按照某種規則對這些資料進行編碼,以生成我們所需的目標。
Android提供的MediaCodec及其相關類為我們提供了所需的方法,這些類主要包括:MediaCodec、MediaExtractor、MediaMuxer、MediaFormat。
MediaCodec用於建立視音訊編解碼器,通過它可以對視音訊資料進行編解碼操作,它是編解碼功能的核心類。
MediaExtractor相當於一個reader,它用於讀取媒體檔案,並提取出其中的視音訊資料。
MediaMuxer相當於一個writer,它用於將記憶體中的視音訊資料寫到檔案中。
MediaFormat即媒體格式類,它用於描述媒體的格式引數,如視訊幀率、音訊取樣率等。
對視音訊檔案進行擷取與拼接的主要過程是:先建立視音訊編解碼器,再分別啟動視訊執行緒和音訊執行緒,以分別對視音訊資料進行解碼、編碼,最後將編碼好的資料寫入檔案。
主要邏輯如下,關鍵是三處執行緒同步的地方,具體原因稍後解釋。
再來了解一下這幾個類的“脾氣”。
一般用MediaCodec建立編解碼器時,使用的都是createDecoderByType方法,但在用三星PAD(API LEVEL 18, Android version 4.3)除錯時發現,呼叫該方法建立音訊編碼器時會出錯。故改為使用createByCodecName("OMX.SEC.aac.enc")建立音訊編碼器。估計這是一個API bug。
configure decoder時,第一個格式引數要與源的格式相同,這裡可以先通過extractor將源的格式讀出來,再直接傳給configure方法。configure encoder時,需設定幾個必要的引數,具體請參考官方說明。
當把全部要處理的資料灌給編解碼器後,使用queueInputBuffer(inputBufIndex,0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM)方法來通知編解碼器結束工作。之後,在OutputBuffer的bufferInfo中,將攜帶這個標誌,通過判斷是否有這個標誌,我們就可以斷定資料是否都已處理完成,以進行後續操作。再之後,dequeueOutputBuffer的返回都將是INFO_TRY_AGAIN_LATER。當然,如果你自己有辦法在OutputBuffer中判斷資料是否灌完,也可以不使用此標誌。
當資料灌完後,要使用releaseOutputBuffer,把緩衝區釋放掉。否則,你會發現queueInputBuffer總是返回-1,因為沒有空閒的緩衝區了。
MediaExtractor用來讀取原始檔,給定檔案路徑後,便可將其中的視音訊資料拿出來。關鍵是它的seekTo方法,它用於對讀取資料的遊標進行定位,可以定位到指定點前的最後一個sync點、指定點後的第一個sync點,或者與指定點最近的sync點。對於H.264資料,sync點可以認為是視訊關鍵幀的時碼位置。
MediaMuxer的使用非常簡單,先建立,再新增視音訊軌,然後start,再writeSampleData,最後stop。需要注意的是,必需先新增完所有的視音訊軌後,再去start,而不能先start,再試圖去addTrack,否則會出錯。這也是為什麼在本文的邏輯中,視訊執行緒需要去wait音訊執行緒新增完音訊軌後再繼續的原因。
需要注意的是,不能在啟動完編解碼器後,立即呼叫getOutputFormat企圖addTrack,而應該在dequeueOutputBuffer後的INFO_OUTPUT_FORMAT_CHANGED中呼叫,否則會出錯。
當要向檔案中同時寫入視訊和音訊資料時,必需先writeSampleData所有視訊資料,再寫音訊資料,或者反之,即二者必需連續呼叫writeSampleData,不能交叉呼叫,否則寫出的檔案會有問題。這也是本文中為何muxer啟動後,音訊執行緒需等待視訊執行緒先寫完資料,自己才能繼續幹活的原因。
當所有的writeSampleData完成後,不要忘記呼叫stop和release,否則寫出的檔案也會有問題。
最後還要注意,這幾個類中,時間單位都是微秒,不要搞錯了。
相關文章
- Android 音視訊 - MediaCodec 編解碼音視訊Android
- wasm + ffmpeg實現前端擷取視訊幀功能ASM前端
- Android音視訊處理之MediaCodecAndroid
- 音訊擷取分割工具音訊
- MySQL 欄位擷取拼接MySql
- 使用JavaCV實現讀取視訊資訊及自動擷取封面圖Java
- php ffmpeg 視訊擷取PHP
- Android音視訊(四)MediaCodec編解碼AACAndroid
- android使用MediaCodec實現非同步視訊編解碼Android非同步
- WebRTC 音視訊同步原理與實現Web
- vue 擷取視訊第一幀Vue
- 帶你用AVPlayer實現音訊和視訊播放音訊
- Java 把多個音訊拼接成一個Java音訊
- Swift 4.0 字串擷取,拼接,字串富文字顯示Swift字串
- MediaCodec、OpenGL、OpenSL/AudioTrack 實現一款簡單的視訊播放器播放器
- SoX — wav 音訊拼接音訊
- pydub -wav 音訊拼接音訊
- Android端實現多人音視訊聊天應用(一)Android
- 三種方法使用FFMPEG擷取視訊片斷
- Android端實現多人音視訊聊天應用(二):多人視訊通話Android
- 手遊中實時音視訊的開發經驗與實現技巧
- 用一段爬蟲程式碼爬取高音質音訊示例爬蟲音訊
- WebRTC – Agora (聲網)簡介與實現音視訊通話WebGo
- 【玩具】獲取B站視訊的音訊片段音訊
- 怎麼將一段音訊批量的新增到多個視訊當中合併成一個完整視訊音訊
- 125 列舉實現PHP擷取中文不亂碼的實現方法PHP
- H5 video標籤列表渲染用canvas擷取視訊畫面做封面H5IDECanvas
- 基於 IJKPlayer-concat 協議的視訊無縫拼接技術實現協議
- mysql 分隔符擷取最後一段MySql
- MediaCodeC解碼視訊指定幀,迅捷、精確
- AudioContext+canvas實現音訊視覺化ContextCanvas音訊視覺化
- ffmpeg+Python實現B站MP4格式音訊與視訊的合併Python音訊
- 【秒懂音視訊開發】13_音訊重取樣音訊
- Java中的多級快取設計與實現Java快取
- 使用MediaCodeC將圖片集編碼為視訊
- Android 音視訊錄製硬編碼實現Android
- [C#] 使用 NAudio 實現音訊視覺化C#音訊視覺化
- 一段音訊音訊
- 如何基於 ZEGO SDK 實現 Android 一對一音視訊聊天應用GoAndroid