function VideoCaptureLatencyTest(texfetch, fullscreen, depth) % VideoCaptureLatencyTest % % This routine tests the latency of Videocapture for % a given Camera -> Computer -> PTB -> gfx-card -> display combo. % % Working principle and usage: % % 1. Point camera to monitor so that cameras field of view captures monitor % display area. % % 2. Calibration: First a black screen is shown to the cam and captured to % find the average intensity of an image of a black display. % Then (over ten trials), the screen turns white and the script measures % the time delay between onset of white screen and arrival of a captured % image with at least 25% more intensity than the 'black'-image -- our % white image. This procedure is repeated 10 times and latencies averaged. % % -> Rough estimate of delay from scene change to arrival of frame. % -> You have to add the display onset delay if captured image should be % shown to subject for video feedback loops. % % Parameters: % % texfetch == 0 Measure only capture latency. 1 == Measure texture fetch % latency as well. 2 == Measure drawing and onset latency as well. % % History: % 2/9/06 mk Written. % Running OpenGL-PTB? This is required. AssertOpenGL; rate = 30; % Find stimulus display: screen=max(Screen('Screens')); if nargin < 1 texfetch=0; end; texfetch if nargin < 2 fullscreen=1; end; fullscreen if nargin < 3 depth = 1; end; depth if IsOctave more off; ignore_function_time_stamp('all'); end %try % Open display with default settings: if fullscreen<1 win=Screen('OpenWindow', screen, 0, [0 0 800 600]); else win=Screen('OpenWindow', screen, 0); end; [w h]=Screen('WindowSize', win); % Setup font and textsize: 24 is also a good size for Linux. Screen('TextSize', win, 24); Screen('TextStyle', win, 1); % Show initial blank screen: Screen('Flip',win); % Open default video capture device: grabber = Screen('OpenVideoCapture', win, 0, [0 0 640 480], depth); % Start video capture: We request at least a 30 Hz capture rate and lowlatency (=1) mode: % Requested start time is 4 seconds from now: [fps capturestarttime]=Screen('StartVideoCapture', grabber, rate, 1, GetSecs + 4); fps oldpts = 0; count = 0; t=GetSecs; while (GetSecs - t) < 600 if KbCheck break; end; [tex pts nrdropped intensity]=Screen('GetCapturedImage', win, grabber, 0); % fprintf('tex = %i pts = %f\n', tex, pts); if (tex>0) % Print instructions: Screen('DrawText', win, 'Point camera to center of Display - Then press any key', 10, h-50); % Print pts: Screen('DrawText', win, ['Capture timestamp (s): ' sprintf('%.4f', pts)], 0, 0, 255); if count>0 % Compute delta: delta = (pts - oldpts) * 1000; oldpts = pts; Screen('DrawText', win, ['Delta since last frame (ms): ' sprintf('%.4f', delta)], 0, 24, 255); Screen('DrawText', win, ['Delta start to first frame (ms): ' sprintf('%.4f', camstartlatency)], 0, 96, 255); else % First image in video fifo. camstartlatency = (pts - capturestarttime) * 1000.0 end; % Compute and print intensity: Screen('DrawText', win, ['Mean intensity: ' sprintf('%.2f', intensity)], 0, 48, 255); % Print count of dropped frames since last fetch: Screen('DrawText', win, ['Dropped frames: ' sprintf('%i', nrdropped)], 0, 72, 255); % New texture from framegrabber. Screen('DrawTexture', win, tex); Screen('Flip', win, 0, 0, 2); Screen('Close', tex); tex=0; count = count + 1; end; end; telapsed = GetSecs - t calcedlatency = PsychCamSettings('EstimateLatency', grabber) * 1000.0 tminimum = 10000000000.0; tminimum2 = 10000000000.0; tcount = 1; for reps=1:5 % Ok, preview finished. Cam should now point to the screen and % we can start the latency measurement procedure: ntrials = 10; tavgdelay = 0; threshold = 0; for i=1:ntrials % Make screen black: Screen('FillRect', win, 0); Screen('Flip', win); % Capture at least 20 frames to make sure we're really black... for j=1:20 Screen('GetCapturedImage', win, grabber, 2); end; % Capture a black frame: tex=0; while (tex==0) [tex pts nrdropped intensity]=Screen('GetCapturedImage', win, grabber, 0); end; if (tex>0) Screen('Close', tex); end; % if threshold==0 blackintensity = intensity; threshold = blackintensity * 1.02; % end; % Eat up all enqueued images, if any. tex=1; while (tex>0) [tex newpts]=Screen('GetCapturedImage', win, grabber, 0); if (tex>0) Screen('Close', tex); pts = newpts; end; end; % Make display white: Screen('FillRect', win, 255); % Show it and take onset timestamp: tonset = Screen('Flip', win); % Now we loop and capture until intensity exceeds threshold: tex=0; intensity=0; lagframes=0; ptsblack = pts; while (tex>=0 && intensity < threshold) if texfetch>0 waitmode=1; else waitmode=2; end; [tex pts nrdropped intensity]=Screen('GetCapturedImage', win, grabber, waitmode); % Captured! Take timestamp: tdelay=(GetSecs - tonset) * 1000; if tex>0 lagframes=lagframes+1; if texfetch>1 && intensity>=threshold Screen('DrawTexture',win,tex,[],[],[],0); tdelay = (Screen('Flip',win) - tonset) * 1000; end; Screen('Close', tex); tex=0; end; end; tdelay lagframes ptslag = (pts - ptsblack) * 1000 tavgdelay=tavgdelay + tdelay; tminimum2=min(tminimum2, tdelay); ttotal(tcount)=tdelay; tcount = tcount + 1; % Next trial... end; % Stop and restart capture loop: Screen('StopVideoCapture', grabber); % Restart with a random delay between 0.0 and 1.0 seconds... Screen('StartVideoCapture', grabber, rate, 1, GetSecs + rand); tavgdelay = tavgdelay / ntrials; tavgdelay tminimum = min(tminimum, tavgdelay); tdelays(reps) = tavgdelay; end % Shutdown capture loop, close screens... Screen('CloseVideoCapture', grabber); Screen('CloseAll'); tminimum tminimum2 figure; plot(tdelays); figure; plot(ttotal); return; %catch %Screen('CloseAll'); %psychrethrow(psychlasterror); %end;