mirror of
https://github.com/Tha14/toxic.git
synced 2025-07-04 07:16:46 +02:00
Implemented video calls for OSX
This commit is contained in:
151
src/osx_video.m
151
src/osx_video.m
@ -59,7 +59,7 @@ static uint8_t rgb_to_v(int r, int g, int b)
|
||||
return v>255? 255 : v<0 ? 0 : v;
|
||||
}
|
||||
|
||||
void bgrtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *rgb, uint16_t width, uint16_t height)
|
||||
void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *rgb, uint16_t width, uint16_t height)
|
||||
{
|
||||
uint16_t x, y;
|
||||
uint8_t *p;
|
||||
@ -71,6 +71,8 @@ void bgrtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *
|
||||
b = *rgb++;
|
||||
g = *rgb++;
|
||||
r = *rgb++;
|
||||
rgb++;
|
||||
|
||||
*plane_y++ = rgb_to_y(r, g, b);
|
||||
}
|
||||
|
||||
@ -78,21 +80,26 @@ void bgrtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *
|
||||
b = *rgb++;
|
||||
g = *rgb++;
|
||||
r = *rgb++;
|
||||
rgb++;
|
||||
|
||||
*plane_y++ = rgb_to_y(r, g, b);
|
||||
|
||||
b = *rgb++;
|
||||
g = *rgb++;
|
||||
r = *rgb++;
|
||||
rgb++;
|
||||
|
||||
*plane_y++ = rgb_to_y(r, g, b);
|
||||
|
||||
b = ((int)b + (int)*(rgb - 6) + (int)*p + (int)*(p + 3) + 2) / 4; p++;
|
||||
g = ((int)g + (int)*(rgb - 5) + (int)*p + (int)*(p + 3) + 2) / 4; p++;
|
||||
r = ((int)r + (int)*(rgb - 4) + (int)*p + (int)*(p + 3) + 2) / 4; p++;
|
||||
b = ((int)b + (int)*(rgb - 8) + (int)*p + (int)*(p + 4) + 2) / 4; p++;
|
||||
g = ((int)g + (int)*(rgb - 7) + (int)*p + (int)*(p + 4) + 2) / 4; p++;
|
||||
r = ((int)r + (int)*(rgb - 6) + (int)*p + (int)*(p + 4) + 2) / 4; p++;
|
||||
p++;
|
||||
|
||||
*plane_u++ = rgb_to_u(r, g, b);
|
||||
*plane_v++ = rgb_to_v(r, g, b);
|
||||
|
||||
p += 3;
|
||||
p += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -112,21 +119,23 @@ void bgrtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *
|
||||
|
||||
CVImageBufferRef _currentFrame;
|
||||
pthread_mutex_t _frameLock;
|
||||
BOOL _shouldMangleDimensions;
|
||||
}
|
||||
|
||||
- (instancetype)initWithDeviceNames: (char **)device_names AmtDevices: (int *)size {
|
||||
_session = [[AVCaptureSession alloc] init];
|
||||
|
||||
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
|
||||
int i = 0;
|
||||
for (AVCaptureDevice *device in devices) {
|
||||
int i;
|
||||
for (i = 0; i < [devices count]; ++i) {
|
||||
AVCaptureDevice *device = [devices objectAtIndex:i];
|
||||
char *video_input_name;
|
||||
NSString *localizedName = [device localizedName];
|
||||
video_input_name = (char*)malloc(strlen([localizedName cStringUsingEncoding:NSUTF8StringEncoding]) + 1);
|
||||
strcpy(video_input_name, (char*)[localizedName cStringUsingEncoding:NSUTF8StringEncoding]);
|
||||
device_names[i] = video_input_name;
|
||||
++i;
|
||||
}
|
||||
|
||||
if ( i <= 0 )
|
||||
return nil;
|
||||
*size = i;
|
||||
@ -134,80 +143,115 @@ void bgrtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)release {
|
||||
- (void)dealloc {
|
||||
pthread_mutex_destroy(&_frameLock);
|
||||
[_session release];
|
||||
[super release];
|
||||
[_linkerVideo release];
|
||||
dispatch_release(_processingQueue);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (int)openVideoDeviceIndex: (uint32_t)device_idx Width: (uint16_t *)width Height: (uint16_t *)height {
|
||||
pthread_mutex_init(&_frameLock, NULL);
|
||||
pthread_mutex_lock(&_frameLock);
|
||||
_processingQueue = dispatch_queue_create("Toxic processing queue", DISPATCH_QUEUE_SERIAL);
|
||||
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
|
||||
int i = 0;
|
||||
for (AVCaptureDevice *device in devices) {
|
||||
if ( i == device_idx ) {
|
||||
NSError *error = NULL;
|
||||
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];
|
||||
AVCaptureDevice *device = [devices objectAtIndex:device_idx];
|
||||
NSError *error = NULL;
|
||||
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];
|
||||
|
||||
if ( error != NULL )
|
||||
return -1;
|
||||
if ( error != NULL ) {
|
||||
[input release];
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Obtain device resolution */
|
||||
/*AVCaptureInputPort *port = [input.ports objectAtIndex:0];
|
||||
CMFormatDescriptionRef format_description = port.formatDescription;
|
||||
if ( format_description ) {
|
||||
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(format_description);
|
||||
*width = dimensions.width;
|
||||
*height = dimensions.height;
|
||||
} else {
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
}*/
|
||||
[_session beginConfiguration];
|
||||
[_session addInput:input];
|
||||
//_session.sessionPreset = AVCaptureSessionPreset640x480;
|
||||
//*width = 640;
|
||||
//*height = 480;
|
||||
_shouldMangleDimensions = YES;
|
||||
[_session commitConfiguration];
|
||||
[input release];
|
||||
[device release];
|
||||
|
||||
[_session beginConfiguration];
|
||||
[_session addInput:input];
|
||||
//session.sessionPreset = AVCaptureSessionPreset640x480;
|
||||
[_session commitConfiguration];
|
||||
[input release];
|
||||
|
||||
break;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
/* Obtain device resolution */
|
||||
AVCaptureInputPort *port = [input.ports objectAtIndex:0];
|
||||
CMFormatDescriptionRef format_description = port.formatDescription;
|
||||
if ( format_description ) {
|
||||
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(format_description);
|
||||
*width = dimensions.width;
|
||||
*height = dimensions.height;
|
||||
} else {
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
}
|
||||
|
||||
_linkerVideo = [[AVCaptureVideoDataOutput alloc] init];
|
||||
[_linkerVideo setSampleBufferDelegate:self queue:_processingQueue];
|
||||
// TODO possibly get a better pixel format
|
||||
[_linkerVideo setVideoSettings:@{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}];
|
||||
if (_shouldMangleDimensions) {
|
||||
[_linkerVideo setVideoSettings:@{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
|
||||
(id)kCVPixelBufferWidthKey: @640,
|
||||
(id)kCVPixelBufferHeightKey: @480}];
|
||||
} else {
|
||||
[_linkerVideo setVideoSettings:@{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}];
|
||||
}
|
||||
[_session addOutput:_linkerVideo];
|
||||
|
||||
[_session startRunning];
|
||||
|
||||
pthread_mutex_unlock(&_frameLock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (void)closeVideoDeviceIndex: (uint32_t)device_idx {
|
||||
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
|
||||
AVCaptureDevice *device = [devices objectAtIndex:device_idx];
|
||||
NSError *error = NULL;
|
||||
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];
|
||||
[_session stopRunning];
|
||||
[_session removeOutput:_linkerVideo];
|
||||
[_session removeInput:input];
|
||||
[_linkerVideo release];
|
||||
}
|
||||
|
||||
- (void)getVideoFrameY: (uint8_t *)y U: (uint8_t *)u V: (uint8_t *)v Width: (uint16_t *)width Height: (uint16_t *)height {
|
||||
/*CVImageBufferRef currentFrame = NULL;
|
||||
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
|
||||
pthread_mutex_lock(&_frameLock);
|
||||
CVImageBufferRef img = CMSampleBufferGetImageBuffer(sampleBuffer);
|
||||
if (!img) {
|
||||
NSLog(@"Toxic WARNING: Bad sampleBuffer from AVfoundation!");
|
||||
} else {
|
||||
CVPixelBufferUnlockBaseAddress(_currentFrame, kCVPixelBufferLock_ReadOnly);
|
||||
RELEASE_CHK(CFRelease, _currentFrame);
|
||||
|
||||
CFRetain(currentFrame);
|
||||
_currentFrame = (CVImageBufferRef)CFRetain(img);
|
||||
// we're not going to do anything to it, so it's safe to lock it always
|
||||
CVPixelBufferLockBaseAddress(_currentFrame, kCVPixelBufferLock_ReadOnly);
|
||||
}
|
||||
pthread_mutex_unlock(&_frameLock);
|
||||
}
|
||||
|
||||
CFTypeID imageType = CFGetTypeID(currentFrame);
|
||||
- (int)getVideoFrameY: (uint8_t *)y U: (uint8_t *)u V: (uint8_t *)v Width: (uint16_t *)width Height: (uint16_t *)height {
|
||||
if (!_currentFrame) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&_frameLock);
|
||||
CFRetain(_currentFrame);
|
||||
|
||||
CFTypeID imageType = CFGetTypeID(_currentFrame);
|
||||
if (imageType == CVPixelBufferGetTypeID()) {
|
||||
// TODO maybe handle other formats
|
||||
bgrxtoyuv420(y, u, v, CVPixelBufferGetBaseAddress(currentFrame), width, height);
|
||||
bgrxtoyuv420(y, u, v, CVPixelBufferGetBaseAddress(_currentFrame), *width, *height);
|
||||
} else if (imageType == CVOpenGLBufferGetTypeID()) {
|
||||
// OpenGL pbuffer
|
||||
} else if (imageType == CVOpenGLTextureGetTypeID()) {
|
||||
// OpenGL Texture (Do we need to handle these?)
|
||||
}
|
||||
|
||||
CVPixelBufferRelease(currentFrame);*/
|
||||
CVPixelBufferRelease(_currentFrame);
|
||||
pthread_mutex_unlock(&_frameLock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@end
|
||||
@ -234,11 +278,15 @@ int osx_video_init(char **device_names, int *size)
|
||||
void osx_video_release()
|
||||
{
|
||||
[_OSXVideo release];
|
||||
_OSXVideo = nil;
|
||||
}
|
||||
|
||||
int osx_video_open_device(uint32_t device_idx, uint16_t *width, uint16_t *height)
|
||||
int osx_video_open_device(uint32_t selection, uint16_t *width, uint16_t *height)
|
||||
{
|
||||
return [_OSXVideo openVideoDeviceIndex: device_idx Width: width Height: height];
|
||||
if ( _OSXVideo == nil )
|
||||
return -1;
|
||||
|
||||
return [_OSXVideo openVideoDeviceIndex: selection Width: width Height: height];
|
||||
}
|
||||
|
||||
void osx_video_close_device(uint32_t device_idx)
|
||||
@ -246,9 +294,12 @@ void osx_video_close_device(uint32_t device_idx)
|
||||
[_OSXVideo closeVideoDeviceIndex: device_idx];
|
||||
}
|
||||
|
||||
void osx_video_read_device(uint8_t *y, uint8_t *u, uint8_t *v, uint16_t *width, uint16_t *height)
|
||||
int osx_video_read_device(uint8_t *y, uint8_t *u, uint8_t *v, uint16_t *width, uint16_t *height)
|
||||
{
|
||||
[_OSXVideo getVideoFrameY: y U: u V: v Width: width Height: height];
|
||||
if ( _OSXVideo == nil )
|
||||
return -1;
|
||||
|
||||
return [_OSXVideo getVideoFrameY: y U: u V: v Width: width Height: height];
|
||||
}
|
||||
/*
|
||||
* End of C-interface for OSXVideo
|
||||
|
Reference in New Issue
Block a user