qtcapture.m
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:14k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2. * qtcapture.m: qtkit (Mac OS X) based capture module
  3. *****************************************************************************
  4. * Copyright (C) 2008 the VideoLAN team
  5. *
  6. * Authors: Pierre d'Herbemont <pdherbemont@videolan.org>
  7. *
  8. *****************************************************************************
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2 of the License.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  22. *
  23. *****************************************************************************/
  24. /*****************************************************************************
  25. * Preamble
  26. *****************************************************************************/
  27. #ifdef HAVE_CONFIG_H
  28. # include "config.h"
  29. #endif
  30. #include <vlc_common.h>
  31. #include <vlc_plugin.h>
  32. #include <vlc_input.h>
  33. #include <vlc_vout.h>
  34. #include <vlc_demux.h>
  35. #include <vlc_interface.h>
  36. #include <vlc_dialog.h>
  37. #import <QTKit/QTKit.h>
  38. #import <CoreAudio/CoreAudio.h>
  39. /*****************************************************************************
  40. * Local prototypes
  41. *****************************************************************************/
  42. static int Open( vlc_object_t *p_this );
  43. static void Close( vlc_object_t *p_this );
  44. static int Demux( demux_t *p_demux );
  45. static int Control( demux_t *, int, va_list );
  46. /*****************************************************************************
  47. * Module descriptor
  48. *****************************************************************************/
  49. vlc_module_begin ()
  50.    set_shortname( N_("Quicktime Capture") )
  51.    set_description( N_("Quicktime Capture") )
  52.    set_category( CAT_INPUT )
  53.    set_subcategory( SUBCAT_INPUT_ACCESS )
  54.    add_shortcut( "qtcapture" )
  55.    set_capability( "access_demux", 10 )
  56.    set_callbacks( Open, Close )
  57. vlc_module_end ()
  58. /*****************************************************************************
  59. * QTKit Bridge
  60. *****************************************************************************/
  61. @interface VLCDecompressedVideoOutput : QTCaptureDecompressedVideoOutput
  62. {
  63.     CVImageBufferRef currentImageBuffer;
  64.     mtime_t currentPts;
  65.     mtime_t previousPts;
  66. }
  67. - (id)init;
  68. - (void)outputVideoFrame:(CVImageBufferRef)videoFrame withSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection;
  69. - (mtime_t)copyCurrentFrameToBuffer:(void *)buffer;
  70. @end
  71. /* Apple sample code */
  72. @implementation VLCDecompressedVideoOutput : QTCaptureDecompressedVideoOutput
  73. - (id)init
  74. {
  75.     if( self = [super init] )
  76.     {
  77.         currentImageBuffer = nil;
  78.         currentPts = 0;
  79.         previousPts = 0;
  80.     }
  81.     return self;
  82. }
  83. - (void)dealloc
  84. {
  85.     @synchronized (self)
  86.     {
  87.         CVBufferRelease(currentImageBuffer);
  88.         currentImageBuffer = nil;
  89.     }
  90.     [super dealloc];
  91. }
  92. - (void)outputVideoFrame:(CVImageBufferRef)videoFrame withSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection
  93. {
  94.     // Store the latest frame
  95.     // This must be done in a @synchronized block because this delegate method is not called on the main thread
  96.     CVImageBufferRef imageBufferToRelease;
  97.     CVBufferRetain(videoFrame);
  98.     @synchronized (self)
  99.     {
  100.         imageBufferToRelease = currentImageBuffer;
  101.         currentImageBuffer = videoFrame;
  102.         currentPts = (mtime_t)(1000000L / [sampleBuffer presentationTime].timeScale * [sampleBuffer presentationTime].timeValue);
  103.         
  104.         /* Try to use hosttime of the sample if available, because iSight Pts seems broken */
  105.         NSNumber *hosttime = (NSNumber *)[sampleBuffer attributeForKey:QTSampleBufferHostTimeAttribute];
  106.         if( hosttime ) currentPts = (mtime_t)AudioConvertHostTimeToNanos([hosttime unsignedLongLongValue])/1000;
  107.     }
  108.     CVBufferRelease(imageBufferToRelease);
  109. }
  110. - (mtime_t)copyCurrentFrameToBuffer:(void *)buffer
  111. {
  112.     CVImageBufferRef imageBuffer;
  113.     mtime_t pts;
  114.     if(!currentImageBuffer || currentPts == previousPts )
  115.         return 0;
  116.     @synchronized (self)
  117.     {
  118.         imageBuffer = CVBufferRetain(currentImageBuffer);
  119.         pts = previousPts = currentPts;
  120.         CVPixelBufferLockBaseAddress(imageBuffer, 0);
  121.         void * pixels = CVPixelBufferGetBaseAddress(imageBuffer);
  122.         memcpy( buffer, pixels, CVPixelBufferGetBytesPerRow(imageBuffer) * CVPixelBufferGetHeight(imageBuffer) );
  123.         CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
  124.     }
  125.     CVBufferRelease(imageBuffer);
  126.     return currentPts;
  127. }
  128. @end
  129. /*****************************************************************************
  130. * Struct
  131. *****************************************************************************/
  132. struct demux_sys_t {
  133.     QTCaptureSession * session;
  134.     QTCaptureDevice * device;
  135.     VLCDecompressedVideoOutput * output;
  136.     int height, width;
  137.     es_out_id_t * p_es_video;
  138. };
  139. /*****************************************************************************
  140. * qtchroma_to_fourcc
  141. *****************************************************************************/
  142. static int qtchroma_to_fourcc( int i_qt )
  143. {
  144.     static const struct
  145.     {
  146.         unsigned int i_qt;
  147.         int i_fourcc;
  148.     } qtchroma_to_fourcc[] =
  149.     {
  150.         /* Raw data types */
  151.         { k422YpCbCr8CodecType,    VLC_FOURCC('U','Y','V','Y') },
  152.         { kComponentVideoCodecType,VLC_FOURCC('Y','U','Y','2') },
  153.         { kComponentVideoUnsigned, VLC_FOURCC('U','Y','V','Y') },
  154.         { 0, 0 }
  155.     };
  156.     int i;
  157.     for( i = 0; qtchroma_to_fourcc[i].i_qt; i++ )
  158.     {
  159.         if( qtchroma_to_fourcc[i].i_qt == i_qt )
  160.             return qtchroma_to_fourcc[i].i_fourcc;
  161.     }
  162.     return 0;
  163. }
  164. /*****************************************************************************
  165. * Open:
  166. *****************************************************************************/
  167. static int Open( vlc_object_t *p_this )
  168. {
  169.     demux_t     *p_demux = (demux_t*)p_this;
  170.     demux_sys_t *p_sys = NULL;
  171.     es_format_t fmt;
  172.     int i;
  173.     int i_width;
  174.     int i_height;
  175.     int i_aspect;
  176.     int result = 0;
  177.     /* Only when selected */
  178.     if( *p_demux->psz_access == '' )
  179.         return VLC_EGENERIC;
  180.     
  181.     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  182.     /* Set up p_demux */
  183.     p_demux->pf_demux = Demux;
  184.     p_demux->pf_control = Control;
  185.     p_demux->info.i_update = 0;
  186.     p_demux->info.i_title = 0;
  187.     p_demux->info.i_seekpoint = 0;
  188.     
  189.     p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) );
  190.     if( !p_sys )
  191.         return VLC_ENOMEM;
  192.     
  193.     memset( &fmt, 0, sizeof( es_format_t ) );    
  194.     
  195.     QTCaptureDeviceInput * input = nil;
  196.     NSError *o_returnedError;
  197.     p_sys->device = [QTCaptureDevice defaultInputDeviceWithMediaType: QTMediaTypeVideo];
  198.     if( !p_sys->device )
  199.     {
  200.         dialog_FatalWait( p_demux, _("No Input device found"),
  201.                         _("Your Mac does not seem to be equipped with a suitable input device. "
  202.                           "Please check your connectors and drivers.") );
  203.         msg_Err( p_demux, "Can't find any Video device" );
  204.         
  205.         goto error;
  206.     }
  207.     if( ![p_sys->device open: &o_returnedError] )
  208.     {
  209.         msg_Err( p_demux, "Unable to open the capture device (%ld)", [o_returnedError code] );
  210.         goto error;
  211.     }
  212.     if( [p_sys->device isInUseByAnotherApplication] == YES )
  213.     {
  214.         msg_Err( p_demux, "default capture device is exclusively in use by another application" );
  215.         goto error;
  216.     }
  217.     input = [[QTCaptureDeviceInput alloc] initWithDevice: p_sys->device];
  218.     if( !input )
  219.     {
  220.         msg_Err( p_demux, "can't create a valid capture input facility" );
  221.         goto error;
  222.     }
  223.     p_sys->output = [[VLCDecompressedVideoOutput alloc] init];
  224.     /* Get the formats */
  225.     NSArray *format_array = [p_sys->device formatDescriptions];
  226.     QTFormatDescription* camera_format = NULL;
  227.     for( int k=0; k < [format_array count]; k++ )
  228.     {
  229.         camera_format = [format_array objectAtIndex: k];
  230.         NSLog( [camera_format localizedFormatSummary] );
  231.         NSLog( [[camera_format formatDescriptionAttributes] description] );
  232.     }
  233.     if( [format_array count] )
  234.         camera_format = [format_array objectAtIndex: 0];
  235.     else goto error;
  236.     int qtchroma = [camera_format formatType];
  237.     int chroma = qtchroma_to_fourcc( qtchroma );
  238.     if( !chroma )
  239.     {
  240.         msg_Err( p_demux, "Unknown qt chroma %4.4s provided by camera", (char*)&qtchroma );
  241.         goto error;
  242.     }
  243.     /* Now we can init */
  244.     es_format_Init( &fmt, VIDEO_ES, chroma );
  245.     NSSize encoded_size = [[camera_format attributeForKey:QTFormatDescriptionVideoEncodedPixelsSizeAttribute] sizeValue];
  246.     NSSize display_size = [[camera_format attributeForKey:QTFormatDescriptionVideoCleanApertureDisplaySizeAttribute] sizeValue];
  247.     NSSize par_size = [[camera_format attributeForKey:QTFormatDescriptionVideoProductionApertureDisplaySizeAttribute] sizeValue];
  248.     fmt.video.i_width = p_sys->width = encoded_size.width;
  249.     fmt.video.i_height = p_sys->height = encoded_size.height;
  250.     if( par_size.width != encoded_size.width )
  251.     {
  252.         fmt.video.i_aspect = par_size.width * VOUT_ASPECT_FACTOR / encoded_size.width ;
  253.     }
  254.     NSLog( @"encoded_size %d %d", (int)encoded_size.width, (int)encoded_size.height );
  255.     NSLog( @"display_size %d %d", (int)display_size.width, (int)display_size.height );
  256.     NSLog( @"PAR size %d %d", (int)par_size.width, (int)par_size.height );
  257.     
  258.     [p_sys->output setPixelBufferAttributes: [NSDictionary dictionaryWithObjectsAndKeys:
  259.         [NSNumber numberWithInt: p_sys->height], kCVPixelBufferHeightKey,
  260.         [NSNumber numberWithInt: p_sys->width], kCVPixelBufferWidthKey,
  261.         [NSNumber numberWithBool:YES], (id)kCVPixelBufferOpenGLCompatibilityKey,
  262.         nil]];
  263.     p_sys->session = [[QTCaptureSession alloc] init];
  264.     bool ret = [p_sys->session addInput:input error: &o_returnedError];
  265.     if( !ret )
  266.     {
  267.         msg_Err( p_demux, "default video capture device could not be added to capture session (%ld)", [o_returnedError code] );
  268.         goto error;
  269.     }
  270.     ret = [p_sys->session addOutput:p_sys->output error: &o_returnedError];
  271.     if( !ret )
  272.     {
  273.         msg_Err( p_demux, "output could not be added to capture session (%ld)", [o_returnedError code] );
  274.         goto error;
  275.     }
  276.     [p_sys->session startRunning];
  277.     msg_Dbg( p_demux, "added new video es %4.4s %dx%d",
  278.             (char*)&fmt.i_codec, fmt.video.i_width, fmt.video.i_height );
  279.     p_sys->p_es_video = es_out_Add( p_demux->out, &fmt );
  280.     [input release];
  281.     [pool release];
  282.     msg_Dbg( p_demux, "QTCapture: We have a video device ready!" );
  283.     return VLC_SUCCESS;
  284. error:
  285.     [input release];
  286.     [pool release];
  287.     free( p_sys );
  288.     return VLC_EGENERIC;
  289. }
  290. /*****************************************************************************
  291. * Close:
  292. *****************************************************************************/
  293. static void Close( vlc_object_t *p_this )
  294. {
  295.     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  296.     demux_t     *p_demux = (demux_t*)p_this;
  297.     demux_sys_t *p_sys = p_demux->p_sys;
  298.     /* Hack: if libvlc was killed, main interface thread was,
  299.      * and poor QTKit needs it, so don't tell him.
  300.      * Else we dead lock. */
  301.     if( vlc_object_alive(p_this->p_libvlc))
  302.     {
  303.         [p_sys->session stopRunning];
  304.         [p_sys->output release];
  305.         [p_sys->session release];
  306.     }
  307.     free( p_sys );
  308.     [pool release];
  309. }
  310. /*****************************************************************************
  311. * Demux:
  312. *****************************************************************************/
  313. static int Demux( demux_t *p_demux )
  314. {
  315.     demux_sys_t *p_sys = p_demux->p_sys;
  316.     block_t *p_block;
  317.     p_block = block_New( p_demux, p_sys->width *
  318.                             p_sys->height * 2 /* FIXME */ );
  319.     if( !p_block )
  320.     {
  321.         msg_Err( p_demux, "cannot get block" );
  322.         return 0;
  323.     }
  324.     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  325.     @synchronized (p_sys->output)
  326.     {
  327.     p_block->i_pts = [p_sys->output copyCurrentFrameToBuffer: p_block->p_buffer];
  328.     }
  329.     if( !p_block->i_pts )
  330.     {
  331.         /* Nothing to display yet, just forget */
  332.         block_Release( p_block );
  333.         [pool release];
  334.         msleep( 10000 );
  335.         return 1;
  336.     }
  337.     es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block->i_pts );
  338.     es_out_Send( p_demux->out, p_sys->p_es_video, p_block );
  339.     [pool release];
  340.     return 1;
  341. }
  342. /*****************************************************************************
  343. * Control:
  344. *****************************************************************************/
  345. static int Control( demux_t *p_demux, int i_query, va_list args )
  346. {
  347.     bool *pb;
  348.     int64_t    *pi64;
  349.     switch( i_query )
  350.     {
  351.         /* Special for access_demux */
  352.         case DEMUX_CAN_PAUSE:
  353.         case DEMUX_CAN_SEEK:
  354.         case DEMUX_SET_PAUSE_STATE:
  355.         case DEMUX_CAN_CONTROL_PACE:
  356.            pb = (bool*)va_arg( args, bool * );
  357.            *pb = false;
  358.            return VLC_SUCCESS;
  359.         case DEMUX_GET_PTS_DELAY:
  360.            pi64 = (int64_t*)va_arg( args, int64_t * );
  361.            *pi64 = (int64_t)DEFAULT_PTS_DELAY;
  362.            return VLC_SUCCESS;
  363.         default:
  364.            return VLC_EGENERIC;
  365.     }
  366.     return VLC_EGENERIC;
  367. }