【蓝牙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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • lammps教程:薄膜渗透模拟(3)–不同孔隙率对过滤效果的影响

    lammps教程:薄膜渗透模拟(3)–不同孔隙率对过滤效果的影响本文是薄膜渗透过滤的最后一篇文章:不同孔隙率薄膜建模。孔隙或空位缺陷的建模原理比较简单:删除一定数量的原子就可以。lammps自带delete_atoms可以随机删除一定比例的原子,如果对孔隙或空位的形状、尺寸等有特殊需求,需要用编程的方法删除原子。delete_atomsporosity命令可随时产生设定比例的原子,如删除50%的原子:delete_atomsporositymembrane0.5482793membrane为原子组0.5为删除原子的比例482793为随机数种子

    2025年8月31日
    3
  • 第30件事 定义需求优先级的4种方法

    第30件事 定义需求优先级的4种方法

    2021年6月6日
    132
  • 公司测试环境k8s节点故障解决

    公司测试环境k8s节点故障解决

    2021年5月29日
    156
  • preference用法for_interference用法

    preference用法for_interference用法文章目录PreferenceFragment简介PreferenceFragment使用PreferenceFragment扩展PreferenceFragment简介在我们写一个项目的时候,基本都有选项设置界面,这类设置界面的原理基本都是本地的一些个性化设置,通过读取本地设置来改变某些差异显示(例如字体大小,主题颜色,WIFI自动下载等)。这些设置一般都会使用Preference来保存,…

    2025年9月30日
    5
  • Java事务详解[通俗易懂]

    Java事务详解[通俗易懂]1.什么是JAVA事务?通常的观念认为,事务仅与数据库相关。事务必须服从ISO/IEC所制定的ACID原则。ACID是原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)的缩写。事务的原子性:表示事务执行过程中的任何失败都将导致事务所做的任何修改失效。事务的一致性:表示当事务执行失败时,所有被该事务影响的数据…

    2022年9月1日
    4
  • H264解码过滤花屏视频帧

    H264解码过滤花屏视频帧众所周知视频在各个领域占有极为重要的地位,安防领域,互联网,医药,教育等等等等。扯淡我就尽量不多扯了,现主要扯安防领域吧,安防领域尤其是视频分析领域,视频质量要求比较苛刻。下面介绍一下场景比较苛刻的图片情况:1.这种2.这种花屏现象,在视频接入解码过程中尤为常见,(比如28181接入,rtsp等等),解码大家都考虑使用ffmpeg进行解码,首先考虑的可能是解码错误直接从解码过程…

    2022年6月16日
    89

发表回复

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

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