00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "Component/ModelManager.H"
00039 #include "Component/ModelOptionDef.H"
00040 #include "Audio/AudioWavFile.H"
00041 #include "Devices/AudioGrabber.H"
00042 #include "Devices/AudioMixer.H"
00043 #include "Devices/DeviceOpts.H"
00044 #include "Image/Image.H"
00045 #include "Media/MPEGStream.H"
00046 #include "Media/MediaOpts.H"
00047 #include "Psycho/PsychoDisplay.H"
00048 #include "Psycho/EyeTrackerConfigurator.H"
00049 #include "Psycho/EyeTracker.H"
00050 #include "Psycho/PsychoOpts.H"
00051 #include "Component/EventLog.H"
00052 #include "Component/ComponentOpts.H"
00053 #include "GUI/SDLdisplay.H"
00054 #include "Util/MathFunctions.H"
00055 #include "Util/Types.H"
00056 #include "Video/VideoFrame.H"
00057 #include "Neuro/NeuroOpts.H"
00058 #include "Image/DrawOps.H"
00059 #include "Image/ImageSet.H"
00060 #include "Image/ShapeOps.H"
00061 #include "GUI/GUIOpts.H"
00062 #include "Image/CutPaste.H"
00063 #include "Raster/Raster.H"
00064
00065 #include <vector>
00066 #include <pthread.h>
00067
00068 #define CACHELEN 150
00069
00070 volatile bool recordaudio = false;
00071 volatile bool keepgoing = true;
00072 volatile int recnb = 0;
00073 volatile bool audioA = false;
00074 volatile bool movingV = false;
00075
00076 static const ModelOptionDef OPT_AudioAfter =
00077 { MODOPT_FLAG, "AudioAfter", &MOC_DISPLAY, OPTEXP_SAVE,
00078 "Record audio after the movie presentation",
00079 "audio-after", '\0', "", "false" };
00080
00081 static const ModelOptionDef OPT_MovingVideo =
00082 { MODOPT_FLAG, "MovingVideo", &MOC_DISPLAY, OPTEXP_SAVE,
00083 "Play the series of videos as moving videos or still videos",
00084 "moving-video", '\0', "", "false" };
00085
00086
00087 static void *audiorecorder(void *agbv)
00088 {
00089 bool recording = false;
00090 std::vector<AudioBuffer<byte> > rec;
00091 AudioGrabber *agb = (AudioGrabber *)agbv;
00092
00093 while(keepgoing)
00094 {
00095
00096 if (recording == false && recordaudio == true)
00097 { rec.clear(); recording = true; }
00098
00099
00100 if (recording == true && recordaudio == false)
00101 {
00102
00103 char fname[100];
00104 if (audioA == true)
00105 {
00106 if (movingV == true)
00107 sprintf(fname, "25sec_moving_audio%04d.wav", recnb);
00108 else
00109 sprintf(fname, "25sec_still_audio%04d.wav", recnb);
00110 }
00111 else
00112 {
00113 if (movingV == true)
00114 sprintf(fname, "3sec_moving_audio%04d.wav", recnb);
00115 else
00116 sprintf(fname, "3sec_still_audio%04d.wav", recnb);
00117 }
00118 writeAudioWavFile(fname, rec);
00119
00120
00121 recnb ++; recording = false;
00122 }
00123
00124
00125
00126
00127
00128
00129
00130 AudioBuffer<byte> data;
00131 agb->grab(data);
00132 if (data.nsamples() != 256U)
00133 LERROR("Recorded len %u is not 256!", data.nsamples());
00134
00135
00136 if (recording == true && recordaudio == true && data.nsamples() == 256U)
00137
00138 rec.push_back(data);
00139 }
00140
00141
00142 pthread_exit(0);
00143 return NULL;
00144 }
00145
00146
00147 static bool cacheFrame(nub::soft_ref<InputMPEGStream>& mp,
00148 std::deque<VideoFrame>& cache)
00149 {
00150 const VideoFrame frame = mp->readVideoFrame();
00151 if (!frame.initialized()) return false;
00152
00153 cache.push_front(frame);
00154 return true;
00155 }
00156
00157
00158 static int submain(const int argc, char** argv)
00159 {
00160 MYLOGVERB = LOG_INFO;
00161
00162
00163 ModelManager manager("Psycho Movie");
00164
00165 OModelParam<bool> audioAfter(&OPT_AudioAfter, &manager);
00166 OModelParam<bool> movingVideo(&OPT_MovingVideo, &manager);
00167
00168
00169 nub::soft_ref<InputMPEGStream> mp
00170 (new InputMPEGStream(manager, "Input MPEG Stream", "InputMPEGStream"));
00171 manager.addSubComponent(mp);
00172
00173 nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager));
00174 manager.addSubComponent(d);
00175
00176 nub::soft_ref<AudioMixer> mix(new AudioMixer(manager));
00177 manager.addSubComponent(mix);
00178
00179 nub::soft_ref<AudioGrabber> agb(new AudioGrabber(manager));
00180 manager.addSubComponent(agb);
00181
00182 nub::soft_ref<EyeTrackerConfigurator>
00183 etc(new EyeTrackerConfigurator(manager));
00184 manager.addSubComponent(etc);
00185
00186 nub::soft_ref<EventLog> el(new EventLog(manager));
00187 manager.addSubComponent(el);
00188
00189
00190 manager.setOptionValString(&OPT_InputMPEGStreamPreload, "true");
00191 manager.setOptionValString(&OPT_EventLogFileName, "psychodata.psy");
00192 manager.setOptionValString(&OPT_EyeTrackerType, "ISCAN");
00193 manager.setOptionValString(&OPT_AudioMixerLineIn, "false");
00194 manager.setOptionValString(&OPT_AudioMixerCdIn, "false");
00195 manager.setOptionValString(&OPT_AudioMixerMicIn, "true");
00196 manager.setOptionValString(&OPT_AudioGrabberBits, "8");
00197 manager.setOptionValString(&OPT_AudioGrabberFreq, "11025");
00198 manager.setOptionValString(&OPT_AudioGrabberBufSamples, "256");
00199 manager.setOptionValString(&OPT_AudioGrabberChans, "1");
00200
00201
00202 if (manager.parseCommandLine(argc, argv,
00203 "<movie1.mpg> ... <movieN.mpg>", 1, -1)==false)
00204 return(1);
00205
00206 audioA = audioAfter.getVal();
00207 movingV = movingVideo.getVal();
00208
00209
00210 nub::soft_ref<EyeTracker> et = etc->getET();
00211 d->setEyeTracker(et);
00212 d->setEventLog(el);
00213 et->setEventLog(el);
00214
00215
00216 manager.start();
00217
00218
00219 d->clearScreen();
00220 d->displayISCANcalib();
00221 d->waitForKey();
00222
00223
00224 uint nbmovies = manager.numExtraArgs(); int index[nbmovies];
00225 for (uint i = 0; i < nbmovies; i ++) index[i] = i;
00226 LINFO("Randomizing movies..."); randShuffle(index,nbmovies);
00227
00228
00229 pthread_t runner;
00230 pthread_create(&runner, NULL, &audiorecorder, (void *)(agb.get()));
00231 char txt[100];
00232
00233
00234 std::deque<VideoFrame> cache;
00235
00236 for (uint i = 0; i < nbmovies; i ++)
00237 {
00238
00239 int calibFreq = 10;
00240
00241 if(movingVideo.getVal() == false && audioAfter.getVal() == true)
00242 {
00243 calibFreq = 2;
00244 }
00245
00246 if ((i % calibFreq) == 0)
00247 {
00248
00249 d->displayText("<SPACE> for eye-tracker calibration");
00250 int k = d->waitForKey();
00251 if (k == ' ') et->calibrate(d);
00252 d->clearScreen();
00253 if (i == 0) d->displayText("<SPACE> to start with the movies");
00254 else d->displayText("<SPACE> to continue with the movies");
00255 d->waitForKey();
00256 }
00257
00258
00259 d->clearScreen();
00260 if (cache.size()) LFATAL("ooops, cache not empty?");
00261 bool streaming = true;
00262 LINFO("Buffering '%s'...", manager.getExtraArg(index[i]).c_str());
00263
00264
00265 mp->setFileName(manager.getExtraArg(index[i]));
00266 for (uint j = 0; j < CACHELEN; j ++)
00267 {
00268 streaming = cacheFrame(mp, cache);
00269 if (streaming == false) break;
00270 }
00271 LINFO("'%s' ready.", manager.getExtraArg(index[i]).c_str());
00272
00273
00274 sleep(1); if (system("sync")) LERROR("error in sync");
00275
00276
00277 d->displayFixation();
00278
00279
00280 d->waitForKey(); int frame = 0;
00281 d->waitNextRequestedVsync(false, true);
00282 d->pushEvent(std::string("===== Playing movie: ") +
00283 manager.getExtraArg(index[i]) + " =====");
00284
00285
00286 et->track(true);
00287
00288
00289 if (audioAfter.getVal() == false)
00290 {
00291 sprintf(txt, "Start audio recording: audio%04d.wav", recnb);
00292 d->pushEvent(txt);
00293 recordaudio = true;
00294 }
00295
00296
00297 d->displayFixationBlink();
00298
00299
00300 d->createVideoOverlay(VIDFMT_YUV420P);
00301
00302
00303 while(cache.size())
00304 {
00305
00306 if (streaming) streaming = cacheFrame(mp, cache);
00307
00308
00309 VideoFrame vidframe = cache.back();
00310 d->displayVideoOverlay(vidframe, frame,
00311 SDLdisplay::NEXT_VSYNC);
00312 cache.pop_back();
00313
00314 ++frame;
00315 }
00316
00317
00318
00319
00320
00321 d->destroyYUVoverlay();
00322 d->clearScreen();
00323
00324
00325
00326 if (audioAfter.getVal())
00327 {
00328 const int movieFreq = movingVideo.getVal() ? 5 : 1;
00329
00330 if (((i+1) % movieFreq) == 0)
00331 {
00332 d->displayText("Please describe what you saw in the last five videos.");
00333 sleep(1);
00334
00335 sprintf(txt, "Start audio recording after 5 movies: audio%04d.wav", recnb);
00336 d->pushEvent(txt);
00337 recordaudio = true;
00338 d->clearScreen();
00339 d->displayFixation();
00340
00341 usleep(25000000);
00342
00343
00344 sprintf(txt, "Stop audio recording after 5 movies: audio%04d.wav", recnb);
00345 d->pushEvent(txt);
00346 recordaudio = false;
00347
00348 d->clearScreen();
00349 }
00350 }
00351 else
00352 {
00353 sleep(3);
00354
00355
00356 sprintf(txt, "Stop audio recording: audio%04d.wav", recnb);
00357 d->pushEvent(txt);
00358 recordaudio = false;
00359 }
00360
00361
00362
00363 et->track(false);
00364 }
00365
00366 d->clearScreen();
00367 d->displayText("Experiment complete. Thank you!");
00368 d->waitForKey();
00369
00370
00371 keepgoing = false;
00372 sleep(1); if (system("sync")) LERROR("error in sync");
00373
00374
00375 manager.stop();
00376
00377
00378 return 0;
00379 }
00380
00381
00382 extern "C" int main(const int argc, char** argv)
00383 {
00384
00385
00386
00387
00388 try
00389 {
00390 return submain(argc, argv);
00391 }
00392 catch (...)
00393 {
00394 REPORT_CURRENT_EXCEPTION;
00395 }
00396
00397 return 1;
00398 }
00399
00400
00401
00402
00403
00404