EasyPusher实现安卓Android手机直播推送同步录像功能(源码解析)

本文详细介绍了如何利用EasyPusher在Android设备上实现边推流边录像的功能。EasyPusher的EasyMuxer类封装了MediaMuxer,用于处理从MediaCodec编码的音视频数据,支持自动分段存储。通过设置开启本地录像,MediaMuxer在添加Video和Audio Track后启动录像,确保音视频同步。录像过程中,pumpStream方法在不同线程中保存音视频数据,当达到预设的最大文件时长,会创建新文件继续录像。整个过程稳定且低延迟,源码可在GitHub找到。
摘要由CSDN通过智能技术生成

EasyPusher是一款非常棒的推送客户端。稳定、高效、低延迟,音视频同步等都特别好。装在安卓上可作为一款单兵设备来用。说到单兵,在项目中通常都需要边传边录的功能,因此后来EasyPusher也加入了该特性。该文章将结合代码来阐述下这个功能是如何实现的。

EasyPusher在设置里增加了相关选项来方便开启和关闭本地录像功能,如下图所示,在设置里勾选后就可以推送的同时进行录像了。

EasyPusher的本地录像功能

EasyPusher用来实现录像的类叫做EasyMuxer,该类对安卓系统的MediaMuxer进行了一些封装,专门对从MediaCodec编码出来的音视频数据进行录像,同时实现了录像自动分段存储的功能。其构造函数如下:

public EasyMuxer(String path, long durationMillis) {
        mFilePath = path;
        this.durationMillis = durationMillis;
        Object mux = null;
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                mux = new MediaMuxer(path + "-" + index++ + ".mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            mMuxer = (MediaMuxer) mux;
        }
    }

构造函数有两个参数,第一个参数为本次录像的文件路径;第二个参数为单个文件最大时长,用来做录像分段(由于MediaMuxerJELLY_BEAN_MR2以上才加入,因此这里做了判断,低于该版本的系统直接忽略了)。函数内部创建了一个MediaMuxer对象,用来实现真正的录像存储功能。

MediaMuxer在录像之前需要加入Video Track和Audio Track,EasyMuxuer进行了如下封装。

    public synchronized void addTrack(MediaFormat format, boolean isVideo) {
        // now that we have the Magic Goodies, start the muxer
        if (mAudioTrackIndex != -1 && mVideoTrackIndex != -1)
            throw new RuntimeException("already add all tracks");

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            int track = mMuxer.addTrack(format);
            if (VERBOSE)
                Log.i(TAG, String.format("addTrack %s result %d", isVideo ? "video" : "audio", track));
            if (isVideo) {
                mVideoFormat = format;
                mVideoTrackIndex = track;
                if (mAudioTrackIndex != -1) {
                    if (VERBOSE)
                        Log.i(TAG, "both audio and video added,and muxer is started");
                    mMuxer.start();
                    mBeginMillis = System.currentTimeMillis();
                }
            } else {
                mAudioFormat = format;
                mAudioTrackIndex = track;
                if (mVideoTrackIndex != -1) {
                    mMuxer.start();
                    mBeginMillis = System.currentTimeMillis();
                }
            }
        }
    }

这个函数有两个参数,第一个为要加入的媒体流的MediaFormat,可通过MediaCodec获取到,第二个表示加入的是Video还是Audio。从代码可以看到,在音频和视频都添加成功后会自动启动录像,这样做的好处是应用层的音视频的处理完全可以独立,不用操心录像的事情,减少了代码耦合性。同时,录像启动的时候会记录下来开始时间,后面需要用这个开始时间来计算文件时长。

录像启动后,接下来就应该保存数据了。我们再继续看下面的函数封装。


    public synchronized void pumpStream(ByteBuffer outputBuffer, MediaCodec.BufferInfo bufferInfo, boolean isVideo) {
        if (mAudioTrackIndex == -1 || mVideoTrackIndex == -1) {
            Log.i(TAG, String.format("pumpStream [%s] but muxer is not start.ignore..", isVideo ? "video" : "audio"));
            return;
        }
        if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
            // The codec config data was pulled out and fed to the muxer when we got
            // the INFO_OUTPUT_FORMAT_CHANGED status.  Ignore it.
        } else if (bufferInfo.size != 0) {
            if (isVideo && mVideoTrackIndex == -
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值