【蓝牙sbc协议】sbc源码阅读笔记(四)——sbc_encode函数详解

【蓝牙sbc协议】sbc源码阅读笔记(四)——sbc_encode函数详解sbc_encode函数详解函数定义://sbc.cSBC_EXPORTssize_tsbc_encode(sbc_t*sbc,constvoid*input,size_tinput_len, void*output,size_toutput_len,ssize_t*written){ structsbc_priv*priv; intsamples; ssize_tframelen; int(*sbc_enc_process_input)(int

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

sbc_encode函数详解


函数定义:
// sbc.c
SBC_EXPORT ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
			void *output, size_t output_len, ssize_t *written)
{ 
   
	struct sbc_priv *priv;
	int samples;
	ssize_t framelen;
	int (*sbc_enc_process_input)(int position,
			const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
			int nsamples, int nchannels);

	if (!sbc || !input)
		return -EIO;

	priv = sbc->priv;

	if (written)
		*written = 0;

  // 初始化 priv->frame
  // priv->frame 包含了一个未打包的 SBC 数据帧
	if (!priv->init) { 
   
		priv->frame.frequency = sbc->frequency;
		priv->frame.mode = sbc->mode;
		priv->frame.channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
		priv->frame.allocation = sbc->allocation;
		priv->frame.subband_mode = sbc->subbands;
		priv->frame.subbands = sbc->subbands ? 8 : 4;
		priv->frame.block_mode = sbc->blocks;
		if (priv->msbc)
			priv->frame.blocks = MSBC_BLOCKS;
		else
			priv->frame.blocks = 4 + (sbc->blocks * 4);
		priv->frame.bitpool = sbc->bitpool;
		priv->frame.codesize = sbc_get_codesize(sbc);
		priv->frame.length = sbc_get_frame_length(sbc);

		sbc_encoder_init(priv->msbc, &priv->enc_state, &priv->frame);
		priv->init = true;
	} else if (priv->frame.bitpool != sbc->bitpool) { 
   
		priv->frame.length = sbc_get_frame_length(sbc);
		priv->frame.bitpool = sbc->bitpool;
	}

	/* input must be large enough to encode a complete frame */
	if (input_len < priv->frame.codesize)
		return 0;

	/* output must be large enough to receive the encoded frame */
	if (!output || output_len < priv->frame.length)
		return -ENOSPC;

	/* Select the needed input data processing function and call it */
	if (priv->frame.subbands == 8) { 
   
		if (sbc->endian == SBC_BE)
			sbc_enc_process_input =
				priv->enc_state.sbc_enc_process_input_8s_be;
		else
			sbc_enc_process_input =
				priv->enc_state.sbc_enc_process_input_8s_le;
	} else { 
   
		if (sbc->endian == SBC_BE)
			sbc_enc_process_input =
				priv->enc_state.sbc_enc_process_input_4s_be;
		else
			sbc_enc_process_input =
				priv->enc_state.sbc_enc_process_input_4s_le;
	}

	priv->enc_state.position = sbc_enc_process_input(
		priv->enc_state.position, (const uint8_t *) input,
		priv->enc_state.X, priv->frame.subbands * priv->frame.blocks,
		priv->frame.channels);

	samples = sbc_analyze_audio(&priv->enc_state, &priv->frame);

	if (priv->frame.mode == JOINT_STEREO) { 
   
		int j = priv->enc_state.sbc_calc_scalefactors_j(
			priv->frame.sb_sample_f, priv->frame.scale_factor,
			priv->frame.blocks, priv->frame.subbands);
		framelen = priv->pack_frame(output,
				&priv->frame, output_len, j);
	} else { 
   
		priv->enc_state.sbc_calc_scalefactors(
			priv->frame.sb_sample_f, priv->frame.scale_factor,
			priv->frame.blocks, priv->frame.channels,
			priv->frame.subbands);
		framelen = priv->pack_frame(output,
				&priv->frame, output_len, 0);
	}

	if (written)
		*written = framelen;

	return samples * priv->frame.channels * 2;
}

在这个函数中,首先进行了变量声明等操作;然后对priv->frame初始化,包含一个未打包的 SBC 数据帧;然后初始化编码器sbc_encoder_init():

// sbc.c
static void sbc_encoder_init(bool msbc, struct sbc_encoder_state *state,
						const struct sbc_frame *frame)
{ 
   
	memset(&state->X, 0, sizeof(state->X));
	state->position = (SBC_X_BUFFER_SIZE - frame->subbands * 9) & ~7;
	if (msbc)
		state->increment = 1;
	else
		state->increment = 4;

  // 检测CPU功能并设置功能指针
	sbc_init_primitives(state);
}

然后选择所需要的输入数据处理函数并调用它:

/* Select the needed input data processing function and call it */
if (priv->frame.subbands == 8) { 
   
	if (sbc->endian == SBC_BE)
		sbc_enc_process_input =
			priv->enc_state.sbc_enc_process_input_8s_be;
	else
		sbc_enc_process_input =
			priv->enc_state.sbc_enc_process_input_8s_le;
} else { 
   
	if (sbc->endian == SBC_BE)
		sbc_enc_process_input =
			priv->enc_state.sbc_enc_process_input_4s_be;
	else
		sbc_enc_process_input =
			priv->enc_state.sbc_enc_process_input_4s_le;
}

priv->enc_state.position = sbc_enc_process_input(
	priv->enc_state.position, (const uint8_t *) input,
	priv->enc_state.X, priv->frame.subbands * priv->frame.blocks,
	priv->frame.channels);

samples = sbc_analyze_audio(&priv->enc_state, &priv->frame);

if (priv->frame.mode == JOINT_STEREO) { 
   
	int j = priv->enc_state.sbc_calc_scalefactors_j(
		priv->frame.sb_sample_f, priv->frame.scale_factor,
		priv->frame.blocks, priv->frame.subbands);
	framelen = priv->pack_frame(output,
			&priv->frame, output_len, j);
} else { 
   
	priv->enc_state.sbc_calc_scalefactors(
		priv->frame.sb_sample_f, priv->frame.scale_factor,
		priv->frame.blocks, priv->frame.channels,
		priv->frame.subbands);
	framelen = priv->pack_frame(output,
			&priv->frame, output_len, 0);
}

最后计算编码前后的数据长度,修改编码后的数据长度,并返回编码前的长度:

if (written)
	*written = framelen;

return samples * priv->frame.channels * 2;
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/195011.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • setUp()和tearDown()函数

    setUp()和tearDown()函数

    2022年4月2日
    89
  • django常用命令_java命令行参数的使用方法

    django常用命令_java命令行参数的使用方法前言我们掌握了如何在命令提示符或PyCharm下创建Django项目和项目应用,无论是创建项目还是创建项目应用,都需要输入相关的指令才能得以实现,这些都是Django内置的操作指令。在PyChar

    2022年7月28日
    5
  • 此工作站和主域间的信任失败原因_电脑域改为工作组后无法登录

    此工作站和主域间的信任失败原因_电脑域改为工作组后无法登录Thedirectoryserverfailedtoautomaticallyupdateserviceaccount,dnsnameand/orportinformation.这个错误通常是由于访问的主机不能再确保可以和当前加入的活动目录域进行安全通信造成的。当前主机的私有安全凭据和域控制器中的值不匹配。当然简单的可以把安全凭据理解为密码,实际上你知道域环境通过非常严格Kerberos验证,因此实际是Kerberos的Keytable的加密存储在本地安全授权子系统中;

    2022年10月19日
    0
  • hibernate之二级缓存「建议收藏」

    hibernate之二级缓存「建议收藏」hibernate之二级缓存缓存的作用:通过缓存,可以减少与数据库的交互,提高数据库访问性能。即把需要的数据存储起来,不需要每次都请求,主要目地减少服务器压力。Hibernate缓存一般分三类:一级缓存(Session对象):Hibernate的内置缓存,必需的,默认启动,不能被卸载。由于Session对象的生命周期通常对应一个数据库事务,因此它的缓存是事务范围的缓存。在一级缓存中,持…

    2022年5月24日
    36
  • 死磕带通滤波器

    死磕带通滤波器带通滤波器的作用与陷波器类似,带通滤波器在数字电源控制领域有重要作用。比如在三相LCL逆变器的谐振抑制控制方面,通过带通滤波器可以提取谐振点附近的频谱做进一步的控制策略。在有源电力滤波器利用带通滤波器可以提取电网信号的基波频率从而做进一步的控制。带通滤波器传递函数带通滤波器的传递函数是:h(s)=AwoBss2+Bs+wo2h(s)=\frac{Aw_oBs}{s^2+Bs+w_o^2}h(s)=s2+Bs+wo2​Awo​Bs​其中,wow_owo​是带通的“中心频率”,也就是想要通过频率

    2022年6月7日
    41
  • idea设置文件头注释_idea设置方法注释

    idea设置文件头注释_idea设置方法注释idea和eclipse的注释还是有一些差别的。idea:类头注释:打开file->setting->Editor->FilrandCodeTemplates->Includes->FileHeader直接在右边的文件框里编辑你说需要注释的东西,然后应用保存之后,当你创建类的时候就会自动生成注释。方法注释:打开file->setting->Editor->LiveTemplate

    2022年9月1日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号