今天來學習一下如何解析和封裝 MP4。此次咱們使用的 API 是 MediaExtractor 和 MediaMuxer。java
一個用來解析,一個用來封裝。git
顧名思義,MediaExtractor 能夠從數據源中提取通過編碼的媒體數據。MediaExtractor 不只能夠解析本地媒體文件,還能夠解析網絡媒體資源。github
一樣,名字已經說明了一切。MediaMuxer 能夠將多個流混合封裝起來,支持 MP四、Webm 和 3GP 文件做爲輸出,並且從 Android N 開始,已經支持在 MP4 中混合 B 幀了。微信
此次的任務是從一個 MP4 文件中只提取視頻數據,並封裝爲一個新的 MP4 文件。外在表現就是將一個有聲視頻,轉換爲一個無聲視頻。markdown
實現部分主要靠 MediaExtractor
提取軌道信息,而後用 MediaMuxer
將數據封裝。步驟以下:網絡
MediaExtractor
設置數據源,就是咱們將要解析的文件的路徑或地址。 MediaExtractor
獲取到咱們的目標軌道。好比此次咱們就須要的是視頻軌道。 這裏給出一個軌道的樣例信息:ide
{track-id=1, level=16, mime=video/avc, frame-count=374, profile=65536, language=und, color-standard=4, display-width=320, csd-1=java.nio.HeapByteBuffer[pos=0 lim=8 cap=8], color-transfer=3, durationUs=12612000, display-height=240, width=320, color-range=2, max-input-size=4676, frame-rate=30, height=240, csd-0=java.nio.HeapByteBuffer[pos=0 lim=29 cap=29]}複製代碼
MediaMuxer
中進行封裝。 val mediaExtractor = MediaExtractor()
mediaExtractor.setDataSource(oriVideoPath)
var videoOnlyTackIndex = -1
var frameRate = 0
val mediaMuxer =
MediaMuxer(outputVideoOnlyPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
for (trackIndex in 0 until mediaExtractor.trackCount) {
val trackFormat = mediaExtractor.getTrackFormat(trackIndex)
val mime = trackFormat.getString(MediaFormat.KEY_MIME)
if (mime == null || !mime.startsWith("video/")) {
// 若是不是視頻軌道,則跳過
continue
}
frameRate = trackFormat.getInteger(MediaFormat.KEY_FRAME_RATE)
mediaExtractor.selectTrack(trackIndex)
videoOnlyTackIndex = mediaMuxer.addTrack(trackFormat)
mediaMuxer.start()
}
if (videoOnlyTackIndex == -1) {
return
}
val bufferInfo = MediaCodec.BufferInfo()
bufferInfo.presentationTimeUs = 0
var sampleSize = 0
val buffer = ByteBuffer.allocate(500 * 1024)
val sampleTime = mediaExtractor.cachedDuration
while (mediaExtractor.readSampleData(buffer, 0).also {
sampleSize = it
} > 0) {
bufferInfo.size = sampleSize
bufferInfo.flags = MediaCodec.BUFFER_FLAG_KEY_FRAME
bufferInfo.presentationTimeUs += 1000 * 1000 / frameRate
mediaMuxer.writeSampleData(videoOnlyTackIndex, buffer, bufferInfo)
mediaExtractor.advance()
}
mediaExtractor.release()
mediaMuxer.stop()
mediaMuxer.release()複製代碼
代碼大概如上所示,可是還有幾個問題沒有搞清楚。學習
buffer
,那麼這個 buffer
是怎麼來的呢? 在這裏簡單解釋一下第一個問題(可能不太準確):編碼
這個 buffer
的大小實際上是能夠根據每一幀的最大大小來設定。而每一幀的最大大小,取決於視頻的分辨率和編碼格式,因此就有了下邊這個公式:spa
每一幀最大大小 = H x W x 編碼格式係數
第二個問題後面再聊~
上代碼!
https://github.com/T-Oner/MediaPractice
最新更新請關注微信公衆號