【蓝牙sbc协议】sbc源码阅读笔记(一)——编码过程
sbcenc.c
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;} } elsefd = 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));elseperror("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_ENDIANsbc->endian = SBC_LE; #elif __BYTE_ORDER == __BIG_ENDIANsbc->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;elseblocks = 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;elsepriv->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;elsesbc_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;elsesbc_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源码阅读笔记(一)——编码过程相关推荐
- [Linux] USB-Storage驱动 源码阅读笔记(一)
USB-Storage驱动 源码阅读笔记--从USB子系统开始 最近在研究U盘的驱动,遇到很多难以理解的问题,虽然之前也参考过一些很不错的书籍如:<USB那些事>,但最终还是觉得下载一份最 ...
- Transformers包tokenizer.encode()方法源码阅读笔记
Transformers包tokenizer.encode()方法源码阅读笔记_天才小呵呵的博客-CSDN博客_tokenizer.encode
- 源码阅读笔记 BiLSTM+CRF做NER任务 流程图
源码阅读笔记 BiLSTM+CRF做NER任务(二) 源码地址:https://github.com/ZhixiuYe/NER-pytorch 本篇正式进入源码的阅读,按照流程顺序,一一解剖. 一.流 ...
- 代码分析:NASM源码阅读笔记
NASM源码阅读笔记 NASM(Netwide Assembler)的使用文档和代码间的注释相当齐全,这给阅读源码 提供了很大的方便.按作者的说法,这是一个模块化的,可重用的x86汇编器, 而且能够被 ...
- CI框架源码阅读笔记4 引导文件CodeIgniter.php
到了这里,终于进入CI框架的核心了.既然是"引导"文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http:// ...
- Yii源码阅读笔记 - 日志组件
2015-03-09 一 By youngsterxyf 使用 Yii框架为开发者提供两个静态方法进行日志记录: Yii::log($message, $level, $category); Yii: ...
- AQS源码阅读笔记(一)
AQS源码阅读笔记 先看下这个类张非常重要的一个静态内部类Node.如下: static final class Node {//表示当前节点以共享模式等待锁static final Node SHA ...
- 【Flink】Flink 源码阅读笔记(20)- Flink 基于 Mailbox 的线程模型
1.概述 转载:Flink 源码阅读笔记(20)- Flink 基于 Mailbox 的线程模型 相似文章:[Flink]Flink 基于 MailBox 实现的 StreamTask 线程模型 Fl ...
- 【Flink】Flink 源码阅读笔记(18)- Flink SQL 中的流和动态表
1.概述 转载:Flink 源码阅读笔记(18)- Flink SQL 中的流和动态表
- 【Flink】Flink 源码阅读笔记(16)- Flink SQL 的元数据管理
1.概述 转载:Flink 源码阅读笔记(16)- Flink SQL 的元数据管理 Flink 源码阅读笔记(17)- Flink SQL 中的时间属
最新文章
- Overleaf-LaTex表格制作
- python编程语言是什么-Python编程语言的特点是什么?老男孩Python学习
- 一篇文章教会你使用html+css3制作GIF图
- ng-options track by 思考
- JAVA里16进制和字节数组互转
- asp.net 的web.config文件编写
- java定时任务管理_基于SpringBoot+layui秒级定时任务管理:JTimer for JAVA项目
- 开发基础框架:mybatis-3.2.8 +hibernate4.0+spring3.0+struts2.3
- 记事本写小程序C语言,抖音上用记事本编写爱心小程序教程
- 《大学》全文及白话翻译
- Matlab实现雷达波位编排
- [Frank kelly] 经济学理论对TCP的收敛性和公平性做出分析,从理论上论证了TCP在互联网环境下的稳定性和有效性
- ubuntu系统压力测试工具--stress
- Android端简单数据库实现
- 软件测试的16种测试类型
- 解决go数据表查询结构体对应字段null问题(sqlx converting NULL to string is unsupported)
- 交换机配置计算机mac地址吗,局域网管理,设置网络核心交换机,局域网电脑IP-MAC地址绑定...
- js -- 打开新窗口(window.open)、关闭窗口(window.close)
- 用 Python 实现英文单词纠错功能!这样就不担心不会辅导孩子了!
- Blockchain for Internet of Energy management: Review, solutions, and challenges
热门文章
- java如何通过域名查ip_Java实现通过IP获取域名,通过域名获取IP
- java excel checkbox_在Java窗体表格中插入复选框
- 关于图片格式的选择,jpg、png、gif、svg
- 国稻种芯百团计划行动 丰收节贸促会·黎志康:惠及亚非18国家
- 首届IBC“社会影响力奖”表彰行业多元化、可持续发展和伦理领导
- 工业和信息化部工业企业问卷调查系统
- 高位十字星收盘什么意思?高位十字星缩量是什么?
- 计算机二级excel设置宏,Excel2013中为宏指定快捷键的方法
- 不是美工,如何使用ps快速更换图标icon的颜色?
- cyj等于什么英语单词_英语解题方法指导及例题分析