【蓝牙sbc协议】sbc源码阅读笔记(四)——sbc_encode函数详解
2023-06-13 09:13:39 时间
大家好,又见面了,我是你们的朋友全栈君。
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.cn/195011.html原文链接:https://javaforall.cn
相关文章
- mysql-5.7.38启动流程源码解读
- Spring Framework 源码学习笔记(一)
- Spring Framework 源码学习笔记(五)
- MyBatis 源码学习笔记(二)- MyBatis 进阶(Part B)
- 卡盟网站程序源码,支持无限分站,货源共享「建议收藏」
- React源码学习入门(三)React源码codebase架构和调试介绍
- ArrayList 源码笔记
- 从分治思维谈”责任链模式“(含源码下载)
- STL源码剖析_traits特性萃取技术
- java蛋糕店蛋糕商城蛋糕系统网站源码
- Android 蓝牙源码学习笔记
- Postgresql源码(100)Portal与事务的关系(顶层事务与子事务)
- Linux源码学习笔记day5 内存0地址处放的都是些什么玩意儿?
- 【Android Gradle 插件】将自定义 Gradle 插件上传到自建 Maven 仓库 ③ ( 配置上传工件 | 将 Gradle 插件 jar 包、源码、文档上传到本地Maven 仓库 )
- 直击灵魂!美团大牛手撸并发原理笔记,由浅入深剖析JDK源码
- 使用make编译源码,使用-j 参数的作用详解程序员
- Linux yum源码包安装和卸载过程详解版
- 探秘Linux操作系统中网卡源码的实现原理(linux网卡源码)
- 结构MySQL源码分析:探究目录结构(mysql 源码 目录)
- Redis 源码下载:一站式服务(redis 源码下载)
- 破解MySQL源码包,立即下载!(mysql 源码包 下载)
- php图片上传存储源码并且可以预览
- Android笔记之:CM9源码下载与编译的应用
- Cocos2d-x学习笔记之HelloWorld源码分析