parent
5682fcd9b8
commit
168c5a831f
@ -0,0 +1,57 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <UDPTCPNetwork.h>
|
||||
#include "inmemoryfile.h"
|
||||
|
||||
InMemoryFile::InMemoryFile() {
|
||||
mem = malloc (INMEMORYFILE_ALLOCATEBLOCK);
|
||||
memallocsize = INMEMORYFILE_ALLOCATEBLOCK;
|
||||
memsize = 0;
|
||||
};
|
||||
|
||||
InMemoryFile::~InMemoryFile() {
|
||||
if (mem != NULL) free (mem);
|
||||
mem = NULL;
|
||||
memallocsize = 0;
|
||||
memsize = 0;
|
||||
};
|
||||
|
||||
|
||||
int InMemoryFile::Allocate(size_t newsize) {
|
||||
// shrink size only if new memory block is smaller then 25%
|
||||
if ((newsize < memallocsize / 4) || (newsize > memallocsize)) {
|
||||
memallocsize = (1+(newsize/INMEMORYFILE_ALLOCATEBLOCK))*INMEMORYFILE_ALLOCATEBLOCK;
|
||||
memsize = newsize;
|
||||
mem = realloc(mem, memallocsize);
|
||||
if (mem == NULL || memsize > memallocsize) {
|
||||
debug ("could not reallocate memory memsize:%d memallocsize:%d\n.", memsize, memallocsize);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
InMemoryFile InMemoryFile::operator=(InMemoryFile rightside) {
|
||||
memsize = rightside.memsize;
|
||||
memallocsize = 1+(memsize/INMEMORYFILE_ALLOCATEBLOCK)*INMEMORYFILE_ALLOCATEBLOCK;
|
||||
mem = realloc(mem, memallocsize+1);
|
||||
if (mem == NULL || memsize > memallocsize) {
|
||||
debug ("could not reallocate memory: %s\n.", strerror(errno));
|
||||
exit (1);
|
||||
}
|
||||
memcpy (mem, rightside.mem, memsize);
|
||||
|
||||
return *this;
|
||||
};
|
||||
|
||||
|
||||
/// @brief copy the memory.
|
||||
/// @param srcptr pointer to the source memory
|
||||
/// @param srcsize size of the memory
|
||||
/// @return 1 on success, 0 on error
|
||||
int InMemoryFile::CopyFrom(void *srcptr, size_t srcsize) {
|
||||
if (Allocate (srcsize) == 0) return 0;
|
||||
memcpy (mem, srcptr, memsize);
|
||||
return 1;
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
#ifndef _INMEMORYFILE_H_
|
||||
#define _INMEMORYFILE_H_
|
||||
|
||||
|
||||
#define INMEMORYFILE_ALLOCATEBLOCK 4096
|
||||
class InMemoryFile {
|
||||
private:
|
||||
size_t memallocsize;
|
||||
public:
|
||||
void *mem;
|
||||
size_t memsize;
|
||||
|
||||
InMemoryFile operator=(InMemoryFile rightside);
|
||||
|
||||
InMemoryFile();
|
||||
~InMemoryFile();
|
||||
|
||||
int Allocate(size_t newsize);
|
||||
int CopyFrom(void *srcptr, size_t srcsize);
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,108 +1,520 @@
|
||||
|
||||
#include "miniwebcam.h"
|
||||
#include "video.h"
|
||||
#include "convert.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
VideoFrame::VideoFrame() {
|
||||
mem = NULL;
|
||||
width = 0;
|
||||
height = 0;
|
||||
mem_allocated = 0;
|
||||
|
||||
|
||||
VideoDevice::VideoDevice() {
|
||||
};
|
||||
|
||||
VideoFrame::~VideoFrame() {
|
||||
FreeFrame();
|
||||
|
||||
VideoDevice::~VideoDevice() {
|
||||
|
||||
};
|
||||
|
||||
|
||||
void VideoFrame::FreeFrame() {
|
||||
if (mem != NULL) {
|
||||
free (mem);
|
||||
mem = NULL;
|
||||
width = 0;
|
||||
height = 0;
|
||||
mem_allocated = 0;
|
||||
}
|
||||
VideoDevice_V4L2::VideoDevice_V4L2() {
|
||||
conf_height = 0;
|
||||
conf_width = 0;
|
||||
conf_videodev = "";
|
||||
conf_iomode = 0;
|
||||
fd = -1;
|
||||
};
|
||||
|
||||
|
||||
void VideoFrame::AllocateFrame() {
|
||||
printf ("VideoFrame::AllocateFrame()\n");
|
||||
int memnewsize = width * height * 3;
|
||||
if (memnewsize >= mem_allocated) return;
|
||||
else if (memnewsize == 0) FreeFrame();
|
||||
VideoDevice_V4L2::~VideoDevice_V4L2() {
|
||||
if (fd != 0) Stop();
|
||||
};
|
||||
|
||||
|
||||
|
||||
int VideoDevice_V4L2::SetDevice(std::string newdevice, int nwidth, int nheight) {
|
||||
int isrunning = 0;
|
||||
|
||||
if (fd != -1) {
|
||||
Stop();
|
||||
isrunning = 1;
|
||||
}
|
||||
|
||||
mem = (unsigned char *) realloc (mem, memnewsize);
|
||||
mem_allocated = memnewsize;
|
||||
conf_videodev = newdevice;
|
||||
conf_width = nwidth;
|
||||
conf_height = nheight;
|
||||
|
||||
if (mem == NULL) {
|
||||
debug ("Error on allocation new frame\n");
|
||||
exit (1);
|
||||
if (isrunning) {
|
||||
if (Start() == 0) return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
int VideoFrame::SetSize(int w, int h) {
|
||||
if (w < 0 && h < 0) return 0;
|
||||
int VideoDevice_V4L2::SetIOMode(int newiomode) {
|
||||
int isrunning = 0;
|
||||
|
||||
width = w;
|
||||
height = h;
|
||||
if (fd != -1) {
|
||||
Stop();
|
||||
isrunning = 1;
|
||||
}
|
||||
|
||||
AllocateFrame();
|
||||
conf_iomode = newiomode;
|
||||
|
||||
if (isrunning) {
|
||||
if (Start() == 0) return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
/*********************************************************************/
|
||||
int VideoDevice_V4L2::Open() {
|
||||
int i;
|
||||
struct v4l2_capability vcap;
|
||||
VideoDevCtrl vctl;
|
||||
char txt[32];
|
||||
|
||||
debug ("Device: '%s'", conf_videodev.c_str());
|
||||
if (fd != -1) return 0;
|
||||
|
||||
//
|
||||
// open device and get device name and capabilities | O_NONBLOCK
|
||||
if((fd = open(conf_videodev.c_str(), O_RDWR)) == -1){
|
||||
debug ("could not open device error: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(ioctl(fd, VIDIOC_QUERYCAP, &vcap) == -1)
|
||||
strncpy ((char*)&vcap.card, "unknown", sizeof(vcap.card));
|
||||
debug ("VideoDevice_V4L2::Open Devicefile:%s Card:%s fd:%d", conf_videodev.c_str(), vcap.card, fd);
|
||||
|
||||
debug ("Capabilities: %u", vcap.capabilities);
|
||||
PrintCaps(vcap.capabilities);
|
||||
debug ("Device Capabilities: %u", vcap.device_caps);
|
||||
PrintCaps(vcap.device_caps);
|
||||
|
||||
if (!(vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
|
||||
debug ("Error: device has no video capture capabilities");
|
||||
return 0;
|
||||
Close();
|
||||
}
|
||||
|
||||
//
|
||||
// query controls
|
||||
struct v4l2_queryctrl queryctrl;
|
||||
uint32_t min;
|
||||
debug ("Get Controls");
|
||||
|
||||
vidctrls.clear();
|
||||
memset (&queryctrl, 0, sizeof (queryctrl));
|
||||
for (i = V4L2_CID_BASE; i < V4L2_CID_DETECT_CLASS_BASE+0x1000; i++) {
|
||||
queryctrl.id = i;
|
||||
if (0 == ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) {
|
||||
vctl.name = (char*)queryctrl.name;
|
||||
vctl.id = queryctrl.id;
|
||||
vctl.min = queryctrl.minimum;
|
||||
vctl.max = queryctrl.maximum;
|
||||
GetDevCtrl(queryctrl.id, &vctl.value);
|
||||
vidctrls.push_back(vctl);
|
||||
}
|
||||
}
|
||||
debug ("got %d controls.", vidctrls.size());
|
||||
|
||||
//
|
||||
// check for cropping.. if we have it setup default
|
||||
debug ("setup cropping");
|
||||
CLEAR (cropcap);
|
||||
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
|
||||
if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
|
||||
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
crop.c = cropcap.defrect; // reset to default
|
||||
|
||||
if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) {
|
||||
debug ("VIDEOC_S_CROP Errorcode: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// prepare resolution and pixelformat
|
||||
debug ("setup video resolution and pixeltype");
|
||||
CLEAR (fmt);
|
||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (conf_width != -1 && conf_height != -1) { // resolution
|
||||
fmt.fmt.pix.width = conf_width;
|
||||
fmt.fmt.pix.height = conf_height;
|
||||
}
|
||||
else {
|
||||
fmt.fmt.pix.width = 1920;
|
||||
fmt.fmt.pix.height = 1080;
|
||||
}
|
||||
|
||||
// fixme: hardcoded video format?????
|
||||
fmt.fmt.pix.pixelformat = convert_to_pixelformat(conf_videofmt);
|
||||
fmt.fmt.pix.field = V4L2_FIELD_NONE;
|
||||
if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)) {
|
||||
debug ("VIDIOC_S_FMT : %s", strerror (errno));
|
||||
close (fd);
|
||||
fd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Note VIDIOC_S_FMT may change width and height.
|
||||
// Buggy driver paranoia. - as written in the v4l2 api documentation
|
||||
min = fmt.fmt.pix.width * 2;
|
||||
if (fmt.fmt.pix.bytesperline < min)
|
||||
fmt.fmt.pix.bytesperline = min;
|
||||
min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
|
||||
if (fmt.fmt.pix.sizeimage < min)
|
||||
fmt.fmt.pix.sizeimage = min;
|
||||
conf_width = fmt.fmt.pix.width;
|
||||
conf_height = fmt.fmt.pix.height;
|
||||
snprintf (txt, 32, "%c%c%c%c", ((char*)&fmt.fmt.pix.pixelformat)[0],
|
||||
((char*)&fmt.fmt.pix.pixelformat)[1],
|
||||
((char*)&fmt.fmt.pix.pixelformat)[2],
|
||||
((char*)&fmt.fmt.pix.pixelformat)[3]);
|
||||
conf_videofmt = txt;
|
||||
PrintFmt (&fmt);
|
||||
|
||||
// init buffers
|
||||
switch (conf_iomode) {
|
||||
case IOMODE_MMAP:
|
||||
if (InitMMap() == 0) {
|
||||
debug ("could not setup MMap (memory mapping)");
|
||||
Close();
|
||||
}
|
||||
break;
|
||||
case IOMODE_READ:
|
||||
for (i = 0; i < VDEV_INBUFFERS; i++) {
|
||||
inbuffer[i].size = fmt.fmt.pix.sizeimage;
|
||||
inbuffer[i].data = (unsigned char*) malloc (fmt.fmt.pix.sizeimage);
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
void VideoFrameFloat::AllocateFrame() {
|
||||
printf ("VideoFrameFloat::AllocateFrame()\n");
|
||||
int memnewsize = width * height * 3 * sizeof(float);
|
||||
if (memnewsize >= mem_allocated) return;
|
||||
else if (memnewsize == 0) FreeFrame();
|
||||
int VideoDevice_V4L2::InitMMap() {
|
||||
struct v4l2_requestbuffers bufreq;
|
||||
struct v4l2_buffer bufinfo;
|
||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
mem = (unsigned char *) realloc (mem, memnewsize);
|
||||
mem_allocated = memnewsize;
|
||||
int i;
|
||||
|
||||
CLEAR(bufreq);
|
||||
CLEAR(bufinfo);
|
||||
|
||||
bufreq.count = VDEV_INBUFFERS;
|
||||
bufreq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
bufreq.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
if (-1 == xioctl(fd, VIDIOC_REQBUFS, &bufreq)) {
|
||||
if (EINVAL == errno) {
|
||||
printf("%s does not support memory mapping", conf_videodev.c_str());
|
||||
return 0;
|
||||
} else {
|
||||
printf ("%s:%d %s Error %s\n", __FILE__, __LINE__, __FUNCTION__, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (bufreq.count < 1) {
|
||||
printf ( "Insufficient buffer memory on %s\n", conf_videodev.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mem == NULL) {
|
||||
debug ("Error on allocation new frame\n");
|
||||
exit (1);
|
||||
for (i = 0; i < VDEV_INBUFFERS; i++) {
|
||||
CLEAR(bufinfo);
|
||||
bufinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
bufinfo.memory = V4L2_MEMORY_MMAP;
|
||||
bufinfo.index = i;
|
||||
|
||||
if(ioctl(fd, VIDIOC_QUERYBUF, &bufinfo) < 0){
|
||||
perror("VIDIOC_QUERYBUF");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
inbuffer[i].size = bufinfo.length;
|
||||
inbuffer[i].data = (unsigned char*)mmap(NULL, bufinfo.length, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, fd, bufinfo.m.offset);
|
||||
if (inbuffer[i].data == MAP_FAILED) {
|
||||
printf ( "%s:%d error on mmap %s\n", __FILE__, __LINE__, strerror(errno));
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int VideoDevice_V4L2::Close() {
|
||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (fd >= 0) {
|
||||
UnInit();
|
||||
close (fd);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
/*********************************************************************/
|
||||
int VideoDevice_V4L2::UnInit() {
|
||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
switch (conf_iomode) {
|
||||
case IOMODE_READ:
|
||||
for (inbuffer_idx = 0; inbuffer_idx < VDEV_INBUFFERS; inbuffer_idx++) {
|
||||
if (inbuffer[inbuffer_idx].data) {
|
||||
free (inbuffer[inbuffer_idx].data);
|
||||
inbuffer[inbuffer_idx].data = NULL;
|
||||
inbuffer[inbuffer_idx].size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case IOMODE_MMAP:
|
||||
for (inbuffer_idx = 0; inbuffer_idx < VDEV_INBUFFERS; inbuffer_idx++)
|
||||
if (inbuffer[inbuffer_idx].data) {
|
||||
if (-1 == munmap(inbuffer[inbuffer_idx].data, inbuffer[inbuffer_idx].size)){
|
||||
fprintf(stderr, "Fatal Error @ %s:%d munmap Error:%s\n", __FILE__, __LINE__, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
inbuffer[inbuffer_idx].data = NULL;
|
||||
inbuffer[inbuffer_idx].size = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
printf ("%s:%d %s wrong IOMODE?\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
VideoDevice::VideoDevice() {
|
||||
videofd = 0;
|
||||
|
||||
int VideoDevice_V4L2::Start() {
|
||||
enum v4l2_buf_type type;
|
||||
|
||||
debug ("");
|
||||
|
||||
if (Open() == 0) {
|
||||
debug ("VideoDevice_V4L2::Start Open Device Failed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (conf_iomode) {
|
||||
case IOMODE_READ:
|
||||
/* Nothing to do. */
|
||||
break;
|
||||
|
||||
case IOMODE_MMAP:
|
||||
struct v4l2_buffer buf;
|
||||
|
||||
for (inbuffer_idx = 0; inbuffer_idx < VDEV_INBUFFERS; inbuffer_idx++) {
|
||||
CLEAR(buf);
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = inbuffer_idx;
|
||||
|
||||
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) {
|
||||
debug ("error on VIDIOC_QBUF %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inbuffer_idx = 0;
|
||||
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) {
|
||||
debug ("VIDIOC_STREAMON %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
debug ("wrong IOMODE?");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ConvertStart(&cdata, fmt.fmt.pix.pixelformat);
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
VideoDevice::~VideoDevice() {
|
||||
int VideoDevice_V4L2::Stop() {
|
||||
enum v4l2_buf_type type;
|
||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
ConvertStop(&cdata, fmt.fmt.pix.pixelformat);
|
||||
|
||||
switch (conf_iomode) {
|
||||
case IOMODE_READ:
|
||||
/* Nothing to do. */
|
||||
break;
|
||||
case IOMODE_MMAP:
|
||||
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type)) {
|
||||
fprintf(stderr, "%s:%d VIDIOC_STREAMOFF Error:%s\n", __FILE__, __LINE__, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf ("%s:%d %s wrong IOMODE?\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
Close();
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
int VideoDevice_V4L2::GetFrame(VideoFrame *destframe) {
|
||||
struct v4l2_buffer buf;
|
||||
int len;
|
||||
|
||||
if (destframe == NULL) return 0;
|
||||
|
||||
switch (conf_iomode) {
|
||||
case IOMODE_READ:
|
||||
if ((len = read (fd, inbuffer[0].data, fmt.fmt.pix.sizeimage)) == -1) {
|
||||
switch (errno) {
|
||||
case EAGAIN:
|
||||
return -1;
|
||||
case EIO:
|
||||
default:
|
||||
debug ("v4l2_grab IOM_READ: %s dest:%p size:%d", strerror (errno), destframe, fmt.fmt.pix.sizeimage);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Convert(&cdata, destframe, inbuffer[0].data, len,
|
||||
fmt.fmt.pix.pixelformat, fmt.fmt.pix.width, fmt.fmt.pix.height);
|
||||
}
|
||||
break;
|
||||
|
||||
case IOMODE_MMAP:
|
||||
CLEAR(buf);
|
||||
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
|
||||
switch (errno) {
|
||||
case EAGAIN:
|
||||
return -1;
|
||||
|
||||
case EIO:
|
||||
debug ("error on VIDIOC_DQBUF EIO %s", strerror(errno));
|
||||
return 0;
|
||||
|
||||
default:
|
||||
debug ("error on VIDIOC_DQBUF %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf.index >= 0 && buf.index < VDEV_INBUFFERS) {
|
||||
Convert(&cdata, destframe, inbuffer[buf.index].data, buf.bytesused,
|
||||
fmt.fmt.pix.pixelformat, fmt.fmt.pix.width, fmt.fmt.pix.height);
|
||||
}
|
||||
|
||||
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) {
|
||||
debug ("error on VIDIOC_QBUF %s", strerror(errno));
|
||||
return 0; }
|
||||
|
||||
if (++inbuffer_idx >= VDEV_INBUFFERS) inbuffer_idx = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
debug ("wrong IOMODE?");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
int VideoDevice::SetDevice() {
|
||||
return 0;
|
||||
int VideoDevice_V4L2::xioctl(int fd, int request, void *arg) {
|
||||
int r;
|
||||
int errnoioctl;
|
||||
struct timeval to1;
|
||||
struct timeval to2;
|
||||
float to;
|
||||
|
||||
gettimeofday(&to1, NULL);
|
||||
do {
|
||||
r = ioctl(fd, request, arg);
|
||||
errnoioctl = errno;
|
||||
gettimeofday(&to2, NULL);
|
||||
to = (float)(to2.tv_sec - to1.tv_sec) + ((to2.tv_usec - to1.tv_usec) / 1000000.0);
|
||||
} while (r == -1 && errnoioctl == EINTR && to < 2.0);
|
||||
|
||||
return r;
|
||||
};
|
||||
|
||||
|
||||
int VideoDevice::Start(int w, int h) {
|
||||
return 0;
|
||||
int VideoDevice_V4L2::SetDevCtrl(unsigned int id, int value) {
|
||||
struct v4l2_control ctrl;
|
||||
|
||||
CLEAR(ctrl);
|
||||
ctrl.id = id;
|
||||
ctrl.value = value;
|
||||
if (-1 == xioctl (fd, VIDIOC_S_CTRL, &ctrl)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
int VideoDevice::Stop() {
|
||||
return 0;
|
||||
int VideoDevice_V4L2::GetDevCtrl(unsigned int id, int *value) {
|
||||
struct v4l2_control ctrl;
|
||||
|
||||
CLEAR(ctrl);
|
||||
ctrl.id = id;
|
||||
if (-1 == xioctl (fd, VIDIOC_G_CTRL, &ctrl)) {
|
||||
return 0;
|
||||
}
|
||||
*value = ctrl.value;
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
int VideoDevice::GetFrame(VideoFrame *destframe) {
|
||||
return 0;
|
||||
void VideoDevice_V4L2::PrintCaps(uint32_t caps) {
|
||||
printf ("%s:%d %s Caps: %x\n", __FILE__, __LINE__, __FUNCTION__, caps);
|
||||
|
||||
if (caps & V4L2_CAP_VIDEO_CAPTURE) printf (" V4L2_CAP_VIDEO_CAPTURE\n");
|
||||
if (caps & V4L2_CAP_EXT_PIX_FORMAT) printf (" V4L2_CAP_EXT_PIX_FORMAT\n");
|
||||
#ifdef V4L2_CAP_META_CAPTURE
|
||||
if (caps & V4L2_CAP_META_CAPTURE) printf (" V4L2_CAP_META_CAPTURE\n");
|
||||
#endif
|
||||
if (caps & V4L2_CAP_STREAMING) printf (" V4L2_CAP_STREAMING\n");
|
||||
if (caps & V4L2_CAP_DEVICE_CAPS) printf (" V4L2_CAP_DEVICE_CAPS\n");
|
||||
if (caps & V4L2_CAP_TUNER) printf (" V4L2_CAP_TUNER\n");
|
||||
if (caps & V4L2_CAP_MODULATOR) printf (" V4L2_CAP_MODULATOR\n");
|
||||
if (caps & V4L2_CAP_READWRITE) printf (" V4L2_CAP_READWRITE\n");
|
||||
if (caps & V4L2_CAP_ASYNCIO) printf (" V4L2_CAP_ASYNCIO\n");
|
||||
};
|
||||
|
||||
|
||||
void VideoDevice_V4L2::PrintFmt(struct v4l2_format *f) {
|
||||
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
printf (" type : %u\n", f->type);
|
||||
printf (" fmt.pix.width : %d\n", f->fmt.pix.width);
|
||||
printf (" fmt.pix.height : %d\n", f->fmt.pix.height);
|
||||
printf (" fmt.fmt.pix.pixelformat : %c%c%c%c\n", ((char*)&f->fmt.pix.pixelformat)[0],
|
||||
((char*)&f->fmt.pix.pixelformat)[1],
|
||||
((char*)&f->fmt.pix.pixelformat)[2],
|
||||
((char*)&f->fmt.pix.pixelformat)[3]);
|
||||
printf (" fmt.pix.field : %d\n", f->fmt.pix.field);
|
||||
printf (" fmt.pix.bytesperline : %d\n", f->fmt.pix.bytesperline);
|
||||
printf (" fmt.pix.sizeimage : %d\n", f->fmt.pix.sizeimage);
|
||||
};
|
||||
|
||||
@ -0,0 +1,144 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <jpeglib.h>
|
||||
#include <UDPTCPNetwork.h>
|
||||
|
||||
#include "videoframe.h"
|
||||
#include "inmemoryfile.h"
|
||||
|
||||
VideoFrame::VideoFrame() {
|
||||
mem = NULL;
|
||||
width = 0;
|
||||
height = 0;
|
||||
mem_allocated = 0;
|
||||
};
|
||||
|
||||
VideoFrame::~VideoFrame() {
|
||||
FreeFrame();
|
||||
};
|
||||
|
||||
|
||||
void VideoFrame::FreeFrame() {
|
||||
if (mem != NULL) {
|
||||
free (mem);
|
||||
mem = NULL;
|
||||
width = 0;
|
||||
height = 0;
|
||||
mem_allocated = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void VideoFrame::AllocateFrame() {
|
||||
int memnewsize = width * height * 3;
|
||||
if (memnewsize < mem_allocated) return;
|
||||
else if (memnewsize == 0) FreeFrame();
|
||||
|
||||
mem = (unsigned char *) realloc (mem, memnewsize);
|
||||
mem_allocated = memnewsize;
|
||||
|
||||
if (mem == NULL) {
|
||||
debug ("Error on allocation new frame\n");
|
||||
exit (1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int VideoFrame::SetSize(int w, int h) {
|
||||
if (w < 0 && h < 0) return 0;
|
||||
|
||||
width = w;
|
||||
height = h;
|
||||
|
||||
AllocateFrame();
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
int VideoFrame::ConvertToJpeg(InMemoryFile *imf, int quality) {
|
||||
unsigned char *outbuffer = NULL;
|
||||
size_t outbuffersize;
|
||||
struct jpeg_compress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
|
||||
int row_stride; /* physical row width in image buffer */
|
||||
|
||||
if (imf == NULL) return 0;
|
||||
if (height == 0 || width == 0) return 0;
|
||||
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
jpeg_create_compress(&cinfo);
|
||||
|
||||
jpeg_mem_dest(&cinfo, &outbuffer, &outbuffersize);
|
||||
|
||||
cinfo.image_width = width; /* image width and height, in pixels */
|
||||
cinfo.image_height = height;
|
||||
cinfo.input_components = 3; /* # of color components per pixel */
|
||||
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
|
||||
jpeg_set_defaults(&cinfo);
|
||||
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
|
||||
jpeg_start_compress(&cinfo, TRUE);
|
||||
row_stride = width * 3; /* JSAMPLEs per row in image_buffer */
|
||||
|
||||
while (cinfo.next_scanline < cinfo.image_height) {
|
||||
row_pointer[0] = & mem[cinfo.next_scanline * row_stride];
|
||||
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
|
||||
}
|
||||
|
||||
jpeg_finish_compress(&cinfo);
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
|
||||
imf->CopyFrom(outbuffer, outbuffersize);
|
||||
free (outbuffer);
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
int VideoFrame::TestScreen(int w, int h) {
|
||||
int x, y;
|
||||
unsigned char r, g, b;
|
||||
|
||||
SetSize (w, h);
|
||||
|
||||
r = g = b = 0;
|
||||
for (x = 0; x < w; x++) {
|
||||
for (g = 0, y = 0; y < h; y++) {
|
||||
b = r + g;
|
||||
|
||||
mem[3*(x + y * width) + 0] = r;
|
||||
mem[3*(x + y * width) + 1] = g;
|
||||
mem[3*(x + y * width) + 2] = b;
|
||||
|
||||
g++;
|
||||
}
|
||||
r ++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
|
||||
|
||||
void VideoFrameFloat::AllocateFrame() {
|
||||
printf ("VideoFrameFloat::AllocateFrame()\n");
|
||||
int memnewsize = width * height * 3 * sizeof(float);
|
||||
if (memnewsize >= mem_allocated) return;
|
||||
else if (memnewsize == 0) FreeFrame();
|
||||
|
||||
mem = (unsigned char *) realloc (mem, memnewsize);
|
||||
mem_allocated = memnewsize;
|
||||
|
||||
if (mem == NULL) {
|
||||
debug ("Error on allocation new frame\n");
|
||||
exit (1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
#ifndef _VIDEOFRAME_H_
|
||||
#define _VIDEOFRAME_H_
|
||||
|
||||
#include "inmemoryfile.h"
|
||||
//
|
||||
// only contain 24bit each color 8Bit
|
||||
class VideoFrame {
|
||||
private:
|
||||
virtual void AllocateFrame();
|
||||
protected:
|
||||
void FreeFrame();
|
||||
int mem_allocated;
|
||||
unsigned char *mem;
|
||||
int height;
|
||||
int width;
|
||||
public:
|
||||
VideoFrame();
|
||||
~VideoFrame();
|
||||
|
||||
int GetHeight() { return height; };
|
||||
int GetWidth() { return width; };
|
||||
unsigned char *GetPixBuf() { return mem; };
|
||||
|
||||
int SetSize(int w, int h);
|
||||
int ConvertToJpeg(InMemoryFile *imf, int quality);
|
||||
int TestScreen(int w, int h);
|
||||
};
|
||||
|
||||
|
||||
class VideoFrameFloat : public VideoFrame {
|
||||
private:
|
||||
void AllocateFrame();
|
||||
protected:
|
||||
public:
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@ -1,2 +1,57 @@
|
||||
|
||||
#include "webserver.h"
|
||||
#include <unistd.h>
|
||||
|
||||
#include "miniwebcam.h"
|
||||
#include "UDPTCPNetwork.h"
|
||||
|
||||
std::string GenerateHtmlFile();
|
||||
InMemoryFile GenerateJpgFile(VideoFrame *vf);
|
||||
|
||||
int WebCamServer::HandleRequest (WebRequestBuffer *requestbuffer, WebServerClient *webclient) {
|
||||
if (requestbuffer == NULL || webclient == NULL) return 0;
|
||||
|
||||
std::string request = requestbuffer->GetRequest();
|
||||
printf ("SimpleWebServerClient::HandleRequest() Request:%s\n", request.c_str());
|
||||
|
||||
if (request.compare ("/") == 0) request = "/index.html";
|
||||
|
||||
if (request.find("/index.html") != std::string::npos) {
|
||||
std::string htmlfile = GenerateHtmlFile();
|
||||
if (webclient->SendResponseFileFromMemory(requestbuffer, request, "",
|
||||
(void*) htmlfile.c_str(),
|
||||
strlen(htmlfile.c_str())) != 1) return 0;
|
||||
}
|
||||
else if (request.find("/snapshot.jpg") != std::string::npos) {
|
||||
InMemoryFile jpgfile;
|
||||
currentimage.ConvertToJpeg(&jpgfile, 99);
|
||||
if (webclient->SendResponseFileFromMemory(requestbuffer, request, "",
|
||||
(void*) jpgfile.mem,
|
||||
jpgfile.memsize) != 1) return 0;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
requestbuffer->Clear();
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
std::string GenerateHtmlFile() {
|
||||
std::string res;
|
||||
res = "<html><head><title>MiniWebCam</title></head><body>";
|
||||
res += "<img id=\"myimage\" src=\"snapshot.jpg\"></img>";
|
||||
res += "<script>\n";
|
||||
res += " function reloadImage() {\n";
|
||||
res += " const img = document.getElementById('myimage');\n";
|
||||
res += " let src = img.src.split('?')[0];\n";
|
||||
res += " src = src + '?' + new Date().getTime();\n";
|
||||
res += " img.src = src;\n";
|
||||
res += "}\n\n";
|
||||
res += "setInterval(reloadImage, 1000);\n";
|
||||
res += "\n\n";
|
||||
res += "</script>\n";
|
||||
res += "</body></html>";
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
#ifndef _WEBSERVER_H_
|
||||
#define _WEBSERVER_H_
|
||||
|
||||
#include "miniwebcam.h"
|
||||
|
||||
#endif
|
||||
Loading…
Reference in new issue