From 2527c8f9f8eca9b19014ba7b442ae4becbe45eac Mon Sep 17 00:00:00 2001 From: Vivia Nikolaidou Date: Wed, 17 Feb 2021 12:41:06 +0200 Subject: [PATCH] libs: audio: Handle meta changes in gst_audio_buffer_truncate Set timestamp and duration to GST_CLOCK_TIME_NONE unless trim==0, because that function doesn't know the rate and therefore can't calculate them. Set offset and offset_end to appropriate values. Make it clear in the documentation that the caller is responsible for setting the timestamp and duration. Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/issues/869 Part-of: --- gst-libs/gst/audio/audio.c | 26 +++++++++++++++++ tests/check/libs/audio.c | 58 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/gst-libs/gst/audio/audio.c b/gst-libs/gst/audio/audio.c index 440a4e87da..075b8db969 100644 --- a/gst-libs/gst/audio/audio.c +++ b/gst-libs/gst/audio/audio.c @@ -258,6 +258,12 @@ gst_audio_buffer_clip (GstBuffer * buffer, const GstSegment * segment, * the necessary amount of samples from the end and @trim number of samples * from the beginning. * + * This function does not know the audio rate, therefore the caller is + * responsible for re-setting the correct timestamp and duration to the + * buffer. However, timestamp will be preserved if trim == 0, and duration + * will also be preserved if there is no trimming to be done. Offset and + * offset end will be preserved / updated. + * * After calling this function the caller does not own a reference to * @buffer anymore. * @@ -274,11 +280,14 @@ gst_audio_buffer_truncate (GstBuffer * buffer, gint bpf, gsize trim, GstBuffer *ret = NULL; gsize orig_samples; gint i; + GstClockTime orig_ts, orig_offset; g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL); meta = gst_buffer_get_audio_meta (buffer); orig_samples = meta ? meta->samples : gst_buffer_get_size (buffer) / bpf; + orig_ts = GST_BUFFER_PTS (buffer); + orig_offset = GST_BUFFER_OFFSET (buffer); g_return_val_if_fail (trim < orig_samples, NULL); g_return_val_if_fail (samples == -1 || trim + samples <= orig_samples, NULL); @@ -312,5 +321,22 @@ gst_audio_buffer_truncate (GstBuffer * buffer, gint bpf, gsize trim, } } + GST_BUFFER_DTS (ret) = GST_CLOCK_TIME_NONE; + if (GST_CLOCK_TIME_IS_VALID (orig_ts) && trim == 0) { + GST_BUFFER_PTS (ret) = orig_ts; + } else { + GST_BUFFER_PTS (ret) = GST_CLOCK_TIME_NONE; + } + /* If duration was the same, it would have meant there's no trimming to be + * done, so we have an early return further up */ + GST_BUFFER_DURATION (ret) = GST_CLOCK_TIME_NONE; + if (orig_offset != GST_BUFFER_OFFSET_NONE) { + GST_BUFFER_OFFSET (ret) = orig_offset + trim; + GST_BUFFER_OFFSET_END (ret) = GST_BUFFER_OFFSET (ret) + samples; + } else { + GST_BUFFER_OFFSET (ret) = GST_BUFFER_OFFSET_NONE; + GST_BUFFER_OFFSET_END (ret) = GST_BUFFER_OFFSET_NONE; + } + return ret; } diff --git a/tests/check/libs/audio.c b/tests/check/libs/audio.c index 3221450428..7a01995e2d 100644 --- a/tests/check/libs/audio.c +++ b/tests/check/libs/audio.c @@ -647,8 +647,7 @@ GST_START_TEST (test_buffer_clip_samples_start_and_stop_no_meta) fail_unless_equals_int64 (GST_BUFFER_TIMESTAMP (ret), 4 * GST_SECOND); fail_unless_equals_int64 (GST_BUFFER_DURATION (ret), GST_CLOCK_TIME_NONE); fail_unless_equals_int64 (GST_BUFFER_OFFSET (ret), 400); - fail_unless_equals_int64 (GST_BUFFER_OFFSET_END (ret), - GST_BUFFER_OFFSET_NONE); + fail_unless_equals_int64 (GST_BUFFER_OFFSET_END (ret), 800); gst_buffer_map (ret, &map, GST_MAP_READ); fail_unless (map.data == data + 200); fail_unless (map.size == 400); @@ -664,7 +663,7 @@ GST_START_TEST (test_buffer_clip_samples_no_timestamp) GstSegment s; GstBuffer *buf; - /* If the buffer has no offset it should assert() + /* If the buffer has no offset it should assert() in DEFAULT format * FIXME: check if return value is the same as the input buffer. * probably can't be done because the assert() does a SIGABRT. */ @@ -683,6 +682,57 @@ GST_START_TEST (test_buffer_clip_samples_no_timestamp) GST_END_TEST; +GST_START_TEST (test_buffer_truncate_samples_offset_end) +{ + GstBuffer *buf; + GstBuffer *ret; + guint8 *data; + + buf = make_buffer (&data); + 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_truncate (buf, 4, 100, 100); + fail_unless (ret != NULL); + + fail_unless_equals_int64 (GST_BUFFER_TIMESTAMP (ret), GST_CLOCK_TIME_NONE); + fail_unless_equals_int64 (GST_BUFFER_DURATION (ret), GST_CLOCK_TIME_NONE); + fail_unless_equals_int64 (GST_BUFFER_OFFSET (ret), 300); + fail_unless_equals_int64 (GST_BUFFER_OFFSET_END (ret), 400); + + gst_buffer_unref (ret); +} + +GST_END_TEST; + +GST_START_TEST (test_buffer_truncate_samples_no_timestamp) +{ + GstBuffer *buf; + GstBuffer *ret; + guint8 *data; + + buf = make_buffer (&data); + 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; + + ret = gst_audio_buffer_truncate (buf, 4, 100, 1); + fail_unless (ret != NULL); + + fail_unless_equals_int64 (GST_BUFFER_TIMESTAMP (ret), GST_CLOCK_TIME_NONE); + fail_unless_equals_int64 (GST_BUFFER_DURATION (ret), GST_CLOCK_TIME_NONE); + fail_unless_equals_int64 (GST_BUFFER_OFFSET (ret), GST_BUFFER_OFFSET_NONE); + fail_unless_equals_int64 (GST_BUFFER_OFFSET_END (ret), + GST_BUFFER_OFFSET_NONE); + + gst_buffer_unref (ret); +} + +GST_END_TEST; + GST_START_TEST (test_multichannel_checks) { GstAudioChannelPosition pos_2_mixed[2] = { @@ -1554,6 +1604,8 @@ audio_suite (void) tcase_add_test (tc_chain, test_buffer_clip_samples_outside); tcase_add_test (tc_chain, test_buffer_clip_samples_start_and_stop_no_meta); tcase_add_test (tc_chain, test_buffer_clip_samples_no_timestamp); + tcase_add_test (tc_chain, test_buffer_truncate_samples_offset_end); + tcase_add_test (tc_chain, test_buffer_truncate_samples_no_timestamp); tcase_add_test (tc_chain, test_multichannel_checks); tcase_add_test (tc_chain, test_multichannel_reorder); tcase_add_test (tc_chain, test_audio_format_s8);