当前位置:主页 > 查看内容

WebRTC-Android边直播边录像

发布时间:2021-05-29 00:00| 位朋友查看

简介:前言 该文章面向对WebRTC有一定基础的码农如果完全没了解过WebRTC的朋友可以点赞并私信我进行一对一辅导哦。 WebRTC-Android SDK自带的实现方式 其实WebRTC已经提供了一个org.webrtc.VideoFileRenderer.java的渲染器专门用于把画面数据存储到本地文件该渲染……

前言

该文章面向对WebRTC有一定基础的码农,如果完全没了解过WebRTC的朋友,可以点赞并私信我进行一对一辅导哦。

WebRTC-Android SDK自带的实现方式

其实WebRTC已经提供了一个org.webrtc.VideoFileRenderer.java的渲染器,专门用于把画面数据存储到本地文件,该渲染器与SurfaceViewRenderer.java一样实现了VideoSink接口

通过VideoTrack.addSink(VideoSink sink)方法把渲染器添加到画面轨道中,即开始录制画面。
通过VideoTrack.removeSink(VideoSink sink)方法可把渲染器从画面轨道中移除,即停止录制画面。

mStartRecordBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 开始录制
        String filePath = getExternalFilesDir(null).getAbsolutePath() + File.separator + System.currentTimeMillis() + ".y4m";
        try {
            mVideoFileRenderer = new VideoFileRenderer(filePath, 480, 640, mEglContext);
        } catch (IOException e) {
            e.printStackTrace();
            mVideoFileRenderer = null;
            return;
        }
        mVideoTrack.addSink(mVideoFileRenderer);
    }
});

mStopRecordBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 停止录制
        if (mVideoFileRenderer != null) {
            mVideoTrack.removeSink(mVideoFileRenderer);
            mVideoFileRenderer.release();
            mVideoFileRenderer = null;
        }
    }
});
但这种方式有2个重大的缺陷:
  1. 只能录制画面,没有实现声音的录制
  2. 录制的画面是YUV裸流,每一帧都是完整帧,所以会导致文件非常大(10几秒的视频就可以超过上百MB)

flutter-webrtc的实现方式

WebRTC-Android SDK自带的实现方式因为有两个重大的缺陷,导致正常的业务基本用不上这种实现方式。
但万幸的是flutter-webrtc项目早已看透了这一切,然后大喊一声我自己来,然后com.cloudwebrtc.webrtc.record.VideoFileRenderer.java这个类就出来了。

跟WebRTC-Android SDK的VideoFileRenderer一样,该渲染器也实现了VideoSink接口,并且额外实现了SamplesReadyCallback接口,实现VideoSink接口是为了获取画面数据,SamplesReadyCallback则是为了获取音频数据。

废话不多,直接上代码

mInitPeerConnectionFactoryBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 初始化PeerConnectionFactory
        ......
        mPeerConnectionFactory = new PeerConnectionFactory.Builder()
                ......
                .setAudioDeviceModule(JavaAudioDeviceModule.builder(context)
                        .setSamplesReadyCallback(new JavaAudioDeviceModule.SamplesReadyCallback() {
                            @Override
                            public void onWebRtcAudioRecordSamplesReady(JavaAudioDeviceModule.AudioSamples audioSamples) {
                                if (mVideoFileRenderer != null) {
                                    // 把音频数据传给VideoFileRenderer
                                    mVideoFileRenderer.onWebRtcAudioRecordSamplesReady(audioSamples);
                                }
                            }
                        })
                ......
                .createAudioDeviceModule());
        ......
    }
});

mStartRecordBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 开始录制
        String filePath = getExternalFilesDir(null).getAbsolutePath() + File.separator + System.currentTimeMillis() + ".mp4";
        try {
            mVideoFileRenderer = new VideoFileRenderer(filePath, mEglContext, true);
        } catch (IOException e) {
            e.printStackTrace();
            mVideoFileRenderer = null;
            return;
        }
        mVideoTrack.addSink(mVideoFileRenderer);
    }
});

mStopRecordBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 停止录制
        if (mVideoFileRenderer != null) {
            mVideoTrack.removeSink(mVideoFileRenderer);
            mVideoFileRenderer.release();
            mVideoFileRenderer = null;
        }
    }
});

至此,我们就可以边直播边录像了!而且录制出来的是mp4文件,视频经过了压缩,文件大小就是正常的mp4文件大小了。

但是,flutter-webrtc的VideoFileRenderer还是有点小问题,就是对于音频的时间计算有点问题,里面直接固定写死音频的采样率是48000Hz,所以我们还需要对VideoFileRenderer进行一点小修改:

@Override
public void onWebRtcAudioRecordSamplesReady(JavaAudioDeviceModule.AudioSamples audioSamples) {
    if (!isRunning)
        return;
    audioThreadHandler.post(() -> {
        ......
        if (bufferIndex >= 0) {
            ......
//            presTime += data.length * 125 / 12; // 1000000 microseconds / 48000hz / 2 bytes
            presTime += data.length * (1_000_000 / audioSamples.getSampleRate() / 2); //16位最后那个数字是2,8位是1
        }
        drainAudio();
    });
}

完美结束~

;原文链接:https://blog.csdn.net/yeahhaey/article/details/115541615
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!
上一篇:iOS 判断是否插了耳机 下一篇:没有了

推荐图文


随机推荐