Android音視頻系列(一):基本概念掃盲

前言

已經(jīng)快兩個月沒寫博客了,最近換了工作,之前一直想研究研究音視頻方面的東西,終于有機會實現(xiàn)了,所以最近會一直寫這個系列。我也是剛剛摸索了一段時間,有什么問題大家一起討論指正。

第一篇是概念掃盲篇,如果不知道一些常用的API之后必然很難下手。

正文

由于FFmpeg特別的火,所以我一直認為音視頻和Android原生的API關(guān)系不大,其實這種理解是錯誤的,F(xiàn)Fmpeg的優(yōu)勢是解決了Android不同版本的API性能差距和問題,盡量在不同機型上達到性能相近的效果,第三方庫的更新肯定要比系統(tǒng)版本更新方便多了。

所以如果對原生的API有了熟練的掌握,過度到FFmpeg就都是小問題了。今天我們了解一些常用的API的概念。

MediaPlayer

音視頻播放的上層API,可以用來播放音頻和視頻文件,特別常用的API。

// 創(chuàng)建MediaPlayer
 val mediaPlayer = MediaPlayer()
 // 設(shè)置要播放的文件路徑
 mediaPlayer.setDataSource(path)
 // 準備
 mediaPlayer.prepare()
 // 播放
 mediaPlayer.start()

還有一些暫停,停止的方法,這里就不介紹了,相信大家都用過。

MediaRecoder

音視頻錄制的上層API,通過一些簡單的配置,就可以直接錄制音視頻保存到指定的文件路徑。

// 創(chuàng)建MediaRecorder
val mediaRecorder = MediaRecorder()
// 錄制聲音的來源,具體參考AudioSource
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
// 錄制視頻的來源
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE)
// 輸出的文件編碼格式
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
// 保存的文件路徑 
mediaRecorder.setOutputFile(videoRecorderFile)

// 設(shè)置錄音編碼器
// 注意設(shè)置的錄制音頻編碼格式與視頻的編碼格式是否匹配
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
// 音頻錄制的其他設(shè)置
mediaRecorder.setAudioEncodingBitRate(60)
mediaRecorder.setAudioSamplingRate(14400)
// 視頻錄制的其他設(shè)置
mediaRecorder.setVideoSize(getScreenWidth(), getScreenHeight())
mediaRecorder.setVideoEncodingBitRate(2 * getScreenWidth().times(getScreenHeight()))
mediaRecorder.setVideoFrameRate(60)
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264)
mediaRecorder.prepare()
mediaRecorder.start()

// 停止錄制
mediaRecorder!!.stop()
mediaRecorder!!.release()

都是基本的配置,不過如果是錄制視頻一般要和Surface一起使用,從攝像頭中得到錄制的內(nèi)容,MediaRecorder也有對應(yīng)的方法設(shè)置:

// 設(shè)置攝像頭
mediaRecorder.setCamera(camera!!)
// 設(shè)置錄制的角度,如果與攝像頭不符,會出現(xiàn)視頻角度不對的問題
mediaRecorder.setOrientationHint(90);
// 設(shè)置錄音和錄制視頻的來源
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER)
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA)
 // 設(shè)置錄制的質(zhì)量
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH))
....

網(wǎng)上有很多Demo,大家可以去搜索一下,之后我們也會自己寫一寫Demo。

AudioRecord

音頻錄制的API,通過流的形式輸出的音頻數(shù)據(jù)是未經(jīng)過編碼的,也就是PCM原數(shù)據(jù),所以直接保存錄制出的內(nèi)容是無法直接使用播放器進行播放。

// 創(chuàng)建AudioRecord
AudioRecord(
            // 錄制音頻的來源,參數(shù)與MediaRecoder相同
            AudioSource,
            // 采樣率,
            sampleRateInH,
            // 聲音的頻道
            CHANNEL,
            // 編碼位數(shù)
            ENCODING,
            // 錄制一幀的最小Buffer大小
            AudioRecord.getMinBufferSize(
                sampleRateInH,
                CHANNEL,
                ENCODING
            )
 )

可以看出,AudioRecorder相比MediaRecoder要更加細致,如果你有對音頻有一些特殊的處理,例如變聲,就需要使用到AudioRecorder,然后再自己編碼保存。

然后我們再了解一下構(gòu)造方法中的參數(shù):

AudioSource:錄制的聲音來源,跟MediaRecoder是一樣的。
·
sampleRateInH:采樣率,通俗的講采樣頻率是指計算機每秒鐘采集多少個信號樣本,單位是Hz。越高聲音肯定是越清晰,常用的大小有:
8000Hz 電話所用采樣率,對于人的說話已經(jīng)足夠
11025Hz 獲得的聲音稱為電話音質(zhì),基本上能讓你分辨出通話人的聲音
22050Hz 無線電廣播所用采樣率,廣播音質(zhì)
32000Hz miniDV數(shù)碼視頻camcorder、DAT(LPmode)所用采樣率
44100Hz 音頻CD,也常用于MPEG-1音頻(VCD,SVCD,MP3)所用采樣率
47250Hz NipponColumbia(Denon)開發(fā)的世界上第一個商用PCM錄音機所用采樣率
48000Hz miniDV、數(shù)字電視、DVD、DAT、電影和專業(yè)音頻所用的數(shù)字聲音所用采樣率
.
CHANNEL:就是視頻的立體聲,左聲道,右聲道
.
ENCODING:這個編碼指的是保存的位數(shù),一般使用16位。
.
AudioRecord.getMinBufferSize:每一幀的最小大小,如果是讀操作,就要用到它。

MediaCodec

音視頻的編碼和解碼器,應(yīng)該是這個系列最重要的API了,為了配合他的使用,還得用到MediaFormat等其他的API。

// 這里僅僅是一個簡單的例子,MediaCodec的使用要更復(fù)雜一些
// 創(chuàng)建一個avc格式的視頻編碼器
mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC)
// 詳細配置MediaFormat
val mediaFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, width, height)
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 125000)
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15)
mediaFormat.setInteger(
          MediaFormat.KEY_COLOR_FORMAT,
          MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface
)
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5)
// 使用配置好的MediaFormat
mediaCodec!!.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
// 開始編碼
mediaCodec!!.start()

在實際應(yīng)用中,MediaCodec的使用要更加復(fù)雜一些,這里只是先簡單了解,之后的案例中我們再慢慢分析。

MediaExtractor

音視頻分提取器,例如把某視頻文件中的音頻提取出來保存成一個音頻文件。

// 創(chuàng)建一個分離器,還沒有指定要分離的部分
val mediaExtractor = MediaExtractor()
// 文件路徑
mediaExtractor.setDataSource(file.absolutePath)
// trackCount表示有多少可以分離的軌道,常用的音軌和視軌
val trackNum = mediaExtractor.trackCount
for (i in 0 until trackNum) {
      // 對應(yīng)軌道的格式
      val mediaFormat = mediaExtractor.getTrackFormat(i)
      // 音頻:“audio/”,視頻:“video/”
      val format = mediaFormat.getString("mime")
      if (format.startsWith(prefix)) {
            // 選擇需要的軌道,接下來就可以提取這個軌道的內(nèi)容了
           videoMediaExtractor.selectTrack(videoIndex)
      }
}
// 讀取內(nèi)容         
val frameSize = mediaExtractor.readSampleData(mReadBuffer, 0)
...
// 釋放資源
mediaExtractor.release()

MediaMuxer

音視頻合成器,視頻音頻合成,視頻合成等等,常用與剛才的MediaExtractor一起使用

mediaMuxer = MediaMuxer(outPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
val mReadBuffer = ByteBuffer.allocate(MAX_BUFF_SIZE)
// 選擇音軌 
val audioMediaExtractor = MediaExtractor()
audioMediaExtractor.setDataSource(path)
val audioIndex = findTrackIndex(audioMediaExtractor, "audio/")
audioMediaExtractor.selectTrack(audioIndex)
// 讀取幀數(shù)據(jù)
val frameSize = mediaExtractor.readSampleData(mReadBuffer, 0)
mReadBuffer.rewind()
// 將數(shù)據(jù)寫入到合成文件中
mediaMuxer!!.writeSampleData(outTrackIndex, mReadBuffer, bufferInfo)
// 釋放
mediaMuxer!!.release()

總結(jié)

今天我們了解了Android原生常用的API,這些API已經(jīng)足夠滿足我們開發(fā)中的各種需要,接下來我們要完成以下任務(wù):

  1. MediaRecoder錄制音頻和視頻
  2. MediaPlayer播放音頻和視頻
  3. MediaCodec播放音頻和視頻
  4. AudioRecoder錄制PCM音頻和播放
  5. MediaCodec錄制視頻
  6. 音視頻合成和抽取
  7. 斷點錄制以及視頻合成

(以上任務(wù)不分先后,順序可能會變)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容