1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/video_engine/vie_input_manager.h"
12
13 #include <assert.h>
14
15 #include "webrtc/common_types.h"
16 #include "webrtc/modules/video_capture/include/video_capture_factory.h"
17 #include "webrtc/modules/video_coding/main/interface/video_coding.h"
18 #include "webrtc/modules/video_coding/main/interface/video_coding_defines.h"
19 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
20 #include "webrtc/system_wrappers/interface/logging.h"
21 #include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
22 #include "webrtc/video_engine/include/vie_errors.h"
23 #include "webrtc/video_engine/vie_capturer.h"
24 #include "webrtc/video_engine/vie_defines.h"
25
26 namespace webrtc {
27
ViEInputManager(const int engine_id,const Config & config)28 ViEInputManager::ViEInputManager(const int engine_id, const Config& config)
29 : config_(config),
30 engine_id_(engine_id),
31 map_cs_(CriticalSectionWrapper::CreateCriticalSection()),
32 device_info_cs_(CriticalSectionWrapper::CreateCriticalSection()),
33 vie_frame_provider_map_(),
34 capture_device_info_(NULL),
35 module_process_thread_(NULL) {
36 for (int idx = 0; idx < kViEMaxCaptureDevices; idx++) {
37 free_capture_device_id_[idx] = true;
38 }
39 }
40
~ViEInputManager()41 ViEInputManager::~ViEInputManager() {
42 for (FrameProviderMap::iterator it = vie_frame_provider_map_.begin();
43 it != vie_frame_provider_map_.end();
44 ++it) {
45 delete it->second;
46 }
47
48 delete capture_device_info_;
49 }
SetModuleProcessThread(ProcessThread * module_process_thread)50 void ViEInputManager::SetModuleProcessThread(
51 ProcessThread* module_process_thread) {
52 assert(!module_process_thread_);
53 module_process_thread_ = module_process_thread;
54 }
55
NumberOfCaptureDevices()56 int ViEInputManager::NumberOfCaptureDevices() {
57 CriticalSectionScoped cs(device_info_cs_.get());
58 if (capture_device_info_ == NULL)
59 capture_device_info_ = VideoCaptureFactory::CreateDeviceInfo(
60 ViEModuleId(engine_id_));
61 assert(capture_device_info_);
62 return capture_device_info_->NumberOfDevices();
63 }
64
GetDeviceName(uint32_t device_number,char * device_nameUTF8,uint32_t device_name_length,char * device_unique_idUTF8,uint32_t device_unique_idUTF8Length)65 int ViEInputManager::GetDeviceName(uint32_t device_number,
66 char* device_nameUTF8,
67 uint32_t device_name_length,
68 char* device_unique_idUTF8,
69 uint32_t device_unique_idUTF8Length) {
70 CriticalSectionScoped cs(device_info_cs_.get());
71 if (capture_device_info_ == NULL)
72 capture_device_info_ = VideoCaptureFactory::CreateDeviceInfo(
73 ViEModuleId(engine_id_));
74 assert(capture_device_info_);
75 return capture_device_info_->GetDeviceName(device_number, device_nameUTF8,
76 device_name_length,
77 device_unique_idUTF8,
78 device_unique_idUTF8Length);
79 }
80
NumberOfCaptureCapabilities(const char * device_unique_idUTF8)81 int ViEInputManager::NumberOfCaptureCapabilities(
82 const char* device_unique_idUTF8) {
83 CriticalSectionScoped cs(device_info_cs_.get());
84 if (capture_device_info_ == NULL)
85 capture_device_info_ = VideoCaptureFactory::CreateDeviceInfo(
86 ViEModuleId(engine_id_));
87 assert(capture_device_info_);
88 return capture_device_info_->NumberOfCapabilities(device_unique_idUTF8);
89 }
90
GetCaptureCapability(const char * device_unique_idUTF8,const uint32_t device_capability_number,CaptureCapability & capability)91 int ViEInputManager::GetCaptureCapability(
92 const char* device_unique_idUTF8,
93 const uint32_t device_capability_number,
94 CaptureCapability& capability) {
95 CriticalSectionScoped cs(device_info_cs_.get());
96 if (capture_device_info_ == NULL)
97 capture_device_info_ = VideoCaptureFactory::CreateDeviceInfo(
98 ViEModuleId(engine_id_));
99 assert(capture_device_info_);
100 VideoCaptureCapability module_capability;
101 int result = capture_device_info_->GetCapability(device_unique_idUTF8,
102 device_capability_number,
103 module_capability);
104 if (result != 0)
105 return result;
106
107 // Copy from module type to public type.
108 capability.expectedCaptureDelay = module_capability.expectedCaptureDelay;
109 capability.height = module_capability.height;
110 capability.width = module_capability.width;
111 capability.interlaced = module_capability.interlaced;
112 capability.rawType = module_capability.rawType;
113 capability.codecType = module_capability.codecType;
114 capability.maxFPS = module_capability.maxFPS;
115 return result;
116 }
117
GetOrientation(const char * device_unique_idUTF8,RotateCapturedFrame & orientation)118 int ViEInputManager::GetOrientation(const char* device_unique_idUTF8,
119 RotateCapturedFrame& orientation) {
120 CriticalSectionScoped cs(device_info_cs_.get());
121 if (capture_device_info_ == NULL)
122 capture_device_info_ = VideoCaptureFactory::CreateDeviceInfo(
123 ViEModuleId(engine_id_));
124 assert(capture_device_info_);
125 VideoCaptureRotation module_orientation;
126 int result = capture_device_info_->GetOrientation(device_unique_idUTF8,
127 module_orientation);
128 // Copy from module type to public type.
129 switch (module_orientation) {
130 case kCameraRotate0:
131 orientation = RotateCapturedFrame_0;
132 break;
133 case kCameraRotate90:
134 orientation = RotateCapturedFrame_90;
135 break;
136 case kCameraRotate180:
137 orientation = RotateCapturedFrame_180;
138 break;
139 case kCameraRotate270:
140 orientation = RotateCapturedFrame_270;
141 break;
142 }
143 return result;
144 }
145
DisplayCaptureSettingsDialogBox(const char * device_unique_idUTF8,const char * dialog_titleUTF8,void * parent_window,uint32_t positionX,uint32_t positionY)146 int ViEInputManager::DisplayCaptureSettingsDialogBox(
147 const char* device_unique_idUTF8,
148 const char* dialog_titleUTF8,
149 void* parent_window,
150 uint32_t positionX,
151 uint32_t positionY) {
152 CriticalSectionScoped cs(device_info_cs_.get());
153 if (capture_device_info_ == NULL)
154 capture_device_info_ = VideoCaptureFactory::CreateDeviceInfo(
155 ViEModuleId(engine_id_));
156 assert(capture_device_info_);
157 return capture_device_info_->DisplayCaptureSettingsDialogBox(
158 device_unique_idUTF8, dialog_titleUTF8, parent_window, positionX,
159 positionY);
160 }
161
CreateCaptureDevice(const char * device_unique_idUTF8,const uint32_t device_unique_idUTF8Length,int & capture_id)162 int ViEInputManager::CreateCaptureDevice(
163 const char* device_unique_idUTF8,
164 const uint32_t device_unique_idUTF8Length,
165 int& capture_id) {
166 CriticalSectionScoped cs(map_cs_.get());
167
168 // Make sure the device is not already allocated.
169 for (FrameProviderMap::iterator it = vie_frame_provider_map_.begin();
170 it != vie_frame_provider_map_.end();
171 ++it) {
172 // Make sure this is a capture device.
173 if (it->first >= kViECaptureIdBase && it->first <= kViECaptureIdMax) {
174 ViECapturer* vie_capture = static_cast<ViECapturer*>(it->second);
175 assert(vie_capture);
176 // TODO(mflodman) Can we change input to avoid this cast?
177 const char* device_name =
178 reinterpret_cast<const char*>(vie_capture->CurrentDeviceName());
179 if (strncmp(device_name, device_unique_idUTF8,
180 strlen(device_name)) == 0) {
181 return kViECaptureDeviceAlreadyAllocated;
182 }
183 }
184 }
185
186 // Make sure the device name is valid.
187 bool found_device = false;
188 CriticalSectionScoped cs_devinfo(device_info_cs_.get());
189 if (capture_device_info_ == NULL)
190 capture_device_info_ = VideoCaptureFactory::CreateDeviceInfo(
191 ViEModuleId(engine_id_));
192 assert(capture_device_info_);
193 for (uint32_t device_index = 0;
194 device_index < capture_device_info_->NumberOfDevices(); ++device_index) {
195 if (device_unique_idUTF8Length > kVideoCaptureUniqueNameLength) {
196 // User's string length is longer than the max.
197 return -1;
198 }
199
200 char found_name[kVideoCaptureDeviceNameLength] = "";
201 char found_unique_name[kVideoCaptureUniqueNameLength] = "";
202 capture_device_info_->GetDeviceName(device_index, found_name,
203 kVideoCaptureDeviceNameLength,
204 found_unique_name,
205 kVideoCaptureUniqueNameLength);
206
207 // TODO(mflodman) Can we change input to avoid this cast?
208 const char* cast_id = reinterpret_cast<const char*>(device_unique_idUTF8);
209 if (strncmp(cast_id, reinterpret_cast<const char*>(found_unique_name),
210 strlen(cast_id)) == 0) {
211 found_device = true;
212 break;
213 }
214 }
215 if (!found_device) {
216 LOG(LS_ERROR) << "Capture device not found: " << device_unique_idUTF8;
217 return kViECaptureDeviceDoesNotExist;
218 }
219
220 int newcapture_id = 0;
221 if (!GetFreeCaptureId(&newcapture_id)) {
222 LOG(LS_ERROR) << "All capture devices already allocated.";
223 return kViECaptureDeviceMaxNoDevicesAllocated;
224 }
225 ViECapturer* vie_capture = ViECapturer::CreateViECapture(
226 newcapture_id, engine_id_, config_, device_unique_idUTF8,
227 device_unique_idUTF8Length, *module_process_thread_);
228 if (!vie_capture) {
229 ReturnCaptureId(newcapture_id);
230 return kViECaptureDeviceUnknownError;
231 }
232
233 vie_frame_provider_map_[newcapture_id] = vie_capture;
234 capture_id = newcapture_id;
235 return 0;
236 }
237
CreateCaptureDevice(VideoCaptureModule * capture_module,int & capture_id)238 int ViEInputManager::CreateCaptureDevice(VideoCaptureModule* capture_module,
239 int& capture_id) {
240 CriticalSectionScoped cs(map_cs_.get());
241 int newcapture_id = 0;
242 if (!GetFreeCaptureId(&newcapture_id)) {
243 LOG(LS_ERROR) << "All capture devices already allocated.";
244 return kViECaptureDeviceMaxNoDevicesAllocated;
245 }
246
247 ViECapturer* vie_capture = ViECapturer::CreateViECapture(
248 newcapture_id, engine_id_, config_,
249 capture_module, *module_process_thread_);
250 if (!vie_capture) {
251 ReturnCaptureId(newcapture_id);
252 return kViECaptureDeviceUnknownError;
253 }
254 vie_frame_provider_map_[newcapture_id] = vie_capture;
255 capture_id = newcapture_id;
256 return 0;
257 }
258
DestroyCaptureDevice(const int capture_id)259 int ViEInputManager::DestroyCaptureDevice(const int capture_id) {
260 ViECapturer* vie_capture = NULL;
261 {
262 // We need exclusive access to the object to delete it.
263 // Take this write lock first since the read lock is taken before map_cs_.
264 ViEManagerWriteScoped wl(this);
265 CriticalSectionScoped cs(map_cs_.get());
266
267 vie_capture = ViECapturePtr(capture_id);
268 if (!vie_capture) {
269 LOG(LS_ERROR) << "No such capture device id: " << capture_id;
270 return -1;
271 }
272 uint32_t num_callbacks =
273 vie_capture->NumberOfRegisteredFrameCallbacks();
274 if (num_callbacks > 0) {
275 LOG(LS_WARNING) << num_callbacks << " still registered to capture id "
276 << capture_id << " when destroying capture device.";
277 }
278 vie_frame_provider_map_.erase(capture_id);
279 ReturnCaptureId(capture_id);
280 // Leave cs before deleting the capture object. This is because deleting the
281 // object might cause deletions of renderers so we prefer to not have a lock
282 // at that time.
283 }
284 delete vie_capture;
285 return 0;
286 }
287
CreateExternalCaptureDevice(ViEExternalCapture * & external_capture,int & capture_id)288 int ViEInputManager::CreateExternalCaptureDevice(
289 ViEExternalCapture*& external_capture,
290 int& capture_id) {
291 CriticalSectionScoped cs(map_cs_.get());
292
293 int newcapture_id = 0;
294 if (GetFreeCaptureId(&newcapture_id) == false) {
295 LOG(LS_ERROR) << "All capture devices already allocated.";
296 return kViECaptureDeviceMaxNoDevicesAllocated;
297 }
298
299 ViECapturer* vie_capture = ViECapturer::CreateViECapture(
300 newcapture_id, engine_id_, config_, NULL, 0, *module_process_thread_);
301 if (!vie_capture) {
302 ReturnCaptureId(newcapture_id);
303 return kViECaptureDeviceUnknownError;
304 }
305
306 vie_frame_provider_map_[newcapture_id] = vie_capture;
307 capture_id = newcapture_id;
308 external_capture = vie_capture;
309 return 0;
310 }
311
GetFreeCaptureId(int * freecapture_id)312 bool ViEInputManager::GetFreeCaptureId(int* freecapture_id) {
313 for (int id = 0; id < kViEMaxCaptureDevices; id++) {
314 if (free_capture_device_id_[id]) {
315 // We found a free capture device id.
316 free_capture_device_id_[id] = false;
317 *freecapture_id = id + kViECaptureIdBase;
318 return true;
319 }
320 }
321 return false;
322 }
323
ReturnCaptureId(int capture_id)324 void ViEInputManager::ReturnCaptureId(int capture_id) {
325 CriticalSectionScoped cs(map_cs_.get());
326 if (capture_id >= kViECaptureIdBase &&
327 capture_id < kViEMaxCaptureDevices + kViECaptureIdBase) {
328 free_capture_device_id_[capture_id - kViECaptureIdBase] = true;
329 }
330 return;
331 }
332
ViEFrameProvider(const ViEFrameCallback * capture_observer) const333 ViEFrameProviderBase* ViEInputManager::ViEFrameProvider(
334 const ViEFrameCallback* capture_observer) const {
335 assert(capture_observer);
336 CriticalSectionScoped cs(map_cs_.get());
337
338 for (FrameProviderMap::const_iterator it = vie_frame_provider_map_.begin();
339 it != vie_frame_provider_map_.end();
340 ++it) {
341 if (it->second->IsFrameCallbackRegistered(capture_observer))
342 return it->second;
343 }
344
345 // No capture device set for this channel.
346 return NULL;
347 }
348
ViEFrameProvider(int provider_id) const349 ViEFrameProviderBase* ViEInputManager::ViEFrameProvider(int provider_id) const {
350 CriticalSectionScoped cs(map_cs_.get());
351
352 FrameProviderMap::const_iterator it =
353 vie_frame_provider_map_.find(provider_id);
354 if (it == vie_frame_provider_map_.end())
355 return NULL;
356 return it->second;
357 }
358
ViECapturePtr(int capture_id) const359 ViECapturer* ViEInputManager::ViECapturePtr(int capture_id) const {
360 if (!(capture_id >= kViECaptureIdBase &&
361 capture_id <= kViECaptureIdBase + kViEMaxCaptureDevices)) {
362 LOG(LS_ERROR) << "Capture device doesn't exist " << capture_id << ".";
363 return NULL;
364 }
365
366 return static_cast<ViECapturer*>(ViEFrameProvider(capture_id));
367 }
368
ViEInputManagerScoped(const ViEInputManager & vie_input_manager)369 ViEInputManagerScoped::ViEInputManagerScoped(
370 const ViEInputManager& vie_input_manager)
371 : ViEManagerScopedBase(vie_input_manager) {
372 }
373
Capture(int capture_id) const374 ViECapturer* ViEInputManagerScoped::Capture(int capture_id) const {
375 return static_cast<const ViEInputManager*>(vie_manager_)->ViECapturePtr(
376 capture_id);
377 }
378
FrameProvider(const ViEFrameCallback * capture_observer) const379 ViEFrameProviderBase* ViEInputManagerScoped::FrameProvider(
380 const ViEFrameCallback* capture_observer) const {
381 return static_cast<const ViEInputManager*>(vie_manager_)->ViEFrameProvider(
382 capture_observer);
383 }
384
FrameProvider(int provider_id) const385 ViEFrameProviderBase* ViEInputManagerScoped::FrameProvider(
386 int provider_id) const {
387 return static_cast<const ViEInputManager*>(vie_manager_)->ViEFrameProvider(
388 provider_id);
389 }
390
391 } // namespace webrtc
392