Camera+MediaCodec+ffmpeg实现视频录制

架构设计

原设计架构:
调用系统Action属性打开手机相机,进行视频录制操作;
使用ProjectApplication.activity.startActivityForResult()回调方式获取录制视频文件;
利用callback机制回传获取录制视频文件到界面,进行数据上传和UI更新操作。

原设计架构存在问题:上传视频后存在颜色失真的问题,这个现象的原因是Camera录制的NV21图像预览数据,没有进行视频编码和封装,直接转为mp4格式文件存储,并不是手机支持的MediaCodec编解码颜色格式,则上传平台后存在颜色失真的现象。

新架构设计:
使用Camera框架采集视频像素数据;
使用MediaCodec将原生YUV数据转码为H264格式;
使用ffmpeg命令将H264文件封装为mp4文件。
利用callback机制将封装MP4文件回传到界面,进行数据上传和UI更新操作。

Camera

Android5.0之前使用android.hardware包下的Camera类进行拍照、录视频等功能。

Camera实现视频数据采集

public class DataCollectVideoDialog extends BaseDialog implements View.OnClickListener, Camera.PreviewCallback {
   

    @BindView(R.id.record_video_sfv)
    SurfaceView surfaceView;
    @BindView(R.id.btn_start_video)
    Button startBtn;
    @BindView(R.id.btn_stop_video)
    Button stopBtn;

    private SurfaceHolder holder;
    private android.hardware.Camera camera;
    private DataCollectCallBack callBack;
    private static int yuvqueuesize = 10;
    private static ArrayBlockingQueue<byte[]> YUVQueue = new ArrayBlockingQueue<byte[]>(yuvqueuesize);
    private MediaUtil mediaUtil;


    public DataCollectVideoDialog(Context context, DataCollectCallBack callBack) {
   
        super(context, R.style.FullScreenDialogTheme);
        this.callBack = callBack;

    }

    @Override
    protected int setContentView() {
   
        return R.layout.dialog_data_collect_video;
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void bindView() {
   
        super.bindView();
        supportAvcCodec();
        init();
    }

	// 对View控件初始化
    private void init() {
   
        getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        holder = surfaceView.getHolder();
        startBtn.setOnClickListener(this);
        stopBtn.setOnClickListener(this);
        stopBtn.setVisibility(View.GONE);
        ((Toolbar) view.findViewById(R.id.record_video_toolbar)).setNavigationOnClickListener(v -> cancelOn());
        setOnKeyListener(((dialog, keyCode, event) -> {
   
            if (keyCode == KeyEvent.KEYCODE_BACK && keyCode == KeyEvent.ACTION_DOWN) {
   
                cancelOn();
            }
            return false;
        }));
        show();
    }

	// 检查当前是否支持video编码
    private boolean supportAvcCodec() {
   
        if (Build.VERSION.SDK_INT >= 18) {
   
            for (int j = MediaCodecList.getCodecCount() - 1; j >= 0; j--) {
   
                MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(j);
                String[] types = codecInfo.getSupportedTypes();
                for (int i = 0; i < types.length; i++) {
   
                    if (types[i].equalsIgnoreCase("video/avc"
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值