access-derivatives 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b6bfadafe61b4098608dde830f1b200e9992f5dd
4
+ data.tar.gz: 662d9471251f35920c4bd9ff3f24a6e948d3e955
5
+ SHA512:
6
+ metadata.gz: 610b63607385ec7728eaa6320d9503946d5277b696d3e44f865588964b12da0becf2fe278da6c4fb922487c9765141324935051f5f44b2a7cee01b8eb051b68f
7
+ data.tar.gz: a028814e83a97c109c62c2093101bfe00d307955143a25dba4bcf586998e5fe804b7421295ea31d35a3e06c2a07ee54fb1f9b7d9469858690ac8b5f617116e7f
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+
19
+ test_data
20
+ test_data_output
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in access-derivatives.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Jason Ronallo
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,11 @@
1
+ # Access Derivatives
2
+
3
+ Ruby scripts used at NCSU Libraries for creating access derivatives.
4
+
5
+ ## Installation
6
+
7
+ $ gem install access-derivatives
8
+
9
+ ## Usage
10
+
11
+ TODO: Write usage instructions here
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'access/derivatives/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "access-derivatives"
8
+ spec.version = Access::Derivatives::VERSION
9
+ spec.authors = ["Jason Ronallo"]
10
+ spec.email = ["jronallo@gmail.com"]
11
+ spec.summary = %q{Create access derivative files.}
12
+ spec.description = %q{Create access derivative files.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ end
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # poster_sprite /path/to/snapshots/directoryname
4
+
5
+ # Creates a poster sprite (and in the future maybe a WebVTT file) from snapshots in a directory.
6
+
7
+ # requires montage and identify from imagemagick
8
+
9
+ module AccessDerivatives
10
+ def self.seconds_to_webvtt_timestamp(total_seconds)
11
+ seconds = total_seconds % 60
12
+ minutes = (total_seconds / 60) % 60
13
+ hours = total_seconds / (60 * 60)
14
+
15
+ format("%02d:%02d:%02d.000", hours, minutes, seconds)
16
+ end
17
+ end
18
+
19
+ directory = File.expand_path(ARGV[0])
20
+ directory_glob = File.join(directory, '*png')
21
+ directory_basename = File.basename(directory)
22
+ sprite_basename = directory_basename + '-sprite.jpg'
23
+ sprite_output_filename = File.join(directory, sprite_basename)
24
+ webvtt_output_filename = File.join(directory, directory_basename + '-sprite.vtt')
25
+
26
+ first_image = Dir.glob(directory_glob).sort.first
27
+ original_dimensions = `identify -format "%[fx:w]x%[fx:h]" #{first_image}`.chomp
28
+
29
+ original_width_str, original_height_str = original_dimensions.split('x')
30
+ original_height = original_height_str.to_i
31
+ original_width = original_width_str.to_i
32
+
33
+ width = 150
34
+ height = (original_height.to_f / original_width * width).to_i
35
+
36
+ tile_per_row = 5
37
+
38
+ `montage #{directory_glob} -tile #{tile_per_row}x -geometry #{width}x#{height}! #{sprite_output_filename}`
39
+
40
+ vtt_asset_base = File.join('http://siskel.lib.ncsu.edu/SCRC/', directory_basename, sprite_basename)
41
+
42
+ File.open(webvtt_output_filename, 'w') do |fh|
43
+ fh.puts "WEBVTT\n\n"
44
+
45
+ # figure out the coordinates when the images are 5 across at 150px wide.
46
+ # What height are they then?
47
+ x = 0
48
+ y = 0
49
+ number_in_row = 1
50
+
51
+ Dir.glob(directory_glob).sort.each_with_index do |file, index|
52
+ full_url = vtt_asset_base + "#xywh=#{x},#{y},#{width},#{height}"
53
+
54
+ start_time_integer = index * 5 # 5 seconds between each
55
+ end_time_integer = start_time_integer + 5
56
+
57
+ start_time = AccessDerivatives.seconds_to_webvtt_timestamp(start_time_integer)
58
+ end_time = AccessDerivatives.seconds_to_webvtt_timestamp(end_time_integer)
59
+
60
+ fh.puts start_time + ' --> ' + end_time
61
+ fh.puts full_url + "\n\n"
62
+
63
+ number_in_row += 1
64
+ x += width
65
+ if number_in_row > tile_per_row
66
+ number_in_row = 1
67
+ x = 0
68
+ y += height
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # poster_sprites_retrospective /path/to/directory/of/videos
4
+
5
+ require 'fileutils'
6
+
7
+ directory = File.expand_path(ARGV[0])
8
+ Dir.glob(File.join(directory, '*.mp4')).each do |video|
9
+ basename = File.basename(video, '.mp4')
10
+
11
+ video_snapshots_directory = File.join(directory, basename)
12
+ Dir.mkdir(video_snapshots_directory) unless File.exist?(video_snapshots_directory)
13
+ video_snapshot_base_filename = File.join(video_snapshots_directory, basename)
14
+
15
+ # Create images every 5 seconds from the MP4 output.
16
+ `ffmpeg -i "#{video}" -f image2 -vf fps=fps=1/5 #{video_snapshot_base_filename}-%05d.png`
17
+
18
+ poster_sprite_command_path = File.join(File.expand_path(File.dirname(__FILE__)), 'poster_sprite')
19
+ `#{poster_sprite_command_path} #{video_snapshots_directory}`
20
+
21
+ FileUtils.rm(Dir.glob(File.join(video_snapshots_directory, '*png')))
22
+ end
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # process_video /path/to/directory/of/video/files/
4
+
5
+ # Requires a recent ffmpeg and mail.
6
+ # requires montage and identify from imagemagick
7
+ require 'etc'
8
+ require 'fileutils'
9
+
10
+ # batch directory for processing
11
+ directory = File.expand_path(ARGV[0])
12
+
13
+ # Get the username of the owner of the batch directory. Used later for sending email.
14
+ uid = File.stat(directory).uid
15
+ username_for_batch = Etc.getpwuid(uid).name
16
+
17
+ # What directory should we place the output in?
18
+ base_output_directory = ENV['PROCESS_VIDEO_OUTPUT_DIRECTORY'] || '/html5/video/output'
19
+ batch_output_directory = File.basename(directory)
20
+
21
+ # Create output directory.
22
+ output_directory = File.join(base_output_directory, batch_output_directory)
23
+ Dir.mkdir(output_directory) unless File.exist?(output_directory)
24
+
25
+ # Create a directory for placing ffmpeg log files.
26
+ log_directory = File.join(output_directory, 'log')
27
+ Dir.mkdir(log_directory) unless File.exist?(log_directory)
28
+
29
+ # Create directory for snapshots.
30
+ snapshot_directory = File.join(output_directory, 'snapshots')
31
+ Dir.mkdir(snapshot_directory) unless File.exist?(snapshot_directory)
32
+
33
+ # Get the list of all the files that ought to be processed
34
+ source_video_files = []
35
+ ['*.mp4','*.flv', '*.mov', '*.avi', '*.mkv','*.m4v', '*.f4v'].each do |source_extension|
36
+ source_video_files << Dir.glob(File.join(directory, source_extension))
37
+ end
38
+ source_video_files.flatten!.compact!
39
+
40
+ # iterate over each of the files that ought to be processed
41
+ source_video_files.each do |filepath|
42
+ # get the basename
43
+ extension = File.extname(filepath)
44
+ basename = File.basename(filepath, extension)
45
+
46
+ # Create the video output directory
47
+ video_output_directory = File.join(output_directory, basename)
48
+ Dir.mkdir(video_output_directory) unless File.exist?(video_output_directory)
49
+
50
+ # Create the snaptshots directory.
51
+ video_snapshots_directory = File.join(snapshot_directory, basename)
52
+ Dir.mkdir(video_snapshots_directory) unless File.exist?(video_snapshots_directory)
53
+ video_snapshots_base_filename = File.join(video_snapshots_directory, basename)
54
+
55
+ # determine filenames for each output format
56
+ video_output_filename_root = File.join(video_output_directory, basename)
57
+ video_output_filename_mp4 = video_output_filename_root + '.mp4'
58
+ video_output_filename_webm = video_output_filename_root + '.webm'
59
+
60
+ # determine the filenames for each of the log files created
61
+ log_file_mp4 = File.join(log_directory, basename + '-ffmpeg-mp4-%t.log')
62
+ log_file_webm = File.join(log_directory, basename + '-ffmpeg-webm-%t.log')
63
+ log_file_snapshot = File.join(log_directory, basename + '-snapshot-%t.log')
64
+
65
+ # Create MP4 suitable for web playback and log output.
66
+ # "-pix_fmt yuv420p" was added to work around an issue where the stream is yuv422p
67
+ `FFREPORT=file=#{log_file_mp4} ffmpeg -i #{filepath} -c:v libx264 -preset slow -crf 23 -profile:v baseline -level 3.0 -filter:v "scale=640:trunc(ow/a/2)*2" -acodec libfdk_aac -b:a 128k -movflags +faststart -pix_fmt yuv420p "#{video_output_filename_mp4}"`
68
+
69
+ # Create WebM and log output.
70
+ `FFREPORT=file=#{log_file_webm} ffmpeg -i "#{filepath}" -c:v libvpx -crf 10 -b:v 1M -filter:v "scale=640:trunc(ow/a/2)*2" -c:a libvorbis -b:a 128k "#{video_output_filename_webm}"`
71
+
72
+ # Create images every 5 seconds from the MP4 output.
73
+ `FFREPORT=file=#{log_file_snapshot} ffmpeg -i "#{video_output_filename_mp4}" -f image2 -vf fps=fps=1/5 #{video_snapshots_base_filename}-%05d.png`
74
+
75
+ # Create poster sprite and related webvtt file
76
+ poster_sprite_command_path = File.join(File.expand_path(File.dirname(__FILE__)), 'poster_sprite')
77
+ `#{poster_sprite_command_path} #{video_snapshots_directory}`
78
+
79
+ # Move poster sprite and WebVTT file into video output directory
80
+ sprite_files_glob = File.join(video_snapshots_directory, '*sprite*')
81
+ Dir.glob(sprite_files_glob).each do |file|
82
+ FileUtils.mv(file, video_output_directory)
83
+ end
84
+ end
85
+
86
+ # Sends an email when the job is done. This may only work this way with the -r option on redhat.
87
+ `echo "To get the files run: scp -r #{username_for_batch}@av1.lib.ncsu.edu:#{output_directory} ." | mail -s "Your transcoding job is done" -r jnronall@ncsu.edu #{username_for_batch}@ncsu.edu`
@@ -0,0 +1,32 @@
1
+ #!/bin/bash
2
+
3
+ # upload_video_batch.sh /path/to/batch/directory
4
+
5
+ # Setting for directory to where the batch directory ought to be uploaded
6
+ upload_batch_directory_base=/html5/video/uploads
7
+
8
+ # This only works if the local user
9
+ whoami=`whoami`
10
+
11
+ # Grab the first argument into a variable so that we can do the basename substitution.
12
+ argv0=$1
13
+ # The basename from whatever path was given
14
+ basename=`basename $argv0`
15
+
16
+ # full upload path
17
+ full_upload_path=${upload_batch_directory_base}/${basename}
18
+ full_upload_path_contents=${full_upload_path}/*
19
+
20
+ # Copy the files to the remote server under the upload batch directory.
21
+ echo -e 'Copying the files to av1... (May need to enter password).\n'
22
+ scp -r $1 $whoami@av1.lib.ncsu.edu:$upload_batch_directory_base
23
+
24
+ echo -e 'Changing group permissions of files. (May need to enter password).'
25
+ ssh $whoami@av1.lib.ncsu.edu "chgrp uploaders $full_upload_path && chmod g+rx $full_upload_path && chmod g+rw $full_upload_path_contents"
26
+
27
+ echo "Hit ENTER when you wish to continue with processing the video. (May need to enter password)."
28
+ read SOMETHIGNANYTHING
29
+
30
+ # Trigger the processing job on the remove server and background it using nohup.
31
+ # Output and errors will go into files. FFmpeg output goes to standard error.
32
+ ssh $whoami@av1.lib.ncsu.edu "PROCESS_VIDEO_OUTPUT_DIRECTORY=/html5/video/output nohup process_video $full_upload_path > upload_batch.out 2> upload_batch.err < /dev/null &"
@@ -0,0 +1,7 @@
1
+ require "access/derivatives/version"
2
+
3
+ module Access
4
+ module Derivatives
5
+ # Your code goes here...
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ module Access
2
+ module Derivatives
3
+ VERSION = "0.0.11"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: access-derivatives
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.11
5
+ platform: ruby
6
+ authors:
7
+ - Jason Ronallo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-02-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Create access derivative files.
42
+ email:
43
+ - jronallo@gmail.com
44
+ executables:
45
+ - poster_sprite
46
+ - poster_sprites_retrospective
47
+ - process_video
48
+ - upload_video_batch.sh
49
+ extensions: []
50
+ extra_rdoc_files: []
51
+ files:
52
+ - ".gitignore"
53
+ - Gemfile
54
+ - LICENSE.txt
55
+ - README.md
56
+ - Rakefile
57
+ - access-derivatives.gemspec
58
+ - bin/poster_sprite
59
+ - bin/poster_sprites_retrospective
60
+ - bin/process_video
61
+ - bin/upload_video_batch.sh
62
+ - lib/access/derivatives.rb
63
+ - lib/access/derivatives/version.rb
64
+ homepage: ''
65
+ licenses:
66
+ - MIT
67
+ metadata: {}
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubyforge_project:
84
+ rubygems_version: 2.4.8
85
+ signing_key:
86
+ specification_version: 4
87
+ summary: Create access derivative files.
88
+ test_files: []