/*****************************************************************************
-* qtcapture.m: qtkit (Mac OS X) based capture module
-*****************************************************************************
-* Copyright (C) 2008-2011 the VideoLAN team
-*
-* Authors: Pierre d'Herbemont <pdherbemont@videolan.org>
-*
-*****************************************************************************
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU Lesser General Public
-* License as published by the Free Software Foundation;
-* version 2 of the License.
-*
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public
-* License along with this library; if not, write to the Free Software
-* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*
-*****************************************************************************/
+ * qtcapture.m: qtkit (Mac OS X) based capture module
+ *****************************************************************************
+ * Copyright © 2008-2011 VLC authors and VideoLAN
+ *
+ * Authors: Pierre d'Herbemont <pdherbemont@videolan.org>
+ *
+ ****************************************************************************
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
/*****************************************************************************
-* Preamble
-*****************************************************************************/
+ * Preamble
+ *****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
CVImageBufferRef currentImageBuffer;
mtime_t currentPts;
mtime_t previousPts;
+ long timeScale;
}
- (id)init;
- (void)outputVideoFrame:(CVImageBufferRef)videoFrame withSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection;
currentImageBuffer = nil;
currentPts = 0;
previousPts = 0;
+ timeScale = 0;
}
return self;
}
[super dealloc];
}
+- (long)timeScale
+{
+ return timeScale;
+}
+
- (void)outputVideoFrame:(CVImageBufferRef)videoFrame withSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection
{
// Store the latest frame
{
imageBufferToRelease = currentImageBuffer;
currentImageBuffer = videoFrame;
- currentPts = (mtime_t)(1000000L / [sampleBuffer presentationTime].timeScale * [sampleBuffer presentationTime].timeValue);
+ QTTime timeStamp = [sampleBuffer presentationTime];
+ timeScale = timeStamp.timeScale;
+ currentPts = (mtime_t)(1000000L / timeScale * timeStamp.timeValue);
/* Try to use hosttime of the sample if available, because iSight Pts seems broken */
NSNumber *hosttime = (NSNumber *)[sampleBuffer attributeForKey:QTSampleBufferHostTimeAttribute];
{
CVImageBufferRef imageBuffer;
mtime_t pts;
- void * pixels;
+
+void * pixels;
if(!currentImageBuffer || currentPts == previousPts )
return 0;
memcpy( buffer, pixels, CVPixelBufferGetBytesPerRow(imageBuffer) * CVPixelBufferGetHeight(imageBuffer));
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
}
-
+
}
CVBufferRelease(imageBuffer);
- if(pixels)
- return currentPts;
- else
- return 0;
+ if(pixels)
+ return currentPts;
+ else
+ return 0;
}
@end
VLCDecompressedVideoOutput * output;
int height, width;
es_out_id_t * p_es_video;
+ BOOL b_es_setup;
+ es_format_t fmt;
};
{
demux_t *p_demux = (demux_t*)p_this;
demux_sys_t *p_sys = NULL;
- es_format_t fmt;
int i;
int i_width;
int i_height;
goto error;
}
- int ivideo;
- for(ivideo = 0; ivideo < [myVideoDevices count]; ivideo++){
+ NSUInteger ivideo;
+ NSUInteger deviceCount = [myVideoDevices count];
+ for(ivideo = 0; ivideo < deviceCount; ivideo++){
QTCaptureDevice *qtk_device;
qtk_device = [myVideoDevices objectAtIndex:ivideo];
- msg_Dbg( p_demux, "qtcapture %d/%lu %s %s", ivideo, [myVideoDevices count], [[qtk_device localizedDisplayName] UTF8String], [[qtk_device uniqueID] UTF8String]);
+ msg_Dbg( p_demux, "qtcapture %lu/%lu %s %s", ivideo, deviceCount, [[qtk_device localizedDisplayName] UTF8String], [[qtk_device uniqueID] UTF8String]);
if([[[qtk_device uniqueID]stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isEqualToString:qtk_currdevice_uid]){
break;
}
}
- memset( &fmt, 0, sizeof( es_format_t ) );
+ memset( &p_sys->fmt, 0, sizeof( es_format_t ) );
QTCaptureDeviceInput * input = nil;
NSError *o_returnedError;
/* Get the formats */
NSArray *format_array = [p_sys->device formatDescriptions];
QTFormatDescription* camera_format = NULL;
- for( int k = 0; k < [format_array count]; k++ )
+ NSUInteger formatCount = [format_array count];
+ for( NSUInteger k = 0; k < formatCount; k++ )
{
camera_format = [format_array objectAtIndex: k];
int chroma = VLC_CODEC_UYVY;
/* Now we can init */
- es_format_Init( &fmt, VIDEO_ES, chroma );
+ es_format_Init( &p_sys->fmt, VIDEO_ES, chroma );
NSSize encoded_size = [[camera_format attributeForKey:QTFormatDescriptionVideoEncodedPixelsSizeAttribute] sizeValue];
NSSize display_size = [[camera_format attributeForKey:QTFormatDescriptionVideoCleanApertureDisplaySizeAttribute] sizeValue];
par_size.height = display_size.height = encoded_size.height
= var_InheritInteger (p_this, "qtcapture-height");
- fmt.video.i_width = p_sys->width = encoded_size.width;
- fmt.video.i_height = p_sys->height = encoded_size.height;
+ p_sys->fmt.video.i_width = p_sys->width = encoded_size.width;
+ p_sys->fmt.video.i_height = p_sys->height = encoded_size.height;
+ p_sys->fmt.video.i_frame_rate = 25.0; // cave: check with setMinimumVideoFrameInterval (see below)
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;
+ p_sys->fmt.video.i_sar_num = (int64_t)encoded_size.height * par_size.width / encoded_size.width;
+ p_sys->fmt.video.i_sar_den = encoded_size.width;
}
msg_Dbg(p_demux, "encoded_size %i %i", (int)encoded_size.width, (int)encoded_size.height );
[NSNumber numberWithInt: p_sys->width], kCVPixelBufferWidthKey,
[NSNumber numberWithBool:YES], (id)kCVPixelBufferOpenGLCompatibilityKey,
nil]];
+ [p_sys->output setAutomaticallyDropsLateVideoFrames:YES];
+ [p_sys->output setMinimumVideoFrameInterval: (1/25)]; // 25 fps
p_sys->session = [[QTCaptureSession alloc] init];
[p_sys->session startRunning];
- msg_Dbg( p_demux, "added new video es %4.4s %dx%d",
- (char*)&fmt.i_codec, fmt.video.i_width, fmt.video.i_height );
-
- p_sys->p_es_video = es_out_Add( p_demux->out, &fmt );
-
[input release];
[pool release];
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 */ );
+ p_block = block_New( p_demux, p_sys->width * p_sys->height * 2 /* FIXME */ );
if( !p_block )
{
msg_Err( p_demux, "cannot get block" );
msleep( 10000 );
return 1;
}
+ else if( !p_sys->b_es_setup )
+ {
+ p_sys->fmt.video.i_frame_rate_base = [p_sys->output timeScale];
+ msg_Dbg( p_demux, "using frame rate base: %i", p_sys->fmt.video.i_frame_rate_base );
+ p_sys->p_es_video = es_out_Add( p_demux->out, &p_sys->fmt );
+ msg_Dbg( p_demux, "added new video es %4.4s %dx%d", (char*)&p_sys->fmt.i_codec, p_sys->fmt.video.i_width, p_sys->fmt.video.i_height );
+ p_sys->b_es_setup = YES;
+ }
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 );
case DEMUX_GET_PTS_DELAY:
pi64 = (int64_t*)va_arg( args, int64_t * );
- *pi64 = (int64_t)DEFAULT_PTS_DELAY;
+ *pi64 = INT64_C(1000) * var_InheritInteger( p_demux, "live-caching" );
return VLC_SUCCESS;
+ case DEMUX_GET_TIME:
+ pi64 = (int64_t*)va_arg( args, int64_t * );
+ *pi64 = mdate();
+ return VLC_SUCCESS;
+
default:
return VLC_EGENERIC;
}