Commit c3cdf251 authored by David Gobbi's avatar David Gobbi

ENH: rollup enhancements to vtkVideoSource:

1) many API changes: separate Record() and Play() [now Play just plays back
   frames, it doesn't grab images]
2) Seek() replaces old Rewind() and Advance()
3) Rewind() now rewinds to earliest frame, rather than backing up just 1 frame
4) automatic freeing of driver at application exit
5) GrabOnUpdate is history
parent 787eb029
......@@ -2,11 +2,19 @@ catch { load vtktcl }
if { [catch {set VTK_TCL $env(VTK_TCL)}] != 0} { set VTK_TCL "../../examplesTcl" }
if { [catch {set VTK_DATA $env(VTK_DATA)}] != 0} { set VTK_DATA "../../../vtkdata" }
# Note: if the frame rate appears to be low, then:
# 1) turn on viewer DoubleBuffer (this will almost always help)
# 2) your video card might not accelerate image uploads, try using
# vtkTexture or vtkImageActor to display video via textures instead
# uncomment this line to use a Win32 video capture device
#vtkWin32VideoSource grabber
vtkVideoSource grabber
#grabber SetOutputFormatToRGB
#grabber SetFrameSize 640 480 1
#grabber SetOutputWholeExtent 0 319 0 239 0 0
#grabber SetOutputWholeExtent 0 319 0 239 0 0
catch { grabber VideoSourceDialog }
catch { grabber VideoFormatDialog }
grabber SetFrameBufferSize 50
grabber SetNumberOfOutputFrames 50
grabber Grab
......@@ -14,7 +22,8 @@ grabber Grab
[grabber GetOutput] UpdateInformation
vtkImageViewer viewer
viewer SetInput [grabber GetOutput]
viewer SetInput [grabber GetOutput]
# settting DoubleBufferOn will greatly enhance performance
#[viewer GetImageWindow] DoubleBufferOn
viewer SetColorWindow 255
viewer SetColorLevel 127.5
......@@ -25,17 +34,26 @@ viewer Render
proc animate {} {
global grabber viewer
if { [grabber GetPlaying] == 1 } {
if { [grabber GetPlaying] == 1 || [grabber GetRecording] == 1} {
viewer Render
after 1 animate
}
}
proc Record {} {
global grabber
if { [grabber GetPlaying] != 1 && [grabber GetRecording] != 1 } {
grabber Record
animate
}
}
proc Play {} {
global grabber
if { [grabber GetPlaying] != 1 } {
grabber Play
if { [grabber GetPlaying] != 1 && [grabber GetRecording] != 1 } {
grabber Play
animate
}
}
......@@ -57,7 +75,9 @@ frame .controls
button .controls.grab -text "Grab" -command Grab
pack .controls.grab -side left
button .controls.stop -text "Stop" -command Stop
pack .controls.stop -side left
pack .controls.stop -side left
button .controls.record -text "Record" -command Record
pack .controls.record -side left
button .controls.play -text "Play" -command Play
pack .controls.play -side left
pack .controls -side top
......@@ -93,7 +113,7 @@ pack .viewframe.scale -side left
pack .viewframe -side top
frame .ex
button .ex.button -text "Exit" -command exit
button .ex.button -text "Exit" -command {destroy .}
pack .ex.button -side left
pack .ex -side top
......
......@@ -444,12 +444,12 @@ void vtkMILVideoSource::ReleaseSystemResources()
{
if (this->MILDigID)
{
if (this->Playing)
if (this->Recording)
{
MdigHalt(this->MILDigID);
}
MdigGrabWait(this->MILDigID,M_GRAB_END);
this->Playing = 0;
this->Recording = 0;
}
/*
if (this->MILDispID != 0)
......@@ -541,6 +541,10 @@ void vtkMILVideoSource::InternalGrab()
int index = this->FrameBufferIndex;
this->FrameBufferTimeStamps[index] = vtkTimerLog::GetCurrentTime();
if (this->FrameCount++ == 0)
{
this->StartTimeStamp = this->FrameBufferTimeStamps[index];
}
void *ptr = ((vtkScalars *)this->FrameBuffer[index])->GetVoidPointer(0);
int depth = this->FrameBufferBitsPerPixel/8;
......@@ -580,13 +584,8 @@ void vtkMILVideoSource::InternalGrab()
// 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)
void vtkMILVideoSource::Grab(int numFrames)
void vtkMILVideoSource::Grab()
{
if (numFrames > this->FrameBufferSize || numFrames < 1)
{
vtkErrorMacro(<< "Grab: # of frames must be at least 1");
}
// ensure that the hardware is initialized.
this->Initialize();
if (!this->Initialized)
......@@ -594,24 +593,26 @@ void vtkMILVideoSource::Grab(int numFrames)
return;
}
int f;
for (f = 0; f < numFrames; f++)
if (!this->Recording)
{
if (!this->Playing)
{
MdigGrab(this->MILDigID,this->MILBufID);
MdigGrabWait(this->MILDigID,M_GRAB_END);
this->InternalGrab();
}
else
{
this->ForceGrab = 1;
}
MdigGrab(this->MILDigID,this->MILBufID);
MdigGrabWait(this->MILDigID,M_GRAB_END);
this->InternalGrab();
}
else
{
this->ForceGrab = 1;
}
}
//----------------------------------------------------------------------------
void vtkMILVideoSource::Play()
{
vtkVideoSource::Play();
}
//----------------------------------------------------------------------------
void vtkMILVideoSource::Record()
{
this->Initialize();
if (!this->Initialized)
......@@ -620,11 +621,17 @@ void vtkMILVideoSource::Play()
}
if (this->Playing)
{
this->Stop();
}
if (this->Recording)
{
return;
}
this->Playing = 1;
this->Recording = 1;
this->FrameCount = 0;
MdigInquire(this->MILDigID,M_GRAB_FRAME_END_HANDLER_PTR,
&this->OldHookFunction);
......@@ -645,12 +652,17 @@ void vtkMILVideoSource::Play()
//----------------------------------------------------------------------------
void vtkMILVideoSource::Stop()
{
if (!this->Playing)
if (this->Playing)
{
vtkVideoSource::Stop();
}
if (!this->Recording)
{
return;
}
this->Playing = 0;
this->Recording = 0;
MdigHalt(this->MILDigID);
MdigHookFunction(this->MILDigID,M_GRAB_FRAME_END,
......@@ -898,11 +910,11 @@ void vtkMILVideoSource::SetSaturationLevel(float saturation)
void vtkMILVideoSource::AllocateMILDigitizer()
{
char *format = "M_NTSC";
int playing = this->Playing;
int recording = this->Recording;
if (this->MILDigID)
{
if (playing)
if (recording)
{
this->Stop();
}
......@@ -1005,9 +1017,9 @@ void vtkMILVideoSource::AllocateMILDigitizer()
if (this->MILDigID && this->MILBufID)
{
if (playing)
if (recording)
{
this->Play();
this->Record();
}
}
}
......@@ -1015,11 +1027,11 @@ void vtkMILVideoSource::AllocateMILDigitizer()
//----------------------------------------------------------------------------
void vtkMILVideoSource::AllocateMILBuffer()
{
int playing = this->Playing;
int recording = this->Recording;
if (this->MILDigID != 0)
{
if (playing)
if (recording)
{
this->Stop();
}
......@@ -1069,9 +1081,9 @@ void vtkMILVideoSource::AllocateMILBuffer()
if (this->MILDigID != 0 && this->MILBufID != 0)
{
if (playing)
if (recording)
{
this->Play();
this->Record();
}
}
}
......
......@@ -86,16 +86,27 @@ public:
void PrintSelf(ostream& os, vtkIndent indent);
// Description:
// See vtkVideoSource
void Initialize();
void ReleaseSystemResources();
// Standard VCR functionality: Record incoming video.
void Record();
void Grab(int n);
void Grab() { this->Grab(1); };
// Description:
// Standard VCR functionality: Play recorded video.
void Play();
// Description:
// Standard VCR functionality: Stop recording or playing.
void Stop();
// Description:
// Grab a single video frame.
void Grab();
// Description:
// Request a particular frame size (set the third value to 1).
void SetFrameSize(int x, int y, int z);
// Description:
// Request a particular output format (default: VTK_RGB).
void SetOutputFormat(int format);
// Description:
......@@ -182,6 +193,16 @@ public:
vtkGetMacro(MILDigID,long);
vtkGetMacro(MILBufID,long);
// Description:
// Initialize the driver (this is called automatically when the
// first grab is done).
void Initialize();
// Description:
// Free the driver (this is called automatically inside the
// destructor).
void ReleaseSystemResources();
// Description:
// For internal use only
void *OldHookFunction;
......
This diff is collapsed.
......@@ -39,12 +39,14 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/
// .NAME vtkVideoSource - Superclass of video digitizers
// .NAME vtkVideoSource - Superclass of video input devices for VTK
// .SECTION Description
// vtkVideoSource is a superclass for video input interfaces for VTK.
// The most important methods are Grab() (grab a single frame),
// Play() (grab frames continuously), and Stop() (stop grabbing
// continuously)
// vtkVideoSource is a superclass for video input interfaces for VTK.
// The goal is to provide an interface which is very similar to the
// interface of a VCR, where the 'tape' is an internal frame buffer
// capable of holding a preset number of video frames. Specialized
// versions of this class record input from various video input sources.
// This base class records input from a noise source.
// .SECTION See Also
// vtkWin32VideoSource vtkMILVideoSource
......@@ -66,38 +68,48 @@ public:
void PrintSelf(ostream& os, vtkIndent indent);
// Description:
// Initialize the hardware. This is called automatically
// on the first Update or Grab.
virtual void Initialize();
// Record incoming video at the specified FrameRate. The recording
// continues indefinitely until Stop() is called.
virtual void Record();
// Description:
// Release the video driver. This is called automatically
// when the vtkVideoSource is destroyed.
virtual void ReleaseSystemResources();
// Play through the 'tape' sequentially at the specified frame rate.
// If you have just finished Recoding, you should call Rewind() first.
virtual void Play();
// Description:
// Grab a single frame or multiple frames.
virtual void Grab(int n);
void Grab() { this->Grab(1); }
// Stop recording or playing.
virtual void Stop();
// Description:
// Go into continuous grab mode. The video source will be
// automatically Modified() every time a new frame arrives.
virtual void Play();
// Rewind to the frame immediately before the frame that has the
// earliest timestamp. Subsequent Play, Record, or Grab operations
// will start on the next frame.
virtual void Rewind();
// Description:
// End continuous grab mode.
virtual void Stop();
// FastForward to the last frame that was recorded (i.e. to the frame
// that has the most recent timestamp).
virtual void FastForward();
// Description:
// Are we in continuous grab mode?
vtkGetMacro(Playing,int);
// Seek forwards or backwards by the specified number of frames
// (positive is forward, negative is backward).
virtual void Seek(int n);
// Description:
// Set the frame rate for 'Play' mode. The default is 30 frames/s
// for most video digitizers.
vtkSetMacro(FrameRate,float);
vtkGetMacro(FrameRate,float);
// Grab a single video frame.
virtual void Grab();
// Description:
// Are we in record mode? (record mode and play mode are mutually
// exclusive).
vtkGetMacro(Recording,int);
// Description:
// Are we in play mode? (record mode and play mode are mutually
// exclusive).
vtkGetMacro(Playing,int);
// Description:
// Set the full-frame size. This must be an allowed size for the device,
......@@ -106,11 +118,16 @@ public:
// The default is usually 320x240x1, but can be device specific.
// The 'depth' should always be 1 (unless you have a device that
// can handle 3D acquisition).
virtual void SetFrameSize(int x, int y, int z);
virtual void SetFrameSize(int dim[3]) {
this->SetFrameSize(dim[0], dim[1], dim[2]); };
virtual void SetFrameSize(int x, int y, int z);
vtkGetVector3Macro(FrameSize,int);
// Description:
// Request a particular frame rate (default 30 frames per second).
virtual void SetFrameRate(float rate);
vtkGetMacro(FrameRate,float);
// Description:
// Set the output format. This must be appropriate for device,
// usually only VTK_LUMINANCE, VTK_RGB, and VTK_RGBA are supported.
......@@ -121,8 +138,8 @@ public:
vtkGetMacro(OutputFormat,int);
// Description:
// Set size of the frame buffer, i.e. the number of frames to
// store.
// Set size of the frame buffer, i.e. the number of frames that
// the 'tape' can store.
virtual void SetFrameBufferSize(int FrameBufferSize);
vtkGetMacro(FrameBufferSize,int);
......@@ -141,16 +158,6 @@ public:
vtkSetMacro(AutoAdvance,int)
vtkGetMacro(AutoAdvance,int);
// Description:
// Advance the buffer by one frame or n frames.
virtual void Advance(int n);
virtual void Advance() { this->Advance(-1); };
// Description:
// Rewind the buffer by one frame or n frames.
virtual void Rewind(int n) { this->Advance(-n); };
virtual void Rewind() { this->Advance(-1); };
// Description:
// Set the clip rectangle for the frames. The video will be clipped
// before it is copied into the framebuffer. Changing the ClipRegion
......@@ -186,39 +193,45 @@ public:
// Description:
// For RGBA output only (4 scalar components), set the opacity. This
// will not modify the contents of the framebuffer, only subsequently
// grabbed frames.
// will not modify the existing contents of the framebuffer, only
// subsequently grabbed frames.
vtkSetMacro(Opacity,float);
vtkGetMacro(Opacity,float);
// Description:
// Enable a video preview window if supported by driver.
vtkSetMacro(Preview,int);
vtkBooleanMacro(Preview,int);
vtkGetMacro(Preview,int);
// Get the number of frames captured since the beginning of the
// last Record session.
vtkGetMacro(FrameCount, int);
// Description:
// Get a time stamp in seconds (resolution of milliseconds) for
// a video frame. Time began on Jan 1, 1970.
// a video frame. Time began on Jan 1, 1970. You can specify
// a number (negative or positive) to specify the position of the
// video frame relative to the current frame.
virtual double GetFrameTimeStamp(int frame);
virtual double GetFrameTimeStamp() { return this->GetFrameTimeStamp(0); };
// Description:
// Set this flag to automatically do a grab on each Update. This might
// be less CPU-intensive than Play() for doing screen animations.
virtual void SetGrabOnUpdate(int yesno);
vtkBooleanMacro(GrabOnUpdate,int);
vtkGetMacro(GrabOnUpdate,int);
// Initialize the hardware. This is called automatically
// on the first Update or Grab.
virtual void Initialize();
// Description:
// Release the video driver. This is called automatically
// when the vtkVideoSource is destroyed.
virtual void ReleaseSystemResources();
// Description:
// The internal function which actually does the grab. You will
// definitely want to override this if you develop a vtkVideoSource
// subclass.
// subclass.
virtual void InternalGrab();
// Description:
// This method returns the largest data that can be generated.
void UpdateInformation();
// And internal variable which marks the beginning of a Record session.
// These methods are for internal use only.
void SetStartTimeStamp(double t) { this->StartTimeStamp = t; };
double GetStartTimeStamp() { return this->StartTimeStamp; };
protected:
vtkVideoSource();
......@@ -246,16 +259,16 @@ protected:
int LastNumberOfScalarComponents;
int LastOutputExtent[6];
int Recording;
int Playing;
float FrameRate;
int FrameCount;
double StartTimeStamp;
int AutoAdvance;
int NumberOfOutputFrames;
float Opacity;
int Preview;
int GrabOnUpdate;
// true if Execute() must apply a vertical flip to each frame
int FlipFrames;
......@@ -263,16 +276,12 @@ protected:
// set if output needs to be cleared to be cleared before being written
int OutputNeedsInitialization;
// set if a frame has been grabbed in the 'GrabOnUpdate' hack
int FrameGrabbed;
// An example of asynchrony
vtkMultiThreader *PlayerThreader;
int PlayerThreadId;
// A mutex for the frame buffer: must be applied when any of the
// below data is modified.
vtkMutexLock *FrameBufferMutex;
// set according to the needs of the hardware:
......
......@@ -67,7 +67,9 @@ vtkWin32VideoSource::vtkWin32VideoSource()
this->Initialized = 0;
this->FrameRate = 30;
this->OutputFormat = VTK_RGB;
this->NumberOfScalarComponents = 3;
this->FrameBufferBitsPerPixel = 24;
this->FlipFrames = 0;
this->FrameBufferRowAlignment = 4;
......@@ -75,10 +77,11 @@ vtkWin32VideoSource::vtkWin32VideoSource()
this->ParentWnd = NULL;
this->BitMapSize = 0;
this->BitMapPtr = NULL;
this->WndClassName[0] = '\0';
this->FatalVFWError = 0;
this->Preview = 0;
this->BeginTimeStamp = 0.0;
this->FatalVFWError = 0;
}
//----------------------------------------------------------------------------
......@@ -98,6 +101,8 @@ vtkWin32VideoSource::~vtkWin32VideoSource()
void vtkWin32VideoSource::PrintSelf(ostream& os, vtkIndent indent)
{
vtkVideoSource::PrintSelf(os,indent);
os << indent << "Preview: " << (this->Preview ? "On\n" : "Off\n");
}
//----------------------------------------------------------------------------
......@@ -152,7 +157,7 @@ LRESULT PASCAL vtkWin32VideoSourceStatusCallbackProc(HWND hwndC, int nID,
if (nID == IDS_CAP_BEGIN)
{
self->SetBeginTimeStamp(vtkTimerLog::GetCurrentTime());
self->SetStartTimeStamp(vtkTimerLog::GetCurrentTime());
//cerr << "start of capture\n";
}
......@@ -411,23 +416,30 @@ void vtkWin32VideoSource::SetPreview(int p)
//----------------------------------------------------------------------------
void vtkWin32VideoSource::ReleaseSystemResources()
{
if (this->Playing)
if (this->Playing || this->Recording)
{
this->Stop();
}
if (this->CapWnd)
{
//MessageBox(this->ParentWnd, "capDriverDisconnect(this->CapWnd)", "", MB_OK | MB_ICONEXCLAMATION);
capDriverDisconnect(this->CapWnd);
//MessageBox(this->ParentWnd, "DestroyWindow(this->CapWnd)", "", MB_OK | MB_ICONEXCLAMATION);
DestroyWindow(this->CapWnd);
this->CapWnd = NULL;
}
if (this->ParentWnd)
{
//MessageBox(this->ParentWnd, "DestroyWindow(this->ParentWnd)", "", MB_OK | MB_ICONEXCLAMATION);
DestroyWindow(this->ParentWnd);
this->ParentWnd = NULL;
}
UnregisterClass(this->WndClassName,GetModuleHandle(NULL));
if (this->WndClassName[0] != '\0')
{
UnregisterClass(this->WndClassName,GetModuleHandle(NULL));
this->WndClassName[0] = '\0';
}
this->FatalVFWError = 1;
this->Initialized = 0;
......@@ -460,7 +472,8 @@ void vtkWin32VideoSource::InternalGrab(LPVIDEOHDR lpVHdr)
int index = this->FrameBufferIndex;
this->FrameBufferTimeStamps[index] = this->GetBeginTimeStamp() + \
this->FrameCount++;
this->FrameBufferTimeStamps[index] = this->StartTimeStamp + \
0.001 * lpVHdr->dwTimeCaptured;
unsigned char *ptr = (unsigned char *)
......@@ -511,15 +524,9 @@ void vtkWin32VideoSource::InternalGrab(LPVIDEOHDR lpVHdr)
}
//----------------------------------------------------------------------------
void vtkWin32VideoSource::Grab(int numFrames)
void vtkWin32VideoSource::Grab()
{
if (numFrames > this->FrameBufferSize || numFrames < 1)
{
vtkErrorMacro(<< "Grab: # of frames must be at least 1");
return;
}
if (this->Playing)
if (this->Recording)
{
return;
}
......@@ -531,16 +538,12 @@ void vtkWin32VideoSource::Grab(int numFrames)
return;
}
// just do the grabs, the callback does the rest
int f;
for (f = 0; f < numFrames; f++)
{
capGrabFrameNoStop(this->CapWnd);
}
// just do the grab, the callback does the rest
capGrabFrameNoStop(this->CapWnd);
}
//----------------------------------------------------------------------------
void vtkWin32VideoSource::Play()
void vtkWin32VideoSource::Record()
{
this->Initialize();
if (!this->Initialized)
......@@ -548,24 +551,39 @@ void vtkWin32VideoSource::Play()
return;
}
if (!this->Playing)
if (this->Playing)
{
this->Playing = 1;
this->Stop();
}
if (!this->Recording)
{
this->Recording = 1;
this->Modified();
capCaptureSequenceNoFile(this->CapWnd);
}
}
//----------------------------------------------------------------------------
void vtkWin32VideoSource::Play()
{
this->vtkVideoSource::Play();
}
//----------------------------------------------------------------------------
void vtkWin32VideoSource::Stop()
{
if (this->Playing)
if (this->Recording)
{
this->Playing = 0;
this->Recording = 0;
this->Modified();
capCaptureStop(this->CapWnd);
}
else if (this->Playing)
{
this->vtkVideoSource::Stop();
}
}
//----------------------------------------------------------------------------
......@@ -1037,8 +1055,9 @@ void vtkWin32VideoSource::DoVFWFormatCheck()
{
this->OutputFormat = VTK_RGB;
this->NumberOfScalarComponents = 3;
}
}
break;
case 24:
case 32:
if (this->OutputFormat != VTK_RGBA)
{
......
......@@ -63,38 +63,60 @@ public:
void PrintSelf(ostream& os, vtkIndent indent);
// Description:
// See vtkVideoSource
void Initialize();
void ReleaseSystemResources();
// Standard VCR functionality: Record incoming video.
void Record();
void Grab(int n);
void Grab() { this->Grab(1); };
// Description:
// Standard VCR functionality: Play recorded video.
void Play();
// Description:
// Standard VCR functionality: Stop recording or playing.
void Stop();
// Description:
// Grab a single video frame.
void Grab();
// Description:
// Request a particular frame size (set the third value to 1).
void SetFrameSize(int x, int y, int z);
// Description:
// Request a particular frame rate (default 30 frames per second).
void SetFrameRate(float rate);
// Description:
// Request a particular output format (default: VTK_RGB).
void SetOutputFormat(int format);
// Description:
// turn on/off the preview window
// Turn on/off the preview (overlay) window.