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.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +91 -0
  7. data/Rakefile +10 -0
  8. data/Vagrantfile +76 -0
  9. data/abrizer.gemspec +31 -0
  10. data/ansible/development-playbook.retry +1 -0
  11. data/ansible/development-playbook.yml +19 -0
  12. data/ansible/development.ini +2 -0
  13. data/ansible/roles/basic-setup/tasks/main.yml +39 -0
  14. data/ansible/roles/bento4/tasks/main.yml +14 -0
  15. data/ansible/roles/ffmpeg/defaults/main.yml +6 -0
  16. data/ansible/roles/ffmpeg/tasks/ff-libraries.yml +21 -0
  17. data/ansible/roles/ffmpeg/tasks/ffmpeg.yml +18 -0
  18. data/ansible/roles/ffmpeg/tasks/libfdk_aac.yml +19 -0
  19. data/ansible/roles/ffmpeg/tasks/libmp3lame.yml +20 -0
  20. data/ansible/roles/ffmpeg/tasks/libogg.yml +18 -0
  21. data/ansible/roles/ffmpeg/tasks/libopus.yml +20 -0
  22. data/ansible/roles/ffmpeg/tasks/libvorbis.yml +18 -0
  23. data/ansible/roles/ffmpeg/tasks/libvpx.yml +18 -0
  24. data/ansible/roles/ffmpeg/tasks/main.yml +80 -0
  25. data/ansible/roles/ffmpeg/tasks/x264.yml +18 -0
  26. data/ansible/roles/ffmpeg/tasks/x265.yml +14 -0
  27. data/ansible/roles/ffmpeg/tasks/yasm.yml +19 -0
  28. data/ansible/roles/franklinkim.environment/.clog.toml +4 -0
  29. data/ansible/roles/franklinkim.environment/.editorconfig +16 -0
  30. data/ansible/roles/franklinkim.environment/.gitignore +2 -0
  31. data/ansible/roles/franklinkim.environment/.travis.yml +17 -0
  32. data/ansible/roles/franklinkim.environment/CHANGELOG.md +14 -0
  33. data/ansible/roles/franklinkim.environment/LICENSE +22 -0
  34. data/ansible/roles/franklinkim.environment/Makefile +11 -0
  35. data/ansible/roles/franklinkim.environment/README.md +100 -0
  36. data/ansible/roles/franklinkim.environment/Vagrantfile +23 -0
  37. data/ansible/roles/franklinkim.environment/defaults/main.yml +13 -0
  38. data/ansible/roles/franklinkim.environment/meta/.galaxy_install_info +1 -0
  39. data/ansible/roles/franklinkim.environment/meta/main.yml +143 -0
  40. data/ansible/roles/franklinkim.environment/meta/readme.yml +11 -0
  41. data/ansible/roles/franklinkim.environment/tasks/config.yml +21 -0
  42. data/ansible/roles/franklinkim.environment/tasks/main.yml +8 -0
  43. data/ansible/roles/franklinkim.environment/tests/main.yml +8 -0
  44. data/ansible/roles/rvm_io.rvm1-ruby/.gitignore +6 -0
  45. data/ansible/roles/rvm_io.rvm1-ruby/.travis.yml +52 -0
  46. data/ansible/roles/rvm_io.rvm1-ruby/LICENSE +22 -0
  47. data/ansible/roles/rvm_io.rvm1-ruby/README.md +142 -0
  48. data/ansible/roles/rvm_io.rvm1-ruby/defaults/main.yml +44 -0
  49. data/ansible/roles/rvm_io.rvm1-ruby/meta/main.yml +21 -0
  50. data/ansible/roles/rvm_io.rvm1-ruby/tasks/main.yml +4 -0
  51. data/ansible/roles/rvm_io.rvm1-ruby/tasks/rubies.yml +78 -0
  52. data/ansible/roles/rvm_io.rvm1-ruby/tasks/rvm.yml +55 -0
  53. data/ansible/roles/rvm_io.rvm1-ruby/tests/inventory +1 -0
  54. data/ansible/roles/rvm_io.rvm1-ruby/tests/test.yml +14 -0
  55. data/ansible/roles/rvm_io.rvm1-ruby/vars/main.yml +22 -0
  56. data/bin/console +14 -0
  57. data/bin/setup +8 -0
  58. data/exe/abrizer +5 -0
  59. data/lib/abrizer/adaptation.rb +53 -0
  60. data/lib/abrizer/adaptation_finder.rb +59 -0
  61. data/lib/abrizer/all.rb +20 -0
  62. data/lib/abrizer/cleaner.rb +37 -0
  63. data/lib/abrizer/cli.rb +84 -0
  64. data/lib/abrizer/ffmpeg_processor.rb +59 -0
  65. data/lib/abrizer/ffprobe_informer.rb +69 -0
  66. data/lib/abrizer/filepath_helpers.rb +33 -0
  67. data/lib/abrizer/package_dash_bento.rb +35 -0
  68. data/lib/abrizer/package_dash_shaka.rb +49 -0
  69. data/lib/abrizer/package_hls_bento.rb +35 -0
  70. data/lib/abrizer/package_hls_shaka.rb +50 -0
  71. data/lib/abrizer/processor.rb +8 -0
  72. data/lib/abrizer/progressive_mp4.rb +37 -0
  73. data/lib/abrizer/progressive_vp9.rb +57 -0
  74. data/lib/abrizer/sprites.rb +24 -0
  75. data/lib/abrizer/version.rb +3 -0
  76. data/lib/abrizer.rb +22 -0
  77. 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,4 @@
1
+ ---
2
+
3
+ - include: 'rvm.yml'
4
+ - include: 'rubies.yml'
@@ -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,14 @@
1
+ ---
2
+
3
+ - hosts: localhost
4
+ remote_user: travis
5
+
6
+ vars:
7
+ rvm1_rubies:
8
+ - 'ruby-2.1.0'
9
+ - 'ruby-2.1.2'
10
+ rvm1_install_path: '/home/travis/.rvm'
11
+ rvm1_install_flags: '--auto-dotfiles --user-install'
12
+
13
+ roles:
14
+ - rvm1-ansible
@@ -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
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/exe/abrizer ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require 'abrizer'
3
+ require 'abrizer/cli'
4
+ require 'byebug'
5
+ Abrizer::CLI.start(ARGV)
@@ -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
@@ -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
@@ -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