main(int argc, char *argv[])
首先设定 option 的默认值,然后根据用户命令设定 option 相关参数。
对指定文件进行编码(执行encode函数)
usage(void)
打印相关option:
Option | Option | 打印帮助信息 |
---|---|---|
h | help | 打印帮助信息 |
v | verbose | 详细模式 |
m | msbc | mSBC编解码器 |
s | subbands | 子带数量(4/8) |
b | bitpool | Bitpool value |
j | joint | 联合立体声 |
d | dualchannel | 双声道 |
S | snr | 信噪比模式(default/loudness) |
B | blocks | block数量(4/8/12/16) |
encode(char *filename, int subbands, int bitpool, int joint, int dualchannel, int snr, int blocks, bool msbc)
定义一个 au_header
类型的变量au_hdr
// formats.h struct au_header { uint32_t magic; /* '.snd' */ uint32_t hdr_size; /* size of header (min 24) */ uint32_t data_size; /* size of data */ uint32_t encoding; /* see to AU_FMT_XXXX */ uint32_t sample_rate; /* sample rate */ uint32_t channels; /* number of channels (voices) */ };
定义一个sbc_t
类型的变量sbc
// sbc.h struct sbc_struct { unsigned long flags; uint8_t frequency; uint8_t blocks; uint8_t subbands; uint8_t mode; uint8_t allocation; uint8_t bitpool; uint8_t endian; void *priv; void *priv_alloc_base; }; typedef struct sbc_struct sbc_t;
定义ssize_t
类型的变量encoded
和len
,实际是ssize_t
就是long
类型。
// _types.h typedef long __darwin_ssize_t; /* byte count or error */ // _ssize_t.h typedef __darwin_ssize_t ssize_t;
检测au_hdr
的长度是否是24。
if (sizeof(au_hdr) != 24) {
/* Sanity check just in case */
fprintf(stderr, "FIXME: sizeof(au_hdr) != 24\n");
return;
}
确定指定文件合法性并打开文件。
if (strcmp(filename, "-")) {
fd = open(filename, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "Can't open file %s: %s\n",
filename, strerror(errno));
return;
}
} else
fd = fileno(stdin);
将文件中头部数据读入au_hdr
,并确定是否读取成功。
len = read(fd, &au_hdr, sizeof(au_hdr));
if (len < (ssize_t) sizeof(au_hdr)) {
if (fd > fileno(stderr))
fprintf(stderr, "Can't read header from file %s: %s\n",
filename, strerror(errno));
else
perror("Can't read audio header");
goto done;
}
确定文件的格式是否符合Sun/NeXT audio S16_BE
格式。
if (au_hdr.magic != AU_MAGIC ||
BE_INT(au_hdr.hdr_size) > 128 ||
BE_INT(au_hdr.hdr_size) < sizeof(au_hdr) ||
BE_INT(au_hdr.encoding) != AU_FMT_LIN16) {
fprintf(stderr, "Not in Sun/NeXT audio S16_BE format\n");
goto done;
}
判断使用sbc编码还是msbc编码。
sbc
sbc
。// sbc.c // sbc_init() SBC_EXPORT int sbc_init(sbc_t *sbc, unsigned long flags) { if (!sbc) return -EIO; memset(sbc, 0, sizeof(sbc_t)); sbc->priv_alloc_base = malloc(sizeof(struct sbc_priv) + SBC_ALIGN_MASK); if (!sbc->priv_alloc_base) return -ENOMEM; sbc->priv = (void *) (((uintptr_t) sbc->priv_alloc_base + SBC_ALIGN_MASK) & ~((uintptr_t) SBC_ALIGN_MASK)); memset(sbc->priv, 0, sizeof(struct sbc_priv)); sbc_set_defaults(sbc, flags); return 0; } // sbc_set_defaults() static void sbc_set_defaults(sbc_t *sbc, unsigned long flags) { struct sbc_priv *priv = sbc->priv; if (priv->msbc) { priv->pack_frame = msbc_pack_frame; priv->unpack_frame = msbc_unpack_frame; } else { priv->pack_frame = sbc_pack_frame; priv->unpack_frame = sbc_unpack_frame; } sbc->flags = flags; sbc->frequency = SBC_FREQ_44100; sbc->mode = SBC_MODE_STEREO; sbc->subbands = SBC_SB_8; sbc->blocks = SBC_BLK_16; sbc->bitpool = 32; #if __BYTE_ORDER == __LITTLE_ENDIAN sbc->endian = SBC_LE; #elif __BYTE_ORDER == __BIG_ENDIAN sbc->endian = SBC_BE; #else #error "Unknown byte order" #endif }
switch (BE_INT(au_hdr.sample_rate)) {
case 16000:
sbc.frequency = SBC_FREQ_16000;
break;
case 32000:
sbc.frequency = SBC_FREQ_32000;
break;
case 44100:
sbc.frequency = SBC_FREQ_44100;
break;
case 48000:
sbc.frequency = SBC_FREQ_48000;
break;
}
srate = BE_INT(au_hdr.sample_rate);
sbc.subbands = subbands == 4 ? SBC_SB_4 : SBC_SB_8;
if (BE_INT(au_hdr.channels) == 1) {
sbc.mode = SBC_MODE_MONO;
if (joint || dualchannel) {
fprintf(stderr, "Audio is mono but joint or "
"dualchannel mode has been specified\n");
goto done;
}
} else if (joint && !dualchannel)
sbc.mode = SBC_MODE_JOINT_STEREO;
else if (!joint && dualchannel)
sbc.mode = SBC_MODE_DUAL_CHANNEL;
else if (!joint && !dualchannel)
sbc.mode = SBC_MODE_STEREO;
else {
fprintf(stderr, "Both joint and dualchannel "
"mode have been specified\n");
goto done;
}
sbc.endian = SBC_BE;
sbc.bitpool = bitpool;
sbc.allocation = snr ? SBC_AM_SNR : SBC_AM_LOUDNESS;
sbc.blocks = blocks == 4 ? SBC_BLK_4 :
blocks == 8 ? SBC_BLK_8 :
blocks == 12 ? SBC_BLK_12 : SBC_BLK_16;
mSBC
sbc
。// sbc.c SBC_EXPORT int sbc_init_msbc(sbc_t *sbc, unsigned long flags) { struct sbc_priv *priv; if (!sbc) return -EIO; memset(sbc, 0, sizeof(sbc_t)); sbc->priv_alloc_base = malloc(sizeof(struct sbc_priv) + SBC_ALIGN_MASK); if (!sbc->priv_alloc_base) return -ENOMEM; sbc->priv = (void *) (((uintptr_t) sbc->priv_alloc_base + SBC_ALIGN_MASK) & ~((uintptr_t) SBC_ALIGN_MASK)); memset(sbc->priv, 0, sizeof(struct sbc_priv)); priv = sbc->priv; priv->msbc = true; sbc_set_defaults(sbc, flags); sbc->frequency = SBC_FREQ_16000; sbc->blocks = MSBC_BLOCKS; sbc->subbands = SBC_SB_8; sbc->mode = SBC_MODE_MONO; sbc->allocation = SBC_AM_LOUDNESS; sbc->bitpool = 26; return 0; }
读入文件数据,并显示详细信息
/* Skip extra bytes of the header if any */
if (read(fd, input, BE_INT(au_hdr.hdr_size) - len) < 0)
goto done;
if (verbose) {
fprintf(stderr, "encoding %s with rate %d, %d blocks, "
"%d subbands, %d bits, allocation method %s, "
"and mode %s\n",
filename, srate, blocks, subbands, bitpool,
sbc.allocation == SBC_AM_SNR ? "SNR" : "LOUDNESS",
sbc.mode == SBC_MODE_MONO ? "MONO" :
sbc.mode == SBC_MODE_STEREO ?
"STEREO" : "JOINTSTEREO");
}
获取编码长度codesize
及帧数nframes
。
codesize = sbc_get_codesize(&sbc);
nframes = sizeof(input) / 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; }
编码。
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.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; 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; } SBC_EXPORT void sbc_finish(sbc_t *sbc) { if (!sbc) return; free(sbc->priv_alloc_base); memset(sbc, 0, sizeof(sbc_t)); }
关闭文件。
done:
if (fd > fileno(stderr))
close(fd);
}