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.

209 lines
7.2KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #include "../JuceDemoHeader.h"
  18. #if JUCE_USE_CAMERA
  19. //==============================================================================
  20. class CameraDemo : public Component,
  21. private ComboBoxListener,
  22. private ButtonListener,
  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.addListener (this);
  38. addAndMakeVisible (snapshotButton);
  39. snapshotButton.addListener (this);
  40. snapshotButton.setEnabled (false);
  41. addAndMakeVisible (recordMovieButton);
  42. recordMovieButton.addListener (this);
  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. Rectangle<int> r (getLocalBounds().reduced (5));
  55. Rectangle<int> 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. Rectangle<int> 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. StringArray cameras = CameraDevice::getAvailableDevices();
  86. for (int i = 0; i < cameras.size(); ++i)
  87. cameraSelectorComboBox.addItem (cameras[i], i + 2);
  88. }
  89. void comboBoxChanged (ComboBox*) override
  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 buttonClicked (Button* b) override
  108. {
  109. if (cameraDevice != nullptr)
  110. {
  111. if (b == &recordMovieButton)
  112. {
  113. // The user has clicked the record movie button..
  114. if (! recordingMovie)
  115. {
  116. // Start recording to a file on the user's desktop..
  117. recordingMovie = true;
  118. File file (File::getSpecialLocation (File::userDesktopDirectory)
  119. .getNonexistentChildFile ("JuceCameraDemo",
  120. CameraDevice::getFileExtension()));
  121. cameraDevice->startRecordingToFile (file);
  122. recordMovieButton.setButtonText ("Stop Recording");
  123. }
  124. else
  125. {
  126. // Already recording, so stop...
  127. recordingMovie = false;
  128. cameraDevice->stopRecording();
  129. recordMovieButton.setButtonText ("Start recording (to a file on your desktop)");
  130. }
  131. }
  132. else
  133. {
  134. // When the user clicks the snapshot button, we'll attach ourselves to
  135. // the camera as a listener, and wait for an image to arrive...
  136. cameraDevice->addListener (this);
  137. }
  138. }
  139. }
  140. // This is called by the camera device when a new image arrives
  141. void imageReceived (const Image& image) override
  142. {
  143. // In this app we just want to take one image, so as soon as this happens,
  144. // we'll unregister ourselves as a listener.
  145. if (cameraDevice != nullptr)
  146. cameraDevice->removeListener (this);
  147. // This callback won't be on the message thread, so to get the image back to
  148. // the message thread, we'll stash a pointer to it (which is reference-counted in
  149. // a thead-safe way), and trigger an async callback which will then display the
  150. // new image..
  151. incomingImage = image;
  152. triggerAsyncUpdate();
  153. }
  154. Image incomingImage;
  155. void handleAsyncUpdate() override
  156. {
  157. if (incomingImage.isValid())
  158. lastSnapshot.setImage (incomingImage);
  159. }
  160. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CameraDemo)
  161. };
  162. // This static object will register this demo type in a global list of demos..
  163. static JuceDemoType<CameraDemo> demo ("29 Graphics: Camera Capture");
  164. #endif // JUCE_USE_CAMERA