关于Android音视频,实现录屏并输出MP4文件

一个视频从录制到生成MP4文件的过程和需要用到的工具类及作用:

原始数据:yuv(视频),pcm(音频)

编码格式:

视频流:h264,h265,mpeg2

音频流:aac,mp3,wmv

封装格式:

mp4,avi,rmvb,flv...

MediaCodec:

用来编解码H264视频流

编码:YUV->H264

解码:H264->YUV

主要代码及作用:

 public class MyRunnable implements Runnable {
        @Override
        public void run() {
            try {
                //1、IO流方式读取h264文件【太大的视频分批加载】
                byte[] bytes = null;
                bytes = getBytes(inputStream);
                Log.e(TAG, "bytes size " + bytes.length);
                //2、拿到 mediaCodec 所有队列buffer[]
                //开始位置
                int startIndex = 0;
                //h264总字节数
                int totalSize = bytes.length;
                //3、解析
                while (true) {
                    //判断是否符合
                    if (totalSize == 0 || startIndex >= totalSize) {
                        break;
                    }
                    //寻找索引
                    int nextFrameStart = findByFrame(bytes, startIndex + 2, totalSize);
                    if (nextFrameStart == -1) {
                        break;
                    }
                  
                    MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
                    Log.i(TAG, "run: infosize = "+ info.size);
                    // 查询10000毫秒后,如果dSP芯片的buffer全部被占用,返回-1;存在则大于0
                    int inIndex = mediaCodec.dequeueInputBuffer(10000);
                    if (inIndex >= 0) {
                        //根据返回的index拿到可以用的buffer
                        ByteBuffer byteBuffer = mediaCodec.getInputBuffer(inIndex);
                        //清空缓存
                        byteBuffer.clear();
                        //开始为buffer填充数据
                        //byte数据,startIndex从哪里开始,nextFrameStart - startIndex到下一个分割符的长度
                        byteBuffer.put(bytes, startIndex, nextFrameStart - startIndex);
                        //填充数据后通知mediacodec查询inIndex索引的这个buffer,
                        //index告诉mediaCodec(dsp)用了那个容器
                        mediaCodec.queueInputBuffer(inIndex, 0, nextFrameStart - startIndex, 0, 0);
                        //到此数据从cpu传到了dsp
                        //为下一帧做准备,下一帧首就是前一帧的尾。
                        startIndex = nextFrameStart;
                    } else {
                        //等待查询空的buffer
                        continue;
                    }
                    //mediaCodec 查询 "mediaCodec的输出方队列"得到索引
                    //解码比较耗时,并不是传一帧数据输出一帧数据
                    int outIndex = mediaCodec.dequeueOutputBuffer(info, 10000);
                    Log.e(TAG, "outIndex " + outIndex);
                    //大于0已经解码完成
                    if (outIndex >= 0) {
                        try {
                            //暂时以休眠线程方式放慢播放速度
                            Thread.sleep(33);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //如果surface绑定了,则直接输入到surface渲染并释放,没有Surface则为false
                        mediaCodec.releaseOutputBuffer(outIndex, true);
                    } else {
                        Log.e(TAG, "没有解码成功");
                    }
                }


            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值