diff options
-rw-r--r-- | gst-libs/gst/audio/gstaudioringbuffer.c | 186 | ||||
-rw-r--r-- | gst-libs/gst/audio/gstaudioringbuffer.h | 8 |
2 files changed, 164 insertions, 30 deletions
diff --git a/gst-libs/gst/audio/gstaudioringbuffer.c b/gst-libs/gst/audio/gstaudioringbuffer.c index 017cecabf..bb433add1 100644 --- a/gst-libs/gst/audio/gstaudioringbuffer.c +++ b/gst-libs/gst/audio/gstaudioringbuffer.c @@ -539,11 +539,16 @@ gst_audio_ring_buffer_acquire (GstAudioRingBuffer * buf, goto was_acquired; buf->acquired = TRUE; + buf->need_reorder = FALSE; rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf); if (G_LIKELY (rclass->acquire)) res = rclass->acquire (buf, spec); + /* Only reorder for raw audio */ + buf->need_reorder = (buf->need_reorder + && buf->spec.type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW); + if (G_UNLIKELY (!res)) goto acquire_failed; @@ -1276,13 +1281,34 @@ no_start: } } -#define FWD_SAMPLES(s,se,d,de) \ + + +#define REORDER_SAMPLE(d, s, l) \ +G_STMT_START { \ + gint i; \ + for (i = 0; i < channels; i++) { \ + memcpy (d + reorder_map[i] * bps, s + i * bps, bps); \ + } \ +} G_STMT_END + +#define REORDER_SAMPLES(d, s, len) \ +G_STMT_START { \ + gint i, len_ = len / bpf; \ + guint8 *d_ = d, *s_ = s; \ + for (i = 0; i < len_; i++) { \ + REORDER_SAMPLE(d_, s_, bpf); \ + d_ += bpf; \ + s_ += bpf; \ + } \ +} G_STMT_END + +#define FWD_SAMPLES(s,se,d,de,F) \ G_STMT_START { \ /* no rate conversion */ \ guint towrite = MIN (se + bpf - s, de - d); \ /* simple copy */ \ if (!skip) \ - memcpy (d, s, towrite); \ + F (d, s, towrite); \ in_samples -= towrite / bpf; \ out_samples -= towrite / bpf; \ s += towrite; \ @@ -1290,12 +1316,12 @@ G_STMT_START { \ } G_STMT_END /* in_samples >= out_samples, rate > 1.0 */ -#define FWD_UP_SAMPLES(s,se,d,de) \ +#define FWD_UP_SAMPLES(s,se,d,de,F) \ G_STMT_START { \ guint8 *sb = s, *db = d; \ while (s <= se && d < de) { \ if (!skip) \ - memcpy (d, s, bpf); \ + F (d, s, bpf); \ s += bpf; \ *accum += outr; \ if ((*accum << 1) >= inr) { \ @@ -1309,12 +1335,12 @@ G_STMT_START { \ } G_STMT_END /* out_samples > in_samples, for rates smaller than 1.0 */ -#define FWD_DOWN_SAMPLES(s,se,d,de) \ +#define FWD_DOWN_SAMPLES(s,se,d,de,F) \ G_STMT_START { \ guint8 *sb = s, *db = d; \ while (s <= se && d < de) { \ if (!skip) \ - memcpy (d, s, bpf); \ + F (d, s, bpf); \ d += bpf; \ *accum += inr; \ if ((*accum << 1) >= outr) { \ @@ -1327,12 +1353,12 @@ G_STMT_START { \ GST_DEBUG ("fwd_down end %d/%d",*accum,*toprocess); \ } G_STMT_END -#define REV_UP_SAMPLES(s,se,d,de) \ +#define REV_UP_SAMPLES(s,se,d,de,F) \ G_STMT_START { \ guint8 *sb = se, *db = d; \ while (s <= se && d < de) { \ if (!skip) \ - memcpy (d, se, bpf); \ + F (d, se, bpf); \ se -= bpf; \ *accum += outr; \ while (d < de && (*accum << 1) >= inr) { \ @@ -1345,12 +1371,12 @@ G_STMT_START { \ GST_DEBUG ("rev_up end %d/%d",*accum,*toprocess); \ } G_STMT_END -#define REV_DOWN_SAMPLES(s,se,d,de) \ +#define REV_DOWN_SAMPLES(s,se,d,de,F) \ G_STMT_START { \ guint8 *sb = se, *db = d; \ while (s <= se && d < de) { \ if (!skip) \ - memcpy (d, se, bpf); \ + F (d, se, bpf); \ d += bpf; \ *accum += inr; \ while (s <= se && (*accum << 1) >= outr) { \ @@ -1368,20 +1394,25 @@ default_commit (GstAudioRingBuffer * buf, guint64 * sample, guint8 * data, gint in_samples, gint out_samples, gint * accum) { gint segdone; - gint segsize, segtotal, bpf, sps; + gint segsize, segtotal, channels, bps, bpf, sps; guint8 *dest, *data_end; gint writeseg, sampleoff; gint *toprocess; gint inr, outr; gboolean reverse; + gboolean need_reorder; g_return_val_if_fail (buf->memory != NULL, -1); g_return_val_if_fail (data != NULL, -1); + need_reorder = buf->need_reorder; + + channels = buf->spec.info.channels; dest = buf->memory; segsize = buf->spec.segsize; segtotal = buf->spec.segtotal; bpf = buf->spec.info.bpf; + bps = bpf / channels; sps = buf->samples_per_seg; reverse = out_samples < 0; @@ -1455,23 +1486,46 @@ default_commit (GstAudioRingBuffer * buf, guint64 * sample, GST_DEBUG_OBJECT (buf, "write @%p seg %d, sps %d, off %d, avail %d", dest + ws * segsize, ws, sps, sampleoff, avail); - if (G_LIKELY (inr == outr && !reverse)) { - /* no rate conversion, simply copy samples */ - FWD_SAMPLES (data, data_end, d, d_end); - } else if (!reverse) { - if (inr >= outr) - /* forward speed up */ - FWD_UP_SAMPLES (data, data_end, d, d_end); - else - /* forward slow down */ - FWD_DOWN_SAMPLES (data, data_end, d, d_end); + if (need_reorder) { + gint *reorder_map = buf->channel_reorder_map; + + if (G_LIKELY (inr == outr && !reverse)) { + /* no rate conversion, simply copy samples */ + FWD_SAMPLES (data, data_end, d, d_end, REORDER_SAMPLES); + } else if (!reverse) { + if (inr >= outr) + /* forward speed up */ + FWD_UP_SAMPLES (data, data_end, d, d_end, REORDER_SAMPLE); + else + /* forward slow down */ + FWD_DOWN_SAMPLES (data, data_end, d, d_end, REORDER_SAMPLE); + } else { + if (inr >= outr) + /* reverse speed up */ + REV_UP_SAMPLES (data, data_end, d, d_end, REORDER_SAMPLE); + else + /* reverse slow down */ + REV_DOWN_SAMPLES (data, data_end, d, d_end, REORDER_SAMPLE); + } } else { - if (inr >= outr) - /* reverse speed up */ - REV_UP_SAMPLES (data, data_end, d, d_end); - else - /* reverse slow down */ - REV_DOWN_SAMPLES (data, data_end, d, d_end); + if (G_LIKELY (inr == outr && !reverse)) { + /* no rate conversion, simply copy samples */ + FWD_SAMPLES (data, data_end, d, d_end, memcpy); + } else if (!reverse) { + if (inr >= outr) + /* forward speed up */ + FWD_UP_SAMPLES (data, data_end, d, d_end, memcpy); + else + /* forward slow down */ + FWD_DOWN_SAMPLES (data, data_end, d, d_end, memcpy); + } else { + if (inr >= outr) + /* reverse speed up */ + REV_UP_SAMPLES (data, data_end, d, d_end, memcpy); + else + /* reverse slow down */ + REV_DOWN_SAMPLES (data, data_end, d, d_end, memcpy); + } } /* for the next iteration we write to the next segment at the beginning. */ @@ -1572,18 +1626,22 @@ gst_audio_ring_buffer_read (GstAudioRingBuffer * buf, guint64 sample, guint8 * data, guint len) { gint segdone; - gint segsize, segtotal, bpf, sps; + gint segsize, segtotal, channels, bps, bpf, sps; guint8 *dest; guint to_read; + gboolean need_reorder; g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), -1); g_return_val_if_fail (buf->memory != NULL, -1); g_return_val_if_fail (data != NULL, -1); + need_reorder = buf->need_reorder; dest = buf->memory; segsize = buf->spec.segsize; segtotal = buf->spec.segtotal; + channels = buf->spec.info.channels; bpf = buf->spec.info.bpf; + bps = bpf / channels; sps = buf->samples_per_seg; to_read = len; @@ -1639,8 +1697,22 @@ gst_audio_ring_buffer_read (GstAudioRingBuffer * buf, guint64 sample, GST_DEBUG_OBJECT (buf, "read @%p seg %d, off %d, sampleslen %d", dest + readseg * segsize, readseg, sampleoff, sampleslen); - memcpy (data, dest + (readseg * segsize) + (sampleoff * bpf), - (sampleslen * bpf)); + if (need_reorder) { + guint8 *ptr = dest + (readseg * segsize) + (sampleoff * bpf); + gint i, j; + gint *reorder_map = buf->channel_reorder_map; + + /* Reorder from device order to GStreamer order */ + for (i = 0; i < sampleslen; i++) { + for (j = 0; j < channels; j++) { + memcpy (data + reorder_map[j] * bps, ptr + j * bps, bps); + } + ptr += bpf; + } + } else { + memcpy (data, dest + (readseg * segsize) + (sampleoff * bpf), + (sampleslen * bpf)); + } next: to_read -= sampleslen; @@ -1796,3 +1868,57 @@ gst_audio_ring_buffer_may_start (GstAudioRingBuffer * buf, gboolean allowed) GST_LOG_OBJECT (buf, "may start: %d", allowed); g_atomic_int_set (&buf->may_start, allowed); } + +/** + * gst_audio_ring_buffer_set_channel_positions: + * @buf: the #GstAudioRingBuffer + * @position: the device channel positions + * + * Tell the ringbuffer about the device's channel positions. This must + * be called in when the ringbuffer is acquired. + */ +void +gst_audio_ring_buffer_set_channel_positions (GstAudioRingBuffer * buf, + const GstAudioChannelPosition * position) +{ + const GstAudioChannelPosition *to; + gint channels; + gint i, j; + + g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf)); + g_return_if_fail (buf->acquired); + + channels = buf->spec.info.channels; + to = buf->spec.info.position; + + buf->need_reorder = FALSE; + if (memcmp (position, to, channels * sizeof (to[0])) == 0) + return; + + /* Build reorder map and check compatibility */ + for (i = 0; i < channels; i++) { + g_return_if_fail (position[i] == GST_AUDIO_CHANNEL_POSITION_NONE + || to[i] == GST_AUDIO_CHANNEL_POSITION_NONE); + g_return_if_fail (position[i] == GST_AUDIO_CHANNEL_POSITION_INVALID + || to[i] == GST_AUDIO_CHANNEL_POSITION_INVALID); + g_return_if_fail (position[i] == GST_AUDIO_CHANNEL_POSITION_MONO + || to[i] == GST_AUDIO_CHANNEL_POSITION_MONO); + + for (j = 0; j < channels; j++) { + if (position[i] == to[j]) { + buf->channel_reorder_map[i] = j; + break; + } + } + + /* Not all channels present in both */ + g_return_if_fail (j == channels); + } + + for (i = 0; i < channels; i++) { + if (buf->channel_reorder_map[i] != i) { + buf->need_reorder = TRUE; + break; + } + } +} diff --git a/gst-libs/gst/audio/gstaudioringbuffer.h b/gst-libs/gst/audio/gstaudioringbuffer.h index 5c1c52ef5..8bf6bfd87 100644 --- a/gst-libs/gst/audio/gstaudioringbuffer.h +++ b/gst-libs/gst/audio/gstaudioringbuffer.h @@ -123,6 +123,7 @@ struct _GstAudioRingBufferSpec GstAudioRingBufferFormatType type; GstAudioInfo info; + guint64 latency_time; /* the required/actual latency time, this is the * actual the size of one segment and the * minimum possible latency we can achieve. */ @@ -189,6 +190,10 @@ struct _GstAudioRingBuffer { GstAudioRingBufferCallback callback; gpointer cb_data; + gboolean need_reorder; + /* gst[channel_reorder_map[i]] = device[i] */ + gint channel_reorder_map[64]; + gboolean flushing; /* ATOMIC */ gint may_start; @@ -273,6 +278,9 @@ gboolean gst_audio_ring_buffer_release (GstAudioRingBuffer *buf); gboolean gst_audio_ring_buffer_is_acquired (GstAudioRingBuffer *buf); +/* set the device channel positions */ +void gst_audio_ring_buffer_set_channel_positions (GstAudioRingBuffer *buf, const GstAudioChannelPosition *position); + /* activating */ gboolean gst_audio_ring_buffer_activate (GstAudioRingBuffer *buf, gboolean active); gboolean gst_audio_ring_buffer_is_active (GstAudioRingBuffer *buf); |