puremotion 0.0.1 → 0.1.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.
- data/.yardopts +1 -0
- data/README.md +69 -0
- data/Rakefile +23 -11
- data/examples/progress_reporting.rb +26 -0
- data/examples/simple.rb +22 -0
- data/ext/puremotion/audio.c +38 -0
- data/ext/puremotion/extconf.rb +34 -0
- data/ext/puremotion/frame.c +176 -0
- data/ext/puremotion/media.c +175 -0
- data/ext/puremotion/puremotion.c +26 -0
- data/ext/puremotion/puremotion.h +38 -0
- data/ext/puremotion/stream.c +128 -0
- data/ext/puremotion/stream_collection.c +44 -0
- data/ext/puremotion/utils.c +81 -0
- data/ext/puremotion/utils.h +6 -0
- data/ext/puremotion/video.c +141 -0
- data/lib/{puremotion/events → events}/event.rb +0 -0
- data/lib/{puremotion/events → events}/generator.rb +0 -0
- data/lib/media.rb +89 -0
- data/lib/preset/audio/audio.rb +42 -0
- data/lib/preset/file.rb +19 -0
- data/lib/preset/general.rb +28 -0
- data/lib/preset/metadata.rb +41 -0
- data/lib/preset/preset.rb +120 -0
- data/lib/preset/video/crop.rb +29 -0
- data/lib/preset/video/pad.rb +31 -0
- data/lib/preset/video/video.rb +130 -0
- data/lib/puremotion.rb +20 -12
- data/lib/puremotion_native.so +0 -0
- data/lib/threading.rb +54 -0
- data/lib/{puremotion/tools → tools}/ffmpeg.rb +12 -50
- data/lib/transcode/transcode.rb +142 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/units/media_spec.rb +13 -0
- data/spec/units/preset_spec.rb +91 -0
- metadata +52 -44
- data/.document +0 -5
- data/.gitignore +0 -21
- data/README.rdoc +0 -18
- data/VERSION +0 -1
- data/lib/puremotion/codecs.rb +0 -59
- data/lib/puremotion/media.rb +0 -490
- data/lib/puremotion/media/stream.rb +0 -4
- data/lib/puremotion/media/stream/audio.rb +0 -0
- data/lib/puremotion/media/stream/base.rb +0 -7
- data/lib/puremotion/media/stream/collection.rb +0 -5
- data/lib/puremotion/media/stream/video.rb +0 -61
- data/lib/puremotion/recipes/ipod.yml +0 -12
- data/lib/puremotion/thread.rb +0 -153
- data/lib/puremotion/transcode/recipe.rb +0 -250
- data/lib/puremotion/transcode/transcode.rb +0 -153
- data/puremotion.gemspec +0 -68
- data/test/helper.rb +0 -10
- data/test/test_puremotion.rb +0 -7
data/lib/puremotion.rb
CHANGED
@@ -1,22 +1,30 @@
|
|
1
1
|
req = File.expand_path(File.dirname(__FILE__)) + '/'
|
2
2
|
|
3
|
-
require 'rubygems'
|
3
|
+
#require 'rubygems'
|
4
4
|
|
5
5
|
module PureMotion
|
6
6
|
|
7
7
|
end
|
8
8
|
|
9
|
-
require req + '
|
10
|
-
require req + '
|
9
|
+
require req + 'puremotion_native'
|
10
|
+
require req + 'events/event'
|
11
|
+
require req + 'events/generator'
|
11
12
|
|
12
13
|
Object.extend(PureMotion::Events::Generator)
|
13
14
|
|
14
|
-
require req + '
|
15
|
-
|
16
|
-
require req + '
|
17
|
-
require req + '
|
18
|
-
require req + '
|
19
|
-
require req + '
|
20
|
-
require req + '
|
21
|
-
require req + '
|
22
|
-
require req + '
|
15
|
+
require req + 'preset/preset'
|
16
|
+
|
17
|
+
require req + 'preset/general'
|
18
|
+
require req + 'preset/file'
|
19
|
+
require req + 'preset/metadata'
|
20
|
+
require req + 'preset/video/video'
|
21
|
+
require req + 'preset/video/crop'
|
22
|
+
require req + 'preset/video/pad'
|
23
|
+
require req + 'preset/audio/audio'
|
24
|
+
|
25
|
+
|
26
|
+
require req + 'threading'
|
27
|
+
require req + 'media'
|
28
|
+
require req + 'codecs'
|
29
|
+
require req + 'transcode/transcode'
|
30
|
+
require req + 'tools/ffmpeg'
|
Binary file
|
data/lib/threading.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# Author:: Jared Kuolt (mailto:me@superjared.com)
|
2
|
+
# Copyright:: Copyright (c) 2009 Jared Kuolt
|
3
|
+
# License:: MIT License
|
4
|
+
#
|
5
|
+
# See README.rdoc[link:files/README_rdoc.html] for usage
|
6
|
+
#
|
7
|
+
|
8
|
+
module PureMotion
|
9
|
+
class Thread
|
10
|
+
|
11
|
+
attr_reader :thread, :exception
|
12
|
+
attr_accessor :name
|
13
|
+
|
14
|
+
def initialize(config={}, &block)
|
15
|
+
args = (config[:args] or [])
|
16
|
+
self.class.init_exit_handler
|
17
|
+
@thread = ::Thread.new(*args) do |*targs|
|
18
|
+
begin
|
19
|
+
block.call(*targs)
|
20
|
+
rescue Exception => e
|
21
|
+
@exception = e
|
22
|
+
# Handle?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
self.name = config[:name] || @thread.inspect
|
26
|
+
self.class.threads << self
|
27
|
+
self.class.init_exit_handler
|
28
|
+
end
|
29
|
+
|
30
|
+
class << self
|
31
|
+
attr_accessor :logger, :exit_thread, :exit_handler_initialized, :callbacks
|
32
|
+
|
33
|
+
def threads
|
34
|
+
@threads ||= []
|
35
|
+
end
|
36
|
+
|
37
|
+
def init_exit_handler
|
38
|
+
return if self.exit_handler_initialized
|
39
|
+
self.exit_thread = false
|
40
|
+
at_exit do
|
41
|
+
self.exit_thread = true
|
42
|
+
begin
|
43
|
+
self.threads.each do |thread|
|
44
|
+
thread.thread.join
|
45
|
+
end
|
46
|
+
rescue Interrupt
|
47
|
+
end
|
48
|
+
end
|
49
|
+
self.exit_handler_initialized = true
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -12,7 +12,8 @@ module PureMotion::Tools
|
|
12
12
|
ERROR = 32
|
13
13
|
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
|
+
attr_reader :pid
|
16
17
|
attr_reader :args
|
17
18
|
attr_accessor :output
|
18
19
|
|
@@ -20,12 +21,8 @@ module PureMotion::Tools
|
|
20
21
|
event :complete
|
21
22
|
event :exited
|
22
23
|
event :status_change
|
23
|
-
|
24
|
-
@
|
25
|
-
|
26
|
-
def self.run(args = {})
|
27
|
-
FFmpeg.new( args )
|
28
|
-
end
|
24
|
+
|
25
|
+
@pid = nil
|
29
26
|
|
30
27
|
def initialize(params = {})
|
31
28
|
if params.class != Hash then raise ArgumentError, "Invalid parameters" end
|
@@ -44,17 +41,15 @@ module PureMotion::Tools
|
|
44
41
|
end
|
45
42
|
|
46
43
|
@output = []
|
47
|
-
|
48
|
-
go
|
49
44
|
end
|
50
45
|
|
51
|
-
def
|
52
|
-
|
53
|
-
@pio = IO.popen("ffmpeg #{@options} 2>&1")
|
54
|
-
|
46
|
+
def run
|
47
|
+
|
55
48
|
temp = ''
|
56
49
|
|
57
|
-
PureMotion::Thread.new do
|
50
|
+
@thread = PureMotion::Thread.new do
|
51
|
+
@pio = IO.popen("ffmpeg #{@options} 2>&1")
|
52
|
+
@pid = @pio.pid
|
58
53
|
@pio.each_byte do |l|
|
59
54
|
if l == 10 or l == 13 then
|
60
55
|
@output.push temp
|
@@ -70,6 +65,9 @@ module PureMotion::Tools
|
|
70
65
|
if @pio.eof? then
|
71
66
|
@done = true
|
72
67
|
complete(true)
|
68
|
+
@pid = nil
|
69
|
+
@pio.close
|
70
|
+
exited(true)
|
73
71
|
end
|
74
72
|
end
|
75
73
|
|
@@ -78,7 +76,6 @@ module PureMotion::Tools
|
|
78
76
|
def ran?
|
79
77
|
@pio.eof? unless @pio.nil?
|
80
78
|
false
|
81
|
-
#!find(/^FFmpeg/).nil?
|
82
79
|
end
|
83
80
|
|
84
81
|
def ended?
|
@@ -101,41 +98,6 @@ module PureMotion::Tools
|
|
101
98
|
@status
|
102
99
|
end
|
103
100
|
|
104
|
-
private
|
105
|
-
|
106
|
-
def prepare_args
|
107
|
-
@args = []
|
108
|
-
@args << ['i', @input]
|
109
|
-
|
110
|
-
args = []
|
111
|
-
|
112
|
-
strings = []
|
113
|
-
|
114
|
-
@args.each do |arg, value|
|
115
|
-
if value.nil? then value = '' end
|
116
|
-
value = '"' + value.to_s + '"' unless value.index(' ').nil?
|
117
|
-
|
118
|
-
args << [ arg, value]
|
119
|
-
|
120
|
-
if value.empty? or value =~ /^\s*$/ then
|
121
|
-
value = ''
|
122
|
-
else
|
123
|
-
value = ' ' << value
|
124
|
-
end
|
125
|
-
|
126
|
-
strings << ( '-' << arg << value )
|
127
|
-
end
|
128
|
-
|
129
|
-
if !@output.nil? then strings << '"' + @output + '"' end
|
130
|
-
|
131
|
-
@args = strings.join(' ')
|
132
|
-
end
|
133
|
-
|
134
|
-
def status=(status_const)
|
135
|
-
@status = status_const
|
136
|
-
status_change(status_const)
|
137
|
-
end
|
138
|
-
|
139
101
|
end
|
140
102
|
|
141
103
|
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
def Transcode(*args, &block)
|
2
|
+
|
3
|
+
raise ArgumentError, "No block given for transcode preset" unless block_given?
|
4
|
+
|
5
|
+
preset = PureMotion::Preset.new(:dsl)
|
6
|
+
preset.instance_eval(&block)
|
7
|
+
|
8
|
+
options = {
|
9
|
+
:input => preset.input,
|
10
|
+
:output => preset.output,
|
11
|
+
:preset => preset
|
12
|
+
}
|
13
|
+
|
14
|
+
options[:log] = preset.log unless preset.log.nil?
|
15
|
+
|
16
|
+
transcode = PureMotion::Transcode::Transcode.new(options)
|
17
|
+
|
18
|
+
transcode.run
|
19
|
+
|
20
|
+
return transcode
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
module PureMotion::Transcode
|
25
|
+
|
26
|
+
class Transcode < Object
|
27
|
+
|
28
|
+
event :progress
|
29
|
+
event :complete
|
30
|
+
event :output
|
31
|
+
|
32
|
+
@ffmpeg = nil
|
33
|
+
@input = nil
|
34
|
+
|
35
|
+
def initialize(options)
|
36
|
+
|
37
|
+
default_options = {
|
38
|
+
:output => nil,
|
39
|
+
:preset => nil,
|
40
|
+
:input => nil
|
41
|
+
}
|
42
|
+
|
43
|
+
raise ArgumentError, "Invalid transcode parameters given" unless options.is_a?(Hash)
|
44
|
+
|
45
|
+
options = default_options.merge(options)
|
46
|
+
|
47
|
+
raise ArgumentError, "No output file given" if options[:output].nil?
|
48
|
+
|
49
|
+
if options[:input].is_a?(String) then
|
50
|
+
@input = PureMotion::Media.new(options[:input])
|
51
|
+
else
|
52
|
+
@input = options[:input]
|
53
|
+
end
|
54
|
+
@preset = options[:preset]
|
55
|
+
@output = options[:output]
|
56
|
+
|
57
|
+
validate
|
58
|
+
|
59
|
+
wire_events
|
60
|
+
|
61
|
+
if options[:log] then
|
62
|
+
@log = File.new(options[:log], 'w')
|
63
|
+
self.output + lambda do |t, line|
|
64
|
+
@log.puts line
|
65
|
+
end
|
66
|
+
self.complete + lambda do |t, complete|
|
67
|
+
@log.close
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Raise error if output file exists and overwrite not set
|
72
|
+
|
73
|
+
@ffmpeg = PureMotion::Tools::FFmpeg.new(:options => @preset.arguments)
|
74
|
+
|
75
|
+
@ffmpeg.line + lambda do |ffmpeg, line|
|
76
|
+
handle_output line
|
77
|
+
end
|
78
|
+
|
79
|
+
@ffmpeg.exited + lambda do |ffmpeg, exited|
|
80
|
+
complete(true)
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
def run
|
86
|
+
@ffmpeg.run
|
87
|
+
end
|
88
|
+
|
89
|
+
def cancel
|
90
|
+
# TODO : Implement
|
91
|
+
end
|
92
|
+
|
93
|
+
def cancel!
|
94
|
+
# TODO : Implement - kill process dead
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def handle_output line
|
100
|
+
output line
|
101
|
+
# /^frame=\s*(?<frame>\d*)\s*fps=\s*(?<fps>\d*)\s*q=(?<q>\S*)\s*size=\s*(?<size>[\d]*)(?<size_unit>[kmg]B)\s*time=\s*(?<time>[\d.]*)\s*bitrate=\s*(?<bitrate>[\d.]*)(?<bitrate_unit>[km]b).*$/
|
102
|
+
progress_line = /frame=\s*(\d*)\s*fps=\s*(\d*)\s*q=(\S*)\s*[L]?size=\s*([\d]*)([kmg]B)\s*time=\s*([\d.]*)\s*bitrate=\s*([\d.]*)([km]b)/
|
103
|
+
# The regex is documentated above and the matches it should give below
|
104
|
+
# 1 => frame
|
105
|
+
# 2 => fps
|
106
|
+
# 3 => q
|
107
|
+
# 4 => size
|
108
|
+
# 5 => size_unit
|
109
|
+
# 6 => time
|
110
|
+
# 7 => bitrate
|
111
|
+
# 8 => bitrate_unit
|
112
|
+
handle_progress(progress_line.match(line)) if progress_line.match(line)
|
113
|
+
end
|
114
|
+
|
115
|
+
def handle_progress line
|
116
|
+
if line[4].to_i == 0 then return false end
|
117
|
+
p = {
|
118
|
+
:frame => line[1].to_i,
|
119
|
+
:fps => line[2].to_i,
|
120
|
+
:q => line[3].to_f,
|
121
|
+
:size => line[4].to_i,
|
122
|
+
:time => line[6].to_f,
|
123
|
+
:bitrate => line[7].to_f,
|
124
|
+
:percent => ((100.00 / @input.duration) * line[6].to_f).to_i
|
125
|
+
}
|
126
|
+
p[:percent] = 100 if p[:percent] > 100 unless p[:percent].nil?
|
127
|
+
progress(p)
|
128
|
+
end
|
129
|
+
|
130
|
+
def validate
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
def wire_events
|
135
|
+
self.complete += @preset.event_handlers[:complete] unless @preset.event_handlers[:complete].nil?
|
136
|
+
self.progress += @preset.event_handlers[:progress] unless @preset.event_handlers[:progress].nil?
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe PureMotion::Preset do
|
4
|
+
|
5
|
+
it "should support all possible inputs" do
|
6
|
+
begin
|
7
|
+
PureMotion::Preset.build do
|
8
|
+
|
9
|
+
input sample_path
|
10
|
+
|
11
|
+
overwrite!
|
12
|
+
|
13
|
+
seek 2
|
14
|
+
duration 10
|
15
|
+
|
16
|
+
file do
|
17
|
+
|
18
|
+
size_limit 10_000_000
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
metadata do
|
23
|
+
|
24
|
+
title "Test"
|
25
|
+
author "Me"
|
26
|
+
copyright "None whatsoever"
|
27
|
+
album "Test"
|
28
|
+
track 2
|
29
|
+
comment "Brilliant"
|
30
|
+
year 1989
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
video do
|
35
|
+
|
36
|
+
disable
|
37
|
+
|
38
|
+
buffer '200'
|
39
|
+
|
40
|
+
bitrate '300k'
|
41
|
+
bitrate 300
|
42
|
+
|
43
|
+
same_quality
|
44
|
+
|
45
|
+
frames 100
|
46
|
+
|
47
|
+
framerate 25
|
48
|
+
fps 25
|
49
|
+
|
50
|
+
resolution 320, 240
|
51
|
+
resolution [320, 240]
|
52
|
+
resolution '320x240'
|
53
|
+
resolution :vga
|
54
|
+
|
55
|
+
crop do
|
56
|
+
top 10
|
57
|
+
bottom 20
|
58
|
+
left 30
|
59
|
+
right 40
|
60
|
+
end
|
61
|
+
|
62
|
+
pad do
|
63
|
+
top 40
|
64
|
+
bottom 30
|
65
|
+
left 20
|
66
|
+
right 10
|
67
|
+
|
68
|
+
color "333333"
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
audio do
|
74
|
+
|
75
|
+
disable
|
76
|
+
|
77
|
+
channels 2
|
78
|
+
sampling 44100
|
79
|
+
frames 100
|
80
|
+
|
81
|
+
language :eng
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
output "output.mp4"
|
86
|
+
|
87
|
+
end
|
88
|
+
end.should_not raise_error
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|