【Bluetooth sbcプロトコル】sbcソース読書ノート(3)——データ読み書きプロセス
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
",
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
",
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)
補足対象: