X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Fqtcapture.m;h=f6665eb45e07f0131c01c6e01abfdac32da08bfb;hb=c60652e38ac6afd74bd8225e9dae5406f13aaa4f;hp=aad13264dec87d9bbc5eea4eb593465d083d94d5;hpb=b65ca27b5b5445bf4814dcbc22985cfc24f0900b;p=vlc diff --git a/modules/access/qtcapture.m b/modules/access/qtcapture.m index aad13264de..f6665eb45e 100644 --- a/modules/access/qtcapture.m +++ b/modules/access/qtcapture.m @@ -33,11 +33,12 @@ #include #include #include -#include #include #include +#include #import +#import /***************************************************************************** * Local prototypes @@ -47,52 +48,18 @@ static void Close( vlc_object_t *p_this ); static int Demux( demux_t *p_demux ); static int Control( demux_t *, int, va_list ); -typedef struct qtcapture_block_t -{ - block_t block; - CVImageBufferRef imageBuffer; - block_free_t pf_original_release; -} qtcapture_block_t; - -static void qtcapture_block_release( block_t *p_block ) -{ - qtcapture_block_t * p_qtblock = (qtcapture_block_t *)p_block; - CVBufferRelease(p_qtblock->imageBuffer); - CVPixelBufferUnlockBaseAddress(p_qtblock->imageBuffer, 0); - p_qtblock->pf_original_release( &p_qtblock->block ); -} - -static block_t * qtcapture_block_new( void * p_buffer, - int i_buffer, - CVImageBufferRef imageBufferToRelease ) -{ - qtcapture_block_t * p_qtblock; - - /* Build block */ - p_qtblock = malloc( sizeof( qtcapture_block_t ) ); - if(!p_qtblock) return NULL; - - /* Fill all fields */ - block_Init( &p_qtblock->block, p_buffer, i_buffer ); - p_qtblock->block.pf_release = qtcapture_block_release; - p_qtblock->imageBuffer = imageBufferToRelease; - - return (block_t *)p_qtblock; -} - - /***************************************************************************** * Module descriptor *****************************************************************************/ -vlc_module_begin(); - set_shortname( N_("Quicktime Capture") ); - set_description( N_("Quicktime Capture") ); - set_category( CAT_INPUT ); - set_subcategory( SUBCAT_INPUT_ACCESS ); - add_shortcut( "qtcapture" ); - set_capability( "access_demux", 10 ); - set_callbacks( Open, Close ); -vlc_module_end(); +vlc_module_begin () + set_shortname( N_("Quicktime Capture") ) + set_description( N_("Quicktime Capture") ) + set_category( CAT_INPUT ) + set_subcategory( SUBCAT_INPUT_ACCESS ) + add_shortcut( "qtcapture" ) + set_capability( "access_demux", 10 ) + set_callbacks( Open, Close ) +vlc_module_end () /***************************************************************************** @@ -106,7 +73,7 @@ vlc_module_end(); } - (id)init; - (void)outputVideoFrame:(CVImageBufferRef)videoFrame withSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection; -- (block_t *)blockWithCurrentFrame; +- (mtime_t)copyCurrentFrameToBuffer:(void *)buffer; @end /* Apple sample code */ @@ -143,37 +110,37 @@ vlc_module_end(); { imageBufferToRelease = currentImageBuffer; currentImageBuffer = videoFrame; - currentPts = 1000000L / [sampleBuffer presentationTime].timeScale * [sampleBuffer presentationTime].timeValue; + 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); } -- (block_t *)blockWithCurrentFrame +- (mtime_t)copyCurrentFrameToBuffer:(void *)buffer { CVImageBufferRef imageBuffer; mtime_t pts; - block_t * p_block = NULL; if(!currentImageBuffer || currentPts == previousPts ) - return NULL; + return 0; @synchronized (self) { - // Released in the p_block release method. imageBuffer = CVBufferRetain(currentImageBuffer); pts = previousPts = currentPts; - - // Unlocked in the p_block release method. CVPixelBufferLockBaseAddress(imageBuffer, 0); void * pixels = CVPixelBufferGetBaseAddress(imageBuffer); - p_block = qtcapture_block_new( imageBuffer, CVPixelBufferGetDataSize( imageBuffer ), - imageBuffer ); - p_block->i_pts = currentPts; + memcpy( buffer, pixels, CVPixelBufferGetBytesPerRow(imageBuffer) * CVPixelBufferGetHeight(imageBuffer) ); + CVPixelBufferUnlockBaseAddress(imageBuffer, 0); } - return p_block; + CVBufferRelease(imageBuffer); + + return currentPts; } @end @@ -196,14 +163,16 @@ struct demux_sys_t { *****************************************************************************/ static int qtchroma_to_fourcc( int i_qt ) { - static struct + static const struct { unsigned int i_qt; int i_fourcc; } qtchroma_to_fourcc[] = { /* Raw data types */ - { k422YpCbCr8CodecType, VLC_FOURCC('U','Y','V','Y') }, + { '2vuy', VLC_CODEC_UYVY }, + { 'yuv2',VLC_CODEC_YUYV }, + { 'yuvs', VLC_CODEC_YUYV }, { 0, 0 } }; int i; @@ -226,7 +195,6 @@ static int Open( vlc_object_t *p_this ) int i; int i_width; int i_height; - int i_aspect; int result = 0; /* Only when selected */ @@ -242,21 +210,19 @@ static int Open( vlc_object_t *p_this ) p_demux->info.i_title = 0; p_demux->info.i_seekpoint = 0; - p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); - if( !p_sys ) return VLC_ENOMEM; + p_demux->p_sys = p_sys = calloc( 1, 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 ) ); - msg_Dbg( p_demux, "QTCapture Probed" ); - QTCaptureDeviceInput * input = nil; NSError *o_returnedError; p_sys->device = [QTCaptureDevice defaultInputDeviceWithMediaType: QTMediaTypeVideo]; if( !p_sys->device ) { - intf_UserFatal( p_demux, true, _("No Input device found"), + dialog_FatalWait( p_demux, _("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" ); @@ -266,7 +232,7 @@ static int Open( vlc_object_t *p_this ) if( ![p_sys->device open: &o_returnedError] ) { - msg_Err( p_demux, "Unable to open the capture device (%i)", [o_returnedError code] ); + msg_Err( p_demux, "Unable to open the capture device (%ld)", [o_returnedError code] ); goto error; } @@ -285,46 +251,71 @@ static int Open( vlc_object_t *p_this ) p_sys->output = [[VLCDecompressedVideoOutput alloc] init]; - /* Hack - This will lower CPU consumption for some reason */ + /* Get the formats */ + NSArray *format_array = [p_sys->device formatDescriptions]; + QTFormatDescription* camera_format = NULL; + for( int k = 0; k < [format_array count]; k++ ) + { + camera_format = [format_array objectAtIndex: k]; + + NSLog( @"%@", [camera_format localizedFormatSummary] ); + NSLog( @"%@",[[camera_format formatDescriptionAttributes] description] ); + } + if( [format_array count] ) + camera_format = [format_array objectAtIndex: 0]; + else goto error; + + int qtchroma = [camera_format formatType]; + int chroma = qtchroma_to_fourcc( qtchroma ); + if( !chroma ) + { + msg_Err( p_demux, "Unknown qt chroma %4.4s provided by camera", (char*)&qtchroma ); + goto error; + } + + /* Now we can init */ + es_format_Init( &fmt, VIDEO_ES, chroma ); + + NSSize encoded_size = [[camera_format attributeForKey:QTFormatDescriptionVideoEncodedPixelsSizeAttribute] sizeValue]; + NSSize display_size = [[camera_format attributeForKey:QTFormatDescriptionVideoCleanApertureDisplaySizeAttribute] sizeValue]; + NSSize par_size = [[camera_format attributeForKey:QTFormatDescriptionVideoProductionApertureDisplaySizeAttribute] sizeValue]; + + fmt.video.i_width = p_sys->width = encoded_size.width; + fmt.video.i_height = p_sys->height = encoded_size.height; + if( par_size.width != encoded_size.width ) + { + fmt.video.i_sar_num = (int64_t)encoded_size.height * par_size.width / encoded_size.width; + fmt.video.i_sar_den = encoded_size.width; + } + + NSLog( @"encoded_size %d %d", (int)encoded_size.width, (int)encoded_size.height ); + NSLog( @"display_size %d %d", (int)display_size.width, (int)display_size.height ); + NSLog( @"PAR size %d %d", (int)par_size.width, (int)par_size.height ); + [p_sys->output setPixelBufferAttributes: [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt:480], kCVPixelBufferHeightKey, - [NSNumber numberWithInt:640], kCVPixelBufferWidthKey, nil]]; + [NSNumber numberWithInt: p_sys->height], kCVPixelBufferHeightKey, + [NSNumber numberWithInt: p_sys->width], kCVPixelBufferWidthKey, + [NSNumber numberWithBool:YES], (id)kCVPixelBufferOpenGLCompatibilityKey, + nil]]; p_sys->session = [[QTCaptureSession alloc] init]; bool ret = [p_sys->session addInput:input error: &o_returnedError]; if( !ret ) { - msg_Err( p_demux, "default video capture device could not be added to capture session (%i)", [o_returnedError code] ); + msg_Err( p_demux, "default video capture device could not be added to capture session (%ld)", [o_returnedError code] ); goto error; } ret = [p_sys->session addOutput:p_sys->output error: &o_returnedError]; if( !ret ) { - msg_Err( p_demux, "output could not be added to capture session (%i)", [o_returnedError code] ); + msg_Err( p_demux, "output could not be added to capture session (%ld)", [o_returnedError code] ); goto error; } [p_sys->session startRunning]; - - int qtchroma = [[[p_sys->device formatDescriptions] objectAtIndex: 0] formatType]; /* FIXME */ - int chroma = qtchroma_to_fourcc( qtchroma ); - if( !chroma ) - { - msg_Err( p_demux, "Unknown qt chroma %4.4s provided by camera", (char*)&qtchroma ); - goto error; - } - - /* Now we can init */ - - es_format_Init( &fmt, VIDEO_ES, chroma ); - - 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 */ - msg_Dbg( p_demux, "added new video es %4.4s %dx%d", (char*)&fmt.i_codec, fmt.video.i_width, fmt.video.i_height ); @@ -360,10 +351,11 @@ static void Close( vlc_object_t *p_this ) * Else we dead lock. */ if( vlc_object_alive(p_this->p_libvlc)) { - [p_sys->session stopRunning]; - [p_sys->device release]; - [p_sys->output release]; - [p_sys->session release]; + // Perform this on main thread, as the framework itself will sometimes try to synchronously + // work on main thread. And this will create a dead lock. + [p_sys->session performSelectorOnMainThread:@selector(stopRunning) withObject:nil waitUntilDone:NO]; + [p_sys->output performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO]; + [p_sys->session performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO]; } free( p_sys ); @@ -379,16 +371,25 @@ static int Demux( demux_t *p_demux ) demux_sys_t *p_sys = p_demux->p_sys; block_t *p_block; + p_block = block_New( p_demux, p_sys->width * + p_sys->height * 2 /* FIXME */ ); + if( !p_block ) + { + msg_Err( p_demux, "cannot get block" ); + return 0; + } + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; @synchronized (p_sys->output) { - p_block = [p_sys->output blockWithCurrentFrame]; + p_block->i_pts = [p_sys->output copyCurrentFrameToBuffer: p_block->p_buffer]; } - if( !p_block ) + if( !p_block->i_pts ) { /* Nothing to display yet, just forget */ + block_Release( p_block ); [pool release]; msleep( 10000 ); return 1;