Commit daf88e5b authored by mcasas@chromium.org's avatar mcasas@chromium.org

Mac Video Capture: Connect error logging to WebRTC Log.

Connect the scattered DLOG(ERROR) to also send an error message to
WebRTC Log. Also log the type of API in use: QTKit or AVFoundation.

BUG=b/14652504

Review URL: https://codereview.chromium.org/308813002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@273863 0039d316-1c4b-4281-b951-d872f2087c98
parent e8fe5711
...@@ -131,6 +131,7 @@ class VideoCaptureController::VideoCaptureDeviceClient ...@@ -131,6 +131,7 @@ class VideoCaptureController::VideoCaptureDeviceClient
const scoped_refptr<media::VideoFrame>& frame, const scoped_refptr<media::VideoFrame>& frame,
base::TimeTicks timestamp) OVERRIDE; base::TimeTicks timestamp) OVERRIDE;
virtual void OnError(const std::string& reason) OVERRIDE; virtual void OnError(const std::string& reason) OVERRIDE;
virtual void OnLog(const std::string& message) OVERRIDE;
private: private:
scoped_refptr<Buffer> DoReserveOutputBuffer(media::VideoFrame::Format format, scoped_refptr<Buffer> DoReserveOutputBuffer(media::VideoFrame::Format format,
...@@ -487,6 +488,11 @@ void VideoCaptureController::VideoCaptureDeviceClient::OnError( ...@@ -487,6 +488,11 @@ void VideoCaptureController::VideoCaptureDeviceClient::OnError(
base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_)); base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_));
} }
void VideoCaptureController::VideoCaptureDeviceClient::OnLog(
const std::string& message) {
MediaStreamManager::SendMessageToNativeLog("Video capture: " + message);
}
scoped_refptr<media::VideoCaptureDevice::Client::Buffer> scoped_refptr<media::VideoCaptureDevice::Client::Buffer>
VideoCaptureController::VideoCaptureDeviceClient::DoReserveOutputBuffer( VideoCaptureController::VideoCaptureDeviceClient::DoReserveOutputBuffer(
media::VideoFrame::Format format, media::VideoFrame::Format format,
......
...@@ -49,8 +49,8 @@ ...@@ -49,8 +49,8 @@
if (device == nil) if (device == nil)
return; return;
for (CrAVCaptureDeviceFormat* format in device.formats) { for (CrAVCaptureDeviceFormat* format in device.formats) {
// MediaSubType comes is a CMPixelFormatType but can be used as // MediaSubType is a CMPixelFormatType but can be used as CVPixelFormatType
// CVPixelFormatType as well according to CMFormatDescription.h // as well according to CMFormatDescription.h
media::VideoPixelFormat pixelFormat = media::PIXEL_FORMAT_UNKNOWN; media::VideoPixelFormat pixelFormat = media::PIXEL_FORMAT_UNKNOWN;
switch (CoreMediaGlue::CMFormatDescriptionGetMediaSubType( switch (CoreMediaGlue::CMFormatDescriptionGetMediaSubType(
[format formatDescription])) { [format formatDescription])) {
...@@ -129,7 +129,8 @@ ...@@ -129,7 +129,8 @@
// Look for input device with requested name. // Look for input device with requested name.
captureDevice_ = [AVCaptureDeviceGlue deviceWithUniqueID:deviceId]; captureDevice_ = [AVCaptureDeviceGlue deviceWithUniqueID:deviceId];
if (!captureDevice_) { if (!captureDevice_) {
DLOG(ERROR) << "Could not open video capture device."; [self sendErrorString:[NSString
stringWithUTF8String:"Could not open video capture device."]];
return NO; return NO;
} }
...@@ -140,8 +141,10 @@ ...@@ -140,8 +141,10 @@
error:&error]; error:&error];
if (!captureDeviceInput_) { if (!captureDeviceInput_) {
captureDevice_ = nil; captureDevice_ = nil;
DLOG(ERROR) << "Could not create video capture input: " [self sendErrorString:[NSString
<< [[error localizedDescription] UTF8String]; stringWithFormat:@"Could not create video capture input (%@): %@",
[error localizedDescription],
[error localizedFailureReason]]];
return NO; return NO;
} }
[captureSession_ addInput:captureDeviceInput_]; [captureSession_ addInput:captureDeviceInput_];
...@@ -152,7 +155,8 @@ ...@@ -152,7 +155,8 @@
[[AVFoundationGlue::AVCaptureVideoDataOutputClass() alloc] init]); [[AVFoundationGlue::AVCaptureVideoDataOutputClass() alloc] init]);
if (!captureVideoDataOutput_) { if (!captureVideoDataOutput_) {
[captureSession_ removeInput:captureDeviceInput_]; [captureSession_ removeInput:captureDeviceInput_];
DLOG(ERROR) << "Could not create video data output."; [self sendErrorString:[NSString
stringWithUTF8String:"Could not create video data output."]];
return NO; return NO;
} }
[captureVideoDataOutput_ [captureVideoDataOutput_
...@@ -270,14 +274,17 @@ ...@@ -270,14 +274,17 @@
- (void)onVideoError:(NSNotification*)errorNotification { - (void)onVideoError:(NSNotification*)errorNotification {
NSError* error = base::mac::ObjCCast<NSError>([[errorNotification userInfo] NSError* error = base::mac::ObjCCast<NSError>([[errorNotification userInfo]
objectForKey:AVFoundationGlue::AVCaptureSessionErrorKey()]); objectForKey:AVFoundationGlue::AVCaptureSessionErrorKey()]);
NSString* str_error = [self sendErrorString:[NSString
[NSString stringWithFormat:@"%@: %@", stringWithFormat:@"%@: %@",
[error localizedDescription], [error localizedDescription],
[error localizedFailureReason]]; [error localizedFailureReason]]];
}
- (void)sendErrorString:(NSString*)error {
DLOG(ERROR) << [error UTF8String];
base::AutoLock lock(lock_); base::AutoLock lock(lock_);
if (frameReceiver_) if (frameReceiver_)
frameReceiver_->ReceiveError([str_error UTF8String]); frameReceiver_->ReceiveError([error UTF8String]);
} }
@end @end
...@@ -52,6 +52,7 @@ class VideoCaptureDeviceMac : public VideoCaptureDevice { ...@@ -52,6 +52,7 @@ class VideoCaptureDeviceMac : public VideoCaptureDevice {
private: private:
void SetErrorState(const std::string& reason); void SetErrorState(const std::string& reason);
void LogMessage(const std::string& message);
bool UpdateCaptureResolution(); bool UpdateCaptureResolution();
// Flag indicating the internal state. // Flag indicating the internal state.
......
...@@ -378,6 +378,10 @@ void VideoCaptureDeviceMac::AllocateAndStart( ...@@ -378,6 +378,10 @@ void VideoCaptureDeviceMac::AllocateAndStart(
GetBestMatchSupportedResolution(&width, &height); GetBestMatchSupportedResolution(&width, &height);
client_ = client.Pass(); client_ = client.Pass();
if (device_name_.capture_api_type() == Name::AVFOUNDATION)
LogMessage("Using AVFoundation for device: " + device_name_.name());
else
LogMessage("Using QTKit for device: " + device_name_.name());
NSString* deviceId = NSString* deviceId =
[NSString stringWithUTF8String:device_name_.id().c_str()]; [NSString stringWithUTF8String:device_name_.id().c_str()];
...@@ -560,6 +564,12 @@ void VideoCaptureDeviceMac::SetErrorState(const std::string& reason) { ...@@ -560,6 +564,12 @@ void VideoCaptureDeviceMac::SetErrorState(const std::string& reason) {
client_->OnError(reason); client_->OnError(reason);
} }
void VideoCaptureDeviceMac::LogMessage(const std::string& message) {
DCHECK(task_runner_->BelongsToCurrentThread());
if (client_)
client_->OnLog(message);
}
bool VideoCaptureDeviceMac::UpdateCaptureResolution() { bool VideoCaptureDeviceMac::UpdateCaptureResolution() {
if (![capture_device_ setCaptureHeight:capture_format_.frame_size.height() if (![capture_device_ setCaptureHeight:capture_format_.frame_size.height()
width:capture_format_.frame_size.width() width:capture_format_.frame_size.width()
......
...@@ -78,25 +78,31 @@ ...@@ -78,25 +78,31 @@
return NO; return NO;
} }
// TODO(mcasas): Consider using [QTCaptureDevice deviceWithUniqueID] instead
// of explicitly forcing reenumeration of devices.
NSArray *captureDevices = NSArray *captureDevices =
[QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo]; [QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo];
NSArray *captureDevicesNames = NSArray *captureDevicesNames =
[captureDevices valueForKey:@"uniqueID"]; [captureDevices valueForKey:@"uniqueID"];
NSUInteger index = [captureDevicesNames indexOfObject:deviceId]; NSUInteger index = [captureDevicesNames indexOfObject:deviceId];
if (index == NSNotFound) { if (index == NSNotFound) {
DLOG(ERROR) << "Video capture device not found."; [self sendErrorString:[NSString
stringWithUTF8String:"Video capture device not found."]];
return NO; return NO;
} }
QTCaptureDevice *device = [captureDevices objectAtIndex:index]; QTCaptureDevice *device = [captureDevices objectAtIndex:index];
if ([[device attributeForKey:QTCaptureDeviceSuspendedAttribute] if ([[device attributeForKey:QTCaptureDeviceSuspendedAttribute]
boolValue]) { boolValue]) {
DLOG(ERROR) << "Cannot open suspended video capture device."; [self sendErrorString:[NSString
stringWithUTF8String:"Cannot open suspended video capture device."]];
return NO; return NO;
} }
NSError *error; NSError *error;
if (![device open:&error]) { if (![device open:&error]) {
DLOG(ERROR) << "Could not open video capture device." [self sendErrorString:[NSString
<< [[error localizedDescription] UTF8String]; stringWithFormat:@"Could not open video capture device (%@): %@",
[error localizedDescription],
[error localizedFailureReason]]];
return NO; return NO;
} }
captureDeviceInput_ = [[QTCaptureDeviceInput alloc] initWithDevice:device]; captureDeviceInput_ = [[QTCaptureDeviceInput alloc] initWithDevice:device];
...@@ -106,8 +112,10 @@ ...@@ -106,8 +112,10 @@
[[[QTCaptureDecompressedVideoOutput alloc] init] autorelease]; [[[QTCaptureDecompressedVideoOutput alloc] init] autorelease];
[captureDecompressedOutput setDelegate:self]; [captureDecompressedOutput setDelegate:self];
if (![captureSession_ addOutput:captureDecompressedOutput error:&error]) { if (![captureSession_ addOutput:captureDecompressedOutput error:&error]) {
DLOG(ERROR) << "Could not connect video capture output." [self sendErrorString:[NSString
<< [[error localizedDescription] UTF8String]; stringWithFormat:@"Could not connect video capture output (%@): %@",
[error localizedDescription],
[error localizedFailureReason]]];
return NO; return NO;
} }
...@@ -126,7 +134,8 @@ ...@@ -126,7 +134,8 @@
} else { } else {
// Remove the previously set capture device. // Remove the previously set capture device.
if (!captureDeviceInput_) { if (!captureDeviceInput_) {
DLOG(ERROR) << "No video capture device set."; [self sendErrorString:[NSString
stringWithUTF8String:"No video capture device set, on removal."]];
return YES; return YES;
} }
if ([[captureSession_ inputs] count] > 0) { if ([[captureSession_ inputs] count] > 0) {
...@@ -139,15 +148,14 @@ ...@@ -139,15 +148,14 @@
id output = [[captureSession_ outputs] objectAtIndex:0]; id output = [[captureSession_ outputs] objectAtIndex:0];
[output setDelegate:nil]; [output setDelegate:nil];
// TODO(shess): QTKit achieves thread safety by posting messages // TODO(shess): QTKit achieves thread safety by posting messages to the
// to the main thread. As part of -addOutput:, it posts a // main thread. As part of -addOutput:, it posts a message to the main
// message to the main thread which in turn posts a notification // thread which in turn posts a notification which will run in a future
// which will run in a future spin after the original method // spin after the original method returns. -removeOutput: can post a
// returns. -removeOutput: can post a main-thread message in // main-thread message in between while holding a lock which the
// between while holding a lock which the notification handler // notification handler will need. Posting either -addOutput: or
// will need. Posting either -addOutput: or -removeOutput: to // -removeOutput: to the main thread should fix it, remove is likely
// the main thread should fix it, remove is likely safer. // safer. http://crbug.com/152757
// http://crbug.com/152757
[captureSession_ performSelectorOnMainThread:@selector(removeOutput:) [captureSession_ performSelectorOnMainThread:@selector(removeOutput:)
withObject:output withObject:output
waitUntilDone:YES]; waitUntilDone:YES];
...@@ -162,15 +170,17 @@ ...@@ -162,15 +170,17 @@
- (BOOL)setCaptureHeight:(int)height width:(int)width frameRate:(int)frameRate { - (BOOL)setCaptureHeight:(int)height width:(int)width frameRate:(int)frameRate {
if (!captureDeviceInput_) { if (!captureDeviceInput_) {
DLOG(ERROR) << "No video capture device set."; [self sendErrorString:[NSString
stringWithUTF8String:"No video capture device set."]];
return NO; return NO;
} }
if ([[captureSession_ outputs] count] != 1) { if ([[captureSession_ outputs] count] != 1) {
DLOG(ERROR) << "Video capture capabilities already set."; [self sendErrorString:[NSString
stringWithUTF8String:"Video capture capabilities already set."]];
return NO; return NO;
} }
if (frameRate <= 0) { if (frameRate <= 0) {
DLOG(ERROR) << "Wrong frame rate."; [self sendErrorString:[NSString stringWithUTF8String: "Wrong frame rate."]];
return NO; return NO;
} }
...@@ -196,14 +206,18 @@ ...@@ -196,14 +206,18 @@
- (BOOL)startCapture { - (BOOL)startCapture {
if ([[captureSession_ outputs] count] == 0) { if ([[captureSession_ outputs] count] == 0) {
// Capture properties not set. // Capture properties not set.
DLOG(ERROR) << "Video capture device not initialized."; [self sendErrorString:[NSString
stringWithUTF8String:"Video capture device not initialized."]];
return NO; return NO;
} }
if ([[captureSession_ inputs] count] == 0) { if ([[captureSession_ inputs] count] == 0) {
NSError *error; NSError *error;
if (![captureSession_ addInput:captureDeviceInput_ error:&error]) { if (![captureSession_ addInput:captureDeviceInput_ error:&error]) {
DLOG(ERROR) << "Could not connect video capture device." [self sendErrorString:[NSString
<< [[error localizedDescription] UTF8String]; stringWithFormat:@"Could not connect video capture device (%@): %@",
[error localizedDescription],
[error localizedFailureReason]]];
return NO; return NO;
} }
NSNotificationCenter * notificationCenter = NSNotificationCenter * notificationCenter =
...@@ -309,12 +323,18 @@ ...@@ -309,12 +323,18 @@
- (void)handleNotification:(NSNotification*)errorNotification { - (void)handleNotification:(NSNotification*)errorNotification {
NSError * error = (NSError*)[[errorNotification userInfo] NSError * error = (NSError*)[[errorNotification userInfo]
objectForKey:QTCaptureSessionErrorKey]; objectForKey:QTCaptureSessionErrorKey];
NSString* str_error = [self sendErrorString:[NSString
[NSString stringWithFormat:@"%@: %@", stringWithFormat:@"%@: %@",
[error localizedDescription], [error localizedDescription],
[error localizedFailureReason]]; [error localizedFailureReason]]];
}
frameReceiver_->ReceiveError([str_error UTF8String]); - (void)sendErrorString:(NSString*)error {
DLOG(ERROR) << [error UTF8String];
[lock_ lock];
if (frameReceiver_)
frameReceiver_->ReceiveError([error UTF8String]);
[lock_ unlock];
} }
@end @end
...@@ -187,6 +187,9 @@ class MEDIA_EXPORT VideoCaptureDevice { ...@@ -187,6 +187,9 @@ class MEDIA_EXPORT VideoCaptureDevice {
// An error has occurred that cannot be handled and VideoCaptureDevice must // An error has occurred that cannot be handled and VideoCaptureDevice must
// be StopAndDeAllocate()-ed. |reason| is a text description of the error. // be StopAndDeAllocate()-ed. |reason| is a text description of the error.
virtual void OnError(const std::string& reason) = 0; virtual void OnError(const std::string& reason) = 0;
// VideoCaptureDevice requests the |message| to be logged.
virtual void OnLog(const std::string& message) {}
}; };
// Creates a VideoCaptureDevice object. // Creates a VideoCaptureDevice object.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment