diff --git a/src/add-ons/media/media-add-ons/usb_webcam/AddOn.cpp b/src/add-ons/media/media-add-ons/usb_webcam/AddOn.cpp new file mode 100644 index 0000000000..5a8ca3db5f --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/AddOn.cpp @@ -0,0 +1,179 @@ +#include +#include + +#include +#include +#include + +#include "AddOn.h" +#include "Producer.h" +#include "CamRoster.h" +#include "CamDebug.h" +#include "CamDevice.h" + +WebCamMediaAddOn::WebCamMediaAddOn(image_id imid) + : BMediaAddOn(imid), + fInitStatus(B_NO_INIT), + fRoster(NULL) +{ + PRINT((CH "()" CT)); + /* Customize these parameters to match those of your node */ + fMediaFormat.type = B_MEDIA_RAW_VIDEO; + fMediaFormat.u.raw_video = media_raw_video_format::wildcard; + fMediaFormat.u.raw_video.interlace = 1; + fMediaFormat.u.raw_video.display.format = B_RGB32; + FillDefaultFlavorInfo(&fDefaultFlavorInfo); + + fRoster = new CamRoster(this); + fRoster->Start(); +// if( fRoster->CountCameras() < 1 ) +/* fInitStatus = B_ERROR; + else +*/ + fInitStatus = B_OK; +} + +WebCamMediaAddOn::~WebCamMediaAddOn() +{ + delete fRoster; +} + + +status_t +WebCamMediaAddOn::InitCheck(const char **out_failure_text) +{ + if (fInitStatus < B_OK) { + *out_failure_text = "No cameras attached"; + return fInitStatus; + } + + return B_OK; +} + +int32 +WebCamMediaAddOn::CountFlavors() +{ + PRINT((CH "()" CT)); + int32 count; + if (!fRoster) + return B_NO_INIT; + if (fInitStatus < B_OK) + return fInitStatus; + + /* This addon only supports a single flavor, as defined in the + * constructor */ + count = fRoster->CountCameras(); + return count;//(count > 0)?count:1;//1; +} + +/* + * The pointer to the flavor received only needs to be valid between + * successive calls to BMediaAddOn::GetFlavorAt(). + */ +status_t +WebCamMediaAddOn::GetFlavorAt(int32 n, const flavor_info **out_info) +{ + PRINT((CH "(%d, ) roster %p is %lx" CT, n, fRoster, fInitStatus)); + int32 count; + CamDevice* cam; + if (!fRoster) + return B_NO_INIT; + if (fInitStatus < B_OK) + return fInitStatus; + + count = fRoster->CountCameras(); + PRINT((CH ": %d cameras" CT, count)); + if (n >= count)//(n != 0) + return B_BAD_INDEX; + + fRoster->Lock(); + cam = fRoster->CameraAt(n); + *out_info = &fDefaultFlavorInfo; + if (cam && cam->FlavorInfo()) + *out_info = cam->FlavorInfo(); + fRoster->Unlock(); + PRINT((CH ": returning flavor for %d" CT, n)); + return B_OK; +} + +BMediaNode * +WebCamMediaAddOn::InstantiateNodeFor( + const flavor_info *info, BMessage* /*_config*/, status_t* /*_out_error*/) +{ + PRINT((CH "()" CT)); + VideoProducer *node; + CamDevice *cam=NULL; + + if (fInitStatus < B_OK) + return NULL; + + fRoster->Lock(); + for (int i = 0; i < fRoster->CountCameras(); i++) { + CamDevice *c; + c = fRoster->CameraAt(i); + PRINT((CH ": cam[%d]: %d, %s" CT, i, c->FlavorInfo()->internal_id, c->BrandName())); + if (c && (c->FlavorInfo()->internal_id == info->internal_id)) { + cam = c; + break; + } + } + fRoster->Unlock(); + if (!cam) + return NULL; + +#if 0 + fRoster->Lock(); + cam = fRoster->CameraAt(n); + *out_info = &fDefaultFlavorInfo; + if (cam && cam->FlavorInfo()) + *out_info = cam->FlavorInfo(); + fRoster->Unlock(); +#endif + /* At most one instance of the node should be instantiated at any given + * time. The locking for this restriction may be found in the VideoProducer + * class. */ + node = new VideoProducer(this, cam, cam->FlavorInfo()->name, fDefaultFlavorInfo.internal_id); + if (node && (node->InitCheck() < B_OK)) { + delete node; + node = NULL; + } + + return node; +} + +status_t +WebCamMediaAddOn::CameraAdded(CamDevice* device) +{ + PRINT((CH "()" CT)); + NotifyFlavorChange(); +} + +status_t +WebCamMediaAddOn::CameraRemoved(CamDevice* device) +{ + PRINT((CH "()" CT)); + NotifyFlavorChange(); +} + +void +WebCamMediaAddOn::FillDefaultFlavorInfo(flavor_info* info) +{ + info->name = "USB Web Camera"; + info->info = "USB Web Camera"; + info->kinds = B_BUFFER_PRODUCER | B_CONTROLLABLE | B_PHYSICAL_INPUT; + info->flavor_flags = 0;//B_FLAVOR_IS_GLOBAL; + info->internal_id = atomic_add((vint32 *)&fInternalIDCounter, 1); + info->possible_count = 1;//0; + info->in_format_count = 0; + info->in_format_flags = 0; + info->in_formats = NULL; + info->out_format_count = 1; + info->out_format_flags = 0; + info->out_formats = &fMediaFormat; +} + +BMediaAddOn * +make_media_addon(image_id imid) +{ + return new WebCamMediaAddOn(imid); +} diff --git a/src/add-ons/media/media-add-ons/usb_webcam/AddOn.h b/src/add-ons/media/media-add-ons/usb_webcam/AddOn.h new file mode 100644 index 0000000000..8bd5b98d09 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/AddOn.h @@ -0,0 +1,52 @@ +#ifndef _VIDEO_ADDON_H +#define _VIDEO_ADDON_H + +#include + +#define TOUCH(x) ((void)(x)) + +extern "C" _EXPORT BMediaAddOn *make_media_addon(image_id you); + +class CamRoster; +class CamDevice; + +class WebCamMediaAddOn : public BMediaAddOn +{ +public: + WebCamMediaAddOn(image_id imid); + virtual ~WebCamMediaAddOn(); + + virtual status_t InitCheck(const char **out_failure_text); + + virtual int32 CountFlavors(); + virtual status_t GetFlavorAt(int32 n, const flavor_info ** out_info); + virtual BMediaNode *InstantiateNodeFor( + const flavor_info * info, + BMessage * config, + status_t * out_error); + + virtual status_t GetConfigurationFor(BMediaNode *node, BMessage *message) + { TOUCH(node); TOUCH(message); return B_OK; } + virtual status_t SaveConfigInfo(BMediaNode *node, BMessage *message) + { TOUCH(node); TOUCH(message); return B_OK; } + + virtual bool WantsAutoStart() { return false; } + virtual status_t AutoStart(int in_count, BMediaNode **out_node, + int32 *out_internal_id, bool *out_has_more) + { TOUCH(in_count); TOUCH(out_node); + TOUCH(out_internal_id); TOUCH(out_has_more); + return B_ERROR; } + // those are for use by CamDevices + status_t CameraAdded(CamDevice* device); + status_t CameraRemoved(CamDevice* device); + void FillDefaultFlavorInfo(flavor_info* info); + +private: + uint32 fInternalIDCounter; + status_t fInitStatus; + flavor_info fDefaultFlavorInfo; + media_format fMediaFormat; + CamRoster* fRoster; +}; + +#endif diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamBufferedFilterInterface.cpp b/src/add-ons/media/media-add-ons/usb_webcam/CamBufferedFilterInterface.cpp new file mode 100644 index 0000000000..5c63aa5368 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamBufferedFilterInterface.cpp @@ -0,0 +1,87 @@ +#include "CamBufferedFilterInterface.h" +#include "CamDevice.h" +#include "CamDebug.h" + +CamBufferedFilterInterface::CamBufferedFilterInterface(CamDevice *device, bool allowWrite) +: CamFilterInterface(device), +fAllowWrite(allowWrite) +{ +} + +CamBufferedFilterInterface::~CamBufferedFilterInterface() +{ +} + +ssize_t +CamBufferedFilterInterface::Read(void *buffer, size_t size) +{ + return fInternalBuffer.Read(buffer, size); +} + +ssize_t +CamBufferedFilterInterface::ReadAt(off_t pos, void *buffer, size_t size) +{ + return fInternalBuffer.ReadAt(pos, buffer, size); +} + +ssize_t +CamBufferedFilterInterface::Write(const void *buffer, size_t size) +{ + if (!fAllowWrite) + return B_READ_ONLY_DEVICE; + return fInternalBuffer.Write(buffer, size); +} + +ssize_t +CamBufferedFilterInterface::WriteAt(off_t pos, const void *buffer, size_t size) +{ + if (!fAllowWrite) + return B_READ_ONLY_DEVICE; + return fInternalBuffer.WriteAt(pos, buffer, size); +} + +off_t +CamBufferedFilterInterface::Seek(off_t position, uint32 seek_mode) +{ + return fInternalBuffer.Seek(position, seek_mode); +} + +off_t +CamBufferedFilterInterface::Position() const +{ + return fInternalBuffer.Position(); +} + +status_t +CamBufferedFilterInterface::SetSize(off_t size) +{ + if (!fAllowWrite) + return B_READ_ONLY_DEVICE; + return fInternalBuffer.SetSize(size); +} + +size_t +CamBufferedFilterInterface::FrameSize() +{ + return fInternalBuffer.BufferLength(); // XXX: really ?? + return 0; +} + +status_t +CamBufferedFilterInterface::DropFrame() +{ + fInternalBuffer.SetSize(0LL); + if (fNextOfKin) + return fNextOfKin->DropFrame(); + return B_OK; +} + +status_t +CamBufferedFilterInterface::SetVideoFrame(BRect frame) +{ + fVideoFrame = frame; + fInternalBuffer.SetSize(FrameSize()); // XXX: really ?? + if (fNextOfKin) + return fNextOfKin->SetVideoFrame(frame); + return B_OK; +} diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamBufferedFilterInterface.h b/src/add-ons/media/media-add-ons/usb_webcam/CamBufferedFilterInterface.h new file mode 100644 index 0000000000..c600fdfae0 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamBufferedFilterInterface.h @@ -0,0 +1,40 @@ +#ifndef _CAM_BUFFERED_FILTER_INTERFACE_H +#define _CAM_BUFFERED_FILTER_INTERFACE_H + +#include +#include +#include +#include "CamFilterInterface.h" + +class CamBufferedFilterInterface : public CamFilterInterface +{ +public: + CamBufferedFilterInterface(CamDevice *device, bool allowWrite); +virtual ~CamBufferedFilterInterface(); + + // BPositionIO interface +virtual ssize_t Read(void *buffer, size_t size); +virtual ssize_t ReadAt(off_t pos, void *buffer, size_t size); + +virtual ssize_t Write(const void *buffer, size_t size); +virtual ssize_t WriteAt(off_t pos, const void *buffer, size_t size); + +virtual off_t Seek(off_t position, uint32 seek_mode); +virtual off_t Position() const; +virtual status_t SetSize(off_t size); + // size of the buffer required for reading a whole frame +virtual size_t FrameSize(); + + // frame handling +virtual status_t DropFrame(); + // video settings propagation +virtual status_t SetVideoFrame(BRect frame); + + +protected: +bool fAllowWrite; +BMallocIO fInternalBuffer; +}; + + +#endif /* _CAM_BUFFERED_FILTER_INTERFACE_H */ diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamBufferingDeframer.cpp b/src/add-ons/media/media-add-ons/usb_webcam/CamBufferingDeframer.cpp new file mode 100644 index 0000000000..1daa97d84c --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamBufferingDeframer.cpp @@ -0,0 +1,120 @@ +/* + * buffer based deframer + * buffers all packet until it finds a complete frame. + * simpler than StreamingDeframer, but doesn't work any better + * and hogs the cpu intermitently :^) + */ + +#define CD_COL "31" +#include "CamBufferingDeframer.h" +#include "CamDevice.h" +#include "CamDebug.h" +#include +#define MAX_TAG_LEN CAMDEFRAMER_MAX_TAG_LEN +#define MAXFRAMEBUF CAMDEFRAMER_MAX_QUEUED_FRAMES + +#define IB fInputBuffs[fInputBuffIndex] + +CamBufferingDeframer::CamBufferingDeframer(CamDevice *device) +: CamDeframer(device), +fInputBuffIndex(0) +{ +} + +CamBufferingDeframer::~CamBufferingDeframer() +{ +} + +ssize_t +CamBufferingDeframer::Write(const void *buffer, size_t size) +{ + uint8 *b; + int l; + int i, s, e; + int which; + fMinFrameSize = fDevice->MinRawFrameSize(); + fMaxFrameSize = fDevice->MaxRawFrameSize(); + IB.Write(buffer, size); + b = (uint8 *)IB.Buffer(); + l = IB.BufferLength(); + + PRINT((CH "(%p, %d), IB: %d" CT, buffer, size, IB.BufferLength())); + + if (l < fMinFrameSize + fSkipSOFTags + fSkipEOFTags) + return size; // not enough data anyway + + if (!fCurrentFrame) { + BAutolock l(fLocker); + if (fFrames.CountItems() < MAXFRAMEBUF) + fCurrentFrame = AllocFrame(); + else { + PRINT((CH "DROPPED %d bytes! (too many queued frames)" CT, size)); + return size; // drop XXX + } + } + + for (s = 0; (l - s > fMinFrameSize) && ((i = FindSOF(b + s, l - fMinFrameSize - s, &which)) > -1); s++) { + s += i; + if (s + fSkipSOFTags + fMinFrameSize + fSkipEOFTags > l) + break; + if (!fDevice->ValidateStartOfFrameTag(b + s, fSkipSOFTags)) + continue; + + PRINT((CH ": SOF[%d] at offset %d" CT, which, s)); + PRINT((CH ": SOF: ... %02x %02x %02x %02x %02x %02x" CT, b[s+6], b[s+7], b[s+8], b[s+9], b[s+10], b[s+11])); + + for (e = s + fSkipSOFTags + fMinFrameSize; + ((e <= s + fSkipSOFTags + fMaxFrameSize) && + (e < l) && ((i = 0*FindEOF(b + e, l - e, &which)) > -1)); + e++) { + e += i; + + //PRINT((CH ": EOF[%d] at offset %d" CT, which, s)); + if (!fDevice->ValidateEndOfFrameTag(b + e, fSkipEOFTags, e - s - fSkipSOFTags)) + continue; + + + + PRINT((CH ": SOF= ... %02x %02x %02x %02x %02x %02x" CT, b[s+6], b[s+7], b[s+8], b[s+9], b[s+10], b[s+11])); + + // we have one! + s += fSkipSOFTags; + + // fill it + fCurrentFrame->Write(b + s, e - s); + + // queue it + BAutolock f(fLocker); + PRINT((CH ": Detaching a frame (%d bytes, %d to %d / %d)" CT, (size_t)fCurrentFrame->Position(), s, e, l)); + fCurrentFrame->Seek(0LL, SEEK_SET); + fFrames.AddItem(fCurrentFrame); + release_sem(fFrameSem); + // next Write() will allocate a new one + fCurrentFrame = NULL; + // discard the frame and everything before it. + DiscardFromInput(e + fSkipEOFTags); + + return size; + } + } + return size; +} + +size_t +CamBufferingDeframer::DiscardFromInput(size_t size) +{ + int next = (fInputBuffIndex+1)%2; + PRINT((CH ": %d bytes of %d from buffs[%d] (%d left)" CT, size, IB.BufferLength(), fInputBuffIndex, IB.BufferLength() - size)); + fInputBuffs[next].Seek(0LL, SEEK_SET); + fInputBuffs[next].SetSize(0); + uint8 *buff = (uint8 *)IB.Buffer(); + if (IB.BufferLength() > size) { + buff += size; + fInputBuffs[next].Write(buff, IB.BufferLength() - size); + } + IB.Seek(0LL, SEEK_SET); + IB.SetSize(0); + fInputBuffIndex = next; + +} + diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamBufferingDeframer.h b/src/add-ons/media/media-add-ons/usb_webcam/CamBufferingDeframer.h new file mode 100644 index 0000000000..609595dd71 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamBufferingDeframer.h @@ -0,0 +1,25 @@ +#ifndef _CAM_BUFFERING_DEFRAMER_H +#define _CAM_BUFFERING_DEFRAMER_H + +#include "CamDeframer.h" + +class CamBufferingDeframer : public CamDeframer +{ +public: + CamBufferingDeframer(CamDevice *device); +virtual ~CamBufferingDeframer(); + // BPositionIO interface + // write from usb transfers +virtual ssize_t Write(const void *buffer, size_t size); +size_t DiscardFromInput(size_t size); + +private: + +BMallocIO fInputBuffs[2]; +int fInputBuffIndex; + + +}; + + +#endif /* _CAM_BUFFERING_DEFRAMER_H */ diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamColorSpaceTransform.cpp b/src/add-ons/media/media-add-ons/usb_webcam/CamColorSpaceTransform.cpp new file mode 100644 index 0000000000..1272a4893d --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamColorSpaceTransform.cpp @@ -0,0 +1,74 @@ +#include "CamColorSpaceTransform.h" +#include "CamDebug.h" + +/* I should replace this by a generic colorspace TranslatorAddOn... */ + +#undef B_WEBCAM_DECLARE_CSTRANSFORM +#define B_WEBCAM_DECLARE_CSTRANSFORM(trclass,trname) \ +extern "C" CamColorSpaceTransform *Instantiate##trclass(); +#include "CamInternalColorSpaceTransforms.h" +#undef B_WEBCAM_DECLARE_CSTRANSFORM +typedef CamColorSpaceTransform *(*TransformInstFunc)(); +struct { const char *name; TransformInstFunc instfunc; } kTransformTable[] = { +#define B_WEBCAM_DECLARE_CSTRANSFORM(trclass,trname) \ +{ #trname, &Instantiate##trclass }, +#include "CamInternalColorSpaceTransforms.h" +{ NULL, NULL }, +}; +#undef B_WEBCAM_DECLARE_CSTRANSFORM + +// ----------------------------------------------------------------------------- +CamColorSpaceTransform::CamColorSpaceTransform() + : fInitStatus(B_NO_INIT), + fVideoFrame() +{ + +} + +// ----------------------------------------------------------------------------- +CamColorSpaceTransform::~CamColorSpaceTransform() +{ + +} + +// ----------------------------------------------------------------------------- +status_t +CamColorSpaceTransform::InitCheck() +{ + return fInitStatus; +} + +// ----------------------------------------------------------------------------- +const char * +CamColorSpaceTransform::Name() +{ + return ""; +} + +// ----------------------------------------------------------------------------- +color_space +CamColorSpaceTransform::OutputSpace() +{ + return B_RGB32; +} + +// ----------------------------------------------------------------------------- +status_t +CamColorSpaceTransform::SetVideoFrame(BRect rect) +{ + return ENOSYS; +} + +// ----------------------------------------------------------------------------- +CamColorSpaceTransform * +CamColorSpaceTransform::Create(const char *name) +{ + int i; + for (i = 0; kTransformTable[i].name; i++) { + if (!strcmp(kTransformTable[i].name, name)) + return kTransformTable[i].instfunc(); + } + return NULL; +} + + diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamColorSpaceTransform.h b/src/add-ons/media/media-add-ons/usb_webcam/CamColorSpaceTransform.h new file mode 100644 index 0000000000..a1c583e5ac --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamColorSpaceTransform.h @@ -0,0 +1,37 @@ +#ifndef _CAM_COLOR_SPACE_TRANSFORM_H +#define _CAM_COLOR_SPACE_TRANSFORM_H + +#include "CamDevice.h" +#include + +// This class represents the camera's (cmos or whatever) sensor chip +class CamColorSpaceTransform +{ + public: + CamColorSpaceTransform(); + virtual ~CamColorSpaceTransform(); + + virtual status_t InitCheck(); + + virtual const char* Name(); + virtual color_space OutputSpace(); + + virtual status_t SetVideoFrame(BRect rect); + virtual BRect VideoFrame() const { return fVideoFrame; }; + + static CamColorSpaceTransform *Create(const char *name); + + protected: + status_t fInitStatus; + BRect fVideoFrame; + private: +}; + +// internal modules +#define B_WEBCAM_DECLARE_CSTRANSFORM(trclass,trname) \ +extern "C" CamColorSpaceTransform *Instantiate##trclass(); \ +CamColorSpaceTransform *Instantiate##trclass() \ +{ return new trclass(); }; + + +#endif /* _CAM_COLOR_SPACE_TRANSFORM_H */ diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamDebug.h b/src/add-ons/media/media-add-ons/usb_webcam/CamDebug.h new file mode 100644 index 0000000000..be4ca3e0ab --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamDebug.h @@ -0,0 +1,14 @@ +#ifndef _CAM_DEBUG_H +#define _CAM_DEBUG_H + +#include + +/* allow overriding ANSI color */ +#ifndef CD_COL +#define CD_COL "34" +#endif + +#define CH "\033[" CD_COL "mWebcam::%s::%s" +#define CT "\033[0m\n", __FILE__, __FUNCTION__ + +#endif diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamDeframer.cpp b/src/add-ons/media/media-add-ons/usb_webcam/CamDeframer.cpp new file mode 100644 index 0000000000..8b937a16de --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamDeframer.cpp @@ -0,0 +1,194 @@ +#define CD_COL "31" +#include "CamDeframer.h" +#include "CamDevice.h" +#include "CamDebug.h" +#include +#define MAX_TAG_LEN CAMDEFRAMER_MAX_TAG_LEN +#define MAXFRAMEBUF CAMDEFRAMER_MAX_QUEUED_FRAMES + +CamDeframer::CamDeframer(CamDevice *device) +: CamFilterInterface(device), +fDevice(device), +fState(ST_SYNC), +fFrameSem(B_ERROR), +fLocker("CamDeframer Framelist lock", true), +fNumSOFTags(0), +fNumEOFTags(0) +{ + fMinFrameSize = fDevice->MinRawFrameSize(); + fMaxFrameSize = fDevice->MaxRawFrameSize(); + fFrameSem = create_sem(0, "CamDeframer sem"); + fCurrentFrame = AllocFrame(); +} + +CamDeframer::~CamDeframer() +{ + delete_sem(fFrameSem); + BAutolock l(fLocker); + delete fCurrentFrame; +} + +ssize_t +CamDeframer::Read(void *buffer, size_t size) +{ + BAutolock l(fLocker); + CamFrame *f = (CamFrame *)fFrames.ItemAt(0); + if (!f) + return EIO; + return f->Read(buffer, size); +} + +ssize_t +CamDeframer::ReadAt(off_t pos, void *buffer, size_t size) +{ + BAutolock l(fLocker); + CamFrame *f = (CamFrame *)fFrames.ItemAt(0); + if (!f) + return EIO; + return f->ReadAt(pos, buffer, size); +} + +off_t +CamDeframer::Seek(off_t position, uint32 seek_mode) +{ + BAutolock l(fLocker); + CamFrame *f = (CamFrame *)fFrames.ItemAt(0); + if (!f) + return EIO; + return f->Seek(position, seek_mode); +} + +off_t +CamDeframer::Position() const +{ + BAutolock l((BLocker &)fLocker); // need to get rid of const here + CamFrame *f = (CamFrame *)fFrames.ItemAt(0); + if (!f) + return EIO; + return f->Position(); +} + +status_t +CamDeframer::SetSize(off_t size) +{ + (void)size; + return EINVAL; +} + +ssize_t +CamDeframer::Write(const void *buffer, size_t size) +{ + (void)buffer; + (void)size; + return EINVAL; +} + +ssize_t +CamDeframer::WriteAt(off_t pos, const void *buffer, size_t size) +{ + (void)pos; + (void)buffer; + (void)size; + return EINVAL; +} + +status_t +CamDeframer::WaitFrame(bigtime_t timeout) +{ + return acquire_sem_etc(fFrameSem, 1, B_RELATIVE_TIMEOUT, timeout); +} + +status_t +CamDeframer::GetFrame(CamFrame **frame, bigtime_t *stamp) +{ + status_t err = EINTR; + PRINT((CH "()" CT)); + BAutolock l(fLocker); + CamFrame *f = (CamFrame *)fFrames.RemoveItem((int32)0); + if (!f) + return ENOENT; + *frame = f; + *stamp = 0LL; + return B_OK; +} + +status_t +CamDeframer::DropFrame() +{ + status_t err = EINTR; + PRINT((CH "()" CT)); + BAutolock l(fLocker); + CamFrame *f = (CamFrame *)fFrames.RemoveItem((int32)0); + if (!f) + return ENOENT; + delete f; + return B_OK; +} + +status_t +CamDeframer::RegisterSOFTags(const uint8 **tags, int count, size_t len, size_t skip) +{ + if (fSOFTags) + return EALREADY; + if (len > MAX_TAG_LEN) + return EINVAL; + if (count > 16) + return EINVAL; + fSOFTags = tags; + fNumSOFTags = count; + fLenSOFTags = len; + fSkipSOFTags = skip; + return B_OK; +} + +status_t +CamDeframer::RegisterEOFTags(const uint8 **tags, int count, size_t len, size_t skip) +{ + if (fEOFTags) + return EALREADY; + if (len > MAX_TAG_LEN) + return EINVAL; + if (count > 16) + return EINVAL; + fEOFTags = tags; + fNumEOFTags = count; + fLenEOFTags = len; + fSkipEOFTags = skip; + return B_OK; +} + +int +CamDeframer::FindTags(const uint8 *buf, size_t buflen, const uint8 **tags, int tagcount, size_t taglen, size_t skiplen, int *which) +{ + int i, t; + for (i = 0; i < buflen - skiplen + 1; i++) { + for (t = 0; t < tagcount; t++) { + if (!memcmp(buf+i, tags[t], taglen)) { + if (which) + *which = t; + return i; + } + } + } + return -1; +} + +int +CamDeframer::FindSOF(const uint8 *buf, size_t buflen, int *which) +{ + return FindTags(buf, buflen, fSOFTags, fNumSOFTags, fLenSOFTags, fSkipSOFTags, which); +} + +int +CamDeframer::FindEOF(const uint8 *buf, size_t buflen, int *which) +{ + return FindTags(buf, buflen, fEOFTags, fNumEOFTags, fLenEOFTags, fSkipEOFTags, which); +} + +CamFrame * +CamDeframer::AllocFrame() +{ + return new CamFrame(); +} + + diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamDeframer.h b/src/add-ons/media/media-add-ons/usb_webcam/CamDeframer.h new file mode 100644 index 0000000000..7c160d058c --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamDeframer.h @@ -0,0 +1,78 @@ +#ifndef _CAM_DEFRAMER_H +#define _CAM_DEFRAMER_H + +#include +#include +#include +#include +#include "CamFilterInterface.h" +class CamDevice; + +#define CAMDEFRAMER_MAX_TAG_LEN 16 +#define CAMDEFRAMER_MAX_QUEUED_FRAMES 50 + +enum { +ST_SYNC, /* waiting for start of frame */ +ST_FRAME +}; + + +/* should have a real Frame class someday */ +#define CamFrame BMallocIO + +class CamDeframer : public CamFilterInterface +{ +public: + CamDeframer(CamDevice *device); +virtual ~CamDeframer(); + // BPositionIO interface + // read from translators/cs transforms +virtual ssize_t Read(void *buffer, size_t size); +virtual ssize_t ReadAt(off_t pos, void *buffer, size_t size); +virtual off_t Seek(off_t position, uint32 seek_mode); +virtual off_t Position() const; +virtual status_t SetSize(off_t size); + // write from usb transfers +virtual ssize_t Write(const void *buffer, size_t size); +virtual ssize_t WriteAt(off_t pos, const void *buffer, size_t size); + +virtual status_t WaitFrame(bigtime_t timeout); +virtual status_t GetFrame(CamFrame **frame, bigtime_t *stamp); // caller deletes +virtual status_t DropFrame(); + +status_t RegisterSOFTags(const uint8 **tags, int count, size_t len, size_t skip); +status_t RegisterEOFTags(const uint8 **tags, int count, size_t len, size_t skip); + +protected: + +int FindTags(const uint8 *buf, size_t buflen, const uint8 **tags, int tagcount, size_t taglen, size_t skiplen, int *which=NULL); +int FindSOF(const uint8 *buf, size_t buflen, int *which=NULL); +int FindEOF(const uint8 *buf, size_t buflen, int *which=NULL); + +CamFrame *AllocFrame(); + +CamDevice *fDevice; +size_t fMinFrameSize; +size_t fMaxFrameSize; +int fState; +sem_id fFrameSem; +BList fFrames; +BLocker fLocker; +CamFrame *fCurrentFrame; /* the one we write to*/ + +/* tags */ +const uint8 **fSOFTags; +const uint8 **fEOFTags; +int fNumSOFTags; +int fNumEOFTags; +size_t fLenSOFTags; +size_t fLenEOFTags; +size_t fSkipSOFTags; +size_t fSkipEOFTags; + + + +}; + + +#endif /* _CAM_DEFRAMER_H */ diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamDefs.cpp b/src/add-ons/media/media-add-ons/usb_webcam/CamDefs.cpp new file mode 100644 index 0000000000..b5c1be5fa1 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamDefs.cpp @@ -0,0 +1,9 @@ +#include "CamDefs.h" + + +supported_usb_camera gkSupportedCameras[] = +{ + { 0x046d, 0xd001 }, // Logitech quick cam pro + { 0, 0 } +}; + diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamDefs.h b/src/add-ons/media/media-add-ons/usb_webcam/CamDefs.h new file mode 100644 index 0000000000..a0ea04c826 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamDefs.h @@ -0,0 +1,14 @@ +#ifndef _CAM_DEFS_H +#define _CAM_DEFS_H + +#include + +struct supported_usb_camera +{ + uint16 vendor_id; + uint16 product_id; +}; + +extern supported_usb_camera gkSupportedCameras[]; + +#endif diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamDevice.cpp b/src/add-ons/media/media-add-ons/usb_webcam/CamDevice.cpp new file mode 100644 index 0000000000..17d36eb854 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamDevice.cpp @@ -0,0 +1,463 @@ +#include "CamDevice.h" +#include "CamSensor.h" +#include "CamDeframer.h" +#include "CamDebug.h" +#include "AddOn.h" + +#include +#include +#include + +//#define DEBUG_WRITE_DUMP +//#define DEBUG_DISCARD_DATA +//#define DEBUG_READ_DUMP +//#define DEBUG_DISCARD_INPUT + +#undef B_WEBCAM_DECLARE_SENSOR +#define B_WEBCAM_DECLARE_SENSOR(sensorclass,sensorname) \ +extern "C" CamSensor *Instantiate##sensorclass(CamDevice *cam); +#include "CamInternalSensors.h" +#undef B_WEBCAM_DECLARE_SENSOR +typedef CamSensor *(*SensorInstFunc)(CamDevice *cam); +struct { const char *name; SensorInstFunc instfunc; } kSensorTable[] = { +#define B_WEBCAM_DECLARE_SENSOR(sensorclass,sensorname) \ +{ #sensorname, &Instantiate##sensorclass }, +#include "CamInternalSensors.h" +{ NULL, NULL }, +}; +#undef B_WEBCAM_DECLARE_SENSOR + +// ----------------------------------------------------------------------------- +CamDevice::CamDevice(CamDeviceAddon &_addon, BUSBDevice* _device) + : fInitStatus(B_NO_INIT), + fCamDeviceAddon(_addon), + fDevice(_device), + fSupportedDeviceIndex(-1), + fTransferEnabled(false), + fLocker("WebcamDeviceLock"), + fSensor(NULL) +{ + // fill in the generic flavor + memset(&fFlavorInfo, 0, sizeof(fFlavorInfo)); + _addon.WebCamAddOn()->FillDefaultFlavorInfo(&fFlavorInfo); + // if we use id matching, cache the index to the list + if (fCamDeviceAddon.SupportedDevices()) + { + fSupportedDeviceIndex = fCamDeviceAddon.Sniff(_device); + fFlavorInfoNameStr = ""; + fFlavorInfoNameStr << fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].vendor << " USB Webcam"; + fFlavorInfoInfoStr = ""; + fFlavorInfoInfoStr << fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].vendor; + fFlavorInfoInfoStr << " (" << fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].product << ") USB Webcam"; + fFlavorInfo.name = (char *)fFlavorInfoNameStr.String(); + fFlavorInfo.info = (char *)fFlavorInfoInfoStr.String(); + } +#ifdef DEBUG_WRITE_DUMP + fDumpFD = open("/boot/home/webcam.out", O_CREAT|O_RDWR, 0644); +#endif +#ifdef DEBUG_READ_DUMP + fDumpFD = open("/boot/home/webcam.out", O_RDONLY, 0644); +#endif + fBufferLen = 1*B_PAGE_SIZE; + fBuffer = (uint8 *)malloc(fBufferLen); +} + +// ----------------------------------------------------------------------------- +CamDevice::~CamDevice() +{ + close(fDumpFD); + free(fBuffer); + if (fDeframer) + delete fDeframer; +} + +// ----------------------------------------------------------------------------- +status_t +CamDevice::InitCheck() +{ + return fInitStatus; +} + +// ----------------------------------------------------------------------------- +bool +CamDevice::Matches(BUSBDevice* _device) +{ + return (_device) == (fDevice); +} + +// ----------------------------------------------------------------------------- +BUSBDevice* +CamDevice::GetDevice() +{ + return fDevice; +} + +// ----------------------------------------------------------------------------- +void +CamDevice::Unplugged() +{ + fDevice = NULL; + fBulkIn = NULL; +} + +// ----------------------------------------------------------------------------- +bool +CamDevice::IsPlugged() +{ + return (fDevice != NULL); +} + +// ----------------------------------------------------------------------------- +const char * +CamDevice::BrandName() +{ + if (fCamDeviceAddon.SupportedDevices() && (fSupportedDeviceIndex > -1)) + return fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].vendor; + return ""; +} + +// ----------------------------------------------------------------------------- +const char * +CamDevice::ModelName() +{ + if (fCamDeviceAddon.SupportedDevices() && (fSupportedDeviceIndex > -1)) + return fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].product; + return ""; +} + +// ----------------------------------------------------------------------------- +bool +CamDevice::SupportsBulk() +{ + return false; +} + +// ----------------------------------------------------------------------------- +bool +CamDevice::SupportsIsochronous() +{ + return false; +} + +// ----------------------------------------------------------------------------- +status_t +CamDevice::StartTransfer() +{ + status_t err = B_OK; + PRINT((CH "()" CT)); + if (fTransferEnabled) + return EALREADY; + fPumpThread = spawn_thread(_DataPumpThread, "USB Webcam Data Pump", 50, this); + if (fPumpThread < B_OK) + return fPumpThread; + if (fSensor) + err = fSensor->StartTransfer(); + if (err < B_OK) + return err; + fTransferEnabled = true; + resume_thread(fPumpThread); + PRINT((CH ": transfer enabled" CT)); + return B_OK; +} + +// ----------------------------------------------------------------------------- +status_t +CamDevice::StopTransfer() +{ + status_t err = B_OK; + PRINT((CH "()" CT)); + if (!fTransferEnabled) + return EALREADY; + if (fSensor) + err = fSensor->StopTransfer(); + if (err < B_OK) + return err; + fTransferEnabled = false; + wait_for_thread(fPumpThread, &err); + return B_OK; +} + +// ----------------------------------------------------------------------------- +status_t +CamDevice::SetVideoFrame(BRect frame) +{ + fVideoFrame = frame; + return B_OK; +} + +// ----------------------------------------------------------------------------- +status_t +CamDevice::SetScale(float scale) +{ + return B_OK; +} + +// ----------------------------------------------------------------------------- +status_t +CamDevice::SetVideoParams(float brightness, float contrast, float hue, float red, float green, float blue) +{ + return B_OK; +} + +// ----------------------------------------------------------------------------- +size_t +CamDevice::MinRawFrameSize() +{ + return 0; +} + +// ----------------------------------------------------------------------------- +size_t +CamDevice::MaxRawFrameSize() +{ + return 0; +} + +// ----------------------------------------------------------------------------- +bool +CamDevice::ValidateStartOfFrameTag(const uint8 *tag, size_t taglen) +{ + return true; +} + +// ----------------------------------------------------------------------------- +bool +CamDevice::ValidateEndOfFrameTag(const uint8 *tag, size_t taglen, size_t datalen) +{ + return true; +} + +// ----------------------------------------------------------------------------- +status_t +CamDevice::GetFrameBitmap(BBitmap **bm) +{ + return EINVAL; +} + +// ----------------------------------------------------------------------------- +status_t +CamDevice::FillFrameBuffer(BBuffer *buffer) +{ + return EINVAL; +} + +// ----------------------------------------------------------------------------- +bool +CamDevice::Lock() +{ + return fLocker.Lock(); +} + +// ----------------------------------------------------------------------------- +void +CamDevice::Unlock() +{ + fLocker.Unlock(); +} + +// ----------------------------------------------------------------------------- +ssize_t +CamDevice::WriteReg(uint16 address, uint8 *data, size_t count) +{ + return ENOSYS; +} + +// ----------------------------------------------------------------------------- +ssize_t +CamDevice::WriteReg8(uint16 address, uint8 data) +{ + return WriteReg(address, &data, sizeof(uint8)); +} + +// ----------------------------------------------------------------------------- +ssize_t +CamDevice::WriteReg16(uint16 address, uint16 data) +{ + // XXX: ENDIAN??? + return WriteReg(address, (uint8 *)&data, sizeof(uint16)); +} + +// ----------------------------------------------------------------------------- +ssize_t +CamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached) +{ + return ENOSYS; +} + +// ----------------------------------------------------------------------------- +/* +status_t +CamDevice::GetStatusIIC() +{ + return ENOSYS; +} +*/ +// ----------------------------------------------------------------------------- +/*status_t +CamDevice::WaitReadyIIC() +{ + return ENOSYS; +} +*/ +// ----------------------------------------------------------------------------- +ssize_t +CamDevice::WriteIIC(uint8 address, uint8 *data, size_t count) +{ + return ENOSYS; +} + +// ----------------------------------------------------------------------------- +ssize_t +CamDevice::WriteIIC8(uint8 address, uint8 data) +{ + return WriteIIC(address, &data, 1); +} + +// ----------------------------------------------------------------------------- +ssize_t +CamDevice::ReadIIC(uint8 address, uint8 *data) +{ + return ENOSYS; +} + +// ----------------------------------------------------------------------------- +CamSensor * +CamDevice::CreateSensor(const char *name) +{ + int i; + for (i = 0; kSensorTable[i].name; i++) { + if (!strcmp(kSensorTable[i].name, name)) + return kSensorTable[i].instfunc(this); + } + return NULL; +} + +// ----------------------------------------------------------------------------- +void +CamDevice::SetDataInput(BDataIO *input) +{ + fDataInput = input; +} + +// ----------------------------------------------------------------------------- +status_t +CamDevice::DataPumpThread() +{ + if (SupportsBulk()) { + PRINT((CH ": using Bulk" CT)); + while (fTransferEnabled) { + ssize_t len = -1; + BAutolock lock(fLocker); + if (!lock.IsLocked()) + break; + if (!fBulkIn) + break; +#ifndef DEBUG_DISCARD_INPUT + len = fBulkIn->BulkTransfer(fBuffer, fBufferLen); +#endif + + //PRINT((CH ": got %d bytes" CT, len)); +#ifdef DEBUG_WRITE_DUMP + write(fDumpFD, fBuffer, len); +#endif +#ifdef DEBUG_READ_DUMP + if ((len = read(fDumpFD, fBuffer, fBufferLen)) < fBufferLen) + lseek(fDumpFD, 0LL, SEEK_SET); +#endif + + if (len <= 0) { + PRINT((CH ": BulkIn: %s" CT, strerror(len))); + break; + } + +#ifndef DEBUG_DISCARD_DATA + if (fDataInput) { + fDataInput->Write(fBuffer, len); + // else drop + } +#endif + //snooze(2000); + } + } + if (SupportsIsochronous()) { + ;//XXX: TODO + } + return B_OK; +} + +// ----------------------------------------------------------------------------- +int32 +CamDevice::_DataPumpThread(void *_this) +{ + CamDevice *dev = (CamDevice *)_this; + return dev->DataPumpThread(); +} + +// ----------------------------------------------------------------------------- +void +CamDevice::DumpRegs() +{ +} + +// ----------------------------------------------------------------------------- +CamDeviceAddon::CamDeviceAddon(WebCamMediaAddOn* webcam) + : fWebCamAddOn(webcam), + fSupportedDevices(NULL) +{ +} + +// ----------------------------------------------------------------------------- +CamDeviceAddon::~CamDeviceAddon() +{ +} + +// ----------------------------------------------------------------------------- +const char * +CamDeviceAddon::BrandName() +{ + return ""; +} + +// ----------------------------------------------------------------------------- +status_t +CamDeviceAddon::Sniff(BUSBDevice *device) +{ + PRINT((CH ": Sniffing for %s" CT, BrandName())); + if (!fSupportedDevices) + return ENODEV; + if (!device) + return EINVAL; + for (uint32 i = 0; fSupportedDevices[i].vendor; i++) + { +/* PRINT((CH "{%u,%u,%u,0x%x,0x%x} <> {%u,%u,%u,0x%x,0x%x}" CT, + device.Class(), device.Subclass(), device.Protocol(), device.VendorID(), device.ProductID(), + fSupportedDevices[i].desc.dev_class, fSupportedDevices[i].desc.dev_subclass, fSupportedDevices[i].desc.dev_protocol, fSupportedDevices[i].desc.vendor, fSupportedDevices[i].desc.product));*/ +/* if (device.Class() != fSupportedDevices[i].desc.dev_class) + continue; + if (device.Subclass() != fSupportedDevices[i].desc.dev_subclass) + continue; + if (device.Protocol() != fSupportedDevices[i].desc.dev_protocol) + continue;*/ + if (device->VendorID() != fSupportedDevices[i].desc.vendor) + continue; + if (device->ProductID() != fSupportedDevices[i].desc.product) + continue; + return i; + } + return ENODEV; +} + +// ----------------------------------------------------------------------------- +CamDevice * +CamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from) +{ + return NULL; +} + +// ----------------------------------------------------------------------------- +void +CamDeviceAddon::SetSupportedDevices(const usb_named_support_descriptor *devs) +{ + fSupportedDevices = devs; +} + diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamDevice.h b/src/add-ons/media/media-add-ons/usb_webcam/CamDevice.h new file mode 100644 index 0000000000..f0f2e976ff --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamDevice.h @@ -0,0 +1,155 @@ +#ifndef _CAM_DEVICE_H +#define _CAM_DEVICE_H + +#include +#include +#include +#include +#include +#include +#include + +namespace Z { + namespace USB { + class BUSBDevice; + } +} + +using Z::USB::BUSBDevice; + +typedef struct { + usb_support_descriptor desc; + const char *vendor; + const char *product; +} usb_named_support_descriptor; + +class CamRoster; +class CamDeviceAddon; +class CamSensor; +class CamDeframer; +class WebCamMediaAddOn; +class BBitmap; +class BBuffer; + +// This class represents each webcam +class CamDevice +{ + public: + CamDevice(CamDeviceAddon &_addon, BUSBDevice* _device); + virtual ~CamDevice(); + + virtual status_t InitCheck(); + bool Matches(BUSBDevice* _device); + BUSBDevice* GetDevice(); + virtual void Unplugged(); // called before the BUSBDevice deletion + virtual bool IsPlugged(); // asserts on-line hardware + + virtual const char* BrandName(); + virtual const char* ModelName(); + const flavor_info* FlavorInfo() const { return &fFlavorInfo; }; + virtual bool SupportsBulk(); + virtual bool SupportsIsochronous(); + virtual status_t StartTransfer(); + virtual status_t StopTransfer(); + virtual bool TransferEnabled() const { return fTransferEnabled; }; + + virtual status_t SetVideoFrame(BRect rect); + virtual BRect VideoFrame() const { return fVideoFrame; }; + virtual status_t SetScale(float scale); + virtual status_t SetVideoParams(float brightness, float contrast, float hue, float red, float green, float blue); + + // for use by deframer + virtual size_t MinRawFrameSize(); + virtual size_t MaxRawFrameSize(); + virtual bool ValidateStartOfFrameTag(const uint8 *tag, size_t taglen); + virtual bool ValidateEndOfFrameTag(const uint8 *tag, size_t taglen, size_t datalen); + + // several ways to get raw frames + virtual status_t GetFrameBitmap(BBitmap **bm); + virtual status_t FillFrameBuffer(BBuffer *buffer); + + // locking + bool Lock(); + void Unlock(); + BLocker* Locker() { return &fLocker; }; + + // sensor chip handling + CamSensor* Sensor() const { return fSensor; }; + + // generic register-like access + virtual ssize_t WriteReg(uint16 address, uint8 *data, size_t count=1); + virtual ssize_t WriteReg8(uint16 address, uint8 data); + virtual ssize_t WriteReg16(uint16 address, uint16 data); + virtual ssize_t ReadReg(uint16 address, uint8 *data, size_t count=1, bool cached=false); + + // I2C-like access + //virtual status_t GetStatusIIC(); + //virtual status_t WaitReadyIIC(); + virtual ssize_t WriteIIC(uint8 address, uint8 *data, size_t count); + virtual ssize_t WriteIIC8(uint8 address, uint8 data); + virtual ssize_t ReadIIC(uint8 address, uint8 *data); + + + void SetDataInput(BDataIO *input); + virtual status_t DataPumpThread(); + static int32 _DataPumpThread(void *_this); + + virtual void DumpRegs(); + + protected: + CamSensor *CreateSensor(const char *name); + status_t fInitStatus; + flavor_info fFlavorInfo; + media_format fMediaFormat; + BString fFlavorInfoNameStr; + BString fFlavorInfoInfoStr; + CamSensor* fSensor; + CamDeframer* fDeframer; + BDataIO* fDataInput; // where data from usb goes, likely fDeframer + const BUSBEndpoint* fBulkIn; + + private: +friend class CamDeviceAddon; + CamDeviceAddon& fCamDeviceAddon; + BUSBDevice* fDevice; + int fSupportedDeviceIndex; + bool fTransferEnabled; + thread_id fPumpThread; + BLocker fLocker; + uint8 *fBuffer; + size_t fBufferLen; + BRect fVideoFrame; + int fDumpFD; +}; + +// the addon itself, that instanciate + +class CamDeviceAddon +{ + public: + CamDeviceAddon(WebCamMediaAddOn* webcam); + virtual ~CamDeviceAddon(); + + virtual const char* BrandName(); + virtual status_t Sniff(BUSBDevice *device); + virtual CamDevice* Instantiate(CamRoster &roster, BUSBDevice *from); + + void SetSupportedDevices(const usb_named_support_descriptor *devs); + const usb_named_support_descriptor* SupportedDevices() const { return fSupportedDevices; }; + WebCamMediaAddOn* WebCamAddOn() const { return fWebCamAddOn; }; + + private: + WebCamMediaAddOn* fWebCamAddOn; + const usb_named_support_descriptor* fSupportedDevices; // last is {{0,0,0,0,0}, NULL, NULL} +}; + +// internal modules +#define B_WEBCAM_MKINTFUNC(modname) \ +get_webcam_addon_##modname + +// external addons -- UNIMPLEMENTED +extern "C" status_t get_webcam_addon(WebCamMediaAddOn* webcam, CamDeviceAddon **addon); +#define B_WEBCAM_ADDON_INSTANTIATION_FUNC_NAME "get_webcam_addon" + + +#endif _CAM_DEVICE_H diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamFilterInterface.cpp b/src/add-ons/media/media-add-ons/usb_webcam/CamFilterInterface.cpp new file mode 100644 index 0000000000..db008a0ade --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamFilterInterface.cpp @@ -0,0 +1,126 @@ +#include "CamFilterInterface.h" +#include "CamDevice.h" +#include "CamDebug.h" + +CamFilterInterface::CamFilterInterface(CamDevice *device) +: BPositionIO(), +fDevice(device), +fNextOfKin(NULL) +{ + fVideoFrame = BRect(0,0,-1,-1); + +} + +CamFilterInterface::~CamFilterInterface() +{ +} + +status_t +CamFilterInterface::ChainFilter(CamFilterInterface *to) +{ + if (fNextOfKin) + return EALREADY; + fNextOfKin = to; + return B_OK; +} + +status_t +CamFilterInterface::DetachFilter(CamFilterInterface *from) +{ + if (from && (fNextOfKin != from)) + return EINVAL; + fNextOfKin = NULL; + return B_OK; +} + +CamFilterInterface* +CamFilterInterface::ChainFilter() +{ + return fNextOfKin; +} + +ssize_t +CamFilterInterface::Read(void *buffer, size_t size) +{ + (void)buffer; + (void)size; + return EINVAL; +} + +ssize_t +CamFilterInterface::ReadAt(off_t pos, void *buffer, size_t size) +{ + (void)pos; + (void)buffer; + (void)size; + return EINVAL; +} + +ssize_t +CamFilterInterface::Write(const void *buffer, size_t size) +{ + (void)buffer; + (void)size; + return EINVAL; +} + +ssize_t +CamFilterInterface::WriteAt(off_t pos, const void *buffer, size_t size) +{ + (void)pos; + (void)buffer; + (void)size; + return EINVAL; +} + +off_t +CamFilterInterface::Seek(off_t position, uint32 seek_mode) +{ + (void)position; + (void)seek_mode; + return EINVAL; +} + +off_t +CamFilterInterface::Position() const +{ + return 0LL; +} + +status_t +CamFilterInterface::SetSize(off_t size) +{ + (void)size; + return EINVAL; +} + +size_t +CamFilterInterface::FrameSize() +{ + return 0; +} + +status_t +CamFilterInterface::WaitFrame(bigtime_t timeout) +{ + if (fNextOfKin) + return fNextOfKin->WaitFrame(timeout); + return EINVAL; +} + +status_t +CamFilterInterface::DropFrame() +{ + if (fNextOfKin) + return fNextOfKin->DropFrame(); + return B_OK; +} + +status_t +CamFilterInterface::SetVideoFrame(BRect frame) +{ + if (fNextOfKin) + return fNextOfKin->SetVideoFrame(frame); + fVideoFrame = frame; + return B_OK; +} diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamFilterInterface.h b/src/add-ons/media/media-add-ons/usb_webcam/CamFilterInterface.h new file mode 100644 index 0000000000..43d9525b29 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamFilterInterface.h @@ -0,0 +1,52 @@ +#ifndef _CAM_FILTER_INTERFACE_H +#define _CAM_FILTER_INTERFACE_H + +#include +#include +#include +class CamDevice; + +class CamFilterInterface : public BPositionIO +{ +public: + CamFilterInterface(CamDevice *device); +virtual ~CamFilterInterface(); + + // filter chain handling, should be accessed with device locked + // stack up this filter on top of 'to' +status_t ChainFilter(CamFilterInterface *to); + // break the chain +status_t DetachFilter(CamFilterInterface *from); + // accessor (next is actually processing data before self) +CamFilterInterface *ChainFilter(); + + + // BPositionIO interface +virtual ssize_t Read(void *buffer, size_t size); +virtual ssize_t ReadAt(off_t pos, void *buffer, size_t size); + +virtual ssize_t Write(const void *buffer, size_t size); +virtual ssize_t WriteAt(off_t pos, const void *buffer, size_t size); + +virtual off_t Seek(off_t position, uint32 seek_mode); +virtual off_t Position() const; +virtual status_t SetSize(off_t size); + // size of the buffer required for reading a whole frame +virtual size_t FrameSize(); + + // frame handling +virtual status_t WaitFrame(bigtime_t timeout); +virtual status_t DropFrame(); + // video settings propagation +virtual status_t SetVideoFrame(BRect frame); + + +protected: + +CamDevice *fDevice; +CamFilterInterface *fNextOfKin; +BRect fVideoFrame; +}; + + +#endif /* _CAM_FILTER_INTERFACE_H */ diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamInternalAddons.h b/src/add-ons/media/media-add-ons/usb_webcam/CamInternalAddons.h new file mode 100644 index 0000000000..34c61730cf --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamInternalAddons.h @@ -0,0 +1,2 @@ +B_WEBCAM_MKINTFUNC(quickcam) +B_WEBCAM_MKINTFUNC(sonix) diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamInternalColorSpaceTransforms.h b/src/add-ons/media/media-add-ons/usb_webcam/CamInternalColorSpaceTransforms.h new file mode 100644 index 0000000000..20323138dd --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamInternalColorSpaceTransforms.h @@ -0,0 +1 @@ +B_WEBCAM_DECLARE_CSTRANSFORM(BayerTransform, bayer) diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamInternalSensors.h b/src/add-ons/media/media-add-ons/usb_webcam/CamInternalSensors.h new file mode 100644 index 0000000000..22d326b9f8 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamInternalSensors.h @@ -0,0 +1,3 @@ +B_WEBCAM_DECLARE_SENSOR(HDCS1000Sensor, hdcs1000) +B_WEBCAM_DECLARE_SENSOR(HV7131E1Sensor, hv7131e1) +B_WEBCAM_DECLARE_SENSOR(TAS5110C1BSensor, tas5110c1b) diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamRoster.cpp b/src/add-ons/media/media-add-ons/usb_webcam/CamRoster.cpp new file mode 100644 index 0000000000..6885b78e45 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamRoster.cpp @@ -0,0 +1,168 @@ +#include "CamRoster.h" + +#include "AddOn.h" +#include "CamDevice.h" +#include "CamDebug.h" +#include "CamDefs.h" + +#include +#include + +#undef B_WEBCAM_MKINTFUNC +#define B_WEBCAM_MKINTFUNC(modname) \ +extern "C" status_t get_webcam_addon_##modname(WebCamMediaAddOn* webcam, CamDeviceAddon **addon); +#include "CamInternalAddons.h" +#undef B_WEBCAM_MKINTFUNC + + +// --------------------------------------------------------------------------- +CamRoster::CamRoster(WebCamMediaAddOn* _addon) + : BUSBRoster(), + fLocker("WebcamRosterLock"), + fAddon(_addon) +{ + PRINT((CH "()" CT)); + LoadInternalAddons(); + LoadExternalAddons(); +} + +// --------------------------------------------------------------------------- +CamRoster::~CamRoster() +{ +} + +// --------------------------------------------------------------------------- +status_t +CamRoster::DeviceAdded(BUSBDevice* _device) +{ + PRINT((CH "()" CT)); + status_t err; + for( int16 i = fCamerasAddons.CountItems()-1; i >= 0; --i ) + { + PRINT((CH ": checking %s for support..." CT, fCamerasAddons[i]->BrandName())); + err = fCamerasAddons[i]->Sniff(_device); + if (err >= B_OK) + { + CamDevice *cam = fCamerasAddons[i]->Instantiate(*this, _device); + PRINT((CH ": found camera %s:%s!" CT, cam->BrandName(), cam->ModelName())); + err = cam->InitCheck(); + if (err >= B_OK) + { + fCameras.AddItem(cam); + fAddon->CameraAdded(cam); + return B_OK; + } + PRINT((CH " error 0x%08lx" CT, err)); + } + } + return B_ERROR; +} + +// --------------------------------------------------------------------------- +void +CamRoster::DeviceRemoved(BUSBDevice* _device) +{ + PRINT((CH "()" CT)); + for(uint32 i = 0; i < fCameras.CountItems(); ++i) + { + CamDevice* cam = fCameras[i]; + if( cam->Matches(_device) ) + { + PRINT((CH ": camera %s:%s removed" CT, cam->BrandName(), cam->ModelName())); + fCameras.RemoveItemsAt(i, 1); + fAddon->CameraRemoved(cam); + // XXX: B_DONT_DO_THAT! + //delete cam; + cam->Unplugged(); + return; + } + } +} + +// --------------------------------------------------------------------------- +uint32 +CamRoster::CountCameras() +{ + int32 count; + PRINT((CH "(): %d cameras" CT, fCameras.CountItems())); + fLocker.Lock(); + count = fCameras.CountItems(); + fLocker.Unlock(); + return count; +} + +// --------------------------------------------------------------------------- +bool +CamRoster::Lock() +{ + PRINT((CH "()" CT)); + return fLocker.Lock(); +} + +// --------------------------------------------------------------------------- +void +CamRoster::Unlock() +{ + PRINT((CH "()" CT)); + fLocker.Unlock(); + return; +} + +// --------------------------------------------------------------------------- +CamDevice* +CamRoster::CameraAt(int32 index) +{ + PRINT((CH "()" CT)); + return fCameras.ItemAt(index); +} + +// --------------------------------------------------------------------------- +status_t +CamRoster::LoadInternalAddons() +{ + PRINT((CH "()" CT)); + CamDeviceAddon *addon; + status_t err; + +#undef B_WEBCAM_MKINTFUNC +#define B_WEBCAM_MKINTFUNC(modname) \ + err = get_webcam_addon_##modname(fAddon, &addon); \ + if (err >= B_OK) { \ + fCamerasAddons.AddItem(addon); \ + PRINT((CH ": registered %s addon" CT, addon->BrandName())); \ + } + +#include "CamInternalAddons.h" +#undef B_WEBCAM_MKINTFUNC + + + return B_OK; +} + +// --------------------------------------------------------------------------- +status_t +CamRoster::LoadExternalAddons() +{ + PRINT((CH "()" CT)); + // FIXME + return B_ERROR; + int32 index; + int32 sclass; + status_t err; + CamDeviceAddon *addon; + status_t (*get_webcam_addon_func)(WebCamMediaAddOn* webcam, CamDeviceAddon **addon); + for (index = 0; get_nth_image_symbol(fAddon->ImageID(), + index, NULL, NULL, + &sclass, + (void **)&get_webcam_addon_func) == B_OK; index++) { + PRINT((CH ": got sym" CT)); +// if (sclass != B_SYMBOL_TYPE_TEXT) +// continue; + err = (*get_webcam_addon_func)(fAddon, &addon); + PRINT((CH ": Loaded addon '%s' with error 0x%08lx" CT, (err>0)?NULL:addon->BrandName(), err)); + } + return B_OK; +} + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamRoster.h b/src/add-ons/media/media-add-ons/usb_webcam/CamRoster.h new file mode 100644 index 0000000000..2b429ac44c --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamRoster.h @@ -0,0 +1,49 @@ +#ifndef _CAM_ROSTER_H +#define _CAM_ROSTER_H + +#include +#include +#include +#include + +class WebCamMediaAddOn; +class CamDevice; +class CamDeviceAddon; + +namespace Z { +namespace USB { + class BUSBDevice; +} +} + +using Z::USB::BUSBDevice; + +class CamRoster : public BUSBRoster +{ +public: + CamRoster(WebCamMediaAddOn* _addon); + virtual ~CamRoster(); + virtual status_t DeviceAdded(BUSBDevice* _device); + virtual void DeviceRemoved(BUSBDevice* _device); + + uint32 CountCameras(); + bool Lock(); + void Unlock(); + // those must be called with Lock() + CamDevice* CameraAt(int32 index); + + + +private: + status_t LoadInternalAddons(); + status_t LoadExternalAddons(); + + BLocker fLocker; + WebCamMediaAddOn* fAddon; + B::Support:: + BVector fCamerasAddons; + B::Support:: + BVector fCameras; +}; + +#endif diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamSensor.cpp b/src/add-ons/media/media-add-ons/usb_webcam/CamSensor.cpp new file mode 100644 index 0000000000..23c8174c23 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamSensor.cpp @@ -0,0 +1,76 @@ +#include "CamSensor.h" +#include "CamDebug.h" + +// ----------------------------------------------------------------------------- +CamSensor::CamSensor(CamDevice *_camera) + : fInitStatus(B_NO_INIT), + fTransferEnabled(false), + fVideoFrame(), + fCamDevice(_camera) +{ + +} + +// ----------------------------------------------------------------------------- +CamSensor::~CamSensor() +{ + +} + +// ----------------------------------------------------------------------------- +status_t +CamSensor::InitCheck() +{ + return fInitStatus; +} + +// ----------------------------------------------------------------------------- +status_t +CamSensor::Setup() +{ + return fInitStatus; +} + +// ----------------------------------------------------------------------------- +const char * +CamSensor::Name() +{ + return ""; +} + +// ----------------------------------------------------------------------------- +status_t +CamSensor::StartTransfer() +{ + fTransferEnabled = true; + return B_OK; +} + +// ----------------------------------------------------------------------------- +status_t +CamSensor::StopTransfer() +{ + fTransferEnabled = false; + return B_OK; +} + +// ----------------------------------------------------------------------------- +status_t +CamSensor::SetVideoFrame(BRect rect) +{ + return ENOSYS; +} + +// ----------------------------------------------------------------------------- +status_t +CamSensor::SetVideoParams(float brightness, float contrast, float hue, float red, float green, float blue) +{ + return ENOSYS; +} + +// ----------------------------------------------------------------------------- +CamDevice * +CamSensor::Device() +{ + return fCamDevice; +} diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamSensor.h b/src/add-ons/media/media-add-ons/usb_webcam/CamSensor.h new file mode 100644 index 0000000000..9babe0fa51 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamSensor.h @@ -0,0 +1,64 @@ +#ifndef _CAM_SENSOR_H +#define _CAM_SENSOR_H + +#include "CamDevice.h" +#include + +// This class represents the camera's (cmos or whatever) sensor chip +class CamSensor +{ + public: + CamSensor(CamDevice *_camera); + virtual ~CamSensor(); + + virtual status_t InitCheck(); + + virtual status_t Setup(); + + virtual const char* Name(); + + virtual status_t StartTransfer(); + virtual status_t StopTransfer(); + virtual bool TransferEnabled() const { return fTransferEnabled; }; + + virtual bool Use400kHz() const { return false; }; + virtual bool UseRealIIC() const { return true; }; + virtual uint8 IICReadAddress() const { return 0; }; + virtual uint8 IICWriteAddress() const { return 0; };; + virtual int MaxWidth() const { return -1; }; + virtual int MaxHeight() const { return -1; }; + + + virtual status_t SetVideoFrame(BRect rect); + virtual BRect VideoFrame() const { return fVideoFrame; }; + virtual status_t SetVideoParams(float brightness, float contrast, float hue, float red, float green, float blue); + + CamDevice *Device(); + +#if 0 + // generic register-like access + virtual status_t WriteReg(uint16 address, uint8 *data, size_t count=1); + virtual status_t WriteReg8(uint16 address, uint8 data); + virtual status_t WriteReg16(uint16 address, uint16 data); + virtual status_t ReadReg(uint16 address, uint8 *data, size_t count=1, bool cached=false); + + // I2C-like access + virtual status_t WriteIIC(uint8 address, uint8 *data, size_t count=1); + virtual status_t ReadIIC(uint8 address, uint8 *data); +#endif + protected: + status_t fInitStatus; + bool fTransferEnabled; + BRect fVideoFrame; + private: + CamDevice *fCamDevice; +}; + +// internal modules +#define B_WEBCAM_DECLARE_SENSOR(sensorclass,sensorname) \ +extern "C" CamSensor *Instantiate##sensorclass(CamDevice *cam); \ +CamSensor *Instantiate##sensorclass(CamDevice *cam) \ +{ return new sensorclass(cam); }; + + +#endif /* _CAM_SENSOR_H */ diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamStreamingDeframer.cpp b/src/add-ons/media/media-add-ons/usb_webcam/CamStreamingDeframer.cpp new file mode 100644 index 0000000000..b5c42341d8 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamStreamingDeframer.cpp @@ -0,0 +1,191 @@ +/* + * stream based deframer + * has a state machine and handles each packet separately. + * much more complex than the buffering one, and I thought it didn't work, + * but since I fixed the rest it seems to be working even better without + * taking the cpu over like the other one. + */ + +#define CD_COL "31" +#include "CamStreamingDeframer.h" +#include "CamDevice.h" +#include "CamDebug.h" +#include +#define MAX_TAG_LEN CAMDEFRAMER_MAX_TAG_LEN +#define MAXFRAMEBUF CAMDEFRAMER_MAX_QUEUED_FRAMES + +CamStreamingDeframer::CamStreamingDeframer(CamDevice *device) +: CamDeframer(device) +{ +} + +CamStreamingDeframer::~CamStreamingDeframer() +{ +} + +ssize_t +CamStreamingDeframer::Write(const void *buffer, size_t size) +{ + int i = -1; + int j; + int end = size; + int which; + const uint8 *buf = (const uint8 *)buffer; + int bufsize = size; + bool detach = false; + bool discard = false; + PRINT((CH "(%p, %d); state=%s framesz=%u queued=%u" CT, buffer, size, (fState==ST_SYNC)?"sync":"frame", (size_t)fCurrentFrame->Position(), (size_t)fInputBuff.Position())); + if (!fCurrentFrame) { + BAutolock l(fLocker); + if (fFrames.CountItems() < MAXFRAMEBUF) + fCurrentFrame = AllocFrame(); + else { + PRINT((CH "DROPPED %d bytes! (too many queued frames)" CT, size)); + return size; // drop XXX + } + } + + // update in case resolution changed + fMinFrameSize = fDevice->MinRawFrameSize(); + fMaxFrameSize = fDevice->MaxRawFrameSize(); + + if (fInputBuff.Position()) { + // residual data ? append to it + fInputBuff.Write(buffer, size); + // and use it as input buf + buf = (uint8 *)fInputBuff.Buffer(); + bufsize = fInputBuff.BufferLength(); + end = bufsize; + } + // whole buffer belongs to a frame, simple + if ((fState == ST_FRAME) && (fCurrentFrame->Position() + bufsize < fMinFrameSize)) { + // no residual data, and + fCurrentFrame->Write(buf, bufsize); + fInputBuff.Seek(0LL, SEEK_SET); + fInputBuff.SetSize(0); + return size; + } + + // waiting for a frame... + if (fState == ST_SYNC) { + i = 0; + while ((j = FindSOF(buf+i, bufsize-i, &which)) > -1) { + i += j; + if (fDevice->ValidateStartOfFrameTag(buf+i, fSkipSOFTags)) + break; + i++; + } + // got one + if (j >= 0) { + PRINT((CH ": SOF[%d] at offset %d" CT, which, i)); + //PRINT((CH ": SOF: ... %02x %02x %02x %02x %02x %02x" CT, buf[i+6], buf[i+7], buf[i+8], buf[i+9], buf[i+10], buf[i+11])); + int start = i + fSkipSOFTags; + buf += start; + bufsize -= start; + end = bufsize; + fState = ST_FRAME; + } + } + + // check for end of frame + if (fState == ST_FRAME) { +#if 0 + int j, k; + i = -1; + k = 0; + while ((j = FindEOF(buf + k, bufsize - k, &which)) > -1) { + k += j; + //PRINT((CH "| EOF[%d] at offset %d; pos %Ld" CT, which, k, fCurrentFrame->Position())); + if (fCurrentFrame->Position()+k >= fMinFrameSize) { + i = k; + break; + } + k++; + if (k >= bufsize) + break; + } +#endif +#if 1 + i = 0; + if (fCurrentFrame->Position() < fMinFrameSize) { + if (fCurrentFrame->Position() + bufsize >= fMinFrameSize) + i = (fMinFrameSize - (size_t)fCurrentFrame->Position()); + else + i = bufsize; + } + PRINT((CH ": checking for EOF; bufsize=%d i=%d" CT, bufsize, i)); + + if (i + fSkipEOFTags > bufsize) { // not enough room to check for EOF, leave it for next time + end = i; + i = -1; // don't detach yet + } else { + PRINT((CH ": EOF? %02x [%02x %02x %02x %02x] %02x" CT, buf[i-1], buf[i], buf[i+1], buf[i+2], buf[i+3], buf[i+4])); + while ((j = FindEOF(buf + i, bufsize - i, &which)) > -1) { + i += j; + PRINT((CH "| EOF[%d] at offset %d; pos %Ld" CT, which, i, fCurrentFrame->Position())); + if (fCurrentFrame->Position()+i >= fMaxFrameSize) { + // too big: discard + //i = -1; + discard = true; + break; + } + if (fDevice->ValidateEndOfFrameTag(buf+i, fSkipEOFTags, fCurrentFrame->Position()+i)) + break; + i++; + if (i >= bufsize) { + i = -1; + break; + } + } + if (j < 0) + i = -1; + } +#endif + if (i >= 0) { + PRINT((CH ": EOF[%d] at offset %d" CT, which, i)); + end = i; + detach = true; + } + PRINT((CH ": writing %d bytes" CT, end)); + if (end <= bufsize) + fCurrentFrame->Write(buf, end); + if (fCurrentFrame->Position() > fMaxFrameSize) { + fCurrentFrame->SetSize(fMaxFrameSize); + detach = true; + } + if (detach) { + BAutolock f(fLocker); + PRINT((CH ": Detaching a frame (%d bytes, end = %d, )" CT, (size_t)fCurrentFrame->Position(), end)); + fCurrentFrame->Seek(0LL, SEEK_SET); + if (discard) { + delete fCurrentFrame; + } else { + fFrames.AddItem(fCurrentFrame); + release_sem(fFrameSem); + } + fCurrentFrame = NULL; + if (fFrames.CountItems() < MAXFRAMEBUF) { + fCurrentFrame = AllocFrame(); + } + fState = ST_SYNC; + } + } + + + + + // put the remainder in input buff, discarding old data +#if 0 + fInputBuff.Seek(0LL, SEEK_SET); + if (bufsize - end > 0) + fInputBuff.Write(buf+end, bufsize - end); +#endif + BMallocIO m; + m.Write(buf+end, bufsize - end); + fInputBuff.Seek(0LL, SEEK_SET); + if (bufsize - end > 0) + fInputBuff.Write(m.Buffer(), bufsize - end); + fInputBuff.SetSize(bufsize - end); + return size; +} + diff --git a/src/add-ons/media/media-add-ons/usb_webcam/CamStreamingDeframer.h b/src/add-ons/media/media-add-ons/usb_webcam/CamStreamingDeframer.h new file mode 100644 index 0000000000..ee122a4997 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/CamStreamingDeframer.h @@ -0,0 +1,23 @@ +#ifndef _CAM_STREAMING_DEFRAMER_H +#define _CAM_STREAMING_DEFRAMER_H + +#include "CamDeframer.h" + +class CamStreamingDeframer : public CamDeframer +{ +public: + CamStreamingDeframer(CamDevice *device); +virtual ~CamStreamingDeframer(); + // BPositionIO interface + // write from usb transfers +virtual ssize_t Write(const void *buffer, size_t size); + +private: + +BMallocIO fInputBuff; + + +}; + + +#endif /* _CAM_STREAMING_DEFRAMER_H */ diff --git a/src/add-ons/media/media-add-ons/usb_webcam/Producer.cpp b/src/add-ons/media/media-add-ons/usb_webcam/Producer.cpp new file mode 100644 index 0000000000..257ebf5cf0 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/Producer.cpp @@ -0,0 +1,784 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +//XXX: change interface +#include + +#include "CamDevice.h" + +#define TOUCH(x) ((void)(x)) + +#define PRINTF(a,b) \ + do { \ + if (a < 2) { \ + printf("VideoProducer::"); \ + printf b; \ + } \ + } while (0) + +#include "Producer.h" + +#define FIELD_RATE 30.f + +int32 VideoProducer::fInstances = 0; + +VideoProducer::VideoProducer( + BMediaAddOn *addon, CamDevice *dev, const char *name, int32 internal_id) + : BMediaNode(name), + BMediaEventLooper(), + BBufferProducer(B_MEDIA_RAW_VIDEO), + BControllable() +{ +// status_t err; + + fInitStatus = B_NO_INIT; + + /* Only allow one instance of the node to exist at any time */ + if (atomic_add(&fInstances, 1) != 0) + return; + + fInternalID = internal_id; + fAddOn = addon; + fCamDevice = dev; + + fBufferGroup = NULL; + + fThread = -1; + fFrameSync = -1; + fProcessingLatency = 0LL; + + fRunning = false; + fConnected = false; + fEnabled = false; + + fOutput.destination = media_destination::null; + + AddNodeKind(B_PHYSICAL_INPUT); + + fInitStatus = B_OK; + return; +} + +VideoProducer::~VideoProducer() +{ + if (fInitStatus == B_OK) { + /* Clean up after ourselves, in case the application didn't make us + * do so. */ + if (fConnected) + Disconnect(fOutput.source, fOutput.destination); + if (fRunning) + HandleStop(); + } + + atomic_add(&fInstances, -1); +} + +/* BMediaNode */ + +port_id +VideoProducer::ControlPort() const +{ + return BMediaNode::ControlPort(); +} + +BMediaAddOn * +VideoProducer::AddOn(int32 *internal_id) const +{ + if (internal_id) + *internal_id = fInternalID; + return fAddOn; +} + +status_t +VideoProducer::HandleMessage(int32 /*message*/, const void* /*data*/, size_t /*size*/) +{ + return B_ERROR; +} + +void +VideoProducer::Preroll() +{ + /* This hook may be called before the node is started to give the hardware + * a chance to start. */ +} + +void +VideoProducer::SetTimeSource(BTimeSource* /*time_source*/) +{ + /* Tell frame generation thread to recalculate delay value */ + release_sem(fFrameSync); +} + +status_t +VideoProducer::RequestCompleted(const media_request_info &info) +{ + return BMediaNode::RequestCompleted(info); +} + +/* BMediaEventLooper */ + +void +VideoProducer::NodeRegistered() +{ + if (fInitStatus != B_OK) { + ReportError(B_NODE_IN_DISTRESS); + return; + } + + /* Set up the parameter web */ + BParameterWeb *web = new BParameterWeb(); + BParameterGroup *main = web->MakeGroup(Name()); + BDiscreteParameter *state = main->MakeDiscreteParameter( + P_COLOR, B_MEDIA_RAW_VIDEO, "Color", "Color"); + state->AddItem(B_HOST_TO_LENDIAN_INT32(0x00ff0000), "Red"); + state->AddItem(B_HOST_TO_LENDIAN_INT32(0x0000ff00), "Green"); + state->AddItem(B_HOST_TO_LENDIAN_INT32(0x000000ff), "Blue"); + + fColor = B_HOST_TO_LENDIAN_INT32(0x00ff0000); + fLastColorChange = system_time(); + + /* After this call, the BControllable owns the BParameterWeb object and + * will delete it for you */ + SetParameterWeb(web); + + fOutput.node = Node(); + fOutput.source.port = ControlPort(); + fOutput.source.id = 0; + fOutput.destination = media_destination::null; + strcpy(fOutput.name, Name()); + + /* Tailor these for the output of your device */ + fOutput.format.type = B_MEDIA_RAW_VIDEO; + fOutput.format.u.raw_video = media_raw_video_format::wildcard; + fOutput.format.u.raw_video.interlace = 1; + fOutput.format.u.raw_video.display.format = B_RGB32; + fOutput.format.u.raw_video.field_rate = 29.97f; // XXX: mmu + + /* Start the BMediaEventLooper control loop running */ + Run(); +} + +void +VideoProducer::Start(bigtime_t performance_time) +{ + BMediaEventLooper::Start(performance_time); +} + +void +VideoProducer::Stop(bigtime_t performance_time, bool immediate) +{ + BMediaEventLooper::Stop(performance_time, immediate); +} + +void +VideoProducer::Seek(bigtime_t media_time, bigtime_t performance_time) +{ + BMediaEventLooper::Seek(media_time, performance_time); +} + +void +VideoProducer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time) +{ + BMediaEventLooper::TimeWarp(at_real_time, to_performance_time); +} + +status_t +VideoProducer::AddTimer(bigtime_t at_performance_time, int32 cookie) +{ + return BMediaEventLooper::AddTimer(at_performance_time, cookie); +} + +void +VideoProducer::SetRunMode(run_mode mode) +{ + BMediaEventLooper::SetRunMode(mode); +} + +void +VideoProducer::HandleEvent(const media_timed_event *event, + bigtime_t lateness, bool realTimeEvent) +{ + TOUCH(lateness); TOUCH(realTimeEvent); + + switch(event->type) + { + case BTimedEventQueue::B_START: + HandleStart(event->event_time); + break; + case BTimedEventQueue::B_STOP: + HandleStop(); + break; + case BTimedEventQueue::B_WARP: + HandleTimeWarp(event->bigdata); + break; + case BTimedEventQueue::B_SEEK: + HandleSeek(event->bigdata); + break; + case BTimedEventQueue::B_HANDLE_BUFFER: + case BTimedEventQueue::B_DATA_STATUS: + case BTimedEventQueue::B_PARAMETER: + default: + PRINTF(-1, ("HandleEvent: Unhandled event -- %lx\n", event->type)); + break; + } +} + +void +VideoProducer::CleanUpEvent(const media_timed_event *event) +{ + BMediaEventLooper::CleanUpEvent(event); +} + +bigtime_t +VideoProducer::OfflineTime() +{ + return BMediaEventLooper::OfflineTime(); +} + +void +VideoProducer::ControlLoop() +{ + BMediaEventLooper::ControlLoop(); +} + +status_t +VideoProducer::DeleteHook(BMediaNode * node) +{ + return BMediaEventLooper::DeleteHook(node); +} + +/* BBufferProducer */ + +status_t +VideoProducer::FormatSuggestionRequested( + media_type type, int32 quality, media_format *format) +{ + if (type != B_MEDIA_ENCODED_VIDEO) + return B_MEDIA_BAD_FORMAT; + + TOUCH(quality); + + *format = fOutput.format; + format->u.raw_video.field_rate = 29.97f; + return B_OK; +} + +status_t +VideoProducer::FormatProposal(const media_source &output, media_format *format) +{ + status_t err; + + if (!format) + return B_BAD_VALUE; + + if (output != fOutput.source) + return B_MEDIA_BAD_SOURCE; + + err = format_is_compatible(*format, fOutput.format) ? + B_OK : B_MEDIA_BAD_FORMAT; + *format = fOutput.format; + return err; + +} + +status_t +VideoProducer::FormatChangeRequested(const media_source &source, + const media_destination &destination, media_format *io_format, + int32 *_deprecated_) +{ + TOUCH(destination); TOUCH(io_format); TOUCH(_deprecated_); + if (source != fOutput.source) + return B_MEDIA_BAD_SOURCE; + + return B_ERROR; +} + +status_t +VideoProducer::GetNextOutput(int32 *cookie, media_output *out_output) +{ + if (!out_output) + return B_BAD_VALUE; + + if ((*cookie) != 0) + return B_BAD_INDEX; + + *out_output = fOutput; + (*cookie)++; + return B_OK; +} + +status_t +VideoProducer::DisposeOutputCookie(int32 cookie) +{ + TOUCH(cookie); + + return B_OK; +} + +status_t +VideoProducer::SetBufferGroup(const media_source &for_source, + BBufferGroup *group) +{ + TOUCH(for_source); TOUCH(group); + + return B_ERROR; +} + +status_t +VideoProducer::VideoClippingChanged(const media_source &for_source, + int16 num_shorts, int16 *clip_data, + const media_video_display_info &display, int32 *_deprecated_) +{ + TOUCH(for_source); TOUCH(num_shorts); TOUCH(clip_data); + TOUCH(display); TOUCH(_deprecated_); + + return B_ERROR; +} + +status_t +VideoProducer::GetLatency(bigtime_t *out_latency) +{ + *out_latency = EventLatency() + SchedulingLatency(); + return B_OK; +} + +status_t +VideoProducer::PrepareToConnect(const media_source &source, + const media_destination &destination, media_format *format, + media_source *out_source, char *out_name) +{ +// status_t err; + + PRINTF(1, ("PrepareToConnect() %ldx%ld\n", \ + format->u.raw_video.display.line_width, \ + format->u.raw_video.display.line_count)); + + if (fConnected) { + PRINTF(0, ("PrepareToConnect: Already connected\n")); + return EALREADY; + } + + if (source != fOutput.source) + return B_MEDIA_BAD_SOURCE; + + if (fOutput.destination != media_destination::null) + return B_MEDIA_ALREADY_CONNECTED; + + /* The format parameter comes in with the suggested format, and may be + * specialized as desired by the node */ + if (!format_is_compatible(*format, fOutput.format)) { + *format = fOutput.format; + return B_MEDIA_BAD_FORMAT; + } + +//XXX:FIXME +// if (format->u.raw_video.display.line_width == 0) + format->u.raw_video.display.line_width = 352;//320; + format->u.raw_video.display.line_width = 320; +// if (format->u.raw_video.display.line_count == 0) + format->u.raw_video.display.line_count = 288;//240; + format->u.raw_video.display.line_count = 240; + if (format->u.raw_video.field_rate == 0) + format->u.raw_video.field_rate = 29.97f; + + *out_source = fOutput.source; + strcpy(out_name, fOutput.name); + + fOutput.destination = destination; + + return B_OK; +} + +void +VideoProducer::Connect(status_t error, const media_source &source, + const media_destination &destination, const media_format &format, + char *io_name) +{ + PRINTF(1, ("Connect() %ldx%ld\n", \ + format.u.raw_video.display.line_width, \ + format.u.raw_video.display.line_count)); + + if (fConnected) { + PRINTF(0, ("Connect: Already connected\n")); + return; + } + + BAutolock lock(fCamDevice->Locker()); + if (!fCamDevice->IsPlugged()) { + PRINTF(0, ("Connect: Device unplugged\n")); + return; + } + + if ( (source != fOutput.source) || (error < B_OK) || + !const_cast(&format)->Matches(&fOutput.format)) { + PRINTF(1, ("Connect: Connect error\n")); + return; + } + + fOutput.destination = destination; + strcpy(io_name, fOutput.name); + + if (fOutput.format.u.raw_video.field_rate != 0.0f) { + fPerformanceTimeBase = fPerformanceTimeBase + + (bigtime_t) + ((fFrame - fFrameBase) * + (1000000 / fOutput.format.u.raw_video.field_rate)); + fFrameBase = fFrame; + } + + fConnectedFormat = format.u.raw_video; + + /* get the latency */ + bigtime_t latency = 0; + media_node_id tsID = 0; + FindLatencyFor(fOutput.destination, &latency, &tsID); + #define NODE_LATENCY 1000 + SetEventLatency(latency + NODE_LATENCY); + + uint32 *buffer, *p, f = 3; + p = buffer = (uint32 *)malloc(4 * fConnectedFormat.display.line_count * + fConnectedFormat.display.line_width); + if (!buffer) { + PRINTF(0, ("Connect: Out of memory\n")); + return; + } + bigtime_t now = system_time(); + for (uint32 y=0;yInitCheck() < B_OK) { + delete fBufferGroup; + fBufferGroup = NULL; + return; + } + + fConnected = true; + fEnabled = true; + + /* Tell frame generation thread to recalculate delay value */ + release_sem(fFrameSync); +} + +void +VideoProducer::Disconnect(const media_source &source, + const media_destination &destination) +{ + PRINTF(1, ("Disconnect()\n")); + + if (!fConnected) { + PRINTF(0, ("Disconnect: Not connected\n")); + return; + } + + if ((source != fOutput.source) || (destination != fOutput.destination)) { + PRINTF(0, ("Disconnect: Bad source and/or destination\n")); + return; + } + + fEnabled = false; + fOutput.destination = media_destination::null; + + fLock.Lock(); + delete fBufferGroup; + fBufferGroup = NULL; + fLock.Unlock(); + + fConnected = false; +} + +void +VideoProducer::LateNoticeReceived(const media_source &source, + bigtime_t how_much, bigtime_t performance_time) +{ + TOUCH(source); TOUCH(how_much); TOUCH(performance_time); +} + +void +VideoProducer::EnableOutput(const media_source &source, bool enabled, + int32 *_deprecated_) +{ + TOUCH(_deprecated_); + + if (source != fOutput.source) + return; + + fEnabled = enabled; +} + +status_t +VideoProducer::SetPlayRate(int32 numer, int32 denom) +{ + TOUCH(numer); TOUCH(denom); + + return B_ERROR; +} + +void +VideoProducer::AdditionalBufferRequested(const media_source &source, + media_buffer_id prev_buffer, bigtime_t prev_time, + const media_seek_tag *prev_tag) +{ + TOUCH(source); TOUCH(prev_buffer); TOUCH(prev_time); TOUCH(prev_tag); +} + +void +VideoProducer::LatencyChanged(const media_source &source, + const media_destination &destination, bigtime_t new_latency, + uint32 flags) +{ + TOUCH(source); TOUCH(destination); TOUCH(new_latency); TOUCH(flags); +} + +/* BControllable */ + +status_t +VideoProducer::GetParameterValue( + int32 id, bigtime_t *last_change, void *value, size_t *size) +{ + if (id != P_COLOR) + return B_BAD_VALUE; + + *last_change = fLastColorChange; + *size = sizeof(uint32); + *((uint32 *)value) = fColor; + + return B_OK; +} + +void +VideoProducer::SetParameterValue( + int32 id, bigtime_t when, const void *value, size_t size) +{ + if ((id != P_COLOR) || !value || (size != sizeof(uint32))) + return; + + if (*(uint32 *)value == fColor) + return; + + fColor = *(uint32 *)value; + fLastColorChange = when; + + BroadcastNewParameterValue( + fLastColorChange, P_COLOR, &fColor, sizeof(fColor)); +} + +status_t +VideoProducer::StartControlPanel(BMessenger *out_messenger) +{ + return BControllable::StartControlPanel(out_messenger); +} + +/* VideoProducer */ + +void +VideoProducer::HandleStart(bigtime_t performance_time) +{ + /* Start producing frames, even if the output hasn't been connected yet. */ + + PRINTF(1, ("HandleStart(%Ld)\n", performance_time)); + + if (fRunning) { + PRINTF(-1, ("HandleStart: Node already started\n")); + return; + } + + fFrame = 0; + fFrameBase = 0; + fPerformanceTimeBase = performance_time; + + fFrameSync = create_sem(0, "frame synchronization"); + if (fFrameSync < B_OK) + goto err1; + + fThread = spawn_thread(_frame_generator_, "frame generator", + B_NORMAL_PRIORITY, this); + if (fThread < B_OK) + goto err2; + + resume_thread(fThread); + + fCamDevice->StartTransfer(); + + fRunning = true; + return; + +err2: + delete_sem(fFrameSync); +err1: + return; +} + +void +VideoProducer::HandleStop(void) +{ + PRINTF(1, ("HandleStop()\n")); + + if (!fRunning) { + PRINTF(-1, ("HandleStop: Node isn't running\n")); + return; + } + + delete_sem(fFrameSync); + wait_for_thread(fThread, &fThread); + + fCamDevice->StopTransfer(); + + fRunning = false; +} + +void +VideoProducer::HandleTimeWarp(bigtime_t performance_time) +{ + fPerformanceTimeBase = performance_time; + fFrameBase = fFrame; + + /* Tell frame generation thread to recalculate delay value */ + release_sem(fFrameSync); +} + +void +VideoProducer::HandleSeek(bigtime_t performance_time) +{ + fPerformanceTimeBase = performance_time; + fFrameBase = fFrame; + + /* Tell frame generation thread to recalculate delay value */ + release_sem(fFrameSync); +} + +/* The following functions form the thread that generates frames. You should + * replace this with the code that interfaces to your hardware. */ +int32 +VideoProducer::FrameGenerator() +{ + bigtime_t wait_until = system_time(); + + while (1) { + status_t err = acquire_sem_etc(fFrameSync, 1, B_ABSOLUTE_TIMEOUT, + wait_until); + + /* The only acceptable responses are B_OK and B_TIMED_OUT. Everything + * else means the thread should quit. Deleting the semaphore, as in + * VideoProducer::HandleStop(), will trigger this behavior. */ + if ((err != B_OK) && (err != B_TIMED_OUT)) + break; + + fFrame++; + + /* Recalculate the time until the thread should wake up to begin + * processing the next frame. Subtract fProcessingLatency so that + * the frame is sent in time. */ + wait_until = TimeSource()->RealTimeFor(fPerformanceTimeBase, 0) + + (bigtime_t) + ((fFrame - fFrameBase) * + (1000000 / fConnectedFormat.field_rate)) - + fProcessingLatency; + + /* Drop frame if it's at least a frame late */ + if (wait_until < system_time()) + continue; + + /* If the semaphore was acquired successfully, it means something + * changed the timing information (see VideoProducer::Connect()) and + * so the thread should go back to sleep until the newly-calculated + * wait_until time. */ + if (err == B_OK) + continue; + + /* Send buffers only if the node is running and the output has been + * enabled */ + if (!fRunning || !fEnabled) + continue; + + BAutolock _(fLock); + + /* Fetch a buffer from the buffer group */ + BBuffer *buffer = fBufferGroup->RequestBuffer( + 4 * fConnectedFormat.display.line_width * + fConnectedFormat.display.line_count, 0LL); + if (!buffer) + continue; + + /* Fill out the details about this buffer. */ + media_header *h = buffer->Header(); + h->type = B_MEDIA_RAW_VIDEO; + h->time_source = TimeSource()->ID(); + h->size_used = 4 * fConnectedFormat.display.line_width * + fConnectedFormat.display.line_count; + /* For a buffer originating from a device, you might want to calculate + * this based on the PerformanceTimeFor the time your buffer arrived at + * the hardware (plus any applicable adjustments). */ + h->start_time = fPerformanceTimeBase + + (bigtime_t) + ((fFrame - fFrameBase) * + (1000000 / fConnectedFormat.field_rate)); + h->file_pos = 0; + h->orig_size = 0; + h->data_offset = 0; + h->u.raw_video.field_gamma = 1.0; + h->u.raw_video.field_sequence = fFrame; + h->u.raw_video.field_number = 0; + h->u.raw_video.pulldown_number = 0; + h->u.raw_video.first_active_line = 1; + h->u.raw_video.line_count = fConnectedFormat.display.line_count; + + // This is where we fill the video buffer. + + uint32 *p = (uint32 *)buffer->Data(); +#if 0 + /* Fill in a pattern */ + for (uint32 y=0;yFillFrameBuffer(buffer); + if (err < B_OK) { + ;//XXX handle error + } +//#endif +#ifdef UseGetFrameBitmap + BBitmap *bm; + err = fCamDevice->GetFrameBitmap(&bm); + if (err >= B_OK) { + ;//XXX handle error + } +#endif + + /* Send the buffer on down to the consumer */ + if (SendBuffer(buffer, fOutput.destination) < B_OK) { + PRINTF(-1, ("FrameGenerator: Error sending buffer\n")); + /* If there is a problem sending the buffer, return it to its + * buffer group. */ + buffer->Recycle(); + } + } + + return B_OK; +} + +int32 +VideoProducer::_frame_generator_(void *data) +{ + return ((VideoProducer *)data)->FrameGenerator(); +} diff --git a/src/add-ons/media/media-add-ons/usb_webcam/Producer.h b/src/add-ons/media/media-add-ons/usb_webcam/Producer.h new file mode 100644 index 0000000000..974334d6d0 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/Producer.h @@ -0,0 +1,141 @@ +#ifndef _VIDEO_PRODUCER_H +#define _VIDEO_PRODUCER_H + +#include +#include +#include +#include +#include +#include +#include + +class CamDevice; + +class VideoProducer : + public virtual BMediaEventLooper, + public virtual BBufferProducer, + public virtual BControllable +{ +public: + VideoProducer(BMediaAddOn *addon, CamDevice *dev, + const char *name, int32 internal_id); +virtual ~VideoProducer(); + +virtual status_t InitCheck() const { return fInitStatus; } + +/* BMediaNode */ +public: +virtual port_id ControlPort() const; +virtual BMediaAddOn *AddOn(int32 * internal_id) const; +virtual status_t HandleMessage(int32 message, const void *data, + size_t size); +protected: +virtual void Preroll(); +virtual void SetTimeSource(BTimeSource * time_source); +virtual status_t RequestCompleted(const media_request_info & info); + +/* BMediaEventLooper */ +protected: +virtual void NodeRegistered(); +virtual void Start(bigtime_t performance_time); +virtual void Stop(bigtime_t performance_time, bool immediate); +virtual void Seek(bigtime_t media_time, bigtime_t performance_time); +virtual void TimeWarp(bigtime_t at_real_time, + bigtime_t to_performance_time); +virtual status_t AddTimer(bigtime_t at_performance_time, int32 cookie); +virtual void SetRunMode(run_mode mode); +virtual void HandleEvent(const media_timed_event *event, + bigtime_t lateness, bool realTimeEvent = false); +virtual void CleanUpEvent(const media_timed_event *event); +virtual bigtime_t OfflineTime(); +virtual void ControlLoop(); +virtual status_t DeleteHook(BMediaNode * node); + +/* BBufferProducer */ +protected: +virtual status_t FormatSuggestionRequested(media_type type, int32 quality, + media_format * format); +virtual status_t FormatProposal(const media_source &output, + media_format *format); +virtual status_t FormatChangeRequested(const media_source &source, + const media_destination &destination, + media_format *io_format, int32 *_deprecated_); +virtual status_t GetNextOutput(int32 * cookie, media_output * out_output); +virtual status_t DisposeOutputCookie(int32 cookie); +virtual status_t SetBufferGroup(const media_source &for_source, + BBufferGroup * group); +virtual status_t VideoClippingChanged(const media_source &for_source, + int16 num_shorts, int16 *clip_data, + const media_video_display_info &display, + int32 * _deprecated_); +virtual status_t GetLatency(bigtime_t * out_latency); +virtual status_t PrepareToConnect(const media_source &what, + const media_destination &where, + media_format *format, + media_source *out_source, char *out_name); +virtual void Connect(status_t error, const media_source &source, + const media_destination &destination, + const media_format & format, char *io_name); +virtual void Disconnect(const media_source & what, + const media_destination & where); +virtual void LateNoticeReceived(const media_source & what, + bigtime_t how_much, bigtime_t performance_time); +virtual void EnableOutput(const media_source & what, bool enabled, + int32 * _deprecated_); +virtual status_t SetPlayRate(int32 numer,int32 denom); +virtual void AdditionalBufferRequested(const media_source & source, + media_buffer_id prev_buffer, bigtime_t prev_time, + const media_seek_tag * prev_tag); +virtual void LatencyChanged(const media_source & source, + const media_destination & destination, + bigtime_t new_latency, uint32 flags); + +/* BControllable */ +protected: +virtual status_t GetParameterValue(int32 id, bigtime_t *last_change, + void *value, size_t *size); +virtual void SetParameterValue(int32 id, bigtime_t when, + const void *value, size_t size); +virtual status_t StartControlPanel(BMessenger *out_messenger); + +/* state */ +private: + void HandleStart(bigtime_t performance_time); + void HandleStop(); + void HandleTimeWarp(bigtime_t performance_time); + void HandleSeek(bigtime_t performance_time); + +static int32 fInstances; + + status_t fInitStatus; + + int32 fInternalID; + BMediaAddOn *fAddOn; + CamDevice *fCamDevice; + + BLocker fLock; + BBufferGroup *fBufferGroup; + + thread_id fThread; + sem_id fFrameSync; +static int32 _frame_generator_(void *data); + int32 FrameGenerator(); + + /* The remaining variables should be declared volatile, but they + * are not here to improve the legibility of the sample code. */ + uint32 fFrame; + uint32 fFrameBase; + bigtime_t fPerformanceTimeBase; + bigtime_t fProcessingLatency; + media_output fOutput; + media_raw_video_format fConnectedFormat; + bool fRunning; + bool fConnected; + bool fEnabled; + + enum { P_COLOR }; + uint32 fColor; + bigtime_t fLastColorChange; +}; + +#endif diff --git a/src/add-ons/media/media-add-ons/usb_webcam/addons/quickcam/QuickCamDevice.cpp b/src/add-ons/media/media-add-ons/usb_webcam/addons/quickcam/QuickCamDevice.cpp new file mode 100644 index 0000000000..8ab9854e89 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/addons/quickcam/QuickCamDevice.cpp @@ -0,0 +1,58 @@ +#include "QuickCamDevice.h" + +#include + +const usb_named_support_descriptor kSupportedDevices[] = { +{{ 0, 0, 0, 0x046d, 0x0840 }, "Logitech", "QuickCam Express"}, +{{ 0, 0, 0, 0x046d, 0x0850 }, "Logitech", "QuickCam Express LEGO"}, +{{ 0, 0, 0, 0x046d, 0xd001 }, "Logitech", "QuickCam Express"}, // Alan's +{{ 0, 0, 0, 0, 0}, NULL, NULL } +}; + + +// ----------------------------------------------------------------------------- +QuickCamDevice::QuickCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device) + :CamDevice(_addon, _device) +{ + fInitStatus = B_OK; +} + +// ----------------------------------------------------------------------------- +QuickCamDevice::~QuickCamDevice() +{ + +} + +// ----------------------------------------------------------------------------- +QuickCamDeviceAddon::QuickCamDeviceAddon(WebCamMediaAddOn* webcam) + : CamDeviceAddon(webcam) +{ + SetSupportedDevices(kSupportedDevices); +} + +// ----------------------------------------------------------------------------- +QuickCamDeviceAddon::~QuickCamDeviceAddon() +{ +} + +// ----------------------------------------------------------------------------- +const char * +QuickCamDeviceAddon::BrandName() +{ + return "QuickCam"; +} + +// ----------------------------------------------------------------------------- +QuickCamDevice * +QuickCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from) +{ + return new QuickCamDevice(*this, from); +} + +extern "C" status_t +B_WEBCAM_MKINTFUNC(quickcam) +(WebCamMediaAddOn* webcam, CamDeviceAddon **addon) +{ + *addon = new QuickCamDeviceAddon(webcam); + return B_OK; +} diff --git a/src/add-ons/media/media-add-ons/usb_webcam/addons/quickcam/QuickCamDevice.h b/src/add-ons/media/media-add-ons/usb_webcam/addons/quickcam/QuickCamDevice.h new file mode 100644 index 0000000000..2e9c605e10 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/addons/quickcam/QuickCamDevice.h @@ -0,0 +1,29 @@ +#ifndef _QUICK_CAM_DEVICE_H +#define _QUICK_CAM_DEVICE_H + +#include "CamDevice.h" + +// This class represents each webcam +class QuickCamDevice : public CamDevice +{ + public: + QuickCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device); + ~QuickCamDevice(); + + private: +}; + +// the addon itself, that instanciate + +class QuickCamDeviceAddon : public CamDeviceAddon +{ + public: + QuickCamDeviceAddon(WebCamMediaAddOn* webcam); + virtual ~QuickCamDeviceAddon(); + + virtual const char *BrandName(); + virtual QuickCamDevice *Instantiate(CamRoster &roster, BUSBDevice *from); + +}; + +#endif /* _QUICK_CAM_CAM_DEVICE_H */ diff --git a/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.cpp b/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.cpp new file mode 100644 index 0000000000..cd0a9adc73 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.cpp @@ -0,0 +1,742 @@ +#include "SonixCamDevice.h" +#include "CamDebug.h" +#include "CamSensor.h" +#include "CamBufferingDeframer.h" +#include "CamStreamingDeframer.h" + +#include +#include +#include + +#include +#include + +const usb_named_support_descriptor kSupportedDevices[] = { +{{ 0, 0, 0, 0x0c45, 0x6005 }, "Sonix", "Sonix"}, +{{ 0, 0, 0, 0x0c45, 0x6009 }, "Trust", "spacec@m 120" }, +{{ 0, 0, 0, 0x0c45, 0x600D }, "Trust", "spacec@m 120" }, +{{ 0, 0, 0, 0, 0}, NULL, NULL } +}; + +// 12 bytes actually +static const uint8 sof_mark_1[] = { 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00 }; +static const uint8 sof_mark_2[] = { 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01 }; +static const uint8 *sof_marks[] = { sof_mark_1, sof_mark_2 }; + +static const uint8 eof_mark_1[] = { 0x00, 0x00, 0x00, 0x00 }; +static const uint8 eof_mark_2[] = { 0x40, 0x00, 0x00, 0x00 }; +static const uint8 eof_mark_3[] = { 0x80, 0x00, 0x00, 0x00 }; +static const uint8 eof_mark_4[] = { 0xc0, 0x00, 0x00, 0x00 }; +static const uint8 *eof_marks[] = { eof_mark_1, eof_mark_2, eof_mark_3, eof_mark_4 }; + +void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT); +void bayer2rgb32le(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT); + +// ----------------------------------------------------------------------------- +SonixCamDevice::SonixCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device) + :CamDevice(_addon, _device) +{ + uchar data[8]; /* store bytes returned from sonix commands */ + status_t err; + fFrameTagState = 0; + + memset(fCachedRegs, 0, SN9C102_REG_COUNT); + fChipVersion = 2; + if ((GetDevice()->ProductID() & ~0x3F) == 0x6080) { + fChipVersion = 3; // says V4L2 + } + switch (GetDevice()->ProductID()) { + case 0x6001: + case 0x6005: + case 0x60ab: + fSensor = CreateSensor("tas5110c1b"); + break; + default: + break; + } + +// fDeframer = new CamBufferingDeframer(this); + fDeframer = new CamStreamingDeframer(this); + fDeframer->RegisterSOFTags(sof_marks, 2, sizeof(sof_mark_1), 12); + fDeframer->RegisterEOFTags(eof_marks, 4, sizeof(eof_mark_1), sizeof(eof_mark_1)); + SetDataInput(fDeframer); + + /* init hw */ + + const BUSBConfiguration *config = GetDevice()->ConfigurationAt(0); + if (config) { + const BUSBInterface *inter = config->InterfaceAt(0); + int i; + + GetDevice()->SetConfiguration(config); + + for (i = 0; inter && (i < inter->CountEndpoints()); i++) { + const BUSBEndpoint *e = inter->EndpointAt(i); + if (e && e->IsBulk() && e->IsInput()) { + fBulkIn = e; + PRINT((CH ": Using inter[0].endpoint[%d]; maxpktsz: %d" CT, i, e->MaxPacketSize())); + break; + } + } + + } + + /* sanity check */ + err = ReadReg(SN9C102_ASIC_ID, data); + if (err < 0 || data[0] != 0x10) { + PRINT((CH ": BAD ASIC signature! (%u != %u)" CT, data[0], 0x10)); + return; + } + + + if (Sensor()) { + PRINT((CH ": CamSensor: %s" CT, Sensor()->Name())); + fInitStatus = Sensor()->Setup(); +// SetVideoFrame(BRect(0, 0, Sensor()->MaxWidth()-1, Sensor()->MaxHeight()-1)); +// SetVideoFrame(BRect(0, 0, 320-1, 240-1)); + } + //SetScale(1); +} + +// ----------------------------------------------------------------------------- +SonixCamDevice::~SonixCamDevice() +{ + if (Sensor()) + delete fSensor; + fSensor = NULL; +} + +// ----------------------------------------------------------------------------- +bool +SonixCamDevice::SupportsBulk() +{ + return true; +} + +// ----------------------------------------------------------------------------- +bool +SonixCamDevice::SupportsIsochronous() +{ + return true; +} + +// ----------------------------------------------------------------------------- +status_t +SonixCamDevice::StartTransfer() +{ + status_t err; + uint8 r; + + SetScale(1); + if (Sensor()) + SetVideoFrame(BRect(0, 0, Sensor()->MaxWidth()-1, Sensor()->MaxHeight()-1)); + + SetVideoFrame(BRect(0, 0, 320-1, 240-1)); + +DumpRegs(); + err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true); + if (err < 0) + return err; + r |= 0x04; + err = WriteReg8(SN9C102_CHIP_CTRL, r); + if (err < 0) + return err; + return CamDevice::StartTransfer(); +} + +// ----------------------------------------------------------------------------- +status_t +SonixCamDevice::StopTransfer() +{ + status_t err; + uint8 r; + +DumpRegs(); + err = CamDevice::StopTransfer(); +// if (err < 0) +// return err; + err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true); + if (err < 0) + return err; + r &= ~0x04; + err = WriteReg8(SN9C102_CHIP_CTRL, r); + if (err < 0) + return err; + return err; +} + +// ----------------------------------------------------------------------------- +ssize_t +SonixCamDevice::WriteReg(uint16 address, uint8 *data, size_t count) +{ + PRINT((CH "(%u, @%p, %u)" CT, address, data, count)); + if (address + count > SN9C102_REG_COUNT) { + PRINT((CH ": Invalid register range [%u;%u]" CT, address, address+count)); + return EINVAL; + } + memcpy(&fCachedRegs[address], data, count); + return SendCommand(USB_REQTYPE_DEVICE_OUT, 0x08, address, 0, count, data); +} + +// ----------------------------------------------------------------------------- +ssize_t +SonixCamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached) +{ + PRINT((CH "(%u, @%p, %u, %d)" CT, address, data, count, cached)); + if (address + count > SN9C102_REG_COUNT) { + PRINT((CH ": Invalid register range [%u;%u]" CT, address, address+count)); + return EINVAL; + } + if (cached) { + memcpy(data, &fCachedRegs[address], count); + return count; + } + return SendCommand(USB_REQTYPE_DEVICE_IN, 0x00, address, 0, count, data); +} + +// ----------------------------------------------------------------------------- +status_t +SonixCamDevice::GetStatusIIC() +{ + status_t err; + uint8 status = 0; + err = ReadReg(SN9C102_I2C_SETUP, &status); + //dprintf(ID "i2c_status: error 0x%08lx, status = %02x\n", err, status); + if (err < 0) + return err; + return (status&0x08)?EIO:0; +} + +// ----------------------------------------------------------------------------- +status_t +SonixCamDevice::WaitReadyIIC() +{ + status_t err; + uint8 status = 0; + int tries = 5; + if (!Sensor()) + return B_NO_INIT; + while (tries--) { + err = ReadReg(SN9C102_I2C_SETUP, &status); + //dprintf(ID "i2c_wait_ready: error 0x%08lx, status = %02x\n", err, status); + if (err < 0) return err; + if (status & 0x04) return B_OK; + //XXX:FIXME:spin((1+5+11*dev->sensor->use_400kHz)*8); + snooze((1+5+11*Sensor()->Use400kHz())*8); + } + return EBUSY; +} + +// ----------------------------------------------------------------------------- +ssize_t +SonixCamDevice::WriteIIC(uint8 address, uint8 *data, size_t count) +{ + status_t err; + uint8 status; + uint8 buffer[8]; + if (!Sensor()) + return B_NO_INIT; + //dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4); + count++; // includes address + if (count > 5) + return EINVAL; + buffer[0] = (count << 4) | Sensor()->Use400kHz()?0x01:0 + | Sensor()->UseRealIIC()?0x80:0; + buffer[1] = Sensor()->IICWriteAddress(); + buffer[2] = address; + memset(&buffer[3], 0, 5); + memcpy(&buffer[3], data, count); + buffer[7] = 0x14; /* absolutely no idea why V4L2 driver use that value */ + err = WriteReg(SN9C102_I2C_SETUP, buffer, 8); + //dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err); + //PRINT((CH ": WriteReg: %s" CT, strerror(err))); + if (err < 0) return err; + err = WaitReadyIIC(); + //dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err); + //PRINT((CH ": Wait: %s" CT, strerror(err))); + if (err) return err; + err = GetStatusIIC(); + //dprintf(ID "sonix_i2c_write_multi: sonix_i2c_status error 0x%08lx\n", err); + //PRINT((CH ": Status: %s" CT, strerror(err))); + if (err) return err; + //dprintf(ID "sonix_i2c_write_multi: succeeded\n"); + PRINT((CH ": success" CT)); + return B_OK; +} + +// ----------------------------------------------------------------------------- +ssize_t +SonixCamDevice::ReadIIC(uint8 address, uint8 *data) +{ + status_t err, lasterr = B_OK; + uint8 status; + uint8 buffer[8]; + if (!Sensor()) + return B_NO_INIT; + //dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4); + buffer[0] = (1 << 4) | Sensor()->Use400kHz()?0x01:0 + | Sensor()->UseRealIIC()?0x80:0; + buffer[1] = Sensor()->IICWriteAddress(); + buffer[2] = address; + buffer[7] = 0x10; /* absolutely no idea why V4L2 driver use that value */ + err = WriteReg(SN9C102_I2C_SETUP, buffer, 8); + //dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err); + if (err) return err; + err = WaitReadyIIC(); + //dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err); + //if (err) return err; + + + //dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4); + buffer[0] = (1 << 4) | Sensor()->Use400kHz()?0x01:0 + | 0x02 | Sensor()->UseRealIIC()?0x80:0; /* read 1 byte */ + buffer[1] = Sensor()->IICReadAddress();//IICWriteAddress + buffer[7] = 0x10; /* absolutely no idea why V4L2 driver use that value */ + err = WriteReg(SN9C102_I2C_SETUP, buffer, 8); + //dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err); + if (err) return err; + err = WaitReadyIIC(); + //dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err); + if (err) return err; + + err = ReadReg(SN9C102_I2C_DATA0, buffer, 5); + if (err) lasterr = err; + + err = GetStatusIIC(); + //dprintf(ID "sonix_i2c_write_multi: sonix_i2c_status error 0x%08lx\n", err); + if (err) return err; + //dprintf(ID "sonix_i2c_write_multi: succeeded\n"); + if (lasterr) return err; + + /* we should get what we want in buffer[4] according to the V4L2 driver... + * probably because the 5 bytes are a bit shift register? + */ + *data = buffer[4]; + + return 1; +} + +// ----------------------------------------------------------------------------- +status_t +SonixCamDevice::SetVideoFrame(BRect frame) +{ + uint16 x, y, width, height; + x = (uint16)frame.left; + y = (uint16)frame.top; + width = (uint16)(frame.right - frame.left + 1) / 16; + height = (uint16)(frame.bottom - frame.top + 1) / 16; + PRINT((CH "(%u, %u, %u, %u)" CT, x, y, width, height)); + + WriteReg8(SN9C102_H_START, x); + WriteReg8(SN9C102_V_START, y); + WriteReg8(SN9C102_H_SIZE, width); + WriteReg8(SN9C102_V_SIZE, height); + if (Sensor()) { + Sensor()->SetVideoFrame(frame); + } + return CamDevice::SetVideoFrame(frame); +} + +// ----------------------------------------------------------------------------- +status_t +SonixCamDevice::SetScale(float scale) +{ + status_t err; + uint8 r; + int iscale = (int)scale; + + PRINT((CH "(%u)" CT, iscale)); + err = ReadReg(SN9C102_SYNC_N_SCALE, &r, 1, true); + if (err < 0) + return err; + r &= ~0x30; + switch (iscale) { + case 1: + case 2: + case 4: + r |= ((iscale-1) << 4); + break; + default: + return EINVAL; + } + err = WriteReg8(SN9C102_SYNC_N_SCALE, r); + return err; +} + +// ----------------------------------------------------------------------------- +status_t +SonixCamDevice::SetVideoParams(float brightness, float contrast, float hue, float red, float green, float blue) +{ + return B_OK; +} + +// ----------------------------------------------------------------------------- +size_t +SonixCamDevice::MinRawFrameSize() +{ + // if (fCompressionEnabled) { ... return ; } + BRect vf(VideoFrame()); + int w = vf.IntegerWidth()+1; + int h = vf.IntegerHeight()+1; + // 1 byte/pixel + return (size_t)(w*h); +} + +// ----------------------------------------------------------------------------- +size_t +SonixCamDevice::MaxRawFrameSize() +{ + // if (fCompressionEnabled) { ... return ; } + return MinRawFrameSize()+1024*0; // fixed size frame (uncompressed) +} + +// ----------------------------------------------------------------------------- +bool +SonixCamDevice::ValidateStartOfFrameTag(const uint8 *tag, size_t taglen) +{ + // SOF come with an 00, 40, 80, C0 sequence, + // supposedly corresponding with an equal byte in the end tag + fFrameTagState = tag[7] & 0xC0; + PRINT((CH "(, %d) state %x" CT, taglen, fFrameTagState)); + + // which seems to be the same as of the EOF tag + return true; +} + +// ----------------------------------------------------------------------------- +bool +SonixCamDevice::ValidateEndOfFrameTag(const uint8 *tag, size_t taglen, size_t datalen) +{ + //PRINT((CH "(, %d) %x == %x" CT, taglen, (tag[0] & 0xC0), fFrameTagState)); + // make sure the tag corresponds to the SOF we refer to + if ((tag[0] & 0xC0) != fFrameTagState) { + PRINT((CH ": discarded EOF %x != %x" CT, fFrameTagState, tag[0] & 0xC0)); + return false; + } + //PRINT((CH ": validated EOF %x, len %d" CT, fFrameTagState, datalen)); + return true; +} + +// ----------------------------------------------------------------------------- +status_t +SonixCamDevice::GetFrameBitmap(BBitmap **bm) +{ + BBitmap *b; + CamFrame *f; + bigtime_t stamp; + status_t err; + PRINT((CH "()" CT)); + err = fDeframer->WaitFrame(200000); + if (err < B_OK) { PRINT((CH ": WaitFrame: %s" CT, strerror(err))); } + if (err < B_OK) + return err; + err = fDeframer->GetFrame(&f, &stamp); + if (err < B_OK) { PRINT((CH ": GetFrame: %s" CT, strerror(err))); } + if (err < B_OK) + return err; + PRINT((CH ": VideoFrame = %fx%f,%fx%f" CT, VideoFrame().left, VideoFrame().top, VideoFrame().right, VideoFrame().bottom)); + + long int w = VideoFrame().right - VideoFrame().left + 1; + long int h = VideoFrame().bottom - VideoFrame().top + 1; + b = new BBitmap(VideoFrame().OffsetToSelf(0,0), 0, B_RGB32, w*4); + PRINT((CH ": Frame: %dx%d" CT, w, h)); + + bayer2rgb24((unsigned char *)b->Bits(), (unsigned char *)f->Buffer(), w, h); + + PRINT((CH ": got 1 frame (len %d)" CT, b->BitsLength())); + *bm = b; + return B_OK; +} + +// ----------------------------------------------------------------------------- +status_t +SonixCamDevice::FillFrameBuffer(BBuffer *buffer) +{ + CamFrame *f; + bigtime_t stamp; + status_t err; + PRINT((CH "()" CT)); + + memset(buffer->Data(), 0, buffer->SizeAvailable()); + err = fDeframer->WaitFrame(2000000); + if (err < B_OK) { PRINT((CH ": WaitFrame: %s" CT, strerror(err))); } + if (err < B_OK) + return err; + + err = fDeframer->GetFrame(&f, &stamp); + if (err < B_OK) { PRINT((CH ": GetFrame: %s" CT, strerror(err))); } + if (err < B_OK) + return err; + + long int w = VideoFrame().right - VideoFrame().left + 1; + long int h = VideoFrame().bottom - VideoFrame().top + 1; + PRINT((CH ": VideoFrame = %fx%f,%fx%f Frame: %dx%d" CT, VideoFrame().left, VideoFrame().top, VideoFrame().right, VideoFrame().bottom, w, h)); + + if (buffer->SizeAvailable() >= w*h*4) + bayer2rgb32le((unsigned char *)buffer->Data(), (unsigned char *)f->Buffer(), w, h); + + delete f; + + PRINT((CH ": available %d, required %d" CT, buffer->SizeAvailable(), w*h*4)); + if (buffer->SizeAvailable() < w*h*4) + return E2BIG; + PRINT((CH ": got 1 frame (len %d)" CT, buffer->SizeUsed())); + return B_OK; +} + +// ----------------------------------------------------------------------------- +void +/* DEBUG: dump the SN regs */ +SonixCamDevice::DumpRegs() +{ + uint8 regs[SN9C102_REG_COUNT]; + status_t err; + + //err = sonix_get_regs(dev, SN_ASIC_ID, regs, SN_REG_COUNT); + err = ReadReg(0, regs, SN9C102_REG_COUNT); + if (err < 0) + return; + printf("REG1: %02x %02x %02x %02x %02x %02x %02x %02x\n", + regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]); + printf(" 2: %02x %02x %02x %02x %02x %02x %02x %02x\n", + regs[8], regs[9], regs[10], regs[11], regs[12], regs[13], regs[14], regs[15]); + printf(" 3: %02x %02x %02x %02x %02x %02x %02x %02x\n", + regs[16], regs[17], regs[18], regs[19], regs[20], regs[21], regs[22], regs[23]); + printf(" 4: %02x %02x %02x %02x %02x %02x %02x %02x\n", + regs[24], regs[25], regs[26], regs[27], regs[28], regs[29], regs[30], regs[31]); +} + +// ----------------------------------------------------------------------------- +status_t +SonixCamDevice::SendCommand(uint8 dir, uint8 request, uint16 value, + uint16 index, uint16 length, void* data) +{ + size_t ret; + if (length > 64) + return EINVAL; + if (!GetDevice()) + return ENODEV; + ret = GetDevice()->ControlTransfer( + USB_REQTYPE_VENDOR | USB_REQTYPE_INTERFACE_OUT | dir, + request, value, index, length, data); + return ret; +} + +// ----------------------------------------------------------------------------- +SonixCamDeviceAddon::SonixCamDeviceAddon(WebCamMediaAddOn* webcam) + : CamDeviceAddon(webcam) +{ + SetSupportedDevices(kSupportedDevices); +} + +// ----------------------------------------------------------------------------- +SonixCamDeviceAddon::~SonixCamDeviceAddon() +{ +} + +// ----------------------------------------------------------------------------- +const char * +SonixCamDeviceAddon::BrandName() +{ + return "Sonix"; +} + +// ----------------------------------------------------------------------------- +SonixCamDevice * +SonixCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from) +{ + return new SonixCamDevice(*this, from); +} + +extern "C" status_t +B_WEBCAM_MKINTFUNC(sonix) +(WebCamMediaAddOn* webcam, CamDeviceAddon **addon) +{ + *addon = new SonixCamDeviceAddon(webcam); + return B_OK; +} + +// XXX: REMOVE ME + + + +/* + * BAYER2RGB24 ROUTINE TAKEN FROM: + * + * Sonix SN9C101 based webcam basic I/F routines + * Copyright (C) 2004 Takafumi Mizuno + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT) +{ + long int i; + unsigned char *rawpt, *scanpt; + long int size; + + rawpt = src; + scanpt = dst; + size = WIDTH*HEIGHT; + + for ( i = 0; i < size; i++ ) { + if ( (i/WIDTH) % 2 == 0 ) { + if ( (i % 2) == 0 ) { + /* B */ + if ( (i > WIDTH) && ((i % WIDTH) > 0) ) { + *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+ + *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; /* R */ + *scanpt++ = (*(rawpt-1)+*(rawpt+1)+ + *(rawpt+WIDTH)+*(rawpt-WIDTH))/4; /* G */ + *scanpt++ = *rawpt; /* B */ + } else { + /* first line or left column */ + *scanpt++ = *(rawpt+WIDTH+1); /* R */ + *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2; /* G */ + *scanpt++ = *rawpt; /* B */ + } + } else { + /* (B)G */ + if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) { + *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2; /* R */ + *scanpt++ = *rawpt; /* G */ + *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* B */ + } else { + /* first line or right column */ + *scanpt++ = *(rawpt+WIDTH); /* R */ + *scanpt++ = *rawpt; /* G */ + *scanpt++ = *(rawpt-1); /* B */ + } + } + } else { + if ( (i % 2) == 0 ) { + /* G(R) */ + if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) { + *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* R */ + *scanpt++ = *rawpt; /* G */ + *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2; /* B */ + } else { + /* bottom line or left column */ + *scanpt++ = *(rawpt+1); /* R */ + *scanpt++ = *rawpt; /* G */ + *scanpt++ = *(rawpt-WIDTH); /* B */ + } + } else { + /* R */ + if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) { + *scanpt++ = *rawpt; /* R */ + *scanpt++ = (*(rawpt-1)+*(rawpt+1)+ + *(rawpt-WIDTH)+*(rawpt+WIDTH))/4; /* G */ + *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+ + *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; /* B */ + } else { + /* bottom line or right column */ + *scanpt++ = *rawpt; /* R */ + *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2; /* G */ + *scanpt++ = *(rawpt-WIDTH-1); /* B */ + } + } + } + rawpt++; + } + +} + +/* modified bayer2rgb24 to output rgb-32 little endian (B_RGB32) + * François Revol + */ + +void bayer2rgb32le(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT) +{ + long int i; + unsigned char *rawpt, *scanpt; + long int size; + + rawpt = src; + scanpt = dst; + size = WIDTH*HEIGHT; + + for ( i = 0; i < size; i++ ) { + if ( (i/WIDTH) % 2 == 0 ) { + if ( (i % 2) == 0 ) { + /* B */ + if ( (i > WIDTH) && ((i % WIDTH) > 0) ) { + *scanpt++ = *rawpt; /* B */ + *scanpt++ = (*(rawpt-1)+*(rawpt+1)+ + *(rawpt+WIDTH)+*(rawpt-WIDTH))/4; /* G */ + *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+ + *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; /* R */ + } else { + /* first line or left column */ + *scanpt++ = *rawpt; /* B */ + *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2; /* G */ + *scanpt++ = *(rawpt+WIDTH+1); /* R */ + } + } else { + /* (B)G */ + if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) { + *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* B */ + *scanpt++ = *rawpt; /* G */ + *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2; /* R */ + } else { + /* first line or right column */ + *scanpt++ = *(rawpt-1); /* B */ + *scanpt++ = *rawpt; /* G */ + *scanpt++ = *(rawpt+WIDTH); /* R */ + } + } + } else { + if ( (i % 2) == 0 ) { + /* G(R) */ + if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) { + *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2; /* B */ + *scanpt++ = *rawpt; /* G */ + *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* R */ + } else { + /* bottom line or left column */ + *scanpt++ = *(rawpt-WIDTH); /* B */ + *scanpt++ = *rawpt; /* G */ + *scanpt++ = *(rawpt+1); /* R */ + } + } else { + /* R */ + if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) { + *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+ + *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; /* B */ + *scanpt++ = (*(rawpt-1)+*(rawpt+1)+ + *(rawpt-WIDTH)+*(rawpt+WIDTH))/4; /* G */ + *scanpt++ = *rawpt; /* R */ + } else { + /* bottom line or right column */ + *scanpt++ = *(rawpt-WIDTH-1); /* B */ + *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2; /* G */ + *scanpt++ = *rawpt; /* R */ + } + } + } + rawpt++; + scanpt++; + } + +} + + diff --git a/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.h b/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.h new file mode 100644 index 0000000000..fe26b6309a --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.h @@ -0,0 +1,101 @@ +#ifndef _SONIX_CAM_DEVICE_H +#define _SONIX_CAM_DEVICE_H + +#include "CamDevice.h" + +#define SN9C102_REG_COUNT 0x20 +/* SN9c102 registers */ +#define SN9C102_ASIC_ID 0x00 +#define SN9C102_CHIP_CTRL 0x01 +#define SN9C102_GPIO 0x02 +#define SN9C102_I2C_SETUP 0x08 +#define SN9C102_I2C_SLAVE_ID 0x09 +#define SN9C102_I2C_DATA0 0x0a +#define SN9C102_I2C_DATA1 0x0b +#define SN9C102_I2C_DATA2 0x0c +#define SN9C102_I2C_DATA3 0x0d +#define SN9C102_I2C_DATA4 0x0e +#define SN9C102_CONTROL_STAT 0x0f /*I2C ??*/ +#define SN9C102_R_B_GAIN 0x10 +#define SN9C102_G_GAIN 0x11 /* Green channel gain control. -> Gain = (1+G_GAIN/8) + Note: It is sync with VSYNC */ +#define SN9C102_H_START 0x12 /* Start active pixel number after H­sync of sensor + Note: + The 1st line sequence of image data is BGBGBG + The 2nd line sequence of image data is GRGRGR */ +#define SN9C102_V_START 0x13 /* Start active line number after V­sync of sensor */ +#define SN9C102_OFFSET 0x14 /* Offset adjustment for sensor image data. */ +#define SN9C102_H_SIZE 0x15 /* Horizontal pixel number for sensor. */ +#define SN9C102_V_SIZE 0x16 /* Vertical pixel number for sensor. */ +#define SN9C102_CLOCK_SEL 0x17 +#define SN9C102_SYNC_N_SCALE 0x18 +#define SN9C102_PIX_CLK 0x19 +#define SN9C102_HO_SIZE 0x1a /* /32 */ +#define SN9C102_VO_SIZE 0x1b /* /32 */ +#define SN9C102_AE_STRX 0x1c +#define SN9C102_AE_STRY 0x1d +#define SN9C102_AE_ENDX 0x1e +#define SN9C102_AE_ENDY 0x1f + +// This class represents each webcam +class SonixCamDevice : public CamDevice +{ + public: + SonixCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device); + ~SonixCamDevice(); + virtual bool SupportsBulk(); + virtual bool SupportsIsochronous(); + virtual status_t StartTransfer(); + virtual status_t StopTransfer(); + + // generic register-like access + virtual ssize_t WriteReg(uint16 address, uint8 *data, size_t count=1); + virtual ssize_t ReadReg(uint16 address, uint8 *data, size_t count=1, bool cached=false); + + // I2C-like access + virtual status_t GetStatusIIC(); + virtual status_t WaitReadyIIC(); + virtual ssize_t WriteIIC(uint8 address, uint8 *data, size_t count=1); + virtual ssize_t ReadIIC(uint8 address, uint8 *data); + + virtual status_t SetVideoFrame(BRect rect); + virtual status_t SetScale(float scale); + virtual status_t SetVideoParams(float brightness, float contrast, float hue, float red, float green, float blue); + + // for use by deframer + virtual size_t MinRawFrameSize(); + virtual size_t MaxRawFrameSize(); + virtual bool ValidateStartOfFrameTag(const uint8 *tag, size_t taglen); + virtual bool ValidateEndOfFrameTag(const uint8 *tag, size_t taglen, size_t datalen); + + virtual status_t GetFrameBitmap(BBitmap **bm); + virtual status_t FillFrameBuffer(BBuffer *buffer); + + + void DumpRegs(); + + private: + status_t SendCommand(uint8 dir, uint8 request, uint16 value, + uint16 index, uint16 length, void* data); + uint8 fCachedRegs[SN9C102_REG_COUNT]; + int fChipVersion; + + int fFrameTagState; +}; + +// the addon itself, that instanciate + +class SonixCamDeviceAddon : public CamDeviceAddon +{ + public: + SonixCamDeviceAddon(WebCamMediaAddOn* webcam); + virtual ~SonixCamDeviceAddon(); + + virtual const char *BrandName(); + virtual SonixCamDevice *Instantiate(CamRoster &roster, BUSBDevice *from); + +}; + + + +#endif /* _SONIX_CAM_DEVICE_H */ diff --git a/src/add-ons/media/media-add-ons/usb_webcam/cstransforms/Bayer.cpp b/src/add-ons/media/media-add-ons/usb_webcam/cstransforms/Bayer.cpp new file mode 100644 index 0000000000..a9cef773b5 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/cstransforms/Bayer.cpp @@ -0,0 +1,51 @@ +/* + * Bayer to RGB32 colorspace transformation + */ + +#include "CamColorSpaceTransform.h" + +class BayerTransform : public CamColorSpaceTransform +{ + public: + BayerTransform(); + virtual ~BayerTransform(); + + virtual const char* Name(); + virtual color_space OutputSpace(); + +// virtual status_t SetVideoFrame(BRect rect); +// virtual BRect VideoFrame() const { return fVideoFrame; }; + + private: +}; + +// ----------------------------------------------------------------------------- +BayerTransform::BayerTransform() +{ +} + +// ----------------------------------------------------------------------------- +BayerTransform::~BayerTransform() +{ +} + +// ----------------------------------------------------------------------------- +const char * +BayerTransform::Name() +{ + return "bayer"; +} + +// ----------------------------------------------------------------------------- +color_space +BayerTransform::OutputSpace() +{ + return B_RGB32; +} + +// ----------------------------------------------------------------------------- + + + +B_WEBCAM_DECLARE_CSTRANSFORM(BayerTransform, bayer) + diff --git a/src/add-ons/media/media-add-ons/usb_webcam/makefile b/src/add-ons/media/media-add-ons/usb_webcam/makefile new file mode 100644 index 0000000000..7d6755bc6f --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/makefile @@ -0,0 +1,204 @@ +## ********************************* ## +## Zeta Generic Makefile v3.0 ## + +## Fill in this file to specify the project being created, and the referenced +## makefile-engine will do all of the hard work for you. + +## Application Specific Settings --------------------------------------------- + +# specify the name of the binary +NAME := webcam.media_addon + +# specify the type of binary +# APP: Application +# SHARED: Shared library or add-on +# STATIC: Static library archive +# DRIVER: Kernel Driver +# MODULE: Kernel Module +# DECOR: A window decorator project +TYPE := ADDON + +# add support for new Pe and Eddie features +# to fill in generic makefile + +#%{ +# @src->@ + +# specify the source files to use +# full paths or paths relative to the makefile can be included +# all files, regardless of directory, will have their object +# files created in the common object directory. +# Note that this means this makefile will not work correctly +# if two source files with the same name (source.c or source.cpp) +# are included from different directories. Also note that spaces +# in folder names do not work well with this makefile. +SRCS := $(wildcard *.cpp) \ +$(wildcard addons/*/*.cpp) \ +$(wildcard sensors/*/*.cpp) \ +$(wildcard cstransforms/*.cpp) + +# specify the resource files to use +# full path or a relative path to the resource file can be used. +RSRCS := + +# Specify your RDEF files, if any. +RDEFS := + +# @<-src@ +#%} + +# end support for Pe and Eddie + +# specify additional libraries to link against +# there are two acceptable forms of library specifications +# - if your library follows the naming pattern of: +# libXXX.so or libXXX.a you can simply specify XXX +# library: libbe.so entry: be +# +# - if your library does not follow the standard library +# naming scheme you need to specify the path to the library +# and it's name +# library: my_lib.a entry: my_lib.a or path/my_lib.a +LIBS := be media usb + +# specify additional paths to directories following the standard +# libXXX.so or libXXX.a naming scheme. You can specify full paths +# or paths relative to the makefile. The paths included may not +# be recursive, so include all of the paths where libraries can +# be found. Directories where source files are found are +# automatically included. +LIBPATHS := /system/lib + +# additional paths to look for system headers +# thes use the form: #include
+# source file directories are NOT auto-included here +SYSTEM_INCLUDE_PATHS := + +# additional paths to look for local headers +# thes use the form: #include "header" +# source file directories are automatically included +LOCAL_INCLUDE_PATHS := + +# specify the level of optimization that you desire +# NONE, SOME, FULL +OPTIMIZE := + +# specify any preprocessor symbols to be defined. The symbols will not +# have their values set automatically; you must supply the value (if any) +# to use. For example, setting DEFINES to "DEBUG=1" will cause the +# compiler option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" +# would pass "-DDEBUG" on the compiler's command line. +DEFINES := + +# specify special warning levels +# if unspecified default warnings will be used +# NONE = supress all warnings +# ALL = enable all warnings +WARNINGS := + +# specify whether image symbols will be created +# so that stack crawls in the debugger are meaningful +# if TRUE symbols will be created +SYMBOLS := + +# specify debug settings +# if TRUE will allow application to be run from a source-level +# debugger. Note that this will disable all optimzation. +DEBUGGER := + +# specify additional compiler flags for all files +COMPILER_FLAGS := + +# specify additional linker flags +LINKER_FLAGS := + +# specify the version of this particular item +# (for example, -app 3 4 0 d 0 -short 340 -long "340 "`echo -n -e '\302\251'`"1999 GNU GPL") +#E This may also be specified in a resource. +APP_VERSION := + +# (for TYPE == DRIVER only) Specify desired location of driver in the /dev +# hierarchy. Used by the driverinstall rule. E.g., DRIVER_PATH = video/usb will +# instruct the driverinstall rule to place a symlink to your driver's binary in +# ~/add-ons/kernel/drivers/dev/video/usb, so that your driver will appear at +# /dev/video/usb when loaded. Default is "misc". +DRIVER_PATH := + +# Specify if you want the object files to be somewhere besides the default location. +OBJ_DIR := + +# Specify a non default placement for the target +TARGET_DIR := + +# Specify a directory for the 'install' target. +INSTALL_DIR := + +# Specify the name of this makefile. +# If you leave this blank, the makefile will not be considered as part of the +# dependenies for the project, and the project will not be rebuilt when the makefile +# is changed +MAKEFILE := + +# Specify TRUE if you want the install target to create links in the BeMenu +MENU_LINKS := + +# Related to MENU_LINKS, specify the name of the direcotry in the BeMenu +# you wish the link to go in. If the directory does not exist, it will be +# created. +APP_MENU := + +# If, for some reason, you don't want to use the dependencies (flex and yacc seem to choke +# on them), set this to false +DODEPS := + +# Set this variable if you have an svg text file you wish to use as your targets +# icon. +SVG_ICON := + +# If you have some fancy custom build steps to do, specify them here +EXTRA_BUILD_STEPS = + +# If you have some other files that should trigger a re-link, such as libs in the same +# project that may get rebuilt, specify the full path to them here. +EXTRA_DEPS := + +########################################################################################### +# The following variables are commented out here because the can be very useful to just +# set at the command line or in the env at time of compiling, allowing you to leave your +# makefile the same, but change the build types easily. + + +# If you wish to have the program output a profiling session file which can be read by bprof, +# set this to 'true' +#BUILD_PROFILE := + +# If you wish to have a debug build, +# set this to 'true' +#BUILD_DEBUG := + +# If you wish to have a build which can do memory checking when MALLOC_DEBUG=15 is set, +# set this to 'true' +#CHECK_MEM := + +# If you want to see the complete build line for every file, then set this to 'true', +# otherwise it will tell you at the end what the build flags were. +#CHATTY := + + + +## include the makefile-engine +include $(BUILDHOME)/etc/makefile-engine + +CamRoster.cpp: CamInternalAddons.h +CamDevice.cpp: CamInternalSensors.h +CamColorSpaceTransform.cpp: CamInternalColorSpaceTransforms.h + +CamInternalAddons.h: $(wildcard addons/*/*CamDevice.cpp) + grep -h B_WEBCAM_MKINTFUNC $(CURDIR)/addons/*/*CamDevice.cpp > $@ + +CamInternalSensors.h: $(wildcard sensors/*/*.cpp) + grep -h B_WEBCAM_DECLARE_SENSOR $(CURDIR)/sensors/*/*.cpp > $@ + +CamInternalColorSpaceTransforms.h: $(wildcard cstransforms/*.cpp) + grep -h B_WEBCAM_DECLARE_CSTRANSFORM $(CURDIR)/cstransforms/*.cpp > $@ + diff --git a/src/add-ons/media/media-add-ons/usb_webcam/sensors/hdcs1000/hdcs1000.cpp b/src/add-ons/media/media-add-ons/usb_webcam/sensors/hdcs1000/hdcs1000.cpp new file mode 100644 index 0000000000..7f2ad28197 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/sensors/hdcs1000/hdcs1000.cpp @@ -0,0 +1,26 @@ +/* +*/ + +#include "CamSensor.h" + +class HDCS1000Sensor : public CamSensor { +public: + HDCS1000Sensor(CamDevice *_camera); + ~HDCS1000Sensor(); +}; + +// ----------------------------------------------------------------------------- +HDCS1000Sensor::HDCS1000Sensor(CamDevice *_camera) +: CamSensor(_camera) +{ + +} + +// ----------------------------------------------------------------------------- +HDCS1000Sensor::~HDCS1000Sensor() +{ +} + +// ----------------------------------------------------------------------------- +B_WEBCAM_DECLARE_SENSOR(HDCS1000Sensor, hdcs1000) + diff --git a/src/add-ons/media/media-add-ons/usb_webcam/sensors/hv7131e1/hv7131e1.cpp b/src/add-ons/media/media-add-ons/usb_webcam/sensors/hv7131e1/hv7131e1.cpp new file mode 100644 index 0000000000..0d96c49d61 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/sensors/hv7131e1/hv7131e1.cpp @@ -0,0 +1,35 @@ +/* +*/ + +#include "CamSensor.h" + +class HV7131E1Sensor : public CamSensor { +public: + HV7131E1Sensor(CamDevice *_camera); + ~HV7131E1Sensor(); + const char* Name(); + +}; + +// ----------------------------------------------------------------------------- +HV7131E1Sensor::HV7131E1Sensor(CamDevice *_camera) +: CamSensor(_camera) +{ + +} + +// ----------------------------------------------------------------------------- +HV7131E1Sensor::~HV7131E1Sensor() +{ +} + +// ----------------------------------------------------------------------------- +const char * +HV7131E1Sensor::Name() +{ + return "Hynix hv7131e1"; +} + +// ----------------------------------------------------------------------------- +B_WEBCAM_DECLARE_SENSOR(HV7131E1Sensor, hv7131e1) + diff --git a/src/add-ons/media/media-add-ons/usb_webcam/sensors/tas5110c1b/tas5110c1b.cpp b/src/add-ons/media/media-add-ons/usb_webcam/sensors/tas5110c1b/tas5110c1b.cpp new file mode 100644 index 0000000000..ed34272d9c --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/sensors/tas5110c1b/tas5110c1b.cpp @@ -0,0 +1,114 @@ +/* +*/ + +#include "CamSensor.h" +#include "CamDebug.h" +#include "addons/sonix/SonixCamDevice.h" + +class TAS5110C1BSensor : public CamSensor { +public: + TAS5110C1BSensor(CamDevice *_camera); + ~TAS5110C1BSensor(); + virtual status_t Setup(); + const char *Name(); + virtual bool Use400kHz() const { return false; }; + virtual bool UseRealIIC() const { return false; }; + virtual uint8 IICReadAddress() const { return 0x00; }; + virtual uint8 IICWriteAddress() const { return 0xff; }; + virtual int MaxWidth() const { return 352; }; + virtual int MaxHeight() const { return 288; }; + virtual status_t SetVideoFrame(BRect rect); +private: + bool fIsSonix; +}; + +// ----------------------------------------------------------------------------- +TAS5110C1BSensor::TAS5110C1BSensor(CamDevice *_camera) +: CamSensor(_camera) +{ + fIsSonix = (dynamic_cast(_camera) != NULL); + if (fIsSonix) { + fInitStatus = B_OK; + } else { + PRINT((CH ": unknown camera device!" CT)); + fInitStatus = ENODEV; + } +} + +// ----------------------------------------------------------------------------- +TAS5110C1BSensor::~TAS5110C1BSensor() +{ +} + +// ----------------------------------------------------------------------------- +status_t +TAS5110C1BSensor::Setup() +{ + PRINT((CH "()" CT)); + if (InitCheck()) + return InitCheck(); + if (fIsSonix) { + Device()->WriteReg8(SN9C102_CHIP_CTRL, 0x01); /* power down the sensor */ + Device()->WriteReg8(SN9C102_CHIP_CTRL, 0x44); /* power up the sensor, enable tx, sysclk@24MHz */ + Device()->WriteReg8(SN9C102_R_B_GAIN, 0x00); /* red, blue gain = 1+0/8 = 1 */ + Device()->WriteReg8(SN9C102_G_GAIN, 0x00); /* green gain = 1+0/8 = 1 */ + Device()->WriteReg8(SN9C102_OFFSET, 0x0a); /* 10 pix offset */ + Device()->WriteReg8(SN9C102_CLOCK_SEL, 0x60); /* enable sensor clk, and invert it */ + Device()->WriteReg8(SN9C102_SYNC_N_SCALE, 0x06); /* no compression, normal curve, + * no scaling, vsync active low, + * v/hsync change at rising edge, + * falling edge of sensor pck */ + Device()->WriteReg8(SN9C102_PIX_CLK, 0xfb); /* pixclk = 2 * masterclk, sensor is slave mode */ + } + + //sonix_i2c_write_multi(dev, dev->sensor->i2c_wid, 2, 0xc0, 0x80, 0, 0, 0); /* AEC = 0x203 ??? */ + Device()->WriteIIC8(0xc0, 0x80); /* AEC = 0x203 ??? */ + + if (fIsSonix) { + // set crop + Device()->WriteReg8(SN9C102_H_SIZE, 69); + Device()->WriteReg8(SN9C102_V_SIZE, 9); + Device()->WriteReg8(SN9C102_PIX_CLK, 0xfb); + Device()->WriteReg8(SN9C102_HO_SIZE, 0x14); + Device()->WriteReg8(SN9C102_VO_SIZE, 0x0a); + fVideoFrame.Set(0, 0, 352-1, 288-1); + /* HACK: TEST IMAGE */ + //Device()->WriteReg8(SN_CLOCK_SEL, 0x70); /* enable sensor clk, and invert it, test img */ + + } + + //Device()->SetScale(1); + + return B_OK; +} + +// ----------------------------------------------------------------------------- +const char * +TAS5110C1BSensor::Name() +{ + return "TASC tas5110c1b"; +} + +// ----------------------------------------------------------------------------- +status_t +TAS5110C1BSensor::SetVideoFrame(BRect rect) +{ + if (fIsSonix) { + // set crop + Device()->WriteReg8(SN9C102_H_START, /*rect.left + */69); + Device()->WriteReg8(SN9C102_V_START, /*rect.top + */9); + Device()->WriteReg8(SN9C102_PIX_CLK, 0xfb); + Device()->WriteReg8(SN9C102_HO_SIZE, 0x14); + Device()->WriteReg8(SN9C102_VO_SIZE, 0x0a); + fVideoFrame = rect; + /* HACK: TEST IMAGE */ + //Device()->WriteReg8(SN9C102_CLOCK_SEL, 0x70); /* enable sensor clk, and invert it, test img */ + + } + + return B_OK; +} + +// ----------------------------------------------------------------------------- +B_WEBCAM_DECLARE_SENSOR(TAS5110C1BSensor, tas5110c1b) +