web_video 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Brainberry
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,107 @@
1
+ =WebVideo
2
+
3
+ WebVideo allows you to inspect and process video files.
4
+
5
+ ==Installation
6
+ You need install 'ffmpeg' liblary ant it's dependent's...
7
+
8
+ ===Mac OS
9
+ sudo port install ffmpeg +lame +libogg +vorbis +faac +faad +xvid +x264 +a52
10
+
11
+ ===Linux (Ubuntu)
12
+ sudo apt-get install ffmpeg
13
+ sudo apt-get install libfaac-dev libxvidcore4-dev liba52-0.7.4 liba52-0.7.4-dev libx264-dev
14
+ sudo apt-get install libavutil49 libavutil-dev libavcodec-dev
15
+ sudo apt-get install libavcodec-unstripped-52
16
+
17
+ ===Install "WebVideo" via plugin
18
+ rails plugin install http://github.com/galetahub/web_video.git
19
+
20
+ ===Install "WebVideo" via gem
21
+ Directly from repository:
22
+ sudo gem install web_video
23
+ Or in your application "Gemfile":
24
+ gem "web_video"
25
+
26
+ ==Logger
27
+ You can put it in "config/initializers/web_video.rb".
28
+
29
+ logfile = File.open(Rails.root.join('log', 'video.log'), 'w')
30
+ logfile.sync = true
31
+
32
+ WebVideo.logger = Logger.new(logfile)
33
+
34
+ ==Example
35
+
36
+ Read video information
37
+ video = WebVideo::Adapters::FfmpegAdapter.new('demo.avi')
38
+
39
+ video.filename # => "demo.avi"
40
+
41
+ video.duration # => "00:03:39.90"
42
+
43
+ video.bitrate # => "2624 kb/s"
44
+
45
+ video.duration_in_seconds # => 219
46
+
47
+ video.streams # => Array of streams
48
+ # [ #<WebVideo::Stream @codec="mpeg4", @type="Video", @details="yuv420p, 640x480 [PAR 1:1 DAR 4:3], 30 tbr, 30 tbn, 30 tbc">,
49
+ # #<WebVideo::Stream @codec="mp3", @type="Audio", @details="44100 Hz, stereo, s16, 128 kb/s">]
50
+
51
+ Video Convertation
52
+ transcoder = WebVideo::Transcoder.new("demo.avi")
53
+ or
54
+ transcoder = WebVideo::Transcoder.new(video)
55
+
56
+ Transcoder attributes
57
+ transcoder.adapter # => :ffmpeg
58
+
59
+ transcoder.source # => return WebVideo::Adapters::FfmpegAdapter instance (video)
60
+
61
+ Generate flv file. Next example will generate "demo.flv" from "demo.avi".
62
+
63
+ options = {:resolution => "480x360"}
64
+
65
+ begin
66
+ transcoder.convert("demo.flv", options) do |command|
67
+ command << "-ar 22050"
68
+ command << "-ab 128k"
69
+ command << "-acodec libmp3lame"
70
+ command << "-vcodec flv"
71
+ command << "-r 25"
72
+ command << "-y"
73
+ end
74
+ rescue WebVideo::CommandLineError => e
75
+ WebVideo.logger.error("Unable to transcode video: #{e.class} - #{e.message}")
76
+ end
77
+
78
+
79
+ Generate images from video
80
+ By default screenshot starts at '00:00:01', to change it pass option :at => '00:05:00' (at five minutes)
81
+
82
+ transcoder.screenshot("demo.jpg", :resolution => "480x360")
83
+
84
+ Next code will generate five images: demo_01.jpg, demo_02.jpg, demo_03.jpg ...
85
+
86
+ image_files = 'demo_%2d.jpg'
87
+ options = {:resolution => "480x360", :count => 5 }
88
+
89
+ begin
90
+ transcoder.screenshot(image_files, options) do |command|
91
+ command << "-vcodec mjpeg"
92
+ # The duration for which image extraction will take place
93
+ #command << "-t 4"
94
+ command << "-y"
95
+ end
96
+ rescue WebVideo::CommandLineError => e
97
+ WebVideo.logger.error("Unable to transcode video: #{e.class} - #{e.message}")
98
+ end
99
+
100
+ ==TODO
101
+ 1. Add adapter for support 'mencoder' tool
102
+ 2. More information about video file (class Stream must parse details)
103
+ 3. Add support for 'flvtool2'
104
+ 4. Write more documentation
105
+ 5. Write tests
106
+
107
+ Copyright (c) 2010 Brainberry, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,42 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the web_video plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the web_video plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'WebVideo'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
24
+
25
+ begin
26
+ require 'jeweler'
27
+ Jeweler::Tasks.new do |gemspec|
28
+ gemspec.name = "web_video"
29
+ gemspec.version = '1.0.0'
30
+ gemspec.summary = "WebVideo allows you to inspect and process video files"
31
+ gemspec.description = "WebVideo allows you to inspect, convert and take screenshots from video files"
32
+ gemspec.email = "galeta.igor@gmail.com"
33
+ gemspec.homepage = "http://github.com/galetahub/web_video"
34
+ gemspec.authors = ["Igor Galeta"]
35
+ gemspec.files = FileList["[A-Z]*", "{lib}/**/*"]
36
+ gemspec.rubyforge_project = "web_video"
37
+ end
38
+
39
+ Jeweler::GemcutterTasks.new
40
+ rescue LoadError
41
+ puts "Jeweler not available. Install it with: gem install jeweler"
42
+ end
@@ -0,0 +1,62 @@
1
+ module WebVideo
2
+ module Adapters
3
+ class AbstractAdapter
4
+ attr_accessor :filepath, :filename, :path
5
+
6
+ def initialize(filepath, options = {})
7
+ @filepath = filepath
8
+
9
+ @filename = File.basename(@filepath)
10
+ @path = File.dirname(@filepath)
11
+
12
+ @options = options.symbolize_keys
13
+ @metadata = parse
14
+ end
15
+
16
+ def file_exists?
17
+ File.exist?(@filepath)
18
+ end
19
+
20
+ def size
21
+ File.size(@filepath)
22
+ end
23
+
24
+ def duration
25
+ @metadata[:duration]
26
+ end
27
+
28
+ def bitrate
29
+ @metadata[:bitrate]
30
+ end
31
+
32
+ def streams
33
+ @metadata[:streams]
34
+ end
35
+
36
+ def command_name
37
+ ''
38
+ end
39
+
40
+ def convert_command
41
+ []
42
+ end
43
+
44
+ def screenshot_command
45
+ []
46
+ end
47
+
48
+ def installed?
49
+ !WebVideo::Tools.run("which", command_name).blank?
50
+ end
51
+
52
+ def run(command, options = {})
53
+ WebVideo::Tools.run_with_option(command_name, command, options)
54
+ end
55
+
56
+ private
57
+ def parse
58
+ return {}
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,71 @@
1
+ module WebVideo
2
+ module Adapters
3
+ class FfmpegAdapter < AbstractAdapter
4
+
5
+ # 00:21:41.18
6
+ def duration_in_seconds
7
+ if @metadata[:duration] =~ /([0-9][0-9])\:([0-9][0-9])\:([0-9][0-9])\.([0-9][0-9])/
8
+ ( $1.to_i * 60 * 60 ) + ( $2.to_i * 60 ) + ( $3.to_i ) + ( ($4.to_i/100) * 60 )
9
+ end
10
+ end
11
+
12
+ def command_name
13
+ 'ffmpeg'
14
+ end
15
+
16
+ def convert_command
17
+ command = []
18
+ command << "-i $input_file$"
19
+ command << "-s $resolution$"
20
+
21
+ command.dup
22
+ end
23
+
24
+ def screenshot_command
25
+ command = []
26
+ command << "-i $input_file$"
27
+
28
+ # Specifies the frame size of the output (Default is the size of the original video.)
29
+ command << "-s $resolution$"
30
+
31
+ # Frame rate of video. i.e. no. of frames to be extracted into images per second
32
+ # The default value is 25
33
+ command << "-r 1"
34
+
35
+ # Disable audio recording.
36
+ command << "-an"
37
+
38
+ # Number of video frames to record
39
+ command << "-vframes $count$"
40
+
41
+ # Force format (image2|rawvideo)
42
+ command << "-f $format$"
43
+
44
+ # Start the extraction from particular point
45
+ command << "-ss $at$"
46
+
47
+ command.dup
48
+ end
49
+
50
+ private
51
+ def parse
52
+ if installed?
53
+ metadata = {}
54
+
55
+ ffmpeg_output = WebVideo::Tools.run(command_name, "-i #{@filepath}", [0,1])
56
+
57
+ metadata[:duration] = $1 if ffmpeg_output =~ /Duration\: ([0-9][0-9]\:[0-9][0-9]\:[0-9][0-9]\.[0-9][0-9])\,/
58
+ metadata[:bitrate] = $1 if ffmpeg_output =~ /\, bitrate\: (.*)$/
59
+
60
+ metadata[:streams] = []
61
+
62
+ ffmpeg_output.scan(/stream #0.([0-9])(\[.+\])?:\s(.*):\s([^,]*),\s(.*)/i).each do |match|
63
+ metadata[:streams] << WebVideo::Stream.new(:type => match[2], :codec => match[3], :details => match[4])
64
+ end
65
+
66
+ return metadata
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,26 @@
1
+ module WebVideo
2
+ class Stream
3
+ attr_accessor :type, :codec, :details
4
+
5
+ #
6
+ # stream = Stream.new :type => 'Video', :codec => 'mpeg4', :details => 'yuv420p, 640x480 [PAR 1:1 DAR 4:3], 30 tbr, 30 tbn, 30 tbc'
7
+ # stream.video? # => true
8
+ # stream.audio? # => false
9
+ #
10
+ def initialize(options = {})
11
+ options.symbolize_keys!
12
+
13
+ @type = options[:type].to_s.downcase
14
+ @codec = options[:codec]
15
+ @details = options[:details]
16
+ end
17
+
18
+ def video?
19
+ @type == 'video'
20
+ end
21
+
22
+ def audio?
23
+ @type == 'audio'
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,39 @@
1
+ module WebVideo
2
+ module Tools
3
+
4
+ def self.run_with_option(command_name, params, options = {})
5
+ run(command_name, apply_options(params, options))
6
+ end
7
+
8
+ #
9
+ # Execute command with params and return output if exit status equal expected_outcodes
10
+ #
11
+ def self.run(cmd, params = "", expected_outcodes = 0)
12
+ command = %Q[#{cmd} #{params}].gsub(/\s+/, " ")
13
+ command = "#{command} 2>&1"
14
+
15
+ WebVideo.logger.info(command)
16
+
17
+ output = `#{command}`
18
+
19
+ WebVideo.logger.info(output)
20
+
21
+ unless [expected_outcodes].flatten.include?($?.exitstatus)
22
+ raise WebVideo::CommandLineError, "Error while running #{cmd}"
23
+ end
24
+
25
+ output
26
+ end
27
+
28
+ def self.apply_options(command, options)
29
+ str = command.dup
30
+
31
+ options.each do |key, value|
32
+ param = value.is_a?(String) ? value.inspect : value
33
+ str.gsub!("$#{key}$", param.to_s)
34
+ end
35
+
36
+ str
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,112 @@
1
+ module WebVideo
2
+ class Transcoder
3
+ attr_accessor :source
4
+ attr_reader :adapter
5
+
6
+ # Video Convertation
7
+ #
8
+ # transcoder = WebVideo::Transcoder.new("demo.avi")
9
+ # transcoder.source # WebVideo::Adapters::AbstractAdapter instance
10
+ #
11
+ # Or
12
+ #
13
+ # video = WebVideo::Adapters::FfmpegAdapter.new('demo.avi')
14
+ # transcoder = WebVideo::Transcoder.new(video)
15
+ # transcoder.source # WebVideo::Adapters::FfmpegAdapter instance (video)
16
+ #
17
+ def initialize(filepath, options = {}, adapter = :ffmpeg)
18
+ @adapter = adapter
19
+
20
+ if filepath.is_a?(WebVideo::Adapters::AbstractAdapter)
21
+ @source = filepath
22
+ else
23
+ args = [filepath, options]
24
+
25
+ @source = case @adapter
26
+ when String, Symbol then
27
+ load_adapter(@adapter.to_s).new(*args)
28
+ when Class then
29
+ @adapter.new(*args)
30
+ else
31
+ @adapter
32
+ end
33
+ end
34
+ end
35
+
36
+ # Create screenshots
37
+ #
38
+ # transcoder = WebVideo::Transcoder.new("demo.avi")
39
+ # transcoder.screenshot("demo.jpg", :resolution => "480x360")
40
+ #
41
+ # options:
42
+ # :count - count images to generate
43
+ # :format - image decoder
44
+ # :at - time to start make screenshots from
45
+ # :resolution - image resolution
46
+ def screenshot(destination, options = {}, &block)
47
+ options.symbolize_keys!
48
+
49
+ options[:count] ||= 1
50
+ options[:format] ||= "image2"
51
+ options[:at] ||= "00:00:01"
52
+
53
+ process(destination, @source.screenshot_command, options, &block)
54
+ end
55
+
56
+ # Generate new video file
57
+ #
58
+ # transcoder = WebVideo::Transcoder.new("demo.avi")
59
+ #
60
+ # begin
61
+ # transcoder.convert("demo.flv", :resolution => "480x360") do |command|
62
+ # command << "-ar 22050"
63
+ # command << "-ab 128k"
64
+ # command << "-acodec libmp3lame"
65
+ # command << "-vcodec flv"
66
+ # command << "-r 25"
67
+ # command << "-y"
68
+ # end
69
+ # rescue WebVideo::CommandLineError => e
70
+ # WebVideo.logger.error("Unable to transcode video: #{e.class} - #{e.message}")
71
+ # end
72
+ #
73
+ # options:
74
+ # :resolution - video resolution
75
+ #
76
+ def convert(destination, options = {}, &block)
77
+ options.symbolize_keys!
78
+
79
+ process(destination, @source.convert_command, options, &block)
80
+ end
81
+
82
+ # Execute command
83
+ #
84
+ def execute(command, options = {})
85
+ @source.run(command, options)
86
+ end
87
+
88
+ private
89
+
90
+ def load_adapter(adapter_name)
91
+ class_name = "#{adapter_name}_adapter".classify
92
+ "WebVideo::Adapters::#{class_name}".constantize
93
+ end
94
+
95
+ def process(destination, command, options = {}, &block)
96
+ options[:input_file] = @source.filepath
97
+ options[:output_file] = destination
98
+
99
+ if block_given?
100
+ begin
101
+ yield command
102
+ rescue Exception => e
103
+ raise WebVideo::Error, "Error take screenshot #{destination}: #{e.class} => #{e.message}"
104
+ end
105
+ end
106
+
107
+ command << "$output_file$"
108
+
109
+ execute(command.join(' '), options)
110
+ end
111
+ end
112
+ end
data/lib/web_video.rb ADDED
@@ -0,0 +1,36 @@
1
+ require 'logger'
2
+
3
+ module WebVideo
4
+ autoload :Tools, 'web_video/tools'
5
+ autoload :Stream, 'web_video/stream'
6
+ autoload :Transcoder, 'web_video/transcoder'
7
+
8
+ module Adapters
9
+ autoload :AbstractAdapter, 'web_video/adapters/abstract_adapter'
10
+ autoload :FfmpegAdapter, 'web_video/adapters/ffmpeg_adapter'
11
+ end
12
+
13
+ #
14
+ # WebVideo.logger.info 'Demo convert'
15
+ #
16
+ def self.logger
17
+ @logger ||= Logger.new('/dev/null')
18
+ @logger
19
+ end
20
+
21
+ #
22
+ # Configure logging. Pass a valid Ruby logger object.
23
+ #
24
+ # logger = Logger.new(STDOUT)
25
+ # WebVideo.logger = logger
26
+ #
27
+ def self.logger=(value)
28
+ @logger = value
29
+ end
30
+
31
+ class Error < StandardError #:nodoc:
32
+ end
33
+
34
+ class CommandLineError < StandardError #:nodoc:
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'active_support'
@@ -0,0 +1,8 @@
1
+ require 'test_helper'
2
+
3
+ class WebVideoTest < ActiveSupport::TestCase
4
+ # Replace this with your real tests.
5
+ test "the truth" do
6
+ assert true
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: web_video
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - Igor Galeta
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-05-07 00:00:00 +03:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: WebVideo allows you to inspect, convert and take screenshots from video files
22
+ email: galeta.igor@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README.rdoc
29
+ files:
30
+ - MIT-LICENSE
31
+ - README.rdoc
32
+ - Rakefile
33
+ - lib/web_video.rb
34
+ - lib/web_video/adapters/abstract_adapter.rb
35
+ - lib/web_video/adapters/ffmpeg_adapter.rb
36
+ - lib/web_video/stream.rb
37
+ - lib/web_video/tools.rb
38
+ - lib/web_video/transcoder.rb
39
+ has_rdoc: true
40
+ homepage: http://github.com/galetahub/web_video
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options:
45
+ - --charset=UTF-8
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ segments:
53
+ - 0
54
+ version: "0"
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ requirements: []
63
+
64
+ rubyforge_project: web_video
65
+ rubygems_version: 1.3.6
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: WebVideo allows you to inspect and process video files
69
+ test_files:
70
+ - test/web_video_test.rb
71
+ - test/test_helper.rb