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

📄 wisinput.cpp

📁 采用公司系列的芯片
💻 CPP
字号:
/* * Copyright (C) 2005 WIS Technologies International Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and the associated README documentation file (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */// An interface to the WIS GO7007 capture device.// Implementation#include "WISInput.hh"#include "Options.hh"#include <fcntl.h>#include <dirent.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <sys/poll.h>#include <linux/soundcard.h>#include <linux/videodev.h>#include "go7007.h"////////// WISOpenFileSource definition //////////// A common "FramedSource" subclass, used for reading from an open file:class WISOpenFileSource: public FramedSource {protected:  WISOpenFileSource(UsageEnvironment& env, WISInput& input, int fileNo);  virtual ~WISOpenFileSource();  virtual void readFromFile() = 0;private: // redefined virtual functions:  virtual void doGetNextFrame();private:  static void incomingDataHandler(WISOpenFileSource* source, int mask);  void incomingDataHandler1();protected:  WISInput& fInput;  int fFileNo;};////////// WISVideoOpenFileSource definition //////////class WISVideoOpenFileSource: public WISOpenFileSource {public:  WISVideoOpenFileSource(UsageEnvironment& env, WISInput& input);  virtual ~WISVideoOpenFileSource();protected: // redefined virtual functions:  virtual void readFromFile();};////////// WISAudioOpenFileSource definition //////////class WISAudioOpenFileSource: public WISOpenFileSource {public:  WISAudioOpenFileSource(UsageEnvironment& env, WISInput& input);  virtual ~WISAudioOpenFileSource();protected: // redefined virtual functions:  virtual void readFromFile();};////////// WISInput implementation //////////WISInput* WISInput::createNew(UsageEnvironment& env) {  if (!fHaveInitialized) {    if (!initialize(env)) return NULL;    fHaveInitialized = True;  }  return new WISInput(env);}FramedSource* WISInput::videoSource() {  if (fOurVideoSource == NULL) {    fOurVideoSource = new WISVideoOpenFileSource(envir(), *this);  }  return fOurVideoSource;}FramedSource* WISInput::audioSource() {  if (fOurAudioSource == NULL) {    fOurAudioSource = new WISAudioOpenFileSource(envir(), *this);  }  return fOurAudioSource;}WISInput::WISInput(UsageEnvironment& env)  : Medium(env) {}WISInput::~WISInput() {}Boolean WISInput::initialize(UsageEnvironment& env) {  do {    if (!openFiles(env)) break;    if (!initALSA(env)) break;    if (!initV4L(env)) break;    return True;  } while (0);  // An error occurred  return False;}static void printErr(UsageEnvironment& env, char const* str = NULL) {  if (str != NULL) env << str;  env << ": " << strerror(env.getErrno()) << "\n";}Boolean WISInput::openFiles(UsageEnvironment& env) {  do {    // Make sure sysfs is mounted and the driver is loaded:    struct stat si;    char const* driverDirName = "/sys/bus/usb/drivers";    if (stat(driverDirName, &si) < 0) {      env << "Unable to read \"" << driverDirName << "\""; printErr(env);      env << "Is sysfs mounted on /sys?\n";      break;    }    char const* driverFileName = "/sys/bus/usb/drivers/go7007";    if (stat(driverFileName, &si) < 0) {      env << "Unable to read \"" << driverFileName << "\""; printErr(env);      env << "Is the go7007-usb kernel module loaded?\n";      break;    }        // Find a Video4Linux device associated with the go7007 driver:    char sympath[PATH_MAX], canonpath[PATH_MAX], gopath[PATH_MAX];    int const maxFileNum = 20;    int i;    for (i = 0; i < maxFileNum; ++i) {      snprintf(sympath, sizeof sympath, "/sys/class/video4linux/video%d/driver", i);      if (realpath(sympath, canonpath) == NULL) continue;      if (strcmp(strrchr(canonpath, '/') + 1, "go7007") == 0) break;    }    snprintf(sympath, sizeof sympath, "/sys/class/video4linux/video%d/device", i);    if (i == maxFileNum || realpath(sympath, gopath) == NULL) {      env << "Driver loaded but no GO7007SB devices found.\n";      env << "Is the device connected properly?\n";      break;    }    // Open it:    char vDeviceName[PATH_MAX];    snprintf(vDeviceName, sizeof vDeviceName, "/dev/video%d", i);    fOurVideoFileNo = open(vDeviceName, O_RDWR);    if (fOurVideoFileNo < 0) {      env << "Unable to open \"" << vDeviceName << "\""; printErr(env);      break;    }      // Find the ALSA device associated with this USB address:    for (i = 0; i < maxFileNum; ++i) {      snprintf(sympath, sizeof sympath, "/sys/class/sound/pcmC%dD0c/device", i);      if (realpath(sympath, canonpath) == NULL) continue;      if (strcmp(gopath, canonpath) == 0) break;    }    if (i == maxFileNum) {      env << "Unable to find a ALSA device associated with the GO7007SB device\n";      break;    }    // Find the OSS emulation minor number for this ALSA device:    char const* ossFileName = "/proc/asound/oss/devices";    FILE* file = fopen(ossFileName, "r");    if (file == NULL) {      env << "Unable to open \"" << ossFileName << "\""; printErr(env);      env << "Is the snd_pcm_oss module loaded?\n";      break;    }    int minor = -1;    char line[128];    while (fgets(line, sizeof line, file) != NULL) {      int m, n;      if (sscanf(line, "%d: [%u-%*u]: digital audio\n", &m, &n) != 2) continue;      if (n == i) {	minor = m;	break;      }    }    fclose(file);    if (minor < 0) {      env << "Unable to find emulated OSS device node\n";      break;    }    // Find the OSS file name for this minor number:    char const* soundDirName = "/sys/class/sound";    DIR* dir = opendir(soundDirName);    if (dir == NULL) {      env << "Unable to read \"" << soundDirName << "\""; printErr(env);      break;    }    struct dirent* ent;    while ((ent = readdir(dir)) != NULL) {      int m = -1;      if (strncmp(ent->d_name, "dsp", 3) != 0) continue;      char adev[PATH_MAX];      snprintf(adev, sizeof adev, "%s/%s/dev", soundDirName, ent->d_name);      file = fopen(adev, "r");      if (file == NULL) continue;      if (fgets(line, sizeof line, file) != NULL) {	sscanf(line, "%*d:%d\n", &m);      }      fclose(file);      if (m == minor) break;    }    closedir(dir);    if (ent == NULL) {      env << "Unable to find emulated OSS device.\n";      break;    }    // Open it:    char aDeviceName[PATH_MAX];    snprintf(aDeviceName, sizeof aDeviceName, "/dev/%s", ent->d_name);    fOurAudioFileNo = open(aDeviceName, O_RDONLY);    if (fOurAudioFileNo < 0) {      env << "Unable to open \"" << aDeviceName << "\""; printErr(env);      break;    }    fcntl(fOurAudioFileNo, F_SETFL, O_NONBLOCK);      return True;  } while (0);  // An error occurred:  return False;}Boolean WISInput::initALSA(UsageEnvironment& env) {  do {    int arg;    arg = AFMT_S16_LE;    if (ioctl(fOurAudioFileNo, SNDCTL_DSP_SETFMT, &arg) < 0) {      printErr(env, "SNDCTL_DSP_SETFMT");      break;    }    arg = audioSamplingFrequency;    if (ioctl(fOurAudioFileNo, SNDCTL_DSP_SPEED, &arg) < 0) {      printErr(env, "SNDCTL_DSP_SPEED");      break;    }    arg = audioIsStereo;    if (ioctl(fOurAudioFileNo, SNDCTL_DSP_STEREO, &arg) < 0) {      printErr(env, "SNDCTL_DSP_STEREO");      break;    }    return True;  } while (0);  // An error occurred:  return False;}#define MAX_BUFFERS     32static struct {  unsigned char *addr;  unsigned int length;} buffers[MAX_BUFFERS];Boolean WISInput::initV4L(UsageEnvironment& env) {  do {    // Set the video input port:    if (ioctl(fOurVideoFileNo, VIDIOC_S_INPUT, &videoInputDeviceNumber) < 0) {      env << "Unable to set video input device " << videoInputDeviceNumber << "\n";      break;    }    // Set the video norm (should be done before setting the format):    int i = videoIsPAL ? V4L2_STD_PAL : V4L2_STD_NTSC_M;    if (ioctl(fOurVideoFileNo, VIDIOC_S_STD, &i) < 0) {      printErr(env, "Unable to set video type (PAL or NTSC)");      break;    }    // Set the format:    struct v4l2_format fmt;    memset(&fmt, 0, sizeof fmt);    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;    fmt.fmt.pix.width = videoWidth;    fmt.fmt.pix.height = videoHeight;    switch (videoFormat) {    case VFMT_MJPEG:      fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;      break;    case VFMT_MPEG1:    case VFMT_MPEG2:    case VFMT_MPEG4:    default:      fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;      break;    }    if (ioctl(fOurVideoFileNo, VIDIOC_S_FMT, &fmt) < 0) {      printErr(env, "Unable to set the video format (and width,height)");      break;    }    // Set the compression parameters:    if (videoFormat != VFMT_MJPEG) {      struct go7007_comp_params comp;      memset(&comp, 0, sizeof comp);      comp.gop_size = 100;      comp.max_b_frames = 0; // B frames are not yet supported #####      comp.aspect_ratio = GO7007_ASPECT_RATIO_1_1;      comp.flags |= GO7007_COMP_CLOSED_GOP;      if (ioctl(fOurVideoFileNo, GO7007IOC_S_COMP_PARAMS, &comp) < 0) {	printErr(env, "Unable to set compression params");	break;      }      struct go7007_mpeg_params mpeg;      memset(&mpeg, 0, sizeof mpeg);      switch (videoFormat) {      case VFMT_MPEG1:	mpeg.mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG1;	break;      case VFMT_MPEG2:	mpeg.mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG2;	break;      case VFMT_MPEG4:      default:	mpeg.mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG4;	break;      }      mpeg.flags |= GO7007_MPEG_REPEAT_SEQHEADER;          // for streaming - ensures that a sequence header appears periodically      if (ioctl(fOurVideoFileNo, GO7007IOC_S_MPEG_PARAMS, &mpeg) < 0) {	printErr(env, "Unable to set MPEG parameters");	break;      }    }    // Set the bitrate:    if (ioctl(fOurVideoFileNo, GO7007IOC_S_BITRATE, &videoBitrate) < 0) {      printErr(env, "Unable to set video bitrate");      break;    }    // Request that buffers be allocated for memory mapping:    struct v4l2_requestbuffers req;    memset(&req, 0, sizeof req);    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;    req.memory = V4L2_MEMORY_MMAP;    req.count = MAX_BUFFERS;    if (ioctl(fOurVideoFileNo, VIDIOC_REQBUFS, &req) < 0) {      printErr(env, "VIDIOC_REQBUFS");      break;    }        // Map each of the buffers into this process's memory,    // and queue them for frame capture:    unsigned j;    for (j = 0; j < req.count; ++j) {      struct v4l2_buffer buf;      memset(&buf, 0, sizeof buf);      buf.index = j;      buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;      if (ioctl(fOurVideoFileNo, VIDIOC_QUERYBUF, &buf) < 0) {	printErr(env, "VIDIOC_QUERYBUF");	break;      }      buffers[buf.index].addr	= (unsigned char *)mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED,				fOurVideoFileNo, buf.m.offset);      if (buffers[buf.index].addr == MAP_FAILED) {	printErr(env, "mmap() failed");	break;      }      buffers[buf.index].length = buf.length;            buf.memory = V4L2_MEMORY_MMAP;      if (ioctl(fOurVideoFileNo, VIDIOC_QBUF, &buf) < 0) {	printErr(env, "VIDIOC_QBUF");	break;      }    }    if (j < req.count) break; // an error occurred        // Start capturing:    int arg = V4L2_BUF_TYPE_VIDEO_CAPTURE;    if (ioctl(fOurVideoFileNo, VIDIOC_STREAMON, &arg) < 0) {      printErr(env, "VIDIOC_STREAMON");      break;    }    return True;  } while (0);  // An error occurred:  return False;}Boolean WISInput::fHaveInitialized = False;int WISInput::fOurVideoFileNo = -1;FramedSource* WISInput::fOurVideoSource = NULL;int WISInput::fOurAudioFileNo = -1;FramedSource* WISInput::fOurAudioSource = NULL;////////// WISOpenFileSource implementation //////////WISOpenFileSource::WISOpenFileSource(UsageEnvironment& env, WISInput& input, int fileNo)  : FramedSource(env),    fInput(input), fFileNo(fileNo) {}WISOpenFileSource::~WISOpenFileSource() {  envir().taskScheduler().turnOffBackgroundReadHandling(fFileNo);}void WISOpenFileSource::doGetNextFrame() {  // Await the next incoming data on our FID:  envir().taskScheduler().turnOnBackgroundReadHandling(fFileNo,	       (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this);}void WISOpenFileSource::incomingDataHandler(WISOpenFileSource* source, int /*mask*/) {  source->incomingDataHandler1();}void WISOpenFileSource::incomingDataHandler1() {  if (!isCurrentlyAwaitingData()) return; // we're not ready for the data yet  // Read the data from our file into the client's buffer:  readFromFile();  // Tell our client that we have new data:  afterGetting(this);}////////// WISVideoOpenFileSource implementation //////////WISVideoOpenFileSource::WISVideoOpenFileSource(UsageEnvironment& env, WISInput& input)  : WISOpenFileSource(env, input, input.fOurVideoFileNo) {}WISVideoOpenFileSource::~WISVideoOpenFileSource() {  fInput.fOurVideoSource = NULL;}void WISVideoOpenFileSource::readFromFile() {  // Retrieve a filled video buffer from the kernel:  struct v4l2_buffer buf;  memset(&buf, 0, sizeof buf);  buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  buf.memory = V4L2_MEMORY_MMAP;  if (ioctl(fFileNo, VIDIOC_DQBUF, &buf) < 0) {    printErr(envir(), "VIDIOC_DQBUF");    return;  }  // Note the timestamp and size:  fPresentationTime = buf.timestamp;  fFrameSize = buf.bytesused;  if (fFrameSize > fMaxSize) {    fNumTruncatedBytes = fFrameSize - fMaxSize;    fFrameSize = fMaxSize;  } else {    fNumTruncatedBytes = 0;  }  // Copy to the desired place:  memmove(fTo, buffers[buf.index].addr, fFrameSize);  // Send the buffer back to the kernel to be filled in again:  if (ioctl(fFileNo, VIDIOC_QBUF, &buf) < 0) {    printErr(envir(), "VIDIOC_QBUF");    return;  }}////////// WISAudioOpenFileSource implementation //////////WISAudioOpenFileSource::WISAudioOpenFileSource(UsageEnvironment& env, WISInput& input)  : WISOpenFileSource(env, input, input.fOurAudioFileNo) {}WISAudioOpenFileSource::~WISAudioOpenFileSource() {  fInput.fOurAudioSource = NULL;}void WISAudioOpenFileSource::readFromFile() {  // Read available audio data:  int ret = read(fInput.fOurAudioFileNo, fTo, fMaxSize);  if (ret < 0) ret = 0;  fFrameSize = (unsigned)ret;  gettimeofday(&fPresentationTime, NULL);}

⌨️ 快捷键说明

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