video_tesseract 0.1.0

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