vncrec 1.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 44f235ad8e44ea1bab090676b4b011ba3eb53993
4
+ data.tar.gz: 314f906e6b36542cc0c8ed42b61fe14c0de4dc31
5
+ SHA512:
6
+ metadata.gz: bcab87f697e3d8ea4da518a1e2bde030235b83016d1c6c48a327168f365d75f4c962589f037fcc4465b5faa09eb88ae4b77b2470fdfe1185fb35c4677ae529a6
7
+ data.tar.gz: ee53667bcbfc8f44e2e86304cd82932d3f095090dedfeabf59618f42680fb942fac35d69dc3b2c93e3aba33f3e0f8e875a6e318f916ad43b0dfa95a81e9fc30a
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ *.swp
15
+ mkmf.log
16
+ tags
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --warnings
3
+ --require spec_helper
4
+ -f doc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in vncrec.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 slowness pc
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.
data/README.md ADDED
@@ -0,0 +1,36 @@
1
+ VNCRec
2
+ ===========
3
+
4
+ VNCRec is a gem that provides you
5
+ tools to record VNC session.
6
+
7
+ ##Usage
8
+ There is a binary called `vncrec`, which is a recorder tool.
9
+
10
+ With no host specified, it will listen on
11
+ given port (5900 by default) for connection
12
+ from VNC server (they refer to that mode as
13
+ _reverse connection_). This is intended to
14
+ be used when you want to record remote
15
+ desktop and you don't know if it's available.
16
+
17
+ Call `vncrec -h` for list of available options.
18
+ To stop recording send `SIGINT` (press ^C).
19
+
20
+ You can also use `VNCRec::Recorder` class in your ruby code.
21
+
22
+ ```ruby
23
+ require 'vncrec'
24
+
25
+ r = VNCRec::Recorder.new(filename: "myvncsession.mp4")
26
+ r.run
27
+ # loop do
28
+ # sleep 100
29
+ # end
30
+ ```
31
+
32
+ If you have FFmpeg installed, file extension is passed just through to it, so
33
+ you can specify encoder you want by passing .mp4 or .flv, etc. If no filename
34
+ specified, `vncrec` assumes raw. There is also a way to
35
+ record raw video by specifying filename with extension .raw. This way FFmpeg is
36
+ not required.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/extensiontask'
3
+ Rake::ExtensionTask.new('enchex_c')
4
+
5
+ CLEAN.add '*.mp4'
6
+ CLEAN.add '*.raw'
7
+ CLEAN.add '*.jpg'
8
+ CLEAN.add 'somefile'
data/bin/vncrec ADDED
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'optparse'
5
+ require 'vncrec'
6
+
7
+ options = VNCRec::Recorder::DEFAULTS
8
+
9
+ OptionParser.new do |opts|
10
+ opts.on('--pix_fmt F', 'Specify pixel format. List available with --pix_fmts') do |d|
11
+ options[:pix_fmt] = d.dup
12
+ end
13
+ opts.on('--pix_fmts', 'List available pix_fmts') do
14
+ puts 'Available pixel formats:'
15
+ puts "bgr8\t8 bits color palette"
16
+ puts "bgra\t32 bits color palette"
17
+ puts
18
+ exit 0
19
+ end
20
+ opts.on('--debug', 'Enable debugger, gem pry-debugger required') do
21
+ require 'pry-byebug'
22
+ options[:debug] = true
23
+ end
24
+ opts.on('-e ENC', '--encoding', 'Specify encoding') do |e|
25
+ name = "ENC_#{e.upcase}".to_sym
26
+ if VNCRec.constants.index(name)
27
+ options[:encoding] = VNCRec.const_get(name)
28
+ else
29
+ puts 'Unsupported encoding type. Pass option --encodings to see a list of available encodings.'
30
+ exit 1
31
+ end
32
+ end
33
+ opts.on('--encodings', 'Print list of available encodings') do
34
+ puts 'Available encodings are:'
35
+ puts "\traw"
36
+ puts "\thextile"
37
+ puts "\tzrle(not yet supported)"
38
+ puts
39
+ exit
40
+ end
41
+ opts.on('-g GEOM', '--geometry GEOM', 'Screen resolution, <X>x<Y>') do |opt|
42
+ unless opt =~ /\d+x\d+/
43
+ puts 'Unknown screen resolution format, use <x>x<y>'
44
+ exit 1
45
+ end
46
+ options[:geometry] = opt
47
+ end
48
+ opts.on('-h', '--help', 'Display this message') do
49
+ puts opts
50
+ exit
51
+ end
52
+ opts.on('--logging', 'Enable logging to stderr') do
53
+ options[:logging] = true
54
+ end
55
+ opts.on('-o NAME', '--output', 'Specify filename to write to. Special name is "stdout"') do |f|
56
+ options[:filename] = f.to_s
57
+ end
58
+ opts.on('-p PORT', '--port', 'Choose port to listen on') do |p|
59
+ options[:port] = p.to_i
60
+ end
61
+ opts.on('-r RATE', '--framerate <rate>', 'Specify framerate') do |r|
62
+ options[:fps] = r.to_i
63
+ end
64
+ opts.on('-s', '--server SERVER', 'Specify host address') do |s|
65
+ options[:host] = s
66
+ end
67
+ end.parse!
68
+
69
+ v = VNCRec::Recorder.new(options)
70
+ v.on_exit << ->() { exit }
71
+ Signal.trap('INT') { v.running? ? v.stop : exit }
72
+ Signal.trap('USR1') do
73
+ puts v.filesize
74
+ $stdout.flush
75
+ end
76
+
77
+ v.run
78
+ loop do
79
+ sleep 100
80
+ end
data/examples/exit.rb ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'vncrec'
5
+
6
+ r = VNCRec::Recorder.new
7
+ # Append exit to the list of on_exit hooks.
8
+ r.on_exit.push(->() { exit })
data/examples/mp4.rb ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'vncrec'
5
+
6
+ VNCRec::Recorder.new(
7
+ encoding: VNCRec::EncHextile,
8
+ filename: 'file.mp4',
9
+ ffmpeg_out_opts: '-vcodec libx264 -preset ultrafast'
10
+ )
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'vncrec'
5
+
6
+ VNCRec::Recorder.new(
7
+ encoding: VNCRec::EncHextile,
8
+ filename: 'file.mp4',
9
+ ffmpeg_ia_opts: '-i /path/to/audio/file.mp3',
10
+ ffmpeg_out_opts: '-map 0 -vcodec libx264 -preset ultrafast -map 1 -acodec mp3'
11
+ )
@@ -0,0 +1,215 @@
1
+ #include <ruby.h>
2
+ #include <ruby/io.h>
3
+ #include <fcntl.h>
4
+
5
+ #include <math.h>
6
+
7
+ int my_readbyte(VALUE io){
8
+ return NUM2INT( rb_funcall(io, rb_intern("readbyte"),0));
9
+ }
10
+
11
+ char *my_read(VALUE io, long nbytes){
12
+ char * result = (char*)malloc(nbytes+1);
13
+ VALUE nbytes_v = INT2NUM(nbytes);
14
+ VALUE rstr = rb_funcall(io, rb_intern("read"), 1,nbytes_v);
15
+ memcpy(
16
+ result,
17
+ RSTRING_PTR(rstr),
18
+ RSTRING_LEN(rstr)
19
+ );
20
+ return result;
21
+ }
22
+
23
+ VALUE mVNC = Qnil;
24
+ VALUE mEncHextile = Qnil;
25
+ VALUE mRFB = Qnil;
26
+
27
+ void Init_enchex_c();
28
+
29
+ static VALUE read_rect_c(VALUE self,VALUE io, VALUE _x, VALUE _y, VALUE _w, VALUE _h, VALUE bitspp, VALUE fb, VALUE fbw, VALUE fbh);
30
+
31
+ void Init_enchex_c() {
32
+ mVNC = rb_define_module("VNCRec");
33
+ mRFB = rb_define_module_under(mVNC, "RFB");
34
+ mEncHextile = rb_define_module_under(mRFB, "EncHextile");
35
+ rb_define_module_function(mEncHextile, "read_rect", read_rect_c, 9);
36
+ }
37
+
38
+ void _read_subrect_c(int rx, int ry, int rw, int rh, int tx, int ty, char *fg, VALUE io, char* fb, int fbw, int fbh, int bpp){
39
+
40
+ unsigned char xy, wh;
41
+ xy = my_readbyte(io);
42
+ wh = my_readbyte(io);
43
+
44
+ if(!fb)
45
+ return;
46
+
47
+ unsigned char stx = (xy & 0xF0) >> 4;
48
+ unsigned char stw = ((wh & 0xF0) >> 4) + 1;
49
+ unsigned char sty = (xy & 0x0F);
50
+ unsigned char sth = (wh & 0x0F) + 1;
51
+ rw *= bpp;
52
+ rx *= bpp;
53
+ tx *= bpp;
54
+ stx *= bpp;
55
+ stw *= bpp;
56
+ char *fg_row = (char*)malloc(stw);
57
+ int k,l;
58
+ for(k = 0; k < stw; k+=bpp){
59
+ for(l = 0; l < bpp; l++){
60
+ fg_row[k+l] = fg[l];
61
+ }
62
+ }
63
+
64
+ int i;
65
+ for (i = 0; i < sth; i++) {
66
+ register int row_begin = fbw*(ry+ty+sty+i) + rx + tx + stx;
67
+ memcpy(&fb[row_begin], fg_row, stw);
68
+ }
69
+ free(fg_row);
70
+ }
71
+
72
+ void _read_subrect_c_raw(int rx, int ry, int rw, int rh, int tx, int ty, int tw, int th, VALUE io, char* fb, int fbw, int fbh, int bpp){
73
+
74
+ rw *= bpp;
75
+ rx *= bpp;
76
+ tw *= bpp;
77
+ tx *= bpp;
78
+
79
+ int trow;
80
+ char *data = my_read(io, tw*th);
81
+
82
+ if(!fb){
83
+ return;
84
+ }
85
+
86
+ for (trow = 0; trow < th; trow++) {
87
+ register int row_begin = fbw*(ry+ty+trow) + rx + tx;
88
+ memcpy( &fb[row_begin], &data[trow*tw],tw);
89
+ }
90
+ free(data);
91
+ }
92
+
93
+ void _fill_tile_bg(int rx, int ry, int rw, int rh, int tx, int ty, int tw, int th, char*bg, VALUE io, char* fb, int fbw, int fbh, int bpp){
94
+ if(!fb)
95
+ return;
96
+
97
+ rw *= bpp;
98
+ rx *= bpp;
99
+ tw *=bpp;
100
+ tx *= bpp;
101
+ int trow;
102
+ char *bg_row = (char*)malloc(tw);
103
+ int k,l;
104
+ for(k = 0; k < tw; k+=bpp){
105
+ for(l = 0; l < bpp; l++){
106
+ bg_row[k+l] = bg[l];
107
+ }
108
+ }
109
+ register int base_row_begin = fbw*(ry+ty) + rx + tx;
110
+ for (trow = 0; trow < th; trow++) {
111
+ register int row_begin = base_row_begin + fbw*trow;
112
+ memcpy(&fb[row_begin], bg_row, tw);
113
+ }
114
+ free(bg_row);
115
+ }
116
+
117
+ static VALUE read_rect_c(VALUE self,VALUE io, VALUE _x, VALUE _y, VALUE _w, VALUE _h, VALUE bitspp, VALUE _fb, VALUE _fbw, VALUE _fbh){
118
+ int w = NUM2INT(_w);
119
+ int h = NUM2INT(_h);
120
+ int rx = NUM2INT(_x);
121
+ int ry = NUM2INT(_y);
122
+ int fbw = NUM2INT(_fbw);
123
+ int fbh = NUM2INT(_fbh);
124
+ int bpp = (float)NUM2INT(bitspp) / 8.0;
125
+
126
+
127
+ int tiles_row_num = ceil((float)h/16.0);
128
+ int tiles_col_num = ceil((float)w/16.0);
129
+
130
+ char *fb;
131
+ int fbsize = fbw*fbh;
132
+ if(ry > fbh || rx * bpp > fbw)
133
+ fb = NULL; // skip
134
+ else
135
+ fb = (char*)malloc(fbsize);
136
+ if(fb)
137
+ memcpy(fb,RSTRING(_fb)->as.heap.ptr,RSTRING(_fb)->as.heap.len);
138
+
139
+ int last_tile_w = w % 16;
140
+ int last_tile_h = h % 16;
141
+
142
+ char prev_tile_bg[4];
143
+ char prev_tile_fg[4];
144
+
145
+ int i,j;
146
+ int tw, th;
147
+ int ty, tx;
148
+ int ti,tj,tk;
149
+ unsigned char subenc;
150
+ for (i = 0; i < tiles_row_num; i++) {
151
+
152
+ if ((i == tiles_row_num-1) && (last_tile_h > 0))
153
+ th = last_tile_h;
154
+ else
155
+ th = 16;
156
+ ty = 16 * i;
157
+ for (j = 0; j < tiles_col_num; j++) {
158
+
159
+ if ((j == tiles_col_num-1) && (last_tile_w > 0))
160
+ tw = last_tile_w;
161
+ else
162
+ tw = 16;
163
+ tx = 16 * j;
164
+
165
+ subenc = my_readbyte(io);
166
+
167
+ if(subenc & 1){ //raw
168
+ _read_subrect_c_raw(rx,ry,w,h,tx,ty,tw,th,io,fb,fbw,fbh,bpp);
169
+ }
170
+ if(subenc & 2){//background specified
171
+ for (tk = 0; tk < bpp; tk++) {
172
+ prev_tile_bg[tk] = my_readbyte(io);
173
+ }
174
+ }
175
+ if(!(subenc & 1)){//should not refill raw
176
+ for (ti = 0; ti < th; ti++) {
177
+ for(tj = 0; tj < tw; tj++){
178
+ _fill_tile_bg(rx,ry,w,h,tx,ty,tw,th,prev_tile_bg,io,fb,fbw,fbh,bpp);
179
+ }
180
+ }
181
+ }
182
+ if(subenc & 4){//foreground specified
183
+ for (tk = 0; tk < bpp; tk++) {
184
+ prev_tile_fg[tk] = my_readbyte(io);
185
+ }
186
+ }
187
+ if(subenc & 8){//any subrect
188
+ size_t subrects_number = my_readbyte(io);
189
+ size_t subrect;
190
+ char fg[4];
191
+ for (subrect = 0; subrect < subrects_number; subrect++) {
192
+ if(subenc & 16){//subrect colored
193
+ for (tk = 0; tk < bpp; tk++) {
194
+ fg[tk] = my_readbyte(io);
195
+ }
196
+ _read_subrect_c(rx,ry,w,h,tx,ty, fg, io, fb, fbw, fbh, bpp);
197
+ }else{
198
+ _read_subrect_c(rx,ry,w,h,tx,ty, prev_tile_fg, io, fb, fbw, fbh, bpp);
199
+ }
200
+ }
201
+ }
202
+
203
+ } //for j
204
+ }//for i
205
+
206
+ if(fb) {
207
+ for (i = 0; i < fbh; i++) {
208
+ rb_str_update(_fb, i*fbw, fbw,
209
+ rb_str_new(&fb[i * fbw], fbw));
210
+ }
211
+ free(fb);
212
+ }
213
+
214
+ return Qtrue;
215
+ }
@@ -0,0 +1,5 @@
1
+ require "mkmf"
2
+
3
+ extension_name = 'enchex_c'
4
+ dir_config(extension_name)
5
+ create_makefile("vncrec/rfb/#{extension_name}")