ipcam 0.2.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5860e0ddb4768629eb61a15d4a91fc174487f130a22c581ab49263e8bc817fc9
4
- data.tar.gz: 3d5a26bd9529d5591c824f6fbe200af084a85baa1c1f98f040697f2b4fd3d0d4
3
+ metadata.gz: 3673112cdc6871dd10631f4a67f4f5e1c93b3f6056af3acd6fbee4ef1ca3a8f8
4
+ data.tar.gz: 119f2126a4a68f850285af9f8fe06e32e08324ff4e17b1939ba0e7ad2f818122
5
5
  SHA512:
6
- metadata.gz: 1b1969bf1a2b71a2dc2a9c445c6bc75939942e3d0982b0ca94f163413bbe55f5eb94c57afce3367f23a96859e26e5e8a2a1942f366f9f7e2ed6e14b27a40ed28
7
- data.tar.gz: 160d3da4692663a2eff313d9b5f0f4d604cf57606afd877d8453331b517ea9f417ad75f7f493734aac6a98c710787d3fd5305c8be9952bc51d048fd72d5d4338
6
+ metadata.gz: 63874cacbf9f2b194b4829a168067b976b3f6692cdf2b1fdc807b1fe66ca1863af4f43857a6b0a89a606af4d050ddb2372a79c21da859a990ba1407951651096
7
+ data.tar.gz: 871dbee9300615fea6fd5b98e0053f0afe1e5311a1cfe615548a6ed189b45ac4b66d0e8f31d1a1d5dd15c595d8ff5489a1182e36ee7d6b4a4a5353cb1f8390aa
data/README.md CHANGED
@@ -25,6 +25,7 @@ options:
25
25
  --bind=ADDR
26
26
  --port=PORT
27
27
  -d, --database-file=FILE
28
+ -e, --extend-header
28
29
  --log-file=FILE
29
30
  --log-age=AGE
30
31
  --log-size=SIZE
@@ -48,6 +49,9 @@ Then connect to port 4567 by http browser and operate. The accessible URLs are a
48
49
  <dt>-d, --database-file=FILE</dt>
49
50
  <dd>Specify the file name to save the camera setting value. by default, it tries to save to "~/.ipcam.db".</dd>
50
51
 
52
+ <dt>-e, --extend-header</dt>
53
+ <dd>Add extend header to part data (for debug).</dd>
54
+
51
55
  <dt>--log-file=FILE</dt>
52
56
  <dd></dd>
53
57
 
@@ -63,7 +67,7 @@ specify target device file (ex: /dev/video1). if omittedm, it will use "/dev/vi
63
67
 
64
68
  ## etc
65
69
  ### About image data
66
- いらすとや(https://www.irasutoya.com/)で配布されている『特撮映画のイラスト』(https://www.irasutoya.com/2018/12/blog-post_90.html)を改変して使用しています。
70
+ いらすとや (https://www.irasutoya.com) で配布されている『特撮映画のイラスト』(https://www.irasutoya.com/2018/12/blog-post_90.html) を改変して使用しています。
67
71
 
68
72
  ## License
69
73
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/bin/ipcam CHANGED
@@ -52,7 +52,7 @@ OptionParser.new { |opt|
52
52
  }
53
53
 
54
54
  opt.on('--port=PORT', Integer) { |val|
55
- $bind_port = val
55
+ $http_port = val
56
56
  $ws_port = val + 1
57
57
  }
58
58
 
@@ -60,6 +60,10 @@ OptionParser.new { |opt|
60
60
  $db_file = Pathname.new(val)
61
61
  }
62
62
 
63
+ opt.on('-e', '--extend-header') { |val|
64
+ $extend_header = true
65
+ }
66
+
63
67
  opt.on('--log-file=FILE') { |val|
64
68
  log[:device] = val
65
69
  }
data/lib/ipcam/main.rb CHANGED
@@ -23,10 +23,10 @@ module IPCam
23
23
  @camera = nil
24
24
  @state = :STOP
25
25
  @img_que = Thread::Queue.new
26
- @cam_thr = Thread.new {camera_thread}
27
- @snd_thr = Thread.new {sender_thread}
28
26
  @clients = []
29
27
 
28
+ start_thread()
29
+
30
30
  WebServer.start(self)
31
31
  WebSocket.start(self)
32
32
 
@@ -34,19 +34,28 @@ module IPCam
34
34
  end
35
35
 
36
36
  def stop
37
- @cam_thr.join
38
-
39
- @snd_thr.raise(Stop)
40
- @snd_thr.join
41
-
37
+ stop_thread()
42
38
 
43
39
  WebServer.stop
44
40
  EM.stop
45
41
  end
46
42
 
43
+ def start_thread
44
+ @cam_thr = Thread.new {camera_thread}
45
+ end
46
+ private :start_thread
47
+
48
+ def stop_thread
49
+ @cam_thr.raise(Stop)
50
+ @cam_thr.join
51
+ @cam_thr = nil
52
+ end
53
+ private :stop_thread
54
+
47
55
  def restart_camera
48
56
  @cam_thr.raise(Restart)
49
57
  end
58
+ private :restart_camera
50
59
 
51
60
  def select_capabilities(cam)
52
61
  ret = cam.frame_capabilities(:MJPEG).instance_eval {
@@ -235,6 +244,8 @@ module IPCam
235
244
  raise("#{$target} is not support Motion-JPEG")
236
245
  end
237
246
 
247
+ snd_thr = Thread.new {sender_thread}
248
+
238
249
  begin
239
250
  @mutex.synchronize {
240
251
  @config = load_settings()
@@ -271,6 +282,10 @@ module IPCam
271
282
  ensure
272
283
  @camera&.close
273
284
  @camera = nil
285
+
286
+ snd_thr&.raise(Stop)
287
+ snd_thr&.join
288
+
274
289
  $logger.info("main") {"camera thread stop"}
275
290
  end
276
291
  private :camera_thread
@@ -285,12 +300,12 @@ module IPCam
285
300
  }
286
301
 
287
302
  rescue Stop
288
- $logger.info("main") {"accept stop request"}
289
303
  @clients.each {|c| c[:que] << nil}
290
304
 
291
305
  ensure
292
306
  $logger.info("main") {"sender thread stop"}
293
307
  end
308
+ private:sender_thread
294
309
 
295
310
  def get_camera_info
296
311
  @mutex.synchronize {
@@ -370,5 +385,29 @@ module IPCam
370
385
  def remove_client(que)
371
386
  @clients.reject! {|c| c[:que] == que}
372
387
  end
388
+
389
+ def start_camera
390
+ raise("state violation") if @state != :STOP and @state != :ABORT
391
+
392
+ start_thread()
393
+ end
394
+
395
+ def stop_camera
396
+ raise("state violation") if @state != :ALIVE
397
+
398
+ stop_thread()
399
+ end
400
+
401
+ def alive?
402
+ @state == :ALIVE
403
+ end
404
+
405
+ def abort?
406
+ @state == :ABORT
407
+ end
408
+
409
+ def stop?
410
+ @state == :STOP
411
+ end
373
412
  end
374
413
  end
data/lib/ipcam/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module IPCam
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.2"
3
3
  end
@@ -66,6 +66,9 @@ module IPCam
66
66
  end
67
67
 
68
68
  get "/stream" do
69
+ halt 500 if app.abort?
70
+ halt 404 if app.stop?
71
+
69
72
  boundary = SecureRandom.hex(20)
70
73
  queue = Thread::Queue.new
71
74
 
@@ -83,18 +86,32 @@ module IPCam
83
86
  port << "\r\n"
84
87
  app.add_client(queue)
85
88
 
89
+ fc = 0
90
+
86
91
  loop {
87
92
  data = queue.deq
88
93
  break if not data
89
94
 
90
- port << <<~EOT.b
91
- --#{boundary}
92
- Content-Type: image/jpeg\r
93
- Content-Length: #{data.bytesize}\r
94
- \r
95
- EOT
95
+ if $extend_header
96
+ port << <<~EOT.b
97
+ --#{boundary}
98
+ Content-Type: image/jpeg\r
99
+ Content-Length: #{data.bytesize}\r
100
+ X-Frame-Number: #{fc}
101
+ X-Timestamp: #{(Time.now.to_f * 1000).round}
102
+ \r
103
+ EOT
104
+ else
105
+ port << <<~EOT.b
106
+ --#{boundary}
107
+ Content-Type: image/jpeg\r
108
+ Content-Length: #{data.bytesize}\r
109
+ \r
110
+ EOT
111
+ end
96
112
 
97
113
  port << data
114
+ fc += 1
98
115
 
99
116
  # データ詰まりを防ぐ為にキューをクリア
100
117
  queue.clear
data/lib/ipcam/websock.rb CHANGED
@@ -106,7 +106,7 @@ module IPCam
106
106
  addr = $bind_addr
107
107
  end
108
108
 
109
- return "tcp://#{addr}:#{$http_port}"
109
+ return "tcp://#{addr}:#{$ws_port}"
110
110
  end
111
111
  private :bind_url
112
112
 
@@ -376,5 +376,31 @@ module IPCam
376
376
  return :OK
377
377
  end
378
378
  remote_public :save_config
379
+
380
+ #
381
+ # カメラの撮影開始
382
+ #
383
+ # @return [:OK] 固定値
384
+ #
385
+ def start_camera(df)
386
+ EM.defer {
387
+ @app.start_camera()
388
+ df.resolve(:OK)
389
+ }
390
+ end
391
+ remote_async :start_camera
392
+
393
+ #
394
+ # カメラの撮影停止
395
+ #
396
+ # @return [:OK] 固定値
397
+ #
398
+ def stop_camera(df)
399
+ EM.defer {
400
+ @app.stop_camera()
401
+ df.resolve(:OK)
402
+ }
403
+ end
404
+ remote_async :stop_camera
379
405
  end
380
406
  end
@@ -27,6 +27,8 @@
27
27
  var previewCanvas;
28
28
  var previewGc;
29
29
 
30
+ var cameraState;
31
+
30
32
  /*
31
33
  * declar functions
32
34
  */
@@ -40,24 +42,28 @@
40
42
  var bg;
41
43
  var lb;
42
44
 
45
+ cameraState = state;
46
+
43
47
  switch (state) {
44
48
  case "STOP":
45
49
  default:
46
50
  fg = "royalblue";
47
- bg = "white";
51
+ bg = "rgba(160, 160, 160, 0.5)";
48
52
  lb = "START";
53
+ clearPreviewCanvas();
49
54
  break;
50
55
 
51
56
  case "ALIVE":
52
57
  fg = "springgreen";
53
- bg = "black";
58
+ bg = "rgba(0, 0, 0, 0.5)";
54
59
  lb = "STOP";
55
60
  break;
56
61
 
57
62
  case "ABORT":
58
63
  fg = "crimson";
59
- bg = "white";
64
+ bg = "rgba(160, 160, 160, 0.5)";
60
65
  lb = "RECOVER";
66
+ clearPreviewCanvas();
61
67
  break;
62
68
  }
63
69
 
@@ -332,6 +338,8 @@
332
338
  previewCanvas.width = imageWidth;
333
339
  previewCanvas.height = imageHeight;
334
340
 
341
+ clearPreviewCanvas();
342
+
335
343
  setTimeout(() => {
336
344
  $('div#preview').getNiceScroll().resize();
337
345
  }, 0);
@@ -433,14 +441,12 @@
433
441
  });
434
442
 
435
443
  } else {
436
- $('h6#device-name').text(null);
437
-
438
444
  $('select#image-size > option').remove();
439
445
  $('select#framerate > option').remove();
440
446
  $('div#controls').empty();
441
-
442
- setupScreenSize();
443
447
  }
448
+
449
+ $('button#action').prop('disabled', false);
444
450
  }
445
451
 
446
452
  function startSession() {
@@ -501,6 +507,23 @@
501
507
  }
502
508
 
503
509
  function setupButtons() {
510
+ $('button#action')
511
+ .on('click', () => {
512
+ clearPreviewCanvas();
513
+ $('button#action').prop('disabled', true);
514
+
515
+ switch (cameraState) {
516
+ case "STOP":
517
+ case "ABORT":
518
+ session.startCamera();
519
+ break;
520
+
521
+ case "ALIVE":
522
+ session.stopCamera();
523
+ break;
524
+ }
525
+ });
526
+
504
527
  $('button#save-config')
505
528
  .on('click', () => {
506
529
  session.saveConfig();
@@ -516,6 +539,11 @@
516
539
  });
517
540
  }
518
541
 
542
+ function clearPreviewCanvas() {
543
+ previewGc.fillStyle = "black";
544
+ previewGc.fillRect(0, 0, previewCanvas.width, previewCanvas.height);
545
+ }
546
+
519
547
  function initialize() {
520
548
  session = new Session(WS_URL);
521
549
  capabilities = null;
@@ -529,6 +557,7 @@
529
557
 
530
558
  setupScreen();
531
559
  setupButtons();
560
+ clearPreviewCanvas();
532
561
 
533
562
  startSession();
534
563
  }
@@ -57,5 +57,12 @@ if (!msgpack || !msgpack.rpc) {
57
57
  return this.remoteCall('save_config');
58
58
  }
59
59
 
60
+ startCamera() {
61
+ return this.remoteCall('start_camera');
62
+ }
63
+
64
+ stopCamera() {
65
+ return this.remoteCall('stop_camera');
66
+ }
60
67
  }
61
68
  })();
@@ -26,7 +26,7 @@
26
26
  <div id="main-area" class="d-flex d-flex-row">
27
27
  <div id="switches">
28
28
  <div class="form-grounp mt-3">
29
- <button id="action" class="btn btn-primary" disabled>STOP</button>
29
+ <button id="action" class="btn btn-primary">STOP</button>
30
30
  </div>
31
31
 
32
32
  <div class="form-grounp mt-3">
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ipcam
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hirosho Kuwagata
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-12 00:00:00.000000000 Z
11
+ date: 2019-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler