Hello *, I just ported the "friendly-name" device detection from the V4L plugin to V4L2. Here are the patch and the additional files needed by the V4L2 new plugin. You should put the new files in the V4L2 plugins/vidinput_v4l2/ plugin directory. Some notes: 1) The additional files define a common class (V4LXNames) that can be used by both the V4L and V4L2 plugins, to avoid code redundancy. It should be placed in a "library" directory (where?) and linked against the plugins. I didn't touch the original V4L plugin code, so it's up to you to decide whether doing the link or not. It requires just 15 minutes of refactoring. 2) The device detection does not freeze anymore, but fails if invoked when the capture device is open. My camera driver seems not to allow opening the same device twice, even with a O_NONBLOCK call. 3) I am trying to use only one mmaped buffer changing its initialization part, without touching the remaining code. Could you please test that on some different cameras (I don't think it is the smartest idea ever, but maybe this is the only workaround for slick's camera). Test, test, test! And let me know. -- Ciao, Nigu ------------------------------------------------------------------ * Nicola Orru' - 49, Rocky Lane - L6 4BA Anfield, Liverpool - UK * ------------------------------------------------------------------
#ifndef _VIDINPUTNAMES_H #define _VIDINPUTNAMES_H #include <ptlib.h> #include <ptlib/videoio.h> #ifndef MAJOR #define MAJOR(a) (int)((unsigned short) (a) >> 8) #endif #ifndef MINOR #define MINOR(a) (int)((unsigned short) (a) & 0xFF) #endif class V4LXNames : public PObject { PCLASSINFO(V4LXNames, PObject); public: V4LXNames() {/* nothing */}; virtual void Update () = 0; PString GetUserFriendly(PString devName); PString GetDeviceName(PString userName); PStringList GetInputDeviceNames(); protected: void AddUserDeviceName(PString userName, PString devName); virtual PString BuildUserFriendly(PString devname) = 0; void PopulateDictionary(); void ReadDeviceDirectory(PDirectory devdir, POrdinalToString & vid); PMutex mutex; PStringToString deviceKey; PStringToString userKey; PStringList inputDeviceNames; }; #endif
#include "vidinput_names.h" void V4LXNames::ReadDeviceDirectory(PDirectory devdir, POrdinalToString & vid) { if (!devdir.Open()) return; do { PString filename = devdir.GetEntryName(); PString devname = devdir + filename; if (devdir.IsSubDir()) ReadDeviceDirectory(devname, vid); else { PFileInfo info; if (devdir.GetInfo(info) && info.type == PFileInfo::CharDevice) { struct stat s; if (lstat(devname, &s) == 0) { static const int deviceNumbers[] = { 81 }; for (PINDEX i = 0; i < PARRAYSIZE(deviceNumbers); i++) { if (MAJOR(s.st_rdev) == deviceNumbers[i]) { PINDEX num = MINOR(s.st_rdev); if (num <= 63 && num >= 0) { vid.SetAt(num, devname); } } } } } } } while (devdir.Next()); } void V4LXNames::PopulateDictionary() { PINDEX i, j; PStringToString tempList; for (i = 0; i < inputDeviceNames.GetSize(); i++) { PString ufname = BuildUserFriendly(inputDeviceNames[i]); tempList.SetAt(inputDeviceNames[i], ufname); } //Now, we need to cope with the case where there are two video //devices available, which both have the same user friendly name. //Matching user friendly names have a (X) appended to the name. for (i = 0; i < tempList.GetSize(); i++) { PString userName = tempList.GetDataAt(i); PINDEX matches = 1; for (j = i + 1; j < tempList.GetSize(); j++) { if (tempList.GetDataAt(j) == userName) { matches++; PStringStream revisedUserName; revisedUserName << userName << " (" << matches << ")"; 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 V4LXNames::GetUserFriendly(PString devName) { PWaitAndSignal m(mutex); PString result= deviceKey(devName); if (result.IsEmpty()) return devName; return result; } PString V4LXNames::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 V4LXNames::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 } } /* There is a duplication in the list of names. Consequently, opening the device as "ov511++" or "/dev/video0" will work. */ PStringList V4LXNames::GetInputDeviceNames() { PWaitAndSignal m(mutex); PStringList result; for (PINDEX i = 0; i < inputDeviceNames.GetSize(); i++) { result += GetUserFriendly (inputDeviceNames[i]); result += inputDeviceNames[i]; } return result; }
Attachment:
patch_nigu_20041106_1.diff.gz
Description: Binary data
Attachment:
pgpsMG8BG9AJC.pgp
Description: PGP signature