网络视频直播系统的流媒体传输中解码的实现流程

在网络视频直播系统中,流媒体传输流程涉及了很多环节,像采集、编码、解码、传输、处理等,其中解码关系着直播内容呈现的效果,所以需要引起足够的重视,在网络视频直播系统中解码的实现流程是什么样的呢?

解码流程

1、初识化,启动解码器
根据MediaFormat中的编码类型(如video/avc,即H264;audio/mp4a-latm,即AAC)创建MediaCodec

//通过Extractor获取到音视频数据的编码信息MediaFormat
val type = mExtractor!!.getFormat()!!.getString(MediaFormat.KEY_MIME)
//调用createDecoderByType创建解码器。
mCodec = MediaCodec.createDecoderByType(type)

2、将网络视频直播系统数据压入解码器输入缓冲
如果SampleSize返回-1,说明没有更多的数据了。queueInputBuffer的最后一个参数要传入结束标记MediaCodec.BUFFER_FLAG_END_OF_STREAM。

//查询是否有可用的输入缓冲,返回缓冲索引
var inputBufferIndex = mCodec!!.dequeueInputBuffer(2000)
//获取可用的缓冲区,并使用Extractor提取待解码数据,填充到缓冲区中。
val inputBuffer = mInputBuffers!![inputBufferIndex]
val sampleSize = mExtractor!!.readBuffer(inputBuffer)
//调用queueInputBuffer将数据压入解码器。
mCodec!!.queueInputBuffer(inputBufferIndex, 0,sampleSize, mExtractor!!.getCurrentTimestamp(), 0)

    /**
     * 读取视频数据
     */
    fun readBuffer(byteBuffer: ByteBuffer): Int {
        //【3,提取数据】
        byteBuffer.clear()
        selectSourceTrack()
        var readSampleCount = mExtractor!!.readSampleData(byteBuffer, 0)
        if (readSampleCount < 0) {
            return -1
        }
        mCurSampleTime = mExtractor!!.sampleTime
        mExtractor!!.advance()
        return readSampleCount
    }

    /**
     * 选择通道
     */
    private fun selectSourceTrack() {
        if (mVideoTrack >= 0) {
            mExtractor!!.selectTrack(mVideoTrack)
        } else if (mAudioTrack >= 0) {
            mExtractor!!.selectTrack(mAudioTrack)
        }
    }

3、将解码好的数据从网络视频直播系统缓冲区拉取出来

 // 查询是否有解码完成的数据,index >=0 时,表示数据有效,并且index为缓冲区索引
    var index = mCodec!!.dequeueOutputBuffer(mBufferInfo, 1000)
    when (index) {
        //输出格式改变了
        MediaCodec.INFO_OUTPUT_FORMAT_CHANGED -> {}
        //没有可用数据,等会再来
        MediaCodec.INFO_TRY_AGAIN_LATER -> {}
        //输入缓冲改变了
        MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED -> {
            mOutputBuffers = mCodec!!.outputBuffers
        }
        else -> {
            return index
        }
    }

4、渲染
视频渲染
​ 网络视频直播系统中视频的渲染并不需要客户端手动去渲染,只需在config时提供绘制表面surface,如果为编解码器配置了输出表面,则将render设置为true会首先将缓冲区发送到该输出表面。

public void configure (MediaFormat format, Surface surface, MediaCrypto crypto, int flags)
releaseOutputBuffer (int index, boolean render)

音频渲染
config时音频不需要surface,直接传null。需要获取采样率,通道数,采样位数等。需要初始化一个网络视频直播系统音频渲染器:AudioTrack

AudioTrack只能播放PCM数据流。

//获取最小缓冲区
    val minBufferSize = AudioTrack.getMinBufferSize(mSampleRate, channel, mPCMEncodeBit)

    mAudioTrack = AudioTrack(
        AudioManager.STREAM_MUSIC,//播放类型:音乐
        mSampleRate, //采样率
        channel, //通道
        mPCMEncodeBit, //采样位数
        minBufferSize, //缓冲区大小
        AudioTrack.MODE_STREAM) //播放模式:数据流动态写入,另一种是一次性写入
        
    mAudioTrack!!.play()

AudioTrack中有MODE_STATIC和MODE_STREAM两种分类。STREAM的意思是由用户在应用程序通过write方式把数据一次一次得写到audiotrack中。这个和我们在socket中发送数据一样,AudioTrack应用层从某个地方获取数据,例如通过编解码得到PCM数据,然后write到audiotrack。这种方式的坏处就是总是在JAVA层和Native层交互,效率损失较大。

而STATIC的意思是一开始创建的时候,就把音频数据放到一个固定的buffer,然后直接传给audiotrack,后续就不用一次次得write了。AudioTrack会自己播放这个buffer中的数据。这种方法对于AudioTrack铃声等内存占用较小,延时要求较高的声音来说很适用

5、释放输出缓冲

mCodec!!.releaseOutputBuffer(index, true)

6、判断解码是否完成

  if (mBufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
    }

7、释放解码器
释放掉所有的资源。至此,网络视频直播系统一次解码结束。

mExtractor?.stop()
 mCodec?.stop()
 mCodec?.release()

 /**
     * 停止读取数据
     */
    fun stop() {
        //【4,释放提取器】
        mExtractor?.release()
        mExtractor = null
    }

以上便是“网络视频直播系统的流媒体传输中解码的实现流程”的全部内容,希望对大家有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值