libis-format 0.9.38 → 0.9.39

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +13 -13
  3. data/data/types.yml +85 -9
  4. data/lib/libis/format.rb +1 -0
  5. data/lib/libis/format/config.rb +2 -0
  6. data/lib/libis/format/converter/audio_converter.rb +181 -0
  7. data/lib/libis/format/converter/video_converter.rb +194 -0
  8. data/lib/libis/format/ffmpeg.rb +41 -0
  9. data/lib/libis/format/identifier.rb +1 -0
  10. data/lib/libis/format/pdf_to_pdfa.rb +1 -3
  11. data/lib/libis/format/pdfa_validator.rb +1 -1
  12. data/lib/libis/format/version.rb +1 -1
  13. data/libis-format.gemspec +1 -0
  14. data/spec/converter_spec.rb +116 -20
  15. data/spec/data/audio/carlin_disappointed.aac +0 -0
  16. data/spec/data/audio/carlin_disappointed.ac3 +0 -0
  17. data/spec/data/audio/carlin_disappointed.aiff +0 -0
  18. data/spec/data/audio/carlin_disappointed.au +0 -0
  19. data/spec/data/audio/carlin_disappointed.flac +0 -0
  20. data/spec/data/audio/carlin_disappointed.m4a +0 -0
  21. data/spec/data/audio/carlin_disappointed.mka +0 -0
  22. data/spec/data/audio/carlin_disappointed.mp3 +0 -0
  23. data/spec/data/audio/carlin_disappointed.ogg +0 -0
  24. data/spec/data/audio/carlin_disappointed.ra +0 -0
  25. data/spec/data/audio/carlin_disappointed.voc +0 -0
  26. data/spec/data/audio/carlin_disappointed.wav +0 -0
  27. data/spec/data/audio/carlin_disappointed.wma +0 -0
  28. data/spec/data/audio/greensleeves.aac +0 -0
  29. data/spec/data/audio/greensleeves.ac3 +0 -0
  30. data/spec/data/audio/greensleeves.aiff +0 -0
  31. data/spec/data/audio/greensleeves.au +0 -0
  32. data/spec/data/audio/greensleeves.flac +0 -0
  33. data/spec/data/audio/greensleeves.m4a +0 -0
  34. data/spec/data/audio/greensleeves.mka +0 -0
  35. data/spec/data/audio/greensleeves.mp3 +0 -0
  36. data/spec/data/audio/greensleeves.ogg +0 -0
  37. data/spec/data/audio/greensleeves.ra +0 -0
  38. data/spec/data/audio/greensleeves.voc +0 -0
  39. data/spec/data/audio/greensleeves.wav +0 -0
  40. data/spec/data/audio/greensleeves.wma +0 -0
  41. data/spec/data/audio/king_nonviolence.aac +0 -0
  42. data/spec/data/audio/king_nonviolence.ac3 +0 -0
  43. data/spec/data/audio/king_nonviolence.aiff +0 -0
  44. data/spec/data/audio/king_nonviolence.au +0 -0
  45. data/spec/data/audio/king_nonviolence.flac +0 -0
  46. data/spec/data/audio/king_nonviolence.m4a +0 -0
  47. data/spec/data/audio/king_nonviolence.mka +0 -0
  48. data/spec/data/audio/king_nonviolence.mp3 +0 -0
  49. data/spec/data/audio/king_nonviolence.ogg +0 -0
  50. data/spec/data/audio/king_nonviolence.ra +0 -0
  51. data/spec/data/audio/king_nonviolence.voc +0 -0
  52. data/spec/data/audio/king_nonviolence.wav +0 -0
  53. data/spec/data/audio/king_nonviolence.wma +0 -0
  54. data/spec/data/audio/top_gun_secret.aac +0 -0
  55. data/spec/data/audio/top_gun_secret.ac3 +0 -0
  56. data/spec/data/audio/top_gun_secret.aiff +0 -0
  57. data/spec/data/audio/top_gun_secret.au +0 -0
  58. data/spec/data/audio/top_gun_secret.flac +0 -0
  59. data/spec/data/audio/top_gun_secret.m4a +0 -0
  60. data/spec/data/audio/top_gun_secret.mka +0 -0
  61. data/spec/data/audio/top_gun_secret.mp3 +0 -0
  62. data/spec/data/audio/top_gun_secret.ogg +0 -0
  63. data/spec/data/audio/top_gun_secret.ra +0 -0
  64. data/spec/data/audio/top_gun_secret.voc +0 -0
  65. data/spec/data/audio/top_gun_secret.wav +0 -0
  66. data/spec/data/audio/top_gun_secret.wma +0 -0
  67. data/spec/data/video/SampleVideo_1080x720_2mb.flv +0 -0
  68. data/spec/data/video/SampleVideo_1080x720_2mb.mkv +0 -0
  69. data/spec/data/video/SampleVideo_1080x720_2mb.mp4 +0 -0
  70. data/spec/data/video/SampleVideo_176x144_2mb.3gp +0 -0
  71. data/spec/data/video/SampleVideo_320x240_2mb.3gp +0 -0
  72. data/spec/data/video/SampleVideo_360x240_2mb.flv +0 -0
  73. data/spec/data/video/SampleVideo_360x240_2mb.mkv +0 -0
  74. data/spec/data/video/SampleVideo_360x240_2mb.mp4 +0 -0
  75. data/spec/data/video/sample.avi +0 -0
  76. data/spec/data/video/sample.flv +0 -0
  77. data/spec/data/video/sample.mkv +0 -0
  78. data/spec/data/video/sample.mov +0 -0
  79. data/spec/data/video/sample.mp4 +0 -0
  80. data/spec/data/video/sample.mpg +0 -0
  81. data/spec/data/video/sample.swf +0 -0
  82. data/spec/data/video/sample.webm +0 -0
  83. data/spec/data/video/sample.wmv +0 -0
  84. data/spec/identifier_spec.rb +29 -39
  85. data/spec/spec_helper.rb +50 -1
  86. metadata +157 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aee2f761cde56c377abdfff7b7d40d09c32c0c93
4
- data.tar.gz: 5d6384f6484d04ec01705883e04ead5b0d02dacb
3
+ metadata.gz: d41852f4f00f61ffa6458f3ba0f9ce58215573d8
4
+ data.tar.gz: 96158848af69ff1ad5ffafc198d6f04b30a94f9c
5
5
  SHA512:
6
- metadata.gz: 5a359cd06cc1f3f442b69981858e44e55f4cd085e0e0291e4b03c0a530e86d5f5e72d1083cc7b2fa306fdd4dba033ce4eb985c49373fe0d4467052f1406146a3
7
- data.tar.gz: 619bdb26cfea98753544d47fd1096150cd2f7ec56e5322bffabf6a4c598797f31be68d22b3f7f267aebcc5f743ae6d60bcd498a1eb27af183a5b0a5cbae7c0a9
6
+ metadata.gz: 7db9b6c77b4429fa91ec099d8a10c55799050e6ca345b1af0f2273c5645841b2edb33b5be9cfe2967eedf52d0438e6bbe92e0ad499f2be3460ec8e53d7e076b1
7
+ data.tar.gz: 6399b4b84f80b7e48c2c85c3390e34fe39b70c8ea1c4a096dfd33981bbcc2eca2ba88f8be9e4738ff424f0e12446f5b898b1db248206ebd080fff098c585af6b
data/.travis.yml CHANGED
@@ -1,5 +1,6 @@
1
1
  language: ruby
2
2
  sudo: false
3
+ dist: trusty
3
4
  cache: bundler
4
5
  rvm:
5
6
  - 2.1.0
@@ -7,31 +8,25 @@ rvm:
7
8
  - ruby-head
8
9
  - jruby-9.0.1.0
9
10
  jdk:
10
- - openjdk7
11
- - oraclejdk7
11
+ - openjdk8
12
12
  - oraclejdk8
13
13
  matrix:
14
14
  exclude:
15
- - rvm: 2.1.0
16
- jdk: oraclejdk7
17
15
  - rvm: 2.1.0
18
16
  jdk: oraclejdk8
19
- - rvm: 2.2.0
20
- jdk: oraclejdk7
21
17
  - rvm: 2.2.0
22
18
  jdk: oraclejdk8
23
- - rvm: ruby-head
24
- jdk: oraclejdk7
25
19
  - rvm: ruby-head
26
20
  jdk: oraclejdk8
27
- allow_failures:
28
- - rvm: 2.1.0
29
- - rvm: 2.2.0
30
- - rvm: ruby-head
31
- - rvm: jruby-9.0.1.0
32
21
  branches:
33
22
  only:
34
23
  - master
24
+ before_install:
25
+ - sudo add-apt-repository ppa:mc3man/trusty-media -y
26
+ - sudo apt-get update -y
27
+ - sudo apt-get install -y ffmpeg gstreamer0.10-ffmpeg
28
+ - sudo pip install opf-fido --upgrade --ignore-installed six
29
+
35
30
  addons:
36
31
  apt:
37
32
  packages:
@@ -39,3 +34,8 @@ addons:
39
34
  - imagemagick
40
35
  - libreoffice
41
36
  - ghostscript
37
+ - sox
38
+ - libsox-dev
39
+ - libsox-fmt-all
40
+ - libchromaprint-dev
41
+ - libchromaprint-tools
data/data/types.yml CHANGED
@@ -70,66 +70,142 @@ IMAGE:
70
70
 
71
71
  AUDIO:
72
72
 
73
- WAV:
74
- NAME: Waveform Audio File Format (WAVE)
75
- MIME: audio/x-wav
76
- EXTENSIONS: wav
77
-
78
73
  MP3:
79
74
  NAME: MPEG-1 or MPEG-2 Audio Layer III (MP3)
80
75
  MIME: audio/mpeg
76
+ PUID: fmt/134
81
77
  EXTENSIONS: mp3
82
78
 
83
79
  FLAC:
84
80
  NAME: Free Lossless Audio Codec (FLAC)
85
81
  MIME: audio/flac
82
+ PUID: fmt/279
86
83
  EXTENSIONS: flac
87
84
 
85
+ AC3:
86
+ NAME: Dolby Digital AC-3
87
+ MIME: audio/ac3
88
+ PUID: fmt/735
89
+ EXTENSIONS: ac3
90
+
91
+ AAC:
92
+ NAME: Advanced Audio Coding (AAC)
93
+ MIME: audio/aac
94
+ EXTENSIONS: aac
95
+
96
+ WMA:
97
+ NAME: Windows Media Audio (WMA)
98
+ MIME: audio/x-ms-wma
99
+ PUID: fmt/132
100
+ EXTENSIONS: wma
101
+
102
+ ALAC:
103
+ NAME: Apple Lossless Audio Codec (ALAC)
104
+ MIME: audio/alac
105
+ EXTENSIONS: alac
106
+
107
+ WAV:
108
+ NAME: Waveform Audio File Format (WAVE)
109
+ MIME: audio/x-wav
110
+ PUID: fmt/6, fmt/141, fmt/142, fmt/143, fmt/1, fmt/703, fmt/706, fmt/709, fmt/2, fmt/704, fmt/707, fmt/710, fmt/527, fmt/705, fmt/708, fmt/711, x-fmt/397, x-fmt/389, x-fmt/396, fmt/712, fmt/713
111
+ EXTENSIONS: wav
112
+
113
+ AIFF:
114
+ NAME: Audio Interchange File Format (AIFF)
115
+ MIME: audio/aiff
116
+ PUID: fmt/414, x-fmt/135, x-fmt/136
117
+ EXTENSIONS: aif aiff aifc
118
+
119
+ AMR:
120
+ NAME: Adaptive Multi-Rate Audio (AMR)
121
+ MIME: audio/amr
122
+ PUID: fmt/954
123
+ EXTENSIONS: amr
124
+
125
+ AU:
126
+ NAME: NeXT/Sun sound (AU)
127
+ MIME: audio/basic
128
+ PUID: x-fmt/139
129
+ EXTENSIONS: au
130
+
131
+ M4A:
132
+ NAME: MPEG-4 Media File (M4A)
133
+ MIME: audio/mp4
134
+ PUID: fmt/199, fmt/596
135
+ EXTENSIONS: m4a f4a
136
+
88
137
  VIDEO:
89
138
 
90
- MPEG:
139
+ MPG:
91
140
  NAME: Moving Picture Experts Group (MPEG-1/MPEG-2)
92
141
  MIME: video/mpeg
142
+ PUID: x-fmt/385 x-fmt/386 fmt/425 fmt/649 fmt/640
93
143
  EXTENSIONS: mpg mpeg mp1 mp2 mp3 m1v m1a m2a mpa mpv
94
144
 
95
- MPEG4:
145
+ MP4:
96
146
  NAME: Moving Picture Experts Group (MPEG-4)
97
- MIME: video/mp4
98
- EXTENSIONS: mp4,mpeg4
147
+ MIME: video/mp4, application/mp4
148
+ PUID: fmt/199
149
+ EXTENSIONS: mp4,m4v,mpeg4
150
+
151
+ WEBM:
152
+ NAME: Webm
153
+ PUID: fmt/573
154
+ MIME: video/webm
155
+ EXTENSIONS: webm
156
+
157
+ FLASH:
158
+ NAME: Macromedia Flash
159
+ MIME: application/x-shockwave-flash
160
+ PUID: fmt/104 fmt/105 fmt/106 fmt/107 fmt/108 fmt/109 fmt/110
161
+ EXTENSIONS: swf
162
+
163
+ MKV:
164
+ NAME: Matroska Multimedia Container (MKV)
165
+ MIME: video/x-matroska
166
+ PUID: fmt/569
167
+ EXTENSIONS: mkv, mk3d, mka, mks
99
168
 
100
169
  MJP2:
101
170
  NAME: Motion JPEG 2000 (MJP2)
102
171
  MIME: video/mj2
172
+ PUID: fmt/337
103
173
  EXTENSIONS: mj2, mjp2
104
174
 
105
175
  QTFF:
106
176
  NAME: QuickTime File Format (QTFF)
107
177
  MIME: video/quicktime
178
+ PUID: x-fmt/384
108
179
  EXTENSIONS: mov, qt
109
180
 
110
181
  AVI:
111
182
  NAME: Audio Video Interleave (AVI)
112
183
  MIME: video/x-msvideo
184
+ PUID: fmt/5
113
185
  EXTENSIONS: avi
114
186
 
115
187
  OGGV:
116
188
  NAME: OGG Video (OGGV)
117
189
  MIME: video/ogg
190
+ PUID: fmt/945
118
191
  EXTENSIONS: ogv
119
192
 
120
193
  WMV:
121
194
  NAME: Windows Media Video (WMV)
122
195
  MIME: video/x-ms-wmv
196
+ PUID: fmt/133 fmt/441
123
197
  EXTENSIONS: wmv
124
198
 
125
199
  DV:
126
200
  NAME: Digital Video (DV)
127
201
  MIME: video/dv
202
+ PUID: x-fmt/152
128
203
  EXTENSIONS: dv
129
204
 
130
205
  FLASH:
131
206
  NAME: Flash video (FLV)
132
207
  MIME: video/x-flv
208
+ PUID: x-fmt/382
133
209
  EXTENSIONS: flv
134
210
 
135
211
  TEXT:
data/lib/libis/format.rb CHANGED
@@ -19,6 +19,7 @@ module Libis
19
19
  autoload :PdfSplit, 'libis/format/pdf_split'
20
20
  autoload :PdfToPdfa, 'libis/format/pdf_to_pdfa'
21
21
  autoload :PdfaValidator, 'libis/format/pdfa_validator'
22
+ autoload :FFMpeg, 'libis/format/ffmpeg'
22
23
 
23
24
  autoload :Converter, 'libis/format/converter'
24
25
 
@@ -15,11 +15,13 @@ module Libis
15
15
  Config[:ghostscript_path] = 'gs'
16
16
  Config[:droid_path] = '/opt/droid/droid.sh'
17
17
  Config[:fido_path] = '/usr/local/bin/fido'
18
+ Config[:ffmpeg_path] = 'ffmpeg'
18
19
  data_dir = File.absolute_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'data'))
19
20
  Config[:fido_formats] = [(File.join(data_dir, 'lias_formats.xml'))]
20
21
  # noinspection RubyStringKeysInHashInspection
21
22
  Config[:xml_validations] = [['archive/ead', File.join(data_dir, 'ead.xsd')]]
22
23
  Config[:type_database] = File.join(data_dir, 'types.yml')
24
+ Config[:raw_audio_convert_cmd] = 'sox %s -e signed -b 16 -t wav %s rate %d channels %d'
23
25
 
24
26
  end
25
27
  end
@@ -0,0 +1,181 @@
1
+ require_relative 'base'
2
+ require 'libis/format/identifier'
3
+ require 'chromaprint'
4
+
5
+ require 'fileutils'
6
+
7
+ module Libis
8
+ module Format
9
+ module Converter
10
+
11
+ class AudioConverter < Libis::Format::Converter::Base
12
+
13
+ def self.input_types
14
+ [:MP3, :FLAC, :AC3, :AAC, :WMA, :ALAC, :WAV, :AIFF, :AMR, :AU, :M4A]
15
+ end
16
+
17
+ def self.output_types(format = nil)
18
+ return [] unless input_types.include?(format)
19
+ [:MP3, :FLAC, :AC3, :AAC, :WMA, :ALAC, :WAV, :AIFF, :AMR, :AU, :M4A]
20
+ end
21
+
22
+ def initialize
23
+ super
24
+ end
25
+
26
+ def quiet(v)
27
+ @flags[:quiet] = !!v
28
+ end
29
+
30
+ def format(format)
31
+ @options[:format] = format
32
+ end
33
+
34
+ def codec(codec)
35
+ @options[:codec] = codec
36
+ end
37
+
38
+ def start(seconds)
39
+ @options[:start] = seconds.to_s
40
+ end
41
+
42
+ def duration(seconds)
43
+ @options[:duration] = seconds.to_s
44
+ end
45
+
46
+ def quality(value)
47
+ @options[:quality] = value.to_s
48
+ end
49
+
50
+ def bit_rate(value)
51
+ @options[:bit_rate] = value.to_s
52
+ end
53
+
54
+ def sampling_freq(value)
55
+ @options[:sampling_freq] = value.to_s
56
+ end
57
+
58
+ def channels(value)
59
+ @options[:channels] = value.to_s
60
+ end
61
+
62
+ def web_stream(value)
63
+ if value
64
+ @options[:codec] = 'mp3'
65
+ end
66
+ end
67
+
68
+ def preset(stream, name)
69
+ (@options[:preset] ||= {})[stream] = name
70
+ end
71
+
72
+ # def encoder(value)
73
+ # @options[:encoder] = value
74
+ # end
75
+ #
76
+ # def encoder_options(value)
77
+ # @options[:encoder_options] = value
78
+ # end
79
+
80
+ def convert(source, target, _format, opts = {})
81
+ super
82
+
83
+ FileUtils.mkpath(File.dirname(target))
84
+
85
+ if source.is_a? Array
86
+
87
+ assemble_and_convert(source, target)
88
+
89
+ elsif File.directory?(source)
90
+
91
+ sources = Dir[File.join(source, '**', '*')].reject {|p| File.directory? p}
92
+ assemble_and_convert(sources, target)
93
+
94
+ else
95
+
96
+ convert_file(source, target)
97
+
98
+ end
99
+
100
+ target
101
+
102
+ end
103
+
104
+ def assemble_and_convert(sources, target)
105
+ Tempfile.create(%w(list .txt)) do |f|
106
+ sources.each {|src| f.puts src}
107
+ opts[:global] ||= []
108
+ opts[:global] += %w(-f concat)
109
+ f.close
110
+ target = convert_file(f.to_path, target)
111
+ end
112
+ target
113
+ end
114
+
115
+ def sounds_like(file1, file2, threshold, rate, channels)
116
+ rate ||= 96000
117
+ channels ||= 2
118
+ threshold ||= 0.85
119
+
120
+ if File.exists?(file1) && File.exists?(file2)
121
+ # Convert input files into raw 16-bit signed audio (WAV) to process with Chramaprint
122
+ file1_raw = File.join('', 'tmp', File.basename(file1) + '.wav')
123
+ file2_raw = File.join('', 'tmp', File.basename(file2) + '.wav')
124
+ FileUtils.rm(file1_raw, force: true)
125
+ FileUtils.rm(file2_raw, force: true)
126
+ cvt_cmd = Libis::Format::Config[:raw_audio_convert_cmd]
127
+ %x"#{cvt_cmd % [file1, file1_raw, rate, channels]}"
128
+ %x"#{cvt_cmd % [file2, file2_raw, rate, channels]}"
129
+ file1_audio = File.binread(file1_raw)
130
+ file2_audio = File.binread(file2_raw)
131
+
132
+ # Get audio fingerprints
133
+ chromaprint = Chromaprint::Context.new(rate, channels, Chromaprint::ALGORITHM_TEST3)
134
+ file1_fp = chromaprint.get_fingerprint(file1_audio)
135
+ file2_fp = chromaprint.get_fingerprint(file2_audio)
136
+
137
+ # Cleanup files
138
+ FileUtils.rm(file1_raw, force: true)
139
+ FileUtils.rm(file2_raw, force: true)
140
+
141
+ # Compare fingerprints and compare result against threshold
142
+ cmp = file1_fp.compare(file2_fp)
143
+ # puts "Threshold[#{File.basename(exp_file)},#{File.basename(tgt_file)}: #{cmp}"
144
+ cmp > threshold
145
+ else
146
+ false
147
+ end
148
+
149
+ rescue Exception => e
150
+ error "Error comparing sound file #{file1} and #{file2}: #{e.message} @ #{e.backtrace.first}"
151
+ false
152
+ end
153
+
154
+ protected
155
+
156
+ def convert_file(source, target)
157
+ opts = {global: [], input: [], filter: [], output: []}
158
+ opts[:global] << '-hide_banner'
159
+ opts[:global] << '-loglevel' << (@options[:quiet] ? 'fatal' : 'warning')
160
+ opts[:output] << '-vn' # disable input video stream in case it exists
161
+ opts[:output] << '-codec:a' << @options[:codec] if @options[:codec]
162
+ opts[:output] << '-map_metadata:g' << '0:g' # Copy global metadata
163
+ opts[:output] << '-map_metadata:s:a' << '0:s:a' # Copy audio metadata
164
+ opts[:input] << '-accurate_seek' << (@options[:start].to_i < 0 ? '-sseof' : '-ss') << @options[:start] if @options[:start]
165
+ opts[:input] << '-t' << @options[:duration] if @options[:duration]
166
+ opts[:output] << '-q:a' << @options[:quality] if @options[:quality]
167
+ opts[:output] << '-b:a' << @options[:bit_rate] if @options[:bit_rate]
168
+ opts[:output] << '-ar' << @options[:sampling_freq] if @options[:sampling_freq]
169
+ opts[:output] << '-ac' << @options[:channels] if @options[:channels]
170
+ opts[:output] << '-f' << @options[:format] if @options[:format]
171
+ result = Libis::Format::FFMpeg.run(source, target, opts)
172
+ info "FFMpeg output: #{result}"
173
+ result
174
+ target
175
+ end
176
+
177
+ end
178
+
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,194 @@
1
+ require_relative 'base'
2
+ require 'libis/format/ffmpeg'
3
+
4
+ require 'fileutils'
5
+
6
+ module Libis
7
+ module Format
8
+ module Converter
9
+
10
+ class VideoConverter < Libis::Format::Converter::Base
11
+
12
+ def self.input_types
13
+ [:WEBM, :M4V, :MPEG, :MJP2, :QTFF, :AVI, :OGGV, :WMV, :DV, :FLASH]
14
+ end
15
+
16
+ def self.output_types(format = nil)
17
+ return [] unless input_types.include?(format)
18
+ [:GIF, :AVI, :FLV, :MKV, :MOV, :MP4, :MPG, :OGGV, :SWF, :WEBM, :WMV]
19
+ end
20
+
21
+ def initialize
22
+ super
23
+ end
24
+
25
+ def quiet(v)
26
+ @flags[:quiet] = !!v
27
+ end
28
+
29
+ def format(format)
30
+ @options[:format] = format
31
+ end
32
+
33
+ def audio_channels(value)
34
+ @options[:audio_channels] = value.to_s
35
+ end
36
+
37
+ def audio_codec(codec)
38
+ @options[:audio_codec] = codec
39
+ end
40
+
41
+ def video_codec(codec)
42
+ @options[:video_codec] = codec
43
+ end
44
+
45
+ def start(seconds)
46
+ @options[:start] = seconds.to_s
47
+ end
48
+
49
+ def duration(seconds)
50
+ @options[:duration] = seconds.to_s
51
+ end
52
+
53
+ def audio_quality(value)
54
+ @options[:audio_quality] = value.to_s
55
+ end
56
+
57
+ def video_quality(value)
58
+ @options[:video_quality] = value.to_s
59
+ end
60
+
61
+ def audio_bitrate(value)
62
+ @options[:audio_bitrate] = value.to_s
63
+ end
64
+
65
+ def video_bitrate(value)
66
+ @options[:video_bitrate] = value.to_s
67
+ end
68
+
69
+ def constant_rate_factor(value)
70
+ @options[:crf] = value.to_s
71
+ end
72
+
73
+ def frame_rate(value)
74
+ @options[:frame_rate] = value.to_s
75
+ end
76
+
77
+ def sampling_freq(value)
78
+ @options[:sampling_freq] = value.to_s
79
+ end
80
+
81
+ def scale(width_x_height)
82
+ @options[:scale] = width_x_height
83
+ end
84
+
85
+ def web_stream(value)
86
+ if value
87
+ @options[:video_codec] = 'h264'
88
+ @options[:audio_codec] = 'acc'
89
+ end
90
+ end
91
+
92
+ def preset(name)
93
+ @options[:preset] = name
94
+ end
95
+
96
+ def audio_preset(name)
97
+ @options[:audio_preset] = name
98
+ end
99
+
100
+ def video_preset(name)
101
+ @options[:video_preset] = name
102
+ end
103
+
104
+ # def video_encoder(value)
105
+ # @options[:video_encoder] = value
106
+ # end
107
+ #
108
+ # def audio_encoder(value)
109
+ # @options[:audio_encoder] = value
110
+ # end
111
+ #
112
+ # def encoder_options(value)
113
+ # @options[:encoder_options] = value
114
+ # end
115
+
116
+ def convert(source, target, _format, opts = {})
117
+ super
118
+
119
+ FileUtils.mkpath(File.dirname(target))
120
+
121
+ if source.is_a? Array
122
+
123
+ assemble_and_convert(source, target)
124
+
125
+ elsif File.directory?(source)
126
+
127
+ sources = Dir[File.join(source, '**', '*')].reject {|p| File.directory? p}
128
+ assemble_and_convert(sources, target)
129
+
130
+ else
131
+
132
+ convert_file(source, target)
133
+
134
+ end
135
+
136
+ target
137
+
138
+ end
139
+
140
+ def assemble_and_convert(sources, target)
141
+ Tempfile.create(%w(list .txt)) do |f|
142
+ sources.each {|src| f.puts src}
143
+ opts[:global] ||= []
144
+ opts[:global] += %w(-f concat)
145
+ f.close
146
+ target = convert_file(f.to_path, target)
147
+ end
148
+ target
149
+ end
150
+
151
+ protected
152
+
153
+ def convert_file(source, target)
154
+ # FLV special: only supports aac and speex audio codecs
155
+ format = (@options[:format] || File.extname(target)[1..-1]).to_s.downcase
156
+ @options[:audio_codec] ||= 'aac' if %w'flv'.include?(format)
157
+
158
+ # FLV special: only supports aac and speex audio codecs
159
+ format = (@options[:format] || File.extname(target)[1..-1]).to_s.downcase
160
+ @options[:audio_codec] ||= 'mp3' if %w'swf'.include?(format)
161
+
162
+ # Set up FFMpeg command line parameters
163
+ opts = {global: [], input: [], filter: [], output: []}
164
+ opts[:global] << '-hide_banner'
165
+ opts[:global] << '-loglevel' << (@options[:quiet] ? 'fatal' : 'warning')
166
+ opts[:output] << '-ac' << @options[:audio_channels] if @options[:audio_channels]
167
+ opts[:output] << '-c:a' << @options[:audio_codec] if @options[:audio_codec]
168
+ opts[:output] << '-c:v' << @options[:video_codec] if @options[:video_codec]
169
+ opts[:output] << '-b:a' << @options[:audio_bitrate] if @options[:audio_bitrate]
170
+ opts[:output] << '-b:v' << @options[:video_bitrate] if @options[:video_bitrate]
171
+ opts[:output] << '-crf' << @options[:crf] if @options[:crf]
172
+ opts[:output] << '-map_metadata:g' << '0:g' # Copy global metadata
173
+ opts[:output] << '-map_metadata:s:a' << '0:s:a' # Copy audio metadata
174
+ opts[:output] << '-map_metadata:s:v' << '0:s:v' # Copy video metadata
175
+ opts[:input] << '-accurate_seek' << (@options[:start].to_i < 0 ? '-sseof' : '-ss') << @options[:start] if @options[:start]
176
+ opts[:input] << '-t' << @options[:duration] if @options[:duration]
177
+ opts[:output] << '-qscale' << @options[:video_quality] if @options[:video_quality]
178
+ opts[:output] << '-q:a' << @options[:audio_quality] if @options[:audio_quality]
179
+ opts[:output] << '-r' << @options[:frame_rate] if @options[:frame_rate]
180
+ opts[:output] << '-ar' << @options[:sampling_freq] if @options[:sampling_freq]
181
+ opts[:output] << '-f' << @options[:format] if @options[:format]
182
+ opts[:output] << '-pre' << @options[:preset] if @options[:preset]
183
+ opts[:output] << '-apre' << @options[:audio_preset] if @options[:audio_preset]
184
+ opts[:output] << '-vpre' << @options[:video_preset] if @options[:video_preset]
185
+ result = Libis::Format::FFMpeg.run(source, target, opts)
186
+ info "FFMpeg output: #{result}"
187
+ target
188
+ end
189
+
190
+ end
191
+
192
+ end
193
+ end
194
+ end