Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

releasing initial 0.1.0 with documentation

  • Loading branch information...
commit 5e04e88fc4daf75ba8c0ab6b1a21ca6a0cb9986f 1 parent 1b8ec79
@ryanb authored
View
3  .gitignore
@@ -3,4 +3,5 @@
Makefile
spec/output/*.mov
spec/output/*.st
-spec/output/*.pct
+spec/output/*.pct
+pkg
View
3  CHANGELOG
@@ -0,0 +1,3 @@
+0.1.0 (October 2nd, 2008)
+
+* initial release
View
20 LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2008 Ryan Bates
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
View
26 Manifest
@@ -0,0 +1,26 @@
+CHANGELOG
+ext/exporter.c
+ext/extconf.rb
+ext/movie.c
+ext/rmov_ext.c
+ext/rmov_ext.h
+ext/track.c
+lib/quicktime/exporter.rb
+lib/quicktime/movie.rb
+lib/quicktime/track.rb
+lib/rmov.rb
+LICENSE
+Rakefile
+README
+spec/fixtures/settings.st
+spec/output/example.pct
+spec/output/saved_settings.st
+spec/quicktime/exporter_spec.rb
+spec/quicktime/movie_spec.rb
+spec/quicktime/track_spec.rb
+spec/spec.opts
+spec/spec_helper.rb
+tasks/setup.rake
+tasks/spec.rake
+TODO
+Manifest
View
75 README
@@ -1,16 +1,73 @@
-RMov
+= RMov
-Ruby wrapper for the QuickTime C API.
+Open, edit, and export QuickTime movies all within Ruby! This is an
+unofficial wrapper around Apple's QuickTime C API. Mac OS X required.
-This is still in very early development. To try it out, run the setup
-task to build the ruby c extensions.
- rake setup
+== Install
-You can then require 'rmov' in the lib directory.
+Install the gem:
+
+ gem install rmov
+
+And then load it in your project:
require 'rmov'
- movie = Quicktime::Movie.open('foo.mov')
- movie.duration # returns number of seconds of movie
-More features coming soon.
+
+== Usage
+
+Use this gem to open QuickTime movies and edit them to your liking.
+
+ movie1 = QuickTime::Movie.open("path/to/movie.mov")
+ movie2 = QuickTime::Movie.open("path/to/another_movie.mov")
+
+ # add movie2 to the end of movie1
+ movie1.append_movie(movie2)
+
+ # make a new movie out of a section of movie 1
+ # this will delete 5 seconds out of the movie at 2 seconds in
+ movie3 = movie1.clip_section(movie1, 2, 5)
+
+ # You can insert that part back into the movie at 8 seconds in
+ movie1.insert_movie(movie3, 8)
+
+Now you can export the movie. Usually this is done through a user
+interface the first time around. The settings can then be saved to
+a file. After that you can load these settings without interfering
+the user with the dialog again.
+
+ exporter = movie1.exporter
+
+ # if we already have saved the settings, load those
+ if File.exist? "settings.st"
+ exporter.load_settings("settings.st")
+ else
+ # otherwise open the QuickTime GUI settings dialog
+ exporter.open_settings_dialog
+
+ # save settings to a file so we don't have to bother user next time
+ exporter.save_settings("settings.st")
+ end
+
+ # export the movie to a file and report the progress along the way
+ exporter.export("movie.mov") do |progress|
+ percent = (progress*100).round
+ puts "#{percent}% complete"
+ end
+
+See Quicktime::Movie in the RDoc for more information.
+
+http://rmov.rubyforge.org
+
+
+== Development
+
+This project can be found on github at the following URL.
+
+http://github.com/ryanb/rmov
+
+If you find a bug, please send me a message on GitHub.
+
+If you would like to contribute to this project, please fork the
+repository and send me a pull request.
View
13 Rakefile
@@ -1,5 +1,16 @@
require 'rubygems'
require 'rake'
-require 'rake/gempackagetask'
+require 'echoe'
+
+Echoe.new('rmov', '0.1.0') do |p|
+ p.summary = "Ruby wrapper for the QuickTime C API."
+ p.description = "Ruby wrapper for the QuickTime C API."
+ p.url = "http://github.com/ryanb/rmov"
+ p.author = 'Ryan Bates'
+ p.email = "ryan (at) railscasts (dot) com"
+ p.ignore_pattern = ["script/*", "tmp/*", "output/*", "**/*.o", "**/*.bundle", "**/*.mov"]
+ p.extensions = ["ext/extconf.rb"]
+ p.development_dependencies = []
+end
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
View
40 ext/exporter.c
@@ -13,6 +13,12 @@ static void exporter_mark(struct RExporter *rExporter)
{
}
+/*
+ Creates a new exporter instance. Usually this is done through movie.exporter.
+
+call-seq:
+ new(movie) -> exporter
+*/
static VALUE exporter_new(VALUE klass)
{
struct RExporter *rExporter;
@@ -28,6 +34,17 @@ static ComponentInstance exporter_component(VALUE obj)
return component;
}
+/*
+ Exports a movie to the given filepath. This will use either the
+ settings you set beforehand, or QuickTime's defaults.
+
+ You can track the progress of this operation by passing a block to this
+ method. It will be called regularly during the process and pass the
+ percentage complete (0.0 to 1.0) as an argument to the block.
+
+call-seq:
+ export_to_file(filepath)
+*/
static VALUE exporter_export_to_file(VALUE obj, VALUE filepath)
{
OSErr err;
@@ -58,6 +75,16 @@ static VALUE exporter_export_to_file(VALUE obj, VALUE filepath)
return Qnil;
}
+/*
+ Opens the offical QuickTime GUI settings dialog. The process will be
+ suspended until the user closes the dialogue. If the user clicks Okay
+ the settings will be applied to this Exporter. You can then use
+ save_settings to save them to a file, and load_settings to load them
+ back again.
+
+call-seq:
+ open_settings_dialog()
+*/
static VALUE exporter_open_settings_dialog(VALUE obj)
{
Boolean canceled;
@@ -98,6 +125,12 @@ static VALUE exporter_open_settings_dialog(VALUE obj)
}
}
+/*
+ Loads the settings at the given filepath. See save_settings.
+
+call-seq:
+ load_settings(filepath)
+*/
static VALUE exporter_load_settings(VALUE obj, VALUE filepath)
{
FILE *file;
@@ -130,6 +163,13 @@ static VALUE exporter_load_settings(VALUE obj, VALUE filepath)
return Qnil;
}
+/*
+ Saves the settings to the given filepath (usually with .st extension).
+ See open_settings_dialog and load_settings.
+
+call-seq:
+ save_settings(filepath)
+*/
static VALUE exporter_save_settings(VALUE obj, VALUE filepath)
{
FILE *file;
View
151 ext/movie.c
@@ -19,12 +19,30 @@ static void movie_mark(struct RMovie *rMovie)
{
}
+/*
+ Creates a new movie instance. Generally you want to go through
+ Movie.open or Movie.empty to load or create a new movie respectively.
+ If you do no then you will need to load the movie with load_empty or
+ load_from_file before you can accomplish anything.
+
+call-seq:
+ new() -> movie
+*/
static VALUE movie_new(VALUE klass)
{
struct RMovie *rMovie;
return Data_Make_Struct(klass, struct RMovie, movie_mark, movie_free, rMovie);
}
+/*
+ Dispose of the loaded QuickTime movie. This will automatically be done
+ when this movie instance is garbage collected. However if you are
+ iterating through many movies it is often helpful to dispose of it
+ as soon as you're done with it.
+
+call-seq:
+ dispose()
+*/
static VALUE movie_dispose(VALUE obj)
{
if (MOVIE(obj)) {
@@ -34,6 +52,14 @@ static VALUE movie_dispose(VALUE obj)
return obj;
}
+/*
+ Loads a new, empty QuickTime movie at given filepath. Should only be
+ called if no movie has been loaded (or it has been disposed). Usually
+ you go through Movie.open.
+
+call-seq:
+ load_from_file(filepath)
+*/
static VALUE movie_load_from_file(VALUE obj, VALUE filepath)
{
if (MOVIE(obj)) {
@@ -67,6 +93,14 @@ static VALUE movie_load_from_file(VALUE obj, VALUE filepath)
}
}
+/*
+ Loads a new, empty QuickTime movie. Should only be called if no movie
+ has been loaded (or it has been disposed). Usually you go through
+ Movie.empty.
+
+call-seq:
+ load_empty()
+*/
static VALUE movie_load_empty(VALUE obj)
{
if (MOVIE(obj)) {
@@ -77,16 +111,36 @@ static VALUE movie_load_empty(VALUE obj)
}
}
+/*
+ Returns the raw duration of the movie. Combine this with time_scale to
+ reach the duration in seconds.
+
+call-seq:
+ raw_duration() -> duration_int
+*/
static VALUE movie_raw_duration(VALUE obj)
{
return INT2NUM(GetMovieDuration(MOVIE(obj)));
}
+/*
+ Returns the time scale of the movie. Usually only needed when working
+ with raw_duration.
+
+call-seq:
+ time_scale() -> scale_int
+*/
static VALUE movie_time_scale(VALUE obj)
{
return INT2NUM(GetMovieTimeScale(MOVIE(obj)));
}
+/*
+ Returns the number of tracks in the movie.
+
+call-seq:
+ track_count() -> count
+*/
static VALUE movie_bounds(VALUE obj)
{
VALUE bounds_hash = rb_hash_new();
@@ -99,11 +153,27 @@ static VALUE movie_bounds(VALUE obj)
return bounds_hash;
}
+/*
+ Returns the number of tracks in the movie.
+
+call-seq:
+ track_count -> count
+*/
static VALUE movie_track_count(VALUE obj)
{
return INT2NUM(GetMovieTrackCount(MOVIE(obj)));
}
+/*
+ Adds the tracks of given movie into called movie at given position (in seconds).
+
+ You can track the progress of this operation by passing a block to this
+ method. It will be called regularly during the process and pass the
+ percentage complete (0.0 to 1.0) as an argument to the block.
+
+call-seq:
+ composite_movie(movie, position)
+*/
static VALUE movie_composite_movie(VALUE obj, VALUE src, VALUE position)
{
if (rb_block_given_p())
@@ -118,6 +188,16 @@ static VALUE movie_composite_movie(VALUE obj, VALUE src, VALUE position)
return obj;
}
+/*
+ Inserts given movie into called movie at given position (in seconds).
+
+ You can track the progress of this operation by passing a block to this
+ method. It will be called regularly during the process and pass the
+ percentage complete (0.0 to 1.0) as an argument to the block.
+
+call-seq:
+ append_movie(movie, position)
+*/
static VALUE movie_insert_movie(VALUE obj, VALUE src, VALUE position)
{
if (rb_block_given_p())
@@ -132,6 +212,16 @@ static VALUE movie_insert_movie(VALUE obj, VALUE src, VALUE position)
return obj;
}
+/*
+ Adds given movie to the end of movie which this method is called on.
+
+ You can track the progress of this operation by passing a block to this
+ method. It will be called regularly during the process and pass the
+ percentage complete (0.0 to 1.0) as an argument to the block.
+
+call-seq:
+ append_movie(movie)
+*/
static VALUE movie_append_movie(VALUE obj, VALUE src)
{
if (rb_block_given_p())
@@ -146,6 +236,13 @@ static VALUE movie_append_movie(VALUE obj, VALUE src)
return obj;
}
+/*
+ Deletes given section from movie. Both start_time and duration
+ should be floats representing seconds.
+
+call-seq:
+ delete_section(start_time, duration)
+*/
static VALUE movie_delete_section(VALUE obj, VALUE start, VALUE duration)
{
SetMovieSelection(MOVIE(obj), MOVIE_TIME(obj, start), MOVIE_TIME(obj, duration));
@@ -153,6 +250,18 @@ static VALUE movie_delete_section(VALUE obj, VALUE start, VALUE duration)
return obj;
}
+/*
+ Returns a new movie in the given section. Does not modify original
+ movie. Both start_time and duration should be floats representing
+ seconds.
+
+ You can track the progress of this operation by passing a block to this
+ method. It will be called regularly during the process and pass the
+ percentage complete (0.0 to 1.0) as an argument to the block.
+
+call-seq:
+ clone_section(start_time, duration) -> movie
+*/
static VALUE movie_clone_section(VALUE obj, VALUE start, VALUE duration)
{
VALUE new_movie_obj = rb_obj_alloc(cMovie);
@@ -169,6 +278,18 @@ static VALUE movie_clone_section(VALUE obj, VALUE start, VALUE duration)
return new_movie_obj;
}
+/*
+ Deletes given section on movie and returns a new movie with that
+ section. Both start_time and duration should be floats representing
+ seconds.
+
+ You can track the progress of this operation by passing a block to this
+ method. It will be called regularly during the process and pass the
+ percentage complete (0.0 to 1.0) as an argument to the block.
+
+call-seq:
+ clip_section(start_time, duration) -> movie
+*/
static VALUE movie_clip_section(VALUE obj, VALUE start, VALUE duration)
{
VALUE new_movie_obj = rb_obj_alloc(cMovie);
@@ -185,6 +306,13 @@ static VALUE movie_clip_section(VALUE obj, VALUE start, VALUE duration)
return new_movie_obj;
}
+/*
+ Determine if a movie has changed since opening. Returns true/false.
+ See reset_changed_status to reset this value.
+
+call-seq:
+ changed?() -> bool
+*/
static VALUE movie_changed(VALUE obj)
{
if (HasMovieChanged(MOVIE(obj))) {
@@ -194,12 +322,26 @@ static VALUE movie_changed(VALUE obj)
}
}
+/*
+ Resets the "changed?" status. Does not revert the movie itself.
+
+call-seq:
+ clear_changed_status()
+*/
static VALUE movie_clear_changed_status(VALUE obj)
{
ClearMovieChanged(MOVIE(obj));
return Qnil;
}
+
+/*
+ Saves the movie to the given filepath by flattening it.
+
+call-seq:
+ flatten(filepath)
+*/
+
static VALUE movie_flatten(VALUE obj, VALUE filepath)
{
OSErr err;
@@ -220,6 +362,15 @@ static VALUE movie_flatten(VALUE obj, VALUE filepath)
return new_movie_obj;
}
+/*
+ Exports a PICT file to given filepath (should end in .pct) at the given
+ time. Time should be a floating point in seconds.
+
+call-seq:
+ export_pict(filepath, time)
+
+*/
+
static VALUE movie_export_pict(VALUE obj, VALUE filepath, VALUE frame_time)
{
GraphicsImportComponent component;
View
71 ext/track.c
@@ -10,12 +10,26 @@ static void track_mark(struct RTrack *rTrack)
{
}
+/*
+ Creates a new track instance. Generally you will do this through
+ movie.tracks to fetch the Track instances for a given movie.
+
+call-seq:
+ new() -> track
+*/
static VALUE track_new(VALUE klass)
{
struct RTrack *rTrack;
return Data_Make_Struct(klass, struct RTrack, track_mark, track_free, rTrack);
}
+/*
+ Loads a QuickTime track from a given movie. This is done automatically
+ when calling movie.tracks.
+
+call-seq:
+ load(movie, index)
+*/
static VALUE track_load(VALUE obj, VALUE movie_obj, VALUE index_obj)
{
RTRACK(obj)->track = GetMovieIndTrack(MOVIE(movie_obj), NUM2INT(index_obj));
@@ -25,21 +39,47 @@ static VALUE track_load(VALUE obj, VALUE movie_obj, VALUE index_obj)
return obj;
}
+/*
+ Returns the raw duration of the track. Combine this with time_scale to
+ reach the duration in seconds.
+
+call-seq:
+ raw_duration() -> duration_int
+*/
static VALUE track_raw_duration(VALUE obj)
{
return INT2NUM(GetMediaDuration(TRACK_MEDIA(obj)));
}
+/*
+ Returns the time scale of the track. Usually only needed when working
+ with raw_duration.
+
+call-seq:
+ time_scale() -> scale_int
+*/
static VALUE track_time_scale(VALUE obj)
{
return INT2NUM(GetMediaTimeScale(TRACK_MEDIA(obj)));
}
+/*
+ Returns the number of frames in the track.
+
+call-seq:
+ frame_count() -> count
+*/
static VALUE track_frame_count(VALUE obj)
{
return INT2NUM(GetMediaSampleCount(TRACK_MEDIA(obj)));
}
+/*
+ Returns either :audio or :video depending on the type of track this is.
+
+call-seq:
+ media_type() -> media_type_sym
+*/
static VALUE track_media_type(VALUE obj)
{
OSType media_type;
@@ -54,29 +94,60 @@ static VALUE track_media_type(VALUE obj)
}
}
+/*
+ Returns either id number QuickTime uses to reference this track.
+ Usually only used internally.
+
+call-seq:
+ id() -> quicktime_track_id_int
+*/
static VALUE track_id(VALUE obj)
{
return INT2NUM(GetTrackID(TRACK(obj)));
}
+/*
+ Removes the track from its movie and deletes it from memory.
+
+call-seq:
+ delete()
+*/
static VALUE track_delete(VALUE obj)
{
DisposeMovieTrack(TRACK(obj));
return Qnil;
}
+/*
+ Disables the track. See enabled? to determine if it's disabled already.
+
+call-seq:
+ disable()
+*/
static VALUE track_disable(VALUE obj, VALUE boolean)
{
SetTrackEnabled(TRACK(obj), FALSE);
return obj;
}
+/*
+ Enables the track. See enabled? to determine if it's enabled already.
+
+call-seq:
+ enable()
+*/
static VALUE track_enable(VALUE obj, VALUE boolean)
{
SetTrackEnabled(TRACK(obj), TRUE);
return obj;
}
+/*
+ Returns true/false depending on if the track is enabled.
+
+call-seq:
+ enabled?() -> bool
+*/
static VALUE track_enabled(VALUE obj, VALUE boolean)
{
if (GetTrackEnabled(TRACK(obj)) == TRUE) {
View
11 lib/quicktime/movie.rb
@@ -1,44 +1,55 @@
module Quicktime
# see ext/movie.c for additional methods
class Movie
+ # Opens a movie at filepath.
def self.open(filepath)
new.load_from_file(filepath)
end
+ # Returns a new, empty movie.
def self.empty
new.load_empty
end
+ # Returns the length of this movie in seconds
+ # using raw_duration and time_scale.
def duration
raw_duration.to_f/time_scale
end
+ # Returns the bounding width of this movie in number of pixels.
def width
bounds[:right] - bounds[:left]
end
+ # Returns the bounding height of this movie in number of pixels.
def height
bounds[:bottom] - bounds[:top]
end
+ # Returns an array of tracks in this movie.
def tracks
(1..track_count).map do |i|
Track.new.load_from_movie(self, i)
end
end
+ # Returns an array of audio tracks in this movie.
def audio_tracks
tracks.select { |t| t.audio? }
end
+ # Returns an array of video tracks in this movie.
def video_tracks
tracks.select { |t| t.video? }
end
+ # Returns an Exporter instance for this movie.
def exporter
Exporter.new(self)
end
+ # Convenience method for exporting the movie. See Exporter::export.
def export(*args, &block)
exporter.export(*args, &block)
end
View
5 lib/quicktime/track.rb
@@ -1,18 +1,23 @@
module Quicktime
# see ext/track.c for additional methods
class Track
+ # Returns the length of this track in seconds
+ # using raw_duration and time_scale.
def duration
raw_duration.to_f/time_scale
end
+ # The average frame_rate for this track. May not be exact.
def frame_rate # what about odd frame rates such as 29.97?
frame_count/duration
end
+ # Returns true/false depending on if track is an audio track.
def audio?
media_type == :audio
end
+ # Returns true/false depending on if track is a video track.
def video?
media_type == :video
end
View
5 lib/rmov.rb
@@ -5,3 +5,8 @@
require 'quicktime/movie'
require 'quicktime/track'
require 'quicktime/exporter'
+
+
+# RMov is made up of several parts. To start, see Quicktime::Movie.
+module Quicktime
+end

0 comments on commit 5e04e88

Please sign in to comment.
Something went wrong with that request. Please try again.