7 #include "PlusConfigure.h" 8 #include "igsioTrackedFrame.h" 9 #include "vtkIGSIOMetaImageSequenceIO.h" 10 #include "vtkObjectFactory.h" 13 #include "vtkIGSIOSequenceIO.h" 14 #include "vtkIGSIOTrackedFrameList.h" 16 #include "vtksys/SystemTools.hxx" 18 #ifdef PLUS_USE_VTKVIDEOIO_MKV 30 static const double WARNING_RECORDING_LAG_SEC = 1.0;
31 static const double MAX_ALLOWED_RECORDING_LAG_SEC = 3.0;
32 static const unsigned int DISABLE_FRAME_BUFFER = std::numeric_limits<unsigned int>::max();
38 , RecordedFrames(vtkIGSIOTrackedFrameList::New())
39 , LastAlreadyRecordedFrameTimestamp(UNDEFINED_TIMESTAMP)
40 , NextFrameToBeRecordedTimestamp(0.0)
41 , RequestedFrameRate(15.0)
42 , ActualFrameRate(0.0)
43 , FirstFrameIndexInThisSegment(0)
47 , BaseFilename(
"TrackedImageSequence.nrrd")
49 , EnableFileCompression(false)
50 , IsHeaderPrepared(false)
51 , TotalFramesRecorded(0)
52 , EnableCapturingOnStart(false)
53 , EnableCapturing(false)
54 , FrameBufferSize(DISABLE_FRAME_BUFFER)
56 , WriterAccessMutex(vtkSmartPointer<vtkIGSIORecursiveCriticalSection>::New())
58 , EncodingFourCC(
"VP90")
62 this->
RecordedFrames->SetValidationRequirements(REQUIRE_UNIQUE_TIMESTAMP);
99 const char* deviceType = deviceConfig->GetAttribute(
"Type");
100 if (deviceType && deviceType != std::string(
"VirtualCapture"))
102 LOG_WARNING(
"Device type \"" << deviceType <<
"\" is deprecated. Use \"VirtualCapture\" instead.");
103 deviceConfig->SetAttribute(
"Type",
"VirtualCapture");
106 XML_READ_STRING_ATTRIBUTE_OPTIONAL(
BaseFilename, deviceConfig);
110 XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(
int,
FrameBufferSize, deviceConfig);
120 deviceElement->SetAttribute(
"EnableCapturing", this->
EnableCapturing ?
"TRUE" :
"FALSE");
121 deviceElement->SetAttribute(
"EnableFileCompression", this->
EnableFileCompression ?
"TRUE" :
"FALSE");
157 LOG_ERROR(
"Unable to append image data to header.");
177 igsioLockGuard<vtkIGSIORecursiveCriticalSection> writerLock(this->
WriterAccessMutex);
179 if (aFilename == NULL || strlen(aFilename) == 0)
181 std::string filenameRoot = igsioCommon::GetSequenceFilenameWithoutExtension(this->
BaseFilename);
182 std::string ext = igsioCommon::GetSequenceFilenameExtension(this->
BaseFilename);
191 LOG_WARNING(
"Compressed saving of metaimage file requested. This is not supported. Reverting to uncompressed metaimage file.");
194 this->
CurrentFilename = filenameRoot +
"_" + vtksys::SystemTools::GetCurrentDateTime(
"%Y%m%d_%H%M%S") + ext;
202 LOG_WARNING(
"Compressed saving of metaimage file requested. This is not supported. Reverting to uncompressed metaimage file.");
208 this->
Writer = vtkIGSIOSequenceIO::CreateSequenceHandlerForFile(aFilename);
211 LOG_ERROR(
"Could not create writer for file: " << aFilename);
226 igsioLockGuard<vtkIGSIORecursiveCriticalSection> writerLock(this->
WriterAccessMutex);
234 if (aFilename != NULL && strlen(aFilename) != 0)
248 this->
Writer->UpdateFieldInImageHeader(this->
Writer->GetDimensionSizeString());
249 this->
Writer->UpdateFieldInImageHeader(this->
Writer->GetDimensionKindsString());
250 this->
Writer->FinalizeHeader();
252 if (resultFilename != NULL)
254 (*resultFilename) = this->
Writer->GetFileName();
260 std::string path = vtksys::SystemTools::GetFilenamePath(fullPath);
261 std::string filename = vtksys::SystemTools::GetFilenameWithoutExtension(fullPath);
262 std::string configFileName = path +
"/" + filename +
"_config.xml";
287 double samplingPeriodSec = 0.1;
294 LOG_WARNING(
"AcquisitionRate value is invalid " << this->
AcquisitionRate <<
". Use default sampling period of " << samplingPeriodSec <<
" sec");
305 double startTimeSec = vtkIGSIOAccurateTimer::GetSystemTime();
317 double maxProcessingTimeSec = samplingPeriodSec * 2.0;
318 double requestedFramePeriodSec = 0.1;
325 LOG_WARNING(
"RequestedFrameRate is invalid");
333 igsioLockGuard<vtkIGSIORecursiveCriticalSection> writerLock(this->
WriterAccessMutex);
340 int nbFramesBefore = this->
RecordedFrames->GetNumberOfTrackedFrames();
343 LOG_ERROR(
"Error while getting tracked frame list from data collector during capturing. Last recorded timestamp: " << std::fixed << this->
NextFrameToBeRecordedTimestamp);
345 int nbFramesAfter = this->
RecordedFrames->GetNumberOfTrackedFrames();
348 int frame1Index = this->
RecordedFrames->GetNumberOfTrackedFrames() - 1;
355 if (frame1Index > frame2Index)
357 igsioTrackedFrame* frame1 = this->
RecordedFrames->GetTrackedFrame(frame1Index);
358 igsioTrackedFrame* frame2 = this->
RecordedFrames->GetTrackedFrame(frame2Index);
359 if (frame1 != NULL && frame2 != NULL)
361 double frameTimeDiff = frame1->GetTimestamp() - frame2->GetTimestamp();
362 if (frameTimeDiff > 0)
375 LOG_ERROR(this->
GetDeviceId() <<
": Unable to write " << nbFramesAfter - nbFramesBefore <<
" frames.");
384 LOG_DYNAMIC(
"No input data available to capture thread. Waiting until input data arrives.", this->
GracePeriodLogLevel);
388 double recordingTimeSec = vtkIGSIOAccurateTimer::GetSystemTime() - startTimeSec;
389 double currentSystemTime = vtkIGSIOAccurateTimer::GetSystemTime();
392 if (recordingTimeSec > samplingPeriodSec)
395 vtkPlusLogger::LogLevelType logLevel = (recordingLagSec > WARNING_RECORDING_LAG_SEC ? vtkPlusLogger::LOG_LEVEL_WARNING : vtkPlusLogger::LOG_LEVEL_DEBUG);
396 LOG_DYNAMIC(
"Recording of frames takes too long time (" << recordingTimeSec <<
"sec instead of the allocated " << samplingPeriodSec <<
"sec, recording lags by " << recordingLagSec <<
"sec). This can cause slow-down of the application and non-uniform sampling. Reduce the acquisition rate or sampling rate to resolve the problem.", logLevel);
399 if (recordingLagSec > MAX_ALLOWED_RECORDING_LAG_SEC)
401 double acquisitionLagSec = recordingLagSec;
405 acquisitionLagSec = currentSystemTime - latestInputTimestamp;
407 if (acquisitionLagSec < MAX_ALLOWED_RECORDING_LAG_SEC)
411 LOG_ERROR(
"Recording cannot keep up with the acquisition. Skip " << recordingLagSec <<
" seconds of the data stream to catch up.");
413 this->NextFrameToBeRecordedTimestamp = vtkIGSIOAccurateTimer::GetSystemTime();
416 this->LastUpdateTime = vtkIGSIOAccurateTimer::GetSystemTime();
426 LOG_WARNING(
"vtkPlusVirtualCapture is expecting no output channel(s) and there are " << this->
OutputChannels.size() <<
" channels. Output channel information will be dropped.");
432 LOG_ERROR(
"No input channel set for vtkPlusVirtualCapture. Unable to save anything.");
439 LOG_WARNING(
"vtkPlusVirtualCapture is expecting one input channel and there are " << this->
InputChannels.size() <<
" channels. First output channel will be used, all other are ignored.");
445 inputChannel->Register(
this);
475 this->
Writer->SetUseCompression(aFileCompression);
501 igsioLockGuard<vtkIGSIORecursiveCriticalSection> writerLock(this->
WriterAccessMutex);
511 this->
Writer->GetTrackedFrameList()->Clear();
518 LOG_ERROR(
"Unable to reset device " << this->
GetDeviceId() <<
".");
538 LOG_ERROR(this->
GetDeviceId() <<
": Cannot take snapshot while the device is recording.");
542 igsioTrackedFrame trackedFrame;
545 LOG_ERROR(this->
GetDeviceId() <<
": Failed to get tracked frame for the snapshot!");
550 std::vector<igsioTransformName> transformNames;
551 trackedFrame.GetFrameTransformNameList(transformNames);
552 bool validFrame =
false;
554 if (transformNames.size() == 0)
560 for (std::vector<igsioTransformName>::iterator it = transformNames.begin(); it != transformNames.end(); ++it)
562 ToolStatus status(TOOL_INVALID);
563 trackedFrame.GetFrameTransformStatus(*it, status);
565 if (status == TOOL_OK)
575 LOG_WARNING(this->
GetDeviceId() <<
": Unable to record tracked frame: All the tool transforms are invalid!");
583 LOG_WARNING(this->
GetDeviceId() <<
": Frame could not be added because validation failed");
589 LOG_ERROR(this->
GetDeviceId() <<
": Failed to write snapshot frame");
601 return this->
Writer->GetTrackedFrameList()->SetCustomString(fieldName, fieldValue);
611 LOG_ERROR(
"Unable to prepare header");
630 LOG_ERROR(
"Unable to append image data to header.");
660 LOG_ERROR(
"No output channels defined");
672 LOG_ERROR(
"No output channels defined");
676 return this->
OutputChannels[0]->GetTrackedFrameListSampled(lastAlreadyRecordedFrameTimestamp, nextFrameToBeRecordedTimestamp, recordedFrames, requestedFramePeriodSec, maxProcessingTimeSec);
684 LOG_ERROR(
"No output channels defined");
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
std::string GetOutputPath(const std::string &subPath)
Abstract interface for tracker and video devices.
virtual PlusStatus InternalUpdate()
vtkIGSIOSequenceIOBase * Writer
vtkStandardNewMacro(vtkPlusVirtualCapture)
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
std::string CurrentFilename
int FirstFrameIndexInThisSegment
Class to abstract away specific sequence file read/write details.
long int TotalFramesRecorded
virtual PlusStatus InternalConnect()
ChannelContainer InputChannels
virtual std::string GetDeviceId() const
virtual bool GetEnableFileCompression()
bool EnableCapturingOnStart
virtual bool IsFrameBuffered() const
PlusStatus GetInputTrackedFrameListSampled(double &lastAlreadyRecordedFrameTimestamp, double &nextFrameToBeRecordedTimestamp, vtkIGSIOTrackedFrameList *recordedFrames, double requestedFramePeriodSec, double maxProcessingTimeSec)
std::string EncodingFourCC
virtual PlusStatus InternalDisconnect()
virtual PlusStatus Reset()
void PrintSelf(ostream &os, vtkIndent indent)
virtual PlusStatus ClearRecordedFrames()
static vtkPlusConfig * GetInstance()
virtual PlusStatus Disconnect()
double MissingInputGracePeriodSec
virtual bool GetEnableCapturingOnStart()
void SetEnableFileCompression(bool aFileCompression)
vtkIGSIOTrackedFrameList * RecordedFrames
virtual PlusStatus TakeSnapshot()
double RecordingStartTime
virtual bool HasUnsavedData() const
virtual ~vtkPlusVirtualCapture()
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *)
virtual PlusStatus CloseFile(const char *aFilename=NULL, std::string *resultFilename=NULL)
virtual PlusStatus StopRecording()
virtual PlusStatus WriteFrames(bool force=false)
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
virtual PlusStatus NotifyConfigured()
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *)
bool EnableFileCompression
double LastAlreadyRecordedFrameTimestamp
virtual void SetIsData3D(bool)
void SetEnableCapturing(bool aValue)
bool StartThreadForInternalUpdates
vtkSmartPointer< vtkIGSIORecursiveCriticalSection > WriterAccessMutex
virtual void InternalWriteOutputChannels(vtkXMLDataElement *rootXMLElement)
bool HasGracePeriodExpired()
Contains an optional timestamped circular buffer containing the video images and a number of timestam...
virtual vtkXMLDataElement * GetDeviceSetConfigurationData()
ChannelContainer OutputChannels
double NextFrameToBeRecordedTimestamp
virtual PlusStatus OpenFile(const char *aFilename=NULL)
double RequestedFrameRate
PlusStatus GetLatestInputItemTimestamp(double ×tamp)
virtual double GetRequestedFrameRate()
virtual bool GetIsData3D()
PlusStatus GetInputTrackedFrame(igsioTrackedFrame &aFrame)
unsigned int FrameBufferSize
virtual PlusStatus SetCustomHeaderField(const std::string &fieldName, const std::string &fieldValue)
virtual unsigned int GetFrameBufferSize()
vtkPlusLogger::LogLevelType GracePeriodLogLevel
virtual int OutputChannelCount() const