]> code.delx.au - pulseaudio/blobdiff - src/pulsecore/resampler.c
Merge HUGE set of changes temporarily into a branch, to allow me to move them from...
[pulseaudio] / src / pulsecore / resampler.c
index 3827ff94a30e0049a6561eee4f8b5699453788c4..248d733747fbf0989b44babd0711136e5a9cb4d8 100644 (file)
@@ -53,8 +53,7 @@ struct pa_resampler {
 };
 
 struct impl_libsamplerate {
-    pa_memblock *buf1_block, *buf2_block, *buf3_block, *buf4_block;
-    float* buf1, *buf2, *buf3, *buf4;
+    pa_memchunk buf1, buf2, buf3, buf4;
     unsigned buf1_samples, buf2_samples, buf3_samples, buf4_samples;
 
     pa_convert_to_float32ne_func_t to_float32ne_func;
@@ -226,14 +225,14 @@ static void libsamplerate_free(pa_resampler *r) {
     if (u->src_state)
         src_delete(u->src_state);
 
-    if (u->buf1_block)
-        pa_memblock_unref(u->buf1_block);
-    if (u->buf2_block)
-        pa_memblock_unref(u->buf2_block);
-    if (u->buf3_block)
-        pa_memblock_unref(u->buf3_block);
-    if (u->buf4_block)
-        pa_memblock_unref(u->buf4_block);
+    if (u->buf1.memblock)
+        pa_memblock_unref(u->buf1.memblock);
+    if (u->buf2.memblock)
+        pa_memblock_unref(u->buf2.memblock);
+    if (u->buf3.memblock)
+        pa_memblock_unref(u->buf3.memblock);
+    if (u->buf4.memblock)
+        pa_memblock_unref(u->buf4.memblock);
     pa_xfree(u);
 }
 
@@ -272,64 +271,80 @@ static void calc_map_table(pa_resampler *r) {
     }
 }
 
-static float * convert_to_float(pa_resampler *r, void *input, unsigned n_frames) {
+static pa_memchunk* convert_to_float(pa_resampler *r, pa_memchunk *input) {
     struct impl_libsamplerate *u;
     unsigned n_samples;
+    void *src, *dst;
 
     assert(r);
     assert(input);
+    assert(input->memblock);
+
     assert(r->impl_data);
     u = r->impl_data;
 
     /* Convert the incoming sample into floats and place them in buf1 */
 
-    if (!u->to_float32ne_func)
+    if (!u->to_float32ne_func || !input->length)
         return input;
 
-    n_samples = n_frames * r->i_ss.channels;
+    n_samples = (input->length / r->i_fz) * r->i_ss.channels;
 
-    if (u->buf1_samples < n_samples) {
-        if (u->buf1_block)
-            pa_memblock_unref(u->buf1_block);
+    if (!u->buf1.memblock || u->buf1_samples < n_samples) {
+        if (u->buf1.memblock)
+            pa_memblock_unref(u->buf1.memblock);
 
         u->buf1_samples = n_samples;
-        u->buf1_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples);
-        u->buf1 = u->buf1_block->data;
+        u->buf1.memblock = pa_memblock_new(r->mempool, u->buf1.length = sizeof(float) * n_samples);
+        u->buf1.index = 0;
     }
 
-    u->to_float32ne_func(n_samples, input, u->buf1);
+    src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index;
+    dst = (uint8_t*) pa_memblock_acquire(u->buf1.memblock);
+    u->to_float32ne_func(n_samples, src, dst);
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(u->buf1.memblock);
+
+    u->buf1.length = sizeof(float) * n_samples;
 
-    return u->buf1;
+    return &u->buf1;
 }
 
-static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) {
+static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) {
     struct impl_libsamplerate *u;
-    unsigned n_samples;
+    unsigned n_samples, n_frames;
     int i_skip, o_skip;
     unsigned oc;
+    float *src, *dst;
 
     assert(r);
     assert(input);
+    assert(input->memblock);
+
     assert(r->impl_data);
     u = r->impl_data;
 
     /* Remap channels and place the result int buf2 */
 
-    if (!u->map_required)
+    if (!u->map_required || !input->length)
         return input;
 
-    n_samples = n_frames * r->o_ss.channels;
+    n_samples = input->length / sizeof(float);
+    n_frames = n_samples / r->o_ss.channels;
 
-    if (u->buf2_samples < n_samples) {
-        if (u->buf2_block)
-            pa_memblock_unref(u->buf2_block);
+    if (!u->buf2.memblock || u->buf2_samples < n_samples) {
+        if (u->buf2.memblock)
+            pa_memblock_unref(u->buf2.memblock);
 
         u->buf2_samples = n_samples;
-        u->buf2_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples);
-        u->buf2 = u->buf2_block->data;
+        u->buf2.memblock = pa_memblock_new(r->mempool, u->buf2.length = sizeof(float) * n_samples);
+        u->buf2.index = 0;
     }
 
-    memset(u->buf2, 0, n_samples * sizeof(float));
+    src = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
+    dst = (float*) pa_memblock_acquire(u->buf2.memblock);
+
+    memset(dst, 0, n_samples * sizeof(float));
 
     o_skip = sizeof(float) * r->o_ss.channels;
     i_skip = sizeof(float) * r->i_ss.channels;
@@ -340,49 +355,57 @@ static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) {
 
         for (i = 0; i < PA_CHANNELS_MAX && u->map_table[oc][i] >= 0; i++)
             oil_vectoradd_f32(
-                u->buf2 + oc, o_skip,
-                u->buf2 + oc, o_skip,
-                input + u->map_table[oc][i], i_skip,
+                dst + oc, o_skip,
+                dst + oc, o_skip,
+                src + u->map_table[oc][i], i_skip,
                 n_frames,
                 &one, &one);
     }
 
-    return u->buf2;
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(u->buf2.memblock);
+
+    u->buf2.length = n_frames * sizeof(float) * r->o_ss.channels;
+
+    return &u->buf2;
 }
 
-static float *resample(pa_resampler *r, float *input, unsigned *n_frames) {
+static pa_memchunk *resample(pa_resampler *r, pa_memchunk *input) {
     struct impl_libsamplerate *u;
     SRC_DATA data;
+    unsigned in_n_frames, in_n_samples;
     unsigned out_n_frames, out_n_samples;
     int ret;
 
     assert(r);
     assert(input);
-    assert(n_frames);
     assert(r->impl_data);
     u = r->impl_data;
 
     /* Resample the data and place the result in buf3 */
 
-    if (!u->src_state)
+    if (!u->src_state || !input->length)
         return input;
 
-    out_n_frames = (*n_frames*r->o_ss.rate/r->i_ss.rate)+1024;
+    in_n_samples = input->length / sizeof(float);
+    in_n_frames = in_n_samples * r->o_ss.channels;
+
+    out_n_frames = (in_n_frames*r->o_ss.rate/r->i_ss.rate)+1024;
     out_n_samples = out_n_frames * r->o_ss.channels;
 
-    if (u->buf3_samples < out_n_samples) {
-        if (u->buf3_block)
-            pa_memblock_unref(u->buf3_block);
+    if (!u->buf3.memblock || u->buf3_samples < out_n_samples) {
+        if (u->buf3.memblock)
+            pa_memblock_unref(u->buf3.memblock);
 
         u->buf3_samples = out_n_samples;
-        u->buf3_block = pa_memblock_new(r->mempool, sizeof(float) * out_n_samples);
-        u->buf3 = u->buf3_block->data;
+        u->buf3.memblock = pa_memblock_new(r->mempool, u->buf3.length = sizeof(float) * out_n_samples);
+        u->buf3.index = 0;
     }
 
-    data.data_in = input;
-    data.input_frames = *n_frames;
+    data.data_in = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
+    data.input_frames = in_n_frames;
 
-    data.data_out = u->buf3;
+    data.data_out = (float*) pa_memblock_acquire(u->buf3.memblock);
     data.output_frames = out_n_frames;
 
     data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate;
@@ -390,16 +413,20 @@ static float *resample(pa_resampler *r, float *input, unsigned *n_frames) {
 
     ret = src_process(u->src_state, &data);
     assert(ret == 0);
-    assert((unsigned) data.input_frames_used == *n_frames);
+    assert((unsigned) data.input_frames_used == in_n_frames);
 
-    *n_frames = data.output_frames_gen;
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(u->buf3.memblock);
 
-    return u->buf3;
+    u->buf3.length = data.output_frames_gen * sizeof(float) * r->o_ss.channels;
+
+    return &u->buf3;
 }
 
-static void *convert_from_float(pa_resampler *r, float *input, unsigned n_frames) {
+static pa_memchunk *convert_from_float(pa_resampler *r, pa_memchunk *input) {
     struct impl_libsamplerate *u;
-    unsigned n_samples;
+    unsigned n_samples, n_frames;
+    void *src, *dst;
 
     assert(r);
     assert(input);
@@ -408,30 +435,35 @@ static void *convert_from_float(pa_resampler *r, float *input, unsigned n_frames
 
     /* Convert the data into the correct sample type and place the result in buf4 */
 
-    if (!u->from_float32ne_func)
+    if (!u->from_float32ne_func || !input->length)
         return input;
 
+    n_frames = input->length / sizeof(float) / r->o_ss.channels;
     n_samples = n_frames * r->o_ss.channels;
 
     if (u->buf4_samples < n_samples) {
-        if (u->buf4_block)
-            pa_memblock_unref(u->buf4_block);
+        if (u->buf4.memblock)
+            pa_memblock_unref(u->buf4.memblock);
 
         u->buf4_samples = n_samples;
-        u->buf4_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples);
-        u->buf4 = u->buf4_block->data;
+        u->buf4.memblock = pa_memblock_new(r->mempool, u->buf4.length = r->o_fz * n_frames);
+        u->buf4.index = 0;
     }
 
-    u->from_float32ne_func(n_samples, input, u->buf4);
+    src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->length;
+    dst = pa_memblock_acquire(u->buf4.memblock);
+    u->from_float32ne_func(n_samples, src, dst);
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(u->buf4.memblock);
 
-    return u->buf4;
+    u->buf4.length = r->o_fz * n_frames;
+
+    return &u->buf4;
 }
 
 static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) {
     struct impl_libsamplerate *u;
-    float *buf;
-    void *input, *output;
-    unsigned n_frames;
+    pa_memchunk *buf;
 
     assert(r);
     assert(in);
@@ -443,55 +475,23 @@ static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchun
 
     u = r->impl_data;
 
-    input = ((uint8_t*) in->memblock->data + in->index);
-    n_frames = in->length / r->i_fz;
-    assert(n_frames > 0);
-
-    buf = convert_to_float(r, input, n_frames);
-    buf = remap_channels(r, buf, n_frames);
-    buf = resample(r, buf, &n_frames);
-
-    if (n_frames) {
-        output = convert_from_float(r, buf, n_frames);
-
-        if (output == input) {
-            /* Mm, no adjustment has been necessary, so let's return the original block */
-            out->memblock = pa_memblock_ref(in->memblock);
-            out->index = in->index;
-            out->length = in->length;
-        } else {
-            out->length = n_frames * r->o_fz;
-            out->index = 0;
-            out->memblock = NULL;
-
-            if (output == u->buf1) {
-                u->buf1 = NULL;
-                u->buf1_samples = 0;
-                out->memblock = u->buf1_block;
-                u->buf1_block = NULL;
-            } else if (output == u->buf2) {
-                u->buf2 = NULL;
-                u->buf2_samples = 0;
-                out->memblock = u->buf2_block;
-                u->buf2_block = NULL;
-            } else if (output == u->buf3) {
-                u->buf3 = NULL;
-                u->buf3_samples = 0;
-                out->memblock = u->buf3_block;
-                u->buf3_block = NULL;
-            } else if (output == u->buf4) {
-                u->buf4 = NULL;
-                u->buf4_samples = 0;
-                out->memblock = u->buf4_block;
-                u->buf4_block = NULL;
-            }
-
-            assert(out->memblock);
-        }
-    } else {
-        out->memblock = NULL;
-        out->index = out->length = 0;
-    }
+    buf = convert_to_float(r, (pa_memchunk*) in);
+    buf = remap_channels(r, buf);
+    buf = resample(r, buf);
+
+    if (buf->length) {
+        buf = convert_from_float(r, buf);
+        *out = *buf;
+
+        if (buf == in)
+            pa_memblock_ref(buf->memblock);
+        else
+            pa_memchunk_reset(buf);
+    } else
+        pa_memchunk_reset(out);
+
+    pa_memblock_release(in->memblock);
+
 }
 
 static void libsamplerate_update_input_rate(pa_resampler *r, uint32_t rate) {
@@ -518,8 +518,10 @@ static int libsamplerate_init(pa_resampler *r) {
 
     r->impl_data = u = pa_xnew(struct impl_libsamplerate, 1);
 
-    u->buf1 = u->buf2 = u->buf3 = u->buf4 = NULL;
-    u->buf1_block = u->buf2_block = u->buf3_block = u->buf4_block = NULL;
+    pa_memchunk_reset(&u->buf1);
+    pa_memchunk_reset(&u->buf2);
+    pa_memchunk_reset(&u->buf3);
+    pa_memchunk_reset(&u->buf4);
     u->buf1_samples = u->buf2_samples = u->buf3_samples = u->buf4_samples = 0;
 
     if (r->i_ss.format == PA_SAMPLE_FLOAT32NE)
@@ -580,6 +582,7 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out
         /* Do real resampling */
         size_t l;
         unsigned o_index;
+        void *src, *dst;
 
         /* The length of the new memory block rounded up */
         l = ((((n_frames+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz;
@@ -587,6 +590,9 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out
         out->index = 0;
         out->memblock = pa_memblock_new(r->mempool, l);
 
+        src = (uint8_t*) pa_memblock_acquire(in->memblock) + in->index;
+        dst = pa_memblock_acquire(out->memblock);
+
         for (o_index = 0;; o_index++, u->o_counter++) {
             unsigned j;
 
@@ -596,13 +602,16 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out
             if (j >= n_frames)
                 break;
 
-            assert(o_index*fz < out->memblock->length);
+            assert(o_index*fz < pa_memblock_get_length(out->memblock));
 
-            memcpy((uint8_t*) out->memblock->data + fz*o_index,
-                   (uint8_t*) in->memblock->data + in->index + fz*j, fz);
+            memcpy((uint8_t*) dst + fz*o_index,
+                   (uint8_t*) src + fz*j, fz);
 
         }
 
+        pa_memblock_release(in->memblock);
+        pa_memblock_release(out->memblock);
+
         out->length = o_index*fz;
     }