Skip to content

encoder

buliaoyin edited this page Nov 21, 2017 · 7 revisions

自定义编码器

SDK提供了通用音视频编码器的基类实现(VideoBufEncoderBase, AudioEncoderBase),开发者可以通过扩展这些基类, 实现几个基础接口,即可将自己的编码器接入到SDK中。

具体应用示例可参考 x264encoderfdkaacencoder.

需要实现、调用的接口说明

  • 开启编码器

    视频编码器实现 int doStart(VideoEncodeConfig config) 接口, 音频编码器实现 int doStart(AudioEncodeConfig config) 接口。
    在该接口实现中,需要根据输入的config参数来配置并打开编码器。

  • 停止编码器

    实现 void doStop() 接口,关闭编码器。

  • 动态码率调整

    视频编码器需实现 void doAdjustBitrate(int bitrate) 接口, 在编码过程中动态调整视频码率以实现码率自适应的特性。

  • Flush编码器数据

    实现 doFlush() 接口,清空当前编码器中的残留的已编码数据。

  • 送入原始音视频数据

    视频编码器实现 int doEncode (ImgBufFrame frame) 接口,音频编码器实现 int doEncode (AudioBufFrame frame) 接口。
    在该接口实现中,需要将参数中传递的原始音视频帧数据送给编码器。

  • 发送编码后的音视频数据

    编码器获取到一帧编码后的数据后,需要调用 sendEncodedPacket(ByteBuffer data, long dts, long pts, int flags) 接口来将其发送至下一级模块。

需要注意的一些点

  • 需要实现的各个抽象方法均在基类创建的单一编码线程中被调用,基类已实现对外接口的异步化处理。

  • AAC音频编码器打开后输出的第一帧必须是flag中带有AVConst.FLAG_CODEC_CONFIG标记的AAC header信息。

  • H264/265视频编码器打开后输出的第一帧必须是flag中带有AVConst.FLAG_CODEC_CONFIG标记的SPS/PPS信息。

  • 视频编码后的数据必须是一个完整的frame。

  • 视频编码后输出的数据,关键帧必须在flag参数中有AVConst.FLAG_KEY_FRAME标记。

kit类集成

参考 UnionStreamer.javaswitchVideoEncoder(), switchAudioEncoder 中的实现。

protected void switchAudioEncoder() {
    AudioEncodeConfig encodeConfig = null;
    if (mAudioEncoder != null) {
        encodeConfig = (AudioEncodeConfig) mAudioEncoder.getEncodeConfig();
        mAudioEncoder.getSrcPin().disconnect(false);
        mAudioMixer.getSrcPin().disconnect(mAudioEncoder.getSinkPin(), true);
    }
    if (mAudioEncodeMethod == StreamerConstants.ENCODE_METHOD_HARDWARE) {
        mAudioEncoder = new MediaCodecAudioEncoder();
    } else {
        mAudioEncoder = new FdkAACEncoder();
    }
    // avAdaptor
    mAudioEncoder.getSrcPin().connect(mAVAdapter.getAudioSink());
    mAudioMixer.getSrcPin().connect(mAudioEncoder.getSinkPin());
    mAudioEncoder.setEncoderListener(mEncoderListener);
    if (encodeConfig != null) {
        mAudioEncoder.configure(encodeConfig);
    }
}

protected void switchVideoEncoder() {
    VideoEncodeConfig encodeConfig = null;
    if (mVideoEncoder != null) {
        encodeConfig = (VideoEncodeConfig) mVideoEncoder.getEncodeConfig();
        mVideoEncoder.getSrcPin().disconnect(false);
        mImgTexMixer.getSrcPin().disconnect(true);
    }
    if (mVideoEncodeMethod == StreamerConstants.ENCODE_METHOD_HARDWARE) {
        mVideoEncoder = new MediaCodecSurfaceEncoder(mGLRender);
        mImgTexMixer.getSrcPin().connect(mVideoEncoder.getSinkPin());
    } else {
        mImgTexToBuf = new ImgTexToBuf(mGLRender);
        mVideoEncoder = new X264Encoder();
        mImgTexToBuf.getSrcPin().connect(mVideoEncoder.getSinkPin());
        mImgTexMixer.getSrcPin().connect(mImgTexToBuf.getSinkPin());
    }
    mVideoEncoder.getSrcPin().connect(mAVAdapter.getVideoSink());
    mVideoEncoder.setEncoderListener(mEncoderListener);
    if (encodeConfig != null) {
        mVideoEncoder.configure(encodeConfig);
    }
}
Note
硬编的MediaCodecSurfaceEncoder接受的输入frame类型为ImgTexFrame, 可以直接接受GPU处理后的数据,而基于VideoBufEncoderBase的视频编码实例接受的输入类型为ImgBufFrame, 需要前置一个ImgTexToBuf模块完成转换。

1. 集成指南

2. 基本功能

2.1 采集

2.2 视频处理

2.3 音频处理

3. 开放接口定义

Clone this wiki locally