示例#1
0
/******************************************************************************
 * 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;
}
示例#3
0
/******************************************************************************
 * 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;
}