Android图片视频拍摄选取及压缩

Android图片视频选取及压缩上传

        • 此博客的主要技术点
        • 需求
        • 开车了
          • 图片选择库
          • 视频压缩
          • 上传

此博客的主要技术点

  1. 视频拍摄、视频选取获取视频地址
  2. 视频压缩
  3. 视频上传

需求

我的项目1.0版本最近刚上线了,里面涉及到了发布日志的功能,用户可以发布纯文字、图片或视频。所以呢…又是一个耗大的工程。

开车了

首先来说选择图片、视频和拍摄吧

本来我是要用知乎的Matisse框架的,毕竟用的人数多,稳定性和兼容性都是值得信任的。我导入到项目中完美的运行了起来,具体的使用方法在这里就不说了,可以去上面的链接自行查看,反正就是傻瓜式用法,很方便快捷。
Android图片视频拍摄选取及压缩_第1张图片

可是直到快上线前3、4天左右,PM突然跟我说要有拍摄视频的功能,我看了看Matisse是没有拍摄视频功能的,自己去做拍摄的话可能时间不够了,并且稳定性和兼容性可能照顾不周。我就开始在github继续翻阅开源库(哈哈,我真是名副其实的代码搬运工)。

终于找到了PictureSelector这个框架,用法和Matisse一样的,添加了许多自定义配置,并且是内置UCrop(著名的图片裁剪框架)、内置视频拍摄的。

换框架

图片选择库

添加依赖

dependencies {
    implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.2.3'
}

项目根目录build.gradle加入

allprojects {
   repositories {
      jcenter()
      maven { url 'https://jitpack.io' }
   }
}

声明权限




用法

// 进入相册 以下是例子:用不到的api可以不写
 PictureSelector.create(MainActivity.this)
 	.openGallery()//全部.PictureMimeType.ofAll()、图片.ofImage()、视频.ofVideo()、音频.ofAudio()
 	.theme()//主题样式(不设置为默认样式) 也可参考demo values/styles下 例如:R.style.picture.white.style
 	.maxSelectNum()// 最大图片选择数量 int
 	.minSelectNum()// 最小选择数量 int
	.imageSpanCount(4)// 每行显示个数 int
 	.selectionMode()// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE
 	.previewImage()// 是否可预览图片 true or false
 	.previewVideo()// 是否可预览视频 true or false
	.enablePreviewAudio() // 是否可播放音频 true or false
 	.isCamera()// 是否显示拍照按钮 true or false
	.imageFormat(PictureMimeType.PNG)// 拍照保存图片格式后缀,默认jpeg
	.isZoomAnim(true)// 图片列表点击 缩放效果 默认true
	.sizeMultiplier(0.5f)// glide 加载图片大小 0~1之间 如设置 .glideOverride()无效
	.setOutputCameraPath("/CustomPath")// 自定义拍照保存路径,可不填
 	.enableCrop()// 是否裁剪 true or false
 	.compress()// 是否压缩 true or false
 	.glideOverride()// int glide 加载宽高,越小图片列表越流畅,但会影响列表图片浏览的清晰度
 	.withAspectRatio()// int 裁剪比例 如16:9 3:2 3:4 1:1 可自定义
 	.hideBottomControls()// 是否显示uCrop工具栏,默认不显示 true or false
 	.isGif()// 是否显示gif图片 true or false
	.compressSavePath(getPath())//压缩图片保存地址
 	.freeStyleCropEnabled()// 裁剪框是否可拖拽 true or false
 	.circleDimmedLayer()// 是否圆形裁剪 true or false
 	.showCropFrame()// 是否显示裁剪矩形边框 圆形裁剪时建议设为false   true or false
 	.showCropGrid()// 是否显示裁剪矩形网格 圆形裁剪时建议设为false    true or false
 	.openClickSound()// 是否开启点击声音 true or false
 	.selectionMedia()// 是否传入已选图片 List list
 	.previewEggs()// 预览图片时 是否增强左右滑动图片体验(图片滑动一半即可看到上一张是否选中) true or false
 	.cropCompressQuality()// 裁剪压缩质量 默认90 int
 	.minimumCompressSize(100)// 小于100kb的图片不压缩 
 	.synOrAsy(true)//同步true或异步false 压缩 默认同步
 	.cropWH()// 裁剪宽高比,设置如果大于图片本身宽高则无效 int 
 	.rotateEnabled() // 裁剪是否可旋转图片 true or false
 	.scaleEnabled()// 裁剪是否可放大缩小图片 true or false
 	.videoQuality()// 视频录制质量 0 or 1 int
	.videoMaxSecond(15)// 显示多少秒以内的视频or音频也可适用 int 
        .videoMinSecond(10)// 显示多少秒以内的视频or音频也可适用 int 
	.recordVideoSecond()//视频秒数录制 默认60s int
	.isDragFrame(false)// 是否可拖动裁剪框(固定)
 	.forResult(PictureConfig.CHOOSE_REQUEST);//结果回调onActivityResult code  
 

结果回调

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            switch (requestCode) {
                case PictureConfig.CHOOSE_REQUEST:
                    // 图片、视频、音频选择结果回调
                    List selectList = PictureSelector.obtainMultipleResult(data);
                    // 例如 LocalMedia 里面返回三种path
                    // 1.media.getPath(); 为原图path
                    // 2.media.getCutPath();为裁剪后path,需判断media.isCut();是否为true  注意:音视频除外
                    // 3.media.getCompressPath();为压缩后path,需判断media.isCompressed();是否为true  注意:音视频除外
                    // 如果裁剪并压缩了,以取压缩路径为准,因为是先裁剪后压缩的
                    adapter.setList(selectList);
                    adapter.notifyDataSetChanged();
                    break;
            }
        }
    }

如果需要图片压缩的话,只需要修改参数即可

      .compress(false)// 是否压缩 true or false
     .synOrAsy(true)//同步true或异步false 压缩 默认同步

 @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE_CHOOSE && resultCode == RESULT_OK) {
            List selectList = PictureSelector.obtainMultipleResult(data);
            File file = null;
            if (selectList.get(0).isCut()) {
                file = new File(selectList.get(0).getCutPath());
            } else {
                file = new File(selectList.get(0).getPath());
            }
   			//取得时候注意,如果这个图片.isCut()的情况再取getCutPath(),否则为空

        }
    }

视频压缩
  1. ffmpeg-android-java框架
  2. VideoCompressor框架

项目最初是采用ffmpeg框架的,但是ffmpeg一个so库就7、8M,并且压缩速度实在是太慢了,实测30M的视频压缩到3.8M用了30多秒,但是压缩后的视频质量很可观,没有严重的丢帧和马赛克。这边奉上ffmpeg进行视频压缩的详细步骤 T_T操作步骤

后来经过我的疯狂百度、Google。终于找到了这个框架VideoCompressor
实测30M到3M用时10s,并且有low、middle、high三种质量可以选择,但是在high压缩的时候可能会出现压缩后比原视频体积还大的情况。最终我们选择了Medium,速度与清晰度都达到要求。

先去Github下载module,导入到自己的项目中。

VideoCompress.compressVideoMedium("源视频路径", "视频生成路径", new VideoCompress.CompressListener() {
            @Override
            public void onStart() {
                Logutils.i(TAG, "---onStart");
            }

            @Override
            public void onSuccess() {
                //压缩成功则开始上传视频
                Logutils.i(TAG, "---onSuccess");
            }

            @Override
            public void onFail() {
            	Logutils.i(TAG, "---onFail");
            }

            @Override
            public void onProgress(float percent) {
                Logutils.i(TAG, "---onProgress:" + percent);
            }
        });

VideoCompress提供了三种视频压缩比率,分别是High、Medium和Low,使用时只需要将compressVideoMedium方法修改一下即可。

上传

媒体上传我倒是没有做太多的处理,就是直接放在MultipartBody里面。

不过项目遇到了个小问题,就是视频上传的时候因为要压缩,所以导致用户上传视频时等待时间过长,体验不好。

最后的解决方案是,用户点击上传的时候我们只创建纯文字的日志。服务器返回日志ID,然后我们存入到本地数据库中,并且唤醒一个foregroundService进行上传操作,不影响用户使用。创建成功后先在列表展示本地的数据,service开启线程上传媒体资源,然后如果用户刷新列表并且日志媒体资源上传成功的情况下,才会展示网络数据,清掉数据库。不知道这样的解决方案合理性如何,各位大神如果有好的解决方案可以直接评论在下方,感谢感谢

ps : 我并不想再改动上传的代码了,哈哈,有点懒。
Android图片视频拍摄选取及压缩_第2张图片

你可能感兴趣的:(Android)