怎么弄屏幕錄制,Android使用MediaRecorder和Camera實現視頻錄制及播放功能整理

 2023-11-19 阅读 25 评论 0

摘要:轉載請注明出處:http://blog.csdn.net/woshizisezise/article/details/51878566 這兩天產品經理向我丟來一個新需求,需要在項目里添加一個視頻錄制的功能,正好是我沒做過的,于是研究了一番。在網上搜索了一些案例,但是都是不完整的,

轉載請注明出處:http://blog.csdn.net/woshizisezise/article/details/51878566

這兩天產品經理向我丟來一個新需求,需要在項目里添加一個視頻錄制的功能,正好是我沒做過的,于是研究了一番。在網上搜索了一些案例,但是都是不完整的,要不就是分辨率有問題的,要不就是聲音有問題的,要不就是實現了視頻錄制但是沒有播放功能的,所以我就想自己做一個,整合一下,來個較完整版的。

怎么弄屏幕錄制。PM的要求如下:實現錄像功能,錄完后可以預覽播放,視頻清晰并且大小不能大,支持刪除視頻功能……

好吧,開始干活了,首先來分析一下原理,現在安卓手機實現錄像的功能無非就兩種方式,第一是實用系統自帶的照相機/攝像機進行錄制,然后通過回調的方式將源返回,例如:

Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
//設置視頻錄制的最長時間
intent.putExtra (MediaStore.EXTRA_DURATION_LIMIT,30);
//設置視頻錄制的畫質
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
startActivityForResult (intent, VIDEO_WITH_CAMERA);

回調如下所示:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {try{if (resultCode == Activity.RESULT_OK && requestCode == VIDEO_WITH_CAMERA){Uri uri = data.getData();Log.e(TAG, "onActivityResult: " + uri.toString());}}catch (Exception e){e.printStackTrace();}
}

錄制新宏?這種方式是直接調用手機的攝像功能,所以就和你打開相機攝像是一模一樣的,但是這樣就產生問題了,現在的手機攝像頭像素越來越高,拍攝效果越來越清晰,很多都達到了720p甚至是1080p,這樣短暫的10s時長內存占用就達到了20M,顯然這樣是不可能的,并且intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);這行代碼,在設置EXTRA_VIDEO_QUALITY為1的情況下,視頻格式保存為mp4,然而無論怎么修改EXTRA_VIDEO_QUALITY為0.幾的時候,視頻保存格式為3gp,并且視頻錄像效果很差,所以后來我放棄了這種方式而改用第二種方式。

第二種方法就是利用安卓自帶的MediaRecorder來錄制視頻,并制定視頻保存路徑,并且可以通過Camera來播放錄制的視頻,下面我們來具體講解一下這種實現的方式。

  • 首先來看一下效果圖吧,很粗糙的

這里寫圖片描述

錄制功能?布局很簡單,一個開始錄制/停止錄制按鈕,一個播放按鈕,一個錄制時間計數器,布局文件代碼如下:

  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><SurfaceViewandroid:id="@+id/surfaceview"android:layout_width="match_parent"android:layout_marginBottom="60dp"android:layout_height="match_parent" /><ImageViewandroid:id="@+id/imageview"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_marginBottom="60dp"android:src="@drawable/ic_launcher"/><Buttonandroid:id="@+id/btnStartStop"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:layout_alignParentBottom="true"android:text="Start"/><Buttonandroid:id="@+id/btnPlayVideo"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_toRightOf="@id/btnStartStop"android:text="Play"android:layout_marginLeft="20dp"/><TextViewandroid:id="@+id/text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="25sp"android:text="0"android:layout_alignParentBottom="true"android:layout_marginBottom="12dp"android:layout_marginLeft="20dp"/></RelativeLayout>

下面是主要的activity界面代碼,控制MediaRecorder工作的邏輯,代碼如下:

  • MainActivity.java
package com.example.mediarecorder;import android.app.Activity;
import android.hardware.Camera;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Environment;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;import java.io.File;
import java.util.Calendar;public class MainActivity extends Activity implements SurfaceHolder.Callback {private static final String TAG = "MainActivity";private SurfaceView mSurfaceview;private Button mBtnStartStop;private Button mBtnPlay;private boolean mStartedFlg = false;//是否正在錄像private boolean mIsPlay = false;//是否正在播放錄像private MediaRecorder mRecorder;private SurfaceHolder mSurfaceHolder;private ImageView mImageView;private Camera camera;private MediaPlayer mediaPlayer;private String path;private TextView textView;private int text = 0;private android.os.Handler handler = new android.os.Handler();private Runnable runnable = new Runnable() {@Overridepublic void run() {text++;textView.setText(text+"");handler.postDelayed(this,1000);}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_main);mSurfaceview = (SurfaceView) findViewById(R.id.surfaceview);mImageView = (ImageView) findViewById(R.id.imageview);mBtnStartStop = (Button) findViewById(R.id.btnStartStop);mBtnPlay = (Button) findViewById(R.id.btnPlayVideo);textView = (TextView)findViewById(R.id.text);mBtnStartStop.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {if (mIsPlay) {if (mediaPlayer != null) {mIsPlay = false;mediaPlayer.stop();mediaPlayer.reset();mediaPlayer.release();mediaPlayer = null;}}if (!mStartedFlg) {handler.postDelayed(runnable,1000);mImageView.setVisibility(View.GONE);if (mRecorder == null) {mRecorder = new MediaRecorder();}camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);if (camera != null) {camera.setDisplayOrientation(90);camera.unlock();mRecorder.setCamera(camera);}try {// 這兩項需要放在setOutputFormat之前
                        mRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);// Set output file format
                        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);// 這兩項需要放在setOutputFormat之后
                        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);mRecorder.setVideoSize(640, 480);mRecorder.setVideoFrameRate(30);mRecorder.setVideoEncodingBitRate(3 * 1024 * 1024);mRecorder.setOrientationHint(90);//設置記錄會話的最大持續時間(毫秒)mRecorder.setMaxDuration(30 * 1000);mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());path = getSDPath();if (path != null) {File dir = new File(path + "/recordtest");if (!dir.exists()) {dir.mkdir();}path = dir + "/" + getDate() + ".mp4";mRecorder.setOutputFile(path);mRecorder.prepare();mRecorder.start();mStartedFlg = true;mBtnStartStop.setText("Stop");}} catch (Exception e) {e.printStackTrace();}} else {//stopif (mStartedFlg) {try {handler.removeCallbacks(runnable);mRecorder.stop();mRecorder.reset();mRecorder.release();mRecorder = null;mBtnStartStop.setText("Start");if (camera != null) {camera.release();camera = null;}} catch (Exception e) {e.printStackTrace();}}mStartedFlg = false;}}});mBtnPlay.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {mIsPlay = true;mImageView.setVisibility(View.GONE);if (mediaPlayer == null) {mediaPlayer = new MediaPlayer();}mediaPlayer.reset();Uri uri = Uri.parse(path);mediaPlayer = MediaPlayer.create(MainActivity.this, uri);mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mediaPlayer.setDisplay(mSurfaceHolder);try{mediaPlayer.prepare();}catch (Exception e){e.printStackTrace();}mediaPlayer.start();}});SurfaceHolder holder = mSurfaceview.getHolder();holder.addCallback(this);// setType必須設置,要不出錯.
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);}@Overrideprotected void onResume() {super.onResume();if (!mStartedFlg) {mImageView.setVisibility(View.VISIBLE);}}/*** 獲取系統時間** @return*/public static String getDate() {Calendar ca = Calendar.getInstance();int year = ca.get(Calendar.YEAR);           // 獲取年份int month = ca.get(Calendar.MONTH);         // 獲取月份int day = ca.get(Calendar.DATE);            // 獲取日int minute = ca.get(Calendar.MINUTE);       //int hour = ca.get(Calendar.HOUR);           // 小時int second = ca.get(Calendar.SECOND);       //
String date = "" + year + (month + 1) + day + hour + minute + second;Log.d(TAG, "date:" + date);return date;}/*** 獲取SD path** @return*/public String getSDPath() {File sdDir = null;boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED); // 判斷sd卡是否存在if (sdCardExist) {sdDir = Environment.getExternalStorageDirectory();// 獲取跟目錄return sdDir.toString();}return null;}@Overridepublic void surfaceCreated(SurfaceHolder surfaceHolder) {mSurfaceHolder = surfaceHolder;}@Overridepublic void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {// 將holder,這個holder為開始在onCreate里面取得的holder,將它賦給mSurfaceHoldermSurfaceHolder = surfaceHolder;}@Overridepublic void surfaceDestroyed(SurfaceHolder surfaceHolder) {mSurfaceview = null;mSurfaceHolder = null;handler.removeCallbacks(runnable);if (mRecorder != null) {mRecorder.release(); mRecorder = null;Log.d(TAG, "surfaceDestroyed release mRecorder");}if (camera != null) {camera.release();camera = null;}if (mediaPlayer != null){mediaPlayer.release();mediaPlayer = null;}}
}

同時,別忘了在AndroidManifest.xml文件中添加相應的權限:

<!--硬件支持-->
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-permission android:name="android.permission.CAMERA" >
</uses-permission>
<uses-permission android:name="android.permission.RECORD_AUDIO" >
</uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
</uses-permission>

代碼里我覺得有幾個地方需要注意一下:

開始錄制視頻?1.視頻質量的問題

mRecorder.setVideoSize(640, 480); 
mRecorder.setVideoFrameRate(30); 
mRecorder.setVideoEncodingBitRate(3 * 1024 * 1024);
  • mRecorder.setVideoSize(640, 480);

這是設置視頻的分辨率,在手機上看不出什么區別,可能在大屏幕上投影或者電腦上觀看的時候就有差距了。

  • mRecorder.setVideoFrameRate(30);

這是設置視頻錄制的幀率,即1秒鐘30幀。

  • mRecorder.setVideoEncodingBitRate(3 * 1024 * 1024);

宏的錄制和應用。這個屬性很重要,這個也直接影響到視頻錄制的大小,這個設置的越大,視頻越清晰,我做了簡單的比較,可以參考下表:?
這里寫圖片描述

所以大家可以根據自己的實際情況具體選擇設置了。

2.視頻錄制時預覽界面角度問題

camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK); 
if (camera != null) { 
camera.setDisplayOrientation(90); 
camera.unlock(); 
mRecorder.setCamera(camera); 
}

這個是在開發過程中實際遇到的問題,我網上找了一下,剛開始以為是哪個參數沒有設置導致的,但是看網友也有類似的反應,明明是豎屏錄制的,但是界面確實橫屏,在給mediarecorder設置mRecorder.setOrientationHint(90);也無濟于事,后來,必須得設置Camera的預覽角度才行,也就是這行代碼:camera.setDisplayOrientation(90);這樣再進行測試,攝像機的預覽角度終于是豎屏的了,并且保存的文件播放時也是豎屏的。


最后,一個簡單的視頻錄制及播放的案例寫完了,測試沒有其他的問題,完成的功能也比較完整,如有不當之處,歡迎大家留言。

案例下載

轉載于:https://www.cnblogs.com/zhujiabin/p/9035883.html

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/179526.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息