vtkMILVideoSource.cxx 29.3 KB
Newer Older
1 2 3
/*=========================================================================

  Program:   Visualization Toolkit
4
  Module:    vtkMILVideoSource.cxx
5

6
  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 8
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
Will Schroeder's avatar
Will Schroeder committed
9

10 11
     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12
     PURPOSE.  See the above copyright notice for more information.
13 14 15

=========================================================================*/
#include "vtkMILVideoSource.h"
Brad King's avatar
Brad King committed
16
#include "vtkTimerLog.h"
17
#include "vtkObjectFactory.h"
18
#include "vtkCriticalSection.h"
19

Brad King's avatar
Brad King committed
20
#include <mil.h>
Sean McBride's avatar
Sean McBride committed
21 22
#include <cctype>
#include <cstring>
Brad King's avatar
Brad King committed
23 24

vtkStandardNewMacro(vtkMILVideoSource);
25 26 27 28 29 30

//----------------------------------------------------------------------------
vtkMILVideoSource::vtkMILVideoSource()
{
  this->Initialized = 0;

31 32 33
  this->FatalMILError = 0;

  this->ContrastLevel = 1.0;
David Gobbi's avatar
David Gobbi committed
34 35
  this->BrightnessLevel = 128;
  this->HueLevel = 0.0;
36
  this->SaturationLevel = 1.0;
37 38
  this->BlackLevel = 0.0;
  this->WhiteLevel = 255.0;
39 40 41 42 43 44 45 46 47

  this->VideoChannel = 0;
  this->VideoInput = VTK_MIL_MONO;
  this->VideoInputForColor = VTK_MIL_YC;
  this->VideoFormat = VTK_MIL_RS170;

  this->FrameMaxSize[0] = 640;
  this->FrameMaxSize[1] = 480;

48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
  this->OldHookFunction = 0;
  this->OldUserDataPtr = 0;

  this->MILAppID = 0;
  this->MILSysID = 0;
  this->MILDigID = 0;
  this->MILBufID = 0;
  //this->MILDispBufID = 0;
  //this->MILDispID = 0;

  this->MILAppInternallyAllocated = 0;
  this->MILSysInternallyAllocated = 0;

  this->MILSystemType = VTK_MIL_DEFAULT;
  this->MILSystemNumber = M_DEFAULT;

  this->MILDigitizerNumber = M_DEFAULT;
  this->MILDigitizerDCF = NULL;

67
  this->MILErrorMessages = 1;
68 69

  this->FlipFrames = 1; //apply vertical flip to each frame
70 71 72 73 74 75

  // for accurate timing
  this->LastTimeStamp = 0;
  this->LastFrameCount = 0;
  this->EstimatedFramePeriod = 0.033;
  this->NextFramePeriod = 0.033;
76 77 78 79
}

//----------------------------------------------------------------------------
vtkMILVideoSource::~vtkMILVideoSource()
80 81
{
  this->vtkMILVideoSource::ReleaseSystemResources();
82

83 84
  delete [] this->MILDigitizerDCF;
  this->MILDigitizerDCF = NULL;
85 86

  this->SetMILSystemType(0);
87
}
88 89

//----------------------------------------------------------------------------
90
void vtkMILVideoSource::PrintSelf(ostream& os, vtkIndent indent)
91
{
Brad King's avatar
Brad King committed
92
  this->Superclass::PrintSelf(os,indent);
93

94 95
  os << indent << "VideoChannel: " << this->VideoChannel << "\n";

96 97 98 99 100 101 102 103
  os << indent << "ContrastLevel: " << this->ContrastLevel << "\n";

  os << indent << "BrightnessLevel: " << this->BrightnessLevel << "\n";

  os << indent << "HueLevel: " << this->HueLevel << "\n";

  os << indent << "SaturationLevel: " << this->SaturationLevel << "\n";

104 105 106 107
  os << indent << "BlackLevel: " << this->BlackLevel << "\n";

  os << indent << "WhiteLevel: " << this->WhiteLevel << "\n";

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
  os << indent << "VideoInput: ";
  switch (this->VideoInput)
    {
    case VTK_MIL_MONO:
      os << "Mono\n";
      break;
    case VTK_MIL_COMPOSITE:
      os << "Mono\n";
      break;
    case VTK_MIL_YC:
      os << "Mono\n";
      break;
    case VTK_MIL_RGB:
      os << "Mono\n";
      break;
    case VTK_MIL_DIGITAL:
      os << "Mono\n";
      break;
    default:
      os << "Unrecognized\n";
      break;
    }

  os << indent << "VideoFormat: ";
  switch (this->VideoFormat)
    {
    case VTK_MIL_RS170:
      os << "RS170\n";
      break;
    case VTK_MIL_NTSC:
      os << "NTSC\n";
      break;
    case VTK_MIL_CCIR:
      os << "CCIR\n";
      break;
    case VTK_MIL_PAL:
      os << "PAL\n";
      break;
    case VTK_MIL_SECAM:
      os << "SECAM\n";
      break;
    default:
      os << "Unrecognized\n";
      break;
    }

154
  os << indent << "MILSystemType: " <<
155
    (this->MILSystemType ? this->MILSystemType : "Default") << "\n";
156 157 158

  os << indent << "MILSystemNumber: " << this->MILSystemNumber << "\n";

159 160
  os << indent << "MILDigitizerDCF: " << (this->MILDigitizerDCF ?
    this->MILDigitizerDCF : "NULL") << "\n";
161 162 163 164 165 166 167 168 169 170 171 172 173 174

  os << indent << "MILDigitizerNumber: " << this->MILDigitizerNumber << "\n";

  os << indent << "MILErrorMessages: " << (this->MILErrorMessages ? "On\n" : "Off\n");

  os << indent << "MILAppID: " << this->MILAppID << "\n";
  os << indent << "MILSysID: " << this->MILSysID << "\n";
  os << indent << "MILDigID: " << this->MILDigID << "\n";
  os << indent << "MILBufID: " << this->MILBufID << "\n";
  //  os << indent << "MILDispBufID: " << this->MILDispBufID << "\n";
  //  os << indent << "MILDispID: " << this->MILDispID << "\n";
}

//----------------------------------------------------------------------------
175
// load the DLL for the specified Matrox digitizer, for MIL 5 and MIL 6
176
char *vtkMILVideoSource::MILInterpreterForSystem(const char *system)
177 178 179 180
{
  char *dll_name;
  char *func_name;

181
  if (strcmp(system,VTK_MIL_CORONA) == 0)
182
    {
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
    dll_name = "milcor";
    func_name = "MDCoronaCommandDecoder";
    }
  else if (strcmp(system,VTK_MIL_METEOR) == 0)
    {
    dll_name = "milmet";
    func_name = "MDMeteorCommandDecoder";
    }
  else if (strcmp(system,VTK_MIL_METEOR_II) == 0)
    {
    dll_name = "milmet2";
    func_name = "MDMeteorIICommandDecoder";
    }
  else if (strcmp(system,VTK_MIL_METEOR_II_DIG) == 0)
    {
    dll_name = "milmet2d";
    func_name = "MDMeteorIIDigCommandDecoder";
    }
  else if (strcmp(system,VTK_MIL_PULSAR) == 0)
    {
    dll_name = "milpul";
    func_name = "MDPulsarCommandDecoder";
    }
  else if (strcmp(system,VTK_MIL_GENESIS) == 0)
    {
    dll_name = "milgen";
    func_name = "MDGenesisCommandDecoder";
210
    }
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
  else if (strcmp(system,VTK_MIL_ORION) == 0)
    {
    dll_name = "milorion";
    func_name = "MDOrionCommandDecoder";
    }
  else
    {
    dll_name = "unknown";
    func_name = "unknown";
    }

  // first try mil.dll (for later versions of mil)
  this->MILInterpreterDLL = "mil";
  HINSTANCE mil_lib = LoadLibrary("mil");
  if (mil_lib == 0)
    {
    return NULL;
    }
  void *proc_address = (void *)GetProcAddress(mil_lib,func_name);
  if (proc_address)
    {
    return proc_address;
    }

  // then try the device-specific dll
236
  this->MILInterpreterDLL = dll_name;
237
  mil_lib = LoadLibrary(dll_name);
238 239 240 241 242 243

  if (mil_lib == 0)
    {
    return NULL;
    }

244
  return (char *)GetProcAddress(mil_lib,func_name);
245 246 247 248
}

//----------------------------------------------------------------------------
static void vtkMILVideoSourceSetChannel(long digID, int channel)
249
{
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
  if (digID == 0)
    {
    return;
    }

  int mil_channel = M_DEFAULT;

  switch(channel)
    {
    case 0:
      mil_channel = M_CH0;
      break;
    case 1:
      mil_channel = M_CH1;
      break;
    case 2:
      mil_channel = M_CH2;
      break;
    case 3:
      mil_channel = M_CH3;
      break;
    }

  MdigChannel(digID,mil_channel);
}

//----------------------------------------------------------------------------
static void vtkMILVideoSourceSetLevel(long digID, int ref, float level)
278
{
279 280 281 282 283
  if (digID == 0)
    {
    return;
    }

284
  long int_level = M_MIN_LEVEL + level*(M_MAX_LEVEL-M_MIN_LEVEL);
285

286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
  if (int_level < M_MIN_LEVEL)
    {
    int_level = M_MIN_LEVEL;
    }

  if (int_level > M_MAX_LEVEL)
    {
    int_level = M_MAX_LEVEL;
    }

  MdigReference(digID,ref,int_level);
}

//----------------------------------------------------------------------------
static void vtkMILVideoSourceSetSize(long digID, int size[3], int maxSize[2])
{
  if (digID == 0)
    {
    return;
    }

  int shrink_x = maxSize[0]/size[0];
  int shrink_y = maxSize[1]/size[1];
  if (shrink_x < 1)
    {
    shrink_x = 1;
    }
  if (shrink_y < 1)
    {
    shrink_y = 1;
    }
317

318 319 320 321 322 323 324 325 326 327 328 329
  // convert shrink_x, shrink_y to power of 2
  int i;
  for (i = 0; shrink_x; i++)
    {
    shrink_x = shrink_x >> 1;
    }
  shrink_x = 1 << (i-1);
  for (i = 0; shrink_y; i++)
    {
    shrink_y = shrink_y >> 1;
    }
  shrink_y = 1 << (i-1);
330

331 332
  MdigControl(digID,M_GRAB_SCALE_X,1.0/shrink_x);
  MdigControl(digID,M_GRAB_SCALE_Y,1.0/shrink_y);
333 334 335 336 337
}

//----------------------------------------------------------------------------
void vtkMILVideoSource::Initialize()
{
338
  static char *system_types[] = { VTK_MIL_METEOR, VTK_MIL_METEOR_II,
339 340
                                  VTK_MIL_METEOR_II_DIG, VTK_MIL_METEOR_II_CL,
                                  VTK_MIL_METEOR_II_1394, VTK_MIL_CORONA_II,
341
                                  VTK_MIL_CORONA, VTK_MIL_PULSAR,
342 343 344
                                  VTK_MIL_GENESIS, VTK_MIL_GENESIS_PLUS,
                                  VTK_MIL_ORION, VTK_MIL_CRONOS,
                                  VTK_MIL_ODYSSEY, 0 };
345

346
  if (this->Initialized || this->FatalMILError)
347 348 349 350 351 352
    {
    return;
    }

  this->Initialized = 1;

353 354 355
  // update the frame buffer now just in case there is an error
  this->UpdateFrameBuffer();

356 357
  if (this->MILAppID == 0)
    {
358 359 360 361 362 363 364
    this->MILAppID = MappAlloc(M_DEFAULT,M_NULL);
    if (this->MILAppID == 0)
      {
      this->ReleaseSystemResources();
      vtkErrorMacro(<< "Initialize: couldn't open MIL application\n");
      return;
      }
365
    this->MILAppInternallyAllocated = 1;
366 367
    }

368 369
  long version = MappInquire(M_VERSION,M_NULL);

370 371
  if (this->MILSysID == 0)
    {
372
    char *systemType;
373
    if (this->MILSystemType != VTK_MIL_DEFAULT)
374
      { // asked for a particular system by name
375 376 377 378 379 380 381 382 383 384
      if (version >= 7)
        {  // try MIL 7 style of allocation
        char tmptext[256];
        strncpy(tmptext,"\\\\.\\",4);
        strncpy(&tmptext[4],this->MILSystemType,252);
        this->MILSysID = MsysAlloc(tmptext,this->MILSystemNumber,
                                   M_DEFAULT,M_NULL);
        }
      else
        { // try MIL 5, MIL 6 which requires loading the appropriate DLL
385 386 387 388 389 390
        systemType = this->MILInterpreterForSystem(this->MILSystemType);
        if (systemType)
          {
          this->MILSysID = MsysAlloc(systemType, this->MILSystemNumber,
                                     M_DEFAULT,M_NULL);
          }
Brad King's avatar
Brad King committed
391
        }
392 393

      if (this->MILSysID == 0)
Brad King's avatar
Brad King committed
394 395 396 397 398
        {
        this->ReleaseSystemResources();
        vtkErrorMacro(<< "Initialize: couldn't find " << this->MILInterpreterDLL << ".dll\n");
        return;
        }
399 400
      }
    else
401
      { // try for any known MIL system
402 403 404
      MappControl(M_ERROR,M_PRINT_DISABLE);
      int i;
      for (i = 0; this->MILSysID == 0 && system_types[i] != 0; i++)
Brad King's avatar
Brad King committed
405
        {
406
        if (version >= 7)
Brad King's avatar
Brad King committed
407
          {
408 409 410 411 412 413 414 415
          // try MIL 7 style of allocation
          char tmptext[256];
          sprintf(tmptext,"\\\\.\\%s",system_types[i]);
          this->MILSysID = MsysAlloc(tmptext,this->MILSystemNumber,
                                     M_DEFAULT,M_NULL);
          }
        else
          { // try MIL 5, MIL 6 which requires loading the appropriate DLL
416 417 418 419
          systemType = this->MILInterpreterForSystem(system_types[i]);
          if (systemType)
            {
            this->MILSysID = MsysAlloc(systemType,this->MILSystemNumber,
Brad King's avatar
Brad King committed
420
                                     M_DEFAULT,M_NULL);
421
            }
Brad King's avatar
Brad King committed
422 423
          }
        }
424
      if (system_types[i] == 0)
Brad King's avatar
Brad King committed
425 426 427 428 429
        {
        this->ReleaseSystemResources();
        vtkErrorMacro(<< "Initialize: Couldn't find a Matrox frame grabber on the system\n");
        return;
        }
430
      MappControl(M_ERROR,M_PRINT_ENABLE);
431 432 433 434 435 436 437 438
      }
    this->MILSysInternallyAllocated = 1;
    }

  this->AllocateMILBuffer();

  this->AllocateMILDigitizer();

439
  MappControl(M_ERROR,
Brad King's avatar
Brad King committed
440
              ( this->MILErrorMessages ? M_PRINT_ENABLE : M_PRINT_DISABLE ));
441

442
  // update frame buffer again to reflect any changes
443
  this->UpdateFrameBuffer();
444
}
445

446 447 448
//----------------------------------------------------------------------------
void vtkMILVideoSource::ReleaseSystemResources()
{
449 450 451 452
  if (this->MILAppID != 0)
    {
    MappControl(M_ERROR, M_PRINT_DISABLE);
    }
453 454
  if (this->MILDigID)
    {
455
    if (this->Recording)
456 457 458 459
      {
      MdigHalt(this->MILDigID);
      }
    MdigGrabWait(this->MILDigID,M_GRAB_END);
460
    this->Recording = 0;
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
    }
  /*
  if (this->MILDispID != 0)
    {
    MdispDeselect(this->MILDispID,this->MILDispBufID);
    MdispFree(this->MILDispID);
    this->MILDispID = 0;
    }
  if (this->MILDispBufID != 0)
    {
    MbufFree(this->MILDispBufID);
    this->MILDispBufID = 0;
    }
  */
  if (this->MILBufID != 0)
    {
    MbufFree(this->MILBufID);
    this->MILBufID = 0;
    }
  if (this->MILDigID != 0)
    {
482 483
    //  The MdigFree call never returns if it is called by atexit(),
    //  and it doesn't seem to hurt anything if it isn't called.
484
    MdigFree(this->MILDigID);
485 486 487 488 489 490 491 492 493 494 495 496 497
    this->MILDigID = 0;
    }
  if (this->MILSysInternallyAllocated && this->MILSysID != 0)
    {
    MsysFree(this->MILSysID);
    this->MILSysID = 0;
    }
  if (this->MILAppInternallyAllocated && this->MILAppID != 0)
    {
    MappFree(this->MILAppID);
    this->MILAppID = 0;
    }
  this->Initialized = 0;
498
  this->FatalMILError = 0;
499 500
}

501 502 503 504 505 506 507 508 509 510 511 512 513 514
//----------------------------------------------------------------------------
long MFTYPE vtkMILVideoSourceHook(long HookType, MIL_ID EventID, void *UserPtr)
{
  vtkMILVideoSource *self = (vtkMILVideoSource *)UserPtr;

  if (HookType == M_GRAB_FRAME_END)
    {
    double time = 1000;
    float rate = self->GetFrameRate();
    int format = self->GetVideoFormat();
    int frame_stride;
    if (rate > 0)
      {
      frame_stride = (int)(30/rate);
515
      if (format == VTK_MIL_CCIR ||
Brad King's avatar
Brad King committed
516 517 518 519 520
          format == VTK_MIL_PAL ||
          format == VTK_MIL_SECAM)
        {
        frame_stride = (int)(25/rate);
        }
521
      }
522
    if ((rate > 0 && ++(self->FrameCounter) >= frame_stride) ||
Brad King's avatar
Brad King committed
523
        self->ForceGrab)
524 525 526 527 528 529 530 531 532
      {
      self->InternalGrab();
      self->FrameCounter = 0;
      self->ForceGrab = 0;
      }
    }
  if (self->OldHookFunction)
    {
    return ((MDIGHOOKFCTPTR)self->OldHookFunction)(HookType,EventID,
Brad King's avatar
Brad King committed
533
                                             self->OldUserDataPtr);
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
    }
  else
    {
    return M_NULL;
    }
}

//----------------------------------------------------------------------------
void vtkMILVideoSource::InternalGrab()
{
  this->FrameBufferMutex->Lock();

  if (this->AutoAdvance)
    {
    this->AdvanceFrameBuffer(1);
549 550 551 552
    if (this->FrameIndex + 1 < this->FrameBufferSize)
      {
      this->FrameIndex++;
      }
553 554 555 556
    }

  int index = this->FrameBufferIndex;

557
  this->FrameBufferTimeStamps[index] =
558
    this->CreateTimeStampForFrame(this->LastFrameCount + 1);
559 560 561 562
  if (this->FrameCount++ == 0)
    {
    this->StartTimeStamp = this->FrameBufferTimeStamps[index];
    }
563

564 565
  void *ptr = ((reinterpret_cast<vtkDataArray *>( \
                       this->FrameBuffer[index]))->GetVoidPointer(0));
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
  int depth = this->FrameBufferBitsPerPixel/8;

  int offsetX = this->FrameBufferExtent[0];
  int offsetY = this->FrameBufferExtent[2];

  int sizeX = this->FrameBufferExtent[1] - this->FrameBufferExtent[0] + 1;
  int sizeY = this->FrameBufferExtent[3] - this->FrameBufferExtent[2] + 1;

  if (sizeX > 0 && sizeY > 0)
    {
    if (depth == 1)
      {
      MbufGet2d(this->MILBufID,offsetX,offsetY,sizeX,sizeY,ptr);
      }
    else if (depth == 3)
      {
      MbufGetColor2d(this->MILBufID,M_RGB24+M_PACKED,M_ALL_BAND,
Brad King's avatar
Brad King committed
583
                     offsetX,offsetY,sizeX,sizeY,ptr);
584
      }
585
    else if (depth == 4)
586 587
      {
      MbufGetColor2d(this->MILBufID,M_RGB32+M_PACKED,M_ALL_BAND,
Brad King's avatar
Brad King committed
588
                     offsetX,offsetY,sizeX,sizeY,ptr);
589 590 591 592
      }
    }

  this->Modified();
593 594

  this->FrameBufferMutex->Unlock();
595
}
596

597 598 599
//----------------------------------------------------------------------------
// for accurate timing of the transformation: this solves a differential
// equation that works to smooth out the jitter in the times that
600
// are returned by vtkTimerLog::GetUniversalTime() i.e. the system clock.
601 602
double vtkMILVideoSource::CreateTimeStampForFrame(unsigned long framecount)
{
603
  double timestamp = vtkTimerLog::GetUniversalTime();
604 605 606 607

  double frameperiod = ((timestamp - this->LastTimeStamp)/
                        (framecount - this->LastFrameCount));
  double deltaperiod = (frameperiod - this->EstimatedFramePeriod)*0.01;
608

609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633
  this->EstimatedFramePeriod += deltaperiod;
  this->LastTimeStamp += ((framecount - this->LastFrameCount)*
                          this->NextFramePeriod);
  this->LastFrameCount = framecount;

  double diffperiod = (timestamp - this->LastTimeStamp);

  if (diffperiod < -0.2 || diffperiod > 0.2)
    { // time is off by more than 0.2 seconds: reset the clock
    this->EstimatedFramePeriod -= deltaperiod;
    this->NextFramePeriod = this->EstimatedFramePeriod;
    this->LastTimeStamp = timestamp;
    return timestamp;
    }

  diffperiod *= 0.1;
  double maxdiff = 0.001;
  if (diffperiod < -maxdiff)
    {
    diffperiod = -maxdiff;
    }
  else if (diffperiod > maxdiff)
    {
    diffperiod = maxdiff;
    }
634

635 636 637 638
  this->NextFramePeriod = this->EstimatedFramePeriod + diffperiod;

  return this->LastTimeStamp;
}
639 640 641 642 643 644

//----------------------------------------------------------------------------
// Circulate the buffer and grab a frame.
// This particular implementation just copies random noise into the frames,
// you will certainly want to override this method (also note that this
// is the only method which you really have to override)
645
void vtkMILVideoSource::Grab()
646 647 648
{
  // ensure that the hardware is initialized.
  this->Initialize();
649 650 651 652
  if (!this->Initialized)
    {
    return;
    }
653

654
  if (!this->Recording)
655
    {
656 657 658 659 660 661 662
    MdigGrab(this->MILDigID,this->MILBufID);
    MdigGrabWait(this->MILDigID,M_GRAB_END);
    this->InternalGrab();
    }
  else
    {
    this->ForceGrab = 1;
663 664 665 666 667
    }
}

//----------------------------------------------------------------------------
void vtkMILVideoSource::Play()
668 669 670 671 672 673
{
  vtkVideoSource::Play();
}

//----------------------------------------------------------------------------
void vtkMILVideoSource::Record()
674 675
{
  this->Initialize();
676 677 678 679
  if (!this->Initialized)
    {
    return;
    }
680 681

  if (this->Playing)
682 683 684 685 686
    {
    this->Stop();
    }

  if (this->Recording)
687 688 689 690
    {
    return;
    }

691 692
  this->Recording = 1;
  this->FrameCount = 0;
693 694

  MdigInquire(this->MILDigID,M_GRAB_FRAME_END_HANDLER_PTR,
Brad King's avatar
Brad King committed
695
              &this->OldHookFunction);
696
  MdigInquire(this->MILDigID,M_GRAB_FRAME_END_HANDLER_USER_PTR,
Brad King's avatar
Brad King committed
697
              &this->OldUserDataPtr);
698
  MdigHookFunction(this->MILDigID,M_GRAB_FRAME_END,
Brad King's avatar
Brad King committed
699 700
                   &vtkMILVideoSourceHook,
                   (void *)this);
701 702 703
  this->FrameCounter = 0;
  this->ForceGrab = 0;

704
  // for accurate timing
705
  this->LastTimeStamp = vtkTimerLog::GetUniversalTime();
706

707 708
  // this will call the hook function on every frame
  MdigGrabContinuous(this->MILDigID,this->MILBufID);
709 710

  this->Modified();
711
}
712

713 714 715
//----------------------------------------------------------------------------
void vtkMILVideoSource::Stop()
{
716 717 718 719 720 721
  if (this->Playing)
    {
    vtkVideoSource::Stop();
    }

  if (!this->Recording)
722 723 724 725
    {
    return;
    }

726
  this->Recording = 0;
727 728 729

  MdigHalt(this->MILDigID);
  MdigHookFunction(this->MILDigID,M_GRAB_FRAME_END,
Brad King's avatar
Brad King committed
730
                   (MDIGHOOKFCTPTR)this->OldHookFunction,
731
                   this->OldUserDataPtr);
David Gobbi's avatar
David Gobbi committed
732
  this->OldHookFunction = 0;
733
  MdigGrabWait(this->MILDigID,M_GRAB_END);
734 735

  this->Modified();
736 737 738 739 740 741 742 743 744 745 746
}

//----------------------------------------------------------------------------
void vtkMILVideoSource::SetMILErrorMessages(int yesno)
{
  if (this->MILErrorMessages == yesno)
    {
    return;
    }

  this->MILErrorMessages = yesno;
747
  this->Modified();
748 749 750 751 752 753 754

  if (this->Initialized)
    {
    MappControl(M_ERROR,( yesno ? M_PRINT_ENABLE : M_PRINT_DISABLE ));
    }
}

755 756 757
//----------------------------------------------------------------------------
void vtkMILVideoSource::SetFrameSize(int x, int y, int z)
{
758 759
  if (x == this->FrameSize[0] &&
      y == this->FrameSize[1] &&
760 761 762 763 764
      z == this->FrameSize[2])
    {
    return;
    }

765
  if (x < 1 || y < 1 || z != 1)
766 767 768 769 770 771 772 773 774
    {
    vtkErrorMacro(<< "SetFrameSize: Illegal frame size");
    return;
    }

  this->FrameSize[0] = x;
  this->FrameSize[1] = y;
  this->FrameSize[2] = z;

775
  if (this->Initialized)
776 777 778 779
    {
    this->FrameBufferMutex->Lock();
    this->UpdateFrameBuffer();
    vtkMILVideoSourceSetSize(this->MILDigID,
Brad King's avatar
Brad King committed
780
                             this->FrameSize,this->FrameMaxSize);
781 782 783 784 785 786
    this->AllocateMILBuffer();
    this->FrameBufferMutex->Unlock();
    }

  this->Modified();
}
787 788 789 790

//----------------------------------------------------------------------------
void vtkMILVideoSource::SetOutputFormat(int format)
{
791
  if (format == this->OutputFormat)
792 793 794 795
    {
    return;
    }

796
  this->OutputFormat = format;
797

798 799 800 801
  // convert color format to number of scalar components
  int numComponents;

  switch (this->OutputFormat)
802
    {
803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
    case VTK_RGBA:
      numComponents = 4;
      break;
    case VTK_RGB:
      numComponents = 3;
      break;
    case VTK_LUMINANCE:
      numComponents = 1;
      break;
    default:
      vtkErrorMacro(<< "SetOutputFormat: Unrecognized color format.");
      break;
    }
  this->NumberOfScalarComponents = numComponents;

  if (this->FrameBufferBitsPerPixel != numComponents*8)
    {
    this->FrameBufferMutex->Lock();
    this->FrameBufferBitsPerPixel = numComponents*8;
    if (this->Initialized)
      {
      this->UpdateFrameBuffer();
      this->AllocateMILBuffer();
      }
    this->FrameBufferMutex->Unlock();
828
    }
829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863

  // set video format to match the output format
  if (this->OutputFormat == VTK_RGB || this->OutputFormat == VTK_RGBA)
    {
    if (this->VideoFormat == VTK_MIL_RS170)
      {
      this->SetVideoFormat(VTK_MIL_NTSC);
      }
    if (this->VideoFormat == VTK_MIL_CCIR)
      {
      this->SetVideoFormat(VTK_MIL_PAL);
      }
    if (this->VideoInput == VTK_MIL_MONO)
      {
      this->SetVideoInput(this->VideoInputForColor);
      }
    }
  if (this->OutputFormat == VTK_LUMINANCE)
    {
    if (this->VideoFormat == VTK_MIL_NTSC)
      {
      this->SetVideoFormat(VTK_MIL_RS170);
      }
    if (this->VideoFormat == VTK_MIL_PAL)
      {
      this->SetVideoFormat(VTK_MIL_CCIR);
      }
    if (this->VideoInput == VTK_MIL_YC || this->VideoInput == VTK_MIL_COMPOSITE)
      {
      this->VideoInputForColor = this->VideoInput;
      this->SetVideoInput(VTK_MIL_MONO);
      }
    }

  this->Modified();
864 865 866 867 868 869 870 871 872 873 874
}

//----------------------------------------------------------------------------
void vtkMILVideoSource::SetVideoFormat(int format)
{
  if (this->VideoFormat == format)
    {
    return;
    }

  this->VideoFormat = format;
875

876 877 878 879 880
  // don't do anything if the digitizer isn't initialized
  if (this->Initialized)
    {
    this->AllocateMILDigitizer();
    }
881
}
882 883 884 885 886 887 888 889

//----------------------------------------------------------------------------
void vtkMILVideoSource::SetVideoInput(int input)
{
  if (this->VideoInput == input)
    {
    return;
    }
890

891 892 893 894 895 896 897
  this->VideoInput = input;

  // don't do anything if the digitizer isn't initialized
  if (this->Initialized)
    {
    this->AllocateMILDigitizer();
    }
898
}
899 900 901 902 903 904 905 906 907 908

//----------------------------------------------------------------------------
void vtkMILVideoSource::SetVideoChannel(int channel)
{
  if (this->VideoChannel == channel)
    {
    return;
    }

  this->VideoChannel = channel;
909
  this->Modified();
910

911 912 913 914 915 916 917
  vtkMILVideoSourceSetChannel(this->MILDigID,channel);
}

//----------------------------------------------------------------------------
void vtkMILVideoSource::SetBrightnessLevel(float brightness)
{
  if (this->BrightnessLevel == brightness)
918 919 920 921
    {
    return;
    }

922 923
  this->BrightnessLevel = brightness;
  this->Modified();
924

David Gobbi's avatar
David Gobbi committed
925
  vtkMILVideoSourceSetLevel(this->MILDigID,M_BRIGHTNESS_REF,brightness/255.0);
926 927 928 929 930 931
}

//----------------------------------------------------------------------------
void vtkMILVideoSource::SetContrastLevel(float contrast)
{
  if (this->ContrastLevel == contrast)
932
    {
933 934 935 936 937 938
    return;
    }

  this->ContrastLevel = contrast;
  this->Modified();

David Gobbi's avatar
David Gobbi committed
939
  vtkMILVideoSourceSetLevel(this->MILDigID,M_CONTRAST_REF,contrast/2.0);
940 941 942 943 944 945 946 947
}

//----------------------------------------------------------------------------
void vtkMILVideoSource::SetHueLevel(float hue)
{
  if (this->HueLevel == hue)
    {
    return;
948 949
    }

950 951 952
  this->HueLevel = hue;
  this->Modified();

David Gobbi's avatar
David Gobbi committed
953
  vtkMILVideoSourceSetLevel(this->MILDigID,M_HUE_REF,0.5+hue);
954 955 956 957 958 959 960 961 962 963 964 965 966
}

//----------------------------------------------------------------------------
void vtkMILVideoSource::SetSaturationLevel(float saturation)
{
  if (this->SaturationLevel == saturation)
    {
    return;
    }

  this->SaturationLevel = saturation;
  this->Modified();

David Gobbi's avatar
David Gobbi committed
967
  vtkMILVideoSourceSetLevel(this->MILDigID,M_SATURATION_REF,saturation/2.0);
968 969
}

970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997
//----------------------------------------------------------------------------
void vtkMILVideoSource::SetBlackLevel(float black)
{
  if (this->BlackLevel == black)
    {
    return;
    }

  this->BlackLevel = black;
  this->Modified();

  vtkMILVideoSourceSetLevel(this->MILDigID,M_BLACK_REF,black/255);
}

//----------------------------------------------------------------------------
void vtkMILVideoSource::SetWhiteLevel(float white)
{
  if (this->WhiteLevel == white)
    {
    return;
    }

  this->WhiteLevel = white;
  this->Modified();

  vtkMILVideoSourceSetLevel(this->MILDigID,M_WHITE_REF,white/255);
}

998 999 1000 1001
//----------------------------------------------------------------------------
void vtkMILVideoSource::AllocateMILDigitizer()
{
  char *format = "M_NTSC";
1002
  int recording = this->Recording;
1003 1004 1005

  if (this->MILDigID)
    {
1006
    if (recording)
1007
      {
1008
      this->Stop();
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
      }
    }

  if (this->MILDigID != 0)
    {
    MdigFree(this->MILDigID);
    }

  switch (this->VideoFormat)
    {
1019
    case VTK_MIL_RS170:
1020
      format = "M_RS170";
1021
      if (this->VideoInput == VTK_MIL_RGB)
Brad King's avatar
Brad King committed
1022 1023 1024
        {
        format = "M_RS170_VIA_RGB";
        }
1025
      break;
1026
    case VTK_MIL_NTSC:
1027
      format = "M_NTSC";
1028
      if (this->VideoInput == VTK_MIL_YC)
Brad King's avatar
Brad King committed
1029 1030 1031
        {
        format = "M_NTSC_YC";
        }
1032
      if (this->VideoInput == VTK_MIL_RGB)
Brad King's avatar
Brad King committed
1033 1034 1035
        {
        format = "M_NTSC_RGB";
        }
1036
      break;
1037
    case VTK_MIL_CCIR:
1038
      format = "M_CCIR";
1039
      if (this->VideoInput == VTK_MIL_RGB)
Brad King's avatar
Brad King committed
1040 1041 1042
        {
        format = "M_CCIR_VIA_RGB";
        }
1043 1044
      this->FrameMaxSize[0] = 768;
      this->FrameMaxSize[1] = 576;
1045
      break;
1046 1047
    case VTK_MIL_PAL:
    case VTK_MIL_SECAM:
1048
      format = "M_PAL";
1049
      if (this->VideoInput == VTK_MIL_YC)
Brad King's avatar
Brad King committed
1050 1051 1052
        {
        format = "M_PAL_YC";
        }
1053
      if (this->VideoInput == VTK_MIL_RGB)
Brad King's avatar
Brad King committed
1054 1055 1056
        {
        format = "M_PAL_RGB";
        }
1057 1058
      this->FrameMaxSize[0] = 768;
      this->FrameMaxSize[1] = 576;
1059
      break;
1060 1061 1062
    case VTK_MIL_NONSTANDARD:
      this->FrameMaxSize[0] = 0;
      this->FrameMaxSize[1] = 0;
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
      break;
    default:
      vtkWarningMacro(<< "AllocateMILDigitizer: Unknown video format");
    }

  if (this->MILDigitizerDCF)
    {
    format = this->MILDigitizerDCF;
    }

1073
  this->MILDigID = MdigAlloc(this->MILSysID,this->MILDigitizerNumber,format,
Brad King's avatar
Brad King committed
1074
                             M_DEFAULT,M_NULL);
1075 1076

  if (this->MILDigID == 0)
1077
    {
1078 1079
    vtkErrorMacro(<< "AllocateMILDigitizer:  Couldn't allocate MIL Digitizer\n");
    return;
1080 1081
    }

1082 1083 1084 1085
  vtkMILVideoSourceSetSize(this->MILDigID,this->FrameSize,this->FrameMaxSize);

  vtkMILVideoSourceSetChannel(this->MILDigID,this->VideoChannel);

David Gobbi's avatar
David Gobbi committed
1086 1087 1088
  if (this->BrightnessLevel != 128)
    {
    vtkMILVideoSourceSetLevel(this->MILDigID,M_BRIGHTNESS_REF,
Brad King's avatar
Brad King committed
1089
                              this->BrightnessLevel/255);
David Gobbi's avatar
David Gobbi committed
1090 1091 1092 1093
    }
  if (this->ContrastLevel != 1.0)
    {
    vtkMILVideoSourceSetLevel(this->MILDigID,M_CONTRAST_REF,
Brad King's avatar
Brad King committed
1094
                              this->ContrastLevel/2.0);
David Gobbi's avatar
David Gobbi committed
1095 1096 1097 1098
    }
  if (this->HueLevel != 0.0)
    {
    vtkMILVideoSourceSetLevel(this->MILDigID,M_HUE_REF,
Brad King's avatar
Brad King committed
1099
                              0.5+this->HueLevel);
David Gobbi's avatar
David Gobbi committed
1100 1101 1102 1103
    }
  if (this->SaturationLevel != 1.0)
    {
    vtkMILVideoSourceSetLevel(this->MILDigID,M_SATURATION_REF,
Brad King's avatar
Brad King committed
1104
                              this->SaturationLevel/2.0);
David Gobbi's avatar
David Gobbi committed
1105
    }
1106 1107 1108 1109 1110 1111 1112 1113 1114 1115
  if (this->BlackLevel != 0.0)
    {
    vtkMILVideoSourceSetLevel(this->MILDigID,M_BLACK_REF,
                              this->BlackLevel/255);
    }
  if (this->WhiteLevel != 255.0)
    {
    vtkMILVideoSourceSetLevel(this->MILDigID,M_WHITE_REF,
                              this->WhiteLevel/255);
    }
1116 1117 1118

  if (this->MILDigID && this->MILBufID)
    {
1119
    if (recording)
1120
      {
1121
      this->Record();
1122 1123 1124 1125 1126 1127 1128
      }
    }
}

//----------------------------------------------------------------------------
void vtkMILVideoSource::AllocateMILBuffer()
{
1129
  int recording = this->Recording;
1130 1131

  if (this->MILDigID != 0)
1132
    {
1133
    if (recording)
1134
      {
1135
      this->Stop();
1136 1137 1138 1139 1140 1141 1142 1143
      }
    }

  if (this->MILBufID != 0)
    {
    MbufFree(this->MILBufID);
    }

1144
  if (this->OutputFormat != VTK_LUMINANCE &&
1145 1146 1147 1148 1149
      this->OutputFormat != VTK_RGB &&
      this->OutputFormat != VTK_RGBA)
    {
    vtkWarningMacro(<< "Initialize: unsupported OutputFormat");
    this->vtkVideoSource::SetOutputFormat(VTK_LUMINANCE);
1150
    }
1151 1152 1153

  if (this->OutputFormat == VTK_LUMINANCE)
    {
1154
     this->MILBufID = MbufAlloc2d(this->MILSysID,this->FrameSize[0],
Brad King's avatar
Brad King committed
1155 1156
                                  this->FrameSize[1],
                                  8+M_UNSIGNED,M_IMAGE+M_GRAB,M_NULL);
1157 1158 1159
    }
  else if (this->OutputFormat == VTK_RGB)
    {
1160
    this->MILBufID = MbufAllocColor(this->MILSysID,3,this->FrameSize[0],
Brad King's avatar
Brad King committed
1161 1162 1163 1164
                                    this->FrameSize[1],
                                    8+M_UNSIGNED,M_IMAGE+M_GRAB+ \
                                    M_RGB24+M_PACKED,
                                    M_NULL);
1165 1166 1167
    }
  else if (this->OutputFormat == VTK_RGBA)
    {
1168
    this->MILBufID = MbufAllocColor(this->MILSysID,3,this->FrameSize[0],
Brad King's avatar
Brad King committed
1169 1170 1171 1172
                                    this->FrameSize[1],
                                    8+M_UNSIGNED,M_IMAGE+M_GRAB+M_RGB32+ \
                                    M_PACKED,
                                    M_NULL);
1173 1174
    }

1175
  if (this->MILBufID == 0)
1176
    {
1177 1178 1179 1180 1181 1182
    vtkErrorMacro(<< "AllocateMILBuffer:  Couldn't allocate MIL Buffer\n");
    return;
    }

  if (this->MILDigID != 0 && this->MILBufID != 0)
    {
1183
    if (recording)
1184
      {
1185
      this->Record();
1186 1187 1188 1189 1190 1191
      }
    }
}