美文网首页
屏幕录制/暂停及音视频混合编码 -2016

屏幕录制/暂停及音视频混合编码 -2016

作者: 薰舞空 | 来源:发表于2020-03-31 15:50 被阅读0次

    老忘密码。。好多帖子都找不到了,把以前csdn写的也转移到这边,这个是2016的

    屏幕录制大体两种方式,一种走系统权限,截取屏幕自动录制,跨应用的,比较简单,就不写了

    另一种则是自己确认录制区,自行混合音视频进行录制,不用权限,这里介绍的第二种

    5.0中提供了MediaProjection类来实现录屏,用起来也简单

    核心是MediaProjection、MediaCodec、MediaMuxer

    我的理解就是:采集 -> 转码 -> 混合生成文件

    简单来说,通过MediaCodec得到一个surface,这是MediaCodec的转码源,就是要进行转码的视频的画布,差不多能这么认为吧,然后用MediaProjection的createVirtualDisplay方法开始对这个surface输出,一个线程循环来使MediaCodec进行转码,获得的数据交给MediaMuxer混合输入到文件中,然后就ok了

    这部的例子很多,功能也很简单,官方的个人的都很多,例如下面这个:

    http://blog.csdn.net/l00149133/article/details/50483327

    但是这样出来的话,一个是没有音频,第二是暂停的问题,基本方法里木有找到暂停的思路,也没发现什么有价值的参考

    感觉暂停比较简单,最初的思路就是,暂停的时间我不写入MediaMuxer就行了,然后发现。。。例如录3秒,暂停3秒,再录3秒,最后的视频是9秒,中间是没有变化的同一帧

    很明显虽然没写入数据还是记了时间,然后第二个思路就是暂停的时候直接stop,然后start,然后就崩了。。。stop会直接放弃之前的设置

    第三个思路,暂停的时候直接stop,然后重新配置,然后start,然后如果是MediaCodec这么做,现象跟不写入时一样,有空白的一段,如果是MediaMuxer,视频就重新开始了。。。

    重新读了下三个核心类的开发文档,首先放弃MediaProjection,功能单一,没什么可尝试的,重点在于MediaCodec向MediaMuxer转入的数据,里面有个时间戳,是不是这个时间戳的问题,一番尝试后搞定,时间戳就是个写入位置的标记,只要减去中间暂停的时间就行了,顺便一说,这个体系的时间单位是微秒

    最后一个问题,音频怎么整,没什么思路啊,后来找到一篇介绍的

    http://blog.csdn.net/jinzhuojun/article/details/32163149

    这个传的还挺广,写的真不错,真想给作者赞几个加个关注什么的,不过连着几个人的都标得原创。。也不知道到底是谁写的,觉得这个最像吧。。。也是无语了。。转人帖子很好,扩散技术,非写自己原创就鄙视了。。

    话题转回来哈,写的有点笼统,主要思路就是两个线程,然后两个MediaCodec,一个还做我们刚才事,另一个做录音,用的是AudioRecord,暂停逻辑都相似,在原来那个线程里每次循环的时候,都加个写入音频,然后录音线程里,加一个向MediaCodec传数据,这个MediaCodec专门负责音频,他的数据源就要通过AudioRecord负责了

    附录制代码:

    /**
     * 处理视频
     */
    private void drainVideoEncoder(boolean endOfStream) {
    
        if (endOfStream) {
            //标志输入流的结束
            videoEncoder.signalEndOfInputStream();
        }
    
        int encoderStatus = videoEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_US);
    
        /* ====== 新的格式或格式改变,应当初始化 ====== */
        if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            //加入视频轨道
            MediaFormat newFormat = videoEncoder.getOutputFormat();
            mVideoTrackIndex = mMuxer.addTrack(newFormat);
            mNumTracksAdded++;
            if (mNumTracksAdded == TOTAL_NUM_TRACKS) {
                mMuxerStarted = true;
                mMuxer.start();
            }
        }
    
        /* ====== 等待 ====== */
        else if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        /* ====== 小于0不处理 ====== */
        else if (encoderStatus < 0) {
            // let's ignore it
        }
    
        /* ====== 大于于0 正式开始纪录 ====== */
        else {
    
            if (!mMuxerStarted) {
                throw new IllegalStateException("MediaMuxer dose not call addTrack(format) ");
            }
    
            ByteBuffer encodedData = videoEncoder.getOutputBuffer(encoderStatus);
    
            //忽略
            if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                // The codec config data was pulled out and fed to the muxer when we got
                // Ignore it.
                mBufferInfo.size = 0;
            }
    
            //空值
            if (mBufferInfo.size == 0) {
                encodedData = null;
            }
    
            //暂停不纪录
            if (mPause.get()) {
                encodedData = null;
            }
    
            if (encodedData != null) {
    
                //从暂停中恢复的第一次纪录
                if (videoFirstResume) {
                    videoFirstResume = false;
                    pauseTime += mBufferInfo.presentationTimeUs - videoLastRecordTime - 10000;
                    videoEncoder.flush();
                    return;
                } else {
                    videoLastRecordTime = mBufferInfo.presentationTimeUs;
                    mBufferInfo.presentationTimeUs -= pauseTime;
    
                    encodedData.position(mBufferInfo.offset);
                    encodedData.limit(mBufferInfo.offset + mBufferInfo.size);
    
                    mMuxer.writeSampleData(mVideoTrackIndex, encodedData, mBufferInfo);
                }
            }
    
            videoEncoder.releaseOutputBuffer(encoderStatus, false);
        }
    
    }
    
    

    相关文章

      网友评论

          本文标题:屏幕录制/暂停及音视频混合编码 -2016

          本文链接:https://www.haomeiwen.com/subject/rmnwuhtx.html