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.

211 lines
7.2KB

  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 ComboBoxListener,
  24. private ButtonListener,
  25. private CameraDevice::Listener,
  26. private AsyncUpdater
  27. {
  28. public:
  29. CameraDemo()
  30. : cameraSelectorComboBox ("Camera"),
  31. snapshotButton ("Take a snapshot"),
  32. recordMovieButton ("Record a movie (to your desktop)..."),
  33. recordingMovie (false)
  34. {
  35. setOpaque (true);
  36. addAndMakeVisible (cameraSelectorComboBox);
  37. updateCameraList();
  38. cameraSelectorComboBox.setSelectedId (1);
  39. cameraSelectorComboBox.addListener (this);
  40. addAndMakeVisible (snapshotButton);
  41. snapshotButton.addListener (this);
  42. snapshotButton.setEnabled (false);
  43. addAndMakeVisible (recordMovieButton);
  44. recordMovieButton.addListener (this);
  45. recordMovieButton.setEnabled (false);
  46. addAndMakeVisible (lastSnapshot);
  47. cameraSelectorComboBox.setSelectedId (2);
  48. }
  49. //==============================================================================
  50. void paint (Graphics& g) override
  51. {
  52. g.fillAll (Colours::black);
  53. }
  54. void resized() override
  55. {
  56. Rectangle<int> r (getLocalBounds().reduced (5));
  57. Rectangle<int> top (r.removeFromTop (25));
  58. cameraSelectorComboBox.setBounds (top.removeFromLeft (250));
  59. r.removeFromTop (4);
  60. top = r.removeFromTop (25);
  61. snapshotButton.changeWidthToFitText (24);
  62. snapshotButton.setBounds (top.removeFromLeft (snapshotButton.getWidth()));
  63. top.removeFromLeft (4);
  64. recordMovieButton.changeWidthToFitText (24);
  65. recordMovieButton.setBounds (top.removeFromLeft (recordMovieButton.getWidth()));
  66. r.removeFromTop (4);
  67. Rectangle<int> previewArea (r.removeFromTop (r.getHeight() / 2));
  68. if (cameraPreviewComp != nullptr)
  69. cameraPreviewComp->setBounds (previewArea);
  70. r.removeFromTop (4);
  71. lastSnapshot.setBounds (r);
  72. }
  73. private:
  74. //==============================================================================
  75. ScopedPointer<CameraDevice> cameraDevice;
  76. ScopedPointer<Component> cameraPreviewComp;
  77. ImageComponent lastSnapshot;
  78. ComboBox cameraSelectorComboBox;
  79. TextButton snapshotButton;
  80. TextButton recordMovieButton;
  81. bool recordingMovie;
  82. void updateCameraList()
  83. {
  84. cameraSelectorComboBox.clear();
  85. cameraSelectorComboBox.addItem ("No camera", 1);
  86. cameraSelectorComboBox.addSeparator();
  87. StringArray cameras = CameraDevice::getAvailableDevices();
  88. for (int i = 0; i < cameras.size(); ++i)
  89. cameraSelectorComboBox.addItem (cameras[i], i + 2);
  90. }
  91. void comboBoxChanged (ComboBox*) override
  92. {
  93. // This is called when the user chooses a camera from the drop-down list.
  94. cameraDevice = nullptr;
  95. cameraPreviewComp = nullptr;
  96. recordingMovie = false;
  97. if (cameraSelectorComboBox.getSelectedId() > 1)
  98. {
  99. // Try to open the user's choice of camera..
  100. cameraDevice = CameraDevice::openDevice (cameraSelectorComboBox.getSelectedId() - 2);
  101. // and if it worked, create a preview component for it..
  102. if (cameraDevice != nullptr)
  103. addAndMakeVisible (cameraPreviewComp = cameraDevice->createViewerComponent());
  104. }
  105. snapshotButton.setEnabled (cameraDevice != nullptr);
  106. recordMovieButton.setEnabled (cameraDevice != nullptr);
  107. resized();
  108. }
  109. void buttonClicked (Button* b) override
  110. {
  111. if (cameraDevice != nullptr)
  112. {
  113. if (b == &recordMovieButton)
  114. {
  115. // The user has clicked the record movie button..
  116. if (! recordingMovie)
  117. {
  118. // Start recording to a file on the user's desktop..
  119. recordingMovie = true;
  120. File file (File::getSpecialLocation (File::userDesktopDirectory)
  121. .getNonexistentChildFile ("JuceCameraDemo",
  122. CameraDevice::getFileExtension()));
  123. cameraDevice->startRecordingToFile (file);
  124. recordMovieButton.setButtonText ("Stop Recording");
  125. }
  126. else
  127. {
  128. // Already recording, so stop...
  129. recordingMovie = false;
  130. cameraDevice->stopRecording();
  131. recordMovieButton.setButtonText ("Start recording (to a file on your desktop)");
  132. }
  133. }
  134. else
  135. {
  136. // When the user clicks the snapshot button, we'll attach ourselves to
  137. // the camera as a listener, and wait for an image to arrive...
  138. cameraDevice->addListener (this);
  139. }
  140. }
  141. }
  142. // This is called by the camera device when a new image arrives
  143. void imageReceived (const Image& image) override
  144. {
  145. // In this app we just want to take one image, so as soon as this happens,
  146. // we'll unregister ourselves as a listener.
  147. if (cameraDevice != nullptr)
  148. cameraDevice->removeListener (this);
  149. // This callback won't be on the message thread, so to get the image back to
  150. // the message thread, we'll stash a pointer to it (which is reference-counted in
  151. // a thead-safe way), and trigger an async callback which will then display the
  152. // new image..
  153. incomingImage = image;
  154. triggerAsyncUpdate();
  155. }
  156. Image incomingImage;
  157. void handleAsyncUpdate() override
  158. {
  159. if (incomingImage.isValid())
  160. lastSnapshot.setImage (incomingImage);
  161. }
  162. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CameraDemo)
  163. };
  164. // This static object will register this demo type in a global list of demos..
  165. static JuceDemoType<CameraDemo> demo ("29 Graphics: Camera Capture");
  166. #endif // JUCE_USE_CAMERA