1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
/*
Psychtoolbox3/Source/Common/SCREENGetMovieImage.c
AUTHORS:
mario.kleiner at tuebingen.mpg.de mk
PLATFORMS:
This file should build on any platform.
HISTORY:
10/23/05 mk Created.
DESCRIPTION:
Fetch an image from the specified movie object and create an OpenGL texture out of it.
Return a handle to the texture.
TO DO:
*/
#include "Screen.h"
static char useString[] = "[ texturePtr [timeindex]]=Screen('GetMovieImage', windowPtr, moviePtr, [waitForImage=1], [fortimeindex], [specialFlags = 0] [, specialFlags2 = 0]);";
static char synopsisString[] =
"Try to fetch a new texture image from movie object 'moviePtr' for visual playback/display in onscreen window 'windowPtr' and "
"return a texture-handle 'texturePtr' on successfull completion. 'waitForImage' If set to 1 (default), the function will wait "
"until the image becomes available. If set to zero, the function will just poll for a new image. If none is ready, it will return "
"a texturePtr of zero, or -1 if none will become ready because movie has reached its end and is not in loop mode. "
"On MS-Windows, polling mode is not possible, the function always waits for a new image, unless you use the GStreamer playback engine.\n"
"'fortimeindex' Don't request the next image, but the image closest to time 'fortimeindex' in seconds. The (optional) return "
"value 'timeindex' contains the exact time when the returned image should be displayed wrt. to the start of the movie - a presentation timestamp. \n"
"'specialFlags' (optional) encodes special requirements for the returned texture. A setting of 2 will request that the texture "
"is prepared for drawing it with highest possible spatial precision. See explanation of 'specialFlags' == 2 in Screen('MakeTexture') "
"for details. \n"
"'specialFlags2' (optional) More special flags: A setting of 1 tells the function to not return presentation timestamps in 'timeindex'. "
"This means that 'timeindex' will be always returned as zero and that the built-in detector for skipped frames is disabled as well. This "
"may (or may not) save a little bit of computation time during playback of very demanding movies on lower end systems, your mileage will "
"vary, depending on many factors.\n"
;
static char seeAlsoString[] = "CloseMovie PlayMovie GetMovieImage GetMovieTimeIndex SetMovieTimeIndex";
PsychError SCREENGetMovieImage(void)
{
PsychWindowRecordType *windowRecord;
PsychWindowRecordType *textureRecord;
PsychRectType rect;
double deadline, tnow;
int moviehandle = -1;
int waitForImage = TRUE;
double requestedTimeIndex = -1;
double presentation_timestamp = 0;
int rc=0;
int specialFlags = 0;
int specialFlags2 = 0;
// All sub functions should have these two lines
PsychPushHelp(useString, synopsisString, seeAlsoString);
if(PsychIsGiveHelp()) {PsychGiveHelp(); return(PsychError_none);};
PsychErrorExit(PsychCapNumInputArgs(6)); // Max. 6 input args.
PsychErrorExit(PsychRequireNumInputArgs(2)); // Min. 2 input args required.
PsychErrorExit(PsychCapNumOutputArgs(2)); // Max. 2 output args.
// Get the window record from the window record argument and get info from the window record
PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
// Only onscreen windows allowed:
if(!PsychIsOnscreenWindow(windowRecord)) {
PsychErrorExitMsg(PsychError_user, "GetMovieImage called on something else than an onscreen window.");
}
// Get the movie handle:
PsychCopyInIntegerArg(2, TRUE, &moviehandle);
if (moviehandle==-1) {
PsychErrorExitMsg(PsychError_user, "GetMovieImage called without valid handle to a movie object.");
}
// Get the 'waitForImage' flag: If waitForImage == true == 1, we'll do a blocking wait for
// arrival of a new image for playback. Otherwise we will return with a 0-Handle if there
// isn't any new image available.
PsychCopyInIntegerArg(3, FALSE, &waitForImage);
// Get the requested timeindex for the frame. The default is -1, which means: Get the next image,
// according to current movie playback time.
PsychCopyInDoubleArg(4, FALSE, &requestedTimeIndex);
// Get the optional specialFlags flag:
PsychCopyInIntegerArg(5, FALSE, &specialFlags);
// Get the optional specialFlags2 flag:
PsychCopyInIntegerArg(6, FALSE, &specialFlags2);
PsychGetAdjustedPrecisionTimerSeconds(&deadline);
deadline += 5;
while (rc==0) {
// With some backends (GStreamer), we can use a checkForImage of type 2 if a blocking wait is
// requested. Type 2 actually blocks inside the backend, to minimize cpu load and achieve lowest signalling delay
// once a new frame becomes available. Type 1 only polls. With the deprecated Quicktime backend, a type 1 and type 2
// check are the same - they translate into a poll for new image, and this while() loop needs to emulate a blocking
// wait via a poll-sleep cycle:
rc = PsychGetTextureFromMovie(windowRecord, moviehandle, (waitForImage != 0) ? 2 : 1, requestedTimeIndex, NULL, NULL);
PsychGetAdjustedPrecisionTimerSeconds(&tnow);
if (rc<0 || ((tnow > deadline) && (waitForImage != 0))) {
// No image available and there won't be any in the future, because the movie has reached
// its end and we are not in looped playback mode:
if (tnow > deadline) printf("PTB-ERROR: In Screen('GetMovieImage') for movie %i: Timed out while waiting for new frame after 5 seconds!\n", moviehandle);
// No new texture available: Return a negative handle:
PsychCopyOutDoubleArg(1, TRUE, -1);
// ...and an invalid timestamp:
PsychCopyOutDoubleArg(2, FALSE, -1);
// Ready!
return(PsychError_none);
}
else if (rc==0 && waitForImage == 0) {
// We should just poll once and no new texture available: Return a null-handle:
PsychCopyOutDoubleArg(1, TRUE, 0);
// ...and an invalid timestamp:
PsychCopyOutDoubleArg(2, FALSE, -1);
// Ready!
return(PsychError_none);
}
else if (rc==0 && waitForImage != 0) {
// No new texture available yet. Just sleep a bit and then retry...
// This is thankfully only needed / used for the deprecated QT backend.
PsychYieldIntervalSeconds(0.001);
}
}
// New image available: Go ahead...
// Create a texture record. Really just a window record adapted for textures.
PsychCreateWindowRecord(&textureRecord); // This also fills the window index field.
// Set mode to 'Texture':
textureRecord->windowType=kPsychTexture;
// We need to assign the screen number of the onscreen-window.
textureRecord->screenNumber=windowRecord->screenNumber;
// It is always a 32 bit texture for movie textures:
textureRecord->depth=32;
textureRecord->nrchannels = 4;
// Create default rectangle which describes the dimensions of the image. Will be overwritten
// later on.
PsychMakeRect(rect, 0, 0, 10, 10);
PsychCopyRect(textureRecord->rect, rect);
// Other setup stuff:
textureRecord->textureMemorySizeBytes= 0;
textureRecord->textureMemory=NULL;
// Assign parent window and copy its inheritable properties:
PsychAssignParentWindow(textureRecord, windowRecord);
// Try to fetch an image from the movie object and return it as texture:
PsychGetTextureFromMovie(windowRecord, moviehandle, FALSE, requestedTimeIndex, textureRecord, ((specialFlags2 & 1) ? NULL : &presentation_timestamp));
// Assign GLSL filter-/lookup-shaders if needed: usefloatformat is always == 0 as
// our current movie engine implementations only return 8 bpc fixed textures.
// The 'userRequest' flag is set if specialmode flag is set to 8.
PsychAssignHighPrecisionTextureShaders(textureRecord, windowRecord, 0, (specialFlags & 2) ? 1 : 0);
// Texture ready for consumption. Mark it valid and return handle to userspace:
PsychSetWindowRecordValid(textureRecord);
PsychCopyOutDoubleArg(1, TRUE, textureRecord->windowIndex);
// Return presentation timestamp for this image:
PsychCopyOutDoubleArg(2, FALSE, presentation_timestamp);
// Ready!
return(PsychError_none);
}
|