rays-video 0.2.0 → 0.3.0
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 +4 -4
- data/.doc/ext/rays-video/video.cpp +68 -57
- data/.github/workflows/release-gem.yml +2 -49
- data/.github/workflows/tag.yml +5 -28
- data/.github/workflows/test.yml +1 -37
- data/ChangeLog.md +15 -0
- data/Gemfile.lock +26 -0
- data/README.md +24 -2
- data/VERSION +1 -1
- data/ext/rays-video/extconf.rb +2 -1
- data/ext/rays-video/video.cpp +72 -60
- data/include/rays/video.h +19 -15
- data/lib/rays/video.rb +4 -0
- data/rays-video.gemspec +5 -5
- data/src/ios/video.mm +1 -632
- data/src/ios/video_audio_in.mm +1 -251
- data/src/osx/video.mm +283 -57
- data/src/osx/video_audio_in.mm +2 -1
- data/src/sdl/video.cpp +19 -13
- data/src/video.cpp +202 -85
- data/src/video.h +7 -5
- data/src/win32/video.cpp +19 -13
- data/test/test_video.rb +164 -27
- metadata +12 -13
- data/.github/workflows/utils.rb +0 -127
- data/src/ios/video_audio_in.h +0 -22
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2bfe8646da57777c45c2061d2343f5872f095c5b05166abe3264b6c47150756b
|
|
4
|
+
data.tar.gz: b7216425b5f1941be61dfe3aa7744cedcfa72e21a95e552e466e28a3dfe623e8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 120b483fdbe17c7890739cf20e2f6f143d0a47e962789aa76f49b8d118fe6f9f34f047a9370c0bd53d870060704c962606ae9c489ce6432cf1c8471483e183e9
|
|
7
|
+
data.tar.gz: 318a8c0ffb1c3f95e0dd1946863fbc6b768ddad518a1f9b3727c6f629f19174eb0ca47e724ed7a0fbb7deda6947644991aaf902a823785c4f09e4d16e958958c
|
|
@@ -9,7 +9,7 @@ RUCY_DEFINE_VALUE_FROM_TO(RAYS_VIDEO_EXPORT, Rays::Video)
|
|
|
9
9
|
|
|
10
10
|
#define THIS to<Rays::Video*>(self)
|
|
11
11
|
|
|
12
|
-
#define CHECK
|
|
12
|
+
#define CHECK RUCY_CHECK_OBJ(Rays::Video, self)
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
static
|
|
@@ -21,7 +21,7 @@ VALUE alloc(VALUE klass)
|
|
|
21
21
|
static
|
|
22
22
|
VALUE initialize(VALUE self, VALUE width, VALUE height, VALUE fps, VALUE pixel_density)
|
|
23
23
|
{
|
|
24
|
-
|
|
24
|
+
RUCY_CHECK_PTR(Rays::Video, self);
|
|
25
25
|
|
|
26
26
|
float fps_ = to<float>(fps);
|
|
27
27
|
*THIS = Rays::Video(
|
|
@@ -34,32 +34,32 @@ VALUE initialize(VALUE self, VALUE width, VALUE height, VALUE fps, VALUE pixel_d
|
|
|
34
34
|
static
|
|
35
35
|
VALUE initialize_copy(VALUE self, VALUE obj)
|
|
36
36
|
{
|
|
37
|
-
|
|
37
|
+
RUCY_CHECK_PTR(Rays::Video, self);
|
|
38
38
|
|
|
39
39
|
*THIS = to<Rays::Video&>(obj).dup();
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
static
|
|
43
|
-
VALUE
|
|
43
|
+
VALUE play(VALUE self)
|
|
44
44
|
{
|
|
45
45
|
CHECK;
|
|
46
|
-
THIS->
|
|
46
|
+
THIS->play();
|
|
47
47
|
return self;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
static
|
|
51
|
-
VALUE
|
|
51
|
+
VALUE pause(VALUE self)
|
|
52
52
|
{
|
|
53
53
|
CHECK;
|
|
54
|
-
THIS->
|
|
54
|
+
THIS->pause();
|
|
55
55
|
return self;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
static
|
|
59
|
-
VALUE
|
|
59
|
+
VALUE stop(VALUE self)
|
|
60
60
|
{
|
|
61
61
|
CHECK;
|
|
62
|
-
THIS->
|
|
62
|
+
THIS->stop();
|
|
63
63
|
return self;
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -85,6 +85,13 @@ VALUE height(VALUE self)
|
|
|
85
85
|
return value(THIS->height());
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
static
|
|
89
|
+
VALUE pixel_density(VALUE self)
|
|
90
|
+
{
|
|
91
|
+
CHECK;
|
|
92
|
+
return value(THIS->pixel_density());
|
|
93
|
+
}
|
|
94
|
+
|
|
88
95
|
static
|
|
89
96
|
VALUE fps(VALUE self)
|
|
90
97
|
{
|
|
@@ -93,102 +100,103 @@ VALUE fps(VALUE self)
|
|
|
93
100
|
}
|
|
94
101
|
|
|
95
102
|
static
|
|
96
|
-
VALUE
|
|
103
|
+
VALUE set_position(VALUE self, VALUE position)
|
|
97
104
|
{
|
|
98
105
|
CHECK;
|
|
99
|
-
|
|
106
|
+
THIS->set_position(to<size_t>(position));
|
|
107
|
+
return position;
|
|
100
108
|
}
|
|
101
109
|
|
|
102
110
|
static
|
|
103
|
-
VALUE
|
|
111
|
+
VALUE get_position(VALUE self)
|
|
104
112
|
{
|
|
105
113
|
CHECK;
|
|
106
|
-
return value(THIS->
|
|
114
|
+
return value(THIS->position());
|
|
107
115
|
}
|
|
108
116
|
|
|
109
117
|
static
|
|
110
|
-
VALUE
|
|
118
|
+
VALUE set_time_scale(VALUE self, VALUE scale)
|
|
111
119
|
{
|
|
112
120
|
CHECK;
|
|
113
|
-
|
|
121
|
+
THIS->set_time_scale(to<float>(scale));
|
|
122
|
+
return scale;
|
|
114
123
|
}
|
|
115
124
|
|
|
116
125
|
static
|
|
117
|
-
VALUE
|
|
126
|
+
VALUE get_time_scale(VALUE self)
|
|
118
127
|
{
|
|
119
128
|
CHECK;
|
|
120
|
-
THIS->
|
|
121
|
-
return position;
|
|
129
|
+
return value(THIS->time_scale());
|
|
122
130
|
}
|
|
123
131
|
|
|
124
132
|
static
|
|
125
|
-
VALUE
|
|
133
|
+
VALUE insert(VALUE self, VALUE index, VALUE image)
|
|
126
134
|
{
|
|
127
135
|
CHECK;
|
|
128
|
-
|
|
136
|
+
THIS->insert(to<size_t>(index), to<const Rays::Image&>(image));
|
|
137
|
+
return self;
|
|
129
138
|
}
|
|
130
139
|
|
|
131
140
|
static
|
|
132
|
-
VALUE
|
|
141
|
+
VALUE append(VALUE self, VALUE image)
|
|
133
142
|
{
|
|
134
143
|
CHECK;
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
ret = yield(value(*it));
|
|
138
|
-
return ret;
|
|
144
|
+
THIS->append(to<const Rays::Image&>(image));
|
|
145
|
+
return self;
|
|
139
146
|
}
|
|
140
147
|
|
|
141
148
|
static
|
|
142
|
-
VALUE
|
|
149
|
+
VALUE remove(VALUE self, VALUE index)
|
|
143
150
|
{
|
|
144
151
|
CHECK;
|
|
145
|
-
|
|
152
|
+
THIS->remove(to<size_t>(index));
|
|
153
|
+
return self;
|
|
146
154
|
}
|
|
147
155
|
|
|
148
156
|
static
|
|
149
|
-
VALUE
|
|
157
|
+
VALUE set_at(VALUE self, VALUE index, VALUE image)
|
|
150
158
|
{
|
|
151
159
|
CHECK;
|
|
152
|
-
|
|
160
|
+
THIS->set(to<size_t>(index), to<const Rays::Image&>(image));
|
|
161
|
+
return image;
|
|
153
162
|
}
|
|
154
163
|
|
|
155
164
|
static
|
|
156
|
-
VALUE
|
|
165
|
+
VALUE get_at(VALUE self, VALUE index)
|
|
157
166
|
{
|
|
158
167
|
CHECK;
|
|
159
|
-
THIS->
|
|
160
|
-
return self;
|
|
168
|
+
return value(THIS->get(to<size_t>(index)));
|
|
161
169
|
}
|
|
162
170
|
|
|
163
171
|
static
|
|
164
|
-
VALUE
|
|
172
|
+
VALUE size(VALUE self)
|
|
165
173
|
{
|
|
166
174
|
CHECK;
|
|
167
|
-
THIS->
|
|
168
|
-
return self;
|
|
175
|
+
return value(THIS->size());
|
|
169
176
|
}
|
|
170
177
|
|
|
171
178
|
static
|
|
172
|
-
VALUE
|
|
179
|
+
VALUE empty(VALUE self)
|
|
173
180
|
{
|
|
174
181
|
CHECK;
|
|
175
|
-
THIS->
|
|
176
|
-
return self;
|
|
182
|
+
return value(THIS->empty());
|
|
177
183
|
}
|
|
178
184
|
|
|
179
185
|
static
|
|
180
|
-
VALUE
|
|
186
|
+
VALUE each(VALUE self)
|
|
181
187
|
{
|
|
182
188
|
CHECK;
|
|
183
|
-
|
|
184
|
-
|
|
189
|
+
Value ret;
|
|
190
|
+
for (auto it = THIS->begin(), end = THIS->end(); it != end; ++it)
|
|
191
|
+
ret = yield(value(*it));
|
|
192
|
+
return ret;
|
|
185
193
|
}
|
|
186
194
|
|
|
187
195
|
static
|
|
188
|
-
VALUE
|
|
196
|
+
VALUE to_image(VALUE self)
|
|
189
197
|
{
|
|
190
198
|
CHECK;
|
|
191
|
-
return value(
|
|
199
|
+
return value((Rays::Image) *THIS);
|
|
192
200
|
}
|
|
193
201
|
|
|
194
202
|
static
|
|
@@ -200,10 +208,12 @@ VALUE load(VALUE self, VALUE path)
|
|
|
200
208
|
static
|
|
201
209
|
VALUE exts(VALUE self)
|
|
202
210
|
{
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
211
|
+
const auto& exts = Rays::get_video_exts();
|
|
212
|
+
|
|
213
|
+
Value list = array(NULL, exts.size());
|
|
214
|
+
for (const auto& ext : exts)
|
|
215
|
+
list.push(ext.c_str());
|
|
216
|
+
return list;
|
|
207
217
|
}
|
|
208
218
|
|
|
209
219
|
|
|
@@ -218,26 +228,27 @@ Init_rays_video ()
|
|
|
218
228
|
rb_define_alloc_func(cVideo, alloc);
|
|
219
229
|
cVideo.define_private_method("initialize!", initialize);
|
|
220
230
|
rb_define_private_method(cVideo, "initialize_copy", RUBY_METHOD_FUNC(initialize_copy), 1);
|
|
221
|
-
cVideo
|
|
222
|
-
cVideo
|
|
223
|
-
cVideo
|
|
231
|
+
rb_define_method(cVideo, "play", RUBY_METHOD_FUNC(play), 0);
|
|
232
|
+
rb_define_method(cVideo, "pause", RUBY_METHOD_FUNC(pause), 0);
|
|
233
|
+
rb_define_method(cVideo, "stop", RUBY_METHOD_FUNC(stop), 0);
|
|
224
234
|
rb_define_method(cVideo, "save", RUBY_METHOD_FUNC(save), 1);
|
|
225
235
|
rb_define_method(cVideo, "width", RUBY_METHOD_FUNC(width), 0);
|
|
226
236
|
rb_define_method(cVideo, "height", RUBY_METHOD_FUNC(height), 0);
|
|
227
|
-
rb_define_method(cVideo, "fps", RUBY_METHOD_FUNC(fps), 0);
|
|
228
237
|
rb_define_method(cVideo, "pixel_density", RUBY_METHOD_FUNC(pixel_density), 0);
|
|
229
|
-
rb_define_method(cVideo, "
|
|
230
|
-
cVideo.define_method("empty?", empty);
|
|
238
|
+
rb_define_method(cVideo, "fps", RUBY_METHOD_FUNC(fps), 0);
|
|
231
239
|
rb_define_method(cVideo, "position=", RUBY_METHOD_FUNC(set_position), 1);
|
|
232
240
|
rb_define_method(cVideo, "position", RUBY_METHOD_FUNC(get_position), 0);
|
|
233
|
-
rb_define_method(cVideo, "play", RUBY_METHOD_FUNC(play), 0);
|
|
234
|
-
rb_define_method(cVideo, "pause", RUBY_METHOD_FUNC(pause), 0);
|
|
235
|
-
rb_define_method(cVideo, "stop", RUBY_METHOD_FUNC(stop), 0);
|
|
236
241
|
rb_define_method(cVideo, "time_scale=", RUBY_METHOD_FUNC(set_time_scale), 1);
|
|
237
242
|
rb_define_method(cVideo, "time_scale", RUBY_METHOD_FUNC(get_time_scale), 0);
|
|
243
|
+
cVideo.define_method("insert!", insert);
|
|
244
|
+
cVideo.define_method("append!", append);
|
|
245
|
+
cVideo.define_method("remove!", remove);
|
|
246
|
+
cVideo.define_method("[]=", set_at);
|
|
247
|
+
cVideo.define_method("[]", get_at);
|
|
248
|
+
rb_define_method(cVideo, "size", RUBY_METHOD_FUNC(size), 0);
|
|
249
|
+
cVideo.define_method("empty?", empty);
|
|
238
250
|
cVideo.define_method("each!", each);
|
|
239
251
|
rb_define_method(cVideo, "to_image", RUBY_METHOD_FUNC(to_image), 0);
|
|
240
|
-
cVideo.define_method("[]", at);
|
|
241
252
|
rb_define_module_function(cVideo, "load", RUBY_METHOD_FUNC(load), 1);
|
|
242
253
|
rb_define_module_function(cVideo, "exts", RUBY_METHOD_FUNC(exts), 0);
|
|
243
254
|
}
|
|
@@ -9,52 +9,5 @@ permissions:
|
|
|
9
9
|
|
|
10
10
|
jobs:
|
|
11
11
|
release:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
steps:
|
|
15
|
-
- name: ruby 3.2
|
|
16
|
-
uses: ruby/setup-ruby@v1
|
|
17
|
-
with:
|
|
18
|
-
ruby-version: 3.2
|
|
19
|
-
|
|
20
|
-
- name: checkout
|
|
21
|
-
uses: actions/checkout@v4
|
|
22
|
-
|
|
23
|
-
- name: setup gems
|
|
24
|
-
run: bundle install
|
|
25
|
-
|
|
26
|
-
- name: setup dependencies
|
|
27
|
-
run: "ruby -I.github/workflows -rutils -e 'setup_dependencies'"
|
|
28
|
-
|
|
29
|
-
- name: packages
|
|
30
|
-
run: bundle exec rake packages
|
|
31
|
-
|
|
32
|
-
- name: setup zig
|
|
33
|
-
if: github.event.repository.name == 'reflex-terminal'
|
|
34
|
-
uses: mlugg/setup-zig@v2
|
|
35
|
-
with:
|
|
36
|
-
version: 0.16.0
|
|
37
|
-
|
|
38
|
-
- name: test
|
|
39
|
-
run: bundle exec rake test
|
|
40
|
-
|
|
41
|
-
- name: create gem
|
|
42
|
-
id: gem
|
|
43
|
-
run: |
|
|
44
|
-
bundle exec rake gem
|
|
45
|
-
echo path=$(ruby -e 'print Dir.glob("*.gem").first') >> $GITHUB_OUTPUT
|
|
46
|
-
|
|
47
|
-
- name: create github release
|
|
48
|
-
env:
|
|
49
|
-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
50
|
-
run: ruby -I.github/workflows -rutils -e 'release(*ARGV)' ./${{ steps.gem.outputs.path }}
|
|
51
|
-
|
|
52
|
-
- name: upload to rubygems
|
|
53
|
-
env:
|
|
54
|
-
GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_AUTH_TOKEN }}
|
|
55
|
-
run: |
|
|
56
|
-
mkdir -p $HOME/.gem
|
|
57
|
-
touch $HOME/.gem/credentials
|
|
58
|
-
chmod 0600 $HOME/.gem/credentials
|
|
59
|
-
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
|
60
|
-
bundle exec rake upload
|
|
12
|
+
uses: xord/xot/.github/workflows/release-gem.yml@master
|
|
13
|
+
secrets: inherit
|
data/.github/workflows/tag.yml
CHANGED
|
@@ -1,35 +1,12 @@
|
|
|
1
1
|
name: Tag
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
|
-
|
|
4
|
+
workflow_run:
|
|
5
|
+
workflows: [Test]
|
|
6
|
+
types: [completed]
|
|
5
7
|
branches: [master]
|
|
6
8
|
|
|
7
9
|
jobs:
|
|
8
10
|
tag:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
steps:
|
|
12
|
-
- name: ruby 3.2
|
|
13
|
-
uses: ruby/setup-ruby@v1
|
|
14
|
-
with:
|
|
15
|
-
ruby-version: 3.2
|
|
16
|
-
|
|
17
|
-
- name: checkout
|
|
18
|
-
uses: actions/checkout@v4
|
|
19
|
-
with:
|
|
20
|
-
fetch-depth: 0
|
|
21
|
-
token: ${{ secrets.PAT }}
|
|
22
|
-
|
|
23
|
-
- name: setup dependencies
|
|
24
|
-
run: "ruby -I.github/workflows -rutils -e 'setup_dependencies only: :xot'"
|
|
25
|
-
|
|
26
|
-
- name: setup user name and email
|
|
27
|
-
run: |
|
|
28
|
-
git config --global user.email "xordog@gmail.com"
|
|
29
|
-
git config --global user.name "xord"
|
|
30
|
-
|
|
31
|
-
- name: tag versions
|
|
32
|
-
run: "ruby -I.github/workflows -rutils -e 'tag_versions'"
|
|
33
|
-
|
|
34
|
-
- name: push tags
|
|
35
|
-
run: git push origin --tags
|
|
11
|
+
uses: xord/xot/.github/workflows/tag.yml@master
|
|
12
|
+
secrets: inherit
|
data/.github/workflows/test.yml
CHANGED
|
@@ -7,40 +7,4 @@ on:
|
|
|
7
7
|
|
|
8
8
|
jobs:
|
|
9
9
|
test:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
steps:
|
|
13
|
-
- name: ruby 3.2
|
|
14
|
-
uses: ruby/setup-ruby@v1
|
|
15
|
-
with:
|
|
16
|
-
ruby-version: 3.2
|
|
17
|
-
|
|
18
|
-
- name: checkout
|
|
19
|
-
uses: actions/checkout@v4
|
|
20
|
-
|
|
21
|
-
- name: setup gems
|
|
22
|
-
run: bundle install
|
|
23
|
-
|
|
24
|
-
- name: setup dependencies
|
|
25
|
-
run: "ruby -I.github/workflows -rutils -e 'setup_dependencies'"
|
|
26
|
-
|
|
27
|
-
- name: packages
|
|
28
|
-
run: bundle exec rake verbose packages
|
|
29
|
-
|
|
30
|
-
- name: setup zig
|
|
31
|
-
if: github.event.repository.name == 'reflex-terminal'
|
|
32
|
-
uses: mlugg/setup-zig@v2
|
|
33
|
-
with:
|
|
34
|
-
version: 0.16.0
|
|
35
|
-
|
|
36
|
-
- name: vendor
|
|
37
|
-
run: bundle exec rake vendor
|
|
38
|
-
|
|
39
|
-
- name: lib
|
|
40
|
-
run: bundle exec rake verbose lib
|
|
41
|
-
|
|
42
|
-
- name: ext
|
|
43
|
-
run: bundle exec rake verbose ext
|
|
44
|
-
|
|
45
|
-
- name: test
|
|
46
|
-
run: bundle exec rake verbose test
|
|
10
|
+
uses: xord/xot/.github/workflows/test.yml@master
|
data/ChangeLog.md
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
# rays-video ChangeLog
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## [v0.3.0] - 2026-11-04
|
|
5
|
+
|
|
6
|
+
- [BREAKING] Make the frames of a video read-only views sharing one decoded frame, and take a writable copy by Image#dup
|
|
7
|
+
- [BREAKING] Reject frames whose size or pixel density differs from the video's
|
|
8
|
+
- Decode video files sequentially with AVAssetReader, which is many times faster
|
|
9
|
+
- Add Video#get and #set, as #[] and #[]=
|
|
10
|
+
- Add Video#push and #<< as aliases of #append, which returns self now
|
|
11
|
+
- Show the last frame for an index past the estimated last one
|
|
12
|
+
|
|
13
|
+
- Fix Video#insert crashing on an index past the end, and raise IndexError
|
|
14
|
+
- Fix a crash on the error paths, as saving a GIF to a path that cannot be written
|
|
15
|
+
- Fix linking the extension statically on macOS
|
|
16
|
+
- Fix the build for iOS
|
|
17
|
+
|
|
18
|
+
|
|
4
19
|
## [v0.2.0] - 2026-08-04
|
|
5
20
|
|
|
6
21
|
- Update dependencies
|
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
GEM
|
|
2
|
+
remote: https://rubygems.org/
|
|
3
|
+
specs:
|
|
4
|
+
power_assert (3.1.0)
|
|
5
|
+
rake (13.4.2)
|
|
6
|
+
test-unit (3.7.8)
|
|
7
|
+
power_assert
|
|
8
|
+
yard (0.9.45)
|
|
9
|
+
|
|
10
|
+
PLATFORMS
|
|
11
|
+
ruby
|
|
12
|
+
|
|
13
|
+
DEPENDENCIES
|
|
14
|
+
rake
|
|
15
|
+
test-unit
|
|
16
|
+
yard
|
|
17
|
+
|
|
18
|
+
CHECKSUMS
|
|
19
|
+
bundler (4.0.20) sha256=7978a8ac648767f5e635bc522445b79e80a52b907a39a36c2d8085ed6bc762ae
|
|
20
|
+
power_assert (3.1.0) sha256=fefe98ed5d3140628138f3f9f9194d6ece01f1320e69700d3c928adca7518251
|
|
21
|
+
rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
|
|
22
|
+
test-unit (3.7.8) sha256=689d1ca53f4d46f678b4e5d68d8e4294f87fc5e8b9238cc4de7c5727e8d65943
|
|
23
|
+
yard (0.9.45) sha256=52e211493f7cb8a3ebf7e104a25a1e73937a3103092545d34cb88fafebb3dc51
|
|
24
|
+
|
|
25
|
+
BUNDLED WITH
|
|
26
|
+
4.0.20
|
data/README.md
CHANGED
|
@@ -64,20 +64,28 @@ A finite sequence of `Rays::Image` frames with a fixed `width`, `height`, `fps`,
|
|
|
64
64
|
| `Video.new(width, height, fps:, pixel_density:)` | Create an empty video (`fps` defaults to 30) |
|
|
65
65
|
| `Video.load(path)` | Load a video file from disk |
|
|
66
66
|
| `Video.exts` | Supported video file extensions on the current platform |
|
|
67
|
-
| `video.append(*images)` | Append one or more frames
|
|
67
|
+
| `video.append(*images)` | Append one or more frames (also `push` and `<<`) |
|
|
68
68
|
| `video.insert(index, *images)` | Insert frames at the given index |
|
|
69
69
|
| `video.remove(index)` | Remove the frame at the given index |
|
|
70
70
|
| `video.each { \|image\| ... }` | Iterate frames (also includes `Enumerable`) |
|
|
71
71
|
| `video[i]` | Get the frame at index *i* as a `Rays::Image` |
|
|
72
|
+
| `video[i] = image` | Replace the frame at index *i* |
|
|
72
73
|
| `video.pos` / `video.pos =` | Current playback position (index) |
|
|
73
74
|
| `video.play` / `video.pause` / `video.stop`| Playback controls |
|
|
74
75
|
| `video.time_scale` / `video.time_scale =` | Speed multiplier for playback |
|
|
75
76
|
| `video.size`, `video.empty?` | Frame count / emptiness |
|
|
76
77
|
| `video.width`, `video.height`, `video.fps`, `video.pixel_density` | Read-only metadata |
|
|
77
|
-
| `video.dup` |
|
|
78
|
+
| `video.dup` | Copy the frame list; loaded frames get their own decoder |
|
|
78
79
|
| `video.save(path)` | Encode the video to a file |
|
|
79
80
|
| `video.to_image` (`Image()` cast) | Get the frame at the current `pos` as a `Rays::Image` |
|
|
80
81
|
|
|
82
|
+
Every frame must have the video's `width`, `height` and `pixel_density`.
|
|
83
|
+
|
|
84
|
+
Frames of a loaded video are read-only views: each source keeps a single
|
|
85
|
+
decoded frame, and a frame's pixels are decoded into it on access. Such
|
|
86
|
+
frames are frozen, so `paint` and `[]=` raise `FrozenError`. `dup` a frame
|
|
87
|
+
to keep or edit it, and put it back with `video[i] = image`.
|
|
88
|
+
|
|
81
89
|
## 💡 Usage
|
|
82
90
|
|
|
83
91
|
### Build a video from frames and save it
|
|
@@ -129,6 +137,20 @@ video.pos = video.size / 2 # mid-point
|
|
|
129
137
|
mid = video.to_image
|
|
130
138
|
```
|
|
131
139
|
|
|
140
|
+
### Edit a frame of a loaded video
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
video = Rays::Video.load 'clip.mp4'
|
|
144
|
+
|
|
145
|
+
frame = video[30].dup # loaded frames are frozen, so copy first
|
|
146
|
+
frame.paint do |p|
|
|
147
|
+
p.fill 1, 0, 0
|
|
148
|
+
p.ellipse 10, 10, 50, 50
|
|
149
|
+
end
|
|
150
|
+
video[30] = frame
|
|
151
|
+
video.save 'edited.mp4'
|
|
152
|
+
```
|
|
153
|
+
|
|
132
154
|
## 🛠️ Development
|
|
133
155
|
|
|
134
156
|
```bash
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.3.0
|
data/ext/rays-video/extconf.rb
CHANGED
|
@@ -15,7 +15,8 @@ Xot::ExtConf.new Xot, Rucy, Beeps, Rays, RaysVideo do
|
|
|
15
15
|
setup do
|
|
16
16
|
headers << 'ruby.h'
|
|
17
17
|
libs.unshift 'gdi32', 'opengl32', 'glew32' if win32?
|
|
18
|
-
frameworks
|
|
18
|
+
frameworks.concat %w[
|
|
19
|
+
AppKit AVFoundation UniformTypeIdentifiers] if osx?
|
|
19
20
|
$LDFLAGS << ' -Wl,--out-implib=librays-video.dll.a' if mingw? || cygwin?
|
|
20
21
|
end
|
|
21
22
|
|