【蓝牙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)
上一篇 2025年10月25日 下午5:22
下一篇 2025年10月25日 下午6:01


相关推荐

  • 快来“千模百炼”全球AI开发者锦标赛,养一只真正的OpenClaw大虾!

    快来“千模百炼”全球AI开发者锦标赛,养一只真正的OpenClaw大虾!

    2026年3月12日
    3
  • Ganglia源码安装

    Ganglia源码安装太久没写博客了 突然心血来潮 记录下自己折腾了一个上午的 ganglia 安装流程 一 套路 Ganglia 是伯克利开发的一个集群监控软件 可以监视和显示集群中的节点的各种状态信息 比如如 cpu mem 硬盘利用率 I O 负载 网络流量情况等 同时可以将历史数据以曲线方式通过 php 页面呈现 二 功能简介 Gmetad 这个程序负责周期性的到各个 datasource 收集各个 c

    2026年3月20日
    2
  • LWIP使用解析_lwip tcp

    LWIP使用解析_lwip tcp1:环境STM32F407RT-thread2:结构体使用最上层:structrt_stm32_ethstructrt_stm32_eth{/*inheritfromethernetdevice*/structeth_deviceparent;/*interfaceaddressinfo,hwaddress*/rt_uint8_tdev_addr[MAX_ADDR_LEN];/*ETH_Speed*/

    2025年6月21日
    7
  • DropDownList的常用属性和事件「建议收藏」

    DropDownList的常用属性和事件「建议收藏」SelectedItem属性设置或获取下拉菜单的选中项,该属性的类型为System.Web.UI.WebControls.ListItem.所有列表控件(ListControl)中的项都是该类型,它

    2022年7月3日
    58
  • 大数据平台建设经验「建议收藏」

    大数据平台建设经验「建议收藏」大数据平台建设技术背景Facebook的DREP原则!!思路建设流程经验教训生产案例饿了么大数据平台建设大数据平台逻辑架构图工具链架构图!!流入三个源数据流的UV计算渠道订单一个大数据平台省了20个IT人力——敦奴数据平台建设案例分享引跑科技副总裁张晓东:引跑DBone数据库助力大数据建设需求挖掘五步曲,快速建设大数据项目整合公司3个网站后台管理子系统的经验总结-实现多系统的单点登录(ASP.N

    2022年6月12日
    38
  • CompoundButton 源码分析

    CompoundButton 源码分析原文地址:https://github.com/Tikitoo/AndroidSdkSourceAnalysis/blob/master/article/CompoundButton%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90.md CompoundButton是一个有两种状态(选中和未选中/checkdunchecked)的Button。当你按下(pres…

    2022年6月7日
    36

发表回复

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

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