sbcenc.c revision 5592142cb9383df0556b27ac59e96547b380310b
1/* 2 * 3 * Bluetooth low-complexity, subband codec (SBC) encoder 4 * 5 * Copyright (C) 2008-2010 Nokia Corporation 6 * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org> 7 * 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 * 23 */ 24 25#ifdef HAVE_CONFIG_H 26#include <config.h> 27#endif 28 29#include <stdio.h> 30#include <errno.h> 31#include <fcntl.h> 32#include <unistd.h> 33#include <stdlib.h> 34#include <stdint.h> 35#include <string.h> 36#include <getopt.h> 37#include <sys/stat.h> 38 39#include "sbc.h" 40#include "formats.h" 41 42static int verbose = 0; 43 44#define BUF_SIZE 32768 45static unsigned char input[BUF_SIZE], output[BUF_SIZE + BUF_SIZE / 4]; 46 47static void encode(char *filename, int subbands, int bitpool, int joint, 48 int dualchannel, int snr, int blocks) 49{ 50 struct au_header au_hdr; 51 sbc_t sbc; 52 int fd, size, srate, codesize, nframes; 53 size_t encoded; 54 ssize_t len; 55 56 if (sizeof(au_hdr) != 24) { 57 /* Sanity check just in case */ 58 fprintf(stderr, "FIXME: sizeof(au_hdr) != 24\n"); 59 return; 60 } 61 62 if (strcmp(filename, "-")) { 63 fd = open(filename, O_RDONLY); 64 if (fd < 0) { 65 fprintf(stderr, "Can't open file %s: %s\n", 66 filename, strerror(errno)); 67 return; 68 } 69 } else 70 fd = fileno(stdin); 71 72 len = read(fd, &au_hdr, sizeof(au_hdr)); 73 if (len < (ssize_t) sizeof(au_hdr)) { 74 if (fd > fileno(stderr)) 75 fprintf(stderr, "Can't read header from file %s: %s\n", 76 filename, strerror(errno)); 77 else 78 perror("Can't read audio header"); 79 goto done; 80 } 81 82 if (au_hdr.magic != AU_MAGIC || 83 BE_INT(au_hdr.hdr_size) > 128 || 84 BE_INT(au_hdr.hdr_size) < sizeof(au_hdr) || 85 BE_INT(au_hdr.encoding) != AU_FMT_LIN16) { 86 fprintf(stderr, "Not in Sun/NeXT audio S16_BE format\n"); 87 goto done; 88 } 89 90 sbc_init(&sbc, 0L); 91 92 switch (BE_INT(au_hdr.sample_rate)) { 93 case 16000: 94 sbc.frequency = SBC_FREQ_16000; 95 break; 96 case 32000: 97 sbc.frequency = SBC_FREQ_32000; 98 break; 99 case 44100: 100 sbc.frequency = SBC_FREQ_44100; 101 break; 102 case 48000: 103 sbc.frequency = SBC_FREQ_48000; 104 break; 105 } 106 107 srate = BE_INT(au_hdr.sample_rate); 108 109 sbc.subbands = subbands == 4 ? SBC_SB_4 : SBC_SB_8; 110 111 if (BE_INT(au_hdr.channels) == 1) { 112 sbc.mode = SBC_MODE_MONO; 113 if (joint || dualchannel) { 114 fprintf(stderr, "Audio is mono but joint or " 115 "dualchannel mode has been specified\n"); 116 goto done; 117 } 118 } else if (joint && !dualchannel) 119 sbc.mode = SBC_MODE_JOINT_STEREO; 120 else if (!joint && dualchannel) 121 sbc.mode = SBC_MODE_DUAL_CHANNEL; 122 else if (!joint && !dualchannel) 123 sbc.mode = SBC_MODE_STEREO; 124 else { 125 fprintf(stderr, "Both joint and dualchannel mode have been " 126 "specified\n"); 127 goto done; 128 } 129 130 sbc.endian = SBC_BE; 131 /* Skip extra bytes of the header if any */ 132 if (read(fd, input, BE_INT(au_hdr.hdr_size) - len) < 0) 133 goto done; 134 135 sbc.bitpool = bitpool; 136 sbc.allocation = snr ? SBC_AM_SNR : SBC_AM_LOUDNESS; 137 sbc.blocks = blocks == 4 ? SBC_BLK_4 : 138 blocks == 8 ? SBC_BLK_8 : 139 blocks == 12 ? SBC_BLK_12 : SBC_BLK_16; 140 141 if (verbose) { 142 fprintf(stderr, "encoding %s with rate %d, %d blocks, " 143 "%d subbands, %d bits, allocation method %s, " 144 "and mode %s\n", 145 filename, srate, blocks, subbands, bitpool, 146 sbc.allocation == SBC_AM_SNR ? "SNR" : "LOUDNESS", 147 sbc.mode == SBC_MODE_MONO ? "MONO" : 148 sbc.mode == SBC_MODE_STEREO ? 149 "STEREO" : "JOINTSTEREO"); 150 } 151 152 codesize = sbc_get_codesize(&sbc); 153 nframes = sizeof(input) / codesize; 154 while (1) { 155 unsigned char *inp, *outp; 156 /* read data for up to 'nframes' frames of input data */ 157 size = read(fd, input, codesize * nframes); 158 if (size < 0) { 159 /* Something really bad happened */ 160 perror("Can't read audio data"); 161 break; 162 } 163 if (size < codesize) { 164 /* Not enough data for encoding even a single frame */ 165 break; 166 } 167 /* encode all the data from the input buffer in a loop */ 168 inp = input; 169 outp = output; 170 while (size >= codesize) { 171 len = sbc_encode(&sbc, inp, codesize, 172 outp, sizeof(output) - (outp - output), 173 &encoded); 174 if (len != codesize || encoded <= 0) { 175 fprintf(stderr, 176 "sbc_encode fail, len=%zd, encoded=%lu\n", 177 len, (unsigned long) encoded); 178 break; 179 } 180 size -= len; 181 inp += len; 182 outp += encoded; 183 } 184 len = write(fileno(stdout), output, outp - output); 185 if (len != outp - output) { 186 perror("Can't write SBC output"); 187 break; 188 } 189 if (size != 0) { 190 /* 191 * sbc_encode failure has been detected earlier or end 192 * of file reached (have trailing partial data which is 193 * insufficient to encode SBC frame) 194 */ 195 break; 196 } 197 } 198 199 sbc_finish(&sbc); 200 201done: 202 if (fd > fileno(stderr)) 203 close(fd); 204} 205 206static void usage(void) 207{ 208 printf("SBC encoder utility ver %s\n", VERSION); 209 printf("Copyright (c) 2004-2010 Marcel Holtmann\n\n"); 210 211 printf("Usage:\n" 212 "\tsbcenc [options] file(s)\n" 213 "\n"); 214 215 printf("Options:\n" 216 "\t-h, --help Display help\n" 217 "\t-v, --verbose Verbose mode\n" 218 "\t-s, --subbands Number of subbands to use (4 or 8)\n" 219 "\t-b, --bitpool Bitpool value (default is 32)\n" 220 "\t-j, --joint Joint stereo\n" 221 "\t-d, --dualchannel Dual channel\n" 222 "\t-S, --snr Use SNR mode (default is loudness)\n" 223 "\t-B, --blocks Number of blocks (4, 8, 12 or 16)\n" 224 "\n"); 225} 226 227static struct option main_options[] = { 228 { "help", 0, 0, 'h' }, 229 { "verbose", 0, 0, 'v' }, 230 { "subbands", 1, 0, 's' }, 231 { "bitpool", 1, 0, 'b' }, 232 { "joint", 0, 0, 'j' }, 233 { "dualchannel",0, 0, 'd' }, 234 { "snr", 0, 0, 'S' }, 235 { "blocks", 1, 0, 'B' }, 236 { 0, 0, 0, 0 } 237}; 238 239int main(int argc, char *argv[]) 240{ 241 int i, opt, subbands = 8, bitpool = 32, joint = 0, dualchannel = 0; 242 int snr = 0, blocks = 16; 243 244 while ((opt = getopt_long(argc, argv, "+hvs:b:jdSB:", 245 main_options, NULL)) != -1) { 246 switch(opt) { 247 case 'h': 248 usage(); 249 exit(0); 250 251 case 'v': 252 verbose = 1; 253 break; 254 255 case 's': 256 subbands = atoi(optarg); 257 if (subbands != 8 && subbands != 4) { 258 fprintf(stderr, "Invalid subbands\n"); 259 exit(1); 260 } 261 break; 262 263 case 'b': 264 bitpool = atoi(optarg); 265 break; 266 267 case 'j': 268 joint = 1; 269 break; 270 271 case 'd': 272 dualchannel = 1; 273 break; 274 275 case 'S': 276 snr = 1; 277 break; 278 279 case 'B': 280 blocks = atoi(optarg); 281 if (blocks != 16 && blocks != 12 && 282 blocks != 8 && blocks != 4) { 283 fprintf(stderr, "Invalid blocks\n"); 284 exit(1); 285 } 286 break; 287 288 default: 289 usage(); 290 exit(1); 291 } 292 } 293 294 argc -= optind; 295 argv += optind; 296 optind = 0; 297 298 if (argc < 1) { 299 usage(); 300 exit(1); 301 } 302 303 for (i = 0; i < argc; i++) 304 encode(argv[i], subbands, bitpool, joint, dualchannel, 305 snr, blocks); 306 307 return 0; 308} 309