zl程序教程

您现在的位置是:首页 >  工具

当前栏目

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

源码笔记协议 详解 函数 阅读 蓝牙 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