X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Fqtcapture.m;h=eac2e6f005426e7a80997989869887cfea21307a;hb=b751665aa8f78719eb3e4fe30545fffd5c423948;hp=c2ef2e6cb80409d5207525302721b1ab077cfa54;hpb=c302959a487d7aa1a4c5cb38d644e1dce6ccc9cf;p=vlc diff --git a/modules/access/qtcapture.m b/modules/access/qtcapture.m index c2ef2e6cb8..eac2e6f005 100644 --- a/modules/access/qtcapture.m +++ b/modules/access/qtcapture.m @@ -30,13 +30,15 @@ # include "config.h" #endif -#include +#include #include #include #include #include +#include #import +#import /***************************************************************************** * Local prototypes @@ -67,6 +69,7 @@ vlc_module_end(); { CVImageBufferRef currentImageBuffer; mtime_t currentPts; + mtime_t previousPts; } - (id)init; - (void)outputVideoFrame:(CVImageBufferRef)videoFrame withSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection; @@ -81,12 +84,14 @@ vlc_module_end(); { currentImageBuffer = nil; currentPts = 0; + previousPts = 0; } return self; } - (void)dealloc { - @synchronized (self) { + @synchronized (self) + { CVBufferRelease(currentImageBuffer); currentImageBuffer = nil; } @@ -101,11 +106,15 @@ vlc_module_end(); CVBufferRetain(videoFrame); - @synchronized (self) { + @synchronized (self) + { imageBufferToRelease = currentImageBuffer; currentImageBuffer = videoFrame; - /* FIXME: is it the right PTS? */ - currentPts = [sampleBuffer presentationTime].timeValue / [sampleBuffer presentationTime].timeScale; + currentPts = (mtime_t)(1000000L / [sampleBuffer presentationTime].timeScale * [sampleBuffer presentationTime].timeValue); + + /* Try to use hosttime of the sample if available, because iSight Pts seems broken */ + NSNumber *hosttime = (NSNumber *)[sampleBuffer attributeForKey:QTSampleBufferHostTimeAttribute]; + if( hosttime ) currentPts = (mtime_t)AudioConvertHostTimeToNanos([hosttime unsignedLongLongValue])/1000; } CVBufferRelease(imageBufferToRelease); } @@ -114,16 +123,20 @@ vlc_module_end(); { CVImageBufferRef imageBuffer; mtime_t pts; - @synchronized (self) { - if(!currentImageBuffer) return 0; + + if(!currentImageBuffer || currentPts == previousPts ) + return 0; + + @synchronized (self) + { imageBuffer = CVBufferRetain(currentImageBuffer); - pts = currentPts; - } + pts = previousPts = currentPts; - CVPixelBufferLockBaseAddress(imageBuffer, 0); - void * pixels = CVPixelBufferGetBaseAddress(imageBuffer); - memcpy( buffer, pixels, CVPixelBufferGetBytesPerRow(imageBuffer) * CVPixelBufferGetHeight(imageBuffer) ); - CVPixelBufferUnlockBaseAddress(imageBuffer, 0); + CVPixelBufferLockBaseAddress(imageBuffer, 0); + void * pixels = CVPixelBufferGetBaseAddress(imageBuffer); + memcpy( buffer, pixels, CVPixelBufferGetBytesPerRow(imageBuffer) * CVPixelBufferGetHeight(imageBuffer) ); + CVPixelBufferUnlockBaseAddress(imageBuffer, 0); + } CVBufferRelease(imageBuffer); @@ -137,10 +150,11 @@ vlc_module_end(); *****************************************************************************/ struct demux_sys_t { - QTCaptureSession * session; - VLCDecompressedVideoOutput * output; - int height, width; - es_out_id_t * p_es_video; + QTCaptureSession * session; + QTCaptureDevice * device; + VLCDecompressedVideoOutput * output; + int height, width; + es_out_id_t * p_es_video; }; @@ -182,73 +196,87 @@ static int Open( vlc_object_t *p_this ) int i_aspect; int result = 0; + /* Only when selected */ + if( *p_demux->psz_access == '\0' ) + return VLC_EGENERIC; + + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + /* Set up p_demux */ p_demux->pf_demux = Demux; p_demux->pf_control = Control; p_demux->info.i_update = 0; p_demux->info.i_title = 0; p_demux->info.i_seekpoint = 0; - - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; - - msg_Dbg( p_demux, "QTCapture Probed" ); - + p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; - + memset( p_sys, 0, sizeof( demux_sys_t ) ); - memset( &fmt, 0, sizeof( es_format_t ) ); + memset( &fmt, 0, sizeof( es_format_t ) ); + + msg_Dbg( p_demux, "QTCapture Probed" ); QTCaptureDeviceInput * input = nil; - QTCaptureSession * session = nil; - VLCDecompressedVideoOutput * output = nil; + NSError *o_returnedError; - QTCaptureDevice * device = [QTCaptureDevice defaultInputDeviceWithMediaType: QTMediaTypeVideo]; - if( !device ) + p_sys->device = [QTCaptureDevice defaultInputDeviceWithMediaType: QTMediaTypeVideo]; + if( !p_sys->device ) { - msg_Err( p_demux, "Can't open any Video device" ); + intf_UserFatal( p_demux, true, _("No Input device found"), + _("Your Mac does not seem to be equipped with a suitable input device. " + "Please check your connectors and drivers.") ); + msg_Err( p_demux, "Can't find any Video device" ); + goto error; } - if( ![device open: nil /* FIXME */] ) + if( ![p_sys->device open: &o_returnedError] ) { - msg_Err( p_demux, "Can't open any Video device" ); + msg_Err( p_demux, "Unable to open the capture device (%i)", [o_returnedError code] ); goto error; } - input = [[QTCaptureDeviceInput alloc] initWithDevice: device]; - if( !device ) + if( [p_sys->device isInUseByAnotherApplication] == YES ) { - msg_Err( p_demux, "Can't create a capture session" ); + msg_Err( p_demux, "default capture device is exclusively in use by another application" ); goto error; } - output = [[VLCDecompressedVideoOutput alloc] init]; + input = [[QTCaptureDeviceInput alloc] initWithDevice: p_sys->device]; + if( !input ) + { + msg_Err( p_demux, "can't create a valid capture input facility" ); + goto error; + } + + p_sys->output = [[VLCDecompressedVideoOutput alloc] init]; /* Hack - This will lower CPU consumption for some reason */ - [output setPixelBufferAttributes: [NSDictionary dictionaryWithObjectsAndKeys: + [p_sys->output setPixelBufferAttributes: [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:480], kCVPixelBufferHeightKey, [NSNumber numberWithInt:640], kCVPixelBufferWidthKey, nil]]; - session = [[QTCaptureSession alloc] init]; + p_sys->session = [[QTCaptureSession alloc] init]; - bool ret = [session addInput:input error:nil /* FIXME */]; + bool ret = [p_sys->session addInput:input error: &o_returnedError]; if( !ret ) { - msg_Err( p_demux, "Can't add the video device as input" ); + msg_Err( p_demux, "default video capture device could not be added to capture session (%i)", [o_returnedError code] ); goto error; } - ret = [session addOutput:output error:nil /* FIXME */]; + ret = [p_sys->session addOutput:p_sys->output error: &o_returnedError]; if( !ret ) { - msg_Err( p_demux, "Can't get any output output" ); + msg_Err( p_demux, "output could not be added to capture session (%i)", [o_returnedError code] ); goto error; } - [session startRunning]; + [p_sys->session startRunning]; + - int qtchroma = [[[device formatDescriptions] objectAtIndex: 0] formatType]; /* FIXME */ + int qtchroma = [[[p_sys->device formatDescriptions] objectAtIndex: 0] formatType]; /* FIXME */ int chroma = qtchroma_to_fourcc( qtchroma ); if( !chroma ) { @@ -256,9 +284,11 @@ static int Open( vlc_object_t *p_this ) goto error; } + /* Now we can init */ + es_format_Init( &fmt, VIDEO_ES, chroma ); - NSSize size = [[device attributeForKey:QTFormatDescriptionVideoEncodedPixelsSizeAttribute] sizeValue]; + NSSize size = [[p_sys->device attributeForKey:QTFormatDescriptionVideoEncodedPixelsSizeAttribute] sizeValue]; p_sys->width = fmt.video.i_width = 640;/* size.width; FIXME */ p_sys->height = fmt.video.i_height = 480;/* size.height; FIXME */ @@ -267,12 +297,7 @@ static int Open( vlc_object_t *p_this ) p_sys->p_es_video = es_out_Add( p_demux->out, &fmt ); - p_sys->output = [output retain]; - p_sys->session = [session retain]; - [input release]; - [output release]; - [session release]; [pool release]; msg_Dbg( p_demux, "QTCapture: We have a video device ready!" ); @@ -280,9 +305,6 @@ static int Open( vlc_object_t *p_this ) return VLC_SUCCESS; error: [input release]; - [session release]; - [input release]; - [output release]; [pool release]; free( p_sys ); @@ -299,8 +321,16 @@ static void Close( vlc_object_t *p_this ) demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys = p_demux->p_sys; - [p_sys->output release]; - [p_sys->session release]; + + /* Hack: if libvlc was killed, main interface thread was, + * and poor QTKit needs it, so don't tell him. + * Else we dead lock. */ + if( vlc_object_alive(p_this->p_libvlc)) + { + [p_sys->session stopRunning]; + [p_sys->output release]; + [p_sys->session release]; + } free( p_sys ); [pool release]; @@ -325,19 +355,20 @@ static int Demux( demux_t *p_demux ) NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + @synchronized (p_sys->output) + { p_block->i_pts = [p_sys->output copyCurrentFrameToBuffer: p_block->p_buffer]; + } if( !p_block->i_pts ) { /* Nothing to display yet, just forget */ block_Release( p_block ); [pool release]; + msleep( 10000 ); return 1; } - /* FIXME */ - p_block->i_pts = mdate(); - es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block->i_pts ); es_out_Send( p_demux->out, p_sys->p_es_video, p_block ); @@ -369,12 +400,6 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) *pi64 = (int64_t)DEFAULT_PTS_DELAY; return VLC_SUCCESS; - case DEMUX_GET_TIME: - pi64 = (int64_t*)va_arg( args, int64_t * ); - *pi64 = mdate(); - return VLC_SUCCESS; - - /* TODO implement others */ default: return VLC_EGENERIC; }