【藍牙sbc協議】sbc源碼閱讀筆記(三)——數據讀寫過程

sbc_編碼過程詳解


編碼部分源碼

// sbcenc.c
static void encode(char *filename, int subbands, int bitpool, int joint,
				int dualchannel, int snr, int blocks, bool msbc)
{
	struct au_header au_hdr;
	sbc_t sbc;
	int fd, size, srate, codesize, nframes;
	ssize_t encoded;
	ssize_t len;

	// 數據初始化
  ···

  // codesize = subbands * blocks *channels * 2
	codesize = sbc_get_codesize(&sbc);
  // read(fd, input, BE_INT(au_hdr.hdr_size) - len)
	nframes = sizeof(input) / codesize;
	while (1) {
		unsigned char *inp, *outp;
		/* read data for up to 'nframes' frames of input data */
		size = read(fd, input, codesize * nframes);
		if (size < 0) {
			/* Something really bad happened */
			perror("Can't read audio data");
			break;
		}
		if (size < codesize) {
			/* Not enough data for encoding even a single frame */
			break;
		}
		/* encode all the data from the input buffer in a loop */
		inp = input;
		outp = output;
		while (size >= codesize) {
			len = sbc_encode(&sbc, inp, codesize,
				outp, sizeof(output) - (outp - output),
				&encoded);
			if (len != codesize || encoded <= 0) {
				fprintf(stderr,
					"sbc_encode fail, len=%zd, encoded=%lu\n",
					len, (unsigned long) encoded);
				break;
			}
			size -= len;
			inp += len;
			outp += encoded;
		}
		len = write(fileno(stdout), output, outp - output);
		if (len != outp - output) {
			perror("Can't write SBC output");
			break;
		}
		if (size != 0) {
			/*
			 * sbc_encode failure has been detected earlier or end
			 * of file reached (have trailing partial data which is
			 * insufficient to encode SBC frame)
			 */
			break;
		}
	}

	sbc_finish(&sbc);
  ···
}

其中codesize爲編碼的長度,通過sbc_get_codesize求出,具體過程爲:

// sbc.c
SBC_EXPORT size_t sbc_get_codesize(sbc_t *sbc)
{
	uint16_t subbands, channels, blocks;
	struct sbc_priv *priv;

	priv = sbc->priv;
	if (!priv->init) {
		subbands = sbc->subbands ? 8 : 4;
		if (priv->msbc)
			blocks = MSBC_BLOCKS;
		else
			blocks = 4 + (sbc->blocks * 4);
		channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
	} else {
		subbands = priv->frame.subbands;
		blocks = priv->frame.blocks;
		channels = priv->frame.channels;
	}
	
	return subbands * blocks * channels * 2;
}

然後求出數據幀數nframes,其中input爲跳過頭部的額外字節:

nframes = sizeof(input) / codesize;

// input
#define BUF_SIZE 32768
static unsigned char input[BUF_SIZE];
/* Skip extra bytes of the header if any */
// #define BE_INT(v)		bswap_32(v)
// hdr.size: size of header (min 24)
// len = read(fd, &au_hdr, sizeof(au_hdr));
read(fd, input, BE_INT(au_hdr.hdr_size) - len);

接下來開始進入讀取數據部分,讀取全部nframe幀的數據:

/* read data for up to 'nframes' frames of input data */
size = read(fd, input, codesize * nframes);

然後在循環中對輸入緩衝區內的所有數據進行編碼,從下面代碼可以看出,對輸入的數據進行逐幀編碼,將編碼後的數據寫入output

/* encode all the data from the input buffer in a loop */
inp = input;
outp = output;
while (size >= codesize) {
	len = sbc_encode(&sbc, inp, codesize,
		outp, sizeof(output) - (outp - output),
		&encoded);
	if (len != codesize || encoded <= 0) {
		fprintf(stderr,
			"sbc_encode fail, len=%zd, encoded=%lu\n",
			len, (unsigned long) encoded);
		break;
	}
	size -= len;
	inp += len;
	outp += encoded;
}
len = write(fileno(stdout), output, outp - output);
if (len != outp - output) {
	perror("Can't write SBC output");
	break;
}
if (size != 0) {
	 /*
		* sbc_encode failure has been detected earlier or end
		* of file reached (have trailing partial data which is
		* insufficient to encode SBC frame)
		*/
	break;
}

以上就是編碼及寫入的整體過程,接下來研究具體的編碼過程,也就是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)

待補充內容:

  • sbc_encode詳解
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章