android 拍摄视频 拍摄照片的 流程 https://www.cnblogs.com/younghao/p/5089118.html,https://www.jianshu.com/p/e5312fd916dd?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
代码
package com.zsch.forestinventory.activity.left_activity.LandForm; import android.content.Intent;import android.hardware.Camera;import android.hardware.Sensor;import android.hardware.SensorEvent;import android.hardware.SensorEventListener;import android.hardware.SensorManager;import android.media.MediaRecorder;import android.net.Uri;import android.os.Bundle;import android.os.Environment;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import android.view.animation.Animation;import android.view.animation.RotateAnimation;import android.widget.FrameLayout;import android.widget.ImageButton;import android.widget.ImageView;import android.widget.Toast;import android.hardware.Camera;import android.hardware.Camera.Parameters;import com.zsch.androidlib.activity.BaseActivity;import com.zsch.androidlib.engine.CameraManager;import com.zsch.androidlib.ui.MySurfaceView;import com.zsch.androidlib.utils.AppConstants;import com.zsch.androidlib.view.LVCircularRing;import com.zsch.forestinventory.MyApplication;import com.zsch.forestinventory.R;import com.zsch.forestinventory.activity.MainActivity;import com.zsch.forestinventory.db.gen.DaoSession;import com.zsch.forestinventory.entity.landforms.LandForm;import com.zsch.forestinventory.entity.landforms.Video;import com.zsch.forestinventory.entity.outdoor_scene.Image;import com.zsch.forestinventory.entity.outdoor_scene.OutdoorScene;import com.zsch.forestinventory.entity.outdoor_scene.SceneGeoPoint;import com.zsch.forestinventory.entity.outdoor_scene.ScenePoint;import com.zsch.forestinventory.utils.DateUtils;import android.hardware.Camera.Size;import org.osmdroid.util.GeoPoint; import java.io.File;import java.io.IOException;import java.util.Calendar;import java.util.List; /** * Created by TinySun on 2017/10/17. * 拍照用的Activity */public class CameraLandFormVideoActivity extends BaseActivity implements View.OnClickListener,CameraManager.IPhotoSaveStateListener{ public static final String PROJECT_NAME_ID = "projectNameId"; // public static final String IMAGE_TYPE_ID= "imagetype_id"; public static final String LAND_FROM_ID = "landFromId"; //新增地质点id 将场景点去除 这里开始接受 mainactivity 传来的 项目名 和 地质点id public static final String VIDEO_ID = "video_id"; public static final String VIDEO_TYPE = "video_type"; private ImageButton mShutter;;//录像按钮 private ImageButton ibBack;//返回按钮 private LVCircularRing ivLoading; //拍攝后的 圆圈动画 // private CameraManager mCameraManager; private Camera mCamera; private MediaRecorder mRecorder; //录制视频的类 // private MySurfaceView mSurfaceView; //显示视频的控件 实现这个接口的Callback接口// private FrameLayout mSurfaceViewLayout; private SurfaceHolder mSurfaceHolder; private SurfaceView mCameraPreview; // 显示视频的控件 实现这个接口的Callback接 private final static int CAMERA_ID = 0; private boolean mIsRecording = false; private boolean mIsSufaceCreated = false; //判斷surfaceView是否创建成功 private DaoSession mSession; private LandForm LandformsImages; //新增 实体LanfForm的 private String projectName; private String imagetype_id; private String video; private String savePath; @Override protected void initVariables() { //初始化变量 long landFromId = getIntent().getLongExtra(LAND_FROM_ID, -1L); // 这里开始接受 mainactivity 传来的地质点id projectName = getIntent().getStringExtra(PROJECT_NAME_ID); //获取传过来的项目名称 这个 必须得有 以后再写 目前 先做别的 imagetype_id=getIntent().getStringExtra(IMAGE_TYPE_ID);//获取传过来的imagetype_id video=getIntent().getStringExtra(VIDEO_TYPE);//获取传过来的视频类型 if (landFromId < 0) onBackPressed(); mSession = ((MyApplication) getApplication()).getSession(); //实例化 //例子 获取User对象时立即执行查询操作获取Friend对象 获取更深层的对象 1对1 表连接 通过这个对象获取 另一个表的对象 LandformsImages = mSession.getLandFormDao().loadDeep(landFromId); //1.通过传过来的id查两个表这两表一对一连接 一起的数据 savePath = AppConstants.APP_DIR + projectName + AppConstants.VIDEO_FILE; //视频的保存路径 APP_DIR为程序路径 startPreview(); //启动预览 } @Override protected void initView(Bundle savedInstanceState) { setContentView(R.layout.activity_camera_land_form_video);// mSurfaceViewLayout = (FrameLayout) findViewById(R.id.mSurfaceViewLayout); mShutter = (ImageButton) findViewById(R.id.record_shutter); ibBack = (ImageButton) findViewById(R.id.ibBack); ivLoading = (LVCircularRing) findViewById(R.id.ivLoading); //拍照后的 旋转框 mCameraPreview = (SurfaceView) findViewById(R.id.camera_preview); //拍照预览 mSurfaceHolder = mCameraPreview.getHolder();// 取得holder mSurfaceHolder.addCallback(mSurfaceCallback);// holder加入回调接口 mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); mShutter.setOnClickListener(this); ibBack.setOnClickListener(this); ivLoading.setViewColor(getResources().getColor(R.color.colorProgressBarDefaultWheel)); ivLoading.setBarColor(getResources().getColor(R.color.colorProgressBarWheel)); } @Override protected void loadData() { } private SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() { @Override public void surfaceDestroyed(SurfaceHolder holder) { mIsSufaceCreated = false; } @Override //必须监听surfaceView的创建,创建完毕后才可以处理播放 public void surfaceCreated(SurfaceHolder holder) { mIsSufaceCreated = true; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { startPreview(); } }; //启动预览 private void startPreview() { //保证仅仅有一个Camera对象 if (mCamera != null || !mIsSufaceCreated) { //当相机对象 ,和 sufaceView 对象 两个 有一个不存在时 就返回 return; } mCamera = Camera.open(CAMERA_ID); //获得照相机对象 Camera.Parameters parameters = mCamera.getParameters();//获取照相参数 List<Camera.Size> sizes = parameters.getSupportedPictureSizes(); //设置预览大小时,必须使用getSupportedPreviewSizes()的值 // List<Camera.Size> sizeVideos = parameters.getSupportedVideoSizes(); parameters.setVideoSize()方法怎么用 错误的没有这个方法 有mRecorder.setVideoSize(1920, 1080); if (sizes.get(0).width > sizes.get(sizes.size() - 1).width) { parameters.setPictureSize(sizes.get(0).width, sizes.get(0).height); //这里通过判断有无照相机镜头 去判断 } else { parameters.setPictureSize(sizes.get(sizes.size() - 1).width, sizes.get(sizes.size() - 1).height); } // parameters.setPreviewSize(sizes.get(sizes.size() - 1).width, sizes.get(sizes.size() - 1).height); 我感觉 录像的这里应该为setPreviewSize parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); //获得焦点 parameters.setPreviewFrameRate(20); //设置相机预览方向 设置正确的预览方向 // mCamera.setDisplayOrientation(90); //调节 窗口的角度 90 是 竖排 默认横拍 mCamera.setParameters(parameters); try { mCamera.setPreviewDisplay(mSurfaceHolder); //设置SurfaceView的SurfaceHolder用于预览。 // mCamera.setPreviewCallback(mPreviewCallback); } catch (Exception e) { } mCamera.startPreview(); //开始预览 } //停止预览 private void stopPreview() { //释放Camera对象 if (mCamera != null) { try { mCamera.setPreviewDisplay(null); } catch (Exception e) { } mCamera.stopPreview(); mCamera.release(); mCamera = null; } } @Override public void onClick(View view) { //点击触发事件 switch (view.getId()) { case R.id.record_shutter://录像按钮 和停止 点击为开始录像 再次点击 为停止 if (mIsRecording) { //mIsRecording 进行判断 是预览状态 还是 在拍摄状态 stopRecording(); } else { initMediaRecorder(); startRecording(); } break; case R.id.ibBack://返回按钮 onBackPressed(); break; } } //录像功能 private void initMediaRecorder() {// Camera录制视频时,除了Camera.open()和Camera.release()调用外,还必须管理Camera.lock()和Camera.unlock()调用,以允许MediaRecorder访问摄像机硬件。 mRecorder = new MediaRecorder();//实例化 创建mediarecorder对象 mCamera.unlock(); //解锁相机以供MediaRecorder使用。从预览那解锁 mRecorder.reset(); //给Recorder设置Camera对象,保证录像跟预览的方向保持一致 mRecorder.setCamera(mCamera); //设置要用于视频捕获的摄像机,使用应用程序的当前摄像机实例 // mRecorder.setOrientationHint(90); //改变保存后的视频文件播放时是否横屏(不加这句。视频文件 // 设置视频来源Camera(相机) mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); //设置声音来源 mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 设置录制完成后视频的封装格式THREE_GPP为3gp.MPEG_4为mp4 mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); // 设置录制的视频编码h263 h264 mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); //设置编码比特率,不设置会使视频图像模糊 且文件大小为3.26M(30秒) 有奇效 mRecorder.setVideoEncodingBitRate(5*900*1024); // 设置音频的编码格式 mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); // 设置视频录制的分辨率。必须放在设置编码和格式的后面,否则报错 mRecorder.setVideoSize(1920, 1080); // 设置录制的视频帧率。必须放在设置编码和格式的后面,否则报错 mRecorder.setVideoFrameRate(30); //设置最大录像时间为30s mRecorder.setMaxDuration(30000); //将画面展示到surfaceView 上 mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());// // 设置视频文件输出的路径// mRecorder.setOutputFile("/sdcard/"+generateVideoName()+".mp4"); //设置视频存储路径 最后通过 uuid 去 建立文件 存储路径 //Environment类:提供访问环境变量. //常用Environment.getExternalStorageState来获取SD卡的状态 //File.separator 路径分隔符 File file1 = new File ("C:\tmp\test.txt");中的 \ 因为 window 和 linux中的分隔符不一样 所以 为了防止 识别错误 跨系统用File.separator // File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) + File.separator + savePath); //创建文夹名 File file = new File(savePath); //创建文夹名 if (!file.exists()) { //多级目录的创建 file.mkdirs(); } String file_Name=generateVideoName() ; //设置视频文件输出的路径 mRecorder.setOutputFile(file.getPath() +"/"+file_Name); //创建文件名 //进行数据库的存储 当点击 停止拍摄后 会 将这些数据 返回到 主函数 hasSaveVideo(file_Name); } private void hasSaveVideo(String file_Name) { //存储 1.视频名称2.视频类型3.项目id4.地质点id5.项目名称 Video video = null; video=new Video(); video.setLandForm_id(getIntent().getLongExtra(LAND_FROM_ID, -1L));//地质点id // video.setProject_id();//.项目id video.setProjectName(projectName); video.setVideo_type(getIntent().getStringExtra(VIDEO_TYPE));//视频类型 video.setName(file_Name);//视频名称2 mSession.insert(video); //这步视频的id以及名字 存入数据库 将id类的相关名字 Intent data = new Intent(); data.putExtra(LAND_FROM_ID, video.getLandForm_id()); //将地质点id返回到主页面里 data.putExtra(VIDEO_ID, video.getId());//将照片id返回 data.putExtra(VIDEO_TYPE, video.getVideo_type());//将照片类型id返回 可以是平面图 也可以是照片 data.putExtra(PROJECT_NAME_ID,projectName);//将项目名称返回 表中无项目名 利用id就行 需要项目名称 实景里面可以 这里 不可以 会出现问题 setResult(RESULT_OK, data); //这里是将图片id 和实景id 返回 之前 应该是 mainactivity 返回后 进行判断 onActivityResult()方法里有 } //开始拍摄 private void startRecording() { if (mRecorder != null) { try { mRecorder.prepare(); //为提供的配置设置准备MediaRecorder。 mRecorder.start(); //开始录制视频 } catch (Exception e) { mIsRecording = false; //mIsRecording 进行判断 是预览状态 还是 在拍摄状态 } } //設置 拍摄时 按钮的样式// mShutter.setImageDrawable(getResources().getDrawable(R.drawable.recording_shutter_hl)); mIsRecording = true; //mIsRecording 进行判断 是预览状态 还是 在拍摄状态// } } //停止 拍攝 將相机锁上 并将 mRecorder 释放 资源 private void stopRecording() { if (mRecorder != null) { mRecorder.stop(); //停止MediaRecorder mRecorder.release(); //释放MediaRecorder mRecorder = null; } if (mCamera != null) { mCamera.lock(); // 锁定相机 mCamera.stopPreview();//停止预览 mCamera.release();//释放相机 } //将按钮样式转变// mShutter.setImageDrawable(getResources().getDrawable(R.drawable.recording_shutter)); // finish();//在Activity中执行this.finish()方法之后,执行如下过程: onPause(),onStop(),onDestory(), mIsRecording = false; //mIsRecording 进行判断 是预览状态 还是 在拍摄状态// 本項目 在拍照完需要 返回到 表格界面 不需要 重新预览// 重新启动预览// startPreview(); finish(); //刪除 onpasue()效果不錯 還是得 改onpasue() 让他的功能符合我的项目 他們 是將 medRecordi 以及camera的 釋放 都卸载了 onpause 和 ondestory里了 } @Override public void onBackPressed() {//为解决 当拍摄中 出现问题 这里需要修改 当 点击 finish() 会跳转到 onpuse 这是 因为mRecorder 程序走了stopPreview(); Intent data = new Intent(); if (LandformsImages != null) { data.putExtra(LAND_FROM_ID, LandformsImages.getId().longValue()); //scenePoint不为空 则把地质点id传回去 setResult(RESULT_OK, data); } else { setResult(RESULT_CANCELED); //RESULT_CANCELED = 0;传回去 } //两种 情况 一种 时 在 拍照前 一种是 拍照后 if(mRecorder!=null){ //说明是在拍摄中 mIsRecording = true; stopRecording(); // 停止 拍攝 这处没问题 mIsRecording=true 说明在拍摄中 }else{ //说明在预览中 stopPreview(); //停止预览 mIsRecording=false 说明还没拍摄 在预览状态 } finish();} private String generateVideoName() { //takePicture()里面获取照片名称 的修饰方法 Calendar calendar = Calendar.getInstance(); //日历类 这里初始化日历对象 StringBuffer buffer = new StringBuffer(); //字符串存储类 buffer.append("V"); String year = calendar.get(Calendar.YEAR) + ""; buffer.append(year.substring(2,4)); int month = calendar.get(Calendar.MONTH) + 1; if (month < 10) { buffer.append("0"); } buffer.append(month); int day = calendar.get(Calendar.DAY_OF_MONTH); if (day < 10) { buffer.append("0"); } buffer.append(day); buffer.append(randomString());//添加随机字母 buffer.append(AppConstants.VIEW_SUFFIX);//添加后缀 .mp4 return buffer.toString(); } /** * 生成随机字符串,使用UUID * @return */ public String randomString() { String str = java.util.UUID.randomUUID().toString(); String text = str.substring(0,8) + str.substring(str.length() - 8,str.length()); return text; } public void notifySystemToScan(File file) { //其实就是通知系统创建或者删除了某个文件,系统需要扫描sd卡,进行更新 Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); Uri uri = Uri.fromFile(file); intent.setData(uri); sendBroadcast(intent); } @Override public void hasSavePhoto(String path) { }} 切记 两个 camera mRecorder 在录像 上 两个 都要打开 最后两个 都要关闭哦 camera 要早于 mRecorder 先进行预览 然后 设置 mrecorder
原文地址:https://www.cnblogs.com/dushutai/p/12642746.html
时间: 2024-10-10 19:18:04