rays-video 0.1.2

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.
data/README.md ADDED
@@ -0,0 +1,147 @@
1
+ # Rays Video - Video support for Rays
2
+
3
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/xord/rays-video)
4
+ ![License](https://img.shields.io/github/license/xord/rays-video)
5
+ ![Build Status](https://github.com/xord/rays-video/actions/workflows/test.yml/badge.svg)
6
+ ![Gem Version](https://badge.fury.io/rb/rays-video.svg)
7
+
8
+ ## ⚠️ Notice
9
+
10
+ This repository is a read-only mirror of our monorepo.
11
+ We do not accept pull requests or direct contributions here.
12
+
13
+ ### 🔄 Where to Contribute?
14
+
15
+ All development happens in our [xord/all](https://github.com/xord/all) monorepo, which contains all our main libraries.
16
+ If you'd like to contribute, please submit your changes there.
17
+
18
+ For more details, check out our [Contribution Guidelines](./CONTRIBUTING.md).
19
+
20
+ Thanks for your support! 🙌
21
+
22
+ ## 🚀 About
23
+
24
+ **Rays Video** is a small extension to [Rays](https://github.com/xord/rays) that adds video reading, writing, and frame-level manipulation. A `Rays::Video` is, conceptually, an ordered list of `Rays::Image` frames with a frame rate and a pixel density — you can build one from scratch, append / insert / remove frames, scrub a playback position, load a video from disk, save it back out, or grab any frame as a regular `Rays::Image` to draw with.
25
+
26
+ Audio support is built on [Beeps](https://github.com/xord/beeps) — video files keep their audio track and it can be fed into a Beeps processor chain.
27
+
28
+ Like the rest of the `xord/*` family, this gem is primarily developed for our own use, but it works as a standalone video gem.
29
+
30
+ > **Platform status:** macOS / iOS only at the moment. Windows and Linux backends are not yet implemented.
31
+
32
+ ## 📋 Requirements
33
+
34
+ - Ruby **3.0.0** or later
35
+ - A C++ compiler with C++20 support
36
+ - [Xot](https://rubygems.org/gems/xot), [Rucy](https://rubygems.org/gems/rucy), [Beeps](https://rubygems.org/gems/beeps), and [Rays](https://rubygems.org/gems/rays) (declared as runtime dependencies)
37
+ - **macOS / iOS** — AVFoundation (bundled with the OS)
38
+
39
+ ## 📦 Installation
40
+
41
+ Add this line to your Gemfile:
42
+ ```ruby
43
+ gem 'rays-video'
44
+ ```
45
+
46
+ Then install:
47
+ ```bash
48
+ $ bundle install
49
+ ```
50
+
51
+ Or install it directly:
52
+ ```bash
53
+ $ gem install rays-video
54
+ ```
55
+
56
+ ## 📚 What's Provided
57
+
58
+ ### `Rays::Video`
59
+
60
+ A finite sequence of `Rays::Image` frames with a fixed `width`, `height`, `fps`, and `pixel_density`.
61
+
62
+ | Method | Purpose |
63
+ | ------------------------------------------ | ------------------------------------------------------------------ |
64
+ | `Video.new(width, height, fps:, pixel_density:)` | Create an empty video (`fps` defaults to 30) |
65
+ | `Video.load(path)` | Load a video file from disk |
66
+ | `Video.exts` | Supported video file extensions on the current platform |
67
+ | `video.append(*images)` | Append one or more frames |
68
+ | `video.insert(index, *images)` | Insert frames at the given index |
69
+ | `video.remove(index)` | Remove the frame at the given index |
70
+ | `video.each { \|image\| ... }` | Iterate frames (also includes `Enumerable`) |
71
+ | `video[i]` | Get the frame at index *i* as a `Rays::Image` |
72
+ | `video.pos` / `video.pos =` | Current playback position (index) |
73
+ | `video.play` / `video.pause` / `video.stop`| Playback controls |
74
+ | `video.time_scale` / `video.time_scale =` | Speed multiplier for playback |
75
+ | `video.size`, `video.empty?` | Frame count / emptiness |
76
+ | `video.width`, `video.height`, `video.fps`, `video.pixel_density` | Read-only metadata |
77
+ | `video.dup` | Deep-ish copy (shares image references) |
78
+ | `video.save(path)` | Encode the video to a file |
79
+ | `video.to_image` (`Image()` cast) | Get the frame at the current `pos` as a `Rays::Image` |
80
+
81
+ ## 💡 Usage
82
+
83
+ ### Build a video from frames and save it
84
+
85
+ ```ruby
86
+ require 'rays'
87
+ require 'rays/video'
88
+
89
+ video = Rays::Video.new(320, 240, fps: 30)
90
+
91
+ 60.times do |n|
92
+ frame = Rays::Image.new(320, 240)
93
+ frame.paint do |p|
94
+ p.background 0
95
+ p.fill 1, 0.5, 0.1
96
+ p.ellipse n * 5, 120, 60, 60
97
+ end
98
+ video.append frame
99
+ end
100
+
101
+ video.save 'out.mp4'
102
+ ```
103
+
104
+ ### Load a video and draw a frame
105
+
106
+ ```ruby
107
+ require 'rays'
108
+ require 'rays/video'
109
+
110
+ video = Rays::Video.load 'clip.mp4'
111
+ puts "#{video.width}×#{video.height} @ #{video.fps}fps, #{video.size} frames"
112
+
113
+ # get the 30th frame as an Image and save it
114
+ video[30].save 'frame30.png'
115
+ ```
116
+
117
+ ### Scrub through a video
118
+
119
+ ```ruby
120
+ video = Rays::Video.load 'clip.mp4'
121
+
122
+ video.pos = 0
123
+ target = Rays::Image.new video.width, video.height
124
+ target.paint do |p|
125
+ p.image video.to_image
126
+ end
127
+
128
+ video.pos = video.size / 2 # mid-point
129
+ mid = video.to_image
130
+ ```
131
+
132
+ ## 🛠️ Development
133
+
134
+ ```bash
135
+ $ rake lib # build the native C++ library (librays-video)
136
+ $ rake ext # build the Ruby C extension
137
+ $ rake test # run the test suite (macOS / iOS only)
138
+ $ rake doc # generate RDoc from C++ sources
139
+ $ rake # default: builds the extension
140
+ ```
141
+
142
+ In the [`xord/all`](https://github.com/xord/all) monorepo you can scope by module, e.g. `rake rays-video test`.
143
+
144
+ ## 📜 License
145
+
146
+ **Rays Video** is licensed under the MIT License.
147
+ See the [LICENSE](./LICENSE) file for details.
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ # -*- mode: ruby -*-
2
+
3
+ %w[../xot ../rucy ../beeps ../rays .]
4
+ .map {|s| File.expand_path "#{s}/lib", __dir__}
5
+ .each {|s| $:.unshift s if !$:.include?(s) && File.directory?(s)}
6
+
7
+ require 'rucy/rake'
8
+
9
+ require 'xot/extension'
10
+ require 'rucy/extension'
11
+ require 'beeps/extension'
12
+ require 'rays/extension'
13
+ require 'rays-video/extension'
14
+
15
+
16
+ EXTENSIONS = [Xot, Rucy, Beeps, Rays, RaysVideo]
17
+ TESTS_ALONE = []
18
+
19
+ default_tasks :ext
20
+ use_bundler
21
+ build_native_library
22
+ build_ruby_extension
23
+ test_ruby_extension unless github_actions? && win32?
24
+ generate_documents
25
+ build_ruby_gem
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.2
@@ -0,0 +1,17 @@
1
+ // -*- c++ -*-
2
+ #pragma once
3
+ #ifndef __RAYS_VIDEO_EXT_DEFS_H__
4
+ #define __RAYS_VIDEO_EXT_DEFS_H__
5
+
6
+
7
+ #include <rucy.h>
8
+ #include "rays/defs.h"
9
+ #include "rays/ruby/defs.h"
10
+
11
+
12
+ using namespace Rucy;
13
+
14
+ using Rays::coord;
15
+
16
+
17
+ #endif//EOH
@@ -0,0 +1,23 @@
1
+ %w[../xot ../rucy ../beeps ../rays .]
2
+ .map {|s| File.expand_path "../../#{s}/lib", __dir__}
3
+ .each {|s| $:.unshift s if !$:.include?(s) && File.directory?(s)}
4
+
5
+ require 'mkmf'
6
+ require 'xot/extconf'
7
+ require 'xot/extension'
8
+ require 'rucy/extension'
9
+ require 'beeps/extension'
10
+ require 'rays/extension'
11
+ require 'rays-video/extension'
12
+
13
+
14
+ Xot::ExtConf.new Xot, Rucy, Beeps, Rays, RaysVideo do
15
+ setup do
16
+ headers << 'ruby.h'
17
+ libs.unshift 'gdi32', 'opengl32', 'glew32' if win32?
18
+ frameworks << 'AppKit' << 'AVFoundation' if osx?
19
+ $LDFLAGS << ' -Wl,--out-implib=librays-video.dll.a' if mingw? || cygwin?
20
+ end
21
+
22
+ create_makefile 'rays_video_ext'
23
+ end
@@ -0,0 +1,17 @@
1
+ #include "defs.h"
2
+
3
+
4
+ void Init_rays_video ();
5
+
6
+
7
+ extern "C" void
8
+ Init_rays_video_ext ()
9
+ {
10
+ RUCY_TRY
11
+
12
+ Rucy::init();
13
+
14
+ Init_rays_video();
15
+
16
+ RUCY_CATCH
17
+ }
@@ -0,0 +1,282 @@
1
+ #include "rays-video/ruby/video.h"
2
+
3
+
4
+ #include "rays/ruby/image.h"
5
+ #include "defs.h"
6
+
7
+
8
+ RUCY_DEFINE_VALUE_FROM_TO(RAYS_VIDEO_EXPORT, Rays::Video)
9
+
10
+ #define THIS to<Rays::Video*>(self)
11
+
12
+ #define CHECK RUCY_CHECK_OBJECT(Rays::Video, self)
13
+
14
+
15
+ static
16
+ RUCY_DEF_ALLOC(alloc, klass)
17
+ {
18
+ return new_type<Rays::Video>(klass);
19
+ }
20
+ RUCY_END
21
+
22
+ static
23
+ RUCY_DEF4(initialize, width, height, fps, pixel_density)
24
+ {
25
+ RUCY_CHECK_OBJ(Rays::Video, self);
26
+
27
+ float fps_ = to<float>(fps);
28
+ *THIS = Rays::Video(
29
+ to<int>(width),
30
+ to<int>(height),
31
+ fps_ > 0 ? fps_ : (float) Rays::Video::DEFAULT_FPS,
32
+ to<float>(pixel_density));
33
+ }
34
+ RUCY_END
35
+
36
+ static
37
+ RUCY_DEF1(initialize_copy, obj)
38
+ {
39
+ RUCY_CHECK_OBJ(Rays::Video, self);
40
+
41
+ *THIS = to<Rays::Video&>(obj).dup();
42
+ }
43
+ RUCY_END
44
+
45
+ static
46
+ RUCY_DEF2(insert, index, image)
47
+ {
48
+ CHECK;
49
+ THIS->insert(to<size_t>(index), to<const Rays::Image&>(image));
50
+ return self;
51
+ }
52
+ RUCY_END
53
+
54
+ static
55
+ RUCY_DEF1(append, image)
56
+ {
57
+ CHECK;
58
+ THIS->append(to<const Rays::Image&>(image));
59
+ return self;
60
+ }
61
+ RUCY_END
62
+
63
+ static
64
+ RUCY_DEF1(remove, index)
65
+ {
66
+ CHECK;
67
+ THIS->remove(to<size_t>(index));
68
+ return self;
69
+ }
70
+ RUCY_END
71
+
72
+ static
73
+ RUCY_DEF1(save, path)
74
+ {
75
+ CHECK;
76
+ THIS->save(path.c_str());
77
+ return self;
78
+ }
79
+ RUCY_END
80
+
81
+ static
82
+ RUCY_DEF0(width)
83
+ {
84
+ CHECK;
85
+ return value(THIS->width());
86
+ }
87
+ RUCY_END
88
+
89
+ static
90
+ RUCY_DEF0(height)
91
+ {
92
+ CHECK;
93
+ return value(THIS->height());
94
+ }
95
+ RUCY_END
96
+
97
+ static
98
+ RUCY_DEF0(fps)
99
+ {
100
+ CHECK;
101
+ return value(THIS->fps());
102
+ }
103
+ RUCY_END
104
+
105
+ static
106
+ RUCY_DEF0(pixel_density)
107
+ {
108
+ CHECK;
109
+ return value(THIS->pixel_density());
110
+ }
111
+ RUCY_END
112
+
113
+ static
114
+ RUCY_DEF0(size)
115
+ {
116
+ CHECK;
117
+ return value(THIS->size());
118
+ }
119
+ RUCY_END
120
+
121
+ static
122
+ RUCY_DEF0(empty)
123
+ {
124
+ CHECK;
125
+ return value(THIS->empty());
126
+ }
127
+ RUCY_END
128
+
129
+ static
130
+ RUCY_DEF1(set_position, position)
131
+ {
132
+ CHECK;
133
+ THIS->set_position(to<size_t>(position));
134
+ return position;
135
+ }
136
+ RUCY_END
137
+
138
+ static
139
+ RUCY_DEF0(get_position)
140
+ {
141
+ CHECK;
142
+ return value(THIS->position());
143
+ }
144
+ RUCY_END
145
+
146
+ static
147
+ RUCY_DEF0(each)
148
+ {
149
+ CHECK;
150
+ Value ret;
151
+ for (auto it = THIS->begin(), end = THIS->end(); it != end; ++it)
152
+ ret = rb_yield(value(*it));
153
+ return ret;
154
+ }
155
+ RUCY_END
156
+
157
+ static
158
+ RUCY_DEF0(to_image)
159
+ {
160
+ CHECK;
161
+ return value((Rays::Image) *THIS);
162
+ }
163
+ RUCY_END
164
+
165
+ static
166
+ RUCY_DEF1(at, index)
167
+ {
168
+ CHECK;
169
+ return value((*THIS)[(size_t) to<int>(index)]);
170
+ }
171
+ RUCY_END
172
+
173
+ static
174
+ RUCY_DEF0(play)
175
+ {
176
+ CHECK;
177
+ THIS->play();
178
+ return self;
179
+ }
180
+ RUCY_END
181
+
182
+ static
183
+ RUCY_DEF0(pause)
184
+ {
185
+ CHECK;
186
+ THIS->pause();
187
+ return self;
188
+ }
189
+ RUCY_END
190
+
191
+ static
192
+ RUCY_DEF0(stop)
193
+ {
194
+ CHECK;
195
+ THIS->stop();
196
+ return self;
197
+ }
198
+ RUCY_END
199
+
200
+ static
201
+ RUCY_DEF1(set_time_scale, scale)
202
+ {
203
+ CHECK;
204
+ THIS->set_time_scale(to<float>(scale));
205
+ return scale;
206
+ }
207
+ RUCY_END
208
+
209
+ static
210
+ RUCY_DEF0(get_time_scale)
211
+ {
212
+ CHECK;
213
+ return value(THIS->time_scale());
214
+ }
215
+ RUCY_END
216
+
217
+ static
218
+ RUCY_DEF1(load, path)
219
+ {
220
+ return value(Rays::load_video(path.c_str()));
221
+ }
222
+ RUCY_END
223
+
224
+ static
225
+ RUCY_DEF0(exts)
226
+ {
227
+ std::vector<Value> list;
228
+ for (const auto& ext : Rays::get_video_exts())
229
+ list.emplace_back(ext.c_str());
230
+ return array(list.data(), list.size());
231
+ }
232
+ RUCY_END
233
+
234
+
235
+ static Class cVideo;
236
+
237
+ void
238
+ Init_rays_video ()
239
+ {
240
+ Module mRays = define_module("Rays");
241
+
242
+ cVideo = mRays.define_class("Video");
243
+ cVideo.define_alloc_func(alloc);
244
+ cVideo.define_private_method("initialize!", initialize);
245
+ cVideo.define_private_method("initialize_copy", initialize_copy);
246
+ cVideo.define_method("insert!", insert);
247
+ cVideo.define_method("append!", append);
248
+ cVideo.define_method("remove!", remove);
249
+ cVideo.define_method("save", save);
250
+ cVideo.define_method("width", width);
251
+ cVideo.define_method("height", height);
252
+ cVideo.define_method("fps", fps);
253
+ cVideo.define_method("pixel_density", pixel_density);
254
+ cVideo.define_method("size", size);
255
+ cVideo.define_method("empty?", empty);
256
+ cVideo.define_method("position=", set_position);
257
+ cVideo.define_method("position", get_position);
258
+ cVideo.define_method("play", play);
259
+ cVideo.define_method("pause", pause);
260
+ cVideo.define_method("stop", stop);
261
+ cVideo.define_method("time_scale=", set_time_scale);
262
+ cVideo.define_method("time_scale", get_time_scale);
263
+ cVideo.define_method("each!", each);
264
+ cVideo.define_method("to_image", to_image);
265
+ cVideo.define_method("[]", at);
266
+ cVideo.define_module_function("load", load);
267
+ cVideo.define_module_function("exts", exts);
268
+ }
269
+
270
+
271
+ namespace Rays
272
+ {
273
+
274
+
275
+ Class
276
+ video_class ()
277
+ {
278
+ return cVideo;
279
+ }
280
+
281
+
282
+ }// Rays
@@ -0,0 +1,102 @@
1
+ // -*- c++ -*-
2
+ #pragma once
3
+ #ifndef __RAYS_VIDEO_H__
4
+ #define __RAYS_VIDEO_H__
5
+
6
+
7
+ #include <vector>
8
+ #include <xot/pimpl.h>
9
+ #include <xot/string.h>
10
+ #include <rays/defs.h>
11
+ #include <rays/image.h>
12
+
13
+
14
+ namespace Rays
15
+ {
16
+
17
+
18
+ class Video
19
+ {
20
+
21
+ typedef Video This;
22
+
23
+ public:
24
+
25
+ typedef std::vector<Image> ImageList;
26
+
27
+ typedef ImageList::const_iterator const_iterator;
28
+
29
+ enum {DEFAULT_FPS = 30};
30
+
31
+ Video ();
32
+
33
+ Video (
34
+ int width, int height,
35
+ float fps = DEFAULT_FPS, float pixel_density = 1);
36
+
37
+ ~Video ();
38
+
39
+ This dup () const;
40
+
41
+ void insert (size_t index, const Image& image);
42
+
43
+ void append (const Image& image);
44
+
45
+ void remove (size_t index);
46
+
47
+ void play ();
48
+
49
+ void pause ();
50
+
51
+ void stop ();
52
+
53
+ void set_time_scale (float scale);
54
+
55
+ float time_scale () const;
56
+
57
+ void save (const char* path);
58
+
59
+ coord width () const;
60
+
61
+ coord height () const;
62
+
63
+ float fps () const;
64
+
65
+ float pixel_density () const;
66
+
67
+ size_t size () const;
68
+
69
+ bool empty () const;
70
+
71
+ void set_position (size_t index);
72
+
73
+ size_t position () const;
74
+
75
+ const_iterator begin () const;
76
+
77
+ const_iterator end () const;
78
+
79
+ Image operator [] (size_t index) const;
80
+
81
+ operator Image () const;
82
+
83
+ operator bool () const;
84
+
85
+ bool operator ! () const;
86
+
87
+ struct Data;
88
+
89
+ Xot::PSharedImpl<Data> self;
90
+
91
+ };// Video
92
+
93
+
94
+ Video load_video (const char* path);
95
+
96
+ const StringList& get_video_exts ();
97
+
98
+
99
+ }// Rays
100
+
101
+
102
+ #endif//EOH
@@ -0,0 +1,47 @@
1
+ // -*- c++ -*-
2
+ #pragma once
3
+ #ifndef __RAYS_VIDEO_RUBY_VIDEO_H__
4
+ #define __RAYS_VIDEO_RUBY_VIDEO_H__
5
+
6
+
7
+ #include <rucy/class.h>
8
+ #include <rucy/extension.h>
9
+ #include <rays/video.h>
10
+
11
+
12
+ #if defined(WIN32) && defined(GCC) && defined(RAYS_VIDEO)
13
+ #define RAYS_VIDEO_EXPORT __declspec(dllexport)
14
+ #else
15
+ #define RAYS_VIDEO_EXPORT
16
+ #endif
17
+
18
+
19
+ RUCY_DECLARE_VALUE_FROM_TO(RAYS_VIDEO_EXPORT, Rays::Video)
20
+
21
+
22
+ namespace Rays
23
+ {
24
+
25
+
26
+ RAYS_VIDEO_EXPORT Rucy::Class video_class ();
27
+ // class Rays::Video
28
+
29
+
30
+ }// Rays
31
+
32
+
33
+ namespace Rucy
34
+ {
35
+
36
+
37
+ template <> inline Class
38
+ get_ruby_class<Rays::Video> ()
39
+ {
40
+ return Rays::video_class();
41
+ }
42
+
43
+
44
+ }// Rucy
45
+
46
+
47
+ #endif//EOH
@@ -0,0 +1,10 @@
1
+ // -*- c++ -*-
2
+ #pragma once
3
+ #ifndef __RAYS_VIDEO_RUBY_ALL_H__
4
+ #define __RAYS_VIDEO_RUBY_ALL_H__
5
+
6
+
7
+ #include <rays-video/ruby/video.h>
8
+
9
+
10
+ #endif//EOH
@@ -0,0 +1,10 @@
1
+ // -*- c++ -*-
2
+ #pragma once
3
+ #ifndef __RAYS_VIDEO_ALL_H__
4
+ #define __RAYS_VIDEO_ALL_H__
5
+
6
+
7
+ #include <rays/video.h>
8
+
9
+
10
+ #endif//EOH