@@ -211,64 +211,82 @@ public Thread newThread(Runnable r) {
211211 /**
212212 * Scheduled executor acting as timer.
213213 */
214- private ScheduledExecutorService executor = Executors . newScheduledThreadPool ( 1 , THREAD_FACTORY ) ;
214+ private ScheduledExecutorService executor = null ;
215215
216216 /**
217- * Repainter updates panel when it is being started .
217+ * Image updater reads images from camera and force panel to be repainted .
218218 *
219- * @author Bartosz Firyn (sarxos )
219+ * @author Bartosz Firyn (SarXos )
220220 */
221- private class Repainter extends Thread {
221+ private class ImageUpdater implements Runnable {
222222
223- public Repainter () {
224- setUncaughtExceptionHandler (WebcamExceptionHandler .getInstance ());
225- setName (String .format ("repainter-%s" , webcam .getName ()));
226- setDaemon (true );
227- }
223+ /**
224+ * Repainter updates panel when it is being started.
225+ *
226+ * @author Bartosz Firyn (sarxos)
227+ */
228+ private class RepaintScheduler extends Thread {
228229
229- @ Override
230- public void run () {
230+ public RepaintScheduler () {
231+ setUncaughtExceptionHandler (WebcamExceptionHandler .getInstance ());
232+ setName (String .format ("repaint-scheduler-%s" , webcam .getName ()));
233+ setDaemon (true );
234+ }
231235
232- repaint ();
236+ @ Override
237+ public void run () {
233238
234- while (starting ) {
235- try {
236- Thread .sleep (50 );
237- } catch (InterruptedException e ) {
238- throw new RuntimeException (e );
239+ if (!running .get ()) {
240+ return ;
239241 }
240- }
241242
242- if (webcam .isOpen ()) {
243- if (isFPSLimited ()) {
244- executor .scheduleAtFixedRate (updater , 0 , (long ) (1000 / frequency ), TimeUnit .MILLISECONDS );
243+ repaint ();
244+
245+ while (starting ) {
246+ try {
247+ Thread .sleep (50 );
248+ } catch (InterruptedException e ) {
249+ throw new RuntimeException (e );
250+ }
251+ }
252+
253+ if (webcam .isOpen ()) {
254+ if (isFPSLimited ()) {
255+ executor .scheduleAtFixedRate (updater , 0 , (long ) (1000 / frequency ), TimeUnit .MILLISECONDS );
256+ } else {
257+ executor .scheduleWithFixedDelay (updater , 100 , 1 , TimeUnit .MILLISECONDS );
258+ }
245259 } else {
246- executor .scheduleWithFixedDelay ( updater , 100 , 1 , TimeUnit .MILLISECONDS );
260+ executor .schedule ( this , 500 , TimeUnit .MILLISECONDS );
247261 }
248- } else {
249- executor .schedule (this , 500 , TimeUnit .MILLISECONDS );
250262 }
263+
251264 }
252265
253- }
266+ private Thread scheduler = new RepaintScheduler ();
254267
255- /**
256- * Image updater reads images from camera and force panel to be repainted.
257- *
258- * @author Bartosz Firyn (SarXos)
259- */
260- private class ImageUpdater implements Runnable {
268+ private AtomicBoolean running = new AtomicBoolean (false );
261269
262- public ImageUpdater () {
270+ public void start () {
271+ if (running .compareAndSet (false , true )) {
272+ executor = Executors .newScheduledThreadPool (1 , THREAD_FACTORY );
273+ scheduler .start ();
274+ }
263275 }
264276
265- public void start () {
266- new Repainter ().start ();
277+ public void stop () {
278+ if (running .compareAndSet (true , false )) {
279+ executor .shutdown ();
280+ }
267281 }
268282
269283 @ Override
270284 public void run () {
271285
286+ if (!running .get ()) {
287+ return ;
288+ }
289+
272290 if (!webcam .isOpen ()) {
273291 return ;
274292 }
@@ -333,7 +351,7 @@ public void run() {
333351 * Repainter is used to fetch images from camera and force panel repaint
334352 * when image is ready.
335353 */
336- private volatile ImageUpdater updater = new ImageUpdater () ;
354+ private volatile ImageUpdater updater = null ;
337355
338356 /**
339357 * Webcam is currently starting.
@@ -425,13 +443,7 @@ public WebcamPanel(Webcam webcam, Dimension size, boolean start) {
425443 }
426444
427445 if (start ) {
428- updater .start ();
429- try {
430- errored = !webcam .open ();
431- } catch (WebcamException e ) {
432- errored = true ;
433- throw e ;
434- }
446+ start ();
435447 }
436448 }
437449
@@ -480,9 +492,7 @@ public void webcamOpen(WebcamEvent we) {
480492
481493 @ Override
482494 public void webcamClosed (WebcamEvent we ) {
483- if (updater != null ) {
484- updater = null ;
485- }
495+ stop ();
486496 }
487497
488498 @ Override
@@ -504,6 +514,8 @@ public void start() {
504514 return ;
505515 }
506516
517+ LOG .debug ("Starting panel rendering and trying to open attached webcam" );
518+
507519 starting = true ;
508520
509521 if (updater == null ) {
@@ -526,14 +538,22 @@ public void start() {
526538 * Stop rendering and close webcam.
527539 */
528540 public void stop () {
529- if (started .compareAndSet (true , false )) {
530- image = null ;
531- try {
532- errored = !webcam .close ();
533- } catch (WebcamException e ) {
534- errored = true ;
535- throw e ;
536- }
541+ if (!started .compareAndSet (true , false )) {
542+ return ;
543+ }
544+
545+ LOG .debug ("Stopping panel rendering and closing attached webcam" );
546+
547+ updater .stop ();
548+ updater = null ;
549+
550+ image = null ;
551+
552+ try {
553+ errored = !webcam .close ();
554+ } catch (WebcamException e ) {
555+ errored = true ;
556+ throw e ;
537557 }
538558 }
539559
@@ -544,20 +564,24 @@ public void pause() {
544564 if (paused ) {
545565 return ;
546566 }
567+
568+ LOG .debug ("Pausing panel rendering" );
569+
547570 paused = true ;
548571 }
549572
550573 /**
551574 * Resume rendering.
552575 */
553576 public void resume () {
577+
554578 if (!paused ) {
555579 return ;
556580 }
581+
582+ LOG .debug ("Resuming panel rendering" );
583+
557584 paused = false ;
558- synchronized (updater ) {
559- updater .notifyAll ();
560- }
561585 }
562586
563587 /**
0 commit comments