access-derivatives 0.0.11

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.
@@ -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: []