OSDN Git Service

Make sbc codec to write directly in application buffers and so avoiding memcpys.
authorLuiz Augusto von Dentz <luiz.dentz@openbossa.org>
Mon, 12 Nov 2007 18:15:59 +0000 (18:15 +0000)
committerLuiz Augusto von Dentz <luiz.dentz@openbossa.org>
Mon, 12 Nov 2007 18:15:59 +0000 (18:15 +0000)
audio/gstsbcdec.c
audio/gstsbcenc.c
audio/pcm_bluetooth.c
sbc/sbc.c
sbc/sbc.h
sbc/sbcdec.c
sbc/sbcenc.c

index 98504d4..a60c3e6 100644 (file)
@@ -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)
index 0e9daed..e1c480a 100644 (file)
@@ -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);
index 89ce896..04eabf2 100644 (file)
@@ -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;
        }
index c95862a..ec1cc37 100644 (file)
--- 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;
+}
index 72512c0..d55587d 100644 (file)
--- 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
index 866b844..09a211a 100644 (file)
@@ -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) {
index 94b9f64..cba31c7 100644 (file)
@@ -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;
                }