gstreamer 4.3.6 → 4.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90a24d64e10b3a4c5d4ac3172cf5521ca579097b040554c4ddaef62dbe2f15fc
4
- data.tar.gz: 40cf5470e711abf4b9327cbe3609c9c25e3e970a0c4f95ec4c7787f79d40411a
3
+ metadata.gz: 415cab8d4468bf433442b7e8da40f47dc4acf152e7dbb1dcc3a2e23edf26581b
4
+ data.tar.gz: 1c132d585039e4d9e50ebf262e89289dd77935d30cc628ecafdd4d6e151d05f3
5
5
  SHA512:
6
- metadata.gz: 0c1af5c7dc657d9b81c9e119a6a9a34f4559d62bfff461209dd886e38c88776f445a5bfa39d7f85f2f14ea281c2a9047a531ae755b9dd1b21edbfbb79f33848d
7
- data.tar.gz: 15b94702d7bb135c0719416f131a7c94af8a79ed1682285648fe2908e80017ad33d8dde821b532ea36fc8ee9bea514724b3be3d5cffed08ceffc02ff9e421240
6
+ metadata.gz: 2fe1ef493c43e1370b6f4650cb1e7aadfa353ec1134c565668309dc2c634cab9cdcae29449f7a481ef36f29f897031907a9dacf7f1f9554f1075b8f00c0d77c0
7
+ data.tar.gz: 797aec06192c0dba4801d73d72483dd2c9c38b285a832608be4c62260b7b37c49aff03b6dc6658a1b43fcf29294ce8085a6f79e2ba863c0a3eb9cefc88937df1
@@ -28,6 +28,7 @@ $LOAD_PATH.unshift(mkmf_gnome2_dir.to_s) if mkmf_gnome2_dir.exist?
28
28
 
29
29
  module_name = "gstreamer"
30
30
  package_id = "gstreamer-1.0"
31
+ audio_package_id = "gstreamer-audio-1.0"
31
32
 
32
33
  require "mkmf-gnome"
33
34
 
@@ -45,11 +46,23 @@ unless required_pkg_config_package(package_id,
45
46
  :redhat => "pkgconfig(#{package_id})",
46
47
  :arch_linux => "gstreamer",
47
48
  :homebrew => "gstreamer",
48
- :macports => "gstreamer",
49
+ :macports => "gstreamer1",
49
50
  :msys2 => "gstreamer")
50
51
  exit(false)
51
52
  end
52
53
 
54
+ unless required_pkg_config_package(audio_package_id,
55
+ :alt_linux => ["gst-plugins1.0-devel", "liborc-devel"],
56
+ :alpine_linux => "gst-plugins-base-dev",
57
+ :conda => "gst-plugins-base",
58
+ :debian => "libgstreamer-plugins-base1.0-dev",
59
+ :redhat => "pkgconfig(#{audio_package_id})",
60
+ :arch_linux => "gst-plugins-base",
61
+ :macports => "gstreamer1-gst-plugins-base",
62
+ :msys2 => "gst-plugins-base")
63
+ exit(false)
64
+ end
65
+
53
66
  unless PKGConfig.have_package("gobject-introspection-1.0")
54
67
  exit(false)
55
68
  end
@@ -0,0 +1,418 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright (C) 2026 Ruby-GNOME Project Team
4
+ *
5
+ * This library is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 of the License, or (at your option) any later version.
9
+ *
10
+ * This library is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public
16
+ * License along with this library; if not, write to the Free Software
17
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18
+ * MA 02110-1301 USA
19
+ */
20
+
21
+ #include <ruby.h>
22
+ #include <ruby/version.h>
23
+ #include <ruby/memory_view.h>
24
+ #include <gst/gstversion.h>
25
+ #include <gst/audio/audio.h>
26
+ #include "rbgst.h"
27
+
28
+ typedef struct memview_private_data {
29
+ GstBuffer *buffer;
30
+ GstMapInfo *map_info;
31
+ } memview_private_data;
32
+
33
+ static gboolean
34
+ rg_gst_combine_buffer_list(GstBuffer **buffer, guint idx, gpointer user_data)
35
+ {
36
+ GstBuffer **acc;
37
+
38
+ acc = (GstBuffer **)user_data;
39
+ *acc = gst_buffer_append(*acc, gst_buffer_ref(*buffer));
40
+
41
+ return TRUE;
42
+ }
43
+
44
+ static gboolean
45
+ rg_gst_is_supported_caps(const gchar *name)
46
+ {
47
+ return g_str_has_prefix(name, "audio/x-raw");
48
+ }
49
+
50
+ static bool
51
+ rg_gst_memory_view_init_from_audio(VALUE obj, rb_memory_view_t *view, int flags, GstSample *sample, GstCaps *caps)
52
+ {
53
+ GstBuffer *buffer;
54
+ GstBufferList *buffer_list;
55
+ GstAudioInfo *audio_info;
56
+ GstMapInfo *map_info;
57
+ bool is_writable_requested;
58
+ gboolean is_writable;
59
+ bool is_interleaved;
60
+ ssize_t *shape;
61
+ ssize_t *strides;
62
+ gint width;
63
+ const char *format = NULL;
64
+ gsize n_samples;
65
+ memview_private_data *private_data;
66
+
67
+ audio_info = gst_audio_info_new_from_caps(caps);
68
+ if (!audio_info) {
69
+ rb_warn("Gst::Sample: failed to get audio info");
70
+
71
+ return false;
72
+ }
73
+ if (!audio_info->finfo) {
74
+ gst_audio_info_free(audio_info);
75
+ rb_warn("Gst::Sample: failed to retrieve audio format info");
76
+
77
+ return false;
78
+ }
79
+
80
+ is_interleaved = audio_info->layout == GST_AUDIO_LAYOUT_INTERLEAVED;
81
+ if (!is_interleaved) {
82
+ // TODO: non-interleaved layout support
83
+ gst_audio_info_free(audio_info);
84
+ rb_warn("Gst::Sample: currently only interleaved layout is supported");
85
+
86
+ return false;
87
+ }
88
+
89
+ is_writable_requested = flags & RUBY_MEMORY_VIEW_WRITABLE;
90
+
91
+ buffer_list = gst_sample_get_buffer_list(sample);
92
+ if (buffer_list) {
93
+ if (is_writable_requested) {
94
+ gst_audio_info_free(audio_info);
95
+ rb_warn("Gst::Sample: currently writable buffer list is not supported");
96
+
97
+ return false;
98
+ }
99
+ buffer = gst_buffer_new();
100
+ gst_buffer_list_foreach(buffer_list, rg_gst_combine_buffer_list, &buffer);
101
+ } else {
102
+ buffer = gst_sample_get_buffer(sample);
103
+ if (!buffer) {
104
+ gst_audio_info_free(audio_info);
105
+ rb_warn("Gst::Sample: failed to get buffer");
106
+
107
+ return false;
108
+ }
109
+ buffer = gst_buffer_ref(buffer);
110
+ }
111
+
112
+ is_writable = gst_sample_is_writable(sample);
113
+ if (is_writable_requested && !is_writable) {
114
+ rb_warn("Gst::Sample: sample is not writable but writable memory view is requested");
115
+ gst_audio_info_free(audio_info);
116
+ gst_buffer_unref(buffer);
117
+
118
+ return false;
119
+ }
120
+ // Doesn't use ALLOC/ALLOC_N because they may raise an exception and then
121
+ // the map_info and audio_info won't be freed and the buffer won't be unrefed.
122
+ map_info = g_new(GstMapInfo, 1);
123
+ if (!gst_buffer_map(buffer, map_info, is_writable_requested ? GST_MAP_WRITE : GST_MAP_READ)) {
124
+ rb_warn("Gst::Sample: failed to map buffer");
125
+ g_free(map_info);
126
+ gst_audio_info_free(audio_info);
127
+ gst_buffer_unref(buffer);
128
+
129
+ return false;
130
+ }
131
+
132
+ width = audio_info->finfo->width / 8;
133
+
134
+ switch (audio_info->finfo->format) {
135
+ case GST_AUDIO_FORMAT_UNKNOWN:
136
+ rb_warn("Gst::Sample: format is unknown");
137
+ break;
138
+ case GST_AUDIO_FORMAT_ENCODED:
139
+ rb_warn("Gst::Sample: encoded format is not supported");
140
+ break;
141
+ case GST_AUDIO_FORMAT_S8:
142
+ format = "c";
143
+ break;
144
+ case GST_AUDIO_FORMAT_U8:
145
+ format = "C";
146
+ break;
147
+ case GST_AUDIO_FORMAT_S16LE:
148
+ format = "s<";
149
+ break;
150
+ case GST_AUDIO_FORMAT_S16BE:
151
+ format = "s>";
152
+ break;
153
+ case GST_AUDIO_FORMAT_U16LE:
154
+ format = "S<";
155
+ break;
156
+ case GST_AUDIO_FORMAT_U16BE:
157
+ format = "S>";
158
+ break;
159
+ case GST_AUDIO_FORMAT_S24_32LE:
160
+ rb_warn("Gst::Sample: S24_32LE format is not supported");
161
+ break;
162
+ case GST_AUDIO_FORMAT_S24_32BE:
163
+ rb_warn("Gst::Sample: S24_32BE format is not supported");
164
+ break;
165
+ case GST_AUDIO_FORMAT_U24_32LE:
166
+ rb_warn("Gst::Sample: U24_32LE format is not supported");
167
+ break;
168
+ case GST_AUDIO_FORMAT_U24_32BE:
169
+ rb_warn("Gst::Sample: U24_32BE format is not supported");
170
+ break;
171
+ case GST_AUDIO_FORMAT_S32LE:
172
+ format = "l<";
173
+ break;
174
+ case GST_AUDIO_FORMAT_S32BE:
175
+ format = "l>";
176
+ break;
177
+ case GST_AUDIO_FORMAT_U32LE:
178
+ format = "L<";
179
+ break;
180
+ case GST_AUDIO_FORMAT_U32BE:
181
+ format = "L>";
182
+ break;
183
+ case GST_AUDIO_FORMAT_S24LE:
184
+ rb_warn("Gst::Sample: S24LE format is not supported");
185
+ break;
186
+ case GST_AUDIO_FORMAT_S24BE:
187
+ rb_warn("Gst::Sample: S24BE format is not supported");
188
+ break;
189
+ case GST_AUDIO_FORMAT_U24LE:
190
+ rb_warn("Gst::Sample: U24LE format is not supported");
191
+ break;
192
+ case GST_AUDIO_FORMAT_U24BE:
193
+ rb_warn("Gst::Sample: U24BE format is not supported");
194
+ break;
195
+ case GST_AUDIO_FORMAT_S20LE:
196
+ rb_warn("Gst::Sample: S20LE format is not supported");
197
+ break;
198
+ case GST_AUDIO_FORMAT_S20BE:
199
+ rb_warn("Gst::Sample: S20BE format is not supported");
200
+ break;
201
+ case GST_AUDIO_FORMAT_U20LE:
202
+ rb_warn("Gst::Sample: U20LE format is not supported");
203
+ break;
204
+ case GST_AUDIO_FORMAT_U20BE:
205
+ rb_warn("Gst::Sample: U20BE format is not supported");
206
+ break;
207
+ case GST_AUDIO_FORMAT_S18LE:
208
+ rb_warn("Gst::Sample: S18LE format is not supported");
209
+ break;
210
+ case GST_AUDIO_FORMAT_S18BE:
211
+ rb_warn("Gst::Sample: S18BE format is not supported");
212
+ break;
213
+ case GST_AUDIO_FORMAT_U18LE:
214
+ rb_warn("Gst::Sample: U18LE format is not supported");
215
+ break;
216
+ case GST_AUDIO_FORMAT_U18BE:
217
+ rb_warn("Gst::Sample: U18BE format is not supported");
218
+ break;
219
+ case GST_AUDIO_FORMAT_F32LE:
220
+ if (rb_memory_view_item_size_from_format("e", NULL) == 4) {
221
+ format = "e";
222
+ } else {
223
+ rb_warn("Gst::Sample: only environment float size is 4 bytes is supported");
224
+ }
225
+ break;
226
+ case GST_AUDIO_FORMAT_F32BE:
227
+ if (rb_memory_view_item_size_from_format("g", NULL) == 4) {
228
+ format = "g";
229
+ } else {
230
+ rb_warn("Gst::Sample: only environment float size is 4 bytes is supported");
231
+ }
232
+ break;
233
+ case GST_AUDIO_FORMAT_F64LE:
234
+ if (rb_memory_view_item_size_from_format("E", NULL) == 8) {
235
+ format = "E";
236
+ } else if (rb_memory_view_item_size_from_format("e", NULL) == 8) {
237
+ format = "e";
238
+ } else {
239
+ rb_warn("Gst::Sample: only environment double or float size is 8 bytes is supported");
240
+ }
241
+ break;
242
+ case GST_AUDIO_FORMAT_F64BE:
243
+ if (rb_memory_view_item_size_from_format("G", NULL) == 8) {
244
+ format = "G";
245
+ } else if (rb_memory_view_item_size_from_format("g", NULL) == 8) {
246
+ format = "g";
247
+ } else {
248
+ rb_warn("Gst::Sample: only environment double or float size is 8 bytes is supported");
249
+ }
250
+ break;
251
+ #if GST_CHECK_VERSION(1, 28, 0)
252
+ case GST_AUDIO_FORMAT_S20_32LE:
253
+ rb_warn("Gst::Sample: S20_32LE format is not supported");
254
+ break;
255
+ case GST_AUDIO_FORMAT_S20_32BE:
256
+ rb_warn("Gst::Sample: S20_32BE format is not supported");
257
+ break;
258
+ case GST_AUDIO_FORMAT_U20_32LE:
259
+ rb_warn("Gst::Sample: U20_32LE format is not supported");
260
+ break;
261
+ case GST_AUDIO_FORMAT_U20_32BE:
262
+ rb_warn("Gst::Sample: U20_32BE format is not supported");
263
+ break;
264
+ #endif
265
+ }
266
+
267
+ if (!format) {
268
+ gst_buffer_unmap(buffer, map_info);
269
+ g_free(map_info);
270
+ gst_buffer_unref(buffer);
271
+ gst_audio_info_free(audio_info);
272
+
273
+ return false;
274
+ }
275
+
276
+ if (map_info->size % (width * audio_info->channels) != 0) {
277
+ rb_warn("Gst::Sample: buffer size is not aligned with sample width and channels");
278
+ gst_buffer_unmap(buffer, map_info);
279
+ g_free(map_info);
280
+ gst_buffer_unref(buffer);
281
+ gst_audio_info_free(audio_info);
282
+
283
+ return false;
284
+ }
285
+ n_samples = map_info->size / width / audio_info->channels;
286
+ // Doesn't use ALLOC/ALLOC_N because they may raise an exception and then
287
+ // the audio_info won't be freed.
288
+ shape = g_new(ssize_t, 2);
289
+ strides = g_new(ssize_t, 2);
290
+ // Currently, interleaved and row-major audio is supported
291
+ shape[0] = n_samples;
292
+ shape[1] = audio_info->channels;
293
+ strides[0] = width * audio_info->channels;
294
+ strides[1] = width;
295
+
296
+ gst_audio_info_free(audio_info);
297
+
298
+ // Uses g_new instead of ALLOC/ALLOC_N for consistency.
299
+ private_data = g_new(memview_private_data, 1);
300
+ private_data->buffer = buffer;
301
+ private_data->map_info = map_info;
302
+
303
+ view->format = format;
304
+ view->data = map_info->data;
305
+ view->obj = obj;
306
+ view->item_size = width;
307
+ view->byte_size = map_info->size;
308
+ view->readonly = !is_writable_requested;
309
+ view->ndim = 2;
310
+ view->shape = shape;
311
+ view->strides = strides;
312
+ view->sub_offsets = NULL;
313
+ #if RUBY_API_VERSION_MAJOR == 3 && RUBY_API_VERSION_MINOR == 0
314
+ *((void **)&view->private) = private_data;
315
+ #else
316
+ view->private_data = (void *)private_data;
317
+ #endif
318
+
319
+ return true;
320
+ }
321
+
322
+ static bool
323
+ rg_gst_sample_get(VALUE obj, rb_memory_view_t *view, int flags)
324
+ {
325
+ GstSample *sample;
326
+ GstCaps *caps;
327
+ bool is_column_major_requested;
328
+
329
+ is_column_major_requested = flags & RUBY_MEMORY_VIEW_COLUMN_MAJOR;
330
+ if (is_column_major_requested) {
331
+ // TODO: column-major support
332
+ rb_warn("Gst::Sample: currently column-major is not supported");
333
+
334
+ return false;
335
+ }
336
+
337
+ sample = GST_SAMPLE(RVAL2GOBJ(obj));
338
+
339
+ caps = gst_sample_get_caps(sample);
340
+
341
+ if (rg_gst_memory_view_init_from_audio(obj, view, flags, sample, caps)) {
342
+ gst_sample_ref(sample);
343
+ return true;
344
+ }
345
+
346
+ return false;
347
+ }
348
+
349
+ static bool
350
+ rg_gst_sample_release(VALUE obj, rb_memory_view_t *view)
351
+ {
352
+ GstSample *sample;
353
+ memview_private_data *private_data;
354
+
355
+ g_free((gpointer)view->shape);
356
+ g_free((gpointer)view->strides);
357
+ #if RUBY_API_VERSION_MAJOR == 3 && RUBY_API_VERSION_MINOR == 0
358
+ private_data = (memview_private_data *)view->private;
359
+ #else
360
+ private_data = (memview_private_data *)view->private_data;
361
+ #endif
362
+ gst_buffer_unmap(private_data->buffer, private_data->map_info);
363
+ gst_buffer_unref(private_data->buffer);
364
+ g_free(private_data->map_info);
365
+ g_free(private_data);
366
+ sample = GST_SAMPLE(RVAL2GOBJ(obj));
367
+ gst_sample_unref(sample);
368
+
369
+ return true;
370
+ }
371
+
372
+ static bool
373
+ rg_gst_sample_available_p(VALUE obj)
374
+ {
375
+ GstSample *sample;
376
+ GstCaps *caps;
377
+ gchar *name;
378
+ gboolean is_supported_caps;
379
+
380
+ sample = GST_SAMPLE(RVAL2GOBJ(obj));
381
+
382
+ caps = gst_sample_get_caps(sample);
383
+ if (!caps) {
384
+ return false;
385
+ }
386
+ if (gst_caps_get_size(caps) != 1) {
387
+ return false;
388
+ }
389
+
390
+ name = gst_caps_to_string(caps);
391
+ is_supported_caps = rg_gst_is_supported_caps(name);
392
+ if (!is_supported_caps) {
393
+ rb_warn("Gst::Sample: currently audio/x-raw caps only supported but is %s", name);
394
+ }
395
+
396
+ g_free(name);
397
+
398
+ return is_supported_caps;
399
+ }
400
+
401
+ static rb_memory_view_entry_t rg_gst_sample_entry = {
402
+ rg_gst_sample_get,
403
+ rg_gst_sample_release,
404
+ rg_gst_sample_available_p,
405
+ };
406
+
407
+ void
408
+ rb_gst_init_sample(void)
409
+ {
410
+ #if GST_CHECK_VERSION(1, 20, 0)
411
+ VALUE mGst;
412
+ VALUE cSample;
413
+
414
+ mGst = rb_const_get(rb_cObject, rb_intern("Gst"));
415
+ cSample = rb_const_get(mGst, rb_intern("Sample"));
416
+ rb_memory_view_register(cSample, &rg_gst_sample_entry);
417
+ #endif
418
+ }
@@ -72,4 +72,5 @@ Init_gstreamer (void)
72
72
 
73
73
  rb_gst_init_child_proxy();
74
74
  rb_gst_init_element();
75
+ rb_gst_init_sample();
75
76
  }
@@ -25,3 +25,4 @@
25
25
  extern void Init_gstreamer (void);
26
26
  G_GNUC_INTERNAL extern void rb_gst_init_child_proxy (void);
27
27
  G_GNUC_INTERNAL extern void rb_gst_init_element (void);
28
+ G_GNUC_INTERNAL extern void rb_gst_init_sample (void);
data/gstreamer.gemspec CHANGED
@@ -44,18 +44,33 @@ Gem::Specification.new do |s|
44
44
 
45
45
  s.add_runtime_dependency("gobject-introspection", "= #{s.version}")
46
46
 
47
- [
48
- ["alpine_linux", "gstreamer-dev"],
49
- ["alt_linux", "gstreamer1.0-devel"],
50
- ["arch_linux", "gstreamer"],
51
- ["conda", "gstreamer"],
52
- ["debian", "libgstreamer1.0-dev"],
53
- ["homebrew", "gstreamer"],
54
- ["macports", "gstreamer"],
55
- ["msys2", "gstreamer"],
56
- ["rhel", "pkgconfig(gstreamer-1.0)"],
57
- ].each do |platform, package|
58
- s.requirements << "system: gstreamer-1.0: #{platform}: #{package}"
47
+ {
48
+ "gstreamer-1.0" => [
49
+ ["alpine_linux", "gstreamer-dev"],
50
+ ["alt_linux", "gstreamer1.0-devel"],
51
+ ["arch_linux", "gstreamer"],
52
+ ["conda", "gstreamer"],
53
+ ["debian", "libgstreamer1.0-dev"],
54
+ ["homebrew", "gstreamer"],
55
+ ["macports", "gstreamer1"],
56
+ ["msys2", "gstreamer"],
57
+ ["rhel", "pkgconfig(gstreamer-1.0)"]
58
+ ],
59
+ "gstreamer-audio-1.0" => [
60
+ ["alpine_linux", "gst-plugins-base-dev"],
61
+ ["alt_linux", "gst-plugins1.0-devel"],
62
+ ["alt_linux", "liborc-devel"],
63
+ ["arch_linux", "gst-plugins-base"],
64
+ ["conda", "gst-plugins-base"],
65
+ ["debian", "libgstreamer-plugins-base1.0-dev"],
66
+ ["macports", "gstreamer1-gst-plugins-base"],
67
+ ["msys2", "gst-plugins-base"],
68
+ ["rhel", "pkgconfig(gstreamer-audio-1.0)"]
69
+ ]
70
+ }.each_pair do |id, requirements|
71
+ requirements.each do |platform, package|
72
+ s.requirements << "system: #{id}: #{platform}: #{package}"
73
+ end
59
74
  end
60
75
 
61
76
  s.metadata["msys2_mingw_dependencies"] = "gstreamer"
data/lib/gst/buffer.rb ADDED
@@ -0,0 +1,45 @@
1
+ # Copyright (C) 2026 Ruby-GNOME Project Team
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ module Gst
18
+ class Buffer
19
+ alias_method :map_raw, :map
20
+ def map(flags)
21
+ success, info = map_raw(flags)
22
+ raise Gst::CoreError::Failed.new("failed to map buffer") unless success
23
+ return info unless block_given?
24
+
25
+ begin
26
+ yield info
27
+ ensure
28
+ unmap(info)
29
+ end
30
+ end
31
+
32
+ alias_method :map_range_raw, :map_range
33
+ def map_range(idx, length, flags)
34
+ success, info = map_range_raw(idx, length, flags)
35
+ raise Gst::CoreError::Failed.new("failed to map buffer") unless success
36
+ return info unless block_given?
37
+
38
+ begin
39
+ yield info
40
+ ensure
41
+ unmap(info)
42
+ end
43
+ end
44
+ end
45
+ end
data/lib/gst/loader.rb CHANGED
@@ -60,6 +60,7 @@ module Gst
60
60
 
61
61
  def require_libraries
62
62
  require "gst/bin"
63
+ require "gst/buffer"
63
64
  require "gst/bus"
64
65
  require "gst/caps"
65
66
  require "gst/element"
@@ -37,7 +37,7 @@ sink.emit_signals = true
37
37
  sink.signal_connect(:new_sample) do |_|
38
38
  sample = sink.pull_sample
39
39
  buffer = sample.buffer
40
- success, map = buffer.map(:read)
40
+ map = buffer.map(:read)
41
41
  p map.data
42
42
  buffer.unmap(map)
43
43
  Gst::FlowReturn::OK
@@ -0,0 +1,127 @@
1
+ # Copyright (C) 2026 Ruby-GNOME Project Team
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ class TestBuffer < Test::Unit::TestCase
18
+ def setup
19
+ unless Gst::ElementFactory.find("videotestsrc")
20
+ omit("gst-plugins-good is needed")
21
+ end
22
+ @pipeline = Gst.parse_launch("videotestsrc ! appsink name=sink")
23
+ @sink = @pipeline.get_by_name("sink")
24
+ end
25
+
26
+ def test_map
27
+ @pipeline.play
28
+ begin
29
+ sample = @sink.try_pull_sample(Gst::SECOND)
30
+ buffer = sample.buffer
31
+ map_info = buffer.map(:read)
32
+
33
+ assert do
34
+ map_info.data.size >= 115200
35
+ end
36
+ ensure
37
+ @pipeline.stop
38
+ end
39
+ end
40
+
41
+ def test_map_with_block
42
+ @pipeline.play
43
+ begin
44
+ sample = @sink.try_pull_sample(Gst::SECOND)
45
+ buffer = sample.buffer
46
+ buffer.map(:read) do |map_info|
47
+ assert do
48
+ map_info.data.size >= 115200
49
+ end
50
+ end
51
+ ensure
52
+ @pipeline.stop
53
+ end
54
+ end
55
+
56
+ def test_map_fail
57
+ @pipeline.play
58
+ begin
59
+ sample = @sink.try_pull_sample(Gst::SECOND)
60
+ buffer = sample.buffer
61
+
62
+ assert_raise(Gst::CoreError::Failed) do
63
+ buffer.map(:write)
64
+ end
65
+ ensure
66
+ @pipeline.stop
67
+ end
68
+ end
69
+
70
+ def test_map_range_full
71
+ @pipeline.play
72
+ begin
73
+ sample = @sink.try_pull_sample(Gst::SECOND)
74
+ buffer = sample.buffer
75
+ map_info = buffer.map_range(0, -1, :read)
76
+
77
+ assert do
78
+ map_info.data.size >= 115200
79
+ end
80
+ ensure
81
+ @pipeline.stop
82
+ end
83
+ end
84
+
85
+ def test_map_range_with_block
86
+ @pipeline.play
87
+ begin
88
+ sample = @sink.try_pull_sample(Gst::SECOND)
89
+ buffer = sample.buffer
90
+ buffer.map_range(0, -1, :read) do |map_info|
91
+ assert do
92
+ map_info.data.size >= 115200
93
+ end
94
+ end
95
+ ensure
96
+ @pipeline.stop
97
+ end
98
+ end
99
+
100
+ def test_map_range_full_fail
101
+ @pipeline.play
102
+ begin
103
+ sample = @sink.try_pull_sample(Gst::SECOND)
104
+ buffer = sample.buffer
105
+
106
+ assert_raise(Gst::CoreError::Failed) do
107
+ buffer.map_range(0, -1, :write)
108
+ end
109
+ ensure
110
+ @pipeline.stop
111
+ end
112
+ end
113
+
114
+ def test_map_range_partial
115
+ allocator = Gst::Allocator.find
116
+ memory1 = allocator.alloc(100)
117
+ memory2 = allocator.alloc(200)
118
+ memory3 = allocator.alloc(300)
119
+ buffer = Gst::Buffer.new
120
+ buffer.append_memory(memory1)
121
+ buffer.append_memory(memory2)
122
+ buffer.append_memory(memory3)
123
+ map_info = buffer.map_range(1, 2, :read)
124
+
125
+ assert_equal(500, map_info.data.size)
126
+ end
127
+ end
@@ -28,8 +28,7 @@ class TestMapInfo < Test::Unit::TestCase
28
28
  begin
29
29
  sample = @sink.try_pull_sample(Gst::SECOND)
30
30
  buffer = sample.buffer
31
- success, map_info = buffer.map(:read)
32
- assert_true(success)
31
+ map_info = buffer.map(:read)
33
32
  assert do
34
33
  map_info.data.size >= 115200
35
34
  end
@@ -0,0 +1,187 @@
1
+ # Copyright (C) 2026 Ruby-GNOME Project Team
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ require "fiddle"
18
+
19
+ class TestSample < Test::Unit::TestCase
20
+ include GStreamerTestUtils
21
+
22
+ AUDIO_TEST_SRC_DEFAULT_SAMPLES_PER_BUFFER = 1024
23
+ AUDIO_TEST_SRC_RAMP = 1
24
+
25
+ def test_memory_view_mono
26
+ only_gstreamer_version(1, 20)
27
+
28
+ samples = generate_samples
29
+
30
+ samples.each_with_index do |sample, i|
31
+ Fiddle::MemoryView.export(sample) do |view|
32
+ assert_equal({
33
+ byte_size: AUDIO_TEST_SRC_DEFAULT_SAMPLES_PER_BUFFER * 4,
34
+ readonly?: true,
35
+ format: "e",
36
+ item_size: 4,
37
+ ndim: 2,
38
+ shape: [AUDIO_TEST_SRC_DEFAULT_SAMPLES_PER_BUFFER, 1],
39
+ strides: [4, 4],
40
+ sub_offsets: nil,
41
+ },
42
+ {
43
+ byte_size: view.byte_size,
44
+ readonly?: view.readonly?,
45
+ format: view.format,
46
+ item_size: view.item_size,
47
+ ndim: view.ndim,
48
+ shape: view.shape,
49
+ strides: view.strides,
50
+ sub_offsets: view.sub_offsets,
51
+ })
52
+
53
+ offset = AUDIO_TEST_SRC_DEFAULT_SAMPLES_PER_BUFFER * i
54
+ (view.byte_size / view.item_size).times do |j|
55
+ assert_in_delta(Math.sin((offset + j + AUDIO_TEST_SRC_RAMP) * 2 * Math::PI * 440 / 16_000) * 0.8,
56
+ view[j, 0],
57
+ 0.001,
58
+ "#{i}th buffer, #{j}th sample")
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ def test_memory_view_stereo
65
+ only_gstreamer_version(1, 20)
66
+
67
+ samples = generate_samples(channels: 2)
68
+
69
+ samples.each_with_index do |sample, i|
70
+ Fiddle::MemoryView.export(sample) do |view|
71
+ assert_equal({
72
+ byte_size: AUDIO_TEST_SRC_DEFAULT_SAMPLES_PER_BUFFER * 4 * 2,
73
+ readonly?: true,
74
+ format: "e",
75
+ item_size: 4,
76
+ ndim: 2,
77
+ shape: [AUDIO_TEST_SRC_DEFAULT_SAMPLES_PER_BUFFER, 2],
78
+ strides: [8, 4],
79
+ sub_offsets: nil,
80
+ },
81
+ {
82
+ byte_size: view.byte_size,
83
+ readonly?: view.readonly?,
84
+ format: view.format,
85
+ item_size: view.item_size,
86
+ ndim: view.ndim,
87
+ shape: view.shape,
88
+ strides: view.strides,
89
+ sub_offsets: view.sub_offsets,
90
+ })
91
+
92
+ offset = AUDIO_TEST_SRC_DEFAULT_SAMPLES_PER_BUFFER * i
93
+ (view.byte_size / view.item_size).times do |j|
94
+ index, channel = j.divmod(2)
95
+ expected_value = Math.sin((offset + index + AUDIO_TEST_SRC_RAMP) * 2 * Math::PI * 440 / 16_000) * 0.8
96
+ assert_in_delta(expected_value, view[index, channel], 0.001, "#{i}th buffer, #{channel}th channel, #{index}th sample")
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ def test_memory_view_non_interleaved
103
+ only_gstreamer_version(1, 20)
104
+
105
+ samples = generate_samples(layout: "non-interleaved", channels: 2)
106
+
107
+ assert_raise(ArgumentError) do
108
+ Fiddle::MemoryView.export(samples[0]) {}
109
+ end
110
+ end
111
+
112
+ def test_memory_view_unsupported_format
113
+ only_gstreamer_version(1, 20)
114
+
115
+ samples = generate_samples(format: "S24_32LE")
116
+
117
+ assert_raise(ArgumentError) do
118
+ Fiddle::MemoryView.export(samples[0]) {}
119
+ end
120
+ end
121
+
122
+ def test_memory_view_from_buffer_list
123
+ only_gstreamer_version(1, 20)
124
+
125
+ samples = generate_samples
126
+ assert_equal(15, samples.size)
127
+
128
+ buffer_list = Gst::BufferList.new
129
+ expected_data = +"".b
130
+
131
+ samples.each do |sample|
132
+ buffer = sample.buffer
133
+ buffer.map(:read) do |map|
134
+ expected_data << map.data.pack("C*")
135
+ end
136
+ buffer_list.insert(-1, buffer)
137
+ end
138
+
139
+ caps = samples.first.caps
140
+ sample = Gst::Sample.new(Gst::Buffer.new, caps, Gst::Segment.new, caps.structures[0])
141
+ sample.buffer_list = buffer_list
142
+
143
+ Fiddle::MemoryView.export(sample) do |view|
144
+ assert_equal(expected_data, view.to_s)
145
+ end
146
+ end
147
+
148
+ private
149
+
150
+ def generate_samples(format: "F32LE", layout: "interleaved", rate: 16_000, channels: 1)
151
+ samples = []
152
+
153
+ pipeline = Gst::Pipeline.new("audio-generator")
154
+ src = Gst::ElementFactory.make("audiotestsrc", nil)
155
+ convert = Gst::ElementFactory.make("audioconvert", nil)
156
+ sink = Gst::ElementFactory.make("appsink", nil)
157
+
158
+ src.set_property("num-buffers", rate / AUDIO_TEST_SRC_DEFAULT_SAMPLES_PER_BUFFER)
159
+
160
+ caps = Gst::Caps.new("audio/x-raw")
161
+ caps["format"] = format
162
+ caps["rate", :int] = rate
163
+ caps["channels", :int] = channels
164
+ caps["layout"] = layout
165
+
166
+ sink.caps = caps
167
+
168
+ pipeline << src << convert << sink
169
+ src >> convert >> sink
170
+
171
+ pipeline.play
172
+ begin
173
+ loop do
174
+ sample = sink.try_pull_sample(Gst::SECOND)
175
+ if sample
176
+ samples << sample
177
+ else
178
+ break
179
+ end
180
+ end
181
+ ensure
182
+ pipeline.stop
183
+ end
184
+
185
+ samples
186
+ end
187
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gstreamer
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.3.6
4
+ version: 4.3.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Ruby-GNOME Project Team
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 4.3.6
18
+ version: 4.3.7
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 4.3.6
25
+ version: 4.3.7
26
26
  description: Ruby/GStreamer is a Ruby binding for GStreamer.
27
27
  email: ruby-gnome2-devel-en@lists.sourceforge.net
28
28
  executables: []
@@ -37,6 +37,7 @@ files:
37
37
  - ext/gstreamer/extconf.rb
38
38
  - ext/gstreamer/rbgst-child-proxy.c
39
39
  - ext/gstreamer/rbgst-element.c
40
+ - ext/gstreamer/rbgst-sample.c
40
41
  - ext/gstreamer/rbgst.c
41
42
  - ext/gstreamer/rbgst.h
42
43
  - extconf.rb
@@ -45,6 +46,7 @@ files:
45
46
  - lib/gst/audio-loader.rb
46
47
  - lib/gst/base-loader.rb
47
48
  - lib/gst/bin.rb
49
+ - lib/gst/buffer.rb
48
50
  - lib/gst/bus.rb
49
51
  - lib/gst/caps.rb
50
52
  - lib/gst/controller-loader.rb
@@ -74,11 +76,13 @@ files:
74
76
  - test/run-test.rb
75
77
  - test/test-audio.rb
76
78
  - test/test-bin.rb
79
+ - test/test-buffer.rb
77
80
  - test/test-bus.rb
78
81
  - test/test-caps.rb
79
82
  - test/test-child-proxy.rb
80
83
  - test/test-element-factory.rb
81
84
  - test/test-map-info.rb
85
+ - test/test-sample.rb
82
86
  - test/test-tag-list.rb
83
87
  - test/test-version.rb
84
88
  homepage: https://ruby-gnome.github.io/
@@ -106,10 +110,19 @@ requirements:
106
110
  - 'system: gstreamer-1.0: conda: gstreamer'
107
111
  - 'system: gstreamer-1.0: debian: libgstreamer1.0-dev'
108
112
  - 'system: gstreamer-1.0: homebrew: gstreamer'
109
- - 'system: gstreamer-1.0: macports: gstreamer'
113
+ - 'system: gstreamer-1.0: macports: gstreamer1'
110
114
  - 'system: gstreamer-1.0: msys2: gstreamer'
111
115
  - 'system: gstreamer-1.0: rhel: pkgconfig(gstreamer-1.0)'
112
- rubygems_version: 4.0.6
116
+ - 'system: gstreamer-audio-1.0: alpine_linux: gst-plugins-base-dev'
117
+ - 'system: gstreamer-audio-1.0: alt_linux: gst-plugins1.0-devel'
118
+ - 'system: gstreamer-audio-1.0: alt_linux: liborc-devel'
119
+ - 'system: gstreamer-audio-1.0: arch_linux: gst-plugins-base'
120
+ - 'system: gstreamer-audio-1.0: conda: gst-plugins-base'
121
+ - 'system: gstreamer-audio-1.0: debian: libgstreamer-plugins-base1.0-dev'
122
+ - 'system: gstreamer-audio-1.0: macports: gstreamer1-gst-plugins-base'
123
+ - 'system: gstreamer-audio-1.0: msys2: gst-plugins-base'
124
+ - 'system: gstreamer-audio-1.0: rhel: pkgconfig(gstreamer-audio-1.0)'
125
+ rubygems_version: 4.0.10
113
126
  specification_version: 4
114
127
  summary: Ruby/GStreamer is a Ruby binding for GStreamer.
115
128
  test_files: []