one-k-rmov 0.1.4
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/CHANGELOG +38 -0
- data/LICENSE +20 -0
- data/Manifest +24 -0
- data/README.rdoc +73 -0
- data/Rakefile +16 -0
- data/TODO +15 -0
- data/ext/exporter.c +195 -0
- data/ext/extconf.rb +4 -0
- data/ext/movie.c +457 -0
- data/ext/rmov_ext.c +16 -0
- data/ext/rmov_ext.h +45 -0
- data/ext/track.c +391 -0
- data/lib/quicktime/exporter.rb +10 -0
- data/lib/quicktime/movie.rb +102 -0
- data/lib/quicktime/track.rb +31 -0
- data/lib/rmov.rb +12 -0
- data/rmov.gemspec +32 -0
- data/spec/fixtures/settings.st +0 -0
- data/spec/quicktime/exporter_spec.rb +29 -0
- data/spec/quicktime/movie_spec.rb +189 -0
- data/spec/quicktime/track_spec.rb +86 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +7 -0
- data/tasks/setup.rake +7 -0
- data/tasks/spec.rake +9 -0
- metadata +98 -0
data/ext/movie.c
ADDED
@@ -0,0 +1,457 @@
|
|
1
|
+
#include "rmov_ext.h"
|
2
|
+
|
3
|
+
VALUE cMovie;
|
4
|
+
|
5
|
+
OSErr movie_progress_proc(Movie movie, short message, short operation, Fixed percent, VALUE proc)
|
6
|
+
{
|
7
|
+
rb_funcall(proc, rb_intern("call"), 1, rb_float_new(FixedToFloat(percent)));
|
8
|
+
return 0;
|
9
|
+
}
|
10
|
+
|
11
|
+
static void movie_free(struct RMovie *rMovie)
|
12
|
+
{
|
13
|
+
if (rMovie->movie) {
|
14
|
+
DisposeMovie(rMovie->movie);
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
static void movie_mark(struct RMovie *rMovie)
|
19
|
+
{
|
20
|
+
}
|
21
|
+
|
22
|
+
/*
|
23
|
+
call-seq: new() -> movie
|
24
|
+
|
25
|
+
Creates a new movie instance. Generally you want to go through
|
26
|
+
Movie.open or Movie.empty to load or create a new movie respectively.
|
27
|
+
If you do no then you will need to load the movie with load_empty or
|
28
|
+
load_from_file before you can accomplish anything.
|
29
|
+
*/
|
30
|
+
static VALUE movie_new(VALUE klass)
|
31
|
+
{
|
32
|
+
struct RMovie *rMovie;
|
33
|
+
return Data_Make_Struct(klass, struct RMovie, movie_mark, movie_free, rMovie);
|
34
|
+
}
|
35
|
+
|
36
|
+
/*
|
37
|
+
call-seq: dispose()
|
38
|
+
|
39
|
+
Dispose of the loaded QuickTime movie. This will automatically be done
|
40
|
+
when this movie instance is garbage collected. However if you are
|
41
|
+
iterating through many movies it is often helpful to dispose of it
|
42
|
+
as soon as you're done with it.
|
43
|
+
*/
|
44
|
+
static VALUE movie_dispose(VALUE obj)
|
45
|
+
{
|
46
|
+
if (MOVIE(obj)) {
|
47
|
+
DisposeMovie(MOVIE(obj));
|
48
|
+
RMOVIE(obj)->movie = NULL;
|
49
|
+
}
|
50
|
+
return obj;
|
51
|
+
}
|
52
|
+
|
53
|
+
/*
|
54
|
+
call-seq: load_from_file(filepath)
|
55
|
+
|
56
|
+
Loads a new, empty QuickTime movie at given filepath. Should only be
|
57
|
+
called if no movie has been loaded (or it has been disposed). Usually
|
58
|
+
you go through Movie.open.
|
59
|
+
*/
|
60
|
+
static VALUE movie_load_from_file(VALUE obj, VALUE filepath)
|
61
|
+
{
|
62
|
+
if (MOVIE(obj)) {
|
63
|
+
rb_raise(eQuickTime, "Movie has already been loaded.");
|
64
|
+
} else {
|
65
|
+
OSErr err;
|
66
|
+
FSSpec fs;
|
67
|
+
short frefnum = -1;
|
68
|
+
short movie_resid = 0;
|
69
|
+
Movie *movie = ALLOC(Movie);
|
70
|
+
|
71
|
+
err = NativePathNameToFSSpec(RSTRING(filepath)->ptr, &fs, 0);
|
72
|
+
if (err != 0)
|
73
|
+
rb_raise(eQuickTime, "Error %d occurred while reading file at %s", err, RSTRING(filepath)->ptr);
|
74
|
+
|
75
|
+
err = OpenMovieFile(&fs, &frefnum, fsRdPerm);
|
76
|
+
if (err != 0)
|
77
|
+
rb_raise(eQuickTime, "Error %d occurred while opening movie at %s", err, RSTRING(filepath)->ptr);
|
78
|
+
|
79
|
+
err = NewMovieFromFile(movie, frefnum, &movie_resid, 0, newMovieActive, 0);
|
80
|
+
if (err != 0)
|
81
|
+
rb_raise(eQuickTime, "Error %d occurred while loading movie at %s", err, RSTRING(filepath)->ptr);
|
82
|
+
|
83
|
+
err = CloseMovieFile(frefnum);
|
84
|
+
if (err != 0)
|
85
|
+
rb_raise(eQuickTime, "Error %d occurred while closing movie file at %s", err, RSTRING(filepath)->ptr);
|
86
|
+
|
87
|
+
RMOVIE(obj)->movie = *movie;
|
88
|
+
|
89
|
+
return obj;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
/*
|
94
|
+
call-seq: load_empty()
|
95
|
+
|
96
|
+
Loads a new, empty QuickTime movie. Should only be called if no movie
|
97
|
+
has been loaded (or it has been disposed). Usually you go through
|
98
|
+
Movie.empty.
|
99
|
+
*/
|
100
|
+
static VALUE movie_load_empty(VALUE obj)
|
101
|
+
{
|
102
|
+
if (MOVIE(obj)) {
|
103
|
+
rb_raise(eQuickTime, "Movie has already been loaded.");
|
104
|
+
} else {
|
105
|
+
RMOVIE(obj)->movie = NewMovie(0);
|
106
|
+
return obj;
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
/*
|
111
|
+
call-seq: raw_duration() -> duration_int
|
112
|
+
|
113
|
+
Returns the raw duration of the movie. Combine this with time_scale to
|
114
|
+
reach the duration in seconds.
|
115
|
+
*/
|
116
|
+
static VALUE movie_raw_duration(VALUE obj)
|
117
|
+
{
|
118
|
+
return INT2NUM(GetMovieDuration(MOVIE(obj)));
|
119
|
+
}
|
120
|
+
|
121
|
+
/*
|
122
|
+
call-seq: time_scale() -> scale_int
|
123
|
+
|
124
|
+
Returns the time scale of the movie. Usually only needed when working
|
125
|
+
with raw_duration.
|
126
|
+
*/
|
127
|
+
static VALUE movie_time_scale(VALUE obj)
|
128
|
+
{
|
129
|
+
return INT2NUM(GetMovieTimeScale(MOVIE(obj)));
|
130
|
+
}
|
131
|
+
|
132
|
+
/*
|
133
|
+
call-seq: bounds() -> bounds_hash
|
134
|
+
|
135
|
+
Returns a hash of boundaries. The hash contains four keys: :left, :top,
|
136
|
+
:right, :bottom. Each holds an integer representing the pixel value.
|
137
|
+
*/
|
138
|
+
static VALUE movie_bounds(VALUE obj)
|
139
|
+
{
|
140
|
+
VALUE bounds_hash = rb_hash_new();
|
141
|
+
Rect bounds;
|
142
|
+
GetMovieBox(MOVIE(obj), &bounds);
|
143
|
+
rb_hash_aset(bounds_hash, ID2SYM(rb_intern("left")), INT2NUM(bounds.left));
|
144
|
+
rb_hash_aset(bounds_hash, ID2SYM(rb_intern("top")), INT2NUM(bounds.top));
|
145
|
+
rb_hash_aset(bounds_hash, ID2SYM(rb_intern("right")), INT2NUM(bounds.right));
|
146
|
+
rb_hash_aset(bounds_hash, ID2SYM(rb_intern("bottom")), INT2NUM(bounds.bottom));
|
147
|
+
return bounds_hash;
|
148
|
+
}
|
149
|
+
|
150
|
+
/*
|
151
|
+
call-seq: track_count() -> count
|
152
|
+
|
153
|
+
Returns the number of tracks in the movie.
|
154
|
+
*/
|
155
|
+
static VALUE movie_track_count(VALUE obj)
|
156
|
+
{
|
157
|
+
return INT2NUM(GetMovieTrackCount(MOVIE(obj)));
|
158
|
+
}
|
159
|
+
|
160
|
+
/*
|
161
|
+
call-seq: composite_movie(movie, position)
|
162
|
+
|
163
|
+
Adds the tracks of given movie into called movie at given position (in seconds).
|
164
|
+
|
165
|
+
You can track the progress of this operation by passing a block to this
|
166
|
+
method. It will be called regularly during the process and pass the
|
167
|
+
percentage complete (0.0 to 1.0) as an argument to the block.
|
168
|
+
*/
|
169
|
+
static VALUE movie_composite_movie(VALUE obj, VALUE src, VALUE position)
|
170
|
+
{
|
171
|
+
if (rb_block_given_p())
|
172
|
+
SetMovieProgressProc(MOVIE(obj), (MovieProgressUPP)movie_progress_proc, rb_block_proc());
|
173
|
+
|
174
|
+
SetMovieSelection(MOVIE(obj), MOVIE_TIME(obj, position), 0);
|
175
|
+
AddMovieSelection(MOVIE(obj), MOVIE(src));
|
176
|
+
|
177
|
+
if (rb_block_given_p())
|
178
|
+
SetMovieProgressProc(MOVIE(obj), 0, 0);
|
179
|
+
|
180
|
+
return obj;
|
181
|
+
}
|
182
|
+
|
183
|
+
/*
|
184
|
+
call-seq: append_movie(movie, position)
|
185
|
+
|
186
|
+
Inserts given movie into called movie at given position (in seconds).
|
187
|
+
|
188
|
+
You can track the progress of this operation by passing a block to this
|
189
|
+
method. It will be called regularly during the process and pass the
|
190
|
+
percentage complete (0.0 to 1.0) as an argument to the block.
|
191
|
+
*/
|
192
|
+
static VALUE movie_insert_movie(VALUE obj, VALUE src, VALUE position)
|
193
|
+
{
|
194
|
+
if (rb_block_given_p())
|
195
|
+
SetMovieProgressProc(MOVIE(obj), (MovieProgressUPP)movie_progress_proc, rb_block_proc());
|
196
|
+
|
197
|
+
SetMovieSelection(MOVIE(obj), MOVIE_TIME(obj, position), 0);
|
198
|
+
PasteMovieSelection(MOVIE(obj), MOVIE(src));
|
199
|
+
|
200
|
+
if (rb_block_given_p())
|
201
|
+
SetMovieProgressProc(MOVIE(obj), 0, 0);
|
202
|
+
|
203
|
+
return obj;
|
204
|
+
}
|
205
|
+
|
206
|
+
/*
|
207
|
+
call-seq: append_movie(movie)
|
208
|
+
|
209
|
+
Adds given movie to the end of movie which this method is called on.
|
210
|
+
|
211
|
+
You can track the progress of this operation by passing a block to this
|
212
|
+
method. It will be called regularly during the process and pass the
|
213
|
+
percentage complete (0.0 to 1.0) as an argument to the block.
|
214
|
+
*/
|
215
|
+
static VALUE movie_append_movie(VALUE obj, VALUE src)
|
216
|
+
{
|
217
|
+
if (rb_block_given_p())
|
218
|
+
SetMovieProgressProc(MOVIE(obj), (MovieProgressUPP)movie_progress_proc, rb_block_proc());
|
219
|
+
|
220
|
+
SetMovieSelection(MOVIE(obj), GetMovieDuration(MOVIE(obj)), 0);
|
221
|
+
PasteMovieSelection(MOVIE(obj), MOVIE(src));
|
222
|
+
|
223
|
+
if (rb_block_given_p())
|
224
|
+
SetMovieProgressProc(MOVIE(obj), 0, 0);
|
225
|
+
|
226
|
+
return obj;
|
227
|
+
}
|
228
|
+
|
229
|
+
/*
|
230
|
+
call-seq: delete_section(start_time, duration)
|
231
|
+
|
232
|
+
Deletes given section from movie. Both start_time and duration
|
233
|
+
should be floats representing seconds.
|
234
|
+
*/
|
235
|
+
static VALUE movie_delete_section(VALUE obj, VALUE start, VALUE duration)
|
236
|
+
{
|
237
|
+
SetMovieSelection(MOVIE(obj), MOVIE_TIME(obj, start), MOVIE_TIME(obj, duration));
|
238
|
+
ClearMovieSelection(MOVIE(obj));
|
239
|
+
return obj;
|
240
|
+
}
|
241
|
+
|
242
|
+
/*
|
243
|
+
call-seq: clone_section(start_time, duration) -> movie
|
244
|
+
|
245
|
+
Returns a new movie in the given section. Does not modify original
|
246
|
+
movie. Both start_time and duration should be floats representing
|
247
|
+
seconds.
|
248
|
+
|
249
|
+
You can track the progress of this operation by passing a block to this
|
250
|
+
method. It will be called regularly during the process and pass the
|
251
|
+
percentage complete (0.0 to 1.0) as an argument to the block.
|
252
|
+
*/
|
253
|
+
static VALUE movie_clone_section(VALUE obj, VALUE start, VALUE duration)
|
254
|
+
{
|
255
|
+
VALUE new_movie_obj = rb_obj_alloc(cMovie);
|
256
|
+
|
257
|
+
if (rb_block_given_p())
|
258
|
+
SetMovieProgressProc(MOVIE(obj), (MovieProgressUPP)movie_progress_proc, rb_block_proc());
|
259
|
+
|
260
|
+
SetMovieSelection(MOVIE(obj), MOVIE_TIME(obj, start), MOVIE_TIME(obj, duration));
|
261
|
+
RMOVIE(new_movie_obj)->movie = CopyMovieSelection(MOVIE(obj));
|
262
|
+
|
263
|
+
if (rb_block_given_p())
|
264
|
+
SetMovieProgressProc(MOVIE(obj), 0, 0);
|
265
|
+
|
266
|
+
return new_movie_obj;
|
267
|
+
}
|
268
|
+
|
269
|
+
/*
|
270
|
+
call-seq: clip_section(start_time, duration) -> movie
|
271
|
+
|
272
|
+
Deletes given section on movie and returns a new movie with that
|
273
|
+
section. Both start_time and duration should be floats representing
|
274
|
+
seconds.
|
275
|
+
|
276
|
+
You can track the progress of this operation by passing a block to this
|
277
|
+
method. It will be called regularly during the process and pass the
|
278
|
+
percentage complete (0.0 to 1.0) as an argument to the block.
|
279
|
+
*/
|
280
|
+
static VALUE movie_clip_section(VALUE obj, VALUE start, VALUE duration)
|
281
|
+
{
|
282
|
+
VALUE new_movie_obj = rb_obj_alloc(cMovie);
|
283
|
+
|
284
|
+
if (rb_block_given_p())
|
285
|
+
SetMovieProgressProc(MOVIE(obj), (MovieProgressUPP)movie_progress_proc, rb_block_proc());
|
286
|
+
|
287
|
+
SetMovieSelection(MOVIE(obj), MOVIE_TIME(obj, start), MOVIE_TIME(obj, duration));
|
288
|
+
RMOVIE(new_movie_obj)->movie = CutMovieSelection(MOVIE(obj));
|
289
|
+
|
290
|
+
if (rb_block_given_p())
|
291
|
+
SetMovieProgressProc(MOVIE(obj), 0, 0);
|
292
|
+
|
293
|
+
return new_movie_obj;
|
294
|
+
}
|
295
|
+
|
296
|
+
/*
|
297
|
+
call-seq: changed?() -> bool
|
298
|
+
|
299
|
+
Determine if a movie has changed since opening. Returns true/false.
|
300
|
+
See reset_changed_status to reset this value.
|
301
|
+
*/
|
302
|
+
static VALUE movie_changed(VALUE obj)
|
303
|
+
{
|
304
|
+
if (HasMovieChanged(MOVIE(obj))) {
|
305
|
+
return Qtrue;
|
306
|
+
} else {
|
307
|
+
return Qfalse;
|
308
|
+
}
|
309
|
+
}
|
310
|
+
|
311
|
+
/*
|
312
|
+
call-seq: clear_changed_status()
|
313
|
+
|
314
|
+
Resets the "changed?" status. Does not revert the movie itself.
|
315
|
+
*/
|
316
|
+
static VALUE movie_clear_changed_status(VALUE obj)
|
317
|
+
{
|
318
|
+
ClearMovieChanged(MOVIE(obj));
|
319
|
+
return Qnil;
|
320
|
+
}
|
321
|
+
|
322
|
+
|
323
|
+
/*
|
324
|
+
call-seq: flatten(filepath)
|
325
|
+
|
326
|
+
Saves the movie to the given filepath by flattening it.
|
327
|
+
*/
|
328
|
+
static VALUE movie_flatten(VALUE obj, VALUE filepath)
|
329
|
+
{
|
330
|
+
OSErr err;
|
331
|
+
FSSpec fs;
|
332
|
+
VALUE new_movie_obj = rb_obj_alloc(cMovie);
|
333
|
+
|
334
|
+
err = NativePathNameToFSSpec(RSTRING(filepath)->ptr, &fs, 0);
|
335
|
+
if (err != fnfErr)
|
336
|
+
rb_raise(eQuickTime, "Error %d occurred while opening file for export at %s", err, RSTRING(filepath)->ptr);
|
337
|
+
|
338
|
+
// TODO make these flags settable through an options hash
|
339
|
+
RMOVIE(new_movie_obj)->movie = FlattenMovieData(MOVIE(obj),
|
340
|
+
flattenDontInterleaveFlatten
|
341
|
+
| flattenCompressMovieResource
|
342
|
+
| flattenAddMovieToDataFork
|
343
|
+
| flattenForceMovieResourceBeforeMovieData,
|
344
|
+
&fs, 'TVOD', smSystemScript, createMovieFileDontCreateResFile);
|
345
|
+
return new_movie_obj;
|
346
|
+
}
|
347
|
+
|
348
|
+
/*
|
349
|
+
call-seq: export_image_type(filepath, time, ostype)
|
350
|
+
|
351
|
+
Exports an image as the given ostype. It is best to use export_image
|
352
|
+
instead if the ostype can be determined from the filepath extension.
|
353
|
+
*/
|
354
|
+
static VALUE movie_export_image_type(VALUE obj, VALUE filepath, VALUE frame_time, VALUE ostype_obj)
|
355
|
+
{
|
356
|
+
GraphicsImportComponent component;
|
357
|
+
PicHandle picture;
|
358
|
+
Handle handle;
|
359
|
+
FSSpec fs;
|
360
|
+
OSErr err;
|
361
|
+
|
362
|
+
picture = GetMoviePict(MOVIE(obj), MOVIE_TIME(obj, frame_time));
|
363
|
+
|
364
|
+
err = NativePathNameToFSSpec(RSTRING(filepath)->ptr, &fs, 0);
|
365
|
+
if (err != fnfErr)
|
366
|
+
rb_raise(eQuickTime, "Error %d occurred while opening file for export at %s.", err, RSTRING(filepath)->ptr);
|
367
|
+
|
368
|
+
// Convert the picture handle into a PICT file (still in a handle)
|
369
|
+
// by adding a 512-byte header to the start.
|
370
|
+
handle = NewHandleClear(512);
|
371
|
+
err = HandAndHand((Handle)picture, handle);
|
372
|
+
if (err != noErr)
|
373
|
+
rb_raise(eQuickTime, "Error %d occurred while converting handle for pict export %s.", err, RSTRING(filepath)->ptr);
|
374
|
+
|
375
|
+
err = OpenADefaultComponent(GraphicsImporterComponentType, kQTFileTypePicture, &component);
|
376
|
+
if (err != noErr)
|
377
|
+
rb_raise(eQuickTime, "Error %d occurred while opening picture component for %s.", err, RSTRING(filepath)->ptr);
|
378
|
+
|
379
|
+
err = GraphicsImportSetDataHandle(component, handle);
|
380
|
+
if (err != noErr)
|
381
|
+
rb_raise(eQuickTime, "Error %d occurred while setting graphics importer data handle for %s.", err, RSTRING(filepath)->ptr);
|
382
|
+
|
383
|
+
err = GraphicsImportExportImageFile(component, OSTYPE(RSTRING(ostype_obj)->ptr), 0, &fs, smSystemScript);
|
384
|
+
if (err != noErr)
|
385
|
+
rb_raise(eQuickTime, "Error %d occurred while exporting pict to file %s.", err, RSTRING(filepath)->ptr);
|
386
|
+
|
387
|
+
CloseComponent(component);
|
388
|
+
DisposeHandle(handle);
|
389
|
+
DisposeHandle((Handle)picture);
|
390
|
+
|
391
|
+
return Qnil;
|
392
|
+
}
|
393
|
+
|
394
|
+
/*
|
395
|
+
call-seq: poster_time() -> seconds
|
396
|
+
|
397
|
+
Returns the poster time of the movie (in seconds).
|
398
|
+
*/
|
399
|
+
static VALUE movie_get_poster_time(VALUE obj)
|
400
|
+
{
|
401
|
+
return rb_float_new((double)GetMoviePosterTime(MOVIE(obj))/GetMovieTimeScale(MOVIE(obj)));
|
402
|
+
}
|
403
|
+
|
404
|
+
/*
|
405
|
+
call-seq: poster_time=(seconds)
|
406
|
+
|
407
|
+
Sets the poster_time of the movie (in seconds).
|
408
|
+
*/
|
409
|
+
static VALUE movie_set_poster_time(VALUE obj, VALUE seconds)
|
410
|
+
{
|
411
|
+
SetMoviePosterTime(MOVIE(obj), MOVIE_TIME(obj, seconds));
|
412
|
+
return Qnil;
|
413
|
+
}
|
414
|
+
|
415
|
+
/*
|
416
|
+
call-seq: new_track(width, height) -> track
|
417
|
+
|
418
|
+
Creates a new track with the given width/height on the movie and returns it.
|
419
|
+
|
420
|
+
This method is generally not called directly. Instead you should call
|
421
|
+
new_video_track or new_audio_track. If you call method make sure to
|
422
|
+
call new_media on track to setup the media.
|
423
|
+
*/
|
424
|
+
static VALUE movie_new_track(VALUE obj, VALUE width, VALUE height)
|
425
|
+
{
|
426
|
+
VALUE track_obj = rb_obj_alloc(cTrack);
|
427
|
+
RTRACK(track_obj)->track = NewMovieTrack(MOVIE(obj), NUM2INT(width), NUM2INT(height), kFullVolume);
|
428
|
+
return track_obj;
|
429
|
+
}
|
430
|
+
|
431
|
+
void Init_quicktime_movie()
|
432
|
+
{
|
433
|
+
VALUE mQuickTime;
|
434
|
+
mQuickTime = rb_define_module("QuickTime");
|
435
|
+
cMovie = rb_define_class_under(mQuickTime, "Movie", rb_cObject);
|
436
|
+
rb_define_alloc_func(cMovie, movie_new);
|
437
|
+
rb_define_method(cMovie, "load_from_file", movie_load_from_file, 1);
|
438
|
+
rb_define_method(cMovie, "load_empty", movie_load_empty, 0);
|
439
|
+
rb_define_method(cMovie, "raw_duration", movie_raw_duration, 0);
|
440
|
+
rb_define_method(cMovie, "time_scale", movie_time_scale, 0);
|
441
|
+
rb_define_method(cMovie, "bounds", movie_bounds, 0);
|
442
|
+
rb_define_method(cMovie, "track_count", movie_track_count, 0);
|
443
|
+
rb_define_method(cMovie, "composite_movie", movie_composite_movie, 2);
|
444
|
+
rb_define_method(cMovie, "insert_movie", movie_insert_movie, 2);
|
445
|
+
rb_define_method(cMovie, "append_movie", movie_append_movie, 1);
|
446
|
+
rb_define_method(cMovie, "delete_section", movie_delete_section, 2);
|
447
|
+
rb_define_method(cMovie, "clone_section", movie_clone_section, 2);
|
448
|
+
rb_define_method(cMovie, "clip_section", movie_clip_section, 2);
|
449
|
+
rb_define_method(cMovie, "changed?", movie_changed, 0);
|
450
|
+
rb_define_method(cMovie, "clear_changed_status", movie_clear_changed_status, 0);
|
451
|
+
rb_define_method(cMovie, "flatten", movie_flatten, 1);
|
452
|
+
rb_define_method(cMovie, "export_image_type", movie_export_image_type, 3);
|
453
|
+
rb_define_method(cMovie, "dispose", movie_dispose, 0);
|
454
|
+
rb_define_method(cMovie, "poster_time", movie_get_poster_time, 0);
|
455
|
+
rb_define_method(cMovie, "poster_time=", movie_set_poster_time, 1);
|
456
|
+
rb_define_method(cMovie, "new_track", movie_new_track, 2);
|
457
|
+
}
|
data/ext/rmov_ext.c
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#include "rmov_ext.h"
|
2
|
+
|
3
|
+
VALUE eQuickTime;
|
4
|
+
|
5
|
+
void Init_rmov_ext()
|
6
|
+
{
|
7
|
+
VALUE mQuickTime;
|
8
|
+
|
9
|
+
EnterMovies(); // Enables the QuickTime framework
|
10
|
+
|
11
|
+
mQuickTime = rb_define_module("QuickTime");
|
12
|
+
eQuickTime = rb_define_class_under(mQuickTime, "Error", rb_eStandardError);
|
13
|
+
Init_quicktime_movie();
|
14
|
+
Init_quicktime_track();
|
15
|
+
Init_quicktime_exporter();
|
16
|
+
}
|
data/ext/rmov_ext.h
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <QuickTime/QuickTime.h>
|
3
|
+
|
4
|
+
extern VALUE eQuickTime, cMovie, cTrack, cExporter;
|
5
|
+
|
6
|
+
|
7
|
+
#define OSTYPE(str) ((str[0] << 24) | (str[1] << 16) | (str[2] << 8) | str[3])
|
8
|
+
|
9
|
+
/*** MOVIE ***/
|
10
|
+
|
11
|
+
void Init_quicktime_movie();
|
12
|
+
OSErr movie_progress_proc(Movie movie, short message, short operation, Fixed percent, VALUE proc);
|
13
|
+
|
14
|
+
#define RMOVIE(obj) (Check_Type(obj, T_DATA), (struct RMovie*)DATA_PTR(obj))
|
15
|
+
#define MOVIE(obj) (RMOVIE(obj)->movie)
|
16
|
+
#define MOVIE_TIME(obj, seconds) (floor(NUM2DBL(seconds)*GetMovieTimeScale(MOVIE(obj))))
|
17
|
+
|
18
|
+
struct RMovie {
|
19
|
+
Movie movie;
|
20
|
+
};
|
21
|
+
|
22
|
+
|
23
|
+
/*** TRACK ***/
|
24
|
+
|
25
|
+
void Init_quicktime_track();
|
26
|
+
|
27
|
+
#define RTRACK(obj) (Check_Type(obj, T_DATA), (struct RTrack*)DATA_PTR(obj))
|
28
|
+
#define TRACK(obj) (RTRACK(obj)->track)
|
29
|
+
#define TRACK_MEDIA(obj) (GetTrackMedia(TRACK(obj)))
|
30
|
+
#define TRACK_TIME(obj, seconds) (floor(NUM2DBL(seconds)*GetMediaTimeScale(TRACK_MEDIA(obj))))
|
31
|
+
|
32
|
+
struct RTrack {
|
33
|
+
Track track;
|
34
|
+
};
|
35
|
+
|
36
|
+
|
37
|
+
/*** EXPORTER ***/
|
38
|
+
|
39
|
+
void Init_quicktime_exporter();
|
40
|
+
|
41
|
+
#define REXPORTER(obj) (Check_Type(obj, T_DATA), (struct RExporter*)DATA_PTR(obj))
|
42
|
+
|
43
|
+
struct RExporter {
|
44
|
+
QTAtomContainer settings;
|
45
|
+
};
|