MediaRecorder for Android Multimedia


foreword

The Android system provides the MediaRecorder class, through which audio, video, and screen can be recorded.

1. MediaRecorder state diagram

Recording control of audio/video files and streams is managed as a state machine. The following diagram shows the lifecycle and states of a MediaRecorder object driven by the supported recording control operations. The ovals represent states in which a MediaRecorder object may reside. Arcs represent recording control operations that drive object state transitions. There are two types of arcs. Arcs with single arrows indicate synchronous method calls, and arcs with double arrows indicate asynchronous method calls.

MediaRecorder state diagram

  1. Use the MediaRecorder construction method to construct a MediaRecorder, which is the Initial state at this time. After calling reset() in other states, it will also enter inital.
  2. After using setAudioSource() or setVideoSource(), enter the Initalized state.
  3. After calling setOutputFormat() to set the recording format, enter the DataSourceConfigured state. In this state, you can encrypt the recorded data and other settings.
  4. Call prepare() to enter the prepared state.
  5. Only in the prepared state can strart() be called to enter the Recording state. In this state, call stop() and reset() to stop recording.
  6. After recording is not needed, call release() to enter the released state, the current state means the end, and the MediaRecorder needs to be reconstructed to enter the intial state.
  7. Register setOnErrorListener to monitor, which can conveniently record error messages that occur during operation. In order to facilitate the end of these messages, the MediaRecorder object needs to be created on the thread of the Loooper (by default, the main thread has already run a Looper).

2. Recording

1. Audio recording

step:

  1. Call the MediaRecorder constructor to obtain a new instance.
  2. Use setOutputFormat() to set the output file format.
  3. Use setOutputFile() to set the output filename.
  4. Use setAuidoEncoder() to set the audio encoder.
  5. Initialization is done through prepare().
  6. Start and stop the recording function through start() and stop().
  7. After using the MediaRecorder instance, use release() to release its resources.

After Andoroid 9 (API 28), apps running in the background cannot access the microphone. Therefore, it can only be recorded when the application is in the foreground, or when the foreground service adds a MediaRecorder instance.
Starting with Android 8 (API 26), it is possible to use MediaMuxer to record multiple simultaneous audio and video streams. In lower versions only one audio track or video track can be recorded.

2. Camera recording

Using the Android framework to capture video requires attention to the management of the Camera object and the coordination with the MediaRecorder class. When using Camera to record video, you must manage Camera.lock() and Camera.unlock() calls to allow MediaRecorder to access the camera hardware, except for Camera.open() and Camera.release() calls.

Starting with Android 4.0 (API level 14), the system automatically manages the Camera.lock() and Camera.unlock() calls for you.

step:

  1. Open Camera - Use Camera.open() to get a Camera object instance.
  2. Attaching Preview - Use Camera.setPreviewDisplay() to attach the SurfaceView to the camera in preparation for a live camera image preview.
  3. Start preview - Call Camera.startPreview() to start displaying the live camera image.
  4. Start Video Recording - To successfully record a video, the following steps must be completed:
1、解锁相机 - 通过调用 Camera.unlock() 解锁相机以供 MediaRecorder 使用。

2、配置 MediaRecorder - 按此顺序在以下 MediaRecorder 方法中调用。
	setCamera() - 设置要用于视频捕获的相机,使用应用程序的当前 Camera 实例。
	
	setAudioSource() - 设置音频源,使用 MediaRecorder.AudioSource.CAMCORDER。
	
	setVideoSource() - 设置视频源,使用 MediaRecorder.VideoSource.CAMERA。

	设置视频的输出格式和编码。对于 Android 2.2(API 级别 8)及更高版本,请使用 MediaRecorder.setProfile 方法,并使用 CamcorderProfile.get() 获取配置文件实例。对于 Android 2.2 之前的版本,您必须设置视频的输出格式和编码参数:
	setOutputFormat() - 设置输出格式,指定默认设置或 MediaRecorder.OutputFormat.MPEG_4。
	setAudioEncoder() - 设置声音编码类型,指定默认设置或 MediaRecorder.AudioEncoder.AMR_NB。
	setVideoEncoder() - 设置视频编码类型,指定默认设置或 MediaRecorder.VideoEncoder.MPEG_4_SP。
	
	setOutputFile() - 设置输出文件,使用保存媒体文件部分示例方法中的 	getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()setPreviewDisplay() - 为您的应用指定 SurfaceView 预览布局元素。使用您在连接预览部分中指定的相同对象。
	
	3、准备 MediaRecorder - 通过调用 MediaRecorder.prepare() 提供的配置设置准备 MediaRecorder4、启动 MediaRecorder - 通过调用 MediaRecorder.start() 开始录制视频。
  1. Stop recording video - Call the following methods in order for video recording to complete successfully
1、停止 MediaRecorder - 通过调用 MediaRecorder.stop() 停止视频录制。

2、重置 MediaRecorder - (可选)通过调用 MediaRecorder.reset() 从录制器中移除配置设置。

3、释放 MediaRecorder - 通过调用 MediaRecorder.release() 释放 MediaRecorder4、锁定相机 - 锁定相机以便未来的 MediaRecorder 会话可通过调用 Camera.lock() 使用它。从 Android 4.0(API 级别 14)开始,除非 MediaRecorder.prepare() 调用失败,否则不需要此调用。
  1. Stop preview - Use Camera.stopPreview() to stop the preview when the Activity finishes using the camera.
  2. Release Camera - Releases the camera so other applications can use it by calling Camera.release().

If the app is usually used to record video, set setRecordingHint(boolean) to true before starting the preview. This setting helps reduce the time it takes to start recording.

3. Screen recording

Android has provided a mobile phone screen recording method since 4.0, but it requires root privileges, which is cumbersome and difficult to implement. However, starting from 5.0, it provides a series of methods for App to record the screen, which is managed through the screen capture interface of MediaProjection and the system-level service MediaProjectionManager.

To protect the user's screen content, Android 10 changes the scope of the READ_FRAME_BUFFER, CAPTURE_VIDEO_OUTPUT, and CAPTURE_SECURE_VIDEO_OUTPUT permissions to disable silent access to the device's screen content. Starting with Android 10, these permissions are only accessible by signature. And the foreground service must be turned on.

If you do not use the above logic to access the screen content, the following error will be reported:

java.lang.SecurityException: Media projections require a foreground service 
of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION

Permissions required in Manifest:

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

step:

  1. After the permission request is passed, request for screen recording permission.
 MediaProjectionManager mProjectionManager = ((MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE));
        if (mProjectionManager != null) {
    
    
            Intent intent = mProjectionManager.createScreenCaptureIntent();
         	startActivityForResult(intent, 1);
         }
  1. The user agrees to the screen admission permission, and obtains the authorized MediaProjection instance through the code and data returned by onActivityResult.
MediaProjectionManager projectionManager = (MediaProjectionManager)getSystemService(Context.MEDIA_PROJECTION_SERVICE);

MediaProjection  mMediaProjection = projectionManager.getMediaProjection(mResultCode, Objects.requireNonNull(mResultData));
  1. Start a foreground service Notification (required from Android 10).
  2. After the above steps are completed, the subsequent recording steps can refer to Camera.
  3. You also need to call mediaProjection.stop() to stop recording, and finally remember to release resources.

3. Case

1. Audio recording

package com.cs.mediarecordertest.audiorecorder;

import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.cs.mediarecordertest.R;
import java.io.File;
import java.io.IOException;

import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;

import static android.os.Environment.DIRECTORY_MOVIES;

public class AudioRecorderActivity extends AppCompatActivity {
    
    
    private static final String TAG = "AudioRecorderActivity";

    private String mPath;
    private MediaPlayer player;
    private String mFileName;
    private MediaRecorder recorder;
    public static final int RECORDING = 1;
    public static final int PLAYING = 2;
    public static final int IDLE = 0;

    private int mState = IDLE;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_audiorecorder);
        hide();
        initView();

    }


    private void hide() {
    
    
        // Hide UI first
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
    
    
            actionBar.hide();
        }

    }

    private boolean checkState() {
    
    

        switch (mState) {
    
    
            case RECORDING:
                Toast.makeText(this, "当前录制状态,请先结束录制!", Toast.LENGTH_SHORT).show();
                return false;
            case PLAYING:
                Toast.makeText(this, "当前播放状态,请先结束播放!", Toast.LENGTH_SHORT).show();
                return false;


        }

        return true;
    }

    private void initView() {
    
    

        MediaPlayer player = new MediaPlayer();
        MediaPlayer.TrackInfo[] trackInfo = player.getTrackInfo();
        player.selectTrack(1);
        File filesDir = getExternalFilesDir(DIRECTORY_MOVIES);
        mPath = filesDir.getAbsolutePath();
        mFileName = mPath + "/audio_1.3gp";
    }


    public void startRecording() {
    
    
        if (!checkState()) {
    
    
            return;
        }
        mState = RECORDING;
        recorder = new MediaRecorder();
        recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        recorder.setOutputFile(mFileName);
        recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

        try {
    
    
            recorder.prepare();
        } catch (IOException e) {
    
    
            Log.e(TAG, "prepare() failed");
            mState = IDLE;
        }

        recorder.start();
    }

    public void stopRecording() {
    
    

        if (recorder != null) {
    
    
            recorder.stop();
            recorder.release();
            recorder = null;
        }else{
    
    
            Toast.makeText(this, "当前已是空闲状态!", Toast.LENGTH_SHORT).show();
        }
        mState = IDLE;
    }


    public void onAudioRecorderStart(View view) {
    
    
        startRecording();
    }

    public void onAudioRecorderStop(View view) {
    
    
        stopRecording();
    }

    public void onPlayAudio(View view) {
    
    
        if (!checkState()) {
    
    
            return;
        }
        mState = PLAYING;
        player = new MediaPlayer();
        try {
    
    
            player.setDataSource(mFileName);
            player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
    
    
                @Override
                public void onCompletion(MediaPlayer mp) {
    
    
                    mState = IDLE;
                }
            });
            player.prepare();
            player.start();

        } catch (IOException e) {
    
    
            Log.e(TAG, "prepare() failed");
            mState = IDLE;
        }
    }

    @Override
    protected void onStop() {
    
    
        super.onStop();
        if (recorder != null) {
    
    
            recorder.release();
            recorder = null;
        }

        if (player != null) {
    
    
            player.release();
            player = null;
        }
    }

}

The cases here are very leak-proof codes, and the effect can only be seen barely, and there are many imperfections.
Because there is no dynamic permission application written, you need to go to the settings after the installation is successful, and manually open the permissions required by the APP.
The other two recording cases are available for reference at https://github.com/zyjy33/MediaRecorderTest.git .

Guess you like

Origin blog.csdn.net/qq_35831940/article/details/118556375