abrizer 0.1.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 +7 -0
- data/.gitignore +11 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +91 -0
- data/Rakefile +10 -0
- data/Vagrantfile +76 -0
- data/abrizer.gemspec +31 -0
- data/ansible/development-playbook.retry +1 -0
- data/ansible/development-playbook.yml +19 -0
- data/ansible/development.ini +2 -0
- data/ansible/roles/basic-setup/tasks/main.yml +39 -0
- data/ansible/roles/bento4/tasks/main.yml +14 -0
- data/ansible/roles/ffmpeg/defaults/main.yml +6 -0
- data/ansible/roles/ffmpeg/tasks/ff-libraries.yml +21 -0
- data/ansible/roles/ffmpeg/tasks/ffmpeg.yml +18 -0
- data/ansible/roles/ffmpeg/tasks/libfdk_aac.yml +19 -0
- data/ansible/roles/ffmpeg/tasks/libmp3lame.yml +20 -0
- data/ansible/roles/ffmpeg/tasks/libogg.yml +18 -0
- data/ansible/roles/ffmpeg/tasks/libopus.yml +20 -0
- data/ansible/roles/ffmpeg/tasks/libvorbis.yml +18 -0
- data/ansible/roles/ffmpeg/tasks/libvpx.yml +18 -0
- data/ansible/roles/ffmpeg/tasks/main.yml +80 -0
- data/ansible/roles/ffmpeg/tasks/x264.yml +18 -0
- data/ansible/roles/ffmpeg/tasks/x265.yml +14 -0
- data/ansible/roles/ffmpeg/tasks/yasm.yml +19 -0
- data/ansible/roles/franklinkim.environment/.clog.toml +4 -0
- data/ansible/roles/franklinkim.environment/.editorconfig +16 -0
- data/ansible/roles/franklinkim.environment/.gitignore +2 -0
- data/ansible/roles/franklinkim.environment/.travis.yml +17 -0
- data/ansible/roles/franklinkim.environment/CHANGELOG.md +14 -0
- data/ansible/roles/franklinkim.environment/LICENSE +22 -0
- data/ansible/roles/franklinkim.environment/Makefile +11 -0
- data/ansible/roles/franklinkim.environment/README.md +100 -0
- data/ansible/roles/franklinkim.environment/Vagrantfile +23 -0
- data/ansible/roles/franklinkim.environment/defaults/main.yml +13 -0
- data/ansible/roles/franklinkim.environment/meta/.galaxy_install_info +1 -0
- data/ansible/roles/franklinkim.environment/meta/main.yml +143 -0
- data/ansible/roles/franklinkim.environment/meta/readme.yml +11 -0
- data/ansible/roles/franklinkim.environment/tasks/config.yml +21 -0
- data/ansible/roles/franklinkim.environment/tasks/main.yml +8 -0
- data/ansible/roles/franklinkim.environment/tests/main.yml +8 -0
- data/ansible/roles/rvm_io.rvm1-ruby/.gitignore +6 -0
- data/ansible/roles/rvm_io.rvm1-ruby/.travis.yml +52 -0
- data/ansible/roles/rvm_io.rvm1-ruby/LICENSE +22 -0
- data/ansible/roles/rvm_io.rvm1-ruby/README.md +142 -0
- data/ansible/roles/rvm_io.rvm1-ruby/defaults/main.yml +44 -0
- data/ansible/roles/rvm_io.rvm1-ruby/meta/main.yml +21 -0
- data/ansible/roles/rvm_io.rvm1-ruby/tasks/main.yml +4 -0
- data/ansible/roles/rvm_io.rvm1-ruby/tasks/rubies.yml +78 -0
- data/ansible/roles/rvm_io.rvm1-ruby/tasks/rvm.yml +55 -0
- data/ansible/roles/rvm_io.rvm1-ruby/tests/inventory +1 -0
- data/ansible/roles/rvm_io.rvm1-ruby/tests/test.yml +14 -0
- data/ansible/roles/rvm_io.rvm1-ruby/vars/main.yml +22 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/abrizer +5 -0
- data/lib/abrizer/adaptation.rb +53 -0
- data/lib/abrizer/adaptation_finder.rb +59 -0
- data/lib/abrizer/all.rb +20 -0
- data/lib/abrizer/cleaner.rb +37 -0
- data/lib/abrizer/cli.rb +84 -0
- data/lib/abrizer/ffmpeg_processor.rb +59 -0
- data/lib/abrizer/ffprobe_informer.rb +69 -0
- data/lib/abrizer/filepath_helpers.rb +33 -0
- data/lib/abrizer/package_dash_bento.rb +35 -0
- data/lib/abrizer/package_dash_shaka.rb +49 -0
- data/lib/abrizer/package_hls_bento.rb +35 -0
- data/lib/abrizer/package_hls_shaka.rb +50 -0
- data/lib/abrizer/processor.rb +8 -0
- data/lib/abrizer/progressive_mp4.rb +37 -0
- data/lib/abrizer/progressive_vp9.rb +57 -0
- data/lib/abrizer/sprites.rb +24 -0
- data/lib/abrizer/version.rb +3 -0
- data/lib/abrizer.rb +22 -0
- metadata +232 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
---
|
2
|
+
|
3
|
+
# Install 1 or more versions of ruby
|
4
|
+
# The last ruby listed will be set as the default ruby
|
5
|
+
rvm1_rubies:
|
6
|
+
- 'ruby-2.2.2'
|
7
|
+
|
8
|
+
# Delete a specific version of ruby (ie. ruby-2.1.0)
|
9
|
+
rvm1_delete_ruby:
|
10
|
+
|
11
|
+
# Install path for rvm (defaults to system wide)
|
12
|
+
rvm1_install_path: '/usr/local/rvm'
|
13
|
+
|
14
|
+
# Add or remove any install flags
|
15
|
+
# NOTE: If you are doing a USER BASED INSTALL then
|
16
|
+
# make sure you ADD the --user-install flag below
|
17
|
+
rvm1_install_flags: '--auto-dotfiles'
|
18
|
+
|
19
|
+
# Add additional ruby install flags
|
20
|
+
rvm1_ruby_install_flags:
|
21
|
+
|
22
|
+
# Set the owner for the rvm directory
|
23
|
+
rvm1_user: 'root'
|
24
|
+
|
25
|
+
# URL for the latest installer script
|
26
|
+
rvm1_rvm_latest_installer: 'https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer'
|
27
|
+
|
28
|
+
# rvm version to use
|
29
|
+
rvm1_rvm_version: 'stable'
|
30
|
+
|
31
|
+
# Check and update rvm, disabling this will force rvm to never update
|
32
|
+
rvm1_rvm_check_for_updates: True
|
33
|
+
|
34
|
+
# GPG key verification, use an empty string if you want to skip this
|
35
|
+
# Note: Unless you know what you're doing, just keep it as is
|
36
|
+
# Identity proof: https://keybase.io/mpapis
|
37
|
+
# PGP message: https://rvm.io/mpapis.asc
|
38
|
+
rvm1_gpg_keys: 'D39DC0E3'
|
39
|
+
|
40
|
+
# The GPG key server
|
41
|
+
rvm1_gpg_key_server: 'hkp://keys.gnupg.net'
|
42
|
+
|
43
|
+
# autolib mode, see https://rvm.io/rvm/autolibs
|
44
|
+
rvm1_autolib_mode: 3
|
@@ -0,0 +1,21 @@
|
|
1
|
+
---
|
2
|
+
galaxy_info:
|
3
|
+
author: Nick Janetakis
|
4
|
+
description: The official rvm role to install and manage your ruby versions.
|
5
|
+
company:
|
6
|
+
license: license (MIT)
|
7
|
+
min_ansible_version: 1.5
|
8
|
+
|
9
|
+
platforms:
|
10
|
+
- name: EL
|
11
|
+
versions:
|
12
|
+
- all
|
13
|
+
- name: Ubuntu
|
14
|
+
versions:
|
15
|
+
- all
|
16
|
+
|
17
|
+
categories:
|
18
|
+
- development
|
19
|
+
- web
|
20
|
+
|
21
|
+
dependencies: []
|
@@ -0,0 +1,78 @@
|
|
1
|
+
---
|
2
|
+
|
3
|
+
- name: Detect if rubies are installed
|
4
|
+
command: '{{ rvm1_rvm }} {{ item }} do true'
|
5
|
+
changed_when: False
|
6
|
+
failed_when: False
|
7
|
+
register: detect_rubies
|
8
|
+
with_items: '{{ rvm1_rubies }}'
|
9
|
+
when: rvm1_rubies
|
10
|
+
|
11
|
+
- name: Install rubies
|
12
|
+
command: '{{ rvm1_rvm }} install {{ item.item }} {{ rvm1_ruby_install_flags }}'
|
13
|
+
when: rvm1_rubies and item.rc|default(0) != 0
|
14
|
+
with_items: '{{ detect_rubies.results }}'
|
15
|
+
become: yes
|
16
|
+
become_user: '{{ rvm1_user }}'
|
17
|
+
|
18
|
+
- name: Detect default ruby version
|
19
|
+
command: '{{ rvm1_rvm }} alias list default'
|
20
|
+
changed_when: False
|
21
|
+
register: detect_default_ruby_version
|
22
|
+
become: yes
|
23
|
+
become_user: '{{ rvm1_user }}'
|
24
|
+
|
25
|
+
- name: Select default ruby
|
26
|
+
command: '{{ rvm1_rvm }} alias create default {{ rvm1_default_ruby_version }}'
|
27
|
+
when: detect_default_ruby_version.stdout|default() == '' or
|
28
|
+
rvm1_default_ruby_version not in detect_default_ruby_version.stdout
|
29
|
+
become: yes
|
30
|
+
become_user: '{{ rvm1_user }}'
|
31
|
+
|
32
|
+
- name: Detect installed ruby patch number
|
33
|
+
shell: >
|
34
|
+
{{ rvm1_rvm }} list strings | grep {{ item }} | tail -n 1
|
35
|
+
with_items: '{{ rvm1_rubies }}'
|
36
|
+
changed_when: False
|
37
|
+
register: ruby_patch
|
38
|
+
always_run: yes # Run even when in --check mode (http://docs.ansible.com/ansible/playbooks_checkmode.html)
|
39
|
+
become: yes
|
40
|
+
become_user: '{{ rvm1_user }}'
|
41
|
+
|
42
|
+
- name: Install bundler if not installed
|
43
|
+
shell: >
|
44
|
+
ls {{ rvm1_install_path }}/wrappers/{{ item.stdout }}
|
45
|
+
| if ! grep "^bundler " ; then {{ rvm1_install_path }}/wrappers/{{ item.stdout }}/gem install bundler ; fi
|
46
|
+
args:
|
47
|
+
creates: '{{ rvm1_install_path }}/wrappers/{{ item.stdout }}/bundler'
|
48
|
+
with_items: '{{ ruby_patch.results }}'
|
49
|
+
register: bundler_install
|
50
|
+
changed_when: '"Successfully installed bundler" in bundler_install.stdout'
|
51
|
+
become: yes
|
52
|
+
become_user: '{{ rvm1_user }}'
|
53
|
+
|
54
|
+
- name: Symlink ruby related binaries on the system path
|
55
|
+
file:
|
56
|
+
state: 'link'
|
57
|
+
src: '{{ rvm1_install_path }}/wrappers/default/{{ item }}'
|
58
|
+
dest: '{{ rvm1_symlink_to }}/{{ item }}'
|
59
|
+
owner: 'root'
|
60
|
+
group: 'root'
|
61
|
+
when: not '--user-install' in rvm1_install_flags
|
62
|
+
with_items: '{{ rvm1_symlink_binaries }}'
|
63
|
+
|
64
|
+
- name: Detect if ruby version can be deleted
|
65
|
+
command: '{{ rvm1_rvm }} {{ rvm1_delete_ruby }} do true'
|
66
|
+
changed_when: False
|
67
|
+
failed_when: False
|
68
|
+
register: detect_delete_ruby
|
69
|
+
when: rvm1_delete_ruby
|
70
|
+
become: yes
|
71
|
+
become_user: '{{ rvm1_user }}'
|
72
|
+
|
73
|
+
- name: Delete ruby version
|
74
|
+
command: '{{ rvm1_rvm }} remove {{ rvm1_delete_ruby }}'
|
75
|
+
changed_when: False
|
76
|
+
when: rvm1_delete_ruby and detect_delete_ruby.rc == 0
|
77
|
+
become: yes
|
78
|
+
become_user: '{{ rvm1_user }}'
|
@@ -0,0 +1,55 @@
|
|
1
|
+
---
|
2
|
+
|
3
|
+
- name: Detect rvm binary
|
4
|
+
stat: path='{{ rvm1_rvm }}'
|
5
|
+
register: rvm_binary
|
6
|
+
|
7
|
+
- name: Detect rvm installer
|
8
|
+
stat: path='{{ rvm1_temp_download_path }}/rvm-installer.sh'
|
9
|
+
register: rvm_installer
|
10
|
+
|
11
|
+
- name: Detect current rvm version
|
12
|
+
command: '{{ rvm1_rvm}} version'
|
13
|
+
changed_when: False
|
14
|
+
register: rvm_current_version
|
15
|
+
when: rvm_binary.stat.exists
|
16
|
+
|
17
|
+
- name: Install rvm installer
|
18
|
+
get_url:
|
19
|
+
url: '{{ rvm1_rvm_latest_installer }}'
|
20
|
+
dest: '{{ rvm1_temp_download_path }}/rvm-installer.sh'
|
21
|
+
when: not rvm_installer.stat.exists
|
22
|
+
|
23
|
+
- name: Configure rvm installer
|
24
|
+
file:
|
25
|
+
path: '{{ rvm1_temp_download_path }}/rvm-installer.sh'
|
26
|
+
mode: 0755
|
27
|
+
when: not rvm_binary.stat.exists
|
28
|
+
|
29
|
+
- name: Import GPG keys
|
30
|
+
command: 'gpg --keyserver {{ rvm1_gpg_key_server }} --recv-keys {{ rvm1_gpg_keys }}'
|
31
|
+
changed_when: False
|
32
|
+
when: rvm1_gpg_keys != ''
|
33
|
+
become: yes
|
34
|
+
become_user: '{{ rvm1_user }}'
|
35
|
+
|
36
|
+
- name: Install rvm
|
37
|
+
command: >
|
38
|
+
{{ rvm1_temp_download_path }}/rvm-installer.sh {{ rvm1_rvm_version }}
|
39
|
+
--path {{ rvm1_install_path }} {{ rvm1_install_flags }}
|
40
|
+
when: not rvm_binary.stat.exists
|
41
|
+
become: yes
|
42
|
+
become_user: '{{ rvm1_user }}'
|
43
|
+
|
44
|
+
- name: Update rvm
|
45
|
+
shell: '{{ rvm1_rvm }} get {{ rvm1_rvm_version }} && {{ rvm1_rvm }} reload'
|
46
|
+
changed_when: False
|
47
|
+
when: rvm_binary.stat.exists and rvm1_rvm_check_for_updates
|
48
|
+
become: yes
|
49
|
+
become_user: '{{ rvm1_user }}'
|
50
|
+
|
51
|
+
- name: Configure rvm
|
52
|
+
command: '{{ rvm1_rvm }} autolibs {{ rvm1_autolib_mode }}'
|
53
|
+
when: not rvm_binary.stat.exists
|
54
|
+
become: yes
|
55
|
+
become_user: '{{ rvm1_user }}'
|
@@ -0,0 +1 @@
|
|
1
|
+
localhost
|
@@ -0,0 +1,22 @@
|
|
1
|
+
---
|
2
|
+
|
3
|
+
rvm1_temp_download_path: '/tmp'
|
4
|
+
|
5
|
+
rvm1_default_ruby_version: '{{ rvm1_rubies | last if rvm1_rubies and rvm1_rubies is iterable else "" }}'
|
6
|
+
|
7
|
+
rvm1_rvm: '{{ rvm1_install_path }}/bin/rvm'
|
8
|
+
|
9
|
+
rvm1_symlink_binaries:
|
10
|
+
- 'bundle'
|
11
|
+
- 'bundler'
|
12
|
+
- 'erb'
|
13
|
+
- 'executable-hooks-uninstaller'
|
14
|
+
- 'gem'
|
15
|
+
- 'irb'
|
16
|
+
- 'rake'
|
17
|
+
- 'rdoc'
|
18
|
+
- 'ri'
|
19
|
+
- 'ruby'
|
20
|
+
- 'testrb'
|
21
|
+
|
22
|
+
rvm1_symlink_to: '/usr/local/bin'
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "abrizer"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/exe/abrizer
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
module Abrizer
|
2
|
+
class Adaptation
|
3
|
+
|
4
|
+
include FilepathHelpers
|
5
|
+
|
6
|
+
attr_reader :width, :height, :bitrate
|
7
|
+
|
8
|
+
def initialize(width:, height:, bitrate:)
|
9
|
+
@width = width
|
10
|
+
@height = height
|
11
|
+
@bitrate = bitrate
|
12
|
+
end
|
13
|
+
|
14
|
+
def ffmpeg_cmd(input, output_directory, pass)
|
15
|
+
cmd = %Q|ffmpeg -y -i #{input} -vf \
|
16
|
+
scale='#{width}:trunc(#{width}/dar/2)*2',setsar=1 \
|
17
|
+
-an -c:v libx264 -x264opts 'keyint=48:min-keyint=48:no-scenecut' \
|
18
|
+
-b:v #{bitrate}k -preset faster |
|
19
|
+
if pass == 2
|
20
|
+
cmd += %Q| -maxrate #{constrained_bitrate}k -bufsize #{bitrate}k -pass 2 #{filepath(input, output_directory)} |
|
21
|
+
else
|
22
|
+
cmd += " -pass 1 -f mp4 /dev/null "
|
23
|
+
end
|
24
|
+
cmd
|
25
|
+
end
|
26
|
+
|
27
|
+
# TODO: make the constrained bitrate (maxrate) value configurable
|
28
|
+
def constrained_bitrate
|
29
|
+
@bitrate * 1.1
|
30
|
+
end
|
31
|
+
|
32
|
+
def outfile_basename(input)
|
33
|
+
extname = File.extname input
|
34
|
+
basename = File.basename input, extname
|
35
|
+
"#{basename}-#{width}x#{height}-#{bitrate}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def filepath(input, output_directory)
|
39
|
+
name = "#{outfile_basename(input)}.mp4"
|
40
|
+
File.join output_directory, name
|
41
|
+
end
|
42
|
+
|
43
|
+
def filepath_fragmented(input, output_directory)
|
44
|
+
name = "#{outfile_basename(input)}-frag.mp4"
|
45
|
+
File.join output_directory, name
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
"Width: #{@width}, Height: #{@height}, Bitrate: #{@bitrate}"
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Abrizer
|
2
|
+
# TODO: AdaptationFinder is incomplete. Basically what we want to do is to
|
3
|
+
# find out the height, width, and aspect ratio of the original and then
|
4
|
+
# determine which adaptations to create. So for a 3:2 video we'll have 4
|
5
|
+
# adaptations but ought to only create ones that are the same size and smaller
|
6
|
+
# than the input file. Adaptations that are larger should not be created.
|
7
|
+
# So first we find the aspect ratio to see the value adaptations we could
|
8
|
+
# apply and then we select the ones that are the same width and smaller.
|
9
|
+
# If there is not an exact match for the
|
10
|
+
# All of the aspect ratios here are given based on real files that have come
|
11
|
+
# through our workflow, so there might be some missing.
|
12
|
+
class AdaptationFinder
|
13
|
+
attr_reader :adaptations, :info
|
14
|
+
def initialize(filename)
|
15
|
+
@filename = filename
|
16
|
+
@informer = Abrizer::FfprobeInformer.new(filename)
|
17
|
+
find_adaptations
|
18
|
+
end
|
19
|
+
|
20
|
+
# TODO: analyze the incoming file and determine which preset to use
|
21
|
+
def find_adaptations
|
22
|
+
raw_adaptations = case @informer.display_aspect_ratio
|
23
|
+
when "4:3"
|
24
|
+
ar_4_3_adaptations
|
25
|
+
when "16:9"
|
26
|
+
ar_16_9_adaptations
|
27
|
+
else
|
28
|
+
puts "Unable to find appropriate adaptation set!"
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
adaptations = raw_adaptations.map{|adaptation| Abrizer::Adaptation.new(adaptation)}
|
32
|
+
@adaptations = adaptations.select{|adaptation| adaptation.width <= @informer.width}
|
33
|
+
end
|
34
|
+
|
35
|
+
# The bitrates here are based on H.264 encoding.
|
36
|
+
def ar_4_3_adaptations
|
37
|
+
[
|
38
|
+
{width: 224, height: 168, bitrate: 200},
|
39
|
+
{width: 448, height: 336, bitrate: 400},
|
40
|
+
{width: 640, height: 480, bitrate: 800},
|
41
|
+
{width: 720, height: 540, bitrate: 1000},
|
42
|
+
]
|
43
|
+
end
|
44
|
+
|
45
|
+
# The bitrates here are based on H.264 encoding.
|
46
|
+
def ar_16_9_adaptations
|
47
|
+
# Average video bitrate from here: https://bitmovin.com/video-bitrate-streaming-hls-dash/
|
48
|
+
[
|
49
|
+
{width: 256, height: 144, bitrate: 200},
|
50
|
+
{width: 512, height: 288, bitrate: 400},
|
51
|
+
{width: 768, height: 432, bitrate: 800},
|
52
|
+
{width: 1024, height: 576, bitrate: 1200},
|
53
|
+
{width: 1280, height: 720, bitrate: 2400},
|
54
|
+
{width: 1920, height: 1080, bitrate: 4800},
|
55
|
+
]
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
data/lib/abrizer/all.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Abrizer
|
2
|
+
class All
|
3
|
+
|
4
|
+
def initialize(filename, output_dir=nil)
|
5
|
+
@filename = filename
|
6
|
+
@output_directory = output_dir
|
7
|
+
end
|
8
|
+
|
9
|
+
def run
|
10
|
+
Abrizer::Processor.process(@filename, @output_directory)
|
11
|
+
Abrizer::ProgressiveMp4.new(@filename, @output_directory).create
|
12
|
+
Abrizer::ProgressiveVp9.new(@filename, @output_directory).create
|
13
|
+
Abrizer::PackageDashBento.new(@filename, @output_directory).package
|
14
|
+
Abrizer::PackageHlsBento.new(@filename, @output_directory).package
|
15
|
+
Abrizer::Sprites.new(@filename, @output_directory).create
|
16
|
+
Abrizer::Cleaner.new(@filename, @output_directory).clean
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Abrizer
|
2
|
+
class Cleaner
|
3
|
+
|
4
|
+
include FilepathHelpers
|
5
|
+
|
6
|
+
def initialize(filename, output_dir=nil)
|
7
|
+
@filename = filename
|
8
|
+
@output_directory = output_dir
|
9
|
+
@adaptations = Abrizer::AdaptationFinder.new(@filename).adaptations
|
10
|
+
end
|
11
|
+
|
12
|
+
def clean
|
13
|
+
delete_adaptations(@adaptations)
|
14
|
+
clean_audio_file
|
15
|
+
remove_pass1_log_files
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete_adaptations(adapts)
|
19
|
+
adapts.map do |adaptation|
|
20
|
+
filepath = adaptation.filepath_fragmented(@filename, output_directory)
|
21
|
+
FileUtils.rm filepath if File.exist? filepath
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def clean_audio_file
|
26
|
+
FileUtils.rm audio_filepath_fragmented if File.exist? audio_filepath_fragmented
|
27
|
+
end
|
28
|
+
|
29
|
+
def remove_pass1_log_files
|
30
|
+
glob = File.join output_directory, "ffmpeg2pass*"
|
31
|
+
Dir.glob(glob).each do |log_filepath|
|
32
|
+
FileUtils.rm log_filepath
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
data/lib/abrizer/cli.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'thor'
|
2
|
+
module Abrizer
|
3
|
+
class CLI < Thor
|
4
|
+
|
5
|
+
desc 'all <filepath> <output_directory>', 'Runn all processes including creating ABR streams, progressive download versions, and images and video sprites'
|
6
|
+
def all(filepath, output_dir=nil)
|
7
|
+
filepath = File.expand_path filepath
|
8
|
+
output_dir = File.expand_path output_dir
|
9
|
+
Abrizer::All.new(filepath, output_dir).run
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'abr <filepath> <output_directory>', 'From file create ABR streams, includes processing MP4 adaptations for packaging'
|
13
|
+
def abr(filepath, output_dir=nil)
|
14
|
+
filepath = File.expand_path filepath
|
15
|
+
output_dir = File.expand_path output_dir
|
16
|
+
Abrizer::Processor.process(filepath, output_dir)
|
17
|
+
Abrizer::PackageDashBento.new(filepath, output_dir).package
|
18
|
+
Abrizer::PackageHlsBento.new(filepath, output_dir).package
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'process <filepath> <output_directory>', 'From mezzanine or preservation file create intermediary adaptations'
|
22
|
+
def process(filepath, output_dir=nil)
|
23
|
+
filepath = File.expand_path filepath
|
24
|
+
output_dir = File.expand_path output_dir
|
25
|
+
Abrizer::Processor.process(filepath, output_dir)
|
26
|
+
end
|
27
|
+
|
28
|
+
desc 'mp4 <filepath> <output_directory>', 'Create a single progressive download version as an MP4 from the next to largest adaptation and audio. The adaptation and audio file must already exist.'
|
29
|
+
def mp4(filepath, output_dir=nil)
|
30
|
+
filepath = File.expand_path filepath
|
31
|
+
output_dir = File.expand_path output_dir
|
32
|
+
Abrizer::ProgressiveMp4.new(filepath, output_dir).create
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'vp9 <filepath> <output_directory>', 'Create a single VP9 progressive download version from the original video.'
|
36
|
+
def vp9(filepath, output_dir=nil)
|
37
|
+
filepath = File.expand_path filepath
|
38
|
+
output_dir = File.expand_path output_dir
|
39
|
+
Abrizer::ProgressiveVp9.new(filepath, output_dir).create
|
40
|
+
end
|
41
|
+
|
42
|
+
desc 'adaptations <filepath>', 'Display which adaptations will be created from input file'
|
43
|
+
def adaptations(filepath)
|
44
|
+
adaptations = Abrizer::AdaptationFinder.new(filepath).adaptations
|
45
|
+
puts adaptations
|
46
|
+
end
|
47
|
+
|
48
|
+
desc 'inform <filepath>', 'Display information about the video/audio file'
|
49
|
+
def inform(filepath)
|
50
|
+
informer = FfprobeInformer.new(filepath)
|
51
|
+
puts informer.json_result
|
52
|
+
puts informer
|
53
|
+
end
|
54
|
+
|
55
|
+
desc 'package <dash_or_hls> <filepath> <output_directory>', "Package dash or hls from adaptations"
|
56
|
+
def package(dash_or_hls, filepath, output_dir=nil)
|
57
|
+
filepath = File.expand_path filepath
|
58
|
+
output_dir = File.expand_path output_dir
|
59
|
+
case dash_or_hls
|
60
|
+
when "dash"
|
61
|
+
Abrizer::PackageDashBento.new(filepath, output_dir).package
|
62
|
+
when "hls"
|
63
|
+
Abrizer::PackageHlsBento.new(filepath, output_dir).package
|
64
|
+
when "all"
|
65
|
+
Abrizer::PackageDashBento.new(filepath, output_dir).package
|
66
|
+
Abrizer::PackageHlsBento.new(filepath, output_dir).package
|
67
|
+
else
|
68
|
+
puts "Not a valid packaging value. Try dash or hls."
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
desc 'sprites <filepath> <output_directory>', 'Create image sprites and metadata WebVTT file'
|
73
|
+
def sprites(filepath, output_dir=nil)
|
74
|
+
filepath = File.expand_path filepath
|
75
|
+
output_dir = File.expand_path output_dir
|
76
|
+
Abrizer::Sprites.new(filepath, output_dir).create
|
77
|
+
end
|
78
|
+
|
79
|
+
desc 'clean <filepath> <output_directory>', 'Clean up intermediary files'
|
80
|
+
def clean(filepath, output_dir=nil)
|
81
|
+
Abrizer::Cleaner.new(filepath, output_dir).clean
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Abrizer
|
2
|
+
class FfmpegProcessor
|
3
|
+
|
4
|
+
include FilepathHelpers
|
5
|
+
|
6
|
+
def initialize(filename, output_dir=nil)
|
7
|
+
@filename = filename
|
8
|
+
@output_directory = output_dir
|
9
|
+
@adaptation_finder = Abrizer::AdaptationFinder.new(@filename)
|
10
|
+
end
|
11
|
+
|
12
|
+
def process
|
13
|
+
make_directory
|
14
|
+
Dir.chdir output_directory
|
15
|
+
process_first_pass
|
16
|
+
process_second_passes
|
17
|
+
process_audio
|
18
|
+
end
|
19
|
+
|
20
|
+
def make_directory
|
21
|
+
FileUtils.mkdir output_directory unless File.exist? output_directory
|
22
|
+
end
|
23
|
+
|
24
|
+
def first_pass_adaptation
|
25
|
+
adaptations = Abrizer::AdaptationFinder.new(@filename).adaptations
|
26
|
+
sorted = adaptations.sort_by do |adaptation|
|
27
|
+
adaptation.width
|
28
|
+
end
|
29
|
+
sorted[-2]
|
30
|
+
end
|
31
|
+
|
32
|
+
def first_pass_cmd
|
33
|
+
first_pass_adaptation.ffmpeg_cmd(@filename, output_directory, 1)
|
34
|
+
end
|
35
|
+
|
36
|
+
def process_first_pass
|
37
|
+
puts first_pass_cmd
|
38
|
+
`#{first_pass_cmd}`
|
39
|
+
end
|
40
|
+
|
41
|
+
# Creates a file per adaptation based on aspect ratio and resolution
|
42
|
+
def process_second_passes
|
43
|
+
@adaptation_finder.adaptations.each do |adaptation|
|
44
|
+
cmd = adaptation.ffmpeg_cmd(@filename, output_directory, 2)
|
45
|
+
puts cmd
|
46
|
+
`#{cmd}`
|
47
|
+
`mp4fragment #{adaptation.filepath(@filename, output_directory)} #{adaptation.filepath_fragmented(@filename, output_directory)}`
|
48
|
+
FileUtils.rm adaptation.filepath(@filename, output_directory)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def process_audio
|
53
|
+
`ffmpeg -y -i #{@filename} -c:a libfdk_aac -b:a 128k -vn #{audio_filepath}`
|
54
|
+
`mp4fragment #{audio_filepath} #{audio_filepath_fragmented}`
|
55
|
+
FileUtils.rm audio_filepath
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Abrizer
|
2
|
+
class FfprobeInformer
|
3
|
+
attr_reader :json_result, :info
|
4
|
+
def initialize(filename)
|
5
|
+
@filename = filename
|
6
|
+
get_info
|
7
|
+
end
|
8
|
+
|
9
|
+
def get_info
|
10
|
+
@json_result = `#{ffmpeg_info_cmd}`
|
11
|
+
@info = JSON.parse @json_result
|
12
|
+
end
|
13
|
+
|
14
|
+
def width
|
15
|
+
video_stream['width'] if video_stream
|
16
|
+
end
|
17
|
+
|
18
|
+
def height
|
19
|
+
video_stream['height'] if video_stream
|
20
|
+
end
|
21
|
+
|
22
|
+
def display_aspect_ratio #dar
|
23
|
+
dar = video_stream['display_aspect_ratio']
|
24
|
+
sar = video_stream['sample_aspect_ratio']
|
25
|
+
if dar == "0:1" #&& sar == "0:1"
|
26
|
+
calculate_aspect_ratio_from_wh
|
27
|
+
else
|
28
|
+
dar
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def calculate_aspect_ratio_from_wh
|
33
|
+
new_width = width
|
34
|
+
new_height = height
|
35
|
+
w = width
|
36
|
+
h = height
|
37
|
+
while h != 0
|
38
|
+
rem = w % h
|
39
|
+
w = h
|
40
|
+
h = rem
|
41
|
+
end
|
42
|
+
new_height = new_height / w
|
43
|
+
new_width = new_width / w
|
44
|
+
"#{new_width}:#{new_height}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def video_stream
|
48
|
+
@info['streams'].find do |stream|
|
49
|
+
stream['codec_type'] == 'video'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def audio_stream
|
54
|
+
@info['streams'].find do |stream|
|
55
|
+
stream['codec_type'] == 'audio'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def ffmpeg_info_cmd
|
60
|
+
"ffprobe -v error -print_format json -show_format -show_streams #{@filename}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_s
|
64
|
+
ffmpeg_info_cmd + "\n" +
|
65
|
+
"#{width}x#{height} DAR:#{display_aspect_ratio}"
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|