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

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;

你可能感兴趣的:(音频处理)