ipcam 0.2.1 → 0.3.2

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 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