| /* |
| * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| /* |
| * video_capture_quick_time_info.cc |
| * |
| */ |
| |
| #include "../../video_capture_config.h" |
| #include "video_capture_quick_time_info.h" |
| |
| #include "critical_section_wrapper.h" |
| #include "event_wrapper.h" |
| #include "thread_wrapper.h" |
| #include "trace.h" |
| #include "video_capture.h" |
| |
| namespace webrtc |
| { |
| |
| VideoCaptureMacQuickTimeInfo::VideoCaptureMacQuickTimeInfo( |
| const WebRtc_Word32 iID) : |
| DeviceInfoImpl(iID), _id(iID), |
| _grabberCritsect(CriticalSectionWrapper::CreateCriticalSection()) |
| { |
| WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCapture, _id, |
| "%s:%d", __FUNCTION__, __LINE__); |
| } |
| |
| VideoCaptureMacQuickTimeInfo::~VideoCaptureMacQuickTimeInfo() |
| { |
| WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCapture, _id, |
| "%s:%d", __FUNCTION__, __LINE__); |
| } |
| |
| WebRtc_Word32 VideoCaptureMacQuickTimeInfo::Init() |
| { |
| |
| WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCapture, _id, |
| "%s:%d", __FUNCTION__, __LINE__); |
| return 0; |
| } |
| |
| WebRtc_UWord32 VideoCaptureMacQuickTimeInfo::NumberOfDevices() |
| { |
| WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCapture, _id, |
| "%s:%d", __FUNCTION__, __LINE__); |
| int numOfDevices = 0; |
| |
| // don't care about these variables... dummy vars to call GetCaptureDevices |
| const int kNameLength = 1024; |
| WebRtc_UWord8 deviceNameUTF8[kNameLength] = ""; |
| WebRtc_UWord8 deviceUniqueIdUTF8[kNameLength] = ""; |
| WebRtc_UWord8 productUniqueIdUTF8[kNameLength] = ""; |
| |
| if (GetCaptureDevices(0, deviceNameUTF8, kNameLength, deviceUniqueIdUTF8, |
| kNameLength, productUniqueIdUTF8, kNameLength, |
| numOfDevices) != 0) |
| { |
| return 0; |
| } |
| |
| return numOfDevices; |
| } |
| |
| WebRtc_Word32 VideoCaptureMacQuickTimeInfo::GetDeviceName( |
| WebRtc_UWord32 deviceNumber, WebRtc_UWord8* deviceNameUTF8, |
| WebRtc_UWord32 deviceNameUTF8Length, WebRtc_UWord8* deviceUniqueIdUTF8, |
| WebRtc_UWord32 deviceUniqueIdUTF8Length, WebRtc_UWord8* productUniqueIdUTF8, |
| WebRtc_UWord32 productUniqueIdUTF8Length) |
| { |
| WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCapture, _id, |
| "%s:%d deviceNumber=\%d", __FUNCTION__, __LINE__); |
| |
| int numOfDevices = 0; // not needed for this function |
| return GetCaptureDevices(deviceNumber, deviceNameUTF8, |
| deviceNameUTF8Length, deviceUniqueIdUTF8, |
| deviceUniqueIdUTF8Length, productUniqueIdUTF8, |
| productUniqueIdUTF8Length, numOfDevices); |
| } |
| |
| WebRtc_Word32 VideoCaptureMacQuickTimeInfo::NumberOfCapabilities( |
| const WebRtc_UWord8* deviceUniqueIdUTF8) |
| { |
| WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCapture, 0, |
| "%s:%d", __FUNCTION__, __LINE__); |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, |
| "NumberOfCapabilities is not supported on the Mac platform."); |
| return -1; |
| } |
| |
| WebRtc_Word32 VideoCaptureMacQuickTimeInfo::GetCapability( |
| const WebRtc_UWord8* deviceUniqueIdUTF8, |
| const WebRtc_UWord32 deviceCapabilityNumber, |
| VideoCaptureCapability& capability) |
| { |
| WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCapture, 0, |
| "%s:%d", __FUNCTION__, __LINE__); |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, |
| "NumberOfCapabilities is not supported on the Mac platform."); |
| return -1; |
| } |
| |
| WebRtc_Word32 VideoCaptureMacQuickTimeInfo::GetBestMatchedCapability( |
| const WebRtc_UWord8*deviceUniqueIdUTF8, |
| const VideoCaptureCapability requested, VideoCaptureCapability& resulting) |
| { |
| WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id, |
| "NumberOfCapabilities is not supported on the Mac platform."); |
| return -1; |
| } |
| |
| WebRtc_Word32 VideoCaptureMacQuickTimeInfo::DisplayCaptureSettingsDialogBox( |
| const WebRtc_UWord8* deviceUniqueIdUTF8, |
| const WebRtc_UWord8* dialogTitleUTF8, void* parentWindow, |
| WebRtc_UWord32 positionX, WebRtc_UWord32 positionY) |
| { |
| WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCapture, 0, |
| "%s:%d", __FUNCTION__, __LINE__); |
| return -1; |
| } |
| |
| WebRtc_Word32 VideoCaptureMacQuickTimeInfo::CreateCapabilityMap( |
| const WebRtc_UWord8* deviceUniqueIdUTF8) |
| { |
| WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCapture, 0, |
| "%s:%d", __FUNCTION__, __LINE__); |
| WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id, |
| "NumberOfCapabilities is not supported on the Mac platform."); |
| return -1; |
| } |
| |
| int VideoCaptureMacQuickTimeInfo::GetCaptureDevices( |
| WebRtc_UWord32 deviceNumber, WebRtc_UWord8* deviceNameUTF8, |
| WebRtc_UWord32 deviceNameUTF8Length, WebRtc_UWord8* deviceUniqueIdUTF8, |
| WebRtc_UWord32 deviceUniqueIdUTF8Length, WebRtc_UWord8* productUniqueIdUTF8, |
| WebRtc_UWord32 productUniqueIdUTF8Length, int& numberOfDevices) |
| { |
| |
| WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCapture, 0, |
| "%s(wrapped):%d deviceNumber: %d", __FUNCTION__, __LINE__, |
| deviceNumber); |
| |
| numberOfDevices = 0; |
| memset(deviceNameUTF8, 0, deviceNameUTF8Length); |
| memset(deviceUniqueIdUTF8, 0, deviceUniqueIdUTF8Length); |
| memset(productUniqueIdUTF8, 0, productUniqueIdUTF8Length); |
| |
| if (deviceNumber < 0) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, |
| "%s:%d Invalid deviceNumber", __FUNCTION__, __LINE__); |
| return -1; |
| } |
| |
| Component captureDevice = NULL; |
| SeqGrabComponent captureGrabber = NULL; |
| SGChannel captureChannel = NULL; |
| bool closeChannel = false; |
| |
| ComponentDescription compCaptureType; |
| |
| compCaptureType.componentType = SeqGrabComponentType; |
| compCaptureType.componentSubType = 0; |
| compCaptureType.componentManufacturer = 0; |
| compCaptureType.componentFlags = 0; |
| compCaptureType.componentFlagsMask = 0; |
| |
| // Get the number of sequence grabbers |
| long numSequenceGrabbers = CountComponents(&compCaptureType); |
| |
| if (deviceNumber > numSequenceGrabbers) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, |
| "%s:%d Invalid deviceNumber", __FUNCTION__, __LINE__); |
| return -1; |
| } |
| |
| if (numSequenceGrabbers <= 0) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, |
| "%s:%d No sequence grabbers available", __FUNCTION__, |
| __LINE__); |
| return -1; |
| } |
| |
| // Open a sequence grabber |
| for (int seqGrabberIndex = 0; |
| seqGrabberIndex < numSequenceGrabbers; |
| seqGrabberIndex++) |
| { |
| captureDevice = FindNextComponent(0, &compCaptureType); |
| captureGrabber = OpenComponent(captureDevice); |
| if (captureGrabber != NULL) |
| { |
| // We've found a sequencegrabber |
| if (SGInitialize(captureGrabber) != noErr) |
| { |
| CloseComponent(captureGrabber); |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, |
| _id, "%s:%d Could not init the sequence grabber", |
| __FUNCTION__, __LINE__); |
| return -1; |
| } |
| break; |
| } |
| if (seqGrabberIndex == numSequenceGrabbers - 1) |
| { |
| // Couldn't open a sequence grabber |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, |
| "%s:%d Could not open a sequence grabber", |
| __FUNCTION__, __LINE__); |
| return -1; |
| } |
| } |
| |
| // Create a temporary channel to get the names of the capture devices. |
| // Takes time, make this in a nother way... |
| if (SGNewChannel(captureGrabber, VideoMediaType, &captureChannel) != noErr) |
| { |
| // Could not create a video channel... |
| SGRelease(captureGrabber); |
| CloseComponent(captureGrabber); |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, |
| "%s:%d Could not create a sequence grabber video channel", |
| __FUNCTION__, __LINE__); |
| return -1; |
| } |
| closeChannel = true; |
| |
| // Find the type of capture devices, e.g. USB-devices, Firewire, DV, ... |
| SGDeviceList deviceList = NULL; |
| if (SGGetChannelDeviceList(captureChannel, sgDeviceListIncludeInputs, |
| &deviceList) != noErr) |
| { |
| if (closeChannel) |
| SGDisposeChannel(captureGrabber, captureChannel); |
| if (captureGrabber) |
| { |
| SGRelease(captureGrabber); |
| CloseComponent(captureGrabber); |
| } |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, |
| "%s:%d Could not create a device list", __FUNCTION__, |
| __LINE__); |
| return -1; |
| } |
| |
| // Loop through all device types and all devices for each type |
| // and store in a list. |
| int numDevices = (*deviceList)->count; |
| WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, _id, |
| "%s:%d Found %d devices", __FUNCTION__, __LINE__, numDevices); |
| |
| for (int i = 0; i < numDevices; i++) |
| { |
| |
| SGDeviceName sgDeviceName = (*deviceList)->entry[i]; |
| // Get the list with input devices for this type of device |
| if (sgDeviceName.inputs) |
| { |
| SGDeviceInputList inputList = sgDeviceName.inputs; |
| int numInputDev = (*inputList)->count; |
| |
| for (int inputDevIndex = 0; |
| inputDevIndex < numInputDev; |
| inputDevIndex++) |
| { |
| // Get the name for this capture device |
| SGDeviceInputName deviceInputName = |
| (*inputList)->entry[inputDevIndex]; |
| |
| VideoCaptureMacName* deviceName = new VideoCaptureMacName(); |
| |
| deviceName->_size = PascalStringToCString( |
| deviceInputName.name, deviceName->_name, |
| sizeof(deviceName->_name)); |
| |
| if (deviceName->_size > 0) |
| { |
| WEBRTC_TRACE(webrtc::kTraceDebug,webrtc::kTraceVideoCapture, |
| _id, |
| "%s:%d Capture device %d: %s was successfully " |
| "set", __FUNCTION__, __LINE__, numberOfDevices, |
| deviceName->_name); |
| |
| if (numberOfDevices == deviceNumber) |
| { |
| strcpy((char*) deviceNameUTF8, deviceName->_name); |
| strcpy((char*) deviceUniqueIdUTF8, deviceName->_name); |
| } |
| numberOfDevices++; |
| } |
| else |
| { |
| delete deviceName; |
| |
| if (deviceName->_size < 0) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, |
| webrtc::kTraceVideoCapture, _id, |
| "%s:%d Error in PascalStringToCString", |
| __FUNCTION__, __LINE__); |
| return -1; |
| } |
| } |
| } |
| } |
| } |
| |
| // clean up |
| SGDisposeDeviceList(captureGrabber, deviceList); |
| if (closeChannel) |
| { |
| SGDisposeChannel(captureGrabber, captureChannel); |
| } |
| if (captureGrabber) |
| { |
| SGRelease(captureGrabber); |
| CloseComponent(captureGrabber); |
| } |
| |
| WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, _id, |
| "%s:%d End function successfully", __FUNCTION__, __LINE__); |
| return 0; |
| } |
| |
| /** |
| Convert a Pascal string to a C string. |
| |
| \param[in] pascalString |
| Pascal string to convert. Pascal strings contain the number of |
| characters in the first byte and are not null-terminated. |
| |
| \param[out] cString |
| The C string buffer into which to copy the converted string. |
| |
| \param[in] bufferSize |
| The size of the C string buffer in bytes. |
| |
| \return The number of characters in the string on success and -1 on failure. |
| */ |
| CFIndex VideoCaptureMacQuickTimeInfo::PascalStringToCString( |
| const unsigned char* pascalString, char* cString, CFIndex bufferSize) |
| { |
| if (pascalString == NULL) |
| { |
| return -1; |
| } |
| |
| if (cString == NULL) |
| { |
| return -1; |
| } |
| |
| if (bufferSize == 0) |
| { |
| return -1; |
| } |
| |
| CFIndex cStringLength = 0; |
| CFIndex maxStringLength = bufferSize - 1; |
| |
| CFStringRef cfString = CFStringCreateWithPascalString( |
| NULL, pascalString, kCFStringEncodingMacRoman); |
| if (cfString == NULL) |
| { |
| CFRelease(cfString); |
| return -1; |
| } |
| |
| CFIndex cfLength = CFStringGetLength(cfString); |
| cStringLength = cfLength; |
| if (cfLength > maxStringLength) |
| { |
| cStringLength = maxStringLength; |
| } |
| |
| Boolean success = CFStringGetCString(cfString, cString, bufferSize, |
| kCFStringEncodingMacRoman); |
| |
| // Ensure the problem isn't insufficient buffer length. |
| // This is fine; we will return a partial string. |
| if (success == false && cfLength <= maxStringLength) |
| { |
| CFRelease(cfString); |
| return -1; |
| } |
| |
| CFRelease(cfString); |
| return cStringLength; |
| } |
| |
| // |
| // |
| // Functions for handling capture devices |
| // |
| // |
| |
| VideoCaptureMacQuickTimeInfo::VideoCaptureMacName::VideoCaptureMacName() : |
| _size(0) |
| { |
| memset(_name, 0, kVideoCaptureMacNameMaxSize); |
| } |
| } // namespace webrtc |