From 397d6c2b3bc7661f978c1777442d33fd86ada21e Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 12 Nov 2007 18:15:59 +0000 Subject: Make sbc codec to write directly in application buffers and so avoiding memcpys. --- audio/gstsbcdec.c | 17 +++++---- audio/gstsbcenc.c | 30 +++++++++------- audio/pcm_bluetooth.c | 24 ++++++------- sbc/sbc.c | 98 +++++++++++++++++++++++++++++++-------------------- sbc/sbc.h | 14 ++++---- sbc/sbcdec.c | 20 +++++------ sbc/sbcenc.c | 23 ++++++------ 7 files changed, 127 insertions(+), 99 deletions(-) diff --git a/audio/gstsbcdec.c b/audio/gstsbcdec.c index 98504d4d..a60c3e69 100644 --- a/audio/gstsbcdec.c +++ b/audio/gstsbcdec.c @@ -58,10 +58,11 @@ static GstFlowReturn sbc_dec_chain(GstPad *pad, GstBuffer *buffer) { GstSbcDec *dec = GST_SBC_DEC(gst_pad_get_parent(pad)); GstFlowReturn res = GST_FLOW_OK; - guint size, offset = 0; + guint size, codesize, offset = 0; guint8 *data; GstClockTime timestamp; + codesize = sbc_get_codesize(&dec->sbc); timestamp = GST_BUFFER_TIMESTAMP(buffer); if (dec->buffer) { @@ -82,10 +83,6 @@ static GstFlowReturn sbc_dec_chain(GstPad *pad, GstBuffer *buffer) GstCaps *caps, *temp; int consumed; - consumed = sbc_decode(&dec->sbc, data + offset, size - offset); - if (consumed <= 0) - break; - caps = gst_caps_new_simple("audio/x-raw-int", "rate", G_TYPE_INT, dec->sbc.rate, "channels", G_TYPE_INT, dec->sbc.channels, @@ -100,14 +97,20 @@ static GstFlowReturn sbc_dec_chain(GstPad *pad, GstBuffer *buffer) res = gst_pad_alloc_buffer_and_set_caps(dec->srcpad, GST_BUFFER_OFFSET_NONE, - dec->sbc.len, temp, &output); + codesize, temp, &output); gst_caps_unref(temp); if (res != GST_FLOW_OK) goto done; - memcpy(GST_BUFFER_DATA(output), dec->sbc.data, dec->sbc.len); + consumed = sbc_decode(&dec->sbc, data + offset, size - offset, + GST_BUFFER_DATA(output), codesize, + NULL); + if (consumed <= 0) + break; + + GST_BUFFER_TIMESTAMP(output) = GST_BUFFER_TIMESTAMP(buffer); res = gst_pad_push(dec->srcpad, output); if (res != GST_FLOW_OK) diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 0e9daed1..e1c480a0 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -134,10 +134,11 @@ static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc, GstCaps *caps) enc->sbc.rate = rate; enc->sbc.channels = channels; - if (enc->mode == 0) - enc->sbc.joint = CFG_MODE_JOINT_STEREO; - else - enc->sbc.joint = enc->mode; + if (enc->mode == CFG_MODE_AUTO) + enc->mode = CFG_MODE_JOINT_STEREO; + + if (enc->mode == CFG_MODE_MONO || enc->mode == CFG_MODE_JOINT_STEREO) + enc->sbc.joint = 1; enc->sbc.blocks = enc->blocks; enc->sbc.subbands = enc->subbands; @@ -247,8 +248,10 @@ static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) GstSbcEnc *enc = GST_SBC_ENC(gst_pad_get_parent(pad)); GstAdapter *adapter = enc->adapter; GstFlowReturn res = GST_FLOW_OK; - gint codesize = enc->sbc.subbands * enc->sbc.blocks * enc->sbc.channels * 2; + gint codesize, frame_len; + codesize = sbc_get_codesize(&enc->sbc); + frame_len = sbc_get_frame_length(&enc->sbc); gst_adapter_push(adapter, buffer); while (gst_adapter_available(adapter) >= codesize && res == GST_FLOW_OK) { @@ -257,20 +260,22 @@ static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) const guint8 *data; int consumed; + caps = GST_PAD_CAPS(enc->srcpad); + + res = gst_pad_alloc_buffer_and_set_caps(enc->srcpad, + GST_BUFFER_OFFSET_NONE, + frame_len, caps, &output); + data = gst_adapter_peek(adapter, codesize); - consumed = sbc_encode(&enc->sbc, (gpointer) data, codesize); + consumed = sbc_encode(&enc->sbc, (gpointer) data, codesize, + GST_BUFFER_DATA(output), frame_len, + NULL); if (consumed <= 0) { GST_ERROR ("comsumed < 0, codesize: %d", codesize); break; } gst_adapter_flush(adapter, consumed); - caps = GST_PAD_CAPS(enc->srcpad); - - res = gst_pad_alloc_buffer_and_set_caps(enc->srcpad, - GST_BUFFER_OFFSET_NONE, - enc->sbc.len, caps, &output); - if (res != GST_FLOW_OK) goto done; @@ -282,7 +287,6 @@ static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) goto done; } - memcpy(GST_BUFFER_DATA(output), enc->sbc.data, enc->sbc.len); GST_BUFFER_TIMESTAMP(output) = GST_BUFFER_TIMESTAMP(buffer); res = gst_pad_push(enc->srcpad, output); diff --git a/audio/pcm_bluetooth.c b/audio/pcm_bluetooth.c index 89ce8965..04eabf24 100644 --- a/audio/pcm_bluetooth.c +++ b/audio/pcm_bluetooth.c @@ -666,7 +666,7 @@ static snd_pcm_sframes_t bluetooth_a2dp_write(snd_pcm_ioplug_t *io, struct bluetooth_a2dp *a2dp = &data->a2dp; snd_pcm_sframes_t ret = 0; snd_pcm_uframes_t frames_to_read, frames_left = size; - int frame_size, encoded; + int frame_size, encoded, written; uint8_t *buff; DBG("areas->step=%u areas->first=%u offset=%lu size=%lu", @@ -728,30 +728,30 @@ static snd_pcm_sframes_t bluetooth_a2dp_write(snd_pcm_ioplug_t *io, } /* Enough data to encode (sbc wants 1k blocks) */ - encoded = sbc_encode(&(a2dp->sbc), data->buffer, a2dp->codesize); + encoded = sbc_encode(&(a2dp->sbc), data->buffer, a2dp->codesize, + a2dp->buffer, sizeof(a2dp->buffer), + &written); if (encoded <= 0) { DBG("Encoding error %d", encoded); goto done; } data->count -= encoded; + a2dp->count += written; + a2dp->frame_count++; + a2dp->samples += encoded / frame_size; + a2dp->nsamples += encoded / frame_size; - DBG("encoded=%d a2dp.sbc.len=%d count=%d", encoded, - a2dp->sbc.len, a2dp->count); + DBG("encoded=%d written=%d count=%d", encoded, + written, a2dp->count); - /* Send previously encoded buffer */ - if (a2dp->count + a2dp->sbc.len >= data->cfg.pkt_len) { + /* No space left for another frame then send */ + if (a2dp->count + written >= data->cfg.pkt_len) { avdtp_write(data); DBG("sending packet %d, count %d, pkt_len %u", c, old_count, data->cfg.pkt_len); } - memcpy(a2dp->buffer + a2dp->count, a2dp->sbc.data, a2dp->sbc.len); - a2dp->count += a2dp->sbc.len; - a2dp->frame_count++; - a2dp->samples += encoded / frame_size; - a2dp->nsamples += encoded / frame_size; - ret += frames_to_read; frames_left -= frames_to_read; } 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; } -- cgit