libis-format 0.9.38 → 0.9.39

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.
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