想到视频录制,肯定又是运用MediaRecorder,这个类实在是方便,但是好用的东西一定要慎重,毕竟没有那么便宜的事,但是基本满足用户要求,但是对于比较苛刻的项目而言,那就很尴尬了,比如:拍摄的视频不聚焦,拍摄像素低,甚至在有些手机上面根本无法进行拍摄录制,这就导致无法很好的使用了。不过我还是提供出工具类。希望高手能修改,并完美运行。
importandroid.annotation.SuppressLint;
importandroid.app.AlertDialog;
importandroid.app.ProgressDialog;
importandroid.content.Context;
importandroid.content.DialogInterface;
importandroid.graphics.Bitmap;
importandroid.graphics.PixelFormat;
importandroid.hardware.Camera;
importandroid.media.MediaRecorder;
importandroid.media.MediaScannerConnection;
importandroid.net.Uri;
importandroid.os.Bundle;
importandroid.os.Environment;
importandroid.os.PowerManager;
importandroid.os.SystemClock;
importandroid.text.TextUtils;
importandroid.util.Log;
importandroid.view.SurfaceHolder;
importandroid.view.View;
importandroid.view.Window;
importandroid.view.WindowManager;
importandroid.widget.Button;
importandroid.widget.Chronometer;
importandroid.widget.ImageView;
importandroid.widget.RelativeLayout;
importandroid.widget.Toast;
importandroid.widget.VideoView;
importcom.lvgou.distribution.R;
importcom.lvgou.distribution.utils.PathUtil;
importcom.lvgou.distribution.utils.Utils;
importjava.io.BufferedOutputStream;
importjava.io.File;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.util.Collections;
importjava.util.List;
/**
* Created by Administrator on 2017/6/14.
*/
publicclassMyRecorderVideoActivityextendsBaseActivityimplementsView.OnClickListener,SurfaceHolder.Callback,MediaRecorder.OnInfoListener,MediaRecorder.OnErrorListener{
privatestaticfinalStringTAG="RecorderVideoActivity";
privatefinalstaticStringCLASS_LABEL="RecordActivity";
privatePowerManager.WakeLockmWakeLock;
privateImageViewbtnStart;//开始拍摄
privateImageViewbtnStop;//停止拍摄
privateMediaRecordermediaRecorder;
privateVideoViewmVideoView;// 显示视频
StringlocalPath="";// 路径保存录像
privateCameramCamera;
privateintpreviewWidth=480;
privateintpreviewHeight=480;
privateChronometerchronometer;//时间
privateintfrontCamera=0;// 0是相机,1是前置摄像头
privateButtonbtn_switch;//切换摄像头
Camera.ParameterscameraParameters=null;
privateSurfaceHoldermSurfaceHolder;
intdefaultVideoFrameRate=-1;
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);// 无标题
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);// 全屏幕
// 半透明模式,用于表面的观点
getWindow().setFormat(PixelFormat.TRANSLUCENT);
setContentView(R.layout.my_recorder_activity);
PowerManagerpm=(PowerManager)getSystemService(Context.POWER_SERVICE);
mWakeLock=pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
CLASS_LABEL);
mWakeLock.acquire();
initViews();
}
privateRelativeLayoutrl_back;
// 初始化控件
privatevoidinitViews(){
rl_back=(RelativeLayout)findViewById(R.id.rl_back);
rl_back.setOnClickListener(this);
btn_switch=(Button)findViewById(R.id.switch_btn);//切换摄像头
btn_switch.setOnClickListener(this);
btn_switch.setVisibility(View.VISIBLE);
mVideoView=(VideoView)findViewById(R.id.mVideoView);//视频控件显示视频
btnStart=(ImageView)findViewById(R.id.recorder_start);//开始拍摄
btnStop=(ImageView)findViewById(R.id.recorder_stop);//停止拍摄
btnStart.setOnClickListener(this);
btnStop.setOnClickListener(this);
mSurfaceHolder=mVideoView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
chronometer=(Chronometer)findViewById(R.id.chronometer);//时间
}
publicvoidback(Viewview){
releaseRecorder();
releaseCamera();
finish();
}
@Override
protectedvoidonResume(){
super.onResume();
if(mWakeLock==null){
// 保持唤醒
PowerManagerpm=(PowerManager)getSystemService(Context.POWER_SERVICE);
mWakeLock=pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
CLASS_LABEL);
mWakeLock.acquire();
}
}
// 初始化照相机
@SuppressLint("NewApi")
privatebooleaninitCamera(){
try{
if(frontCamera==0){
mCamera=Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
}else{
mCamera=Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
}
Camera.ParameterscamParams=mCamera.getParameters();
mCamera.lock();
mSurfaceHolder=mVideoView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mCamera.setDisplayOrientation(90);
}catch(RuntimeExceptionex){
returnfalse;
}
returntrue;
}
privatevoidhandleSurfaceChanged(){
if(mCamera==null){
finish();
return;
}
booleanhasSupportRate=false;
ListsupportedPreviewFrameRates=mCamera.getParameters()
.getSupportedPreviewFrameRates();
if(supportedPreviewFrameRates!=null
&&supportedPreviewFrameRates.size()>0){
Collections.sort(supportedPreviewFrameRates);
for(inti=0;i
intsupportRate=supportedPreviewFrameRates.get(i);
if(supportRate==15){
hasSupportRate=true;
}
}
if(hasSupportRate){
defaultVideoFrameRate=15;
}else{
defaultVideoFrameRate=supportedPreviewFrameRates.get(0);
}
}
// 得到所有相机提供的决议
ListresolutionList=Utils.getResolutionList(mCamera);
if(resolutionList!=null&&resolutionList.size()>0){
Collections.sort(resolutionList,newUtils.ResolutionComparator());
Camera.SizepreviewSize=null;
booleanhasSize=false;
// 如果相机支持使用60 * 480
for(inti=0;i
Camera.Sizesize=resolutionList.get(i);
if(size!=null&&size.width==640&&size.height==480){
previewSize=size;
previewWidth=previewSize.width;
previewHeight=previewSize.height;
hasSize=true;
break;
}
}
// 使用中等分辨率如果相机不支持上述决议
if(!hasSize){
intmediumResolution=resolutionList.size()/2;
if(mediumResolution>=resolutionList.size())
mediumResolution=resolutionList.size()-1;
previewSize=resolutionList.get(mediumResolution);
previewWidth=previewSize.width;
previewHeight=previewSize.height;
}
}
}
@Override
protectedvoidonPause(){
super.onPause();
if(mWakeLock!=null){
mWakeLock.release();
mWakeLock=null;
}
}
@Override
publicvoidonClick(Viewview){
inti=view.getId();
if(i==R.id.switch_btn){
//切换摄像头
switchCamera();
}elseif(i==R.id.recorder_start){
// 开始录制
if(!startRecording())
return;
Toast.makeText(this,R.string.The_video_to_start,Toast.LENGTH_SHORT).show();
btn_switch.setVisibility(View.INVISIBLE);
btnStart.setVisibility(View.INVISIBLE);
btnStart.setEnabled(false);
btnStop.setVisibility(View.VISIBLE);
chronometer.setBase(SystemClock.elapsedRealtime());
chronometer.start();
}elseif(i==R.id.recorder_stop){
// 停止录制
btnStop.setEnabled(false);
stopRecording();
btn_switch.setVisibility(View.VISIBLE);
chronometer.stop();
btnStart.setVisibility(View.VISIBLE);
btnStop.setVisibility(View.INVISIBLE);
//弹出是否发送对话框
newAlertDialog.Builder(this)
.setMessage("是否使用该视频!")
.setPositiveButton(R.string.ok,
newDialogInterface.OnClickListener(){
@Override
publicvoidonClick(DialogInterfacedialog,intwhich){
dialog.dismiss();
//发送视频
sendVideo(null);
}
})
.setNegativeButton(R.string.cancel,
newDialogInterface.OnClickListener(){
@Override
publicvoidonClick(DialogInterfacedialog,intwhich){
if(localPath!=null){
Filefile=newFile(localPath);
if(file.exists())
file.delete();
}
finish();
}
}).setCancelable(false).show();
}elseif(i==R.id.rl_back){
if(localPath!=null){
Filefile=newFile(localPath);
if(file.exists())
file.delete();
}
finish();
}
}
@Override
publicvoidsurfaceChanged(SurfaceHolderholder,intformat,intwidth,
intheight){
mSurfaceHolder=holder;
}
@Override
publicvoidsurfaceCreated(SurfaceHolderholder){
if(mCamera==null){
if(!initCamera()){
showFailDialog();
return;
}
}
try{
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
handleSurfaceChanged();
}catch(Exceptione1){
showFailDialog();
}
}
@Override
publicvoidsurfaceDestroyed(SurfaceHolderarg0){
}
publicbooleanstartRecording(){
if(mediaRecorder==null){
if(!initRecorder())
returnfalse;
}
mediaRecorder.setOnInfoListener(this);
mediaRecorder.setOnErrorListener(this);
mediaRecorder.start();
returntrue;
}
publicbooleanisSdcardExist(){
returnandroid.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
}
@SuppressLint("NewApi")
privatebooleaninitRecorder(){
if(!isSdcardExist()){
showNoSDCardDialog();
returnfalse;
}
if(mCamera==null){
if(!initCamera()){
showFailDialog();
returnfalse;
}
}
mVideoView.setVisibility(View.VISIBLE);
mCamera.stopPreview();
mediaRecorder=newMediaRecorder();
mCamera.unlock();
mediaRecorder.setCamera(mCamera);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
if(frontCamera==1){
mediaRecorder.setOrientationHint(270);
}else{
mediaRecorder.setOrientationHint(90);
}
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
// 设置分辨率,应设置在格式和编码器
// mediaRecorder.setVideoSize(previewWidth, previewHeight);
mediaRecorder.setVideoEncodingBitRate(384*1024);
// 设置帧率,应设置在格式和编码器
if(defaultVideoFrameRate!=-1){
mediaRecorder.setVideoFrameRate(defaultVideoFrameRate);
}
// 设置视频文件的路径
localPath=PathUtil.getInstance().getVideoPath()+"/"
+System.currentTimeMillis()+".mp4";
mediaRecorder.setOutputFile(localPath);
mediaRecorder.setMaxDuration(30000);
mediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
Log.i("fdsafasdfsadfasd","----------initRecorder-------"+localPath);
try{
mediaRecorder.prepare();
}catch(IllegalStateExceptione){
e.printStackTrace();
returnfalse;
}catch(IOExceptione){
e.printStackTrace();
returnfalse;
}
returntrue;
}
// 停止录制
publicvoidstopRecording(){
if(mediaRecorder!=null){
mediaRecorder.setOnErrorListener(null);
mediaRecorder.setOnInfoListener(null);
try{
mediaRecorder.stop();
}catch(Exceptione){
}
}
releaseRecorder();
if(mCamera!=null){
mCamera.stopPreview();
releaseCamera();
}
}
privatevoidreleaseRecorder(){
if(mediaRecorder!=null){
mediaRecorder.release();
mediaRecorder=null;
}
}
protectedvoidreleaseCamera(){
try{
if(mCamera!=null){
mCamera.stopPreview();
mCamera.release();
mCamera=null;
}
}catch(Exceptione){
}
}
// 切换摄像头
@SuppressLint("NewApi")
publicvoidswitchCamera(){
if(mCamera==null){
return;
}
if(Camera.getNumberOfCameras()>=2){
btn_switch.setEnabled(false);
if(mCamera!=null){
mCamera.stopPreview();
mCamera.release();
mCamera=null;
}
switch(frontCamera){
case0:
mCamera=Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
frontCamera=1;
break;
case1:
mCamera=Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
frontCamera=0;
break;
}
try{
mCamera.lock();
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mVideoView.getHolder());
mCamera.startPreview();
}catch(IOExceptione){
mCamera.release();
mCamera=null;
}
btn_switch.setEnabled(true);
}
}
MediaScannerConnectionmsc=null;
ProgressDialogprogressDialog=null;
publicvoidsendVideo(Viewview){
if(TextUtils.isEmpty(localPath)){
return;
}
if(msc==null)
msc=newMediaScannerConnection(this,
newMediaScannerConnection.MediaScannerConnectionClient(){
@Override
publicvoidonScanCompleted(Stringpath,Uriuri){
msc.disconnect();
progressDialog.dismiss();
setResult(RESULT_OK,getIntent().putExtra("uri",uri));
finish();
/* String[] proj = {MediaStore.Images.Media.DATA};
Cursor actualimagecursor = managedQuery(uri, proj, null, null, null);
int actual_image_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
actualimagecursor.moveToFirst();
String img_path = actualimagecursor.getString(actual_image_column_index);
ArrayList file_list = new ArrayList<>();
File file = new File(img_path);
file_list.add(file);
Intent intent = new Intent();
intent.setClass(MyRecorderVideoActivity.this, MovieBuffAddVideoActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable("file_list", file_list);
bundle.putString("localPath", localPath);
intent.putExtras(bundle);
startActivity(intent);
onBackPressed();*/
}
@Override
publicvoidonMediaScannerConnected(){
msc.scanFile(localPath,"video/*");
}
});
if(progressDialog==null){
progressDialog=newProgressDialog(this);
progressDialog.setMessage("processing...");
progressDialog.setCancelable(false);
}
progressDialog.show();
msc.connect();
}
@Override
publicvoidonInfo(MediaRecordermr,intwhat,intextra){
if(what==MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED){
stopRecording();
btn_switch.setVisibility(View.VISIBLE);
chronometer.stop();
btnStart.setVisibility(View.VISIBLE);
btnStop.setVisibility(View.INVISIBLE);
chronometer.stop();
if(localPath==null){
return;
}
Stringst3=getResources().getString(R.string.Whether_to_send);
newAlertDialog.Builder(this)
.setMessage("是否使用该视频!")
.setPositiveButton(R.string.ok,
newDialogInterface.OnClickListener(){
@Override
publicvoidonClick(DialogInterfacearg0,
intarg1){
arg0.dismiss();
sendVideo(null);
}
}).setNegativeButton(R.string.cancel,null)
.setCancelable(false).show();
}
}
@Override
publicvoidonError(MediaRecordermr,intwhat,intextra){
stopRecording();
Toast.makeText(this,"Recording error has occurred. Stopping the recording",Toast.LENGTH_SHORT).show();
}
publicvoidsaveBitmapFile(Bitmapbitmap){
Filefile=newFile(Environment.getExternalStorageDirectory(),"a.jpg");
try{
BufferedOutputStreambos=newBufferedOutputStream(newFileOutputStream(file));
bitmap.compress(Bitmap.CompressFormat.JPEG,100,bos);
bos.flush();
bos.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
@Override
protectedvoidonDestroy(){
super.onDestroy();
releaseCamera();
if(mWakeLock!=null){
mWakeLock.release();
mWakeLock=null;
}
}
@Override
publicvoidonBackPressed(){
back(null);
}
privatevoidshowFailDialog(){
newAlertDialog.Builder(this)
.setTitle(R.string.prompt)
.setMessage(R.string.Open_the_equipment_failure)
.setPositiveButton(R.string.ok,
newDialogInterface.OnClickListener(){
@Override
publicvoidonClick(DialogInterfacedialog,
intwhich){
finish();
}
}).setCancelable(false).show();
}
privatevoidshowNoSDCardDialog(){
newAlertDialog.Builder(this)
.setTitle(R.string.prompt)
.setMessage("No sd card!")
.setPositiveButton(R.string.ok,
newDialogInterface.OnClickListener(){
@Override
publicvoidonClick(DialogInterfacedialog,
intwhich){
finish();
}
}).setCancelable(false).show();
}
}
MyRecorderVideoActivity.java
下面是xml布局文件
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:id="@+id/rl_title"
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="@color/bg_white">
android:id="@+id/rl_back"
android:layout_width="45dp"
android:layout_height="match_parent"
android:layout_alignParentLeft="true">
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:background="@mipmap/rl_back"/>
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="录制视频"
android:textColor="@color/bg_text_black"
android:textSize="@dimen/sixteen"/>
android:layout_width="fill_parent"
android:layout_height="fill_parent">
android:id="@+id/mVideoView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
android:id="@+id/switch_btn"
android:layout_width="35dip"
android:layout_height="35dip"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:background="@drawable/em_camera_switch_selector"
android:visibility="invisible"/>
android:id="@+id/chronometer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:background="@color/btn_gray_normal"
android:gravity="center_horizontal"
android:textColor="#FFF"/>
android:id="@+id/recorder_start"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:gravity="center"
android:src="@mipmap/em_video_recorder_start_btn"
android:visibility="visible"/>
android:id="@+id/recorder_stop"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:gravity="center"
android:src="@mipmap/em_video_recorder_stop_btn"
android:visibility="invisible"/>
my_recorder_activity.xml
为此我也在网上找了一些资料,不过大部分demo的原理也是MediaRecorder。但是我看到了我拍摄照片的方式,就调用系统自带的摄像头,然后进行拍摄,获取路径就可以了。因此我就想到了拍摄视频如果使用系统自带的录制那就很好的能解决兼容性问题了。唯一不好的就是拍摄界面无法自己定义,各自手机自带的是什么样子的拍摄就保留怎样的拍摄。其实很简单:
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
//设置视频大小
intent.putExtra(Android.provider.MediaStore.EXTRA_SIZE_LIMIT, 768000);
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);
//设置视频时间
intent.putExtra(android.provider.MediaStore.EXTRA_DURATION_LIMIT, 10);
startActivityForResult(intent, REQUEST_CODE_MAP);
然后就是接收了:
Uri uri = data.getData();
// Uri uri = data.getParcelableExtra("uri");
String[] projects = new String[]{MediaStore.Video.Media.DATA,
MediaStore.Video.Media.DURATION};
Cursor cursor = getContentResolver().query(uri,projects, null, null, null);
int duration = 0;
String copyfilepaths="";
String filePath = null;
if (cursor.moveToFirst()) {
// 路径:MediaStore.Audio.Media.DATA
filePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA));
try {
copyfilepaths=PathUtil.getInstance().getVideoPath() + "/" + System.currentTimeMillis() + ".mp4";
copyFileTo(new File(filePath),new File(copyfilepaths));
} catch (IOException e) {
e.printStackTrace();
}
// 总播放时长:MediaStore.Audio.Media.DURATION
duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION));
}
if (cursor != null) {
cursor.close();
cursor = null;
}
File file = new File(PathUtil.getInstance().getImagePath(), "thvideo" + System.currentTimeMillis());
FileOutputStream fos = new FileOutputStream(file);
Bitmap ThumbBitmap = ThumbnailUtils.createVideoThumbnail(filePath, 5);
ThumbBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
值得一提的是:必须要将保存下来的文件copy一次
因为在某些手机使用中,上传文件到服务器是不允许被上传的,然后就导致服务器那边就收不到文件,所以我写了一个方法来转换文件,其实也就是复制文件。
booleancopyFileTo(File srcFile, File destFile)throwsIOException {
if(srcFile.isDirectory() || destFile.isDirectory())
returnfalse;//判断是否是文件
FileInputStream fis =newFileInputStream(srcFile);
FileOutputStream fos =newFileOutputStream(destFile);
intreadLen =0;
byte[] buf =newbyte[1024];
while((readLen = fis.read(buf)) != -1) {
fos.write(buf,0, readLen);
}
fos.flush();
fos.close();
fis.close();
returntrue;
}
csdn项目地址:http://blog.csdn.net/greatdaocaoren/article/details/73497819