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.

250 lines
7.9KB

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