streamio-ffmpeg 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.
data/.gitignore CHANGED
@@ -19,3 +19,5 @@ rdoc
19
19
  pkg
20
20
 
21
21
  ## PROJECT::SPECIFIC
22
+ script/*
23
+ tmp/*
data/CHANGELOG CHANGED
@@ -1,3 +1,7 @@
1
+ == 0.3.0 2009-02-07
2
+
3
+ * Simple transcoding
4
+
1
5
  == 0.2.0 2009-02-06
2
6
 
3
7
  * Some more metadata parsing
data/README.rdoc CHANGED
@@ -10,6 +10,8 @@ Simplest possible wrapper around FFMPEG to get metadata from movie files and do
10
10
 
11
11
  == Usage
12
12
 
13
+ === Reading Metadata
14
+
13
15
  movie = FFMPEG::Movie.new("path/to/movie.mov")
14
16
 
15
17
  movie.duration # 7.5 (duration of the movie in seconds)
@@ -29,6 +31,27 @@ Simplest possible wrapper around FFMPEG to get metadata from movie files and do
29
31
  movie.audio_channels # 2
30
32
 
31
33
  movie.valid? # true (would be false if ffmpeg fails to read the movie)
34
+
35
+ === Transcoding
36
+
37
+ Use :output_file option to specify the output file path.
38
+
39
+ movie.transcode(:output_file => "tmp/movie.mp4") # Default ffmpeg settings for mp4 format
40
+
41
+ Keep track of progress with an optional block.
42
+
43
+ movie.transcode(:output_file => "movie.mp4") { |progress| puts progress } # 0.2 ... 0.5 ... 1.0
44
+
45
+ Give custom command line options to ffmpeg through :raw_options.
46
+
47
+ movie.transcode(:raw_options => "-ac aac -vc libx264 -ac 2 ...", :output_file => "movie.mp4")
48
+
49
+ The transcode function returns a Movie object for the encoded file.
50
+
51
+ transcoded_movie = movie.transcode(:output_file => "tmp/movie.flv")
52
+
53
+ transcoded_movie.video_codec # "flv"
54
+ transcoded_movie.audio_codec # "mp3"
32
55
 
33
56
  == Copyright
34
57
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.0
data/lib/ffmpeg/movie.rb CHANGED
@@ -1,14 +1,14 @@
1
- require 'open3'
2
-
3
1
  module FFMPEG
4
2
  class Movie
5
- attr_reader :duration, :bitrate
3
+ attr_reader :path, :duration, :bitrate
6
4
  attr_reader :video_stream, :video_codec, :colorspace, :resolution
7
5
  attr_reader :audio_stream, :audio_codec, :audio_sample_rate
8
6
 
9
7
  def initialize(path)
10
8
  raise Errno::ENOENT, "the file '#{path}' does not exist" unless File.exists?(path)
11
9
 
10
+ @path = path
11
+
12
12
  stdin, stdout, stderr = Open3.popen3("ffmpeg -i #{path}") # Output will land in stderr
13
13
  output = stderr.read
14
14
 
@@ -58,5 +58,10 @@ module FFMPEG
58
58
  def frame_rate
59
59
  video_stream[/(\d*\.\d*)\s?fps/] ? $1.to_f : nil
60
60
  end
61
+
62
+ def transcode(options, &block)
63
+ transcoder = Transcoder.new(self, options)
64
+ transcoder.run &block
65
+ end
61
66
  end
62
- end
67
+ end
@@ -0,0 +1,47 @@
1
+ require 'open3'
2
+
3
+ module FFMPEG
4
+ class Transcoder
5
+ def initialize(movie, options)
6
+ raise ArgumentError, "you need to specify options[:output_file]" unless options[:output_file]
7
+
8
+ @movie = movie
9
+ @options = options
10
+ end
11
+
12
+ def run
13
+ command = "ffmpeg -y -i '#{@movie.path}' #{@options[:raw_options]} '#{@options[:output_file]}'"
14
+ last_output = nil
15
+ Open3.popen3(command) do |stdin, stdout, stderr|
16
+ stderr.each("r") do |line|
17
+ if line =~ /time=(\d+.\d+)/
18
+ time = $1.to_f
19
+ progress = time / @movie.duration
20
+ yield(progress) if block_given?
21
+ end
22
+ if line =~ /Unsupported codec/
23
+ raise "Failed encoding: #{line}"
24
+ end
25
+ last_output = line
26
+ end
27
+ end
28
+
29
+ if encoding_succeeded?
30
+ yield(1.0) if block_given?
31
+ else
32
+ raise "Failed encoding. Last output: #{last_output}. Original duration: #{@movie.duration}. Encoded duration: #{encoded.duration}."
33
+ end
34
+
35
+ encoded
36
+ end
37
+
38
+ def encoding_succeeded?
39
+ precision = 1.1
40
+ encoded.valid? && !(encoded.duration >= (@movie.duration * precision) or encoded.duration <= (@movie.duration / precision))
41
+ end
42
+
43
+ def encoded
44
+ @encoded ||= Movie.new(@options[:output_file])
45
+ end
46
+ end
47
+ end
@@ -1,6 +1,7 @@
1
1
  $LOAD_PATH.unshift File.dirname(__FILE__)
2
2
 
3
3
  require 'ffmpeg/movie'
4
+ require 'ffmpeg/transcoder'
4
5
 
5
6
  module FFMPEG
6
7
  VERSION = '0.1.0'
@@ -1,7 +1,7 @@
1
- #require File.dirname(__FILE__) + '/../spec_helper.rb'
2
1
  require 'spec_helper.rb'
3
2
 
4
3
  module FFMPEG
4
+
5
5
  describe Movie do
6
6
  describe "given a non existing file" do
7
7
  it "should throw ArgumentError" do
@@ -9,73 +9,90 @@ module FFMPEG
9
9
  end
10
10
  end
11
11
 
12
- describe "given a non movie file" do
13
- before(:all) do
14
- @movie = Movie.new(__FILE__)
15
- end
16
-
17
- it "should not be valid" do
18
- @movie.should_not be_valid
19
- end
20
- end
21
-
22
- describe "given awesome.mov file" do
23
- before(:all) do
24
- @movie = Movie.new("#{fixture_path}/movies/awesome.mov")
25
- end
26
-
27
- it "should parse duration to number of seconds" do
28
- @movie.duration.should == 7.5
29
- end
30
-
31
- it "should parse the bitrate" do
32
- @movie.bitrate.should == 481
33
- end
12
+ describe "parsing" do
13
+ describe "given a non movie file" do
14
+ before(:all) do
15
+ @movie = Movie.new(__FILE__)
16
+ end
34
17
 
35
- it "should parse video stream information" do
36
- @movie.video_stream.should == "h264, yuv420p, 640x480 [PAR 1:1 DAR 4:3], 371 kb/s, 16.75 fps, 15 tbr, 600 tbn, 1200 tbc"
18
+ it "should not be valid" do
19
+ @movie.should_not be_valid
20
+ end
37
21
  end
38
22
 
39
- it "should know the video codec" do
40
- @movie.video_codec.should == "h264"
41
- end
23
+ describe "given awesome.mov file" do
24
+ before(:all) do
25
+ @movie = Movie.new("#{fixture_path}/movies/awesome.mov")
26
+ end
42
27
 
43
- it "should know the colorspace" do
44
- @movie.colorspace.should == "yuv420p"
45
- end
28
+ it "should remember the movie path" do
29
+ @movie.path.should == "#{fixture_path}/movies/awesome.mov"
30
+ end
46
31
 
47
- it "should know the resolution" do
48
- @movie.resolution.should == "640x480"
49
- end
32
+ it "should parse duration to number of seconds" do
33
+ @movie.duration.should == 7.5
34
+ end
50
35
 
51
- it "should know the width and height" do
52
- @movie.width.should == 640
53
- @movie.height.should == 480
54
- end
36
+ it "should parse the bitrate" do
37
+ @movie.bitrate.should == 481
38
+ end
55
39
 
56
- it "should know the framerate" do
57
- @movie.frame_rate.should == 16.75
58
- end
59
-
60
- it "should parse audio stream information" do
61
- @movie.audio_stream.should == "aac, 44100 Hz, stereo, s16, 75 kb/s"
62
- end
63
-
64
- it "should know the audio codec" do
65
- @movie.audio_codec.should == "aac"
66
- end
67
-
68
- it "should know the sample rate" do
69
- @movie.audio_sample_rate.should == 44100
70
- end
71
-
72
- it "should know the number of audio channels" do
73
- @movie.audio_channels.should == 2
74
- end
40
+ it "should parse video stream information" do
41
+ @movie.video_stream.should == "h264, yuv420p, 640x480 [PAR 1:1 DAR 4:3], 371 kb/s, 16.75 fps, 15 tbr, 600 tbn, 1200 tbc"
42
+ end
43
+
44
+ it "should know the video codec" do
45
+ @movie.video_codec.should == "h264"
46
+ end
47
+
48
+ it "should know the colorspace" do
49
+ @movie.colorspace.should == "yuv420p"
50
+ end
51
+
52
+ it "should know the resolution" do
53
+ @movie.resolution.should == "640x480"
54
+ end
55
+
56
+ it "should know the width and height" do
57
+ @movie.width.should == 640
58
+ @movie.height.should == 480
59
+ end
60
+
61
+ it "should know the framerate" do
62
+ @movie.frame_rate.should == 16.75
63
+ end
75
64
 
76
- it "should should be valid" do
77
- @movie.should be_valid
65
+ it "should parse audio stream information" do
66
+ @movie.audio_stream.should == "aac, 44100 Hz, stereo, s16, 75 kb/s"
67
+ end
68
+
69
+ it "should know the audio codec" do
70
+ @movie.audio_codec.should == "aac"
71
+ end
72
+
73
+ it "should know the sample rate" do
74
+ @movie.audio_sample_rate.should == 44100
75
+ end
76
+
77
+ it "should know the number of audio channels" do
78
+ @movie.audio_channels.should == 2
79
+ end
80
+
81
+ it "should should be valid" do
82
+ @movie.should be_valid
83
+ end
84
+ end
85
+ end
86
+
87
+ describe "transcode" do
88
+ it "should run the transcoder" do
89
+ FileUtils.rm_f "#{tmp_path}/awesome.flv"
90
+ movie = Movie.new("#{fixture_path}/movies/awesome.mov")
91
+ encoded = movie.transcode(:output_file => "#{tmp_path}/awesome.flv")
92
+ encoded.should be_valid
93
+ File.exists?("#{tmp_path}/awesome.flv").should be_true
78
94
  end
79
95
  end
80
96
  end
97
+
81
98
  end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper.rb'
2
+
3
+ module FFMPEG
4
+ describe Transcoder do
5
+ describe "initializing" do
6
+ it "should require an output_file option" do
7
+ lambda { Transcoder.new(nil, {}) }.should raise_error(ArgumentError, /output_file/)
8
+ end
9
+ end
10
+
11
+ describe "transcoding" do
12
+ it "should transcode the movie" do
13
+ FileUtils.rm_f "#{tmp_path}/awesome.flv"
14
+ movie = Movie.new("#{fixture_path}/movies/awesome.mov")
15
+ transcoder = Transcoder.new(movie, :output_file => "tmp/awesome.flv")
16
+ transcoder.run
17
+ transcoder.encoded.should be_valid
18
+ File.exists?("#{tmp_path}/awesome.flv").should be_true
19
+ end
20
+ end
21
+ end
22
+ end
data/spec/spec_helper.rb CHANGED
@@ -3,6 +3,7 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
  require 'streamio-ffmpeg'
4
4
  require 'spec'
5
5
  require 'spec/autorun'
6
+ require 'fileutils'
6
7
 
7
8
  Spec::Runner.configure do |config|
8
9
 
@@ -10,4 +11,10 @@ end
10
11
 
11
12
  def fixture_path
12
13
  @fixture_path ||= File.join(File.dirname(__FILE__), 'fixtures')
13
- end
14
+ end
15
+
16
+ def tmp_path
17
+ @tmp_path ||= File.join(File.dirname(__FILE__), "..", "tmp")
18
+ end
19
+
20
+ FileUtils.mkdir_p tmp_path
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{streamio-ffmpeg}
8
- s.version = "0.2.0"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["David Backeus"]
12
- s.date = %q{2010-02-06}
12
+ s.date = %q{2010-02-07}
13
13
  s.description = %q{Simple wrapper around ffmpeg to get metadata from movies and do transcoding}
14
14
  s.email = %q{duztdruid@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -25,8 +25,10 @@ Gem::Specification.new do |s|
25
25
  "Rakefile",
26
26
  "VERSION",
27
27
  "lib/ffmpeg/movie.rb",
28
+ "lib/ffmpeg/transcoder.rb",
28
29
  "lib/streamio-ffmpeg.rb",
29
30
  "spec/ffmpeg/movie_spec.rb",
31
+ "spec/ffmpeg/transcoder_spec.rb",
30
32
  "spec/fixtures/movies/awesome.mov",
31
33
  "spec/spec.opts",
32
34
  "spec/spec_helper.rb",
@@ -39,6 +41,7 @@ Gem::Specification.new do |s|
39
41
  s.summary = %q{Simple wrapper around ffmpeg to get metadata from movies and do transcoding}
40
42
  s.test_files = [
41
43
  "spec/ffmpeg/movie_spec.rb",
44
+ "spec/ffmpeg/transcoder_spec.rb",
42
45
  "spec/spec_helper.rb"
43
46
  ]
44
47
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: streamio-ffmpeg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Backeus
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-02-06 00:00:00 +01:00
12
+ date: 2010-02-07 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -40,8 +40,10 @@ files:
40
40
  - Rakefile
41
41
  - VERSION
42
42
  - lib/ffmpeg/movie.rb
43
+ - lib/ffmpeg/transcoder.rb
43
44
  - lib/streamio-ffmpeg.rb
44
45
  - spec/ffmpeg/movie_spec.rb
46
+ - spec/ffmpeg/transcoder_spec.rb
45
47
  - spec/fixtures/movies/awesome.mov
46
48
  - spec/spec.opts
47
49
  - spec/spec_helper.rb
@@ -76,4 +78,5 @@ specification_version: 3
76
78
  summary: Simple wrapper around ffmpeg to get metadata from movies and do transcoding
77
79
  test_files:
78
80
  - spec/ffmpeg/movie_spec.rb
81
+ - spec/ffmpeg/transcoder_spec.rb
79
82
  - spec/spec_helper.rb