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