streamio-ffmpeg 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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