【蓝牙sbc协议】sbc源码阅读笔记(一)——编码过程

sbcenc.c

  1. main(int argc, char *argv[])

    首先设定 option 的默认值,然后根据用户命令设定 option 相关参数。

    对指定文件进行编码(执行encode函数)

  2. 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)
  3. 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类型的变量encodedlen,实际是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

    1. 初始化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
    }
    
    1. 设置采样率、子带数量等参数。
    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

    1. 初始化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);
    }
    

你可能感兴趣的:(音频处理,蓝牙协议,sbc协议,sbc源码,源码阅读)