zoukankan      html  css  js  c++  java
  • 安卓 日常问题 工作日志10

    android 拍摄视频 拍摄照片的 流程    https://www.cnblogs.com/younghao/p/5089118.htmlhttps://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: mp est.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
  • 相关阅读:
    linux下模拟CISCO设备输出NetFlow数据 规格严格
    国际:十个习惯让你精通新的开发技术
    国人眼中的Scrum
    NetBeans 时事通讯(刊号 # 2 Apr 08, 2008)
    Ruby语言的发展趋势和启示
    离开几天
    Ruby语言的发展趋势和启示
    だ い が く せ い か つ
    NetBeans 时事通讯(刊号 # 2 Apr 08, 2008)
    离开几天
  • 原文地址:https://www.cnblogs.com/dushutai/p/12642746.html
Copyright © 2011-2022 走看看