音视频中环形缓冲区(ring buffer)的应用

环形缓冲区的概念

了解完环形缓冲区的概念后,本文介绍其在音视频项目中的应用。

代码实例

相关函数如下

static int LUX_VENC_SaveStream(int chnId, IMPEncoderStream *stream)
{
    int ret = 0;
    int i = 0;
    int nr_pack = stream->packCount;
    IMPEncoderPack *pack = NULL;
    uint32_t remSize = 0;
    char saveName[32] = {0};
    char *formatTable[3] = {"h264", "h264", "jpg"};
    static FILE *fp[VIDEO_ENC_CHN_MAX] = {NULL};

    if (!fp[chnId])
    {
        sprintf(saveName, "video_stream_chn%d.%s", chnId, formatTable[chnId]);

        fp[chnId] = fopen(saveName, "wb");
        if (NULL == fp[chnId])
            return 0;
    }

    for (i = 0; i < nr_pack; i++) 
    {
        pack = &stream->pack[i];

        if (pack->length)
        {
            remSize = stream->streamSize - pack->offset;
            if (remSize < pack->length)
            {
                ret = fwrite((void *)(stream->virAddr + pack->offset), 1, remSize, fp[chnId]);
                if (ret != remSize)
                {
                    IMP_LOG_ERR(TAG, "stream write ret(%d) != pack[%d].remSize(%d) len:%d\n", ret, i, remSize, ret);
                    return -1;
                }
                ret = fwrite((void *)stream->virAddr, 1, pack->length - remSize, fp[chnId]);
                if (ret != (pack->length - remSize))
                {
                    IMP_LOG_ERR(TAG, "stream write ret(%d) != pack[%d].(length-remSize)(%d) len:%d\n", ret, i, (pack->length - remSize), ret);
                    return -1;
                }
            }
            else
            {
                ret = fwrite((void *)(stream->virAddr + pack->offset), 1, pack->length, fp[chnId]);
                if (ret != pack->length)
                {
                    IMP_LOG_ERR(TAG, "stream write ret(%d) != pack[%d].length(%d) len:%d\n", ret, i, pack->length, ret);
                    return -1;
                }
            }
        }
    }

    return 0;
}

所用到的数据结构如下

/**
 * 定义编码帧码流包结构体
 */
typedef struct {
	uint32_t	offset;						/**< 码流包地址偏移 */
	uint32_t	length;							/**< 码流包长度 */
	int64_t	timestamp;						/**< 时间戳,单位us */
	bool	frameEnd;						/**< 帧结束标识 */
	IMPEncoderNalType   nalType;				/**< H.264和H.265编码Channel码流NAL类型 */
	IMPEncoderSliceType sliceType;
} IMPEncoderPack;

/**
 * 定义编码帧码流类型结构体
 */
typedef struct {
	uint32_t		  phyAddr;          /**< 帧码流物理地址 */
	uint32_t		  virAddr;          /**< 帧码流包虚拟地址 */
	uint32_t		  streamSize;       /**< virAddr对应分配的地址空间大小 */
	IMPEncoderPack  *pack;				/**< 帧码流包结构 */
	uint32_t        packCount;			/**< 一帧码流的所有包的个数 */
	uint32_t        seq;				/**< 编码帧码流序列号 */
} IMPEncoderStream;

代码解释

1、获取包的总数作为循环条件
2、将当前包的属性存入IMPEncoderPack结构体中
3、第一层判断,是为了区分是否还有包要传。若没有包,则对应结构体中的所有数据都是0
4、判断是否需要折返

相关变量描述

  • virAddr——虚拟地址(内存首地址)
  • streamSize——虚拟地址的长度
  • pack->offset——基于virAddr的偏移量,用于计算包的位置
  • pack->length——包的长度
  • remSize——streamSize中剩余可用的存储空间

在这里插入图片描述
remsize忘记画了,remSize = StreamSize - offset
即除了offset外的可用于存储的空间

上图的length写错了,应该是所有包的长度

折返判断

if (remSize < pack->length)
            {
                ret = fwrite((void *)(stream->virAddr + pack->offset), 1, remSize, fp[chnId]);
                if (ret != remSize)
                    return -1;

                ret = fwrite((void *)stream->virAddr, 1, pack->length - remSize, fp[chnId]);
                if (ret != (pack->length - remSize))
                    return -1;
            }
            else
            {
                ret = fwrite((void *)(stream->virAddr + pack->offset), 1, pack->length, fp[chnId]);
                if (ret != pack->length)
                	return -1;
            }

去掉打印后如上

判断条件为remSize < pack->length,即剩余空间是否能够存放剩下的包

else中,剩余空间能够放下所有的包
于是直接从首地址加上偏移量的位置开始存

if中,剩余空间不能存完全部的包长
首先从头开始存,存不下之后,剩余的从首地址开始存

以此达到环形buffer的效果

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Spark!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值