Esempio n. 1
0
fg_rect fg_get_capture_window(fg_grabber *fg)
{
    fg_rect rect = { 0, 0, 0, 0 };
    struct v4l2_crop crop;

    crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    if (v4l2_ioctl(fg->fd, VIDIOC_S_CROP, &crop) == -1)
    {
        if (errno == EINVAL)
        {
            fg_debug_error("fg_get_capture_window(): "
                            "device does not support cropping");
            return rect;
        }
        else
        {
            fg_debug_error("fg_get_capture_window(): "
                            "getting cropping window failed");
            return rect;
        }
    }

    rect.left = crop.c.left;
    rect.top = crop.c.top;
    rect.width = crop.c.width;
    rect.height = crop.c.height;

    return rect;
}
Esempio n. 2
0
//--------------------------------------------------------------------------
// TODO: fg_*_channel() functions not tested at all yet.
int fg_set_channel( fg_grabber* fg, float freq )
{
    int val, scale;
    struct v4l2_frequency frq;

    if ( !(fg->inputs[fg->input].type & V4L2_INPUT_TYPE_TUNER) )
    {
        fg_debug_error("fg_set_channel(): current source is not a tuner");
        return -1;
    }

    // TODO: is this still correct?
    // The LOW flag means freq in 1/16 MHz, not 1/16 kHz
    if ( fg->tuners[fg->tuner].capability & V4L2_TUNER_CAP_LOW )
        scale = 16000;
    else
        scale = 16;
    val = (int)( freq * scale );

    frq.tuner = fg->inputs[fg->input].tuner;
    frq.type = fg->tuners[fg->tuner].type;
    frq.frequency = val;
    FG_CLEAR(frq.reserved);

    if ( v4l2_ioctl( fg->fd, VIDIOC_S_FREQUENCY, &frq ) < 0 )
    {
        fg_debug_error( "fg_set_channel(): failed to tune channel" );
        return -1;
    }

    return 0;
}
Esempio n. 3
0
int fg_grab_frame(fg_grabber *fg, fg_frame *fr)
{

    for (;;)
    {

        fd_set fds;
        struct timeval tv;
        int r;

        FD_ZERO(&fds);
        FD_SET(fg->fd, &fds);

        tv.tv_sec = FG_READ_TIMEOUT;
        tv.tv_usec = 0;

        r = select(fg->fd + 1, &fds, NULL, NULL, &tv);

        if ( r == -1 )
        {
            if (EINTR == errno)
                continue;

            fg_debug_error("fg_grab_frame(): grabbing frame failed");
            return -1;
        }

        if (0 == r)
        {
            fg_debug_error("fg_grab_frame(): frame grabbing timeout reached");
            return -1;
        }

        if (v4l2_read(fg->fd, fr->data, fr->length) == -1) {

            if (errno == EAGAIN)
                continue;
            else
            {
                fg_debug_error(
                    "fg_grab_frame(): error reading from device");
                return -1;
            }
        }
        else
        {
            gettimeofday(&(fr->timestamp), NULL);
            return 0;
        }
    }

    return -1;
}
Esempio n. 4
0
int fg_frame_save( fg_frame* fr, const char* filename )
{

    if (fr->format != FG_FORMAT_RGB24)
    {
        fg_debug_error("fg_frame_save(): failed because format is not RGB24");
        return -1;
    }

    FILE *outfile;

    if ( (outfile = fopen(filename, "wb")) == NULL)
    {
        fg_debug_error("fg_frame_save(): unable to open output file");
        return -1;
    }

    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;
    JSAMPROW row_pointer[1];

    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);
    jpeg_stdio_dest(&cinfo, outfile);

    cinfo.in_color_space = JCS_RGB;
    jpeg_set_defaults(&cinfo);

    cinfo.image_width = fr->size.width;
    cinfo.image_height = fr->size.height;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;
    jpeg_set_defaults(&cinfo);

    jpeg_set_quality(&cinfo, 80, FALSE);

    jpeg_start_compress(&cinfo, TRUE);

    while (cinfo.next_scanline < cinfo.image_height)
    {
        row_pointer[0] = &(fr->data[cinfo.next_scanline*fr->rowstride]);
        jpeg_write_scanlines(&cinfo, row_pointer, 1);
    }

    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);

    return 0;
}
Esempio n. 5
0
int fg_set_input(fg_grabber* fg, int index)
{
    struct v4l2_format fmt;

    if (index >= fg->num_inputs)
    {
        fg_debug_error("fg_set_input(): invalid input number");
        return -1;
    }

    FG_CLEAR(fmt);
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (v4l2_ioctl(fg->fd, VIDIOC_G_FMT, &fmt) == -1)
    {
        fg_debug_error("fg_set_input(): failed saving current format");
        return -1;
    }

    while (v4l2_ioctl(fg->fd, VIDIOC_S_INPUT, &index) == -1)
    {
        switch(errno)
        {
            case EBUSY:
                continue;
            case EINVAL:
            default:
                fg_debug_error( "fg_set_input(): set input failed" );
                return -1;
        }
    }

    // Reset the video format
    fg->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fg->format.fmt.pix.width = fmt.fmt.pix.width;
    fg->format.fmt.pix.height = fmt.fmt.pix.height;
    fg->format.fmt.pix.pixelformat = fmt.fmt.pix.pixelformat;
    fg->format.fmt.pix.field = fmt.fmt.pix.field;

    if (v4l2_ioctl(fg->fd, VIDIOC_S_FMT, &(fg->format)) == -1)
    {
        fg_debug_error("fg_set_input(): resetting video format failed");
        return -1;
    }

    fg->input = index;

    return 0;
}
Esempio n. 6
0
int fg_get_format(fg_grabber *fg)
{
    if (v4l2_ioctl(fg->fd, VIDIOC_G_FMT, &(fg->format)) == -1)
    {
        fg_debug_error("fg_get_format(): getting video format failed");
        return -1;
    }
    return fg->format.fmt.pix.pixelformat;
}
Esempio n. 7
0
int fg_get_input_type( fg_grabber* fg, int index )
{
    if (index > fg->num_inputs - 1)
    {
        fg_debug_error("fg_get_input_type(): invalid input number" );
        return -1;
    }

    return fg->inputs[index].type;
}
Esempio n. 8
0
char *fg_get_input_name(fg_grabber *fg, int index)
{

    if (index > fg->num_inputs - 1)
    {
        fg_debug_error("fg_get_input_name(): invalid input number" );
        return NULL;
    }

    return (char *)fg->inputs[index].name;
}
Esempio n. 9
0
int fg_get_input(fg_grabber *fg)
{
    int current_input;

    if (v4l2_ioctl(fg->fd, VIDIOC_G_INPUT, &current_input) == -1)
    {
        fg_debug_error("fg_get_input(): unable to get current input index.");
        return -1;
    }

    return current_input;
}
Esempio n. 10
0
void fg_unref(fg_grabber *fg)
{

    // Make sure we free all memory (backwards!)
    if (v4l2_close(fg->fd) != 0)
        fg_debug_error("fg_close(): warning: failed closing device file");
    free(fg->device);
    free(fg->inputs);
    free(fg->tuners);
    free(fg->controls);
    free(fg);

}
Esempio n. 11
0
fg_size fg_get_capture_size(fg_grabber *fg)
{
    fg_size size = { 0, 0 };
    if (v4l2_ioctl(fg->fd, VIDIOC_G_FMT, &(fg->format)) == -1)
    {
        fg_debug_error("fg_get_capture_size(): getting capture size failed");
        return size;

    }
    size.width = fg->format.fmt.pix.width;
    size.height = fg->format.fmt.pix.height;
    return size;
}
Esempio n. 12
0
int fg_set_format(fg_grabber *fg, int fmt)
{

    fg->format.fmt.pix.pixelformat = fmt;

    if (v4l2_ioctl(fg->fd, VIDIOC_S_FMT, &(fg->format)) == -1)
    {
        fg_debug_error("fg_set_format(): setting video format failed");
        return -1;
    }

    return 0;
}
Esempio n. 13
0
int fg_set_capture_size(fg_grabber *fg, fg_size size)
{
    fg->format.fmt.pix.width = size.width;
    fg->format.fmt.pix.height = size.height;

    if (v4l2_ioctl(fg->fd, VIDIOC_S_FMT, &(fg->format)) == -1)
    {
        fg_debug_error("fg_set_capture_size(): setting capture size to "
            "'%dx%d failed", size.width, size.height);
        return -1;
    }

    return 0;
}
Esempio n. 14
0
fg_frame *fg_grab(fg_grabber *fg)
{
    fg_frame *fr = fg_frame_new(fg);

    if (fr == NULL)
    {
        fg_debug_error("fg_grab(): ran out of memory allocating frame");
        return NULL;
    }

    if (fg_grab_frame(fg, fr) == -1)
    {
        free(fr);
        return NULL;
    }

    return fr;
}
Esempio n. 15
0
fg_frame *fg_frame_new(fg_grabber *fg)
{
    fg_frame* fr = malloc( sizeof( fg_frame ) );
    fr->size = fg_get_capture_size(fg);
    fr->format = fg->format.fmt.pix.pixelformat;
    fr->rowstride = fg->format.fmt.pix.bytesperline;
    fr->length = fg->format.fmt.pix.sizeimage;
    fr->data = malloc( fr->length );

    if (fr->data == NULL)
    {
        fg_debug_error("frame_new(): ran out of memory allocating new frame");
        free(fr);
        return NULL;
    }

    return fr;
}
Esempio n. 16
0
float fg_get_channel( fg_grabber* fg )
{
    int scale;
    struct v4l2_frequency freq;

    // TODO: is this correct? (original lib was backwards from set func)
    // The LOW flag means freq in 1/16 MHz, not 1/16 kHz
    if (fg->tuners[fg->tuner].capability & V4L2_TUNER_CAP_LOW)
        scale = 16000;
    else
        scale = 16;

    freq.tuner = fg->tuner;
    FG_CLEAR(freq.reserved);

    if ( v4l2_ioctl( fg->fd, VIDIOC_G_FREQUENCY, &freq ) == -1 )
    {
        fg_debug_error( "fg_get_channel(): failed to query channel" );
        return -1;
    }

    return ( freq.frequency / scale );
}
Esempio n. 17
0
fg_grabber *fg_open(const char *dev)
{

    fg_grabber* fg;
    int i;
    struct stat st;
    struct v4l2_crop crop;

    fg = malloc(sizeof(fg_grabber));

    if (fg == NULL)
    {
        fg_debug_error(
            "fg_open(): ran out of memory allocating frame grabber.");
        return NULL;
    }

    // Make these safe to free()
    fg->device = NULL;
    fg->inputs = NULL;
    fg->tuners = NULL;
    fg->controls = NULL;

    // Use default device if none specified
    if (dev != NULL)
        fg->device = strdup(dev);
    else
        fg->device = strdup(FG_DEFAULT_DEVICE);

    // Verify the device exists
    if (stat(fg->device, &st) == -1)
    {
        fg_debug_error("fg_open(): video device '%s' does not exist",
            fg->device);
        goto error_exit;
    }

    // Verify the device is a character device
    if (!S_ISCHR(st.st_mode))
    {
        fg_debug_error("fg_open(): video device '%s' is not a "
            "character device", fg->device);
        goto error_exit;
    }

    // Open the video device
    fg->fd = v4l2_open(fg->device, O_RDWR | O_NONBLOCK, 0);
    if ( fg->fd == -1 )
    {
        fg_debug_error( "fg_open(): open video device failed" );
        goto error_exit;
    }

    // Make sure child processes don't inherit video (close on exec)
    fcntl(fg->fd, F_SETFD, FD_CLOEXEC);

    // Get the device capabilities
    if (v4l2_ioctl(fg->fd, VIDIOC_QUERYCAP, &(fg->caps)) == -1)
    {
        fg_debug_error( "fg_open(): query capabilities failed" );
        goto error_exit;
    }

    // Make sure video capture is supported
    if (!(fg->caps.capabilities & V4L2_CAP_VIDEO_CAPTURE))
    {
        fg_debug_error("fg_open(): video device does not support video capture");
        goto error_exit;
    }

    // Determine the number of inputs
    if ( (fg->num_inputs = fg_get_input_count(fg)) < 1 )
    {
        fg_debug_error("fg_open(): no video inputs were found on video device");
        goto error_exit;
    }

    // Read info for all input sources
    fg->input = 0;
    fg->inputs = malloc(sizeof(struct v4l2_input) * fg->num_inputs);

    if (fg->inputs == NULL)
    {
        fg_debug_error("fg_open(): ran out of memory allocating inputs.");
        goto error_exit;
    }

    for (i=0; i < fg->num_inputs; i++)
    {
        fg->inputs[i].index = i;
        if (v4l2_ioctl(fg->fd, VIDIOC_ENUMINPUT, &(fg->inputs[i])) == -1)
        {
            fprintf(stderr, "%d\n", i);
            fg_debug_error("fg_open(): error getting input information");
            goto error_exit;
        }
    }

    if (fg_set_input(fg, fg->input) == -1)
    {
        fg_debug_error("fg_open(): error setting default input");
        goto error_exit;
    }

    // Determine the number of tuners
    fg->tuner = 0;
    if ((fg->num_tuners = count_tuners(fg->fd)) > 0)
    {
        // Read info for all tuners
        fg->tuners = malloc(sizeof(struct v4l2_tuner) * fg->num_tuners);

        if (fg->tuners == NULL)
        {
            fg_debug_error("fg_open(): ran out of memory allocating tuners");
            goto error_exit;
        }

        for (i=0; i < fg->num_tuners; i++)
        {
            fg->tuners[i].index = 0;
            if (v4l2_ioctl(fg->fd, VIDIOC_G_TUNER, &(fg->tuners[i])) == -1)
            {
                fg_debug_error("fg_open(): error getting tuner information");
                goto error_exit;
            }
        }
    }

    // Reset cropping to default (if supported)
    FG_CLEAR(fg->cropcap);
    fg->cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (v4l2_ioctl(fg->fd, VIDIOC_CROPCAP, &(fg->cropcap)) == 0)
    {
        crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        crop.c = fg->cropcap.defrect;
        if (v4l2_ioctl(fg->fd, VIDIOC_S_CROP, &crop) == -1)
        {
            if (errno == EINVAL)
            {
                fg_debug("fg_open(): warning: cropping not supported");
            }
            else
            {
                fg_debug_error(
                    "fg_open(): error setting crop window on video device");
                goto error_exit;
            }
        }
    }
    else
    {
        // should be fatal because the documentation says the VIDIOC_CROPCAP
        // is mandatory on capture devices, but several of my devices disagree
        fg_debug_error("fg_open(): warning: error getting cropping info");
        // goto error_exit;
    }

    // Set the video format
    FG_CLEAR(fg->format);
    fg->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fg->format.fmt.pix.width = FG_DEFAULT_WIDTH;
    fg->format.fmt.pix.height = FG_DEFAULT_HEIGHT;
    // libv4l should intervene here to support this format even if the
    // device does not support it directly (phew!)
    fg->format.fmt.pix.pixelformat = FG_FORMAT_RGB24;
    fg->format.fmt.pix.field = V4L2_FIELD_INTERLACED;

    if (v4l2_ioctl(fg->fd, VIDIOC_S_FMT, &(fg->format)) == -1)
    {
        fg_debug_error("fg_open(): setting video format failed");
        goto error_exit;
    }

    // Reset all supported controls to defaults
    if (fg_default_controls(fg) == -1)
    {
        fg_debug_error("fg_open(): failed setting controls to default.");
        goto error_exit;
    }

    // List available frame rates
    /*
    struct v4l2_frmivalenum fi;
    FG_CLEAR(fi);
    fi.index = 0;
    fi.pixel_format = fg->format.fmt.pix.pixelformat;
    fi.width = fg->format.fmt.pix.width;
    fi.height = fg->format.fmt.pix.height;
    if (v4l2_ioctl(fg->fd, VIDIOC_ENUM_FRAMEINTERVALS, &fi) == -1)
    {
        fg_debug_error("fg_open(): error enumerating frame intervals");
        goto error_exit;
    }
    switch(fi.type)
    {
        case V4L2_FRMIVAL_TYPE_DISCRETE:
            fprintf(stderr, "DISCRETE: %d/%d\n", fi.discrete.numerator, fi.discrete.denominator);
            break;
        case V4L2_FRMIVAL_TYPE_STEPWISE:
            fprintf(stderr, "STEPWISE\n");
            break;
        case V4L2_FRMIVAL_TYPE_CONTINUOUS:
            fprintf(stderr, "CONTINUOUS\n");
            break;
        default:
            fprintf(stderr, "ERR\n");
    }
    */

    return fg;

// Free memory allocated in this function and return NULL
error_exit:

    fg_unref(fg);
    return NULL;

}