Commit 6be25240 authored by Sebastian Dröge's avatar Sebastian Dröge

API: Add buffer clipping function for raw audio buffers. Fixes #456656.

Original commit message from CVS:
* docs/libs/gst-plugins-base-libs-sections.txt:
* gst-libs/gst/audio/audio.c: (gst_audio_buffer_clip):
* gst-libs/gst/audio/audio.h:
* tests/check/libs/audio.c: (GST_START_TEST), (audio_suite):
API: Add buffer clipping function for raw audio buffers. Fixes #456656.
Also add deprecation guards for gst_audio_structure_set_int() to the
header.
parent 14e30102
2007-07-23 Sebastian Dröge <slomo@circular-chaos.org>
* docs/libs/gst-plugins-base-libs-sections.txt:
* gst-libs/gst/audio/audio.c: (gst_audio_buffer_clip):
* gst-libs/gst/audio/audio.h:
* tests/check/libs/audio.c: (GST_START_TEST), (audio_suite):
API: Add buffer clipping function for raw audio buffers. Fixes #456656.
Also add deprecation guards for gst_audio_structure_set_int() to the
header.
2007-07-23 Stefan Kost <ensonic@users.sf.net>
* docs/libs/gst-plugins-base-libs-sections.txt:
......@@ -17,6 +17,7 @@ gst_audio_frame_length
gst_audio_duration_from_pad_buffer
gst_audio_is_buffer_framed
gst_audio_structure_set_int
gst_audio_buffer_clip
</SECTION>
<SECTION>
......
......@@ -251,3 +251,162 @@ gst_audio_structure_set_int (GstStructure * structure, GstAudioFieldFlag flag)
_gst_audio_structure_set_list (structure, "signed", G_TYPE_BOOLEAN, 2, TRUE,
FALSE, NULL);
}
/**
* gst_audio_buffer_clip:
* @buffer: The buffer to clip.
* @segment: Segment in %GST_FORMAT_TIME or %GST_FORMAT_DEFAULT to which the buffer should be clipped.
* @rate: sample rate.
* @frame_size: size of one audio frame in bytes.
*
* Clip the the buffer to the given %GstSegment.
*
* After calling this function do not reference @buffer anymore.
*
* Returns: %NULL if the buffer is completely outside the configured segment,
* otherwise the clipped buffer is returned.
*
* Since: 0.10.14
*/
GstBuffer *
gst_audio_buffer_clip (GstBuffer * buffer, GstSegment * segment, gint rate,
gint frame_size)
{
GstBuffer *ret;
GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
guint64 offset = GST_BUFFER_OFFSET_NONE, offset_end = GST_BUFFER_OFFSET_NONE;
guint8 *data;
guint size;
gboolean change_duration = TRUE, change_offset = TRUE, change_offset_end =
TRUE;
g_return_val_if_fail (segment->format == GST_FORMAT_TIME ||
segment->format == GST_FORMAT_DEFAULT, buffer);
g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
g_return_val_if_fail (GST_BUFFER_TIMESTAMP_IS_VALID (buffer), buffer);
/* Get copies of the buffer metadata to change later.
* Calculate the missing values for the calculations,
* they won't be changed later though. */
data = GST_BUFFER_DATA (buffer);
size = GST_BUFFER_SIZE (buffer);
timestamp = GST_BUFFER_TIMESTAMP (buffer);
if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
duration = GST_BUFFER_DURATION (buffer);
} else {
change_duration = FALSE;
duration = gst_util_uint64_scale (size / frame_size, GST_SECOND, rate);
}
if (GST_BUFFER_OFFSET_IS_VALID (buffer)) {
offset = GST_BUFFER_OFFSET (buffer);
} else {
change_offset = FALSE;
offset = 0;
}
if (GST_BUFFER_OFFSET_END_IS_VALID (buffer)) {
offset_end = GST_BUFFER_OFFSET_END (buffer);
} else {
change_offset_end = FALSE;
offset_end = offset + size / frame_size;
}
if (segment->format == GST_FORMAT_TIME) {
/* Handle clipping for GST_FORMAT_TIME */
gint64 start, stop, cstart, cstop, diff;
start = timestamp;
stop = timestamp + duration;
if (gst_segment_clip (segment, GST_FORMAT_TIME,
start, stop, &cstart, &cstop)) {
diff = cstart - start;
if (diff > 0) {
timestamp = cstart;
if (change_duration)
duration -= diff;
diff = gst_util_uint64_scale (diff, rate, GST_SECOND);
if (change_offset)
offset += diff;
data += diff * frame_size;
size -= diff * frame_size;
}
diff = stop - cstop;
if (diff > 0) {
/* duration is always valid if stop is valid */
duration -= diff;
diff = gst_util_uint64_scale (diff, rate, GST_SECOND);
if (change_offset_end)
offset_end -= diff;
size -= diff * frame_size;
}
} else {
gst_buffer_unref (buffer);
return NULL;
}
} else {
/* Handle clipping for GST_FORMAT_DEFAULT */
gint64 start, stop, cstart, cstop, diff;
g_return_val_if_fail (GST_BUFFER_OFFSET_IS_VALID (buffer), buffer);
start = offset;
stop = offset_end;
if (gst_segment_clip (segment, GST_FORMAT_DEFAULT,
start, stop, &cstart, &cstop)) {
diff = cstart - start;
if (diff > 0) {
offset = cstart;
timestamp = gst_util_uint64_scale (cstart, GST_SECOND, rate);
if (change_duration)
duration -= gst_util_uint64_scale (diff, GST_SECOND, rate);
data += diff * frame_size;
size -= diff * frame_size;
}
diff = stop - cstop;
if (diff > 0) {
offset_end = cstop;
if (change_duration)
duration -= gst_util_uint64_scale (diff, GST_SECOND, rate);
size -= diff * frame_size;
}
} else {
gst_buffer_unref (buffer);
return NULL;
}
}
/* Get a metadata writable buffer and apply all changes */
ret = gst_buffer_make_metadata_writable (buffer);
GST_BUFFER_TIMESTAMP (ret) = timestamp;
GST_BUFFER_SIZE (ret) = size;
GST_BUFFER_DATA (ret) = data;
if (change_duration)
GST_BUFFER_DURATION (ret) = duration;
if (change_offset)
GST_BUFFER_OFFSET (ret) = offset;
if (change_offset_end)
GST_BUFFER_OFFSET_END (ret) = offset_end;
return ret;
}
......@@ -143,7 +143,11 @@ typedef enum {
GST_AUDIO_FIELD_SIGNED = (1 << 5),
} GstAudioFieldFlag;
#ifndef GST_DISABLE_DEPRECATED
void gst_audio_structure_set_int (GstStructure *structure, GstAudioFieldFlag flag);
#endif /* GST_DISABLE_DEPRECATED */
GstBuffer *gst_audio_buffer_clip (GstBuffer *buffer, GstSegment *segment, gint rate, gint frame_size);
G_END_DECLS
......
......@@ -118,6 +118,343 @@ GST_START_TEST (test_multichannel_checks)
GST_END_TEST;
GST_START_TEST (test_buffer_clipping_time)
{
GstSegment s;
GstBuffer *buf;
GstBuffer *ret;
guint8 *data;
/* Clip start and end */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
GST_BUFFER_SIZE (buf) = 1000;
GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
gst_segment_init (&s, GST_FORMAT_TIME);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_TIME, 4 * GST_SECOND,
8 * GST_SECOND, 4 * GST_SECOND);
GST_BUFFER_TIMESTAMP (buf) = 2 * GST_SECOND;
GST_BUFFER_DURATION (buf) = 10 * GST_SECOND;
GST_BUFFER_OFFSET (buf) = 200;
GST_BUFFER_OFFSET_END (buf) = 1200;
ret = gst_audio_buffer_clip (buf, &s, 100, 1);
fail_unless (ret != NULL);
fail_unless (GST_BUFFER_TIMESTAMP (ret) == 4 * GST_SECOND);
fail_unless (GST_BUFFER_DURATION (ret) == 4 * GST_SECOND);
fail_unless (GST_BUFFER_OFFSET (ret) == 400);
fail_unless (GST_BUFFER_OFFSET_END (ret) == 800);
fail_unless (GST_BUFFER_DATA (ret) == data + 200);
fail_unless (GST_BUFFER_SIZE (ret) == 400);
gst_buffer_unref (ret);
/* Clip only start */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
GST_BUFFER_SIZE (buf) = 1000;
GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
gst_segment_init (&s, GST_FORMAT_TIME);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_TIME, 4 * GST_SECOND,
12 * GST_SECOND, 4 * GST_SECOND);
GST_BUFFER_TIMESTAMP (buf) = 2 * GST_SECOND;
GST_BUFFER_DURATION (buf) = 10 * GST_SECOND;
GST_BUFFER_OFFSET (buf) = 200;
GST_BUFFER_OFFSET_END (buf) = 1200;
ret = gst_audio_buffer_clip (buf, &s, 100, 1);
fail_unless (ret != NULL);
fail_unless (GST_BUFFER_TIMESTAMP (ret) == 4 * GST_SECOND);
fail_unless (GST_BUFFER_DURATION (ret) == 8 * GST_SECOND);
fail_unless (GST_BUFFER_OFFSET (ret) == 400);
fail_unless (GST_BUFFER_OFFSET_END (ret) == 1200);
fail_unless (GST_BUFFER_DATA (ret) == data + 200);
fail_unless (GST_BUFFER_SIZE (ret) == 800);
gst_buffer_unref (ret);
/* Clip only stop */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
GST_BUFFER_SIZE (buf) = 1000;
GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
gst_segment_init (&s, GST_FORMAT_TIME);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_TIME, 2 * GST_SECOND,
10 * GST_SECOND, 2 * GST_SECOND);
GST_BUFFER_TIMESTAMP (buf) = 2 * GST_SECOND;
GST_BUFFER_DURATION (buf) = 10 * GST_SECOND;
GST_BUFFER_OFFSET (buf) = 200;
GST_BUFFER_OFFSET_END (buf) = 1200;
ret = gst_audio_buffer_clip (buf, &s, 100, 1);
fail_unless (ret != NULL);
fail_unless (GST_BUFFER_TIMESTAMP (ret) == 2 * GST_SECOND);
fail_unless (GST_BUFFER_DURATION (ret) == 8 * GST_SECOND);
fail_unless (GST_BUFFER_OFFSET (ret) == 200);
fail_unless (GST_BUFFER_OFFSET_END (ret) == 1000);
fail_unless (GST_BUFFER_DATA (ret) == data);
fail_unless (GST_BUFFER_SIZE (ret) == 800);
gst_buffer_unref (ret);
/* Buffer outside segment */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
GST_BUFFER_SIZE (buf) = 1000;
GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
gst_segment_init (&s, GST_FORMAT_TIME);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_TIME, 12 * GST_SECOND,
20 * GST_SECOND, 12 * GST_SECOND);
GST_BUFFER_TIMESTAMP (buf) = 2 * GST_SECOND;
GST_BUFFER_DURATION (buf) = 10 * GST_SECOND;
GST_BUFFER_OFFSET (buf) = 200;
GST_BUFFER_OFFSET_END (buf) = 1200;
ret = gst_audio_buffer_clip (buf, &s, 100, 1);
fail_unless (ret == NULL);
/* Clip start and end but don't touch duration and offset_end */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
GST_BUFFER_SIZE (buf) = 1000;
GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
gst_segment_init (&s, GST_FORMAT_TIME);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_TIME, 4 * GST_SECOND,
8 * GST_SECOND, 4 * GST_SECOND);
GST_BUFFER_TIMESTAMP (buf) = 2 * GST_SECOND;
GST_BUFFER_DURATION (buf) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET (buf) = 200;
GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
ret = gst_audio_buffer_clip (buf, &s, 100, 1);
fail_unless (ret != NULL);
fail_unless (GST_BUFFER_TIMESTAMP (ret) == 4 * GST_SECOND);
fail_unless (GST_BUFFER_DURATION (ret) == GST_CLOCK_TIME_NONE);
fail_unless (GST_BUFFER_OFFSET (ret) == 400);
fail_unless (GST_BUFFER_OFFSET_END (ret) == GST_BUFFER_OFFSET_NONE);
fail_unless (GST_BUFFER_DATA (ret) == data + 200);
fail_unless (GST_BUFFER_SIZE (ret) == 400);
gst_buffer_unref (ret);
/* If the buffer has no timestamp it should assert()
* FIXME: check if return value is the same as the input buffer.
* probably can't be done because the assert() does a SIGABRT.
*/
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
GST_BUFFER_SIZE (buf) = 1000;
GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
gst_segment_init (&s, GST_FORMAT_TIME);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_TIME, 0 * GST_SECOND,
10 * GST_SECOND, 0 * GST_SECOND);
GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
GST_BUFFER_DURATION (buf) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE;
GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
ASSERT_CRITICAL (ret = gst_audio_buffer_clip (buf, &s, 100, 1));
gst_buffer_unref (buf);
/* If the format is not TIME or DEFAULT it should assert()
* FIXME: check if return value is the same as the input buffer.
* probably can't be done because the assert() does a SIGABRT.
*/
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
GST_BUFFER_SIZE (buf) = 1000;
GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
gst_segment_init (&s, GST_FORMAT_PERCENT);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_PERCENT, 0, 10, 0);
GST_BUFFER_TIMESTAMP (buf) = 0 * GST_SECOND;
GST_BUFFER_DURATION (buf) = 0;
GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE;
GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
ASSERT_CRITICAL (ret = gst_audio_buffer_clip (buf, &s, 100, 1));
gst_buffer_unref (buf);
}
GST_END_TEST;
GST_START_TEST (test_buffer_clipping_samples)
{
GstSegment s;
GstBuffer *buf;
GstBuffer *ret;
guint8 *data;
/* Clip start and end */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
GST_BUFFER_SIZE (buf) = 1000;
GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
gst_segment_init (&s, GST_FORMAT_DEFAULT);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_DEFAULT, 400,
800, 400);
GST_BUFFER_TIMESTAMP (buf) = 2 * GST_SECOND;
GST_BUFFER_DURATION (buf) = 10 * GST_SECOND;
GST_BUFFER_OFFSET (buf) = 200;
GST_BUFFER_OFFSET_END (buf) = 1200;
ret = gst_audio_buffer_clip (buf, &s, 100, 1);
fail_unless (ret != NULL);
fail_unless (GST_BUFFER_TIMESTAMP (ret) == 4 * GST_SECOND);
fail_unless (GST_BUFFER_DURATION (ret) == 4 * GST_SECOND);
fail_unless (GST_BUFFER_OFFSET (ret) == 400);
fail_unless (GST_BUFFER_OFFSET_END (ret) == 800);
fail_unless (GST_BUFFER_DATA (ret) == data + 200);
fail_unless (GST_BUFFER_SIZE (ret) == 400);
gst_buffer_unref (ret);
/* Clip only start */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
GST_BUFFER_SIZE (buf) = 1000;
GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
gst_segment_init (&s, GST_FORMAT_DEFAULT);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_DEFAULT, 400,
1200, 400);
GST_BUFFER_TIMESTAMP (buf) = 2 * GST_SECOND;
GST_BUFFER_DURATION (buf) = 10 * GST_SECOND;
GST_BUFFER_OFFSET (buf) = 200;
GST_BUFFER_OFFSET_END (buf) = 1200;
ret = gst_audio_buffer_clip (buf, &s, 100, 1);
fail_unless (ret != NULL);
fail_unless (GST_BUFFER_TIMESTAMP (ret) == 4 * GST_SECOND);
fail_unless (GST_BUFFER_DURATION (ret) == 8 * GST_SECOND);
fail_unless (GST_BUFFER_OFFSET (ret) == 400);
fail_unless (GST_BUFFER_OFFSET_END (ret) == 1200);
fail_unless (GST_BUFFER_DATA (ret) == data + 200);
fail_unless (GST_BUFFER_SIZE (ret) == 800);
gst_buffer_unref (ret);
/* Clip only stop */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
GST_BUFFER_SIZE (buf) = 1000;
GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
gst_segment_init (&s, GST_FORMAT_DEFAULT);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_DEFAULT, 200,
1000, 200);
GST_BUFFER_TIMESTAMP (buf) = 2 * GST_SECOND;
GST_BUFFER_DURATION (buf) = 10 * GST_SECOND;
GST_BUFFER_OFFSET (buf) = 200;
GST_BUFFER_OFFSET_END (buf) = 1200;
ret = gst_audio_buffer_clip (buf, &s, 100, 1);
fail_unless (ret != NULL);
fail_unless (GST_BUFFER_TIMESTAMP (ret) == 2 * GST_SECOND);
fail_unless (GST_BUFFER_DURATION (ret) == 8 * GST_SECOND);
fail_unless (GST_BUFFER_OFFSET (ret) == 200);
fail_unless (GST_BUFFER_OFFSET_END (ret) == 1000);
fail_unless (GST_BUFFER_DATA (ret) == data);
fail_unless (GST_BUFFER_SIZE (ret) == 800);
gst_buffer_unref (ret);
/* Buffer outside segment */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
GST_BUFFER_SIZE (buf) = 1000;
GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
gst_segment_init (&s, GST_FORMAT_DEFAULT);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_DEFAULT, 1200,
2000, 1200);
GST_BUFFER_TIMESTAMP (buf) = 2 * GST_SECOND;
GST_BUFFER_DURATION (buf) = 10 * GST_SECOND;
GST_BUFFER_OFFSET (buf) = 200;
GST_BUFFER_OFFSET_END (buf) = 1200;
ret = gst_audio_buffer_clip (buf, &s, 100, 1);
fail_unless (ret == NULL);
/* Clip start and end but don't touch duration and offset_end */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
GST_BUFFER_SIZE (buf) = 1000;
GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
gst_segment_init (&s, GST_FORMAT_DEFAULT);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_DEFAULT, 400,
800, 400);
GST_BUFFER_TIMESTAMP (buf) = 2 * GST_SECOND;
GST_BUFFER_DURATION (buf) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET (buf) = 200;
GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
ret = gst_audio_buffer_clip (buf, &s, 100, 1);
fail_unless (ret != NULL);
fail_unless (GST_BUFFER_TIMESTAMP (ret) == 4 * GST_SECOND);
fail_unless (GST_BUFFER_DURATION (ret) == GST_CLOCK_TIME_NONE);
fail_unless (GST_BUFFER_OFFSET (ret) == 400);
fail_unless (GST_BUFFER_OFFSET_END (ret) == GST_BUFFER_OFFSET_NONE);
fail_unless (GST_BUFFER_DATA (ret) == data + 200);
fail_unless (GST_BUFFER_SIZE (ret) == 400);
gst_buffer_unref (ret);
/* If the buffer has no offset it should assert()
* FIXME: check if return value is the same as the input buffer.
* probably can't be done because the assert() does a SIGABRT.
*/
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
GST_BUFFER_SIZE (buf) = 1000;
GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
gst_segment_init (&s, GST_FORMAT_DEFAULT);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_DEFAULT, 0, 10, 0);
GST_BUFFER_TIMESTAMP (buf) = 0 * GST_SECOND;
GST_BUFFER_DURATION (buf) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE;
GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
ASSERT_CRITICAL (ret = gst_audio_buffer_clip (buf, &s, 100, 1));
gst_buffer_unref (buf);
}
GST_END_TEST;
static Suite *
audio_suite (void)
{
......@@ -126,6 +463,8 @@ audio_suite (void)
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_multichannel_checks);
tcase_add_test (tc_chain, test_buffer_clipping_time);
tcase_add_test (tc_chain, test_buffer_clipping_samples);
return s;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment