/****************************************************************************** * Capture_create ******************************************************************************/ Capture_Handle Capture_create(BufTab_Handle hBufTab, Capture_Attrs *attrs) { struct v4l2_capability cap; struct v4l2_crop crop; struct v4l2_format fmt; enum v4l2_buf_type type; Capture_Handle hCapture; VideoStd_Type videoStd; Int32 width, height; assert(attrs); Dmai_clear(fmt); /* Allocate space for state object */ hCapture = calloc(1, sizeof(Capture_Object)); if (hCapture == NULL) { Dmai_err0("Failed to allocate space for Capture Object\n"); return NULL; } /* User allocated buffers by default */ hCapture->userAlloc = TRUE; /* Open video capture device */ hCapture->fd = open(attrs->captureDevice, O_RDWR, 0); if (hCapture->fd == -1) { Dmai_err2("Cannot open %s (%s)\n", attrs->captureDevice, strerror(errno)); cleanup(hCapture); return NULL; } /* See if an input is connected, and if so which standard */ if (Capture_detectVideoStd(hCapture, &videoStd, attrs) < 0) { cleanup(hCapture); return NULL; } hCapture->videoStd = videoStd; if (VideoStd_getResolution(videoStd, &width, &height) < 0) { cleanup(hCapture); Dmai_err0("Failed to get resolution of capture video standard\n"); return NULL; } /* Query for capture device capabilities */ if (ioctl(hCapture->fd, VIDIOC_QUERYCAP, &cap) == -1) { cleanup(hCapture); if (errno == EINVAL) { Dmai_err1("%s is no V4L2 device\n", attrs->captureDevice); cleanup(hCapture); return NULL; } Dmai_err2("Failed VIDIOC_QUERYCAP on %s (%s)\n", attrs->captureDevice, strerror(errno)); cleanup(hCapture); return NULL; } if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { Dmai_err1("%s is not a video capture device\n", attrs->captureDevice); cleanup(hCapture); return NULL; } if (!(cap.capabilities & V4L2_CAP_STREAMING)) { Dmai_err1("%s does not support streaming i/o\n", attrs->captureDevice); cleanup(hCapture); return NULL; } fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(hCapture->fd, VIDIOC_G_FMT, &fmt) == -1) { Dmai_err2("Failed VIDIOC_G_FMT on %s (%s)\n", attrs->captureDevice, strerror(errno)); cleanup(hCapture); return NULL; } fmt.fmt.pix.width = width; fmt.fmt.pix.height = height; fmt.fmt.pix.bytesperline = width * 2; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; if (ioctl(hCapture->fd, VIDIOC_S_FMT, &fmt) == -1) { Dmai_err2("Failed VIDIOC_S_FMT on %s (%s)\n", attrs->captureDevice, strerror(errno)); cleanup(hCapture); return NULL; } Dmai_dbg3("Video input connected size %dx%d pitch %d\n", fmt.fmt.pix.width, fmt.fmt.pix.height, fmt.fmt.pix.bytesperline); if (attrs->cropWidth > 0 && attrs->cropHeight > 0) { if (attrs->cropX & 0x1) { Dmai_err1("Crop width (%ld) needs to be even\n", attrs->cropX); cleanup(hCapture); return NULL; } crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; crop.c.left = attrs->cropX; crop.c.top = attrs->cropY; crop.c.width = attrs->cropWidth; crop.c.height = hCapture->topOffset ? attrs->cropHeight + 4 + 2 : attrs->cropHeight; Dmai_dbg4("Setting capture cropping at %dx%d size %dx%d\n", crop.c.left, crop.c.top, crop.c.width, crop.c.height); /* Crop the image depending on requested image size */ if (ioctl(hCapture->fd, VIDIOC_S_CROP, &crop) == -1) { Dmai_err2("VIDIOC_S_CROP failed on %s (%s)\n", attrs->captureDevice, strerror(errno)); cleanup(hCapture); return NULL; } } if (hBufTab == NULL) { hCapture->userAlloc = FALSE; /* The driver allocates the buffers */ if (_Dmai_v4l2DriverAlloc(hCapture->fd, attrs->numBufs, V4L2_BUF_TYPE_VIDEO_CAPTURE, &hCapture->bufDescs, &hBufTab, hCapture->topOffset, attrs->colorSpace) < 0) { Dmai_err1("Failed to allocate capture driver buffers on %s\n", attrs->captureDevice); cleanup(hCapture); return NULL; } } else { /* Make the driver use the user supplied buffers */ if (_Dmai_v4l2UserAlloc(hCapture->fd, attrs->numBufs, V4L2_BUF_TYPE_VIDEO_CAPTURE, &hCapture->bufDescs, hBufTab, 0, attrs->colorSpace, TRUE) < 0) { Dmai_err1("Failed to intialize capture driver buffers on %s\n", attrs->captureDevice); cleanup(hCapture); return NULL; } } hCapture->hBufTab = hBufTab; /* Start the video streaming */ type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(hCapture->fd, VIDIOC_STREAMON, &type) == -1) { Dmai_err2("VIDIOC_STREAMON failed on %s (%s)\n", attrs->captureDevice, strerror(errno)); cleanup(hCapture); return NULL; } hCapture->started = TRUE; return hCapture; }
/****************************************************************************** * Display_fbdev_create ******************************************************************************/ Display_Handle Display_fbdev_create(BufTab_Handle hBufTab, Display_Attrs *attrs) { BufferGfx_Attrs gfxAttrs = BufferGfx_Attrs_DEFAULT; struct fb_var_screeninfo varInfo; struct fb_fix_screeninfo fixInfo; Int displaySize; Int bufIdx; Int8 *virtPtr; Int32 physPtr; Int32 height, width; Display_Handle hDisplay; Buffer_Handle hBuf; if (attrs == NULL) { Dmai_err0("Must supply valid attrs\n"); return NULL; } if (hBufTab != NULL) { Dmai_err0("FBdev display does not accept user allocated buffers\n"); return NULL; } hDisplay = calloc(1, sizeof(Display_Object)); if (hDisplay == NULL) { Dmai_err0("Failed to allocate space for Display Object\n"); return NULL; } /* Open video display device */ hDisplay->fd = open(attrs->displayDevice, O_RDWR); if (hDisplay->fd == -1) { Dmai_err2("Failed to open fb device %s (%s)\n", attrs->displayDevice, strerror(errno)); cleanup(hDisplay); return NULL; } /* Get fixed screen info */ if (ioctl(hDisplay->fd, FBIOGET_FSCREENINFO, &fixInfo) == -1) { Dmai_err2("Failed FBIOGET_FSCREENINFO on %s (%s)\n", attrs->displayDevice, strerror(errno)); cleanup(hDisplay); return NULL; } /* Get virtual screen info */ if (ioctl(hDisplay->fd, FBIOGET_VSCREENINFO, &varInfo) == -1) { Dmai_err2("Failed FBIOGET_VSCREENINFO on %s (%s)\n", attrs->displayDevice, strerror(errno)); cleanup(hDisplay); return NULL; } Dmai_dbg5("Found width=%d height=%d, yres_virtual=%d,xres_virtual=%d," " line_length=%d\n", varInfo.xres, varInfo.yres, varInfo.yres_virtual,varInfo.xres_virtual, fixInfo.line_length); /* Save current virtual screen info. */ memcpy(&hDisplay->origVarInfo, &varInfo, sizeof(struct fb_var_screeninfo)); /* If video standard is set to auto then use current height and width */ if (attrs->videoStd == VideoStd_AUTO) { width = varInfo.xres; height = varInfo.yres; } /* If video standard is not set then use the height/width passed from * attribute. */ else if (attrs->videoStd == -1) { width = attrs->width; height = attrs->height; } /* calulcate height/width from video standard */ else { VideoStd_getResolution(attrs->videoStd, &width, &height); } if (attrs->width > 0) { width = attrs->width; } if (attrs->height > 0) { height = attrs->height; } if (width > varInfo.xres) { width = varInfo.xres; } if (height > varInfo.yres) { height = varInfo.yres; } varInfo.xoffset = 0; varInfo.yoffset = 0; varInfo.xres = width; varInfo.yres = height; varInfo.xres_virtual = width; varInfo.yres_virtual = varInfo.yres * attrs->numBufs; /* Set video display format */ Dmai_dbg4("Setting width=%d height=%d, yres_virtual=%d," " xres_virtual=%d\n", varInfo.xres, varInfo.yres, varInfo.yres_virtual, varInfo.xres_virtual); if (ioctl(hDisplay->fd, FBIOPUT_VSCREENINFO, &varInfo) == -1) { Dmai_err2("Failed FBIOPUT_VSCREENINFO on %s (%s)\n", attrs->displayDevice, strerror(errno)); cleanup(hDisplay); return NULL; } if (ioctl(hDisplay->fd, FBIOGET_FSCREENINFO, &fixInfo) == -1) { Dmai_err2("Failed FBIOGET_FSCREENINFO on %s (%s)\n", attrs->displayDevice, strerror(errno)); cleanup(hDisplay); return NULL; } Dmai_dbg5("New width=%d, height=%d, yres_virtual=%d,xres_virtual=%d, " "line_length=%d\n", varInfo.xres, varInfo.yres, varInfo.yres_virtual, varInfo.xres_virtual, fixInfo.line_length); gfxAttrs.dim.width = varInfo.xres; gfxAttrs.colorSpace = attrs->colorSpace; gfxAttrs.dim.height = varInfo.yres; gfxAttrs.dim.lineLength = fixInfo.line_length; gfxAttrs.bAttrs.reference = TRUE; displaySize = fixInfo.line_length * varInfo.yres; hBufTab = BufTab_create(attrs->numBufs, displaySize, BufferGfx_getBufferAttrs(&gfxAttrs)); if (hBufTab == NULL) { Dmai_err0("Failed to allocate BufTab for display buffers\n"); cleanup(hDisplay); return NULL; } hBuf = BufTab_getBuf(hBufTab, 0); Buffer_setNumBytesUsed(hBuf, varInfo.xres * varInfo.yres * varInfo.bits_per_pixel / 8); virtPtr = (Int8 *) mmap (NULL, displaySize * attrs->numBufs, PROT_READ | PROT_WRITE, MAP_SHARED, hDisplay->fd, 0); if (virtPtr == MAP_FAILED) { Dmai_err2("Failed mmap on %s (%s)\n", attrs->displayDevice, strerror(errno)); cleanup(hDisplay); return NULL; } if (Buffer_setUserPtr(hBuf, virtPtr) < 0) { cleanup(hDisplay); return NULL; } _Dmai_blackFill(hBuf); Dmai_dbg3("Display buffer %d mapped to %#lx has physical address %#lx\n", 0, (Int32) virtPtr, physPtr); for (bufIdx=1; bufIdx < attrs->numBufs; bufIdx++) { hBuf = BufTab_getBuf(hBufTab, bufIdx); Buffer_setNumBytesUsed(hBuf, varInfo.xres * varInfo.yres * varInfo.bits_per_pixel / 8); virtPtr = virtPtr + displaySize; Buffer_setUserPtr(hBuf, virtPtr); _Dmai_blackFill(hBuf); Dmai_dbg3("Display buffer %d mapped to %#lx, physical address %#lx\n", bufIdx, (unsigned long) virtPtr, physPtr); } hDisplay->hBufTab = hBufTab; hDisplay->displayIdx = 0; hDisplay->workingIdx = attrs->numBufs > 1 ? 1 : 0; hDisplay->displayStd = Display_Std_FBDEV; if (setDisplayBuffer(hDisplay, hDisplay->displayIdx) < 0) { cleanup(hDisplay); return NULL; } return hDisplay; }
/****************************************************************************** * initHwParams ******************************************************************************/ static Int initHwParams(snd_pcm_t *rc, snd_pcm_hw_params_t *hwParams, Sound_Attrs *attrs, Sound_Handle hSound) { Int status; snd_pcm_uframes_t periodSize,bufSize; Uns buffer_time = 0; Uns sampleRate = attrs->sampleRate; /* Fill the params with the defaults */ status = snd_pcm_hw_params_any(rc, hwParams); if (status < 0) { Dmai_err2("Failed to init ALSA hardware param structure on %s (%s)\n", AUDIO_DEVICE, snd_strerror(status)); return Dmai_EFAIL; } /* Set the access type to interleaved */ status = snd_pcm_hw_params_set_access(rc, hwParams, SND_PCM_ACCESS_RW_INTERLEAVED); if (status < 0) { Dmai_err2("Failed to set ALSA access type on %s (%s)\n", AUDIO_DEVICE, snd_strerror(status)); return Dmai_EFAIL; } /* Set the format to 16 bit little endian */ status = snd_pcm_hw_params_set_format(rc, hwParams, SND_PCM_FORMAT_S16_LE); if (status < 0) { Dmai_err2("Failed to set sample format on %s (%s)\n", AUDIO_DEVICE, snd_strerror(status)); return Dmai_EFAIL; } /* Set the sample rate */ status = snd_pcm_hw_params_set_rate_near(rc, hwParams, (Uns *) &sampleRate, 0); if (status < 0) { Dmai_err3("Failed to set sample rate to %d on %s (%s)\n", attrs->sampleRate, AUDIO_DEVICE, snd_strerror(status)); return Dmai_EFAIL; } /* Set the number of channels to 2 */ status = snd_pcm_hw_params_set_channels(rc, hwParams, attrs->channels); if (status < 0) { Dmai_err3("Failed to set channel count to %d on %s (%s)\n", attrs->channels, AUDIO_DEVICE, snd_strerror(status)); return Dmai_EFAIL; } /* Set period size */ periodSize = hSound->periodSize=16; status = snd_pcm_hw_params_set_period_size_near (rc, hwParams, &periodSize, 0); if (status < 0) { Dmai_err3("Failed to set the period size to %d on %s (%s)\n", periodSize, AUDIO_DEVICE, snd_strerror(status)); return Dmai_EFAIL; } if (periodSize != hSound->periodSize) { Dmai_dbg4("Failed to set buffer size (%d) , got (%d) on %s (%s)\n", hSound->periodSize, periodSize, AUDIO_DEVICE, snd_strerror(status)); hSound->periodSize = periodSize; } /* Set the maximum buffer time */ status = snd_pcm_hw_params_get_buffer_time_max(hwParams, &buffer_time, 0); if (status < 0) { Dmai_err2("Failed to get maximum buffer time on %s (%s)\n", AUDIO_DEVICE, snd_strerror(status)); return Dmai_EFAIL; } if (buffer_time > 500000) { buffer_time = 500000; } status = snd_pcm_hw_params_set_buffer_time_near(rc, hwParams, &buffer_time, 0); if (status < 0) { Dmai_err2("Failed to set maximum buffer time on %s (%s)\n", AUDIO_DEVICE, snd_strerror(status)); return Dmai_EFAIL; } /* Prepare the PCM interface with the parameters chosen */ status = snd_pcm_hw_params(rc, hwParams); if (status < 0) { Dmai_err2("Failed to set ALSA parameters on %s (%s)\n", AUDIO_DEVICE, snd_strerror(status)); return Dmai_EFAIL; } /* Do sanity check */ snd_pcm_hw_params_get_period_size(hwParams, &periodSize, 0); snd_pcm_hw_params_get_buffer_size(hwParams, &bufSize); if (periodSize == bufSize) { Dmai_err2("Can't use period size equal to buf size (%d == %d)\n", periodSize, bufSize); return Dmai_EFAIL; } hSound->periodSize = periodSize; hSound->bufSize = bufSize; return Dmai_EOK; }