function VideoCaptureLatencyTest(texfetch, fullscreen, depth)
% VideoCaptureLatencyTest([texfetch=0][, fullscreen=1][, depth=1])
%
% 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

if nargin < 2
    fullscreen=1;
end

if nargin < 3
    depth = 1;
end

if IsOctave
    more off;
    ignore_function_time_stamp('all');
end

% Open display with default settings:
if fullscreen<1
    win=Screen('OpenWindow', screen, 0, [0 0 800 600]);
else
    win=Screen('OpenWindow', screen, 0);
end

[~, 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 %#ok<*NOPRT>

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
        Screen('DrawText', win, 'Point camera to center of Display - Then press any key', 10, h-50);
        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);
        count = count + 1;
    end
end

calcedlatency = PsychCamSettings('EstimateLatency', grabber) * 1000.0;
fprintf('Estimated camera latency from cam or lut: %f msecs.', calcedlatency);
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;

    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, ~, intensity]=Screen('GetCapturedImage', win, grabber, 0);
        end

        if tex > 0
            Screen('Close', tex);
        end

        blackintensity = intensity;
        threshold = blackintensity * 1.02;

        % 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, ~, 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; %#ok<*AGROW>
        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;
    fprintf('Average delay in block number %i: %f msecs.', reps, tavgdelay);

    tminimum = min(tminimum, tavgdelay);
    tdelays(reps) = tavgdelay;
end

% Shutdown capture loop, close screens...
Screen('CloseVideoCapture', grabber);
Screen('CloseAll');

fprintf('Minimum average delay from the 5 blocks of trials: %f msecs.\n', tminimum)
fprintf('Absolute minimum delay over all trials: %f msecs.\n', tminimum2)

figure;
plot(tdelays);
title('Average delay in each block [msecs]')
figure;
plot(ttotal);
title('Delay for each trial [msecs]')

return;