8 #include "PlusConfigure.h" 24 static const std::string START_CMD =
"StartRecording";
25 static const std::string SUSPEND_CMD =
"SuspendRecording";
26 static const std::string RESUME_CMD =
"ResumeRecording";
27 static const std::string STOP_CMD =
"StopRecording";
28 static const std::string HEADER_CMD =
"AddCustomHeaders";
33 : EnableCompression(false)
54 cmdNames.push_back(START_CMD);
55 cmdNames.push_back(SUSPEND_CMD);
56 cmdNames.push_back(RESUME_CMD);
57 cmdNames.push_back(STOP_CMD);
58 cmdNames.push_back(HEADER_CMD);
65 if (commandName.empty() || igsioCommon::IsEqualInsensitive(commandName, START_CMD))
68 desc +=
": Start collecting data into file with a VirtualCapture device.";
69 desc +=
" Attributes: OutputFilename: name of the output file (optional if base file name is specified in config file).";
70 desc +=
" CaptureDeviceId: ID of the capture device, if not specified then the first VirtualCapture device will be started (optional)";
71 desc +=
" PauseOnStart: Whether to enable capture when opening file. (optional)";
73 if (commandName.empty() || igsioCommon::IsEqualInsensitive(commandName, SUSPEND_CMD))
76 desc +=
": Suspend data collection. Attributes: CaptureDeviceId: (optional)";
78 if (commandName.empty() || igsioCommon::IsEqualInsensitive(commandName, RESUME_CMD))
81 desc +=
": Resume suspended data collection. Attributes: CaptureDeviceId (optional)";
83 if (commandName.empty() || igsioCommon::IsEqualInsensitive(commandName, STOP_CMD))
86 desc +=
": Stop collecting data into file with a VirtualCapture device. Attributes: OutputFilename: name of the output file (optional if base file name is specified in config file). CaptureDeviceId (optional)";
88 if (commandName.empty() || igsioCommon::IsEqualInsensitive(commandName, HEADER_CMD))
91 desc +=
": Add custom headers to the opened capture instance. Attributes: CaptureDeviceId (optional)";
117 XML_READ_CSTRING_ATTRIBUTE_OPTIONAL(CaptureDeviceId, aConfig);
118 XML_READ_CSTRING_ATTRIBUTE_OPTIONAL(ChannelId, aConfig);
120 if (CaptureDeviceId.empty() && ChannelId.empty())
122 LOG_ERROR(
"Neither CaptureDeviceId nor ChannelId specified. Aborting.");
127 XML_READ_CSTRING_ATTRIBUTE_OPTIONAL(OutputFilename, aConfig);
130 if (this->GetName() == START_CMD)
132 XML_READ_BOOL_ATTRIBUTE_OPTIONAL(EnableCompression, aConfig);
133 XML_READ_BOOL_ATTRIBUTE_OPTIONAL(PauseOnStart, aConfig);
134 XML_READ_STRING_ATTRIBUTE_OPTIONAL(CodecFourCC, aConfig);
136 else if (this->GetName() == HEADER_CMD)
138 this->RequestedCustomHeaders.clear();
141 for (
int elemIndex = 0; elemIndex < aConfig->GetNumberOfNestedElements(); ++elemIndex)
143 vtkXMLDataElement* currentElem = aConfig->GetNestedElement(elemIndex);
144 if (igsioCommon::IsEqualInsensitive(currentElem->GetName(),
"Header"))
146 const char* headerName = currentElem->GetAttribute(
"Name");
147 const char* headerValue = currentElem->GetAttribute(
"Value");
148 if (!headerName || !headerValue)
150 LOG_ERROR(
"Unable to find required Name or Value attribute in " << (currentElem->GetName() ? currentElem->GetName() :
"(undefined)") <<
" element is AddCustomHeaders command");
154 this->RequestedCustomHeaders[headerName] = headerValue;
170 XML_WRITE_STRING_ATTRIBUTE_REMOVE_IF_EMPTY(CaptureDeviceId, aConfig);
171 XML_WRITE_STRING_ATTRIBUTE_REMOVE_IF_EMPTY(ChannelId, aConfig);
172 XML_WRITE_STRING_ATTRIBUTE_REMOVE_IF_EMPTY(OutputFilename, aConfig);
174 if (this->GetName() == START_CMD)
176 XML_WRITE_BOOL_ATTRIBUTE(EnableCompression, aConfig);
186 if (dataCollector == NULL)
188 LOG_ERROR(
"Data collector is invalid");
192 if (!captureDeviceId.empty())
198 LOG_ERROR(
"No VirtualCapture has been found by the name " << captureDeviceId);
203 if (captureDevice == NULL)
206 LOG_ERROR(
"The specified device " << captureDeviceId <<
" is not a VirtualCapture device.");
216 if (captureDevice != NULL)
222 if (captureDevice == NULL)
224 LOG_ERROR(
"No VirtualCapture has been found");
228 return captureDevice;
235 if (dataCollector == NULL)
237 LOG_ERROR(
"Data collector is invalid");
241 if (channelId.empty())
249 LOG_ERROR(
"Unable to locate channel. Aborting.");
256 if (dynamic_cast<vtkPlusVirtualCapture*>(*
iter) !=
nullptr)
258 std::vector<vtkPlusDevice*> devices;
259 (*iter)->GetInputDevices(devices);
260 for (
auto it = devices.begin(); it != devices.end(); ++it)
263 if ((*it)->GetOutputChannelByName(aChannel, channelId) ==
PLUS_SUCCESS)
265 foundDevice = dynamic_cast<vtkPlusVirtualCapture*>(*
iter);
271 if (foundDevice !=
nullptr)
278 assert(device !=
nullptr);
281 vtkSmartPointer<vtkPlusDeviceFactory> factory = vtkSmartPointer<vtkPlusDeviceFactory>::New();
282 if (factory->CreateInstance(
"VirtualCapture", newDevice, channelId +
"_capture") !=
PLUS_SUCCESS)
284 LOG_ERROR(
"Unable to create capture device. Aborting.");
287 auto capDevice = dynamic_cast<vtkPlusVirtualCapture*>(newDevice);
290 capDevice->SetEnableFileCompression(this->EnableCompression);
291 if (!this->CodecFourCC.empty())
293 capDevice->SetEncodingFourCC(this->CodecFourCC);
295 capDevice->SetBaseFilename(channelId +
"_capture.nrrd");
303 LOG_INFO(
"vtkPlusStartStopRecordingCommand::Execute:");
305 if (this->
Name.empty())
312 if (!this->CaptureDeviceId.empty())
316 else if (!this->ChannelId.empty())
321 if (captureDevice == NULL)
324 + (!this->CaptureDeviceId.empty() ? this->CaptureDeviceId : !this->ChannelId.empty() ? this->ChannelId :
"auto-detect") +
"), " + this->
Name);
328 std::string responseMessageBase = std::string(
"VirtualCapture (") + captureDevice->
GetDeviceId() +
") " + this->
Name +
" ";
329 LOG_INFO(
"vtkPlusStartStopRecordingCommand::Execute: " << this->
Name);
331 if (igsioCommon::IsEqualInsensitive(this->
Name, START_CMD))
335 this->
QueueCommandResponse(
PLUS_FAIL,
"Command failed. See error message.", responseMessageBase + std::string(
"Recording to file is already in progress."));
339 if (!this->OutputFilename.empty())
341 outputFilename = this->OutputFilename;
348 this->
QueueCommandResponse(
PLUS_FAIL,
"Command failed. See error message.", responseMessageBase + std::string(
"Failed to open file ") + (!this->OutputFilename.empty() ? this->OutputFilename :
"(undefined)") + std::string(
"."));
355 else if (igsioCommon::IsEqualInsensitive(this->
Name, SUSPEND_CMD))
359 this->
QueueCommandResponse(
PLUS_FAIL,
"Command failed. See error message.", responseMessageBase + std::string(
"Suspend recording failed: recording to file is not in progress."));
366 else if (igsioCommon::IsEqualInsensitive(this->
Name, RESUME_CMD))
370 this->
QueueCommandResponse(
PLUS_FAIL,
"Command failed. See error message.", responseMessageBase + std::string(
"Resume recording failed: recording to file is already in progress."));
377 else if (igsioCommon::IsEqualInsensitive(this->
Name, STOP_CMD))
391 if (!this->OutputFilename.empty())
393 resultFilename = this->OutputFilename;
397 std::string actualOutputFilename;
400 this->
QueueCommandResponse(
PLUS_FAIL,
"Command failed. See error message.", responseMessageBase +
"Failed to finalize file: " + resultFilename);
403 std::ostringstream ss;
404 ss <<
"Recording " << numberOfFramesRecorded <<
" frames successful to file " << actualOutputFilename;
408 else if (igsioCommon::IsEqualInsensitive(this->
Name, HEADER_CMD))
410 std::map<std::string, std::string>::iterator headerIt;
411 for (headerIt = this->RequestedCustomHeaders.begin(); headerIt != this->RequestedCustomHeaders.end(); ++headerIt)
413 std::string headerName = headerIt->first;
414 std::string headerValue = headerIt->second;
418 this->
QueueCommandResponse(
PLUS_FAIL,
"Command failed. See error message.", responseMessageBase +
"Failed to write header: " + headerName +
", " + headerValue);
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *aConfig)
PlusStatus AddInputChannel(vtkPlusChannel *aChannel)
virtual void PrintSelf(ostream &os, vtkIndent indent)
Abstract interface for tracker and video devices.
std::vector< vtkPlusDevice * >::const_iterator DeviceCollectionConstIterator
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *aConfig)
PlusStatus GetDevice(vtkPlusDevice *&aDevice, const std::string &aDeviceId) const
This is an abstract superclass for commands in the OpenIGTLink network interface for Plus.
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *aConfig)
virtual std::string GetDeviceId() const
virtual ~vtkPlusStartStopRecordingCommand()
virtual std::string GetDescription(const std::string &commandName)
virtual long int GetTotalFramesRecorded()
virtual bool GetPauseOnStart()
static vtkPlusStartStopRecordingCommand * New()
virtual PlusStatus Execute()
DeviceCollectionConstIterator GetDeviceConstIteratorBegin() const
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *aConfig)
void SetEnableFileCompression(bool aFileCompression)
DeviceCollectionConstIterator GetDeviceConstIteratorEnd() const
Manages devices that record image or positional data.
virtual bool GetEnableCapturing()
virtual PlusStatus CloseFile(const char *aFilename=NULL, std::string *resultFilename=NULL)
vtkPlusStartStopRecordingCommand()
virtual bool GetEnableCompression()
virtual std::string GetBaseFilename()
virtual void PrintSelf(ostream &os, vtkIndent indent)
void QueueCommandResponse(PlusStatus status, const std::string &message, const std::string &error="", const igtl::MessageBase::MetaDataMap *metaData=nullptr)
virtual vtkPlusDataCollector * GetDataCollector()
virtual vtkPlusCommand * Clone()
void SetEnableCapturing(bool aValue)
virtual void SetDataCollector(vtkPlusDataCollector *_arg)
vtkStandardNewMacro(vtkPlusStartStopRecordingCommand)
Contains an optional timestamped circular buffer containing the video images and a number of timestam...
virtual PlusStatus OpenFile(const char *aFilename=NULL)
This command starts and stops capturing with a vtkPlusVirtualCapture capture on the server side.
virtual std::string GetOutputFileName()
vtkPlusVirtualCapture * GetOrCreateCaptureDevice(const std::string &channelId)
PlusStatus GetChannel(vtkPlusChannel *&aChannel, const std::string &aChannelId) const
static vtkPlusVirtualCapture * SafeDownCast(vtkObject *o)
virtual void GetCommandNames(std::list< std::string > &cmdNames)
vtkPlusVirtualCapture * GetCaptureDevice(const std::string &captureDeviceId)
virtual PlusStatus SetCustomHeaderField(const std::string &fieldName, const std::string &fieldValue)