The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

206 lines
6.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. #include "../JuceDemoHeader.h"
  20. #if JUCE_USE_CAMERA
  21. //==============================================================================
  22. class CameraDemo : public Component,
  23. private CameraDevice::Listener,
  24. private AsyncUpdater
  25. {
  26. public:
  27. CameraDemo()
  28. : cameraSelectorComboBox ("Camera"),
  29. snapshotButton ("Take a snapshot"),
  30. recordMovieButton ("Record a movie (to your desktop)..."),
  31. recordingMovie (false)
  32. {
  33. setOpaque (true);
  34. addAndMakeVisible (cameraSelectorComboBox);
  35. updateCameraList();
  36. cameraSelectorComboBox.setSelectedId (1);
  37. cameraSelectorComboBox.onChange = [this] { cameraChanged(); };
  38. addAndMakeVisible (snapshotButton);
  39. snapshotButton.onClick = [this] { takeSnapshot(); };
  40. snapshotButton.setEnabled (false);
  41. addAndMakeVisible (recordMovieButton);
  42. recordMovieButton.onClick = [this] { startRecording(); };
  43. recordMovieButton.setEnabled (false);
  44. addAndMakeVisible (lastSnapshot);
  45. cameraSelectorComboBox.setSelectedId (2);
  46. }
  47. //==============================================================================
  48. void paint (Graphics& g) override
  49. {
  50. g.fillAll (Colours::black);
  51. }
  52. void resized() override
  53. {
  54. auto r = getLocalBounds().reduced (5);
  55. auto top = r.removeFromTop (25);
  56. cameraSelectorComboBox.setBounds (top.removeFromLeft (250));
  57. r.removeFromTop (4);
  58. top = r.removeFromTop (25);
  59. snapshotButton.changeWidthToFitText (24);
  60. snapshotButton.setBounds (top.removeFromLeft (snapshotButton.getWidth()));
  61. top.removeFromLeft (4);
  62. recordMovieButton.changeWidthToFitText (24);
  63. recordMovieButton.setBounds (top.removeFromLeft (recordMovieButton.getWidth()));
  64. r.removeFromTop (4);
  65. auto previewArea = r.removeFromTop (r.getHeight() / 2);
  66. if (cameraPreviewComp != nullptr)
  67. cameraPreviewComp->setBounds (previewArea);
  68. r.removeFromTop (4);
  69. lastSnapshot.setBounds (r);
  70. }
  71. private:
  72. //==============================================================================
  73. ScopedPointer<CameraDevice> cameraDevice;
  74. ScopedPointer<Component> cameraPreviewComp;
  75. ImageComponent lastSnapshot;
  76. ComboBox cameraSelectorComboBox;
  77. TextButton snapshotButton;
  78. TextButton recordMovieButton;
  79. bool recordingMovie;
  80. void updateCameraList()
  81. {
  82. cameraSelectorComboBox.clear();
  83. cameraSelectorComboBox.addItem ("No camera", 1);
  84. cameraSelectorComboBox.addSeparator();
  85. auto cameras = CameraDevice::getAvailableDevices();
  86. for (int i = 0; i < cameras.size(); ++i)
  87. cameraSelectorComboBox.addItem (cameras[i], i + 2);
  88. }
  89. void cameraChanged()
  90. {
  91. // This is called when the user chooses a camera from the drop-down list.
  92. cameraDevice = nullptr;
  93. cameraPreviewComp = nullptr;
  94. recordingMovie = false;
  95. if (cameraSelectorComboBox.getSelectedId() > 1)
  96. {
  97. // Try to open the user's choice of camera..
  98. cameraDevice = CameraDevice::openDevice (cameraSelectorComboBox.getSelectedId() - 2);
  99. // and if it worked, create a preview component for it..
  100. if (cameraDevice != nullptr)
  101. addAndMakeVisible (cameraPreviewComp = cameraDevice->createViewerComponent());
  102. }
  103. snapshotButton.setEnabled (cameraDevice != nullptr);
  104. recordMovieButton.setEnabled (cameraDevice != nullptr);
  105. resized();
  106. }
  107. void startRecording()
  108. {
  109. if (cameraDevice != nullptr)
  110. {
  111. // The user has clicked the record movie button..
  112. if (! recordingMovie)
  113. {
  114. // Start recording to a file on the user's desktop..
  115. recordingMovie = true;
  116. auto file = File::getSpecialLocation (File::userDesktopDirectory)
  117. .getNonexistentChildFile ("JuceCameraDemo", CameraDevice::getFileExtension());
  118. cameraDevice->startRecordingToFile (file);
  119. recordMovieButton.setButtonText ("Stop Recording");
  120. }
  121. else
  122. {
  123. // Already recording, so stop...
  124. recordingMovie = false;
  125. cameraDevice->stopRecording();
  126. recordMovieButton.setButtonText ("Start recording (to a file on your desktop)");
  127. }
  128. }
  129. }
  130. void takeSnapshot()
  131. {
  132. // When the user clicks the snapshot button, we'll attach ourselves to
  133. // the camera as a listener, and wait for an image to arrive...
  134. cameraDevice->addListener (this);
  135. }
  136. // This is called by the camera device when a new image arrives
  137. void imageReceived (const Image& image) override
  138. {
  139. // In this app we just want to take one image, so as soon as this happens,
  140. // we'll unregister ourselves as a listener.
  141. if (cameraDevice != nullptr)
  142. cameraDevice->removeListener (this);
  143. // This callback won't be on the message thread, so to get the image back to
  144. // the message thread, we'll stash a pointer to it (which is reference-counted in
  145. // a thead-safe way), and trigger an async callback which will then display the
  146. // new image..
  147. incomingImage = image;
  148. triggerAsyncUpdate();
  149. }
  150. Image incomingImage;
  151. void handleAsyncUpdate() override
  152. {
  153. if (incomingImage.isValid())
  154. lastSnapshot.setImage (incomingImage);
  155. }
  156. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CameraDemo)
  157. };
  158. // This static object will register this demo type in a global list of demos..
  159. static JuceDemoType<CameraDemo> demo ("29 Graphics: Camera Capture");
  160. #endif // JUCE_USE_CAMERA