Android視訊錄製、播放的兩種方式
1、通過Intent的方式:Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
2、使用Camera的API,呼叫Media的MediaRecorder。
Intent的方式
注意:這裡播放camera錄製的視訊使用VideoView,不使用MediaPlayer和SurfaceView的結合。用幀佈局Framelayout佈局,VideoView和ImageView,播放時隱藏視訊縮圖,暫停時或初始化時顯示視訊縮圖。
因為VideoView沒有設定監聽播放和暫停狀態的事件,所以我自定義一個CustomVideoView繼承了
使用相機intent獲取視訊是使用最少程式碼使得你的應用獲取視訊的捷徑.一個視訊獲取intent可以包含以下額外資訊:
MediaStore.EXTRA_OUTPUT-此設定需要一個儲存視訊的路徑和檔名的Uri.此設定是可選的但是強列推薦的.如果你不指定此值,相機應用就把請求到的影象以預設的檔名儲存到預設的資料夾下,這些資訊儲存在返回的intent的Intent.getData()欄位中.
MediaStore.EXTRA_VIDEO_QUALITY- 此值在最低質量最小檔案尺寸時是0,在最高質量最大檔案尺寸時是1
MediaStore.EXTRA_DURATION_LIMIT- 此值設定獲取視訊的長度,以秒為單位.
MediaStore.EXTRA_SIZE_LIMIT- 此值設定獲取視訊檔案的大小,以位元組為單位.
XML佈局檢視:
public class MainActivity extends AppCompatActivity {
private static int REQUST_VIDEO = 1;
private Button btn;
private Button btn_start;
private FrameLayout fl;
private CustomVideoView video;
private ImageView iv;
private String sdCard;
private String videoPath;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init(){
btn = ((Button) findViewById(R.id.btn_recoder));
btn_start = ((Button) findViewById(R.id.btn_start));
fl = ((FrameLayout) findViewById(R.id.fl_video));
video = ((CustomVideoView) findViewById(R.id.video));
iv = ((ImageView) findViewById(R.id.iv));
sdCard = Environment.getExternalStorageDirectory().getPath();
String currenTimeMillis = new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date(System.currentTimeMillis()));
videoPath = sdCard + "/" + "0000.mp4";
MediaController controller = new MediaController(this);
video.setMediaController(controller);
if (video.isPlaying()){
iv.setVisibility(View.INVISIBLE);
}
video.setPlayPauseListener(new CustomVideoView.PlayPauseListener() {
@Override
public void onPlay() {
Toast.makeText(MainActivity.this,"播放",Toast.LENGTH_SHORT).show();
iv.setVisibility(View.INVISIBLE);
}
@Override
public void onPause() {
Toast.makeText(MainActivity.this,"暫停",Toast.LENGTH_SHORT).show();
iv.setVisibility(View.VISIBLE);
}
});
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,videoPath);
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY,1);
startActivityForResult(intent,REQUST_VIDEO);
}
});
}
private Bitmap getVideoBitmap(String videoPath){
MediaMetadataRetriever retriever = null;
try {
retriever = new MediaMetadataRetriever();
retriever.setDataSource(videoPath);
Bitmap bitmap = retriever.getFrameAtTime();
return bitmap;
}finally {
retriever.release();
}
}
private Bitmap getVideoBitmap2(Uri uri){
MediaMetadataRetriever retriever = null;
try {
retriever = new MediaMetadataRetriever();
retriever.setDataSource(this,uri);
Bitmap bitmap = retriever.getFrameAtTime();
return bitmap;
}finally {
retriever.release();
}
}
public void start(View view){
iv.setVisibility(View.INVISIBLE);
video.start();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK){
if (requestCode == REQUST_VIDEO){
fl.setVisibility(View.VISIBLE);
btn_start.setVisibility(View.VISIBLE);
Uri uri = data.getData();
video.setVideoURI(uri);
// Bitmap bitmap = getVideoBitmap(videoPath);
Bitmap bitmap = getVideoBitmap2(uri);
iv.setImageBitmap(bitmap);
}
}
}
}
//自定義VideoView
public class CustomVideoView extends VideoView {
private PlayPauseListener listener;
public CustomVideoView(Context context) {
super(context);
}
public CustomVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setPlayPauseListener(PlayPauseListener listener){
this.listener = listener;
}
@Override
public void pause() {
super.pause();
if (listener!=null){
listener.onPause();
}
}
@Override
public void start() {
super.start();
if (listener!=null){
listener.onPlay();
}
}
interface PlayPauseListener{
void onPlay();
void onPause();
}
}
最終Intent方式的效果圖:
提取碼:yydc
許可權:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
例子中先用mediarecorder錄製儲存一個視訊然後播放看看效果,點選“跳轉”可以調到第二個Main2Activity中,用VideoView播放剛才錄製的視訊,Main2Activity主要測試如何播放在本地手機的視訊。
XML佈局:(MainActivity)
程式碼:
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback{
private static final String TAG = "MainActivity";
private SurfaceView mSurfaceview;
private Button btn_start_or_stop;
private Button btn_play;
private Button btn_turnto;
private boolean isRecording = false;//是否正在錄影
private boolean isPlay = false;//是否正在播放錄影
private MediaRecorder mRecorder;
private SurfaceHolder mSurfaceHolder;
private ImageView mImageView;
private Camera camera;
private MediaPlayer mediaPlayer;
private String path;
private TextView time;
private int text = 0;
private Handler handler = new Handler();
private Runnable runnable = new Runnable() {
@Override
public void run() {
text++;
time.setText("錄製"+text+"秒");
handler.postDelayed(this,1000);
}
};
@Override
protected 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);
btn_start_or_stop = (Button) findViewById(R.id.btn_start_or_stop);
btn_turnto = (Button) findViewById(R.id.btn_turnto);
btn_play = (Button) findViewById(R.id.btn_play);
time = (TextView)findViewById(R.id.time);
btn_turnto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (path != null){
File file = new File(path);
if(file.exists()){
Intent intent = new Intent(MainActivity.this,Main2Activity.class);
intent.putExtra("path",path);
startActivity(intent);
}else {
Toast.makeText(MainActivity.this,"視訊檔案不存在",Toast.LENGTH_SHORT).show();
}
}else {
Toast.makeText(MainActivity.this,"檔案路徑不存在",Toast.LENGTH_SHORT).show();
}
}
});
btn_start_or_stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isPlay){
if (mediaPlayer != null){
isPlay = false;
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer = null;
}
}
if (!isRecording){
handler.postDelayed(runnable,1000);
mImageView.setVisibility(View.GONE);
if (mRecorder == null){
mRecorder = new MediaRecorder();// 建立mediarecorder物件
text = 0;//當點選停止之後,每一次進到這裡都要重置錄製的時間數
}
camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
if (camera != null){
camera.setDisplayOrientation(90);//攝像圖旋轉90度
camera.unlock();
mRecorder.setCamera(camera);// 設定錄製視訊源為Camera(相機)
}
try{
mRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); // 這兩項需要放在setOutputFormat之前
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // 這兩項需要放在setOutputFormat之前
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);//設定錄製視訊的輸出格式
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);//設定音訊編碼格式
mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);//設定視訊編碼格式// 設定錄製的視訊編碼h263 h264
mRecorder.setVideoSize(640,480);//設定視訊的解析度,必須放在設定編碼和格式的後面,否則報錯
mRecorder.setVideoFrameRate(30);//這是設定視訊錄製的幀率,即1秒鐘30幀。。必須放在設定編碼和格式的後面,否則報錯
mRecorder.setVideoEncodingBitRate(4 * 1024 * 1024);//這個屬性很重要,這個也直接影響到視訊錄製的大小,這個設定的越大,視訊越清晰
mRecorder.setOrientationHint(90);//視訊旋轉90度
mRecorder.setMaxDuration(30 * 1000);//設定錄製最長時間為30秒
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();// 開始錄製
isRecording = true;
btn_start_or_stop.setText("停止");
}
}catch (Exception e){
e.printStackTrace();
}
}else {
if (isRecording){
try {
handler.removeCallbacks(runnable);
mRecorder.stop();// 停止錄製
mRecorder.reset();// 恢復到未初始化的狀態
mRecorder.release();// 釋放資源
mRecorder = null;
btn_start_or_stop.setText("開始");
if (camera != null){
camera.release();
camera = null;
}
}catch (Exception e){
e.printStackTrace();
}
isRecording = false;
}
}
}
});
btn_play.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
isPlay = true;
mImageView.setVisibility(View.GONE);
if (mediaPlayer == null){
mediaPlayer = new MediaPlayer();
}
mediaPlayer.reset();
Uri uri = Uri.parse(path);
if (uri == null){
Toast.makeText(MainActivity.this,"請先錄製視訊",Toast.LENGTH_SHORT).show();
return;
}
mediaPlayer = MediaPlayer.create(MainActivity.this,uri);//使用mediaplayer播放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);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
protected void onResume() {
super.onResume();
if (!isRecording){
mImageView.setVisibility(View.VISIBLE);
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mSurfaceHolder = holder;
}
/**
* 獲取系統時間
*
* @return
*/
private static String getDate(){
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DATE);
int minute = calendar.get(Calendar.MINUTE);
int hour = calendar.get(Calendar.HOUR);
int second = calendar.get(Calendar.SECOND);
String date = "" + year + (month + 1) + day + hour + minute + second;
return date;
}
/**
* 獲取SD path
*
* @return
*/
public String getSdPath(){
File sdDir = null;
boolean sdCardExist = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);//判斷sd卡是否存在
if (sdCardExist){
sdDir = Environment.getExternalStorageDirectory();//獲取根目錄
return sdDir.toString();
}
return null;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// 將holder,這個holder為開始在onCreate裡面取得的holder,將它賦給mSurfaceHolder
mSurfaceHolder = holder;
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// surfaceDestroyed的時候同時物件設定為null
mSurfaceview = null;
mSurfaceHolder = null;
handler.removeCallbacks(runnable);
if (mRecorder != null) {
mRecorder.release();
mRecorder = null;
}
if (camera != null) {
camera.release();
camera = null;
}
if (mediaPlayer != null){
mediaPlayer.release();
mediaPlayer = null;
}
}
}
效果圖:
MAin2Activity
XML佈局(MAin2Activity)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="project.wgc.mymediarecordertest01.Main2Activity">
<VideoView
android:id="@+id/video"
android:layout_width="300dp"
android:layout_height="400dp"
/>
<Button
android:id="@+id/btn_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="播放"/>
</LinearLayout>
Main2Activity程式碼:
public class Main2Activity extends AppCompatActivity {
private Button play;
private VideoView video;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
video = ((VideoView) findViewById(R.id.video));
Intent intent = getIntent();
String path = intent.getStringExtra("path");
//Uri uri = Uri.parse(path);//第一種。把路徑轉換為uri,然後給videoview設定,
// video.setVideoURI(uri);
video.setVideoPath(path);//第二種,直接把本地視訊的路徑設定給VideoView也可以.
play = ((Button) findViewById(R.id.btn_play));
play.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
video.start();
}
});
}
}
效果圖:
提取碼:z3ul