📄 vidinput_v4l.cxx
字号:
videoCapability.minwidth = 352;
}
maxHeight = videoCapability.maxheight;
maxWidth = videoCapability.maxwidth;
minHeight = videoCapability.minheight;
minWidth = videoCapability.minwidth;
PTRACE(3,"PVideoInputDevice_V4L:\t GetFrameSizeLimits. "<<minWidth<<"x"<<minHeight<<" -- "<<maxWidth<<"x"<<maxHeight);
return TRUE;
}
BOOL PVideoInputDevice_V4L::SetFrameSize(unsigned width, unsigned height)
{
PTRACE(5, "PVideoInputDevice_V4L\t SetFrameSize " << width <<"x"<<height << " Initiated.");
if (!PVideoDevice::SetFrameSize(width, height)) {
PTRACE(3,"PVideoInputDevice_V4L\t SetFrameSize "<<width<<"x"<<height<<" FAILED");
return FALSE;
}
ClearMapping();
if (!VerifyHardwareFrameSize(width, height)) {
PTRACE(3,"PVideoInputDevice_V4L\t SetFrameSize failed for "<<width<<"x"<<height);
PTRACE(3,"VerifyHardwareFrameSize failed.");
return FALSE;
}
frameBytes = CalculateFrameBytes(frameWidth, frameHeight, colourFormat);
return TRUE;
}
PINDEX PVideoInputDevice_V4L::GetMaxFrameBytes()
{
return GetMaxFrameBytesConverted(frameBytes);
}
BOOL PVideoInputDevice_V4L::GetFrameData(BYTE *buffer, PINDEX *bytesReturned)
{
if(frameRate>0) {
frameTimeError += msBetweenFrames;
do {
if ( !GetFrameDataNoDelay(buffer, bytesReturned))
{
return FALSE;
}
PTime now;
PTimeInterval delay = now - previousFrameTime;
frameTimeError -= (int)delay.GetMilliSeconds();
previousFrameTime = now;
} while(frameTimeError > 0) ;
return TRUE;
}
return GetFrameDataNoDelay(buffer, bytesReturned);
}
BOOL PVideoInputDevice_V4L::GetFrameDataNoDelay(BYTE * buffer, PINDEX * bytesReturned)
{
if (canMap < 0) {
//When canMap is < 0, it is the first use of GetFrameData. Check for memory mapping.
if (::ioctl(videoFd, VIDIOCGMBUF, &frame) < 0) {
canMap=0;
PTRACE(3, "VideoGrabber " << deviceName << " cannot do memory mapping - GMBUF failed.");
//This video device cannot do memory mapping.
} else {
videoBuffer = (BYTE *)::mmap(0, frame.size, PROT_READ|PROT_WRITE, MAP_SHARED, videoFd, 0);
if (videoBuffer < 0) {
canMap = 0;
PTRACE(3, "VideoGrabber " << deviceName << " cannot do memory mapping - ::mmap failed.");
//This video device cannot do memory mapping.
} else {
canMap = 1;
frameBuffer[0].frame = 0;
frameBuffer[0].format = colourFormatCode;
frameBuffer[0].width = frameWidth;
frameBuffer[0].height = frameHeight;
frameBuffer[1].frame = 1;
frameBuffer[1].format = colourFormatCode;
frameBuffer[1].width = frameWidth;
frameBuffer[1].height = frameHeight;
currentFrame = 0;
int ret;
ret = ::ioctl(videoFd, VIDIOCMCAPTURE, &frameBuffer[currentFrame]);
if (ret < 0) {
PTRACE(1,"PVideoInputDevice_V4L::GetFrameData mcapture1 failed : " << ::strerror(errno));
ClearMapping();
canMap = 0;
//This video device cannot do memory mapping.
}
pendingSync[currentFrame] = TRUE;
}
}
}
if (canMap == 0)
{
return NormalReadProcess(buffer, bytesReturned);
}
/*****************************
* The xawtv package from http://bytesex.org/xawtv/index.html
* contains a programming-FAQ by Gerd Knorr.
* For streaming video with video4linux at the full frame rate
* (25 hz PAL, 30 hz NTSC) you need to,
*
* videoiomcapture frame 0 (setup)
*
* loop:
* videoiomcapture frame 1 (returns immediately)
* videoiocsync frame 0 (waits on the data)
* goto loop:
*
* the loop body could also have been:
* videoiomcapture frame 0 (returns immediately)
* videoiocsync frame 1 (waits on the data)
*
* The driver requires each mcapture has a corresponding sync.
* Thus, you use the pendingSync array.
*
* After the loop is finished, you need a videoiocsync 0.
*/
// trigger capture of next frame in this buffer.
// fallback to read() on errors.
int ret = -1;
ret = ::ioctl(videoFd, VIDIOCMCAPTURE, &frameBuffer[ 1 - currentFrame ]);
if ( ret < 0 ) {
PTRACE(1,"PVideoInputDevice_V4L::GetFrameData mcapture2 failed : " << ::strerror(errno));
ClearMapping();
canMap = 0;
return NormalReadProcess(buffer, bytesReturned);
}
pendingSync[ 1 - currentFrame ] = TRUE;
// device does support memory mapping, get data
// wait for the frame to load.
ret = ::ioctl(videoFd, VIDIOCSYNC, ¤tFrame);
pendingSync[currentFrame] = FALSE;
if (ret < 0) {
PTRACE(1,"PVideoInputDevice_V4L::GetFrameData csync failed : " << ::strerror(errno));
ClearMapping();
canMap = 0;
return NormalReadProcess(buffer, bytesReturned);
}
// If converting on the fly do it from frame store to output buffer, otherwise do
// straight copy.
if (converter != NULL)
converter->Convert(videoBuffer + frame.offsets[currentFrame], buffer, bytesReturned);
else {
memcpy(buffer, videoBuffer + frame.offsets[currentFrame], frameBytes);
if (bytesReturned != NULL)
*bytesReturned = frameBytes;
}
// change buffers
currentFrame = 1 - currentFrame;
return TRUE;
}
//This video device does not support memory mapping - so
// use normal read process to extract a frame of video data.
BOOL PVideoInputDevice_V4L::NormalReadProcess(BYTE *resultBuffer, PINDEX *bytesReturned)
{
ssize_t ret;
ret = -1;
while (ret < 0) {
ret = ::read(videoFd, resultBuffer, frameBytes);
if ((ret < 0) && (errno == EINTR))
continue;
if (ret < 0) {
PTRACE(1,"PVideoInputDevice_V4L::NormalReadProcess() failed");
return FALSE;
}
}
if ((PINDEX)ret != frameBytes) {
PTRACE(1,"PVideoInputDevice_V4L::NormalReadProcess() returned a short read");
// Not a completely fatal. Maybe it should return FALSE instead of a partial
// image though?
// return FALSE;
}
if (converter != NULL)
return converter->ConvertInPlace(resultBuffer, bytesReturned);
if (bytesReturned != NULL)
*bytesReturned = frameBytes;
return TRUE;
}
void PVideoInputDevice_V4L::ClearMapping()
{
if ((canMap == 1) && (videoBuffer != NULL)) {
for (int i=0; i<2; i++) {
if (pendingSync[i]) {
int res = ::ioctl(videoFd, VIDIOCSYNC, &i);
if (res < 0)
PTRACE(1,"PVideoInputDevice_V4L::GetFrameData csync failed : " << ::strerror(errno));
pendingSync[i] = FALSE;
}
::munmap(videoBuffer, frame.size);
}
}
canMap = -1;
videoBuffer = NULL;
}
BOOL PVideoInputDevice_V4L::VerifyHardwareFrameSize(unsigned width, unsigned height)
{
struct video_window vwin;
if (HINT(HINT_FORCE_LARGE_SIZE))
if( (width==352) && (height==288) ) {
PTRACE(3,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize USB OK 352x288 ");
return TRUE;
} else {
PTRACE(3,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize USB FAIL "<<width<<"x"<<height);
return FALSE;
}
if (HINT(HINT_ALWAYS_WORKS_320_240) && (width==320) && (height==240) ) {
PTRACE(3,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize OK for 320x240 ");
return TRUE;
}
if (HINT(HINT_ALWAYS_WORKS_640_480) && (width==640) && (height==480) ) {
PTRACE(3,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize OK for 640x480 ");
return TRUE;
}
if (HINT(HINT_CGWIN_FAILS)) {
PTRACE(3,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize fails for size "
<< width << "x" << height);
return FALSE;
}
// Request current hardware frame size
if (::ioctl(videoFd, VIDIOCGWIN, &vwin) < 0) {
PTRACE(3,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize VIDIOCGWIN1 error::" << ::strerror(errno));
return FALSE;
}
// Request the width and height
vwin.width = width;
vwin.height = height;
// The only defined flags appear to be as status indicators
// returned in the CGWIN call. At least the bttv driver fails
// when flags isn't zero. Check the driver hints for clearing
// the flags.
if (HINT(HINT_CSWIN_ZERO_FLAGS)) {
PTRACE(1,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize: Clearing flags field");
vwin.flags = 0;
}
::ioctl(videoFd, VIDIOCSWIN, &vwin);
// Read back settings to be careful about existing (broken) V4L drivers
if (::ioctl(videoFd, VIDIOCGWIN, &vwin) < 0) {
PTRACE(3,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize VIDIOCGWIN2 error::" << ::strerror(errno));
return FALSE;
}
if ((vwin.width != width) || (vwin.height != height)) {
PTRACE(3,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize Size mismatch.");
return FALSE;
}
return TRUE;
}
int PVideoInputDevice_V4L::GetBrightness()
{
if (!IsOpen())
return -1;
struct video_picture vp;
if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
return -1;
frameBrightness = vp.brightness;
return frameBrightness;
}
int PVideoInputDevice_V4L::GetWhiteness()
{
if (!IsOpen())
return -1;
struct video_picture vp;
if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
return -1;
frameWhiteness = vp.whiteness;
return frameWhiteness;
}
int PVideoInputDevice_V4L::GetColour()
{
if (!IsOpen())
return -1;
struct video_picture vp;
if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
return -1;
frameColour = vp.colour;
return frameColour;
}
int PVideoInputDevice_V4L::GetContrast()
{
if (!IsOpen())
return -1;
struct video_picture vp;
if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
return -1;
frameContrast = vp.contrast;
return frameContrast;
}
int PVideoInputDevice_V4L::GetHue()
{
if (!IsOpen())
return -1;
struct video_picture vp;
if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
return -1;
frameHue = vp.hue;
return frameHue;
}
BOOL PVideoInputDevice_V4L::SetBrightness(unsigned newBrightness)
{
if (!IsOpen())
return FALSE;
struct video_picture vp;
if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
return FALSE;
vp.brightness = newBrightness;
if (::ioctl(videoFd, VIDIOCSPICT, &vp) < 0)
return FALSE;
frameBrightness=newBrightness;
return TRUE;
}
BOOL PVideoInputDevice_V4L::SetWhiteness(unsigned newWhiteness)
{
if (!IsOpen())
return FALSE;
struct video_picture vp;
if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
return FALSE;
vp.whiteness = newWhiteness;
if (::ioctl(videoFd, VIDIOCSPICT, &vp) < 0)
return FALSE;
frameWhiteness = newWhiteness;
return TRUE;
}
BOOL PVideoInputDevice_V4L::SetColour(unsigned newColour)
{
if (!IsOpen())
return FALSE;
struct video_picture vp;
if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
return FALSE;
vp.colour = newColour;
if (::ioctl(videoFd, VIDIOCSPICT, &vp) < 0)
return FALSE;
frameColour = newColour;
return TRUE;
}
BOOL PVideoInputDevice_V4L::SetContrast(unsigned newContrast)
{
if (!IsOpen())
return FALSE;
struct video_picture vp;
if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
return FALSE;
vp.contrast = newContrast;
if (::ioctl(videoFd, VIDIOCSPICT, &vp) < 0)
return FALSE;
frameContrast = newContrast;
return TRUE;
}
BOOL PVideoInputDevice_V4L::SetHue(unsigned newHue)
{
if (!IsOpen())
return FALSE;
struct video_picture vp;
if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
return FALSE;
vp.hue = newHue;
if (::ioctl(videoFd, VIDIOCSPICT, &vp) < 0)
return FALSE;
frameHue=newHue;
return TRUE;
}
BOOL PVideoInputDevice_V4L::GetParameters (int *whiteness, int *brightness,
int *colour, int *contrast, int *hue)
{
if (!IsOpen())
return FALSE;
struct video_picture vp;
if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
{
PTRACE(3, "GetParams bombs out!");
return FALSE;
}
*brightness = vp.brightness;
*colour = vp.colour;
*contrast = vp.contrast;
*hue = vp.hue;
*whiteness = vp.whiteness;
frameBrightness = *brightness;
frameColour = *colour;
frameContrast = *contrast;
frameHue = *hue;
frameWhiteness = *whiteness;
return TRUE;
}
BOOL PVideoInputDevice_V4L::TestAllFormats()
{
return TRUE;
}
// End Of File ///////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -