1. 程式人生 > >《android多媒體api》之MediaRecorder音視訊錄製api

《android多媒體api》之MediaRecorder音視訊錄製api

《android多媒體api》系列是整合梳理android開發中經常用到的媒體相關api;多媒體開發主要內容有音訊、視訊錄製播放、攝像頭操作、錄製操作、流媒體、直播、推流、拉流等方面;最近幾年移動直播和視訊應用發展猶如雨後春筍一般直插雲霄,呃。。好吧這段比喻可以不用看了!!,反正行業興起肯定催生了很多多媒體相關應用開發程式設計師。那麼怎樣才能成為多媒體開發程式設計師,首先必須要熟練使用和了解android自帶的多媒體api,並且還要掌握pcm、yuv、rgb、h264、aac、flv、mpegts、mp4、udp、rtp、rtmp等等眾多檔案格式和流媒體協議等等。所以這裡整理android相關多媒體api,提供給想從事流媒體同學作為參照,同樣還是要鳴謝網路上那些具有分享精神大神們!!

基本概念:

  1. 視訊播放:demuxer(解複用)->分離出音訊流和視訊流->decoder(解碼)->播放原始資料(例如:pcm yuv)
  2. 視訊錄製:採集原始資料(例如:pcm yuv)->encoder(編碼)->muxer(封裝格式 例如:mp4 3gp)
  3. 流媒體協議:udp、rtp、rtmp、rtcp、rtsp等
  4. 音視訊封裝格式:mp4 、3gp、flv等
  5. 音視訊編碼格式:aac、amr、h264、h265等
  6. 原始音視訊資料格式:pcm 、yuv、rgb等

流程圖:
image

文章目錄:

MediaRecorder是什麼?
MediaPlayer類主要用於音訊視訊錄製的api。現在有很多短視訊app非常火爆,所以瞭解視訊錄製api是非常重要的,android自帶多媒體錄製api都是在硬編碼(依靠硬體驅動編碼)基礎上進行封裝,所以如果要達到專業級別的短視訊應用開發工程師還要了解如何前置處理pcm 、jpg等處理演算法。
首先視訊音訊錄製是屬於使用者敏感資訊,所以使用之前一定要申請許可權:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
/>

這裡構建一個demo app,使用mediarecorder api 錄製mp4 視訊檔案,使用surfaceview 控制元件進行預覽。

效果圖:

這裡寫圖片描述

MediaRecorder api方法:

final static int getAudioSourceMax()

獲取音訊源的最大值。

int getMaxAmplitude()

獲取在前一次呼叫此方法之後錄音中出現的最大振幅。

void prepare()

準備錄製。

void release()

釋放資源。

void reset()

將MediaRecorder設為空閒狀態,即Initial狀態。

void setAudioChannels(int numChannels)

設定錄製的音訊通道數。

void setAudioEncoder(int audio_encoder)

設定所錄製的聲音的編碼格式。

void setAudioEncodingBitRate(int bitRate)

設定所錄製的聲音的編碼位率。

void setAudioSamplingRate(int samplingRate)

設定所錄製的聲音的取樣率。

void setAudioSource(int audio_source)

設定聲音來源,一般傳入 MediaRecorder. AudioSource.MIC引數指定錄製來自麥克風的聲音。

void setCamera(Camera c)

設定一個攝像頭用於錄製。

void setCaptureRate(double fps)

設定視訊幀捕獲率。

void setLocation(float latitude, float longitude)

設定並存儲在輸出檔案中的地理資料(經度和緯度)。

void setMaxDuration(int max_duration_ms)

設定錄製會話的最長持續時間(以ms為單位)。

void setMaxFileSize(long max_filesize_bytes)

設定錄製檔案的最大檔案大小。

void setOnErrorListener(MediaRecorder.OnErrorListener l)

註冊一個用於記錄錄製時出現的錯誤的監聽器。

void setOnInfoListener(MediaRecorder.OnInfoListener listener)

註冊一個用於記錄錄製時出現的資訊事件。

void setOrientationHint(int degrees)

設定輸出的視訊播放的方向提示。

void setOutputFile(FileDescriptor fd)

設定錄製的音訊檔案的儲存位置。

void setOutputFile(String path)

設定錄製的音訊檔案的儲存位置。

void setOutputFormat(int output_format)

設定所錄製的音視訊檔案的格式。

void setPreviewDisplay(Surface sv)

設定使用哪個SurfaceView來顯示視訊預覽。

void setProfile(CamcorderProfile profile)

指定CamcorderProfile物件。

void setVideoEncoder(int video_encoder)

設定所錄製視訊的編碼格式。

void setVideoEncodingBitRate(int bitRate)

設定所錄製視訊的編碼位率。

void setVideoFrameRate(int rate)

設定錄製視訊的捕獲幀速率。

void setVideoSize(int width, int height)

設定要拍攝的寬度和視訊的高度。

void setVideoSource(int video_source)

設定用於錄製的視訊來源。

void start()

開始錄製。

void stop()

停止錄製。

基於MediaRecorder實現自定義錄影機:

xml佈局檔案:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <SurfaceView
        android:id="@+id/surfaceView1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"/>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_gravity="bottom|center_horizontal"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:onClick="onClick"
            android:id="@+id/start_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="開始錄製"/>


        <Button
            android:onClick="onClick"
            android:layout_marginLeft="80dp"
            android:id="@+id/btnStop"
            android:layout_width="80dip"
            android:layout_height="wrap_content"
            android:text="停止錄製"/>
    </LinearLayout>
</FrameLayout>

java程式碼:

package com.jared.helloffmpeg;

import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.Nullable;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Toast;

public class RecordMP4Push extends Activity implements View.OnClickListener, SurfaceHolder.Callback {

    private SurfaceView surfaceView;
    private MediaRecorder mediaRecorder;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        setContentView(R.layout.record_aac_and_pcm);

        surfaceView=findViewById(R.id.surfaceView1);
        surfaceView.getHolder().addCallback(this);
    }

    @Override
    public void onClick(View view) {
        if (view.getId()==R.id.start_btn)
        {
            if (mediaRecorder!=null)
                return;
            // 燒錄按鈕
            try {
                mediaRecorder=new MediaRecorder();
                mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
                mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
                mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
                mediaRecorder.setOutputFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+System.currentTimeMillis()+".3gp");
                mediaRecorder.setPreviewDisplay(surfaceView.getHolder().getSurface());
                mediaRecorder.prepare();
                mediaRecorder.start();
                Toast.makeText(getApplicationContext(), "錄影", Toast.LENGTH_SHORT).show();
            } catch (Exception e) {
                Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
            }
        }
        if (view.getId()==R.id.btnStop)
        {
            if (mediaRecorder==null)
                return;
            mediaRecorder.stop();
            mediaRecorder.release();
            mediaRecorder=null;
            Toast.makeText(getApplicationContext(), "停止錄影", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {

    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {

    }
}