8 #include "PlusConfigure.h" 14 #include <vtkImageData.h> 15 #include <vtkObjectFactory.h> 21 #include <sys/ioctl.h> 32 int xioctl(
int fh,
unsigned long int request,
void* arg)
38 r = ioctl(fh, request, arg);
40 while (-1 == r && EINTR == errno);
46 #define CLEAR(x) memset(&(x), 0, sizeof(x)) 51 , IOMethod(IO_METHOD_READ)
53 , FrameBuffers(nullptr)
55 , DeviceFormat(std::make_shared<v4l2_format>())
56 , FormatWidth(nullptr)
57 , FormatHeight(nullptr)
58 , PixelFormat(nullptr)
62 memset(this->
DeviceFormat.get(), 0,
sizeof(
struct v4l2_format));
77 os << indent <<
"DeviceName: " << this->
DeviceName << std::endl;
79 os << indent <<
"BufferCount: " << this->
BufferCount << std::endl;
83 os << indent <<
"Available formats: " << std::endl;
85 struct v4l2_fmtdesc fmtdesc;
87 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
88 while (ioctl(this->
FileDescriptor, VIDIOC_ENUM_FMT, &fmtdesc) == 0)
90 os << indent << fmtdesc.description << std::endl;
96 os << indent <<
"Cannot enumerate known formats. Camera not connected." << std::endl;
105 XML_READ_STRING_ATTRIBUTE_REQUIRED(
DeviceName, deviceConfig);
106 std::string ioMethod;
107 XML_READ_STRING_ATTRIBUTE_NONMEMBER_OPTIONAL(
IOMethod, ioMethod, deviceConfig);
118 XML_READ_VECTOR_ATTRIBUTE_NONMEMBER_OPTIONAL(
int, 2, FrameSize, frameSize, deviceConfig);
119 if (deviceConfig->GetAttribute(
"FrameSize") !=
nullptr)
121 if (frameSize[0] < 0 || frameSize[1] < 0)
123 LOG_WARNING(
"Invalid frame size in configuration file. Not setting parameters to device.");
127 this->
FormatHeight = std::make_shared<unsigned int>(static_cast<unsigned int>(frameSize[0]));
128 this->
FormatWidth = std::make_shared<unsigned int>(static_cast<unsigned int>(frameSize[1]));
132 std::string pixelFormat;
133 XML_READ_STRING_ATTRIBUTE_NONMEMBER_OPTIONAL(
PixelFormat, pixelFormat, deviceConfig);
134 if (deviceConfig->GetAttribute(
"PixelFormat") !=
nullptr)
139 std::string fieldOrder;
140 XML_READ_STRING_ATTRIBUTE_NONMEMBER_OPTIONAL(
FieldOrder, fieldOrder, deviceConfig);
141 if (deviceConfig->GetAttribute(
"FieldOrder") !=
nullptr)
154 XML_WRITE_STRING_ATTRIBUTE_IF_NOT_EMPTY(
DeviceName, deviceConfig);
158 int frameSize[2] = { static_cast<int>(this->
DeviceFormat->fmt.pix.width), static_cast<int>(this->
DeviceFormat->fmt.pix.height) };
159 deviceConfig->SetVectorAttribute(
"FrameSize", 2, frameSize);
171 this->
FrameBuffers = (FrameBuffer*) calloc(1,
sizeof(FrameBuffer));
175 LOG_ERROR(
"Unable to allocate " <<
sizeof(FrameBuffer) <<
" bytes for capture frame.");
184 LOG_ERROR(
"Unable to allocate " << bufferSize <<
" bytes for capture frame.");
196 struct v4l2_requestbuffers req;
201 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
202 req.memory = V4L2_MEMORY_MMAP;
208 LOG_ERROR(this->
DeviceName <<
" does not support memory mapping");
212 LOG_ERROR(
"VIDIOC_REQBUFS" <<
": " << strerror(errno));
219 LOG_ERROR(
"Insufficient buffer memory on " << this->
DeviceName);
223 this->
FrameBuffers = (FrameBuffer*) calloc(req.count,
sizeof(FrameBuffer));
227 LOG_ERROR(
"Out of memory");
236 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
237 buf.memory = V4L2_MEMORY_MMAP;
242 LOG_ERROR(
"VIDIOC_QUERYBUF" <<
": " << strerror(errno));
247 this->
FrameBuffers[this->
BufferCount].start = mmap(NULL , buf.length, PROT_READ | PROT_WRITE , MAP_SHARED , this->FileDescriptor, buf.m.offset);
251 LOG_ERROR(
"mmap" <<
": " << strerror(errno));
261 struct v4l2_requestbuffers req;
266 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
267 req.memory = V4L2_MEMORY_USERPTR;
273 LOG_ERROR(this->
DeviceName <<
" does not support user pointer i/o");
277 LOG_ERROR(
"VIDIOC_REQBUFS" <<
": " << strerror(errno));
282 this->
FrameBuffers = (FrameBuffer*) calloc(4,
sizeof(FrameBuffer));
286 LOG_ERROR(
"Out of memory");
297 LOG_ERROR(
"Out of memory");
310 if (-1 == stat(this->
DeviceName.c_str(), &st))
312 LOG_ERROR(
"Cannot identify " << this->
DeviceName <<
": " << strerror(errno));
315 if (!S_ISCHR(st.st_mode))
317 LOG_ERROR(this->
DeviceName <<
" is not a valid device.");
325 LOG_ERROR(
"Cannot open " << this->
DeviceName <<
": " << strerror(errno));
335 LOG_ERROR(this->
DeviceName <<
" is not a V4L2 device");
339 LOG_ERROR(
"VIDIOC_QUERYCAP" <<
": " << strerror(errno));
344 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
346 LOG_ERROR(this->
DeviceName <<
" is not a video capture device");
354 if (!(cap.capabilities & V4L2_CAP_READWRITE))
356 LOG_ERROR(this->
DeviceName <<
" does not support read i/o");
362 case IO_METHOD_USERPTR:
364 if (!(cap.capabilities & V4L2_CAP_STREAMING))
366 LOG_ERROR(this->
DeviceName <<
" does not support streaming i/o");
373 LOG_ERROR(
"Unknown IO method.");
379 struct v4l2_cropcap cropcap;
381 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
384 struct v4l2_crop crop;
386 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
387 crop.c = cropcap.defrect;
405 LOG_ERROR(
"VIDIOC_G_FMT" <<
": " << strerror(errno));
428 LOG_WARNING(
"Unable to set requested video format. Continuing with existing format: " << strerror(errno));
431 LOG_ERROR(
"VIDIOC_G_FMT" <<
": " << strerror(errno));
459 case IO_METHOD_USERPTR:
486 LOG_ERROR(
"munmap" <<
": " << strerror(errno));
492 case IO_METHOD_USERPTR:
506 LOG_ERROR(
"Close" <<
": " << strerror(errno));
534 LOG_ERROR(
"Unable to select video device" <<
": " << strerror(errno));
540 LOG_ERROR(
"Select timeout.");
544 unsigned int currentBufferIndex;
545 unsigned int bytesUsed;
551 if (this->
DataSource->
AddItem(this->FrameBuffers[currentBufferIndex].start, this->ImageSize, bytesUsed, US_IMG_BRIGHTNESS, this->FrameNumber, UNDEFINED_TIMESTAMP, UNDEFINED_TIMESTAMP, &this->FrameFields) !=
PLUS_SUCCESS)
553 LOG_ERROR(
"vtkPlusV4L2VideoSource::Unable to add item to the buffer.");
574 case IO_METHOD_USERPTR:
600 LOG_ERROR(
"Read" <<
": " << strerror(errno));
606 currentBufferIndex = 0;
615 struct v4l2_buffer buf;
618 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
619 buf.memory = V4L2_MEMORY_MMAP;
635 LOG_ERROR(
"VIDIOC_DQBUF" <<
": " << strerror(errno));
643 LOG_ERROR(
"VIDIOC_QBUF" <<
": " << strerror(errno));
647 currentBufferIndex = buf.index;
648 bytesUsed = buf.length;
659 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
660 buf.memory = V4L2_MEMORY_USERPTR;
676 LOG_ERROR(
"VIDIOC_DQBUF" <<
": " << strerror(errno));
682 for (currentBufferIndex = 0; currentBufferIndex < this->
BufferCount; ++currentBufferIndex)
684 if (buf.m.userptr == (
unsigned long) this->FrameBuffers[currentBufferIndex].start && buf.length == this->FrameBuffers[currentBufferIndex].length)
692 LOG_ERROR(
"VIDIOC_QBUF" <<
": " << strerror(errno));
696 bytesUsed = buf.bytesused;
706 LOG_ERROR(
"No output channels defined for vtkPlusV4L2VideoSource. Cannot proceed.");
713 LOG_ERROR(
"Cannot retrieve first output video source. Unable to start device.");
733 case IO_METHOD_USERPTR:
735 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
738 LOG_ERROR(
"VIDIOC_STREAMOFF" <<
": " << strerror(errno));
750 enum v4l2_buf_type type;
758 struct v4l2_buffer buf;
760 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
761 buf.memory = V4L2_MEMORY_MMAP;
766 LOG_ERROR(
"VIDIOC_QBUF" <<
": " << strerror(errno));
770 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
773 LOG_ERROR(
"VIDIOC_STREAMON" <<
": " << strerror(errno));
778 case IO_METHOD_USERPTR:
782 struct v4l2_buffer buf;
784 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
785 buf.memory = V4L2_MEMORY_USERPTR;
792 LOG_ERROR(
"VIDIOC_QBUF" <<
": " << strerror(errno));
796 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
799 LOG_ERROR(
"VIDIOC_STREAMON" <<
": " << strerror(errno));
817 return "IO_METHOD_READ";
819 return "IO_METHOD_MMAP";
820 case IO_METHOD_USERPTR:
821 return "IO_METHOD_USERPTR";
823 return "IO_METHOD_UNKNOWN";
830 if (igsioCommon::IsEqualInsensitive(method,
"IO_METHOD_READ"))
832 return IO_METHOD_READ;
834 else if (igsioCommon::IsEqualInsensitive(method,
"IO_METHOD_MMAP"))
836 return IO_METHOD_MMAP;
838 else if (igsioCommon::IsEqualInsensitive(method,
"IO_METHOD_USERPTR"))
840 return IO_METHOD_USERPTR;
844 return IO_METHOD_UNKNOWN;
849 #define PIXEL_FORMAT_CASE(format) case format: return #format 963 {
return "V4L2_PIX_FMT_XXXX";}
966 #undef PIXEL_FORMAT_CASE 969 #define PIXEL_FORMAT_STRING_COMPARE(format, formatStr) else if (igsioCommon::IsEqualInsensitive(#format, formatStr)) return format 972 if (igsioCommon::IsEqualInsensitive(
"V4L2_PIX_FMT_RGB332", format)) {
return V4L2_PIX_FMT_RGB332;}
1080 else {
return v4l2_fourcc(
'x',
'x',
'x',
'x');}
1082 #undef PIXEL_FORMAT_STRING_COMPARE 1085 #define FIELD_ORDER_CASE(field) case field: return #field 1101 {
return "V4L2_FIELD_ANY";}
1104 #undef FIELD_ORDER_CASE 1109 if (igsioCommon::IsEqualInsensitive(
"V4L2_FIELD_ANY", field)) {
return V4L2_FIELD_ANY;}
1110 else if (igsioCommon::IsEqualInsensitive(
"V4L2_FIELD_TOP", field)){
return V4L2_FIELD_TOP;}
1111 else if (igsioCommon::IsEqualInsensitive(
"V4L2_FIELD_BOTTOM", field)){
return V4L2_FIELD_BOTTOM;}
1112 else if (igsioCommon::IsEqualInsensitive(
"V4L2_FIELD_INTERLACED", field)){
return V4L2_FIELD_INTERLACED;}
1113 else if (igsioCommon::IsEqualInsensitive(
"V4L2_FIELD_SEQ_TB", field)){
return V4L2_FIELD_SEQ_TB;}
1114 else if (igsioCommon::IsEqualInsensitive(
"V4L2_FIELD_SEQ_BT", field)){
return V4L2_FIELD_SEQ_BT;}
1115 else if (igsioCommon::IsEqualInsensitive(
"V4L2_FIELD_ALTERNATE", field)){
return V4L2_FIELD_ALTERNATE;}
1116 else if (igsioCommon::IsEqualInsensitive(
"V4L2_FIELD_INTERLACED_TB", field)){
return V4L2_FIELD_INTERLACED_TB;}
1117 else if (igsioCommon::IsEqualInsensitive(
"V4L2_FIELD_INTERLACED_BT", field)){
return V4L2_FIELD_INTERLACED_BT;}
1118 else {
return V4L2_FIELD_ANY;}
std::shared_ptr< unsigned int > FormatWidth
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
static unsigned int StringToPixelFormat(const std::string &format)
virtual PlusStatus InternalStartRecording() VTK_OVERRIDE
uint32_t NumberOfScalarComponents
PlusStatus InitRead(unsigned int bufferSize)
std::shared_ptr< unsigned int > PixelFormat
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
PlusStatus ReadConfiguration(vtkXMLDataElement *config)
static std::string IOMethodToString(V4L2_IO_METHOD ioMethod)
FrameBuffer * FrameBuffers
PlusStatus SetInputFrameSize(unsigned int x, unsigned int y, unsigned int z)
virtual PlusStatus AddItem(vtkImageData *frame, US_IMAGE_ORIENTATION usImageOrientation, US_IMAGE_TYPE imageType, long frameNumber, double unfilteredTimestamp=UNDEFINED_TIMESTAMP, double filteredTimestamp=UNDEFINED_TIMESTAMP, const igsioFieldMapType *customFields=NULL)
PlusStatus WriteConfiguration(vtkXMLDataElement *config)
PlusStatus ReadFrame(unsigned int ¤tBufferIndex, unsigned int &bytesUsed)
PlusStatus ReadFrameFileDescriptor(unsigned int ¤tBufferIndex, unsigned int &bytesUsed)
PlusStatus SetPixelType(igsioCommon::VTKScalarPixelType pixelType)
virtual PlusStatus NotifyConfigured()
PlusStatus InternalUpdate()
PlusStatus GetFirstActiveOutputVideoSource(vtkPlusDataSource *&aVideoSource)
Class for interfacing an V4L2 device and recording frames into a Plus buffer.
unsigned long FrameNumber
static v4l2_field StringToFieldOrder(const std::string &field)
#define PIXEL_FORMAT_CASE(format)
PlusStatus InitUserp(unsigned int bufferSize)
vtkPlusDataSource * DataSource
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
static V4L2_IO_METHOD StringToIOMethod(const std::string &method)
igsioFieldMapType FrameFields
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
vtkStandardNewMacro(vtkPlusV4L2VideoSource)
static std::string PixelFormatToString(unsigned int format)
static std::string FieldOrderToString(v4l2_field field)
std::shared_ptr< v4l2_field > FieldOrder
bool StartThreadForInternalUpdates
~vtkPlusV4L2VideoSource()
ChannelContainer OutputChannels
virtual PlusStatus InternalDisconnect() VTK_OVERRIDE
PlusStatus SetNumberOfScalarComponents(unsigned int numberOfScalarComponents)
#define PIXEL_FORMAT_STRING_COMPARE(format, formatStr)
std::shared_ptr< unsigned int > FormatHeight
std::shared_ptr< struct v4l2_format > DeviceFormat
virtual PlusStatus InternalStopRecording() VTK_OVERRIDE
PlusStatus ReadFrameMemoryMap(unsigned int ¤tBufferIndex, unsigned int &bytesUsed)
#define FIELD_ORDER_CASE(field)
virtual PlusStatus InternalConnect() VTK_OVERRIDE
PlusStatus ReadFrameUserPtr(unsigned int ¤tBufferIndex, unsigned int &bytesUsed)