Android音視頻系列(二):MediaRecorder和MediaPlayer

前言

因?yàn)镸ediaRecorder和MediaPlayer都是比較常用的API,比較簡(jiǎn)單恩商,只需要寫好對(duì)應(yīng)的配置就實(shí)現(xiàn)了音視頻的錄制功能变逃,對(duì)于音頻錄制要求不高的話,基本滿足日常開(kāi)發(fā)的需求怠堪。

正文

首先我們添加需要使用到的權(quán)限:攝像頭揽乱,讀寫內(nèi)存卡和錄音,千萬(wàn)不要忘記粟矿。

錄制

/**
 * @author li.zhipeng
 *
 *      錄制視頻頁(yè)面
 * */
class MediaRecorderActivity : AppCompatActivity(), SurfaceHolder.Callback {

    private val videoRecorderFile: String

    init {

        val fileDir = File("${Environment.getExternalStorageDirectory().absolutePath}/test")
        fileDir.mkdirs()
        // 創(chuàng)建要保存的錄音文件的路徑
        videoRecorderFile = "$fileDir/video_record.mp4"

    }

    private var camera: Camera? = null
    
    // 需要自己維護(hù)錄制的狀態(tài)
    private var isRecording = false

    private var mediaRecorder: MediaRecorder? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        requestWindowFeature(Window.FEATURE_NO_TITLE)
        setContentView(R.layout.activity_media_recorder)

        surface_view.holder.addCallback(this)
        // 新版本可以忽略設(shè)置下面的屬性
//        surface_view.holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS)

        video_record.setOnClickListener {
            if (isRecording) {
                stopVideoRecord()
            } else {
                startVideoRecord()
            }

        }
    }

    override fun surfaceCreated(holder: SurfaceHolder?) {
        // 開(kāi)啟攝像頭
        if (camera == null) {
            camera = Camera.open()
        }
        // 雖然關(guān)閉了提示音凰棉,但是是沒(méi)有作用的
        camera!!.enableShutterSound(false)
        camera!!.setDisplayOrientation(90)
        // 綁定顯示的SurfaceHolder
        camera!!.setPreviewDisplay(holder)
        // 開(kāi)啟預(yù)覽
        camera!!.startPreview()
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
        if (holder.surface == null) {
            return
        }

        camera!!.stopPreview()
        camera!!.setPreviewDisplay(holder)
        camera!!.startPreview()
    }

    override fun surfaceDestroyed(holder: SurfaceHolder?) {
    }

    private fun startVideoRecord() {
        mediaRecorder = MediaRecorder().apply {
            camera!!.unlock()
            setCamera(camera!!)
            // 設(shè)置錄制的角度,如果與攝像頭不符陌粹,會(huì)出現(xiàn)視頻角度不對(duì)的問(wèn)題
            setOrientationHint(90);
            // 設(shè)置錄音和錄制視頻的來(lái)源
            setAudioSource(MediaRecorder.AudioSource.CAMCORDER)
            setVideoSource(MediaRecorder.VideoSource.CAMERA)
            // 還可以設(shè)置其他的信息
            // 輸出的視頻格式
//            setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
            // 設(shè)置編碼的格式
//            setVideoEncoder(MediaRecorder.VideoEncoder.H264)
            // 設(shè)置視頻的大小撒犀,必須要在設(shè)置視頻格式之后設(shè)置,否則會(huì)報(bào)錯(cuò)
//            setVideoSize()
            //視頻的幀率
//            setVideoFrameRate(25)
            // 設(shè)置錄制的質(zhì)量
            setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH))
            // 設(shè)置文件的輸出路徑
            setOutputFile(videoRecorderFile)

            setPreviewDisplay(surface_view.holder.surface)
            prepare()
            // 開(kāi)始錄制
            start()
        }

        isRecording = true
        video_record.text = "停止錄制"
    }

    private fun stopVideoRecord() {
        mediaRecorder?.let {
            it.stop()
            it.release()
            mediaRecorder = null
        }
        camera!!.lock()
        isRecording = false
        video_record.text = "開(kāi)始錄制"
        // 跳轉(zhuǎn)播放
        startActivity(Intent(this, MediaPlayerActivity::class.java))
    }

}

非常的簡(jiǎn)單掏秩,值得一提的是這種錄制方式有一個(gè)特別大的缺陷:開(kāi)始錄制的時(shí)候有“滴”的提示音;蛭琛!蒙幻!

可能不同的手機(jī)有不一樣的表現(xiàn)映凳,但是這個(gè)提示音是無(wú)法消除的,這也是為了防止用戶的隱私泄露邮破,所以為了用戶體驗(yàn)诈豌,大部分的軟件都沒(méi)有使用MediaRecorder。

播放

/**
 *  @author li.zhipeng
 *
 *          MediaPlayer播放視頻
 * */
class MediaPlayerActivity : AppCompatActivity(), MediaPlayer.OnPreparedListener {

    private val videoRecorderFile: String

    init {

        val fileDir = File("${Environment.getExternalStorageDirectory().absolutePath}/test")
        fileDir.mkdirs()
        // 創(chuàng)建要保存的錄音文件的路徑
        videoRecorderFile = "$fileDir/video_record.mp4"

    }

    private lateinit var mediaPlayer: MediaPlayer

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_media_player)
    }

    override fun onResume() {
        super.onResume()

        if (this::mediaPlayer.isInitialized) {
            mediaPlayer.start()
        } else {
            createMediaPlayer()
        }
    }

    private fun createMediaPlayer() {
        mediaPlayer = MediaPlayer().apply {
            setDataSource(videoRecorderFile)
            setOnPreparedListener(this@MediaPlayerActivity)
            prepare()
            start()
        }
    }

    override fun onPrepared(mp: MediaPlayer?) {
        mediaPlayer.setDisplay(surface_view.holder)
    }

    override fun onStop() {
        super.onStop()
        mediaPlayer.pause()
    }

    override fun onDestroy() {
        super.onDestroy()
        mediaPlayer.stop()
        mediaPlayer.release()
    }
}

播放同樣也非常的簡(jiǎn)單抒和,只需要把MediaPlayer和SurfaceHolder綁定起來(lái)矫渔,畫面就會(huì)自己顯示上去。

總結(jié)

MediaRecoder和MediaPlayer非常的簡(jiǎn)單摧莽,下一篇我們使用AudioRecoder錄制PCM音頻和播放庙洼,看看他們之間有什么樣的區(qū)別。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市送膳,隨后出現(xiàn)的幾起案子员魏,更是在濱河造成了極大的恐慌,老刑警劉巖叠聋,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件撕阎,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡碌补,警方通過(guò)查閱死者的電腦和手機(jī)虏束,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)厦章,“玉大人镇匀,你說(shuō)我怎么就攤上這事⊥嗫校” “怎么了汗侵?”我有些...
    開(kāi)封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)群发。 經(jīng)常有香客問(wèn)我晰韵,道長(zhǎng),這世上最難降的妖魔是什么熟妓? 我笑而不...
    開(kāi)封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任雪猪,我火速辦了婚禮,結(jié)果婚禮上起愈,老公的妹妹穿的比我還像新娘只恨。我一直安慰自己,他們只是感情好抬虽,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布官觅。 她就那樣靜靜地躺著,像睡著了一般斥赋。 火紅的嫁衣襯著肌膚如雪缰猴。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天疤剑,我揣著相機(jī)與錄音,去河邊找鬼闷堡。 笑死隘膘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的杠览。 我是一名探鬼主播弯菊,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼踱阿!你這毒婦竟也來(lái)了管钳?” 一聲冷哼從身側(cè)響起钦铁,我...
    開(kāi)封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎才漆,沒(méi)想到半個(gè)月后牛曹,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡醇滥,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年黎比,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盟榴。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡赊抖,死狀恐怖粘都,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情颓帝,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布窝革,位于F島的核電站躲履,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏聊闯。R本人自食惡果不足惜工猜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望菱蔬。 院中可真熱鬧篷帅,春花似錦、人聲如沸拴泌。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蚪腐。三九已至箭昵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間回季,已是汗流浹背家制。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留泡一,地道東北人颤殴。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鼻忠,于是被迫代替她去往敵國(guó)和親涵但。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容