Android硬编解码并播放

Android 采集过程注意

  1. Camera.addCallbackBuffer(byte[] data)其中data的大小要紧密与采集数据的格式相关.
  2. 如采集到的数据格式yuv422i,那么data的大小应该为width * height * 2.
  3. Camera.setPreviewCallback(Camera.PreviewCallback cb)
  4. 每次调用onPreviewFrame(...)的末尾在添加一次Camera.addCallbackBuffer(byte[] data)

Android H264硬编码过程

  1. 生成编码器并且设置相关参数
    public synchronized void open() {
        //YUV420P的大小关系
        byte[] yuv420 = new byte[mWidth * mHeight * 3 / 2];
        //生成编码器并且设置相关参数
        mediaCodec = MediaCodec.createEncoderByType("video/avc");
        //编码格式参数设置,如果对yuv数据进行旋转以后,注意mWidth,
        //mHeight的在90度或270度会颠倒,不设置正确的话对端会花屏
        MediaFormat mediaFormat = MediaFormat.createVideoFormat(
            "video/avc", mWidth, mHeight);
        //设置码率,码率越低,失真越厉害
        mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
        /**设置编码输入缓存大小,默认输入数据为yuv420大小,即1.5倍的宽高积,
        如果使用的是其他格式,如yuv422那么就要手动设置大小,不然塞数据时
        会报BufferOverflowException异常*/
        mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE,
                 mWidth * mHeight * 3 / 2);
        //设置帧率
        mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, framerate);
        /**设置颜色格式(I420,YV12,NV21等)
            如:MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar*/
        mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
        //设置发送I帧的时间间隔
        mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);//单位:s(秒)
        //完成配置,启动
        mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAT_ENCODE);
        mediaCodec.start();
    }
  1. 进行编码
    public synchronized int encode(byte[] in, int offset, byte[] out, int length) {
        int pos = 0;
        byte[] inBuf = in;
        int l = length;
        /**由于Android 摄像头默认采集的数据是NV21格式,所以要
           转成MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar
           让编码器支持.*/
        NV21toYUV420SemiPlannr(in, offset, yuv420, mWidth, mHeight);
        try {
            /**
                    注意此处获取inputBuffer和outputBuffer的方法,在android LOLLIPOP之后
                    的版本要修改inputBuffer = MediaCodec.getInputBuffer(index);
            */
            ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
            ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
            /**
                解码的时候,如果此处TIME_OUT非0会有个大坑,很多机子在这句卡死
            */
            int inputBufferIndex = mediaCodec.dequeueInputBuffer(TIME_OUT);
            if(inputBufferIndex >= 0){
                ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
                inputBuffer.clear();
                inputBuffer.put(inBuf, offset, l);
                /**此处getMyTime()函数维护一个递增的时间戳
                    据说此处的第四个参数不传,第一个I帧以后,
                    mediaCodec.dequeueOutputBuffer()一直返回-1,
                    -1对应原生代码的再试一遍的意思*/
                mediaCodec.queueInputBuffer(inputBufferIndex, 0, l, getMyTime(), 0);
            }
            MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
            /**
                此处的TIME_OUT是否要传,待研究.
             */
            int outBufferIndex = mediaCodec.dequeueInputBuffer(bufferInfo, TIME_OUT);
            //待理解继续
        }
    }

(待补充)

Android H264硬解码过程

  1. 生成MediaCodec对象并且设置好参数
    //H264解码器
    codec = MediaCodec.createDecoderByType("video/avc");
    MeidaFormat mediaFormat = MediaFormat.createVideoFormat(
        "video/avc", width, height);
    mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, width * height);
    codec.configure(mediaFormat, surface, null, 0);
    codec.start();
  1. 进行解码并且播放
    public void decodeAndPlayBack(byte[] in, int offset, int length) {
        //获取喂数据的ByteBuffer数组
        ByteBuffer[] inputBuffers = codec.getInputBuffers();
        /**以下特别注意,TIME_OUT建议设置成0,设置非0很多机子
            出现卡死在此句代码,设置成0的代价只是丢帧*/
        int inputBuffersIndex = codec.dequeueInputBuffer(TIME_OUT);
        if(inputBuffersIndex >= 0) {
            ByteBuffer inputBuffer = inputBuffers[inputBuffersIndex];
            inputBuffer.clear();
            inputBuffer.put(in, offset, length);
            //填充好数据以后,提交通知解码器解码,这几个参数待研究
            codec.queueInputBuffer(inputBuffersIndex, 0, length, 0, 0);
        }
        //释放缓存空间
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        int outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, 0);
        while (outputBufferIndex >=0) {
            codec.releaseOutputBuffer(outputBufferIndex, true);
            outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, 0);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值