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.

244 lines
7.9KB

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