Android调用相机拍照录视频录音以及存储,7.0以上及以下都可使用。

简介: Android调用相机拍照录视频录音以及存储,7.0以上及以下都可使用。

在开头,先说一下在imageVIew中如何显示文件中存储的视频的第一帧的图片。很简单,几行代码就搞定。

MediaMetadataRetriever media = new MediaMetadataRetriever();
            media.setDataSource(user.getPath());
            Bitmap bitmap = media.getFrameAtTime();

下来,开始说拍照和存储视频,先在配置文件中声明一下provider,因为在安卓7.0以上想要存储必须要这个东西,没办法,写吧。

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="zj.it.bhne.gridengineeringsurvey.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

meta-data中的file_paths就是自己建的一个xml文件。"."的意思时所有格式。

<?xml version="1.0" encoding="utf-8"?>
<paths >
    <external-path name="external_files" path="."/>
    <files-path name="my_images" path="images/"/>
    <root-path
        name="root_path"
        path="." />
</paths>

好了,准备工作做完之后就开始编写拍照和录视频吧。首先时录视频。

/**
     * 启动相机,创建文件,并要求返回uri
     */
    private void startVideo() {
        Intent intent = new Intent();
        //指定动作,启动相机
        intent.setAction(MediaStore.ACTION_VIDEO_CAPTURE);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        Log.d(TAG, "指定启动相机动作,完成。");
        //创建文件
        createVideoFile();
        Log.d(TAG, "创建视频文件结束。");
        //添加权限
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        Log.d(TAG, "添加权限。");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //做一些处理
            //获取uri
            mVideoUri = FileProvider.getUriForFile(this, "zj.it.bhne.gridengineeringsurvey.fileprovider", mVideoFile);
        } else {
            //在版本低于此的时候,做一些处理
            mVideoUri = Uri.fromFile(mVideoFile);
        }
        Log.d(TAG, "根据视频文件路径获取uri。");
        //将uri加入到额外数据
        intent.putExtra(MediaStore.EXTRA_OUTPUT, mVideoUri);
        Log.d(TAG, "将uri加入启动相机的额外数据。");
        Log.d(TAG, "启动相机...");
        //启动相机并要求返回结果
        startActivityForResult(intent, VIDEO_RESULT_CODE);
        Log.d(TAG, "拍摄中...");
    }
    /**
     * 创建视频文件
     */
    private void createVideoFile() {
        Log.d(TAG, "开始创建图片文件...");
        //设置图片文件名(含后缀),以当前时间的毫秒值为名称
        mVideoName = Calendar.getInstance().getTimeInMillis() + ".mp4";
        Log.d(TAG, "设置图片文件的名称为:"+mVideoName);
        //创建图片文件
        mVideoFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
                + "/bhne/" + getPath() + "/", mVideoName);
        //将图片的绝对路径设置给mImagePath,后面会用到
        mVideoPath = mVideoFile.getAbsolutePath();
        //按设置好的目录层级创建
        mVideoFile.getParentFile().mkdirs();
        Log.d(TAG, "按设置的目录层级创建图片文件,路径:"+mVideoPath);
        //不加这句会报Read-only警告。且无法写入SD
        mVideoFile.setWritable(true);
        Log.d(TAG, "将图片文件设置可写。");
    }


需要标注的我都写好了注释,直接看代码就可以了。下面是拍照并存储。

/**
     * 启动相机,创建文件,并要求返回uri
     */
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void startCamera() {
        Intent intent = new Intent();
        //指定动作,启动相机
        intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        Log.d(TAG, "指定启动相机动作,完成。");
        //创建文件
        createImageFile();
        Log.d(TAG, "创建图片文件结束。");
        //添加权限
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        Log.d(TAG, "添加权限。");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //做一些处理
            //获取uri
            mImageUri = FileProvider.getUriForFile(this, "zj.it.bhne.gridengineeringsurvey.fileprovider", mImageFile);
        } else {
            //在版本低于此的时候,做一些处理
            mImageUri = Uri.fromFile(mImageFile);
        }
        Log.d(TAG, "根据图片文件路径获取uri。");
        //将uri加入到额外数据
        intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
        Log.d(TAG, "将uri加入启动相机的额外数据。");
        Log.d(TAG, "启动相机...");
        //启动相机并要求返回结果
        startActivityForResult(intent, PHOTO_RESULT_CODE);
        Log.d(TAG, "拍摄中...");
    }
    /**
     * 创建图片文件
     */
    private void createImageFile(){
        Log.d(TAG, "开始创建图片文件...");
        //设置图片文件名(含后缀),以当前时间的毫秒值为名称
        mImageName = Calendar.getInstance().getTimeInMillis() + ".jpg";
        Log.d(TAG, "设置图片文件的名称为:"+mImageName);
        //创建图片文件
        mImageFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
                + "/bhne/" + getPath() + "/", mImageName);
        //将图片的绝对路径设置给mImagePath,后面会用到
        mImagePath = mImageFile.getAbsolutePath();
        //按设置好的目录层级创建
        mImageFile.getParentFile().mkdirs();
        Log.d(TAG, "按设置的目录层级创建图片文件,路径:"+mImagePath);
        //不加这句会报Read-only警告。且无法写入SD
        mImageFile.setWritable(true);
        Log.d(TAG, "将图片文件设置可写。");
    }


好了。就这样,注意任何时候不要硬编码文件路径,请使用 Android 文件系统 API 访问。千万不要像下面这样写:

File file = new File("/mnt/sdcard/Download/Album", alName);

下面时录音的存储:

/**
     * 启动录音机,创建文件
     */
    private void startRecord() {
        Intent intent = new Intent();
        intent.setAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
        createVoiceFile();
        Log.d(TAG, "创建录音文件");
        //添加权限
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        Log.d(TAG, "启动系统录音机,开始录音...");
        startActivityForResult(intent, VOICE_RESULT_CODE);
    }
    /**
     * 创建音频目录
     */
    private void createVoiceFile() {
        mVoiceName = getMyTime() + ".amr";
        Log.d(TAG, "录音文件名称:" + mVoiceName);
        mVoiceFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
                + "/" + SD_APP_DIR_NAME + "/" + VOICE_DIR_NAME + "/", mVoiceName);
        mVoicePath = mVoiceFile.getAbsolutePath();
        mVoiceFile.getParentFile().mkdirs();
        Log.d(TAG, "按设置的目录层级创建音频文件,路径:" + mVoicePath);
        mVoiceFile.setWritable(true);
    }
  /**
     * 获取日期并格式化
     * 如:2017_10_20 周三 上午 11:20:35
     *
     * @return 格式化好的日期字符串
     */
    private String getMyTime() {
        //存储格式化后的时间
        String time;
        //存储上午下午
        String ampTime = "";
        //判断上午下午,am上午,值为 0 ; pm下午,值为 1
        int apm = Calendar.getInstance().get(Calendar.AM_PM);
        if (apm == 0) {
            ampTime = "上午";
        } else {
            ampTime = "下午";
        }
        //设置格式化格式
        SimpleDateFormat format = new SimpleDateFormat("yyyy_MM_dd E " + ampTime + " kk:mm:ss");
        time = format.format(new Date());
        return time;
    }
    /**
     * 保存音频到SD卡的指定位置
     *
     * @param path 录音文件的路径
     */
    private void saveVoiceToSD(String path) {
        //创建输入输出
        InputStream isFrom = null;
        OutputStream osTo = null;
        try {
            //设置输入输出流
            isFrom = new FileInputStream(path);
            osTo = new FileOutputStream(mVoicePath);
            byte bt[] = new byte[1024];
            int len;
            while ((len = isFrom.read(bt)) != -1) {
                Log.d(TAG, "len = " + len);
                osTo.write(bt, 0, len);
            }
            Log.d(TAG, "保存录音完成。");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (osTo != null) {
                try {
                    //不管是否出现异常,都要关闭流
                    osTo.close();
                    Log.d(TAG, "关闭输出流");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (isFrom != null) {
                try {
                    isFrom.close();
                    Log.d(TAG, "关闭输入流");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
/**
     * 通过Uri,获取录音文件的路径(绝对路径)
     *
     * @param uri 录音文件的uri
     * @return 录音文件的路径(String)
     */
    private String getAudioFilePathFromUri(Uri uri) {
        Cursor cursor = getContentResolver()
                .query(uri, null, null, null, null);
        cursor.moveToFirst();
        int index = cursor.getColumnIndex(MediaStore.Audio.AudioColumns.DATA);
        String temp = cursor.getString(index);
        cursor.close();
        return temp;
    }

下面处理照片,视频以及录音存储

/**
     * 处理返回结果。
     * 1、图片
     * 2、音频
     * 3、视频
     *
     * @param requestCode 请求码
     * @param resultCode  结果码 成功 -1 失败 0
     * @param data        返回的数据
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
//        Log.d(TAG, "拍摄结束。");
        Log.d(TAG, "录音结束。");
        if (resultCode == Activity.RESULT_OK) {
            Log.d(TAG, "返回成功。");
            Log.d(TAG, "请求码:" + requestCode + "  结果码:" + resultCode + "  data:" + data);
            switch (requestCode) {
                case PHOTO_RESULT_CODE: {
                    Bitmap bitmap = null;
                    try {
                        //根据uri设置bitmap
                        bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), mImageUri);
                        Log.d(TAG, "根据uri设置bitmap。");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    //将图片保存到SD的指定位置
                    savePhotoToSD(bitmap);
                    //更新系统图库
                    updateSystemGallery();
                    Log.d(TAG, "结束。");
                    break;
                }
                case VOICE_RESULT_CODE: {
                    try {
                        Uri uri = data.getData();
                        String filePath = getAudioFilePathFromUri(uri);
                        Log.d(TAG, "根据uri获取文件路径:" + filePath);
                        Log.d(TAG, "开始保存录音文件");
                        saveVoiceToSD(filePath);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                    break;
                }
                case VIDEO_RESULT_CODE: {
//                    saveVideoTOSD();
                    break;
                }
            }
        }
    }
目录
相关文章
|
6月前
|
Android开发
Android调用相机与相册的方法1
Android调用相机与相册的方法
81 0
|
5月前
|
Android开发 容器
35. 【Android教程】视频页面:ViewPager
35. 【Android教程】视频页面:ViewPager
58 3
|
5月前
|
存储 API 文件存储
47. 【Android教程】SharedPreferences 存储
47. 【Android教程】SharedPreferences 存储
63 2
|
6月前
|
Java Android开发
Android12 双击power键启动相机源码解析
Android12 双击power键启动相机源码解析
189 0
|
3月前
|
存储 安全 API
Android经典实战之存储方案对比:SharedPreferences vs MMKV vs DataStore
本文介绍了 Android 开发中常用的键值对存储方案,包括 SharedPreferences、MMKV 和 DataStore,并对比了它们在性能、并发处理、易用性和稳定性上的特点。通过实际代码示例,帮助开发者根据项目需求选择最适合的存储方案,提升应用性能和用户体验。
93 1
|
3月前
|
测试技术 API Android开发
Android经典实战之简化 Android 相机开发:CameraX 库的全面解析
CameraX是Android Jetpack的一个组件,旨在简化相机应用开发,提供了易于使用的API并支持从Android 5.0(API级别21)起的设备。其主要特性包括广泛的设备兼容性、简洁的API、生命周期感知、简化实现及方便的集成与测试。通过简单的几个步骤即可实现如拍照、视频录制等功能。此外,还提供了最佳实践指导以确保应用的稳定性和性能。
66 0
|
3月前
|
编解码 监控 API
惊艳登场!揭秘如何在Android平台上轻松玩转GB28181标准,实现多视频通道接入的超实用指南!
【8月更文挑战第14天】GB28181是公共安全视频监控联网的技术标准。本文介绍如何在Android平台上实现该标准下的多视频通道接入。首先准备开发环境,接着引入GB28181 SDK依赖并初始化SDK。实现设备注册与登录后,通过指定不同通道号请求多路视频流。最后,处理接收到的数据并显示给用户。此过程涉及视频解码,需确保应用稳定及良好的用户体验。
49 0
|
5月前
|
监控 Android开发 数据安全/隐私保护
安卓kotlin JetPack Compose 实现摄像头监控画面变化并录制视频
在这个示例中,开发者正在使用Kotlin和Jetpack Compose构建一个Android应用程序,该程序 能够通过手机后置主摄像头录制视频、检测画面差异、实时预览并将视频上传至FTP服务器的Android应用
|
4月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的高校后勤网上报修系统安卓app附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的高校后勤网上报修系统安卓app附带文章源码部署视频讲解等
55 0
|
5月前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的安卓的微博客系统附带文章和源代码部署视频讲解等
基于ssm+vue.js+uniapp小程序的安卓的微博客系统附带文章和源代码部署视频讲解等
48 2