abrizer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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