video_tesseract 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 (3) hide show
  1. checksums.yaml +7 -0
  2. data/bin/video-tesseract +155 -0
  3. metadata +45 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0afb26ca6638e1ab64bbd929df6661238d07d3ef
4
+ data.tar.gz: a6b7ba869db9390130aa5b9455f2c93187713336
5
+ SHA512:
6
+ metadata.gz: 9b0dfab4fb0f34a20938edc50bdb306eaadb5a185b5a73f74f57b2a9a61ef4876e5e2241c4c517aa2abfed8e85caeed04c3e5ae7c831ac1f08499fe2b9f96575
7
+ data.tar.gz: c8f751daf2035c22419ab4f2ff2ee9f8e9d7698adb2a911b994b0b48ef3c57f5029975d6b805fccd7d25be240f206f6d2f282af745137db9851c8f9861b31f19
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'mkmf'
5
+ require 'tmpdir'
6
+
7
+ @tile_width = 320
8
+ @tile_height = 180
9
+
10
+ @frame_rate = 23.976
11
+
12
+ @cols = 5
13
+ @rows = 5
14
+
15
+ @input = nil
16
+ @output = 'tesseract.mp4'
17
+
18
+ @verbose = false
19
+
20
+ optparse = OptionParser.new do |opts|
21
+ opts.banner = "Usage: tesseract [options]"
22
+
23
+ opts.on('-i', '--input [input.mp4]', 'Path to input video (Required)') do |i|
24
+ @input = i
25
+ end
26
+
27
+ opts.on('-o', '--output [tesseract.mp4]', 'Path to write output tesseracted video (Defaults to tesseract.mp4)') do |o|
28
+ @output = o
29
+ end
30
+
31
+ opts.on('-s', '--size [<width>x<height>]', 'Tile size in pixels (Defaults to 320x180)') do |s|
32
+ @tile_width, @tile_height = s.split('x').map(&:to_i)
33
+ end
34
+
35
+ opts.on('-g', '--grid [<columns>x<rows>]', 'Tesseract grid layout (Defaults to 5x5)') do |g|
36
+ @cols, @rows = g.split('x').map(&:to_i)
37
+ end
38
+
39
+ opts.on('-r', '--frame-rate [23.976]', 'Frame rate of the tesseracted video (Defaults to 23.976)') do |r|
40
+ @frame_rate = r.to_f
41
+ end
42
+
43
+ opts.on('-v', '--[no-]verbose', 'Run verbosely') do |v|
44
+ @verbose = v
45
+ end
46
+
47
+ opts.on('-h', '--help', 'Prints help') do
48
+ puts opts
49
+ exit
50
+ end
51
+ end
52
+
53
+ optparse.parse!
54
+
55
+
56
+ # Make sure we have @input
57
+ if @input.nil? || !File.exist?(@input)
58
+ puts 'Missing or invalid input video file (--input)'
59
+ puts ''
60
+ puts optparse
61
+ abort
62
+ end
63
+
64
+ # Make sure we have ffmpeg and imagemagick installed
65
+ unless find_executable('ffmpeg')
66
+ puts 'Cannot find ffmpeg executable. Make sure you have FFmpeg installed.'
67
+ abort
68
+ end
69
+
70
+ unless find_executable('convert')
71
+ puts 'Cannot find convert executable. Make sure you have ImageMagick installed.'
72
+ abort
73
+ end
74
+
75
+ Dir.mktmpdir do |data_dir|
76
+
77
+ # get the frame count for the video
78
+ frames = `ffmpeg -i #{@input} -vcodec copy -acodec copy -f null /dev/null 2>&1 | grep 'frame=' | cut -f 2 -d ' '`.to_i
79
+
80
+ tiles = @rows * @cols
81
+ frames_per_tile = frames / tiles
82
+ tesseract_width = @tile_width * @cols
83
+ tesseract_height = @tile_height * @rows
84
+
85
+
86
+
87
+ puts ''
88
+ puts "Generating #{@cols}x#{@rows} tesseract with tile size #{@tile_width}x#{@tile_height}"
89
+ puts "Tesseract video will be #{tesseract_width}x#{tesseract_height} with a duration of #{frames_per_tile} frames."
90
+ puts ''
91
+
92
+
93
+
94
+ #
95
+ # Step 1: Extract all frames from the video
96
+ #
97
+ # Note: Skip this step if the we already have the frames extracted.
98
+
99
+ print "Extracting all frames of the video ... "
100
+ `ffmpeg -y -i #{@input} -vcodec png -s #{@tile_width}x#{@tile_height} -an -y #{data_dir}/frame_%d.png #{'2>&1' unless @verbose}`
101
+ puts 'done'
102
+
103
+
104
+
105
+ #
106
+ # Step 2: Creating the montages from the frames
107
+ #
108
+ (1..frames_per_tile).each do |offset|
109
+
110
+ images = (offset..frames).step(frames_per_tile).map { |idx| "#{data_dir}/frame_#{idx}.png" }[0...tiles]
111
+
112
+ # how much to move each frame to the left as time goes on
113
+ x_shift = (offset / frames_per_tile.to_f) * @tile_width
114
+
115
+ cmd = "convert -size #{tesseract_width}x#{tesseract_height} xc:black "
116
+ images.each_with_index do |image, idx|
117
+ x_offset = (idx % @cols) * @tile_width + x_shift
118
+ y_offset = (idx / @cols) * @tile_height
119
+ cmd << "#{image} -geometry +#{x_offset}+#{y_offset} -composite "
120
+
121
+ # if it's the last image in the row, repeat it in the row below to the left
122
+ # of the first image for that row
123
+ if idx % @cols == @cols - 1
124
+ x_offset = ((idx + 1) % @cols) * @tile_width + x_shift - @tile_width
125
+ y_offset = ((idx + 1) / @cols) * @tile_height
126
+ cmd << "#{image} -geometry +#{x_offset}+#{y_offset} -composite "
127
+ end
128
+ end
129
+
130
+ cmd << "#{data_dir}/montage_#{offset}.png"
131
+
132
+ if @verbose
133
+ puts cmd
134
+ puts ''
135
+ end
136
+
137
+ print "Generating montage #{offset}/#{frames_per_tile}\r"
138
+ $stdout.flush
139
+
140
+ system(cmd)
141
+
142
+ end
143
+ puts "Generated all #{frames_per_tile} montages."
144
+
145
+
146
+
147
+ #
148
+ # Step 3: Creating the tesseracted video from the montages
149
+ #
150
+
151
+ print "Generating final tesseracted video: #{@output} ... "
152
+ `ffmpeg -y -framerate #{@frame_rate} -i #{data_dir}/montage_%d.png -c:v libx264 -r #{@frame_rate} -pix_fmt yuv420p #{@output} #{'2>&1' unless @verbose}`
153
+ puts 'done'
154
+
155
+ end
metadata ADDED
@@ -0,0 +1,45 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: video_tesseract
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Brendan Schwartz
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-16 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: 'Video tesseract lays '
14
+ email: brendan@wistia.com
15
+ executables:
16
+ - video-tesseract
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - bin/video-tesseract
21
+ homepage: https://github.com/wistia/video-tesseract
22
+ licenses:
23
+ - MIT
24
+ metadata: {}
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ required_rubygems_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ requirements: []
40
+ rubyforge_project:
41
+ rubygems_version: 2.2.2
42
+ signing_key:
43
+ specification_version: 4
44
+ summary: Tesseract your videos
45
+ test_files: []