⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vidinput_v4l.cxx

📁 sloedgy open sip stack source code
💻 CXX
📖 第 1 页 / 共 3 页
字号:
        tempList.SetDataAt(j, revisedUserName);
      }
    }
  }

  //At this stage, we have correctly modified the temp list of names.
  for (j = 0; j < tempList.GetSize(); j++)
    AddUserDeviceName(tempList.GetDataAt(j), tempList.GetKeyAt(j));  
}

PString V4LNames::GetUserFriendly(PString devName)
{
  PWaitAndSignal m(mutex);

  
  PString result= deviceKey(devName);
  if (result.IsEmpty())
    return devName;

  return result;
}

PString V4LNames::GetDeviceName(PString userName)
{
  PWaitAndSignal m(mutex);

  for (PINDEX i = 0; i < userKey.GetSize(); i++)
    if (userKey.GetKeyAt(i).Find(userName) != P_MAX_INDEX)
      return userKey.GetDataAt(i);

  return userName;
}

void V4LNames::AddUserDeviceName(PString userName, PString devName)
{
  if (userName != devName) { // must be a real userName!
    userKey.SetAt(userName, devName);
    deviceKey.SetAt(devName, userName);
  } else { // we didn't find a good userName
    if (!deviceKey.Contains (devName)) { // never met before: fallback
      userKey.SetAt(userName, devName);
      deviceKey.SetAt(devName, userName);
    } // no else: we already know the pair
  }
}

PString V4LNames::BuildUserFriendly(PString devname)
{
  PString Result;

  int fd = ::open((const char *)devname, O_RDONLY);
  if(fd < 0) {
    return devname;
  }

  struct video_capability videocap;
  if (::ioctl(fd, VIDIOCGCAP, &videocap) < 0)  {
      ::close(fd);
      return devname;
    }
  
  ::close(fd);
  PString ufname(videocap.name);  

  return ufname;
}

/*
  There is a duplication in the list of names.
  Consequently, opening the device as "ov511++" or "/dev/video0" will work.
*/
PStringList V4LNames::GetInputDeviceNames()
{
  PWaitAndSignal m(mutex);
  PStringList result;
  for (PINDEX i = 0; i < inputDeviceNames.GetSize(); i++) {
    result += GetUserFriendly (inputDeviceNames[i]);
    //result += inputDeviceNames[i];
  }

  return result;
}

static 
V4LNames & GetNames()
{
  static V4LNames names;
  names.Update();
  return names;
} 

///////////////////////////////////////////////////////////////////////////////
// PVideoInputDevice_V4L

PVideoInputDevice_V4L::PVideoInputDevice_V4L()
{
  videoFd       = -1;
  hint_index    = PARRAYSIZE(driver_hints) - 1;

  canMap           = -1;
  for (int i=0; i<2; i++)
    pendingSync[i] = FALSE;
}

PVideoInputDevice_V4L::~PVideoInputDevice_V4L()
{
    Close();
}
static struct {
  const char * colourFormat;
  int code;
} colourFormatTab[] = {
  { "Grey", VIDEO_PALETTE_GREY },  //Entries in this table correspond
  { "BGR32", VIDEO_PALETTE_RGB32 }, //(line by line) to those in the 
  { "BGR24", VIDEO_PALETTE_RGB24 }, // PVideoDevice ColourFormat table.
  { "RGB565", VIDEO_PALETTE_RGB565 },
  { "RGB555", VIDEO_PALETTE_RGB555 },
  { "YUV422", VIDEO_PALETTE_YUV422 },
  { "YUV422P", VIDEO_PALETTE_YUV422P },
  { "YUV411", VIDEO_PALETTE_YUV411 },
  { "YUV411P", VIDEO_PALETTE_YUV411P },
  { "YUV420", VIDEO_PALETTE_YUV420 },
  { "YUV420P", VIDEO_PALETTE_YUV420P },
  { "YUV410P", VIDEO_PALETTE_YUV410P },
  { "UYVY422", VIDEO_PALETTE_UYVY }
};


BOOL PVideoInputDevice_V4L::Open(const PString & devName, BOOL startImmediate)
{
  struct utsname buf;
  PString version;
  
  uname (&buf);

  if (buf.release)
    version = PString (buf.release);

  Close();
  
  PTRACE(1,"PVideoInputDevice_V4L: trying to open "<< devName);

  // check if it is a userfriendly name, and if so, get the real device name

  PString deviceName = GetNames().GetDeviceName(devName);
  videoFd = ::open((const char *)deviceName, O_RDWR);
  if (videoFd < 0) {
    PTRACE(1,"PVideoInputDevice_V4L::Open failed : "<< ::strerror(errno));
    return FALSE;
  }
  
  // get the device capabilities
  if (::ioctl(videoFd, VIDIOCGCAP, &videoCapability) < 0)  {
    PTRACE(1,"PVideoInputDevice_V4L:: get device capablilities failed : "<< ::strerror(errno));
    ::close (videoFd);
    videoFd = -1;
    return FALSE;
  }
  
  if ((videoCapability.type & VID_TYPE_CAPTURE) == 0) {
    PTRACE(1,"PVideoInputDevice_V4L:: device capablilities reports cannot capture");
    ::close (videoFd);
    videoFd = -1;
    return FALSE;
  }

  hint_index = PARRAYSIZE(driver_hints) - 1;
  PString driver_name(videoCapability.name);  

  // Scan the hint table, looking for regular expression matches with
  // drivers we hold hints for.
  PINDEX tbl;
  for (tbl = 0; tbl < PARRAYSIZE(driver_hints); tbl ++) {
    PRegularExpression regexp;
    regexp.Compile(driver_hints[tbl].name_regexp, PRegularExpression::Extended);

    if (driver_name.FindRegEx(regexp) != P_MAX_INDEX) {
      PTRACE(1,"PVideoInputDevice_V4L::Open: Found driver hints: " << driver_hints[tbl].name);
      PTRACE(1,"PVideoInputDevice_V4L::Open: format: " << driver_hints[tbl].pref_palette);

      if (driver_hints[tbl].version && !version.IsEmpty ()) {
        if (PString (version) < PString (driver_hints[tbl].version)) {
          PTRACE(1,"PVideoInputDevice_V4L::Open: Hints applied because kernel version less than " << driver_hints[tbl].version);
          hint_index = tbl;
          break;
        }
        else {
          PTRACE(1,"PVideoInputDevice_V4L::Open: Hints not applied because kernel version is not less than " << driver_hints[tbl].version);
        }
      }
      else {
        hint_index = tbl;
        break;
      }
    }
  }


  // Force double-buffering with buggy Quickcam driver.
  if (HINT (HINT_FORCE_DBLBUF)) {

#define QC_IOCTLBASE            220
#define VIDIOCQCGCOMPATIBLE     _IOR ('v',QC_IOCTLBASE+10,int)  /* Get enable workaround for bugs, bitfield */
#define VIDIOCQCSCOMPATIBLE     _IOWR('v',QC_IOCTLBASE+10,int)  /* Set enable workaround for bugs, bitfield */

    int reg = 2; /* enable double buffering */
    ::ioctl (videoFd, VIDIOCQCSCOMPATIBLE, &reg);
  }

    
  // set height and width
  frameHeight = PMIN (videoCapability.maxheight, QCIFHeight);
  frameWidth  = PMIN (videoCapability.maxwidth, QCIFWidth);
  

  // Init audio
  struct video_audio videoAudio;
  if (::ioctl(videoFd, VIDIOCGAUDIO, &videoAudio) >= 0 &&
                      (videoAudio.flags & VIDEO_AUDIO_MUTABLE) != 0) {
    videoAudio.flags &= ~VIDEO_AUDIO_MUTE;
    videoAudio.mode = VIDEO_SOUND_MONO;
    ::ioctl(videoFd, VIDIOCSAUDIO, &videoAudio);
    } 

  return TRUE;
}


BOOL PVideoInputDevice_V4L::IsOpen() 
{
  return videoFd >= 0;
}


BOOL PVideoInputDevice_V4L::Close()
{
  if (!IsOpen())
    return FALSE;


  // Mute audio
  struct video_audio videoAudio;
  if (::ioctl(videoFd, VIDIOCGAUDIO, &videoAudio) >= 0 &&
                      (videoAudio.flags & VIDEO_AUDIO_MUTABLE) != 0) {
    videoAudio.flags |= VIDEO_AUDIO_MUTE;
    ::ioctl(videoFd, VIDIOCSAUDIO, &videoAudio);
  }

  ClearMapping();
  ::close(videoFd);

  videoFd = -1;
  canMap  = -1;
  
  return TRUE;
}


BOOL PVideoInputDevice_V4L::Start()
{
  return TRUE;
}


BOOL PVideoInputDevice_V4L::Stop()
{
  return TRUE;
}


BOOL PVideoInputDevice_V4L::IsCapturing()
{
  return IsOpen();
}


PStringList PVideoInputDevice_V4L::GetInputDeviceNames()
{
  return GetNames().GetInputDeviceNames();
}

BOOL PVideoInputDevice_V4L::SetVideoFormat(VideoFormat newFormat)
{
  if (!PVideoDevice::SetVideoFormat(newFormat)) {
    PTRACE(1,"PVideoDevice::SetVideoFormat\t failed");
    return FALSE;
  }

  // The channel and format are both set at the same time with one ioctl().
  // Get the channel information (to check if channel is valid)
  // Note: If the channel is -1, we need to search for the first valid channel
  if (channelNumber == -1) {
    if (!SetChannel(channelNumber)){
      PTRACE(1,"PVideoDevice::Cannot set default channel in SetVideoFormat");
      return FALSE;
    }
  }

  struct video_channel channel;
  channel.channel = channelNumber;
  if (::ioctl(videoFd, VIDIOCGCHAN, &channel) < 0) {
    PTRACE(1,"VideoInputDevice Get Channel info failed : "<< ::strerror(errno));    
    return FALSE;
  }
  
  // set channel information
  static int fmt[4] = { VIDEO_MODE_PAL, VIDEO_MODE_NTSC, 
                          VIDEO_MODE_SECAM, VIDEO_MODE_AUTO };
  channel.norm = fmt[newFormat];

  // set the information
  if (::ioctl(videoFd, VIDIOCSCHAN, &channel) >= 0)
    return TRUE;

  PTRACE(1,"VideoInputDevice SetChannel failed : "<< ::strerror(errno));  

  if (newFormat != Auto)
    return FALSE;

  if (SetVideoFormat(PAL))
    return TRUE;
  if (SetVideoFormat(NTSC))
    return TRUE;
  if (SetVideoFormat(SECAM))
    return TRUE;

  return FALSE;
}


int PVideoInputDevice_V4L::GetNumChannels() 
{
  /* If Opened, return the capability value, else 1 as in videoio.cxx */
  if (IsOpen ())
    return videoCapability.channels;
  else
    return 1;
}


BOOL PVideoInputDevice_V4L::SetChannel(int newChannel)
{
  if (!PVideoDevice::SetChannel(newChannel))
    return FALSE;

  // get channel information (to check if channel is valid)
  struct video_channel channel;
  channel.channel = channelNumber;
  if (::ioctl(videoFd, VIDIOCGCHAN, &channel) < 0) {
    PTRACE(1,"VideoInputDevice:: Get info on channel " << channelNumber << " failed : "<< ::strerror(errno));    
    return FALSE;
  }
  
  // set channel information
  channel.channel = channelNumber;

  // set the information
  if (::ioctl(videoFd, VIDIOCSCHAN, &channel) < 0) {
    PTRACE(1,"VideoInputDevice:: Set info on channel " << channelNumber << " failed : "<< ::strerror(errno));    
    return FALSE;
  }
  
  return TRUE;
}


BOOL PVideoInputDevice_V4L::SetVideoChannelFormat (int newNumber, VideoFormat videoFormat) 
{
  if (!PVideoDevice::SetChannel(newNumber))
    return FALSE;

  if (!PVideoDevice::SetVideoFormat(videoFormat)) {
    PTRACE(1,"PVideoDevice::SetVideoFormat\t failed");
    return FALSE;
  }

  static int fmt[4] = { VIDEO_MODE_PAL, VIDEO_MODE_NTSC, 
                          VIDEO_MODE_SECAM, VIDEO_MODE_AUTO };

  // select the specified input and video format
  // get channel information (to check if channel is valid)
  struct video_channel channel;
  channel.channel = channelNumber;
  if (::ioctl(videoFd, VIDIOCGCHAN, &channel) < 0) {
    PTRACE(1,"VideoInputDevice Get Channel info failed : "<< ::strerror(errno));    

    return FALSE;
  }
  
  // set channel information
  channel.norm = fmt[videoFormat];
  channel.channel = channelNumber;

  // set the information
  if (::ioctl(videoFd, VIDIOCSCHAN, &channel) < 0) {
    PTRACE(1,"VideoInputDevice SetChannel failed : "<< ::strerror(errno));  

    return FALSE;
  }

  return TRUE;
}

BOOL PVideoInputDevice_V4L::SetColourFormat(const PString & newFormat)
{
  PINDEX colourFormatIndex = 0;
  while (newFormat != colourFormatTab[colourFormatIndex].colourFormat) {
    colourFormatIndex++;
    if (colourFormatIndex >= PARRAYSIZE(colourFormatTab))
      return FALSE;
  }

  if (!PVideoDevice::SetColourFormat(newFormat))
    return FALSE;

  ClearMapping();

  // get current picture information
  struct video_picture pictureInfo;
  if (::ioctl(videoFd, VIDIOCGPICT, &pictureInfo) < 0) {
    PTRACE(1,"PVideoInputDevice_V4L::Get pict info failed : "<< ::strerror(errno));
    return FALSE;
  }
  
  // set colour format
  colourFormatCode = colourFormatTab[colourFormatIndex].code;
  pictureInfo.palette = colourFormatCode;
  if (HINT (HINT_FORCE_DEPTH_16))
    pictureInfo.depth = 16;

  // set the information
  if (::ioctl(videoFd, VIDIOCSPICT, &pictureInfo) < 0) {
    PTRACE(1,"PVideoInputDevice_V4L::Set pict info failed : "<< ::strerror(errno));
    PTRACE(1,"PVideoInputDevice_V4L:: used code of "<<colourFormatCode);
    PTRACE(1,"PVideoInputDevice_V4L:: palette: "<<colourFormatTab[colourFormatIndex].colourFormat);
    return FALSE;
  }
  

  // Driver only (and always) manages to set the colour format  with call to VIDIOCSPICT.
  if( (HINT(HINT_ONLY_WORKS_PREF_PALETTE) ) &&                   
      ( colourFormatCode == driver_hints[hint_index].pref_palette) ) {
    PTRACE(3,"PVideoInputDevice_V4L:: SetColourFormat succeeded with "<<newFormat);
    return TRUE;
  }

  // Some drivers always return success for CSPICT, and can't
  // read the current palette back in CGPICT.  We can't do much
  // more than just check to see if there is a preferred palette,
  // and fail if the request isn't the preferred palette.
  
  if (HINT(HINT_CSPICT_ALWAYS_WORKS) &&
      HINT(HINT_CGPICT_DOESNT_SET_PALETTE) &&
      HINT(HINT_HAS_PREF_PALETTE)) {
      if (colourFormatCode != driver_hints[hint_index].pref_palette)
        return FALSE;
  }

  // Some V4L drivers can't use CGPICT to check for errors.
  if (!HINT(HINT_CGPICT_DOESNT_SET_PALETTE)) {
    if (::ioctl(videoFd, VIDIOCGPICT, &pictureInfo) < 0) {
      PTRACE(1,"PVideoInputDevice_V4L::Get pict info failed : "<< ::strerror(errno));
      return FALSE;
    }
    
    if (pictureInfo.palette != colourFormatCode)
      return FALSE;
  }
  
  // set the new information
  return SetFrameSizeConverter(frameWidth, frameHeight, FALSE);
}


BOOL PVideoInputDevice_V4L::SetFrameRate(unsigned rate)
{
  if (!PVideoDevice::SetFrameRate(rate))
    return FALSE;

  return TRUE;
}


BOOL PVideoInputDevice_V4L::GetFrameSizeLimits(unsigned & minWidth,
                                           unsigned & minHeight,
                                           unsigned & maxWidth,
                                           unsigned & maxHeight) 
{
  if (!IsOpen())
    return FALSE;

  if(HINT(HINT_FORCE_LARGE_SIZE)) {
    videoCapability.maxheight = 288;
    videoCapability.maxwidth  = 352;
    videoCapability.minheight = 288;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -