paperclip-ffmpeg 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.md +50 -0
- data/Rakefile +2 -0
- data/lib/paperclip-ffmpeg.rb +113 -0
- data/lib/paperclip-ffmpeg/version.rb +5 -0
- data/paperclip-ffmpeg.gemspec +23 -0
- metadata +73 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
Paperclip FFMPEG
|
2
|
+
================
|
3
|
+
|
4
|
+
Adding video handling to Paperclip via ffmpeg.
|
5
|
+
This gem has been tested under Linux and Mac OS X, YMMV under Windows.
|
6
|
+
|
7
|
+
Requirements
|
8
|
+
------------
|
9
|
+
|
10
|
+
FFMPEG must be installed and Paperclip must have access to it. To ensure
|
11
|
+
that it does, on your command line, run `which ffmpeg`.
|
12
|
+
This will give you the path where ffmpeg is installed. For
|
13
|
+
example, it might return `/usr/local/bin/ffmpeg`.
|
14
|
+
|
15
|
+
Then, in your environment config file, let Paperclip know to look there by adding that
|
16
|
+
directory to its path.
|
17
|
+
|
18
|
+
In development mode, you might add this line to `config/environments/development.rb)`:
|
19
|
+
|
20
|
+
Paperclip.options[:command_path] = "/usr/local/bin/"
|
21
|
+
|
22
|
+
Installation
|
23
|
+
------------
|
24
|
+
|
25
|
+
Include the gem in your Gemfile:
|
26
|
+
|
27
|
+
gem "paperclip-ffmpeg"
|
28
|
+
|
29
|
+
Quick Start
|
30
|
+
-----------
|
31
|
+
|
32
|
+
In your model:
|
33
|
+
|
34
|
+
class User < ActiveRecord::Base
|
35
|
+
has_attached_file :avatar, :styles => {
|
36
|
+
:medium => { :geometry => "640x480", :format => 'flv' }
|
37
|
+
:thumb => { :geometry => "100x100#", :format => 'jpg', :time => 10 }
|
38
|
+
}, :processors => [:ffmpeg]
|
39
|
+
end
|
40
|
+
|
41
|
+
This will produce:
|
42
|
+
|
43
|
+
1. A transcoded +:medium+ FLV file with the requested dimensions if they will match the aspect ratio of the original file, otherwise, width will be maintained and height will be recalculated to keep the original aspect ration.
|
44
|
+
2. A screenshot +:thumb+ with the requested dimensions regardless of the aspect ratio.
|
45
|
+
|
46
|
+
|
47
|
+
License
|
48
|
+
-------
|
49
|
+
|
50
|
+
Licensed under BSD license.
|
data/Rakefile
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require "paperclip"
|
2
|
+
module Paperclip
|
3
|
+
class Ffmpeg < Processor
|
4
|
+
attr_accessor :geometry, :format, :whiny, :convert_options
|
5
|
+
|
6
|
+
# Creates a Video object set to work on the +file+ given. It
|
7
|
+
# will attempt to transcode the video into one defined by +target_geometry+
|
8
|
+
# which is a "WxH"-style string. +format+ should be specified.
|
9
|
+
# Video transcoding will raise no errors unless
|
10
|
+
# +whiny+ is true (which it is, by default. If +convert_options+ is
|
11
|
+
# set, the options will be appended to the convert command upon video transcoding
|
12
|
+
def initialize file, options = {}, attachment = nil
|
13
|
+
@convert_options = {
|
14
|
+
:ab => '46k',
|
15
|
+
:ac => 2,
|
16
|
+
:ar => 44100,
|
17
|
+
:b => '1200k',
|
18
|
+
:deinterlace => nil,
|
19
|
+
:r => 25,
|
20
|
+
:y => nil,
|
21
|
+
}
|
22
|
+
@convert_options.reverse_merge! options[:convert_options] unless options[:convert_options].nil? || options[:convert_options].class != Hash
|
23
|
+
|
24
|
+
@geometry = options[:geometry]
|
25
|
+
@file = file
|
26
|
+
@keep_aspect = @geometry.nil? || @geometry[-1,1] != '#'
|
27
|
+
@whiny = options[:whiny].nil? ? true : options[:whiny]
|
28
|
+
@format = options[:format]
|
29
|
+
@time = options[:time].nil? ? 3 : options[:time]
|
30
|
+
@current_format = File.extname(@file.path)
|
31
|
+
@basename = File.basename(@file.path, @current_format)
|
32
|
+
@meta = identify
|
33
|
+
end
|
34
|
+
# Performs the transcoding of the +file+ into a thumbnail/video. Returns the Tempfile
|
35
|
+
# that contains the new image/video.
|
36
|
+
def make
|
37
|
+
src = @file
|
38
|
+
dst = Tempfile.new([@basename, @format ? ".#{@format}" : ''])
|
39
|
+
dst.binmode
|
40
|
+
|
41
|
+
begin
|
42
|
+
parameters = []
|
43
|
+
parameters << '-y'
|
44
|
+
# Add geometry
|
45
|
+
if @geometry
|
46
|
+
if @geometry =~ /(\d*)x(\d*)/
|
47
|
+
target_width = $1
|
48
|
+
target_height = $2
|
49
|
+
end
|
50
|
+
current_geometry = @meta[:size].split('x')
|
51
|
+
current_width = current_geometry[0]
|
52
|
+
current_height = current_geometry[1]
|
53
|
+
if @keep_aspect
|
54
|
+
# Correct size to keep aspect
|
55
|
+
if current_width.to_i > target_width.to_i
|
56
|
+
# Scaling down
|
57
|
+
width = target_width.to_i
|
58
|
+
height = (width.to_f / (@meta[:aspect].to_f)).to_i
|
59
|
+
else
|
60
|
+
# TODO: Padding
|
61
|
+
end
|
62
|
+
@convert_options[:s] = "#{width.to_i}x#{height.to_i}" unless width.nil? || height.nil?
|
63
|
+
else
|
64
|
+
@convert_options[:s] = @geometry
|
65
|
+
end
|
66
|
+
end
|
67
|
+
# Add format
|
68
|
+
case @format
|
69
|
+
when 'jpg', 'jpeg', 'png', 'gif' # Images
|
70
|
+
@convert_options[:f] = 'image2'
|
71
|
+
@convert_options[:ss] = @time
|
72
|
+
@convert_options[:vframes] = 1
|
73
|
+
end
|
74
|
+
|
75
|
+
parameters << '-i :source'
|
76
|
+
parameters << @convert_options.map { |k,v| "-#{k.to_s} #{v} "}
|
77
|
+
parameters << ":dest"
|
78
|
+
|
79
|
+
parameters = parameters.flatten.compact.join(" ").strip.squeeze(" ")
|
80
|
+
success = Paperclip.run("ffmpeg", parameters, :source => "#{File.expand_path(src.path)}", :dest => File.expand_path(dst.path))
|
81
|
+
|
82
|
+
rescue PaperclipCommandLineError => e
|
83
|
+
raise PaperclipError, "error while processing video for #{@basename}." if @whiny
|
84
|
+
end
|
85
|
+
|
86
|
+
dst
|
87
|
+
end
|
88
|
+
|
89
|
+
def identify
|
90
|
+
meta = {}
|
91
|
+
command = "ffmpeg -i #{File.expand_path(@file.path)} 2>&1"
|
92
|
+
Paperclip.log(command)
|
93
|
+
ffmpeg = IO.popen(command)
|
94
|
+
ffmpeg.each("\r") do |line|
|
95
|
+
if line =~ /((\d*)\s.?)fps,/
|
96
|
+
meta[:fps] = $1.to_i
|
97
|
+
end
|
98
|
+
# Matching lines like:
|
99
|
+
# Video: mjpeg, yuvj420p, 640x480 [PAR 72:72 DAR 4:3], 10301 kb/s, 30 fps, 30 tbr, 600 tbn, 600 tbc
|
100
|
+
if line =~ /Video:(\s.?(\w*),\s.?(\w*),\s(\d*x\d*)\s.?PAR\s.?(\d*):(\d*)\s.?DAR\s(\d*):(\d*))/
|
101
|
+
meta[:size] = $4
|
102
|
+
meta[:aspect] = $7.to_f / $8.to_f
|
103
|
+
end
|
104
|
+
# Matching Duration: 00:01:31.66, start: 0.000000, bitrate: 10404 kb/s
|
105
|
+
if line =~ /Duration:(\s.?(\d*):(\d*):(\d*\.\d*))/
|
106
|
+
meta[:length] = $2.to_s + ":" + $3.to_s + ":" + $4.to_s
|
107
|
+
meta[:frames] = ($4.to_i + ($3.to_i * 60) + ($2.to_i * 60 * 60)) * meta[:fps]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
meta
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "paperclip-ffmpeg/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "paperclip-ffmpeg"
|
7
|
+
s.version = Paperclip::Ffmpeg::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Omar Abdel-Wahab"]
|
10
|
+
s.email = ["owahab@gmail.com"]
|
11
|
+
s.homepage = "http://github.com/owahab/paperclip-ffmpeg"
|
12
|
+
s.summary = %q{Process your attachments with FFMPEG}
|
13
|
+
s.description = %q{Process your attachments with FFMPEG}
|
14
|
+
|
15
|
+
s.rubyforge_project = "paperclip-ffmpeg"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency('paperclip', '>=2.3.8')
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: paperclip-ffmpeg
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.2.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Omar Abdel-Wahab
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-06-01 00:00:00 +02:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: paperclip
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 2.3.8
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
description: Process your attachments with FFMPEG
|
28
|
+
email:
|
29
|
+
- owahab@gmail.com
|
30
|
+
executables: []
|
31
|
+
|
32
|
+
extensions: []
|
33
|
+
|
34
|
+
extra_rdoc_files: []
|
35
|
+
|
36
|
+
files:
|
37
|
+
- .gitignore
|
38
|
+
- Gemfile
|
39
|
+
- README.md
|
40
|
+
- Rakefile
|
41
|
+
- lib/paperclip-ffmpeg.rb
|
42
|
+
- lib/paperclip-ffmpeg/version.rb
|
43
|
+
- paperclip-ffmpeg.gemspec
|
44
|
+
has_rdoc: true
|
45
|
+
homepage: http://github.com/owahab/paperclip-ffmpeg
|
46
|
+
licenses: []
|
47
|
+
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options: []
|
50
|
+
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: "0"
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project: paperclip-ffmpeg
|
68
|
+
rubygems_version: 1.5.2
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: Process your attachments with FFMPEG
|
72
|
+
test_files: []
|
73
|
+
|