日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

MediaRecorder之视频录制

發布時間:2023/12/18 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MediaRecorder之视频录制 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一 前言

? ?在前面已經介紹過使用MediaRecorder錄制音頻,那么錄制視頻呢?很顯然錄制視頻也需要MediaRecorder,同時需要攝像頭Camera(相當于攝像機)。Camera用來取景,然后使用SurfaceView顯示影像,那么MediaRecorder用來做錄制的工作,接下來就是看看視頻的錄制的過程。 ? ?本篇通過一個示例來認識簡單視頻的錄制的過程,示例說明:通過Camera、MediaRecorder實現視頻錄制,停止錄制后,點擊播放按鈕使用MediaPlayer來播放視頻,示例完整代碼最后提供(該實例的完整代碼在recodervideomediarecorder的module中 )。

二?視頻錄制

? ?視頻錄制步驟大致如下: (1)打開Camera(攝像頭); (2)設置攝像機參數(CamcorderProfile),設置攝像頭參數; (3)創建MediaRecorder對象實例,可以通過默認的構造方法進行創建; (4)設置音頻來源、視頻來源、錄制設備(Camera)、錄制信息(CamcorderProfile)、輸出文件格式等; (5)創建SurfaceView(可以直接在布局中使用),并給SurfaceHolder添加callback監聽; (6)通過MediaRecorder對象實例調用setPreviewDisplay方法設置視頻預覽界面; (7)調用prepare方法做錄制前的準備工作; (8)調用start、pause、stop方法控制錄制過程; 接下來就來看看具體實現過程。

1 打開Camera(攝像頭)

public static Camera open(int cameraId) {
//獲取攝像頭數目
int numCameras = Camera.getNumberOfCameras();
if (numCameras == 0) {
Log.w(TAG, "No cameras!");
return null;
}
// cameraId the hardware camera to access, between 0 and numCameras(攝像頭數目) - 1
boolean explicitRequest = cameraId >= 0;

if (!explicitRequest) {
// Select a camera if no explicit camera requested
int index = 0;
while (index < numCameras) {
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
Camera.getCameraInfo(index, cameraInfo);
//判斷使用是前置還是后置攝像頭 如果是后置攝像頭則停止循環
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
break;
}
index++;
}

cameraId = index;
}

Camera camera;
if (cameraId < numCameras) {
printMessage("Opening camera #" + cameraId);
camera = Camera.open(cameraId);
} else {
if (explicitRequest) {
Log.w(TAG, "Requested camera does not exist: " + cameraId);
camera = null;
} else {// cameraId 值 小于 0 且 不存在后置攝像頭時,會走這里
printMessage( "No camera facing back; returning camera #0");
camera = Camera.open(0);
}
}

return camera;
}
說明:上述代碼的功能主要是通過ID打開攝像頭,一般ID為0的是后置攝像頭;如果有多個攝像頭的ID依次為0,1,2,...。

2 設置攝像機參數(CamcorderProfile)與攝像頭參數

(1)設置攝像機參數 public static CamcorderProfile setCamcorderProfile(boolean isHigh ){
//返回后置相機的配置信息的類
CamcorderProfile profile = CamcorderProfile.get(isHigh ? CamcorderProfile.QUALITY_HIGH : CamcorderProfile.QUALITY_LOW);
//設置視頻幀的寬度
profile.videoFrameWidth = (int) (profile.videoFrameWidth * VIDEO_SIZE_RATE);
//設置視頻幀的高度
profile.videoFrameHeight = (int) (profile.videoFrameHeight * VIDEO_SIZE_RATE);
//設置視頻輸出比特率 The target video output bit rate in bits per second
profile.videoBitRate = VIDEO_BIT_RATE;
CamcorderProfile highProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
//The video encoder being used for the video track 設置視頻編碼
profile.videoCodec = highProfile.videoCodec;
//設置音頻編碼
profile.audioCodec = highProfile.audioCodec;
//The file output format of the camcorder profile 設置輸出格式
profile.fileFormat = MediaRecorder.OutputFormat.MPEG_4;
return profile;
} 說明:很顯然上方法主要是配置攝像機參數,返回CamcorderProfile即配置文件(在后面會用到)。那么CamcorderProfile是什么鬼?CamcorderProfile是用來保存攝像機配置信息的一個實體類,準確說是保存音視頻配置信息,Android系統已經幫我們預定好了這些配置信息,當然你也可以自己設置,這些信息有:
  • 文件輸出格式
  • 視頻編解碼格式
  • 視頻比特率,以位/秒為單位
  • 視頻幀速率(以每秒幀數為單位)
  • 視頻幀寬和高度,
  • 音頻編解碼格式
  • 音頻比特率,以位/秒為單位,
  • 音頻采樣率
  • 錄制的音頻通道數。
  • 對應的變量為: public int fileFormat; public int videoCodec; public int videoBitRate; public int videoFrameRate; public int videoFrameWidth; public int videoFrameHeight; public int audioCodec; public int audioBitRate; public int audioSampleRate; public int audioChannels 同時它包含了視頻的質量信息,獲取方法如下: 手機支持的最低分辨率: 1.直接獲取 CamcorderProfile profile=CamcorderProfile.get(CamcorderProfile.QUALITY_LOW); 2.按時間流逝,質量變化情況來 CamcorderProfile profile=CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_LOW); 3.按高幀數下的質量來 CamcorderProfile profile=CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH_SPEED_LOW); 手機支持的最高分辨率:
    1.直接獲取 CamcorderProfile profile=CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH); 2.按時間流逝,質量變化情況來 CamcorderProfile profile=CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH); 3.按高幀數下的質量來 CamcorderProfile profile=CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH_SPEED_HIGH); 因此CamcorderProfile為我們實現視頻的錄制提供很大的方便。 (2)設置攝像頭參數 /**
    * 設置攝像頭參數,錄制視頻時使用該方法
    * @param camera 攝像頭
    * @param profile 該參數為攝像機配置文件,里面保存類攝像機的參數
    * @param whiteBalance 白平衡 可以為 null
    * @param colorEffect 顏色效果 可以為 null
    * @return 攝像頭參數類 {@link Camera.Parameters } 對象
    */
    public static Camera.Parameters setCameraParameters(Camera camera , CamcorderProfile profile , String whiteBalance , String colorEffect){
    if (camera == null){
    printMessage("camera can not null !");
    return null;
    }
    if (profile == null){
    printMessage("profile can not null !");
    return null;
    }


    //因為android不支持豎屏錄制,所以需要順時針轉90度,讓其游覽器顯示正常
    camera.setDisplayOrientation(90);

    Camera.Parameters parameters = camera.getParameters();
    //設置預覽圖片的大小
    parameters.setPreviewSize(profile.videoFrameWidth, profile.videoFrameHeight);
    //設置預覽圖片的幀率
    parameters.setPreviewFrameRate(profile.videoFrameRate);
    //設置獲焦模式
    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);

    if (TextUtils.isEmpty(whiteBalance)){
    whiteBalance = "auto";
    }
    if (TextUtils.isEmpty(colorEffect)){
    colorEffect = "none";
    }
    // 設置白平衡參數。
    if (isSupported(whiteBalance, parameters.getSupportedWhiteBalance())) {
    parameters.setWhiteBalance(whiteBalance);
    }
    // 參數設置顏色效果。
    if (isSupported(colorEffect, parameters.getSupportedColorEffects())) {
    parameters.setColorEffect(colorEffect);
    }

    camera.setParameters(parameters);
    return parameters;
    } 說明:上述代碼主要通過Camera.Parameters與上面返回的CamcorderProfile設置預覽圖片的大小,幀的速率等,在這里我使用豎屏拍攝,所以Camera直接旋轉了90度。

    3 創建MediaRecorder對象實例

    MediaRecorder mediaRecorder = new MediaRecorder();

    4 設置音頻來源、視頻來源、錄制設備(Camera)、錄制信息(CamcorderProfile)、輸出文件格式等;

    //關閉鎖,使其他線程可以訪問攝像頭 在打開攝像頭時要打開鎖
    camera.unlock();
    mediaRecorder.setCamera(camera);
    // 設置錄制視頻源為Camera(相機)
    mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    // 設置音頻資源
    mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    //Uses the settings from a CamcorderProfile object for recording 根據CamcorderProfile對象設置錄制信息
    mediaRecorder.setProfile(profile);
    //設置視頻大小(分辨率)
    mediaRecorder.setVideoSize(1280, 720);
    // 設置視頻一次寫多少字節(可調節視頻空間大小)
    mediaRecorder.setVideoEncodingBitRate(1024 * 1024);
    //每秒4幀
    mediaRecorder.setVideoFrameRate(4);

    //設置視頻文件的輸出格式 必須在設置聲音編碼格式、圖像編碼格式之前設置
    // mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    // mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
    // mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);

    // 最大期限
    mediaRecorder.setMaxDuration(35 * 1000);
    //視頻文件名
    String fileName = "VID_" + System.currentTimeMillis() + ".mp4";
    file = new File(videoPath, fileName);
    // 指定輸出文件 , 設置視頻文件輸出的路徑
    mediaRecorder.setOutputFile(file.getAbsolutePath()); 說明:videoPath為視頻本地保存路徑,還有一點需要注意的就是打開Camera后,要調用lock方法鎖住Camera,在開始錄制前避免被其他線程訪問Camera(不然老是出現錯誤,Camera無法使用,我試過了好多次都不行),在開始錄制的時候再調用unlock方法開鎖,使其線程可以訪問

    5 創建SurfaceView(可以直接在布局中使用),并給SurfaceHolder添加callback監聽

    (1)創建SurfaceView surfaceView = (SurfaceView) findViewById(R.id.sufaceview); (2)給SurfaceHolder添加callback監聽 surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    if (camera != null){
    CameraHelpUtil.startPreview(camera,surfaceView.getHolder());
    }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    if (camera != null){
    camera.stopPreview();
    }
    }
    });

    6 通過MediaRecorder對象實例調用setPreviewDisplay方法設置視頻預覽界面

    //設置 surface 預覽視頻
    mediaRecorder.setPreviewDisplay(holder.getSurface());
    // // 設置保存錄像方向
    mediaRecorder.setOrientationHint(90);

    7 調用prepare方法做錄制前的準備工作

    try {
    mediaRecorder.prepare();
    } catch (IOException e) {
    Log.d(TAG,e.getMessage());
    }

    8 開始錄制

    mediaRecorder.start();
    說明:步驟3,4,6,7,8組合在一起形成一個完整的方法如下: /**
    * 初始化 MediaRecorder 對象實例
    * @param camera 攝像頭
    * @param profile 攝像頭配置文件
    * @param videoPath 視頻保存的位置
    * @param holder SurfaceHolder 對象實例
    */
    public static MediaRecorder record( Camera camera , CamcorderProfile profile , String videoPath, SurfaceHolder holder){
    MediaRecorder mediaRecorder = new MediaRecorder();
    //關閉鎖,使其他線程可以訪問攝像頭 在打開攝像頭時要打開鎖
    camera.unlock();
    mediaRecorder.setCamera(camera);
    // 設置錄制視頻源為Camera(相機)
    mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    // 設置音頻資源
    mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    //Uses the settings from a CamcorderProfile object for recording 根據CamcorderProfile對象設置錄制信息
    mediaRecorder.setProfile(profile);
    //設置視頻大小(分辨率)
    mediaRecorder.setVideoSize(1280, 720);
    // 設置視頻一次寫多少字節(可調節視頻空間大小)
    mediaRecorder.setVideoEncodingBitRate(1024 * 1024);
    //每秒4幀
    mediaRecorder.setVideoFrameRate(4);

    //設置視頻文件的輸出格式 必須在設置聲音編碼格式、圖像編碼格式之前設置
    // mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    // mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
    // mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);

    // 最大期限
    mediaRecorder.setMaxDuration(35 * 1000);
    //視頻文件名
    String fileName = "VID_" + System.currentTimeMillis() + ".mp4";
    file = new File(videoPath, fileName);
    // 指定輸出文件 , 設置視頻文件輸出的路徑
    mediaRecorder.setOutputFile(file.getAbsolutePath());
    //設置 surface 預覽視頻
    mediaRecorder.setPreviewDisplay(holder.getSurface());
    // // 設置保存錄像方向
    mediaRecorder.setOrientationHint(90);

    mediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() {
    @Override
    public void onError(MediaRecorder mr, int what, int extra) {
    // Toast.makeText(RecorderVideoActivity.this, "未知錯誤", Toast.LENGTH_SHORT).show();
    }
    });

    mediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
    @Override
    public void onInfo(MediaRecorder mr, int what, int extra) {

    }
    });

    try {
    mediaRecorder.prepare();
    mediaRecorder.start();
    } catch (IOException e) {
    Log.d(TAG,e.getMessage());
    }

    return mediaRecorder;
    }
    說明:上述代碼都是錄制視頻業務邏輯的實現過程,都寫成了工具類,源碼中有,播放視頻的實現前面有介紹過,這里就不累述了,下面貼出示例的實現代碼:

    三 示例

    1 視頻錄制界面Activity的實現代碼

    public class RecorderVideoActivity extends AppCompatActivity {

    private String filePath = " ";
    private Camera camera;
    private CamcorderProfile profile;
    private MediaRecorder mediaRecorder;
    private SurfaceView surfaceView;
    private ImageView img_start;
    /** true 正在錄制 */
    private boolean isRecoding = false;
    private TextView txt_play;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_recorder_video);
    surfaceView = (SurfaceView) findViewById(R.id.sufaceview);
    img_start = (ImageView) findViewById(R.id.img_start);
    txt_play = (TextView) findViewById(R.id.txt_play);
    setListener();
    }

    /**
    * 設置監聽
    */
    private void setListener() {
    surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    if (camera != null){
    CameraHelpUtil.startPreview(camera,surfaceView.getHolder());
    }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    if (camera != null){
    camera.stopPreview();
    }
    }
    });

    img_start.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    if (camera == null){
    return;
    }
    if (isRecoding){
    isRecoding = false;
    MediaRecorderHelpUtil.stop(mediaRecorder);
    img_start.setImageResource(R.mipmap.icon_voice_transcribe);
    }else {
    mediaRecorder = MediaRecorderHelpUtil.record(camera,profile,filePath,surfaceView.getHolder());
    isRecoding = true;
    img_start.setImageResource(R.mipmap.icon_stop_transcribe);
    }
    }
    });

    txt_play.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    play();
    }
    });
    }

    private void play() {
    if (null == MediaRecorderHelpUtil.getFile()){
    return;
    }
    Intent intent = new Intent(this,MediaPlayerSurfaceActivity.class);
    intent.putExtra("video_Path",MediaRecorderHelpUtil.getFile().getAbsolutePath());
    startActivity(intent);
    }


    @Override
    protected void onResume() {
    super.onResume();
    isRecoding = false;
    }


    @Override
    protected void onStart() {
    super.onStart();
    if (camera == null){
    checkPermission();
    }
    }

    /**
    * 動態檢測必要的權限
    */
    private void checkPermission() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M){
    initDrives();
    return;
    }
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != 0 ||
    ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != 0 ||
    ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != 0 ||
    ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != 0){
    ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
    Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.RECORD_AUDIO,Manifest.permission.CAMERA},0x123);
    }else {
    initDrives();
    }
    }

    /**
    * 初始化攝像頭設備
    */
    private void initDrives() {
    getFilePath();
    camera = CameraHelpUtil.open();
    //打開鎖 ,使其他線程無法訪問 攝像頭
    camera.lock();
    if (camera != null){
    profile = CameraHelpUtil.setCamcorderProfile(false);
    CameraHelpUtil.setCameraParameters(camera,profile,null,null);
    }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == 0x123){
    if (grantResults[0] == 0 && grantResults[1] == 0 && grantResults[2] == 0 && grantResults[3] == 0){
    initDrives();
    }else {
    Toast.makeText(this, "需要必要的權限,請授權", Toast.LENGTH_SHORT).show();
    }
    }
    }


    /**
    * 獲取文件保存路徑
    */
    private void getFilePath(){
    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
    filePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath() /*+ File.separator + getPackageName()*/;
    }else {
    filePath = Environment.getDataDirectory().getAbsolutePath() /*+ File.separator + getPackageName()*/;
    }
    filePath = filePath + File.separator + "Camera";
    File file = new File(filePath);
    if (!file.exists()){
    file.mkdirs();
    }
    filePath = file.getAbsolutePath();
    }


    @Override
    protected void onDestroy() {
    CameraHelpUtil.releaseCamera(camera);
    if (isRecoding){
    MediaRecorderHelpUtil.stop(mediaRecorder);
    // MediaRecorderHelpUtil.release(mediaRecorder);
    }
    super.onDestroy();
    }
    }
    其Xml文件如下: <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.lzb.video.RecorderVideoActivity">

    <SurfaceView
    android:id="@+id/sufaceview"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

    <ImageView
    android:id="@+id/img_start"
    android:layout_gravity="bottom|center_horizontal"
    android:src="@mipmap/icon_voice_transcribe"
    android:layout_marginBottom="50dp"
    android:scaleType="fitXY"
    android:layout_width="60dp"
    android:layout_height="60dp" />

    <TextView
    android:id="@+id/txt_play"
    android:text="播放視頻"
    android:textColor="@android:color/white"
    android:layout_gravity="bottom|center_horizontal"
    android:layout_marginBottom="20dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
    </FrameLayout>

    2 播放界面代碼

    public class MediaPlayerSurfaceActivity extends Activity implements View.OnClickListener{

    /** 視頻播放控件*/
    private SurfaceView surfaceView;
    private Display currDisplay;
    /** 給SurfaceView添加CallBack監聽 */
    private SurfaceHolder holder;
    /** 多媒體*/
    private MediaPlayer player;
    private int vWidth,vHeight;
    /** 視頻路徑*/
    private String videoPath = "";
    private Button button;

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

    button = (Button) findViewById(R.id.btn_start);
    button.setOnClickListener(this);
    //獲取播放地址
    Intent intent = getIntent();
    videoPath = intent.getStringExtra("video_Path");

    surfaceView = (SurfaceView) findViewById(R.id.surface_surface_view);
    //然后,我們取得當前Display對象
    currDisplay = this.getWindowManager().getDefaultDisplay();
    //下面開始實例化MediaPlayer對象
    player = new MediaPlayer();
    setPlayerListener();
    setHolder();
    }

    /**
    * 將要播放的視頻圖像輸送到surfaceView
    */
    private void setHolder() {
    //給SurfaceView添加CallBack監聽
    holder = surfaceView.getHolder();
    //為了可以播放視頻或者使用Camera預覽,我們需要指定其Buffer類型
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    holder.addCallback(new Callback() {
    /**
    * Activity進入后臺會觸發該方法
    * @param holder
    */
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    Toast.makeText(MediaPlayerSurfaceActivity.this, "Surface被銷毀", Toast.LENGTH_SHORT).show();

    }

    /**
    *
    * Activity進入前臺會觸發該方法
    *
    * 當SurfaceView中的Surface被創建的時候被調用*/
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    Toast.makeText(MediaPlayerSurfaceActivity.this, "Surface被創建", Toast.LENGTH_SHORT).show();
    play();

    }
    /** 當Surface尺寸等參數改變時觸發 */
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {

    }
    });
    }

    /**
    *
    * MediaPlayer中的prepare方法和prepareAsync方法的區別
    * prepare方法是將資源同步緩存到內存中,一般加載本地較小的資源可以用這個,
    * 如果是較大的資源或者網絡資源建議使用prepareAsync方法,異步加載.但如果想讓資源啟動,即start()起來,
    * 因為在異步中,如果不設置監聽直接start的話,是拿不到這個資源,如果讓線程睡眠一段時間,則可以取得資源,因為這個時候,
    * 異步線程已經取得資源,但不可能使用線程睡眠的方式來獲取資源啊.所以就需要設置監聽事件setOnPreparedListener();
    * 來通知MediaPlayer資源已經獲取到了,然后實現onPrepared(MediaPlayer mp)方法.在里面啟動MediaPlayer
    * 參考:http://blog.csdn.net/qq_24223073/article/details/69315856
    * 設置監聽示例{@link #setPlayerListener}
    * 開始播放視頻
    */
    void play() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    surfaceView.setForeground(null);
    }
    if (TextUtils.isEmpty(videoPath)){
    return;
    }
    player.reset();
    //將要播放的視頻圖像輸送到surfaceView
    player.setDisplay(holder);
    try {
    player.setDataSource(videoPath);
    // player.prepare();
    player.prepareAsync();
    } catch (IOException e) {
    e.printStackTrace();
    }
    //首先取得video的寬和高
    vWidth = player.getVideoWidth();
    vHeight = player.getVideoHeight();
    if(vWidth > currDisplay.getWidth() || vHeight > currDisplay.getHeight()){
    //如果video的寬或者高超出了當前屏幕的大小,則要進行縮放
    float wRatio = (float)vWidth/(float)currDisplay.getWidth();
    float hRatio = (float)vHeight/(float)currDisplay.getHeight();
    //選擇大的一個進行縮放
    float ratio = Math.max(wRatio, hRatio);
    vWidth = (int)Math.ceil((float)vWidth/ratio);
    vHeight = (int)Math.ceil((float)vHeight/ratio);
    //設置surfaceView的布局參數
    surfaceView.setLayoutParams(new LinearLayout.LayoutParams(vWidth, vHeight - 100));
    //然后開始播放視頻
    // player.start();
    }
    // player.start();

    }

    /**
    *
    * 設置播放監聽
    *
    * @version 1.0
    * @createTime 2016-1-20,下午3:04:38
    * @updateTime 2016-1-20,下午3:04:38
    * @createAuthor lzb
    * @updateAuthor
    * @updateInfo (此處輸入修改內容,若無修改可不寫.)
    */
    @SuppressLint("NewApi") @SuppressWarnings("deprecation")
    private void setPlayerListener() {
    //設置播放完監聽
    player.setOnCompletionListener(new OnCompletionListener() {
    /** 當MediaPlayer播放完成后觸發 */
    @Override
    public void onCompletion(MediaPlayer mp) {
    Toast.makeText(MediaPlayerSurfaceActivity.this, "播放完成", Toast.LENGTH_SHORT).show();
    }
    });
    //播放錯誤監聽
    player.setOnErrorListener(new OnErrorListener() {
    @TargetApi(Build.VERSION_CODES.CUPCAKE) @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
    switch (what) {
    //播放器壞了
    case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
    Toast.makeText(MediaPlayerSurfaceActivity.this, "播放器壞了", Toast.LENGTH_SHORT).show();
    break;
    //未知錯誤
    case MediaPlayer.MEDIA_ERROR_UNKNOWN:
    Toast.makeText(MediaPlayerSurfaceActivity.this, "未知錯誤", Toast.LENGTH_SHORT).show();
    break;
    default:
    break;
    }
    return false;
    }
    });
    //詳細監聽
    player.setOnInfoListener(new OnInfoListener() {
    /** 當一些特定信息出現或者警告時觸發 */
    @Override
    public boolean onInfo(MediaPlayer mp, int what, int extra) {
    switch(what){
    case MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING: //視頻交叉紊亂
    Toast.makeText(MediaPlayerSurfaceActivity.this, "視頻交叉紊亂", Toast.LENGTH_SHORT).show();
    break;
    case MediaPlayer.MEDIA_INFO_METADATA_UPDATE: //更新
    Toast.makeText(MediaPlayerSurfaceActivity.this, "更新", Toast.LENGTH_SHORT).show();
    break;
    case MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING: //無法解碼
    Toast.makeText(MediaPlayerSurfaceActivity.this, "無法解碼", Toast.LENGTH_SHORT).show();
    break;
    case MediaPlayer.MEDIA_INFO_NOT_SEEKABLE: //不能搜索
    Toast.makeText(MediaPlayerSurfaceActivity.this, "不能搜索", Toast.LENGTH_SHORT).show();
    break;
    }
    return false;
    }
    });

    //準備監聽 如果是使用異步加載的方式必須要設置該監聽,在onPrepared方法中調用start()方法
    player.setOnPreparedListener(new OnPreparedListener() {
    /** 當prepare完成后,該方法觸發,在這里我們播放視頻*/
    @Override
    public void onPrepared(MediaPlayer mp) {
    player.start();
    }
    });

    player.setOnSeekCompleteListener(new OnSeekCompleteListener() {
    /** seek操作完成時觸發 */
    @Override
    public void onSeekComplete(MediaPlayer mp) {

    }
    });
    /** 當video大小改變時觸發 這個方法在設置player的source后至少觸發一次 */
    player.setOnVideoSizeChangedListener(new OnVideoSizeChangedListener() {
    @Override
    public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {

    }
    });
    }

    /**
    * 啟動其他Activity或者對話框,暫停播放
    */
    @Override
    protected void onPause() {
    if (player != null){
    if (player.isPlaying()){
    player.stop();
    }
    }
    super.onPause();
    }

    @Override
    protected void onDestroy() {
    if (player != null){
    if (player.isPlaying()){
    player.stop();
    }
    player.release();
    }
    super.onDestroy();
    }

    @Override
    public void onClick(View v) {
    if (player.isPlaying()){
    player.stop();
    player.reset();
    play();
    }else {
    play();
    }
    }
    }
    其XML文件如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/main_rLayout"
    tools:context="com.lzb.video.MediaPlayerSurfaceActivity" >
    <SurfaceView
    android:id="@+id/surface_surface_view"
    android:layout_weight="1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
    <Button
    android:id="@+id/btn_start"
    android:text="重播"
    android:textColor="@android:color/white"
    android:background="@android:color/transparent"
    android:layout_centerHorizontal="true"
    android:layout_alignParentBottom="true"
    android:layout_marginBottom="30dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
    </RelativeLayout> 完整示例代碼

    四 效果圖



    總結

    以上是生活随笔為你收集整理的MediaRecorder之视频录制的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。