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.

237 lines
7.7KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  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 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. #if JUCE_MAC
  21. #include "../native/juce_CameraDevice_mac.h"
  22. #elif JUCE_WINDOWS
  23. #include "../native/juce_CameraDevice_windows.h"
  24. #elif JUCE_IOS
  25. #include "../native/juce_CameraDevice_ios.h"
  26. #elif JUCE_ANDROID
  27. #include "../native/juce_CameraDevice_android.h"
  28. #endif
  29. #if JUCE_ANDROID || JUCE_IOS
  30. //==============================================================================
  31. class CameraDevice::CameraFactory
  32. {
  33. public:
  34. static CameraFactory& getInstance()
  35. {
  36. static CameraFactory factory;
  37. return factory;
  38. }
  39. void openCamera (int index, OpenCameraResultCallback resultCallback,
  40. int minWidth, int minHeight, int maxWidth, int maxHeight, bool useHighQuality)
  41. {
  42. auto cameraId = getAvailableDevices()[index];
  43. if (getCameraIndex (cameraId) != -1)
  44. {
  45. // You are trying to open the same camera twice.
  46. jassertfalse;
  47. return;
  48. }
  49. std::unique_ptr<CameraDevice> device (new CameraDevice (cameraId, index,
  50. minWidth, minHeight, maxWidth,
  51. maxHeight, useHighQuality));
  52. camerasToOpen.add ({ nextRequestId++,
  53. std::unique_ptr<CameraDevice> (device.release()),
  54. resultCallback });
  55. auto& pendingOpen = camerasToOpen.getReference (camerasToOpen.size() - 1);
  56. pendingOpen.device->pimpl->open ([this] (const String& deviceId, const String& error)
  57. {
  58. int cIndex = getCameraIndex (deviceId);
  59. if (cIndex == -1)
  60. return;
  61. auto& cameraPendingOpen = camerasToOpen.getReference (cIndex);
  62. if (error.isEmpty())
  63. cameraPendingOpen.resultCallback (cameraPendingOpen.device.release(), error);
  64. else
  65. cameraPendingOpen.resultCallback (nullptr, error);
  66. int id = cameraPendingOpen.requestId;
  67. MessageManager::callAsync ([this, id]() { removeRequestWithId (id); });
  68. });
  69. }
  70. private:
  71. int getCameraIndex (const String& cameraId) const
  72. {
  73. for (int i = 0; i < camerasToOpen.size(); ++i)
  74. {
  75. auto& pendingOpen = camerasToOpen.getReference (i);
  76. if (pendingOpen.device->pimpl->getCameraId() == cameraId)
  77. return i;
  78. }
  79. return -1;
  80. }
  81. void removeRequestWithId (int id)
  82. {
  83. for (int i = camerasToOpen.size(); --i >= 0;)
  84. {
  85. if (camerasToOpen.getReference (i).requestId == id)
  86. {
  87. camerasToOpen.remove (i);
  88. return;
  89. }
  90. }
  91. }
  92. struct PendingCameraOpen
  93. {
  94. int requestId;
  95. std::unique_ptr<CameraDevice> device;
  96. OpenCameraResultCallback resultCallback;
  97. };
  98. Array<PendingCameraOpen> camerasToOpen;
  99. static int nextRequestId;
  100. };
  101. int CameraDevice::CameraFactory::nextRequestId = 0;
  102. #endif
  103. //==============================================================================
  104. CameraDevice::CameraDevice (const String& nm, int index, int minWidth, int minHeight, int maxWidth, int maxHeight, bool useHighQuality)
  105. : name (nm), pimpl (new Pimpl (*this, name, index, minWidth, minHeight, maxWidth, maxHeight, useHighQuality))
  106. {
  107. }
  108. CameraDevice::~CameraDevice()
  109. {
  110. jassert (juce::MessageManager::getInstance()->currentThreadHasLockedMessageManager());
  111. stopRecording();
  112. pimpl.reset();
  113. }
  114. Component* CameraDevice::createViewerComponent()
  115. {
  116. return new ViewerComponent (*this);
  117. }
  118. void CameraDevice::takeStillPicture (std::function<void (const Image&)> pictureTakenCallback)
  119. {
  120. pimpl->takeStillPicture (pictureTakenCallback);
  121. }
  122. void CameraDevice::startRecordingToFile (const File& file, int quality)
  123. {
  124. stopRecording();
  125. pimpl->startRecordingToFile (file, quality);
  126. }
  127. Time CameraDevice::getTimeOfFirstRecordedFrame() const
  128. {
  129. return pimpl->getTimeOfFirstRecordedFrame();
  130. }
  131. void CameraDevice::stopRecording()
  132. {
  133. pimpl->stopRecording();
  134. }
  135. void CameraDevice::addListener (Listener* listenerToAdd)
  136. {
  137. if (listenerToAdd != nullptr)
  138. pimpl->addListener (listenerToAdd);
  139. }
  140. void CameraDevice::removeListener (Listener* listenerToRemove)
  141. {
  142. if (listenerToRemove != nullptr)
  143. pimpl->removeListener (listenerToRemove);
  144. }
  145. //==============================================================================
  146. StringArray CameraDevice::getAvailableDevices()
  147. {
  148. JUCE_AUTORELEASEPOOL
  149. {
  150. return Pimpl::getAvailableDevices();
  151. }
  152. }
  153. CameraDevice* CameraDevice::openDevice ([[maybe_unused]] int index,
  154. [[maybe_unused]] int minWidth, [[maybe_unused]] int minHeight,
  155. [[maybe_unused]] int maxWidth, [[maybe_unused]] int maxHeight,
  156. [[maybe_unused]] bool useHighQuality)
  157. {
  158. jassert (juce::MessageManager::getInstance()->currentThreadHasLockedMessageManager());
  159. #if ! JUCE_ANDROID && ! JUCE_IOS
  160. std::unique_ptr<CameraDevice> d (new CameraDevice (getAvailableDevices() [index], index,
  161. minWidth, minHeight, maxWidth, maxHeight, useHighQuality));
  162. if (d != nullptr && d->pimpl->openedOk())
  163. return d.release();
  164. #else
  165. // Use openDeviceAsync to open a camera device on iOS or Android.
  166. jassertfalse;
  167. #endif
  168. return nullptr;
  169. }
  170. void CameraDevice::openDeviceAsync (int index, OpenCameraResultCallback resultCallback,
  171. int minWidth, int minHeight, int maxWidth, int maxHeight, bool useHighQuality)
  172. {
  173. jassert (juce::MessageManager::getInstance()->currentThreadHasLockedMessageManager());
  174. if (resultCallback == nullptr)
  175. {
  176. // A valid callback must be passed.
  177. jassertfalse;
  178. return;
  179. }
  180. #if JUCE_ANDROID || JUCE_IOS
  181. CameraFactory::getInstance().openCamera (index, std::move (resultCallback),
  182. minWidth, minHeight, maxWidth, maxHeight, useHighQuality);
  183. #else
  184. auto* device = openDevice (index, minWidth, minHeight, maxWidth, maxHeight, useHighQuality);
  185. resultCallback (device, device != nullptr ? String() : "Could not open camera device");
  186. #endif
  187. }
  188. } // namespace juce