Android 编码摄像头数据为h.264格式

之前自学了下ffmpeg,使用ffmpeg在ubuntu下编解码比较方便,但是到了Android,发现使用比较多的编解码类是MediaCodec,在工作之余,抽点时间,学习下这个类的使用,做点记录,以供后续查阅。 MediaCodec类可用于访问Android底层的媒体编解码器,它是Android为多媒体支持提供的底层接口的一部分(通常与MediaExtractor, MediaSync, Med
摘要由CSDN通过智能技术生成

之前自学了下ffmpeg,使用ffmpeg在ubuntu下编解码比较方便,但是到了Android,发现使用比较多的编解码类是MediaCodec,在工作之余,抽点时间,学习下这个类的使用,做点记录,以供后续查阅。
MediaCodec类可用于访问Android底层的媒体编解码器,它是Android为多媒体支持提供的底层接口的一部分(通常与MediaExtractor, MediaSync, MediaMuxer, MediaCrypto, MediaDrm, Image, Surface, 以及AudioTrack一起使用)—这是官网对MediaCodec类的简介。阅读了下API文档,还是水里雾里的,于是设计了一个实验,慢慢尝试MediaCodec类的使用。
我设计的实验非常简单,就是从摄像头拿到数据,然后使用MediaCodec将其压缩为h.264格式,压缩完成后写入一个文件中。
获取摄像头的数据的过程之前在 一文中已经说过了,是的,基于此,我们将拿到的数据进行编码。
先看一下结果吧,因为h.264文件是可以直接播放的:
这里写图片描述

从摄像头取出图像数据

首先,创建一个TextureView对象或者SurfaceView,二者都可以,这里使用TextureView,它直接在布局文件中使用,然后在Activity中使用findViewById来找到它。
其次,给TextureView设置监听器:textureView.setSurfaceTextureListener(this);Acitivity实现了这个监听器接口。
然后,在onSurfaceTextureAvailable函数中初始化摄像头,并打开,就像下面这样:

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        Log.d("jw_liu","onPreviewFrame");

        mCamera = Camera.open();
        try {
            mCamera.setPreviewTexture(surface);
            mCamera.setPreviewCallback(new Camera.PreviewCallback() {
                @Override
                public void onPreviewFrame(byte[] data, Camera camera) {
                    Log.d("jinwei","l:"+data.length);
                    if(MediaCodecManager.frame != null){
                        System.arraycopy(data,0,MediaCodecManager.frame,0,data.length);
                    }
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPictureFormat(PixelFormat.JPEG);
        parameters.setPreviewFormat(PixelFormat.YCbCr_420_SP);
        parameters.setPreviewSize(480, 320);

        parameters.set("orientation", "portrait");
        parameters.set("rotation", 180);
        mCamera.setDisplayOrientation(180);

        mCamera.setParameters(parameters);
        mCamera.startPreview();
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
      //  Log.d("jw_liu","onSurfaceTextureSizeChanged");
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
       // Log.d("jw_liu","onSurfaceTextureDestroyed");
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
       // Log.d("jw_liu","onSurfaceTextureUpdated");
    }

这个流程非常简单,我们需要关注的是摄像头的配置参数。
我们将摄像头的预览格式配置成 了YCbCr_420_SP,预览的大小为420*320,这两个参数非常重要,因为编码器也需要设置编码图像的大小和图片格式,如果这两者是一致的,那么你就省去了在这之间做转换的繁琐工作。

我们给camera设置了预览的回调函数,这样,当摄像头采集到数据以后,回调函数就会将预览的数据传给你,由此,我们获取到了摄像头的数据。
获取到摄像头的数据以后,我们便可以对其进行编码了。我把这部分逻辑放在一个单独的类MediaCodecManager中。这个类会创建一个MeidaCodec的实例,并使用它来对视屏编码。

编码的流程

首先,我们要获得一个编码器,这没什么好说的,我们可以通过类型来直接获取:
mediaCodec = MediaCodec.createEncoderByType(“video/avc”);
其次,这个编码器我们需要对他进行配置。官方文档中对配置的条目有明确的书名,很多条目都是必须要配置的,配置的不对,调用mediaCodec.start()方法就会失败。我对编码器做的配置如下:

        try {
            mediaCodec = MediaCodec.createEncoderByType("video/avc");
        } catch (IOException e) {
            e.printStackTrace();
        }
        MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 480, 320);
        mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 125000);
        mediaFormat
  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值