abrizer 0.3.0 → 0.4.0
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Vagrantfile +6 -1
- data/ansible/development-playbook.yml +4 -1
- data/ansible/roles/apache/tasks/main.yml +9 -0
- data/ansible/roles/basic-setup/tasks/main.yml +3 -0
- data/ansible/roles/bento4/tasks/main.yml +4 -0
- data/ansible/roles/rvm-setup/tasks/main.yml +9 -0
- data/exe/abrizer +1 -1
- data/lib/abrizer/adaptation.rb +13 -3
- data/lib/abrizer/adaptations_file.rb +20 -0
- data/lib/abrizer/all.rb +6 -1
- data/lib/abrizer/canvas.rb +9 -79
- data/lib/abrizer/cli.rb +31 -4
- data/lib/abrizer/data.rb +163 -0
- data/lib/abrizer/debug_settings.rb +11 -0
- data/lib/abrizer/ffmpeg_processor.rb +4 -2
- data/lib/abrizer/ffprobe_file.rb +17 -0
- data/lib/abrizer/filepath_helpers.rb +32 -0
- data/lib/abrizer/identifier_helpers.rb +53 -0
- data/lib/abrizer/information_helpers.rb +34 -0
- data/lib/abrizer/package_dash_shaka.rb +1 -1
- data/lib/abrizer/package_hls_shaka.rb +1 -1
- data/lib/abrizer/progressive_mp3.rb +21 -0
- data/lib/abrizer/progressive_mp4.rb +3 -5
- data/lib/abrizer/progressive_vp9.rb +8 -8
- data/lib/abrizer/read_adaptations.rb +34 -0
- data/lib/abrizer/sprites.rb +31 -0
- data/lib/abrizer/temporary_poster.rb +2 -0
- data/lib/abrizer/version.rb +1 -1
- data/lib/abrizer.rb +9 -0
- metadata +12 -4
- data/ansible/development-playbook.retry +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 56c129ae5143fedefa8b41cd5c98ccf2a370bf72
|
4
|
+
data.tar.gz: 6162f79282a5576b77bdc9b74cf6c7ff0c74044b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a14b4b77761e7f0cd2de95264f2232856cb3da83c431be859b602567491762baeda3eae4855bfd66094be2f9dd5091cee548accaa08f9f800d504c89415bd439
|
7
|
+
data.tar.gz: 0c36ba67ab3d170df18fe87b748f6de4bf96e930fe97b6beef316bfd50ca0c14bdc10610e92900808faedcc7050dd3fbd92a0891fe46035542e21ad965ac3c12
|
data/.gitignore
CHANGED
data/Vagrantfile
CHANGED
@@ -4,7 +4,12 @@
|
|
4
4
|
Vagrant.configure("2") do |config|
|
5
5
|
config.vm.box = "boxcutter/centos72"
|
6
6
|
|
7
|
-
|
7
|
+
# Create a private network, which allows host-only access to the machine
|
8
|
+
# using a specific IP.
|
9
|
+
config.vm.network "private_network", ip: "192.168.33.40"
|
10
|
+
|
11
|
+
config.vm.synced_folder '.', '/vagrant', type: 'nfs', mount_options: ['nolock']
|
12
|
+
|
8
13
|
config.vm.network "forwarded_port", guest: 80, host: 8088,
|
9
14
|
auto_correct: true
|
10
15
|
|
@@ -7,14 +7,17 @@
|
|
7
7
|
gather_facts: yes
|
8
8
|
roles:
|
9
9
|
- role: basic-setup
|
10
|
-
- role: apache
|
11
10
|
- role: franklinkim.environment
|
12
11
|
environment_config:
|
13
12
|
PATH: /usr/local/bento4/bin:/usr/bin:/usr/local/bin
|
13
|
+
- role: apache
|
14
14
|
- role: ffmpeg
|
15
15
|
build_dir: /root/ffmpeg_build
|
16
16
|
source_dir: /root/ffmpeg_sources
|
17
17
|
- role: rvm_io.rvm1-ruby
|
18
18
|
rvm1_rubies:
|
19
19
|
- 2.3.3
|
20
|
+
- role: rvm-setup
|
21
|
+
users:
|
22
|
+
- vagrant
|
20
23
|
- role: bento4
|
@@ -9,6 +9,11 @@
|
|
9
9
|
line: 'Header set Access-Control-Allow-Origin "*"'
|
10
10
|
# regexp: '<Directory "/var/www/html">'
|
11
11
|
insertafter: '<Directory "/var/www/html">'
|
12
|
+
- name: enable range requests
|
13
|
+
lineinfile:
|
14
|
+
dest: /etc/httpd/conf/httpd.conf
|
15
|
+
line: 'Header set Access-Control-Allow-Headers Range'
|
16
|
+
insertafter: 'Header set Access-Control-Allow-Origin "*"'
|
12
17
|
- name: remove firewall
|
13
18
|
yum:
|
14
19
|
name: firewalld
|
@@ -21,3 +26,7 @@
|
|
21
26
|
force: yes
|
22
27
|
- name: restart httpd
|
23
28
|
service: name=httpd state=restarted
|
29
|
+
- name: enable httpd
|
30
|
+
service:
|
31
|
+
name: httpd
|
32
|
+
enabled: yes
|
@@ -0,0 +1,9 @@
|
|
1
|
+
---
|
2
|
+
- name: add users to rvm group
|
3
|
+
command: /bin/bash -lc 'rvm group add rvm {{item}}'
|
4
|
+
with_items: "{{users}}"
|
5
|
+
- name: auto-dotfiles
|
6
|
+
command: /bin/bash -lc 'rvm get stable --auto-dotfiles'
|
7
|
+
- name: rvm fix-permissions system
|
8
|
+
command: /bin/bash -lc 'rvm fix-permissions :rvm'
|
9
|
+
# - TODO: name: fix bundler permissions
|
data/exe/abrizer
CHANGED
data/lib/abrizer/adaptation.rb
CHANGED
@@ -2,6 +2,7 @@ module Abrizer
|
|
2
2
|
class Adaptation
|
3
3
|
|
4
4
|
include FilepathHelpers
|
5
|
+
include DebugSettings
|
5
6
|
|
6
7
|
attr_reader :width, :height, :bitrate
|
7
8
|
|
@@ -12,10 +13,11 @@ module Abrizer
|
|
12
13
|
end
|
13
14
|
|
14
15
|
def ffmpeg_cmd(input, output_directory, pass)
|
15
|
-
cmd = %Q|ffmpeg -y
|
16
|
-
|
16
|
+
cmd = %Q|ffmpeg -y #{debug_settings} \
|
17
|
+
-i #{input} -vf \
|
18
|
+
yadif,scale='#{width}:trunc(#{width}/dar/2)*2',setsar=1 \
|
17
19
|
-an -c:v libx264 -x264opts 'keyint=48:min-keyint=48:no-scenecut' \
|
18
|
-
-b:v #{bitrate}k -preset faster |
|
20
|
+
-b:v #{bitrate}k -preset faster -pix_fmt yuv420p |
|
19
21
|
if pass == 2
|
20
22
|
cmd += %Q| -maxrate #{constrained_bitrate}k -bufsize #{bitrate}k -pass 2 #{filepath(input, output_directory)} |
|
21
23
|
else
|
@@ -49,5 +51,13 @@ module Abrizer
|
|
49
51
|
"Width: #{@width}, Height: #{@height}, Bitrate: #{@bitrate}"
|
50
52
|
end
|
51
53
|
|
54
|
+
def to_json
|
55
|
+
MultiJson.dump(to_hash)
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_hash
|
59
|
+
{width: @width, height: @height, bitrate: @bitrate}
|
60
|
+
end
|
61
|
+
|
52
62
|
end
|
53
63
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Abrizer
|
2
|
+
class AdaptationsFile
|
3
|
+
|
4
|
+
include FilepathHelpers
|
5
|
+
|
6
|
+
def initialize(filepath, output_directory)
|
7
|
+
@filepath = filepath
|
8
|
+
@output_directory = output_directory
|
9
|
+
end
|
10
|
+
|
11
|
+
def adaptations
|
12
|
+
adapt = Abrizer::AdaptationFinder.new(@filepath).adaptations
|
13
|
+
adapt_dump = adapt.map{|a| a.to_hash}
|
14
|
+
File.open(adaptations_filepath, 'w') do |fh|
|
15
|
+
fh.puts MultiJson.dump(adapt_dump)
|
16
|
+
end
|
17
|
+
adapt
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/abrizer/all.rb
CHANGED
@@ -4,19 +4,24 @@ module Abrizer
|
|
4
4
|
def initialize(filename, output_dir, base_url)
|
5
5
|
@filename = filename
|
6
6
|
@output_directory = output_dir
|
7
|
+
FileUtils.mkdir_p @output_directory
|
7
8
|
@base_url = base_url
|
8
9
|
end
|
9
10
|
|
10
11
|
def run
|
12
|
+
Abrizer::FfprobeFile.new(@filename, @output_directory).run
|
13
|
+
Abrizer::AdaptationsFile.new(@filename, @output_directory).adaptations
|
11
14
|
Abrizer::Processor.process(@filename, @output_directory)
|
12
15
|
Abrizer::ProgressiveMp4.new(@filename, @output_directory).create
|
13
|
-
Abrizer::ProgressiveVp9.new(@filename, @output_directory).create
|
16
|
+
# Abrizer::ProgressiveVp9.new(@filename, @output_directory).create
|
17
|
+
Abrizer::ProgressiveMp3.new(@filename, @output_directory).create
|
14
18
|
Abrizer::PackageDashBento.new(@filename, @output_directory).package
|
15
19
|
Abrizer::PackageHlsBento.new(@filename, @output_directory).package
|
16
20
|
Abrizer::Captions.new(@filename, @output_directory).copy
|
17
21
|
Abrizer::Sprites.new(@filename, @output_directory).create
|
18
22
|
Abrizer::TemporaryPoster.new(@output_directory).copy
|
19
23
|
Abrizer::Canvas.new(@filename, @output_directory, @base_url).create
|
24
|
+
Abrizer::Data.new(@filename, @output_directory, @base_url).create
|
20
25
|
Abrizer::Cleaner.new(@filename, @output_directory).clean
|
21
26
|
end
|
22
27
|
|
data/lib/abrizer/canvas.rb
CHANGED
@@ -3,17 +3,22 @@ module Abrizer
|
|
3
3
|
class Canvas
|
4
4
|
|
5
5
|
include FilepathHelpers
|
6
|
+
include IdentifierHelpers
|
7
|
+
include InformationHelpers
|
8
|
+
include ReadAdaptations
|
6
9
|
|
7
10
|
# TODO: allow control of items/versions listed on canvas
|
8
11
|
def initialize(filepath, output_directory, base_url)
|
9
|
-
@
|
12
|
+
@filepath = filepath
|
10
13
|
@output_directory = output_directory
|
11
14
|
@base_url = base_url
|
12
|
-
finder = AdaptationFinder.new(@filename)
|
13
|
-
@adaptations = finder.adaptations
|
15
|
+
# finder = AdaptationFinder.new(@filename)
|
16
|
+
# @adaptations = finder.adaptations
|
17
|
+
read_adaptations
|
14
18
|
end
|
15
19
|
|
16
20
|
def create
|
21
|
+
FileUtils.mkdir_p output_directory unless File.exist? output_directory
|
17
22
|
File.open(canvas_filepath, 'w') do |fh|
|
18
23
|
fh.puts create_json
|
19
24
|
end
|
@@ -143,8 +148,7 @@ module Abrizer
|
|
143
148
|
|
144
149
|
def captions_item(json)
|
145
150
|
# TODO: update captions for multiple captions
|
146
|
-
|
147
|
-
if File.exist? captions_file
|
151
|
+
if File.exist? captions_filepath
|
148
152
|
json.child! do
|
149
153
|
json.id vtt_id
|
150
154
|
json.type 'Text'
|
@@ -178,79 +182,5 @@ module Abrizer
|
|
178
182
|
end
|
179
183
|
end
|
180
184
|
|
181
|
-
def media_base_url
|
182
|
-
File.join @base_url, output_directory_basename
|
183
|
-
end
|
184
|
-
|
185
|
-
def canvas_id
|
186
|
-
File.join media_base_url, canvas_partial_filepath
|
187
|
-
end
|
188
|
-
|
189
|
-
def poster_id
|
190
|
-
File.join media_base_url, poster_partial_filepath
|
191
|
-
end
|
192
|
-
|
193
|
-
def mpd_id
|
194
|
-
File.join media_base_url, mpd_partial_filepath
|
195
|
-
end
|
196
|
-
|
197
|
-
def hlsts_id
|
198
|
-
File.join media_base_url, hlsts_partial_filepath
|
199
|
-
end
|
200
|
-
|
201
|
-
def hlsts_aac_id
|
202
|
-
File.join media_base_url, hlsts_aac_partial_filepath
|
203
|
-
end
|
204
|
-
|
205
|
-
def mp4_id
|
206
|
-
File.join media_base_url, mp4_partial_filepath
|
207
|
-
end
|
208
|
-
|
209
|
-
def vp9_id
|
210
|
-
File.join media_base_url, vp9_partial_filepath
|
211
|
-
end
|
212
|
-
|
213
|
-
def vtt_id
|
214
|
-
File.join media_base_url, 'vtt/captions.vtt'
|
215
|
-
end
|
216
|
-
|
217
|
-
def sprites_id
|
218
|
-
File.join media_base_url, sprites_partial_filepath
|
219
|
-
end
|
220
|
-
|
221
|
-
def duration
|
222
|
-
informer = Abrizer::FfprobeInformer.new(mp4_filename)
|
223
|
-
informer.duration.to_f
|
224
|
-
end
|
225
|
-
|
226
|
-
def max_width
|
227
|
-
@adaptations.last.width
|
228
|
-
end
|
229
|
-
|
230
|
-
def min_width
|
231
|
-
@adaptations.first.width
|
232
|
-
end
|
233
|
-
|
234
|
-
def max_height
|
235
|
-
@adaptations.last.height
|
236
|
-
end
|
237
|
-
|
238
|
-
def min_height
|
239
|
-
@adaptations.first.height
|
240
|
-
end
|
241
|
-
|
242
|
-
def mp4_width
|
243
|
-
@adaptations[-2].width
|
244
|
-
end
|
245
|
-
|
246
|
-
def mp4_height
|
247
|
-
@adaptations[-2].height
|
248
|
-
end
|
249
|
-
|
250
|
-
# TODO: DRY up with progressive_mp4.rb
|
251
|
-
def mp4_filename
|
252
|
-
File.join output_directory, "progressive.mp4"
|
253
|
-
end
|
254
|
-
|
255
185
|
end
|
256
186
|
end
|
data/lib/abrizer/cli.rb
CHANGED
@@ -1,4 +1,9 @@
|
|
1
1
|
require 'thor'
|
2
|
+
|
3
|
+
if ENV['DEBUG_ABRIZER']
|
4
|
+
require 'byebug'
|
5
|
+
end
|
6
|
+
|
2
7
|
module Abrizer
|
3
8
|
class CLI < Thor
|
4
9
|
|
@@ -9,6 +14,13 @@ module Abrizer
|
|
9
14
|
Abrizer::All.new(filepath, output_dir, base_url).run
|
10
15
|
end
|
11
16
|
|
17
|
+
desc 'ffprobe <filepath> <output_directory>', 'Save the output of ffprobe to a file as JSON'
|
18
|
+
def ffprobe(filepath, output_dir)
|
19
|
+
filepath = File.expand_path filepath
|
20
|
+
output_dir = File.expand_path output_dir
|
21
|
+
Abrizer::FfprobeFile.new(filepath, output_dir).run
|
22
|
+
end
|
23
|
+
|
12
24
|
desc 'abr <filepath> <output_directory>', 'From file create ABR streams, includes processing MP4 adaptations for packaging'
|
13
25
|
def abr(filepath, output_dir=nil)
|
14
26
|
filepath = File.expand_path filepath
|
@@ -39,9 +51,9 @@ module Abrizer
|
|
39
51
|
Abrizer::ProgressiveVp9.new(filepath, output_dir).create
|
40
52
|
end
|
41
53
|
|
42
|
-
desc 'adaptations <filepath>', '
|
43
|
-
def adaptations(filepath)
|
44
|
-
adaptations = Abrizer::
|
54
|
+
desc 'adaptations <filepath> <output_directory>', 'Output which adaptations will be created from input file to a JSON file and output to console'
|
55
|
+
def adaptations(filepath, output_directory=nil)
|
56
|
+
adaptations = Abrizer::AdaptationsFile.new(filepath, output_directory).adaptations
|
45
57
|
puts adaptations
|
46
58
|
end
|
47
59
|
|
@@ -69,6 +81,15 @@ module Abrizer
|
|
69
81
|
end
|
70
82
|
end
|
71
83
|
|
84
|
+
desc 'mp3 <filepath> <output_directory>', 'Create a progressive MP3 file from the audio of the original media'
|
85
|
+
def mp3(filepath, output_directory)
|
86
|
+
# TODO: repeating expanding filepath and output_directory is probably the
|
87
|
+
# most annoying thing in this library. DRY this up somehow.
|
88
|
+
filepath = File.expand_path filepath
|
89
|
+
output_dir = File.expand_path output_directory
|
90
|
+
Abrizer::ProgressiveMp3.new(filepath, output_dir).create
|
91
|
+
end
|
92
|
+
|
72
93
|
desc 'sprites <filepath> <output_directory>', 'Create image sprites and metadata WebVTT file'
|
73
94
|
def sprites(filepath, output_dir=nil)
|
74
95
|
filepath = File.expand_path filepath
|
@@ -89,13 +110,19 @@ module Abrizer
|
|
89
110
|
Abrizer::Captions.new(filepath, output_dir).copy
|
90
111
|
end
|
91
112
|
|
92
|
-
desc 'canvas <
|
113
|
+
desc 'canvas <filepath_or_identifier> <output_directory> <base_url>', 'Creates a IIIF Canvas JSON-LD document as an API into the resources'
|
93
114
|
def canvas(filepath, output_directory, base_url)
|
94
115
|
filepath = File.expand_path filepath
|
95
116
|
output_directory = File.expand_path output_directory
|
96
117
|
Abrizer::Canvas.new(filepath, output_directory, base_url).create
|
97
118
|
end
|
98
119
|
|
120
|
+
desc 'data <filepath_or_identifier> <output_directory> <base_url>', 'Creates a JSON file with data about the video resources.'
|
121
|
+
def data(filepath, output_directory, base_url)
|
122
|
+
output_directory = File.expand_path output_directory
|
123
|
+
Abrizer::Data.new(filepath, output_directory, base_url).create
|
124
|
+
end
|
125
|
+
|
99
126
|
desc 'clean <filepath> <output_directory>', 'Clean up intermediary files'
|
100
127
|
def clean(filepath, output_dir=nil)
|
101
128
|
Abrizer::Cleaner.new(filepath, output_dir).clean
|
data/lib/abrizer/data.rb
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
module Abrizer
|
2
|
+
# Creates a JSON file with information about the videos
|
3
|
+
class Data
|
4
|
+
|
5
|
+
include FilepathHelpers
|
6
|
+
include IdentifierHelpers
|
7
|
+
include InformationHelpers
|
8
|
+
include ReadAdaptations
|
9
|
+
|
10
|
+
def initialize(filepath, output_directory, base_url)
|
11
|
+
@filepath = filepath
|
12
|
+
# This is kind of hacky, but if the @output_directory is set then we can
|
13
|
+
# use that to look up the vp9_filepath
|
14
|
+
@output_directory = output_directory
|
15
|
+
@base_url = base_url
|
16
|
+
|
17
|
+
# This sets @filename in some cases and more importantly sets @adaptations
|
18
|
+
# based on the filepath or identifier that's passed in.
|
19
|
+
read_adaptations
|
20
|
+
end
|
21
|
+
|
22
|
+
def find_adaptations
|
23
|
+
finder = AdaptationFinder.new(@filename)
|
24
|
+
@adaptations = finder.adaptations
|
25
|
+
end
|
26
|
+
|
27
|
+
def create
|
28
|
+
FileUtils.mkdir_p output_directory unless File.exist? output_directory
|
29
|
+
File.open(data_filepath, 'w') do |fh|
|
30
|
+
fh.puts create_json
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_json
|
35
|
+
Jbuilder.encode do |json|
|
36
|
+
json.id data_id
|
37
|
+
json.max_width max_width
|
38
|
+
json.max_height max_height
|
39
|
+
json.duration duration
|
40
|
+
json.poster do
|
41
|
+
poster(json)
|
42
|
+
end
|
43
|
+
json.video do
|
44
|
+
mpd_source(json)
|
45
|
+
hlsts_source(json)
|
46
|
+
vp9_source(json)
|
47
|
+
mp4_source(json)
|
48
|
+
end
|
49
|
+
json.audio do
|
50
|
+
mp3_source(json)
|
51
|
+
aac_source(json)
|
52
|
+
end
|
53
|
+
json.tracks do
|
54
|
+
captions(json)
|
55
|
+
end
|
56
|
+
json.sprites do
|
57
|
+
sprites(json)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def poster(json)
|
63
|
+
if File.exist? poster_filepath
|
64
|
+
json.child! do
|
65
|
+
json.id poster_id
|
66
|
+
json.format "image/jpg"
|
67
|
+
json.width max_width
|
68
|
+
json.height max_height
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def mpd_source(json)
|
74
|
+
if File.exist? mpd_filepath
|
75
|
+
json.child! do
|
76
|
+
json.id mpd_id
|
77
|
+
json.format "application/dash+xml"
|
78
|
+
json.width max_width
|
79
|
+
json.height max_height
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def hlsts_source(json)
|
85
|
+
if File.exist? hlsts_filepath
|
86
|
+
json.child! do
|
87
|
+
json.id hlsts_id
|
88
|
+
json.type "Video"
|
89
|
+
# TODO: or "vnd.apple.mpegURL"
|
90
|
+
json.format "application/x-mpegURL"
|
91
|
+
json.width max_width
|
92
|
+
json.height max_height
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def vp9_source(json)
|
98
|
+
if File.exist? vp9_filepath
|
99
|
+
json.child! do
|
100
|
+
json.id vp9_id
|
101
|
+
json.type "Video"
|
102
|
+
#TODO: add webm codecs
|
103
|
+
json.format "video/webm"
|
104
|
+
json.width max_width
|
105
|
+
json.height max_height
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def mp4_source(json)
|
111
|
+
if File.exist? mp4_filepath
|
112
|
+
json.child! do
|
113
|
+
json.id mp4_id
|
114
|
+
json.type "Video"
|
115
|
+
#TODO: add mp4 codecs
|
116
|
+
json.format "video/mp4"
|
117
|
+
json.width mp4_width
|
118
|
+
json.height mp4_height
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def mp3_source(json)
|
124
|
+
if File.exist? mp3_filepath
|
125
|
+
json.child! do
|
126
|
+
json.id mp3_id
|
127
|
+
json.format 'audio/mpeg'
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def aac_source(json)
|
133
|
+
if File.exist? hlsts_aac_filepath
|
134
|
+
json.child! do
|
135
|
+
json.id hlsts_aac_id
|
136
|
+
json.format 'audio/aac'
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def captions(json)
|
142
|
+
if File.exist? captions_filepath
|
143
|
+
json.child! do
|
144
|
+
json.id vtt_id
|
145
|
+
json.format 'text/vtt'
|
146
|
+
json.kind 'captions'
|
147
|
+
json.label 'English captions'
|
148
|
+
json.language 'en'
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def sprites(json)
|
154
|
+
if File.exist? sprites_filepath
|
155
|
+
json.id sprites_id
|
156
|
+
json.format 'text/vtt'
|
157
|
+
json.kind 'metadata'
|
158
|
+
json.label 'image sprite metadata'
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Abrizer
|
2
|
+
module DebugSettings
|
3
|
+
|
4
|
+
# This is useful for testing an encoding setting on just part of a video.
|
5
|
+
# This gets applied before the input video is set.
|
6
|
+
def debug_settings
|
7
|
+
ENV['ABRIZER_DEBUG_SETTINGS'] || ''
|
8
|
+
# "-ss 10 -t 10"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -1,7 +1,9 @@
|
|
1
1
|
module Abrizer
|
2
|
+
# Creates the fMP4 files that are then packaged
|
2
3
|
class FfmpegProcessor
|
3
4
|
|
4
5
|
include FilepathHelpers
|
6
|
+
include DebugSettings
|
5
7
|
|
6
8
|
def initialize(filename, output_dir=nil)
|
7
9
|
@filename = filename
|
@@ -18,7 +20,7 @@ module Abrizer
|
|
18
20
|
end
|
19
21
|
|
20
22
|
def make_directory
|
21
|
-
FileUtils.
|
23
|
+
FileUtils.mkdir_p output_directory unless File.exist? output_directory
|
22
24
|
end
|
23
25
|
|
24
26
|
def first_pass_adaptation
|
@@ -50,7 +52,7 @@ module Abrizer
|
|
50
52
|
end
|
51
53
|
|
52
54
|
def process_audio
|
53
|
-
`ffmpeg -y -i #{@filename} -c:a libfdk_aac -b:a 128k -vn #{audio_filepath}`
|
55
|
+
`ffmpeg -y #{debug_settings} -i #{@filename} -c:a libfdk_aac -b:a 128k -vn #{audio_filepath}`
|
54
56
|
`mp4fragment #{audio_filepath} #{audio_filepath_fragmented}`
|
55
57
|
FileUtils.rm audio_filepath
|
56
58
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Abrizer
|
2
|
+
class FfprobeFile
|
3
|
+
|
4
|
+
include FilepathHelpers
|
5
|
+
|
6
|
+
def initialize(filename, output_directory)
|
7
|
+
@informer = FfprobeInformer.new(filename)
|
8
|
+
@output_directory = output_directory
|
9
|
+
end
|
10
|
+
|
11
|
+
def run
|
12
|
+
File.open(ffprobe_filepath, 'w') do |fh|
|
13
|
+
fh.puts @informer.json_result
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -34,10 +34,22 @@ module Abrizer
|
|
34
34
|
File.basename @filename, extname
|
35
35
|
end
|
36
36
|
|
37
|
+
def ffprobe_filepath
|
38
|
+
File.join output_directory, 'ffprobe.json'
|
39
|
+
end
|
40
|
+
|
41
|
+
def adaptations_filepath
|
42
|
+
File.join output_directory, 'adaptations.json'
|
43
|
+
end
|
44
|
+
|
37
45
|
def poster_partial_filepath
|
38
46
|
'poster.jpg'
|
39
47
|
end
|
40
48
|
|
49
|
+
def poster_filepath
|
50
|
+
File.join output_directory, poster_partial_filepath
|
51
|
+
end
|
52
|
+
|
41
53
|
def mpd_partial_filepath
|
42
54
|
'fmp4/stream.mpd'
|
43
55
|
end
|
@@ -78,6 +90,18 @@ module Abrizer
|
|
78
90
|
File.join output_directory, vp9_partial_filepath
|
79
91
|
end
|
80
92
|
|
93
|
+
def mp3_partial_filepath
|
94
|
+
'progressive.mp3'
|
95
|
+
end
|
96
|
+
|
97
|
+
def mp3_filepath
|
98
|
+
File.join output_directory, mp3_partial_filepath
|
99
|
+
end
|
100
|
+
|
101
|
+
def captions_filepath
|
102
|
+
File.join output_directory, 'vtt/captions.vtt'
|
103
|
+
end
|
104
|
+
|
81
105
|
def canvas_partial_filepath
|
82
106
|
'canvas.json'
|
83
107
|
end
|
@@ -86,6 +110,14 @@ module Abrizer
|
|
86
110
|
File.join output_directory, canvas_partial_filepath
|
87
111
|
end
|
88
112
|
|
113
|
+
def data_partial_filepath
|
114
|
+
'data.json'
|
115
|
+
end
|
116
|
+
|
117
|
+
def data_filepath
|
118
|
+
File.join output_directory, data_partial_filepath
|
119
|
+
end
|
120
|
+
|
89
121
|
def sprites_partial_filepath
|
90
122
|
'sprites/sprites.vtt'
|
91
123
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Abrizer
|
2
|
+
module IdentifierHelpers
|
3
|
+
|
4
|
+
def media_base_url
|
5
|
+
File.join @base_url, output_directory_basename
|
6
|
+
end
|
7
|
+
|
8
|
+
def canvas_id
|
9
|
+
File.join media_base_url, canvas_partial_filepath
|
10
|
+
end
|
11
|
+
|
12
|
+
def data_id
|
13
|
+
File.join media_base_url, data_partial_filepath
|
14
|
+
end
|
15
|
+
|
16
|
+
def poster_id
|
17
|
+
File.join media_base_url, poster_partial_filepath
|
18
|
+
end
|
19
|
+
|
20
|
+
def mpd_id
|
21
|
+
File.join media_base_url, mpd_partial_filepath
|
22
|
+
end
|
23
|
+
|
24
|
+
def hlsts_id
|
25
|
+
File.join media_base_url, hlsts_partial_filepath
|
26
|
+
end
|
27
|
+
|
28
|
+
def hlsts_aac_id
|
29
|
+
File.join media_base_url, hlsts_aac_partial_filepath
|
30
|
+
end
|
31
|
+
|
32
|
+
def mp4_id
|
33
|
+
File.join media_base_url, mp4_partial_filepath
|
34
|
+
end
|
35
|
+
|
36
|
+
def vp9_id
|
37
|
+
File.join media_base_url, vp9_partial_filepath
|
38
|
+
end
|
39
|
+
|
40
|
+
def mp3_id
|
41
|
+
File.join media_base_url, mp3_partial_filepath
|
42
|
+
end
|
43
|
+
|
44
|
+
def vtt_id
|
45
|
+
File.join media_base_url, 'vtt/captions.vtt'
|
46
|
+
end
|
47
|
+
|
48
|
+
def sprites_id
|
49
|
+
File.join media_base_url, sprites_partial_filepath
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Abrizer
|
2
|
+
module InformationHelpers
|
3
|
+
|
4
|
+
def duration
|
5
|
+
informer = Abrizer::FfprobeInformer.new(mp4_filepath)
|
6
|
+
informer.duration.to_f
|
7
|
+
end
|
8
|
+
|
9
|
+
def max_width
|
10
|
+
@adaptations.last.width
|
11
|
+
end
|
12
|
+
|
13
|
+
def min_width
|
14
|
+
@adaptations.first.width
|
15
|
+
end
|
16
|
+
|
17
|
+
def max_height
|
18
|
+
@adaptations.last.height
|
19
|
+
end
|
20
|
+
|
21
|
+
def min_height
|
22
|
+
@adaptations.first.height
|
23
|
+
end
|
24
|
+
|
25
|
+
def mp4_width
|
26
|
+
@adaptations[-2].width
|
27
|
+
end
|
28
|
+
|
29
|
+
def mp4_height
|
30
|
+
@adaptations[-2].height
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Abrizer
|
2
|
+
class ProgressiveMp3
|
3
|
+
|
4
|
+
include FilepathHelpers
|
5
|
+
include DebugSettings
|
6
|
+
|
7
|
+
def initialize(filepath, output_directory)
|
8
|
+
@filepath = filepath
|
9
|
+
@output_directory = output_directory
|
10
|
+
end
|
11
|
+
|
12
|
+
def create
|
13
|
+
`#{ffmpeg_cmd}`
|
14
|
+
end
|
15
|
+
|
16
|
+
def ffmpeg_cmd
|
17
|
+
"ffmpeg -y #{debug_settings} -i #{@filepath} -vn -c:a libmp3lame -b:a 128k #{mp3_filepath}"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -26,11 +26,9 @@ module Abrizer
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def ffmpeg_cmd
|
29
|
-
"ffmpeg -y -i #{input_video_filepath} -i #{audio_filepath_fragmented} -c:v copy -c:a copy #{
|
30
|
-
|
31
|
-
|
32
|
-
def static_filepath
|
33
|
-
File.join output_directory, "progressive.mp4"
|
29
|
+
"ffmpeg -y -i #{input_video_filepath} -i #{audio_filepath_fragmented} -c:v copy -c:a copy #{mp4_filepath} -movflags faststart"
|
30
|
+
# Previously used command:
|
31
|
+
# "ffmpeg -y -i #{@filename} -profile:v high -pix_fmt yuv420p -movflags faststart -b:v #{@adaptation.bitrate}k #{mp4_filepath}"
|
34
32
|
end
|
35
33
|
|
36
34
|
end
|
@@ -2,6 +2,7 @@ module Abrizer
|
|
2
2
|
class ProgressiveVp9
|
3
3
|
|
4
4
|
include FilepathHelpers
|
5
|
+
include DebugSettings
|
5
6
|
|
6
7
|
def initialize(filename, output_dir=nil)
|
7
8
|
@filename = filename
|
@@ -17,7 +18,7 @@ module Abrizer
|
|
17
18
|
end
|
18
19
|
|
19
20
|
def make_directory
|
20
|
-
FileUtils.
|
21
|
+
FileUtils.mkdir_p @output_directory unless File.exist? @output_directory
|
21
22
|
end
|
22
23
|
|
23
24
|
def find_adaptation
|
@@ -35,23 +36,22 @@ module Abrizer
|
|
35
36
|
end
|
36
37
|
|
37
38
|
def ffmpeg_cmd_pass1
|
38
|
-
"ffmpeg -y -i #{@filename} -c:v libvpx-vp9 -b:v #{bitrate}k -c:a libvorbis \
|
39
|
-
-vf scale='#{@adaptation.width}:trunc(#{@adaptation.width}/dar/2)*2',setsar=1 \
|
40
|
-
-speed 4 -tile-columns 6 -frame-parallel 1 \
|
39
|
+
"ffmpeg -y #{debug_settings} -i #{@filename} -c:v libvpx-vp9 -crf 10 -b:v #{bitrate*1.1}k -c:a libvorbis \
|
40
|
+
-vf yadif,scale='#{@adaptation.width}:trunc(#{@adaptation.width}/dar/2)*2',setsar=1 \
|
41
|
+
-speed 4 -tile-columns 6 -frame-parallel 1 -pix_fmt yuv420p \
|
41
42
|
-pass 1 -passlogfile ffmpeg2pass-webm -f webm /dev/null"
|
42
43
|
end
|
43
44
|
|
44
45
|
def ffmpeg_cmd_pass2
|
45
|
-
"ffmpeg -y -i #{@filename} -c:v libvpx-vp9 -b:v #{bitrate}k -c:a libvorbis \
|
46
|
-
-vf scale='#{@adaptation.width}:trunc(#{@adaptation.width}/dar/2)*2',setsar=1 \
|
46
|
+
"ffmpeg -y #{debug_settings} -i #{@filename} -c:v libvpx-vp9 -crf 10 -b:v #{bitrate*1.1}k -c:a libvorbis \
|
47
|
+
-vf yadif,scale='#{@adaptation.width}:trunc(#{@adaptation.width}/dar/2)*2',setsar=1 \
|
47
48
|
-speed 1 -tile-columns 6 -frame-parallel 1 -auto-alt-ref 1 -lag-in-frames 25 \
|
48
|
-
-pass 2 -passlogfile ffmpeg2pass-webm -
|
49
|
+
-pass 2 -passlogfile ffmpeg2pass-webm -pix_fmt yuv420p #{static_filepath}"
|
49
50
|
end
|
50
51
|
|
51
52
|
def static_filepath
|
52
53
|
File.join output_directory, "progressive-vp9.webm"
|
53
54
|
end
|
54
55
|
|
55
|
-
|
56
56
|
end
|
57
57
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Abrizer
|
2
|
+
module ReadAdaptations
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
def read_adaptations
|
7
|
+
# Either we have a filepath to an original or we make the assumption we
|
8
|
+
# really have an identifier instead of a filepath and we use that
|
9
|
+
# identifier to look for an adaptations.json file. Failing finding the
|
10
|
+
# adaptations.json file we just use the adaptations based on the
|
11
|
+
# vp9_filepath.
|
12
|
+
if File.exist?(File.expand_path(@filepath)) && !File.directory?(@filepath)
|
13
|
+
@filename = @filepath
|
14
|
+
find_adaptations
|
15
|
+
elsif File.exist? adaptations_filepath
|
16
|
+
# assume we have an identifier and look up for the adaptations file
|
17
|
+
adaptations_json = File.read adaptations_filepath
|
18
|
+
adaptations = MultiJson.load adaptations_json
|
19
|
+
# TODO: There ought to be a class that recreates an Adaptation instance
|
20
|
+
# based on the adaptations.json file. For now we fake it with a
|
21
|
+
# OpenStruct.
|
22
|
+
@adaptations = adaptations.map do |a|
|
23
|
+
OpenStruct.new(a)
|
24
|
+
end
|
25
|
+
elsif File.exist? vp9_filepath
|
26
|
+
# assume we just got an identifier and look for the webm
|
27
|
+
@filename = vp9_filepath
|
28
|
+
find_adaptations
|
29
|
+
else
|
30
|
+
raise "Neither original file or VP9 version exist."
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/abrizer/sprites.rb
CHANGED
@@ -18,6 +18,37 @@ module Abrizer
|
|
18
18
|
def create
|
19
19
|
processor = VideoSprites::Processor.new(@filename, @output_directory, @options)
|
20
20
|
processor.process
|
21
|
+
FileUtils.chmod_R "go+r", @output_directory
|
22
|
+
optimize_images
|
23
|
+
end
|
24
|
+
|
25
|
+
def optimize_images
|
26
|
+
optimize_sprites
|
27
|
+
optimize_individual_images
|
28
|
+
end
|
29
|
+
|
30
|
+
def optimize_sprites
|
31
|
+
`jpegoptim #{sprite_paths.join(' ')}`
|
32
|
+
end
|
33
|
+
|
34
|
+
def sprite_paths
|
35
|
+
Dir.glob(sprites_glob)
|
36
|
+
end
|
37
|
+
|
38
|
+
def sprites_glob
|
39
|
+
File.join @output_directory, "*.jpg"
|
40
|
+
end
|
41
|
+
|
42
|
+
def optimize_individual_images
|
43
|
+
`jpegoptim #{individual_image_paths.join(' ')}`
|
44
|
+
end
|
45
|
+
|
46
|
+
def individual_image_paths
|
47
|
+
Dir.glob(individual_image_glob)
|
48
|
+
end
|
49
|
+
|
50
|
+
def individual_image_glob
|
51
|
+
File.join @output_directory, "images/*.jpg"
|
21
52
|
end
|
22
53
|
|
23
54
|
end
|
data/lib/abrizer/version.rb
CHANGED
data/lib/abrizer.rb
CHANGED
@@ -4,23 +4,32 @@ MultiJson.use :yajl
|
|
4
4
|
MultiJson.dump_options = {pretty: true}
|
5
5
|
require 'jbuilder'
|
6
6
|
require 'video_sprites'
|
7
|
+
require 'ostruct'
|
7
8
|
require "abrizer/version"
|
8
9
|
require 'abrizer/filepath_helpers'
|
10
|
+
require 'abrizer/read_adaptations'
|
11
|
+
require 'abrizer/debug_settings'
|
12
|
+
require 'abrizer/identifier_helpers'
|
13
|
+
require 'abrizer/information_helpers'
|
9
14
|
require 'abrizer/package_dash_shaka'
|
10
15
|
require 'abrizer/package_hls_shaka'
|
11
16
|
require 'abrizer/package_dash_bento'
|
12
17
|
require 'abrizer/package_hls_bento'
|
13
18
|
require 'abrizer/adaptation'
|
14
19
|
require 'abrizer/adaptation_finder'
|
20
|
+
require 'abrizer/adaptations_file'
|
15
21
|
require 'abrizer/ffmpeg_processor'
|
16
22
|
require 'abrizer/ffprobe_informer'
|
23
|
+
require 'abrizer/ffprobe_file'
|
17
24
|
require 'abrizer/processor'
|
18
25
|
require 'abrizer/cleaner'
|
19
26
|
require 'abrizer/progressive_mp4'
|
20
27
|
require 'abrizer/progressive_vp9'
|
28
|
+
require 'abrizer/progressive_mp3'
|
21
29
|
require 'abrizer/sprites'
|
22
30
|
require 'abrizer/captions'
|
23
31
|
require 'abrizer/canvas'
|
32
|
+
require 'abrizer/data'
|
24
33
|
require 'abrizer/temporary_poster'
|
25
34
|
require 'abrizer/all'
|
26
35
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: abrizer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Ronallo
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-03-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -152,7 +152,6 @@ files:
|
|
152
152
|
- Rakefile
|
153
153
|
- Vagrantfile
|
154
154
|
- abrizer.gemspec
|
155
|
-
- ansible/development-playbook.retry
|
156
155
|
- ansible/development-playbook.yml
|
157
156
|
- ansible/development.ini
|
158
157
|
- ansible/roles/apache/tasks/main.yml
|
@@ -187,6 +186,7 @@ files:
|
|
187
186
|
- ansible/roles/franklinkim.environment/tasks/config.yml
|
188
187
|
- ansible/roles/franklinkim.environment/tasks/main.yml
|
189
188
|
- ansible/roles/franklinkim.environment/tests/main.yml
|
189
|
+
- ansible/roles/rvm-setup/tasks/main.yml
|
190
190
|
- ansible/roles/rvm_io.rvm1-ruby/.gitignore
|
191
191
|
- ansible/roles/rvm_io.rvm1-ruby/.travis.yml
|
192
192
|
- ansible/roles/rvm_io.rvm1-ruby/LICENSE
|
@@ -205,21 +205,29 @@ files:
|
|
205
205
|
- lib/abrizer.rb
|
206
206
|
- lib/abrizer/adaptation.rb
|
207
207
|
- lib/abrizer/adaptation_finder.rb
|
208
|
+
- lib/abrizer/adaptations_file.rb
|
208
209
|
- lib/abrizer/all.rb
|
209
210
|
- lib/abrizer/canvas.rb
|
210
211
|
- lib/abrizer/captions.rb
|
211
212
|
- lib/abrizer/cleaner.rb
|
212
213
|
- lib/abrizer/cli.rb
|
214
|
+
- lib/abrizer/data.rb
|
215
|
+
- lib/abrizer/debug_settings.rb
|
213
216
|
- lib/abrizer/ffmpeg_processor.rb
|
217
|
+
- lib/abrizer/ffprobe_file.rb
|
214
218
|
- lib/abrizer/ffprobe_informer.rb
|
215
219
|
- lib/abrizer/filepath_helpers.rb
|
220
|
+
- lib/abrizer/identifier_helpers.rb
|
221
|
+
- lib/abrizer/information_helpers.rb
|
216
222
|
- lib/abrizer/package_dash_bento.rb
|
217
223
|
- lib/abrizer/package_dash_shaka.rb
|
218
224
|
- lib/abrizer/package_hls_bento.rb
|
219
225
|
- lib/abrizer/package_hls_shaka.rb
|
220
226
|
- lib/abrizer/processor.rb
|
227
|
+
- lib/abrizer/progressive_mp3.rb
|
221
228
|
- lib/abrizer/progressive_mp4.rb
|
222
229
|
- lib/abrizer/progressive_vp9.rb
|
230
|
+
- lib/abrizer/read_adaptations.rb
|
223
231
|
- lib/abrizer/sprites.rb
|
224
232
|
- lib/abrizer/temporary_poster.rb
|
225
233
|
- lib/abrizer/version.rb
|
@@ -243,7 +251,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
243
251
|
version: '0'
|
244
252
|
requirements: []
|
245
253
|
rubyforge_project:
|
246
|
-
rubygems_version: 2.
|
254
|
+
rubygems_version: 2.5.2
|
247
255
|
signing_key:
|
248
256
|
specification_version: 4
|
249
257
|
summary: Creates MPEG-DASH and HLS streams from a video file.
|
@@ -1 +0,0 @@
|
|
1
|
-
localhost
|