summaryrefslogtreecommitdiffstats
path: root/sbc
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.dentz@openbossa.org>2007-11-12 18:15:59 +0000
committerLuiz Augusto von Dentz <luiz.dentz@openbossa.org>2007-11-12 18:15:59 +0000
commit397d6c2b3bc7661f978c1777442d33fd86ada21e (patch)
tree7ac2b0d3768715896e286eab291dccfde333cfb8 /sbc
parentf89c7796c7882c65e829e5203a79606c3d1d63b0 (diff)
Make sbc codec to write directly in application buffers and so avoiding memcpys.
Diffstat (limited to 'sbc')
-rw-r--r--sbc/sbc.c98
-rw-r--r--sbc/sbc.h14
-rw-r--r--sbc/sbcdec.c20
-rw-r--r--sbc/sbcenc.c23
4 files changed, 88 insertions, 67 deletions
diff --git a/sbc/sbc.c b/sbc/sbc.c
index c95862a0..ec1cc37d 100644
--- a/sbc/sbc.c
+++ b/sbc/sbc.c
@@ -95,6 +95,8 @@ struct sbc_frame {
} allocation_method;
uint8_t subbands;
uint8_t bitpool;
+ uint8_t codesize;
+ uint8_t length;
/* bit number x set means joint stereo has been used in subband x */
uint8_t join;
@@ -1230,23 +1232,24 @@ int sbc_init(sbc_t *sbc, unsigned long flags)
return 0;
}
-int sbc_parse(sbc_t *sbc, void *data, int count)
+int sbc_parse(sbc_t *sbc, void *input, int input_len)
{
- return sbc_decode(sbc, data, count);
+ return sbc_decode(sbc, input, input_len, NULL, 0, NULL);
}
-int sbc_decode(sbc_t *sbc, void *data, int count)
+int sbc_decode(sbc_t *sbc, void *input, int input_len, void *output,
+ int output_len, int *written)
{
struct sbc_priv *priv;
char *ptr;
int i, ch, framelen, samples;
- if (!sbc)
+ if (!sbc && !input)
return -EIO;
priv = sbc->priv;
- framelen = sbc_unpack_frame(data, &priv->frame, count);
+ framelen = sbc_unpack_frame(input, &priv->frame, input_len);
if (!priv->init) {
sbc_decoder_init(&priv->dec_state, &priv->frame);
@@ -1257,26 +1260,23 @@ int sbc_decode(sbc_t *sbc, void *data, int count)
sbc->subbands = priv->frame.subbands;
sbc->blocks = priv->frame.blocks;
sbc->bitpool = priv->frame.bitpool;
+
+ priv->frame.codesize = sbc_get_codesize(sbc);
+ priv->frame.length = sbc_get_frame_length(sbc);
}
- samples = sbc_synthesize_audio(&priv->dec_state, &priv->frame);
+ if (!output)
+ return framelen;
- if (!sbc->data) {
- sbc->size = samples * priv->frame.channels * 2;
- sbc->data = malloc(sbc->size);
- }
+ if (written)
+ *written = 0;
- if (sbc->size < samples * priv->frame.channels * 2) {
- sbc->size = samples * priv->frame.channels * 2;
- sbc->data = realloc(sbc->data, sbc->size);
- }
+ samples = sbc_synthesize_audio(&priv->dec_state, &priv->frame);
- if (!sbc->data) {
- sbc->size = 0;
- return -ENOMEM;
- }
+ ptr = output;
- ptr = sbc->data;
+ if (output_len < samples * priv->frame.channels * 2)
+ samples = output_len / (priv->frame.channels * 2);
for (i = 0; i < samples; i++) {
for (ch = 0; ch < priv->frame.channels; ch++) {
@@ -1293,22 +1293,27 @@ int sbc_decode(sbc_t *sbc, void *data, int count)
}
}
- sbc->len = samples * priv->frame.channels * 2;
+ if (written)
+ *written = samples * priv->frame.channels * 2;
return framelen;
}
-int sbc_encode(sbc_t *sbc, void *data, int count)
+int sbc_encode(sbc_t *sbc, void *input, int input_len, void *output,
+ int output_len, int *written)
{
struct sbc_priv *priv;
char *ptr;
int i, ch, framelen, samples;
- if (!sbc)
+ if (!sbc && !input)
return -EIO;
priv = sbc->priv;
+ if (written)
+ *written = 0;
+
if (!priv->init) {
priv->frame.sampling_frequency = sbc->rate;
priv->frame.channels = sbc->channels;
@@ -1325,16 +1330,22 @@ int sbc_encode(sbc_t *sbc, void *data, int count)
priv->frame.subbands = sbc->subbands;
priv->frame.blocks = sbc->blocks;
priv->frame.bitpool = sbc->bitpool;
+ priv->frame.codesize = sbc_get_codesize(sbc);
+ priv->frame.length = sbc_get_frame_length(sbc);
sbc_encoder_init(&priv->enc_state, &priv->frame);
priv->init = 1;
}
/* input must be large enough to encode a complete frame */
- if (count < priv->frame.subbands * priv->frame.blocks * sbc->channels * 2)
+ if (input_len < priv->frame.codesize)
return 0;
- ptr = data;
+ /* output must be large enough to receive the encoded frame */
+ if (!output || output_len < priv->frame.length)
+ return -ENOSPC;
+
+ ptr = input;
for (i = 0; i < priv->frame.subbands * priv->frame.blocks; i++) {
for (ch = 0; ch < sbc->channels; ch++) {
@@ -1351,19 +1362,10 @@ int sbc_encode(sbc_t *sbc, void *data, int count)
samples = sbc_analyze_audio(&priv->enc_state, &priv->frame);
- if (!sbc->data) {
- sbc->size = 1024;
- sbc->data = malloc(sbc->size);
- }
-
- if (!sbc->data) {
- sbc->size = 0;
- return -ENOMEM;
- }
+ framelen = sbc_pack_frame(output, &priv->frame, output_len);
- framelen = sbc_pack_frame(sbc->data, &priv->frame, sbc->size);
-
- sbc->len = framelen;
+ if (written)
+ *written = framelen;
sbc->duration = (1000000 * priv->frame.subbands * priv->frame.blocks) / sbc->rate;
@@ -1375,11 +1377,29 @@ void sbc_finish(sbc_t *sbc)
if (!sbc)
return;
- if (sbc->data)
- free(sbc->data);
-
if (sbc->priv)
free(sbc->priv);
memset(sbc, 0, sizeof(sbc_t));
}
+
+int sbc_get_frame_length(sbc_t *sbc)
+{
+ int ret;
+
+ ret = 4 + (4 * sbc->subbands * sbc->channels) / 8;
+
+ /* This term is not always evenly devide so we round it up */
+ if (sbc->channels == 1)
+ ret += ((sbc->blocks * sbc->channels * sbc->bitpool) + 7) / 8;
+ else
+ ret += ((sbc->joint * sbc->subbands + sbc->blocks * sbc->bitpool)
+ + 7) / 8;
+
+ return ret;
+}
+
+int sbc_get_codesize(sbc_t *sbc)
+{
+ return sbc->subbands * sbc->blocks * sbc->channels * 2;
+}
diff --git a/sbc/sbc.h b/sbc/sbc.h
index 72512c02..d55587d0 100644
--- a/sbc/sbc.h
+++ b/sbc/sbc.h
@@ -42,10 +42,6 @@ struct sbc_struct {
int bitpool;
int swap;
- void *data;
- int size;
- int len;
-
unsigned long duration;
void *priv;
@@ -54,9 +50,13 @@ struct sbc_struct {
typedef struct sbc_struct sbc_t;
int sbc_init(sbc_t *sbc, unsigned long flags);
-int sbc_parse(sbc_t *sbc, void *data, int count);
-int sbc_decode(sbc_t *sbc, void *data, int count);
-int sbc_encode(sbc_t *sbc, void *data, int count);
+int sbc_parse(sbc_t *sbc, void *input, int input_len);
+int sbc_decode(sbc_t *sbc, void *input, int input_len, void *output,
+ int output_len, int *len);
+int sbc_encode(sbc_t *sbc, void *input, int input_len, void *output,
+ int output_len, int *written);
+int sbc_get_frame_length(sbc_t *sbc);
+int sbc_get_codesize(sbc_t *sbc);
void sbc_finish(sbc_t *sbc);
#ifdef __cplusplus
diff --git a/sbc/sbcdec.c b/sbc/sbcdec.c
index 866b8448..09a211a1 100644
--- a/sbc/sbcdec.c
+++ b/sbc/sbcdec.c
@@ -46,7 +46,7 @@ static void decode(char *filename, char *output, int tofile)
struct stat st;
off_t filesize;
sbc_t sbc;
- int fd, ad, pos, streamlen, framelen, count, written;
+ int fd, ad, pos, streamlen, framelen, count, written, len;
int format = AFMT_S16_BE;
if (stat(filename, &st) < 0) {
@@ -97,7 +97,7 @@ static void decode(char *filename, char *output, int tofile)
sbc_init(&sbc, 0L);
sbc.swap = 1;
- framelen = sbc_decode(&sbc, stream, streamlen);
+ framelen = sbc_decode(&sbc, stream, streamlen, buf, sizeof(buf), &len);
printf("%d Hz, %d channels\n", sbc.rate, sbc.channels);
if (!tofile) {
if (ioctl(ad, SNDCTL_DSP_SETFMT, &format) < 0) {
@@ -125,7 +125,7 @@ static void decode(char *filename, char *output, int tofile)
* length of the frame we just decoded count is the number of
* decoded bytes yet to be written */
- if (count + sbc.len > BUF_SIZE) {
+ if (count + len > BUF_SIZE) {
/* buffer is too full to stuff decoded audio in so it
* must be written to the device */
written = write(ad, buf, count);
@@ -134,23 +134,23 @@ static void decode(char *filename, char *output, int tofile)
}
/* sanity check */
- if (count + sbc.len > BUF_SIZE) {
+ if (count + len > BUF_SIZE) {
fprintf(stderr,
"buffer size of %d is too small for decoded"
- " data (%d)\n", BUF_SIZE, sbc.len + count);
+ " data (%d)\n", BUF_SIZE, len + count);
exit(1);
}
- /* move the latest decoded data into buf and increase
- * the count */
- memcpy(buf + count, sbc.data, sbc.len);
- count += sbc.len;
+ /* increase the count */
+ count += len;
/* push the pointer in the file forward to the next bit to be
* decoded tell the decoder to decode up to the remaining
* length of the file (!) */
pos += framelen;
- framelen = sbc_decode(&sbc, stream + pos, streamlen - pos);
+ framelen = sbc_decode(&sbc, stream + pos, streamlen - pos,
+ buf + count, sizeof(buf) - count,
+ &len);
}
if (count > 0) {
diff --git a/sbc/sbcenc.c b/sbc/sbcenc.c
index 94b9f642..cba31c7b 100644
--- a/sbc/sbcenc.c
+++ b/sbc/sbcenc.c
@@ -104,9 +104,9 @@ static ssize_t __write(int fd, const void *buf, size_t count)
static void encode(char *filename, int subbands, int joint)
{
struct au_header *au_hdr;
- unsigned char buf[2048];
+ unsigned char input[2048], output[2048];
sbc_t sbc;
- int fd, len, size, count;
+ int fd, len, size, count, encoded;
if (strcmp(filename, "-")) {
fd = open(filename, O_RDONLY);
@@ -118,7 +118,7 @@ static void encode(char *filename, int subbands, int joint)
} else
fd = fileno(stdin);
- len = __read(fd, buf, sizeof(buf));
+ len = __read(fd, input, sizeof(input));
if (len < sizeof(*au_hdr)) {
if (fd > fileno(stderr))
fprintf(stderr, "Can't read header from file %s: %s\n",
@@ -128,7 +128,7 @@ static void encode(char *filename, int subbands, int joint)
goto done;
}
- au_hdr = (struct au_header *) buf;
+ au_hdr = (struct au_header *) input;
if (au_hdr->magic != AU_MAGIC ||
BE_INT(au_hdr->hdr_size) > 128 ||
@@ -147,11 +147,11 @@ static void encode(char *filename, int subbands, int joint)
sbc.swap = 1;
count = BE_INT(au_hdr->data_size);
size = len - BE_INT(au_hdr->hdr_size);
- memmove(buf, buf + BE_INT(au_hdr->hdr_size), size);
+ memmove(input, input + BE_INT(au_hdr->hdr_size), size);
while (1) {
- if (size < sizeof(buf)) {
- len = __read(fd, buf + size, sizeof(buf) - size);
+ if (size < sizeof(input)) {
+ len = __read(fd, input + size, sizeof(input) - size);
if (len == 0)
break;
@@ -163,17 +163,18 @@ static void encode(char *filename, int subbands, int joint)
size += len;
}
- len = sbc_encode(&sbc, buf, size);
+ len = sbc_encode(&sbc, input, size, output, sizeof(output),
+ &encoded);
if (len < size)
- memmove(buf, buf + len, size - len);
+ memmove(input, input + len, size - len);
size -= len;
- len = __write(fileno(stdout), sbc.data, sbc.len);
+ len = __write(fileno(stdout), output, encoded);
if (len == 0)
break;
- if (len < 0 || len != sbc.len) {
+ if (len < 0 || len != encoded) {
perror("Can't write SBC output");
break;
}