summaryrefslogtreecommitdiffstats
path: root/tinyDAV/src/video/v4linux/tdav_producer_video_v4l2.c
diff options
context:
space:
mode:
Diffstat (limited to 'tinyDAV/src/video/v4linux/tdav_producer_video_v4l2.c')
-rwxr-xr-xtinyDAV/src/video/v4linux/tdav_producer_video_v4l2.c1855
1 files changed, 927 insertions, 928 deletions
diff --git a/tinyDAV/src/video/v4linux/tdav_producer_video_v4l2.c b/tinyDAV/src/video/v4linux/tdav_producer_video_v4l2.c
index ef3152a..cb023fc 100755
--- a/tinyDAV/src/video/v4linux/tdav_producer_video_v4l2.c
+++ b/tinyDAV/src/video/v4linux/tdav_producer_video_v4l2.c
@@ -1,17 +1,17 @@
/* Copyright (C) 2014 Mamadou DIOP.
-*
+*
* This file is part of Open Source Doubango Framework.
*
* DOUBANGO is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
-*
+*
* DOUBANGO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-*
+*
* You should have received a copy of the GNU General Public License
* along with DOUBANGO.
*/
@@ -53,60 +53,58 @@
#define V4L2_DEBUG_FATAL(FMT, ...) TSK_DEBUG_FATAL("[V4L2 Producer] " FMT, ##__VA_ARGS__)
typedef enum v4l2_io_method_e {
- V4L2_IO_METHOD_NONE = 0,
- V4L2_IO_METHOD_READ,
- V4L2_IO_METHOD_MMAP,
- V4L2_IO_METHOD_USERPTR,
+ V4L2_IO_METHOD_NONE = 0,
+ V4L2_IO_METHOD_READ,
+ V4L2_IO_METHOD_MMAP,
+ V4L2_IO_METHOD_USERPTR,
}
v4l2_io_method_t;
typedef struct v4l2_buffer_s {
- void *p_start;
- size_t n_length;
+ void *p_start;
+ size_t n_length;
}
v4l2_buffer_t;
// By preference order
static const v4l2_io_method_t io_method_prefs[] = {
- V4L2_IO_METHOD_MMAP,
- V4L2_IO_METHOD_USERPTR,
- V4L2_IO_METHOD_READ,
+ V4L2_IO_METHOD_MMAP,
+ V4L2_IO_METHOD_USERPTR,
+ V4L2_IO_METHOD_READ,
};
-static const unsigned int pix_format_prefs[] =
-{
- V4L2_PIX_FMT_YUV420,
- V4L2_PIX_FMT_NV12,
- V4L2_PIX_FMT_NV21,
- V4L2_PIX_FMT_YUYV,
- V4L2_PIX_FMT_UYVY, // SINCITY
- V4L2_PIX_FMT_RGB24,
- V4L2_PIX_FMT_RGB32,
- V4L2_PIX_FMT_MJPEG
+static const unsigned int pix_format_prefs[] = {
+ V4L2_PIX_FMT_YUV420,
+ V4L2_PIX_FMT_NV12,
+ V4L2_PIX_FMT_NV21,
+ V4L2_PIX_FMT_YUYV,
+ V4L2_PIX_FMT_UYVY, // SINCITY
+ V4L2_PIX_FMT_RGB24,
+ V4L2_PIX_FMT_RGB32,
+ V4L2_PIX_FMT_MJPEG
};
-typedef struct tdav_producer_video_v4l2_s
-{
- TMEDIA_DECLARE_PRODUCER;
-
- tsk_bool_t b_muted;
- tsk_bool_t b_started;
- tsk_bool_t b_prepared;
- tsk_bool_t b_paused;
-
- int fd;
- v4l2_io_method_t io;
- struct v4l2_format fmt;
- struct v4l2_capability cap;
- struct v4l2_cropcap cropcap;
- struct v4l2_crop crop;
- unsigned int n_buffers;
- v4l2_buffer_t* p_buffers;
-
- tsk_timer_manager_handle_t *p_timer_mgr;
- tsk_timer_id_t id_timer_grab;
- uint64_t u_timout_grab;
-
- TSK_DECLARE_SAFEOBJ;
+typedef struct tdav_producer_video_v4l2_s {
+ TMEDIA_DECLARE_PRODUCER;
+
+ tsk_bool_t b_muted;
+ tsk_bool_t b_started;
+ tsk_bool_t b_prepared;
+ tsk_bool_t b_paused;
+
+ int fd;
+ v4l2_io_method_t io;
+ struct v4l2_format fmt;
+ struct v4l2_capability cap;
+ struct v4l2_cropcap cropcap;
+ struct v4l2_crop crop;
+ unsigned int n_buffers;
+ v4l2_buffer_t* p_buffers;
+
+ tsk_timer_manager_handle_t *p_timer_mgr;
+ tsk_timer_id_t id_timer_grab;
+ uint64_t u_timout_grab;
+
+ TSK_DECLARE_SAFEOBJ;
}
tdav_producer_video_v4l2_t;
@@ -128,956 +126,960 @@ static int _tdav_producer_video_v4l2_grab(tdav_producer_video_v4l2_t* p_self);
/* ============ Media Producer Interface ================= */
static int _tdav_producer_video_v4l2_set(tmedia_producer_t *p_self, const tmedia_param_t* pc_param)
{
- int ret = 0;
- tdav_producer_video_v4l2_t* p_v4l2 = (tdav_producer_video_v4l2_t*)p_self;
-
- if (!p_v4l2 || !pc_param) {
- V4L2_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- if (pc_param->value_type == tmedia_pvt_pchar) {
- if (tsk_striequals(pc_param->key, "local-hwnd") || tsk_striequals(pc_param->key, "preview-hwnd")) {
- V4L2_DEBUG_ERROR("Not implemented yet");
- }
- else if (tsk_striequals(pc_param->key, "src-hwnd")) {
- V4L2_DEBUG_ERROR("Not implemented yet");
- }
- }
- else if (pc_param->value_type == tmedia_pvt_int32) {
- if (tsk_striequals(pc_param->key, "mute")) {
- p_v4l2->b_muted = (TSK_TO_INT32((uint8_t*)pc_param->value) != 0);
- }
- }
-
- return ret;
+ int ret = 0;
+ tdav_producer_video_v4l2_t* p_v4l2 = (tdav_producer_video_v4l2_t*)p_self;
+
+ if (!p_v4l2 || !pc_param) {
+ V4L2_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (pc_param->value_type == tmedia_pvt_pchar) {
+ if (tsk_striequals(pc_param->key, "local-hwnd") || tsk_striequals(pc_param->key, "preview-hwnd")) {
+ V4L2_DEBUG_ERROR("Not implemented yet");
+ }
+ else if (tsk_striequals(pc_param->key, "src-hwnd")) {
+ V4L2_DEBUG_ERROR("Not implemented yet");
+ }
+ }
+ else if (pc_param->value_type == tmedia_pvt_int32) {
+ if (tsk_striequals(pc_param->key, "mute")) {
+ p_v4l2->b_muted = (TSK_TO_INT32((uint8_t*)pc_param->value) != 0);
+ }
+ }
+
+ return ret;
}
static int _tdav_producer_video_v4l2_prepare(tmedia_producer_t* p_self, const tmedia_codec_t* pc_codec)
{
- tdav_producer_video_v4l2_t* p_v4l2 = (tdav_producer_video_v4l2_t*)p_self;
- int ret = 0;
-
- if (!p_v4l2 || !pc_codec) {
- V4L2_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- tsk_safeobj_lock(p_v4l2);
-
- if (!p_v4l2->p_timer_mgr && !(p_v4l2->p_timer_mgr = tsk_timer_manager_create())) {
- V4L2_DEBUG_ERROR("Failed to create timer manager");
- ret = -2;
- goto bail;
- }
-
- TMEDIA_PRODUCER(p_v4l2)->video.fps = TMEDIA_CODEC_VIDEO(pc_codec)->out.fps;
- TMEDIA_PRODUCER(p_v4l2)->video.width = TMEDIA_CODEC_VIDEO(pc_codec)->out.width;
- TMEDIA_PRODUCER(p_v4l2)->video.height = TMEDIA_CODEC_VIDEO(pc_codec)->out.height;
-
- p_v4l2->u_timout_grab = (1000/TMEDIA_PRODUCER(p_v4l2)->video.fps);
-
- // prepare()
- if ((ret = _v4l2_prepare(p_v4l2))) {
- goto bail;
- }
-
- // update() - up to the "converter" to perform chroma conversion and scaling
- TMEDIA_PRODUCER(p_v4l2)->video.width = p_v4l2->fmt.fmt.pix.width;
- TMEDIA_PRODUCER(p_v4l2)->video.height = p_v4l2->fmt.fmt.pix.height;
+ tdav_producer_video_v4l2_t* p_v4l2 = (tdav_producer_video_v4l2_t*)p_self;
+ int ret = 0;
+
+ if (!p_v4l2 || !pc_codec) {
+ V4L2_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(p_v4l2);
+
+ if (!p_v4l2->p_timer_mgr && !(p_v4l2->p_timer_mgr = tsk_timer_manager_create())) {
+ V4L2_DEBUG_ERROR("Failed to create timer manager");
+ ret = -2;
+ goto bail;
+ }
+
+ TMEDIA_PRODUCER(p_v4l2)->video.fps = TMEDIA_CODEC_VIDEO(pc_codec)->out.fps;
+ TMEDIA_PRODUCER(p_v4l2)->video.width = TMEDIA_CODEC_VIDEO(pc_codec)->out.width;
+ TMEDIA_PRODUCER(p_v4l2)->video.height = TMEDIA_CODEC_VIDEO(pc_codec)->out.height;
+
+ p_v4l2->u_timout_grab = (1000/TMEDIA_PRODUCER(p_v4l2)->video.fps);
+
+ // prepare()
+ if ((ret = _v4l2_prepare(p_v4l2))) {
+ goto bail;
+ }
+
+ // update() - up to the "converter" to perform chroma conversion and scaling
+ TMEDIA_PRODUCER(p_v4l2)->video.width = p_v4l2->fmt.fmt.pix.width;
+ TMEDIA_PRODUCER(p_v4l2)->video.height = p_v4l2->fmt.fmt.pix.height;
#if V4L2_FAKE_UYVY
- TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_uyvy422;
+ TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_uyvy422;
#else
- switch (p_v4l2->fmt.fmt.pix.pixelformat) {
- case V4L2_PIX_FMT_YUV420:
- TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_yuv420p;
- break;
- case V4L2_PIX_FMT_NV12:
- TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_nv12;
- break;
- case V4L2_PIX_FMT_NV21:
- TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_nv21;
- break;
- case V4L2_PIX_FMT_YUYV:
- TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_yuyv422;
- break;
- case V4L2_PIX_FMT_UYVY:
- TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_uyvy422; // SINCITY
- break;
- case V4L2_PIX_FMT_RGB24:
- TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_rgb24;
- break;
- case V4L2_PIX_FMT_RGB32:
- TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_rgb32;
- break;
- case V4L2_PIX_FMT_MJPEG:
- TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_mjpeg;
- break;
- default:
- V4L2_DEBUG_ERROR("Failed to match negotiated format: %d", p_v4l2->fmt.fmt.pix.pixelformat);
- ret = -1;
- goto bail;
- }
+ switch (p_v4l2->fmt.fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_YUV420:
+ TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_yuv420p;
+ break;
+ case V4L2_PIX_FMT_NV12:
+ TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_nv12;
+ break;
+ case V4L2_PIX_FMT_NV21:
+ TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_nv21;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_yuyv422;
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_uyvy422; // SINCITY
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_rgb24;
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_rgb32;
+ break;
+ case V4L2_PIX_FMT_MJPEG:
+ TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_mjpeg;
+ break;
+ default:
+ V4L2_DEBUG_ERROR("Failed to match negotiated format: %d", p_v4l2->fmt.fmt.pix.pixelformat);
+ ret = -1;
+ goto bail;
+ }
#endif /* V4L2_FAKE_UYVY */
- V4L2_DEBUG_INFO("Negotiated caps: fps=%d, width=%d, height=%d, chroma=%d",
- TMEDIA_PRODUCER(p_v4l2)->video.fps,
- TMEDIA_PRODUCER(p_v4l2)->video.width,
- TMEDIA_PRODUCER(p_v4l2)->video.height,
- TMEDIA_PRODUCER(p_v4l2)->video.chroma);
- p_v4l2->b_prepared = (ret == 0) ? tsk_true : tsk_false;
-
+ V4L2_DEBUG_INFO("Negotiated caps: fps=%d, width=%d, height=%d, chroma=%d",
+ TMEDIA_PRODUCER(p_v4l2)->video.fps,
+ TMEDIA_PRODUCER(p_v4l2)->video.width,
+ TMEDIA_PRODUCER(p_v4l2)->video.height,
+ TMEDIA_PRODUCER(p_v4l2)->video.chroma);
+ p_v4l2->b_prepared = (ret == 0) ? tsk_true : tsk_false;
+
bail:
- tsk_safeobj_unlock(p_v4l2);
- return ret;
+ tsk_safeobj_unlock(p_v4l2);
+ return ret;
}
static int _tdav_producer_video_v4l2_start(tmedia_producer_t* p_self)
{
- tdav_producer_video_v4l2_t* p_v4l2 = (tdav_producer_video_v4l2_t*)p_self;
- int ret = 0;
-
- if (!p_v4l2) {
- V4L2_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- tsk_safeobj_lock(p_v4l2);
-
- if (!p_v4l2->b_prepared) {
- V4L2_DEBUG_INFO("Not prepared");
- ret = -1;
- goto bail;
- }
-
- p_v4l2->b_paused = tsk_false;
-
- if (p_v4l2->b_started) {
- V4L2_DEBUG_INFO("Already started");
- goto bail;
- }
-
- if ((ret = tsk_timer_manager_start(p_v4l2->p_timer_mgr))) {
- goto bail;
- }
-
- // start()
- if ((ret = _v4l2_start(p_v4l2))) {
- goto bail;
- }
-
- p_v4l2->b_started = tsk_true;
-
- // Schedule frame grabbing
- p_v4l2->id_timer_grab = tsk_timer_manager_schedule(p_v4l2->p_timer_mgr, p_v4l2->u_timout_grab, _tdav_producer_video_v4l2_timer_cb, p_v4l2);
- if (!TSK_TIMER_ID_IS_VALID(p_v4l2->id_timer_grab)) {
- V4L2_DEBUG_ERROR("Failed to schedule timer with timeout=%llu", p_v4l2->u_timout_grab);
- ret = -2;
- goto bail;
- }
+ tdav_producer_video_v4l2_t* p_v4l2 = (tdav_producer_video_v4l2_t*)p_self;
+ int ret = 0;
+
+ if (!p_v4l2) {
+ V4L2_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(p_v4l2);
+
+ if (!p_v4l2->b_prepared) {
+ V4L2_DEBUG_INFO("Not prepared");
+ ret = -1;
+ goto bail;
+ }
+
+ p_v4l2->b_paused = tsk_false;
+
+ if (p_v4l2->b_started) {
+ V4L2_DEBUG_INFO("Already started");
+ goto bail;
+ }
+
+ if ((ret = tsk_timer_manager_start(p_v4l2->p_timer_mgr))) {
+ goto bail;
+ }
+
+ // start()
+ if ((ret = _v4l2_start(p_v4l2))) {
+ goto bail;
+ }
+
+ p_v4l2->b_started = tsk_true;
+
+ // Schedule frame grabbing
+ p_v4l2->id_timer_grab = tsk_timer_manager_schedule(p_v4l2->p_timer_mgr, p_v4l2->u_timout_grab, _tdav_producer_video_v4l2_timer_cb, p_v4l2);
+ if (!TSK_TIMER_ID_IS_VALID(p_v4l2->id_timer_grab)) {
+ V4L2_DEBUG_ERROR("Failed to schedule timer with timeout=%llu", p_v4l2->u_timout_grab);
+ ret = -2;
+ goto bail;
+ }
bail:
- if (ret) {
- _v4l2_stop(p_v4l2);
- p_v4l2->b_started = tsk_false;
- if (p_v4l2->p_timer_mgr) {
- tsk_timer_manager_stop(p_v4l2->p_timer_mgr);
- }
- }
- else {
- V4L2_DEBUG_INFO("Started :)");
- }
- tsk_safeobj_unlock(p_v4l2);
-
- return ret;
+ if (ret) {
+ _v4l2_stop(p_v4l2);
+ p_v4l2->b_started = tsk_false;
+ if (p_v4l2->p_timer_mgr) {
+ tsk_timer_manager_stop(p_v4l2->p_timer_mgr);
+ }
+ }
+ else {
+ V4L2_DEBUG_INFO("Started :)");
+ }
+ tsk_safeobj_unlock(p_v4l2);
+
+ return ret;
}
static int _tdav_producer_video_v4l2_pause(tmedia_producer_t* p_self)
{
- tdav_producer_video_v4l2_t* p_v4l2 = (tdav_producer_video_v4l2_t*)p_self;
- int ret;
+ tdav_producer_video_v4l2_t* p_v4l2 = (tdav_producer_video_v4l2_t*)p_self;
+ int ret;
- if (!p_v4l2) {
- V4L2_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if (!p_v4l2) {
+ V4L2_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- tsk_safeobj_lock(p_v4l2);
+ tsk_safeobj_lock(p_v4l2);
- if ((ret = _v4l2_pause(p_v4l2))) {
- goto bail;
- }
+ if ((ret = _v4l2_pause(p_v4l2))) {
+ goto bail;
+ }
- p_v4l2->b_paused = tsk_true;
- goto bail;
+ p_v4l2->b_paused = tsk_true;
+ goto bail;
bail:
- tsk_safeobj_unlock(p_v4l2);
+ tsk_safeobj_unlock(p_v4l2);
- return ret;
+ return ret;
}
static int _tdav_producer_video_v4l2_stop(tmedia_producer_t* p_self)
{
- tdav_producer_video_v4l2_t* p_v4l2 = (tdav_producer_video_v4l2_t*)p_self;
-
- if (!p_v4l2) {
- V4L2_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- tsk_safeobj_lock(p_v4l2);
-
- if (!p_v4l2->b_started) {
- V4L2_DEBUG_INFO("Already stopped");
- goto bail;
- }
-
- if (p_v4l2->p_timer_mgr) {
- tsk_timer_manager_stop(p_v4l2->p_timer_mgr);
- }
-
- // next start will be called after prepare()
- _v4l2_unprepare(p_v4l2); // stop() then unprepare()
-
- p_v4l2->b_started = tsk_false;
- p_v4l2->b_paused = tsk_false;
- p_v4l2->b_prepared = tsk_false;
+ tdav_producer_video_v4l2_t* p_v4l2 = (tdav_producer_video_v4l2_t*)p_self;
+
+ if (!p_v4l2) {
+ V4L2_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(p_v4l2);
+
+ if (!p_v4l2->b_started) {
+ V4L2_DEBUG_INFO("Already stopped");
+ goto bail;
+ }
+
+ if (p_v4l2->p_timer_mgr) {
+ tsk_timer_manager_stop(p_v4l2->p_timer_mgr);
+ }
+
+ // next start will be called after prepare()
+ _v4l2_unprepare(p_v4l2); // stop() then unprepare()
+
+ p_v4l2->b_started = tsk_false;
+ p_v4l2->b_paused = tsk_false;
+ p_v4l2->b_prepared = tsk_false;
bail:
- tsk_safeobj_unlock(p_v4l2);
- V4L2_DEBUG_INFO("Stopped");
+ tsk_safeobj_unlock(p_v4l2);
+ V4L2_DEBUG_INFO("Stopped");
- return 0;
+ return 0;
}
static int _v4l2_prepare(tdav_producer_video_v4l2_t* p_self)
{
-const char* device_names[] =
- {
- tmedia_producer_get_friendly_name(TMEDIA_PRODUCER(p_self)->plugin->type),
- "/dev/video0",
- }; // FIXME: VIDIOC_C_ENUM_INPUT and choose best one
- const char* device_name;
- int i, err = -1;
- struct stat st;
- unsigned int min;
-
- V4L2_DEBUG_INFO("--- PREPARE ---");
-
- if (p_self->fd > 0) {
- V4L2_DEBUG_WARN("Producer already prepared");
- return 0;
- }
- for (i = 0; i < sizeof(device_names)/sizeof(device_names[0]); ++i) {
- if ((device_name = device_names[i])) {
- V4L2_DEBUG_INFO("Preparing '%s'...", device_name);
- if (stat(device_name, &st) == -1) {
- V4L2_DEBUG_WARN("stat('%s'): %d, %s", device_name, errno, strerror(errno));
- continue;
- }
- if (!S_ISCHR(st.st_mode)) {
- V4L2_DEBUG_WARN("'%s' not a valid device", device_name);
- continue;
- }
- if ((p_self->fd = open(device_name, O_RDWR /* required */ | O_NONBLOCK, 0)) == -1) {
- V4L2_DEBUG_WARN("Failed to open '%s': %d, %s\n", device_name, errno, strerror(errno));
- continue;
- }
- V4L2_DEBUG_INFO("'%s' successfully opened", device_name);
- }
- }
- if (p_self->fd == -1) {
- V4L2_DEBUG_ERROR("No valid device found");
- goto bail;
- }
-
- if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_QUERYCAP, &p_self->cap)) {
- if (EINVAL == errno) {
- V4L2_DEBUG_ERROR("%s is no V4L2 device", device_name);
- goto bail;
- } else {
- V4L2_DEBUG_ERROR("xioctl(%s, VIDIOC_QUERYCAP) failed: %s error %d", device_name, strerror(errno), errno);
- goto bail;
- }
- }
-
- if (!(p_self->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
- V4L2_DEBUG_ERROR("%s is no video capture device", device_name);
- goto bail;
- }
-
- // Get best io method
- p_self->io = V4L2_IO_METHOD_NONE;
- for (i = 0; i < sizeof(io_method_prefs)/sizeof(io_method_prefs[0]) && p_self->io == V4L2_IO_METHOD_NONE; ++i) {
- V4L2_DEBUG_INFO("Trying with io method=%d", io_method_prefs[i]);
- switch (io_method_prefs[i]) {
- case V4L2_IO_METHOD_READ:
- if (!(p_self->cap.capabilities & V4L2_CAP_READWRITE)) {
- V4L2_DEBUG_WARN("%s does not support read i/o", device_name);
- continue;
- }
- p_self->io = io_method_prefs[i];
- break;
-
- case V4L2_IO_METHOD_MMAP:
- case V4L2_IO_METHOD_USERPTR:
- if (!(p_self->cap.capabilities & V4L2_CAP_STREAMING)) {
- V4L2_DEBUG_WARN("%s does not support streaming i/o", device_name);
- continue;
- }
- p_self->io = io_method_prefs[i];
- break;
- }
- }
- if (p_self->io == V4L2_IO_METHOD_NONE) {
- V4L2_DEBUG_ERROR("Failed to peek an i/o method for '%s' device", device_name);
- goto bail;
- }
- V4L2_DEBUG_INFO("i/o method for '%s' device is %d", device_name, p_self->io);
-
- /* Select video input, video standard and tune here. */
-
- V4L2_CLEAR(p_self->cropcap);
-
- p_self->cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if (0 == _v4l2_xioctl(p_self->fd, VIDIOC_CROPCAP, &p_self->cropcap)) {
- p_self->crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- p_self->crop.c = p_self->cropcap.defrect; /* reset to default */
-
- if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_S_CROP, &p_self->crop)) {
- switch (errno) {
- case EINVAL:
- default:
- V4L2_DEBUG_INFO("'%s' device doesn't support cropping", device_name);
- break;
- }
- }
- else {
- V4L2_DEBUG_INFO("'%s' device supports cropping with type = %d", device_name, p_self->crop.type);
- }
- } else {
- V4L2_DEBUG_INFO("'%s' device doesn't support cropping", device_name);
- }
-
- /* Best format */
- V4L2_CLEAR(p_self->fmt);
- // get()
- if (_v4l2_get_best_format(p_self, device_name, &p_self->fmt) != 0) {
- V4L2_DEBUG_ERROR("Failed to peek best format for '%s' device", device_name);
- goto bail;
- }
- // set()
- if (_v4l2_xioctl(p_self->fd, VIDIOC_S_FMT, &p_self->fmt) == -1) {
- goto bail;
- }
- V4L2_DEBUG_INFO("device '%s' best format: width:%d, height:%d, field:%d, pixelformat:%d",
- device_name, p_self->fmt.fmt.pix.width, p_self->fmt.fmt.pix.height, p_self->fmt.fmt.pix.field, p_self->fmt.fmt.pix.pixelformat);
-
- /* Buggy driver paranoia. */
+ const char* device_names[] = {
+ tmedia_producer_get_friendly_name(TMEDIA_PRODUCER(p_self)->plugin->type),
+ "/dev/video0",
+ }; // FIXME: VIDIOC_C_ENUM_INPUT and choose best one
+ const char* device_name;
+ int i, err = -1;
+ struct stat st;
+ unsigned int min;
+
+ V4L2_DEBUG_INFO("--- PREPARE ---");
+
+ if (p_self->fd > 0) {
+ V4L2_DEBUG_WARN("Producer already prepared");
+ return 0;
+ }
+ for (i = 0; i < sizeof(device_names)/sizeof(device_names[0]); ++i) {
+ if ((device_name = device_names[i])) {
+ V4L2_DEBUG_INFO("Preparing '%s'...", device_name);
+ if (stat(device_name, &st) == -1) {
+ V4L2_DEBUG_WARN("stat('%s'): %d, %s", device_name, errno, strerror(errno));
+ continue;
+ }
+ if (!S_ISCHR(st.st_mode)) {
+ V4L2_DEBUG_WARN("'%s' not a valid device", device_name);
+ continue;
+ }
+ if ((p_self->fd = open(device_name, O_RDWR /* required */ | O_NONBLOCK, 0)) == -1) {
+ V4L2_DEBUG_WARN("Failed to open '%s': %d, %s\n", device_name, errno, strerror(errno));
+ continue;
+ }
+ V4L2_DEBUG_INFO("'%s' successfully opened", device_name);
+ }
+ }
+ if (p_self->fd == -1) {
+ V4L2_DEBUG_ERROR("No valid device found");
+ goto bail;
+ }
+
+ if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_QUERYCAP, &p_self->cap)) {
+ if (EINVAL == errno) {
+ V4L2_DEBUG_ERROR("%s is no V4L2 device", device_name);
+ goto bail;
+ }
+ else {
+ V4L2_DEBUG_ERROR("xioctl(%s, VIDIOC_QUERYCAP) failed: %s error %d", device_name, strerror(errno), errno);
+ goto bail;
+ }
+ }
+
+ if (!(p_self->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
+ V4L2_DEBUG_ERROR("%s is no video capture device", device_name);
+ goto bail;
+ }
+
+ // Get best io method
+ p_self->io = V4L2_IO_METHOD_NONE;
+ for (i = 0; i < sizeof(io_method_prefs)/sizeof(io_method_prefs[0]) && p_self->io == V4L2_IO_METHOD_NONE; ++i) {
+ V4L2_DEBUG_INFO("Trying with io method=%d", io_method_prefs[i]);
+ switch (io_method_prefs[i]) {
+ case V4L2_IO_METHOD_READ:
+ if (!(p_self->cap.capabilities & V4L2_CAP_READWRITE)) {
+ V4L2_DEBUG_WARN("%s does not support read i/o", device_name);
+ continue;
+ }
+ p_self->io = io_method_prefs[i];
+ break;
+
+ case V4L2_IO_METHOD_MMAP:
+ case V4L2_IO_METHOD_USERPTR:
+ if (!(p_self->cap.capabilities & V4L2_CAP_STREAMING)) {
+ V4L2_DEBUG_WARN("%s does not support streaming i/o", device_name);
+ continue;
+ }
+ p_self->io = io_method_prefs[i];
+ break;
+ }
+ }
+ if (p_self->io == V4L2_IO_METHOD_NONE) {
+ V4L2_DEBUG_ERROR("Failed to peek an i/o method for '%s' device", device_name);
+ goto bail;
+ }
+ V4L2_DEBUG_INFO("i/o method for '%s' device is %d", device_name, p_self->io);
+
+ /* Select video input, video standard and tune here. */
+
+ V4L2_CLEAR(p_self->cropcap);
+
+ p_self->cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (0 == _v4l2_xioctl(p_self->fd, VIDIOC_CROPCAP, &p_self->cropcap)) {
+ p_self->crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ p_self->crop.c = p_self->cropcap.defrect; /* reset to default */
+
+ if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_S_CROP, &p_self->crop)) {
+ switch (errno) {
+ case EINVAL:
+ default:
+ V4L2_DEBUG_INFO("'%s' device doesn't support cropping", device_name);
+ break;
+ }
+ }
+ else {
+ V4L2_DEBUG_INFO("'%s' device supports cropping with type = %d", device_name, p_self->crop.type);
+ }
+ }
+ else {
+ V4L2_DEBUG_INFO("'%s' device doesn't support cropping", device_name);
+ }
+
+ /* Best format */
+ V4L2_CLEAR(p_self->fmt);
+ // get()
+ if (_v4l2_get_best_format(p_self, device_name, &p_self->fmt) != 0) {
+ V4L2_DEBUG_ERROR("Failed to peek best format for '%s' device", device_name);
+ goto bail;
+ }
+ // set()
+ if (_v4l2_xioctl(p_self->fd, VIDIOC_S_FMT, &p_self->fmt) == -1) {
+ goto bail;
+ }
+ V4L2_DEBUG_INFO("device '%s' best format: width:%d, height:%d, field:%d, pixelformat:%d",
+ device_name, p_self->fmt.fmt.pix.width, p_self->fmt.fmt.pix.height, p_self->fmt.fmt.pix.field, p_self->fmt.fmt.pix.pixelformat);
+
+ /* Buggy driver paranoia. */
#if 1
- min = p_self->fmt.fmt.pix.width * 2;
- if (p_self->fmt.fmt.pix.bytesperline < min) {
- p_self->fmt.fmt.pix.bytesperline = min;
- }
- min = p_self->fmt.fmt.pix.bytesperline * p_self->fmt.fmt.pix.height;
- if (p_self->fmt.fmt.pix.sizeimage < min) {
- p_self->fmt.fmt.pix.sizeimage = min;
- }
+ min = p_self->fmt.fmt.pix.width * 2;
+ if (p_self->fmt.fmt.pix.bytesperline < min) {
+ p_self->fmt.fmt.pix.bytesperline = min;
+ }
+ min = p_self->fmt.fmt.pix.bytesperline * p_self->fmt.fmt.pix.height;
+ if (p_self->fmt.fmt.pix.sizeimage < min) {
+ p_self->fmt.fmt.pix.sizeimage = min;
+ }
#endif
- switch (p_self->io) {
- case V4L2_IO_METHOD_READ:
- if (_v4l2_init_read(p_self, p_self->fmt.fmt.pix.sizeimage) != 0) {
- goto bail;
- }
- break;
-
- case V4L2_IO_METHOD_MMAP:
- if (_v4l2_init_mmap(p_self, device_name) != 0) {
- goto bail;
- }
- break;
-
- case V4L2_IO_METHOD_USERPTR:
- if (_v4l2_init_userp(p_self, p_self->fmt.fmt.pix.sizeimage, device_name) != 0) {
- goto bail;
- }
- break;
- }
- V4L2_DEBUG_INFO("'%s' device initialized using i/o method=%d", device_name, p_self->io);
-
- // all is OK
- err = 0;
+ switch (p_self->io) {
+ case V4L2_IO_METHOD_READ:
+ if (_v4l2_init_read(p_self, p_self->fmt.fmt.pix.sizeimage) != 0) {
+ goto bail;
+ }
+ break;
+
+ case V4L2_IO_METHOD_MMAP:
+ if (_v4l2_init_mmap(p_self, device_name) != 0) {
+ goto bail;
+ }
+ break;
+
+ case V4L2_IO_METHOD_USERPTR:
+ if (_v4l2_init_userp(p_self, p_self->fmt.fmt.pix.sizeimage, device_name) != 0) {
+ goto bail;
+ }
+ break;
+ }
+ V4L2_DEBUG_INFO("'%s' device initialized using i/o method=%d", device_name, p_self->io);
+
+ // all is OK
+ err = 0;
bail:
- if (err) {
- _v4l2_unprepare(p_self);
- }
- else {
- V4L2_DEBUG_INFO("Prepared :)");
- }
- return err;
+ if (err) {
+ _v4l2_unprepare(p_self);
+ }
+ else {
+ V4L2_DEBUG_INFO("Prepared :)");
+ }
+ return err;
}
static int _v4l2_start(tdav_producer_video_v4l2_t* p_self)
{
- unsigned int i;
- enum v4l2_buf_type type;
-
- V4L2_DEBUG_INFO("--- START ---");
-
- if (p_self->b_started) {
- V4L2_DEBUG_WARN("Already started");
- return 0;
- }
-
- switch (p_self->io) {
- case V4L2_IO_METHOD_READ:
- /* Nothing to do. */
- break;
-
- case V4L2_IO_METHOD_MMAP:
- for (i = 0; i < p_self->n_buffers; ++i) {
- struct v4l2_buffer buf;
-
- V4L2_CLEAR(buf);
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- buf.index = i;
-
- if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_QBUF, &buf)) {
- V4L2_DEBUG_ERROR("xioctl(VIDIOC_QBUF) failed: %s error %d", strerror(errno), errno);
- return -1;
- }
- }
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_STREAMON, &type)) {
- V4L2_DEBUG_ERROR("xioctl(VIDIOC_STREAMON) failed: %s error %d", strerror(errno), errno);
- return -1;
- }
- break;
-
- case V4L2_IO_METHOD_USERPTR:
- for (i = 0; i < p_self->n_buffers; ++i) {
- struct v4l2_buffer buf;
-
- V4L2_CLEAR(buf);
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_USERPTR;
- buf.index = i;
- buf.m.userptr = (unsigned long)p_self->p_buffers[i].p_start;
- buf.length = p_self->p_buffers[i].n_length;
-
- if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_QBUF, &buf)) {
- V4L2_DEBUG_ERROR("xioctl(VIDIOC_QBUF) failed: %s error %d", strerror(errno), errno);
- return -1;
- }
- }
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_STREAMON, &type)) {
- V4L2_DEBUG_ERROR("xioctl(VIDIOC_STREAMON) failed: %s error %d", strerror(errno), errno);
- return -1;
- }
- break;
- }
- return 0;
+ unsigned int i;
+ enum v4l2_buf_type type;
+
+ V4L2_DEBUG_INFO("--- START ---");
+
+ if (p_self->b_started) {
+ V4L2_DEBUG_WARN("Already started");
+ return 0;
+ }
+
+ switch (p_self->io) {
+ case V4L2_IO_METHOD_READ:
+ /* Nothing to do. */
+ break;
+
+ case V4L2_IO_METHOD_MMAP:
+ for (i = 0; i < p_self->n_buffers; ++i) {
+ struct v4l2_buffer buf;
+
+ V4L2_CLEAR(buf);
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = i;
+
+ if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_QBUF, &buf)) {
+ V4L2_DEBUG_ERROR("xioctl(VIDIOC_QBUF) failed: %s error %d", strerror(errno), errno);
+ return -1;
+ }
+ }
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_STREAMON, &type)) {
+ V4L2_DEBUG_ERROR("xioctl(VIDIOC_STREAMON) failed: %s error %d", strerror(errno), errno);
+ return -1;
+ }
+ break;
+
+ case V4L2_IO_METHOD_USERPTR:
+ for (i = 0; i < p_self->n_buffers; ++i) {
+ struct v4l2_buffer buf;
+
+ V4L2_CLEAR(buf);
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_USERPTR;
+ buf.index = i;
+ buf.m.userptr = (unsigned long)p_self->p_buffers[i].p_start;
+ buf.length = p_self->p_buffers[i].n_length;
+
+ if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_QBUF, &buf)) {
+ V4L2_DEBUG_ERROR("xioctl(VIDIOC_QBUF) failed: %s error %d", strerror(errno), errno);
+ return -1;
+ }
+ }
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_STREAMON, &type)) {
+ V4L2_DEBUG_ERROR("xioctl(VIDIOC_STREAMON) failed: %s error %d", strerror(errno), errno);
+ return -1;
+ }
+ break;
+ }
+ return 0;
}
static int _v4l2_pause(tdav_producer_video_v4l2_t* p_self)
{
- V4L2_DEBUG_INFO("--- PAUSE ---");
+ V4L2_DEBUG_INFO("--- PAUSE ---");
- return 0;
+ return 0;
}
static int _v4l2_stop(tdav_producer_video_v4l2_t* p_self)
{
- enum v4l2_buf_type type;
-
- V4L2_DEBUG_INFO("--- STOP ---");
-
- switch (p_self->io) {
- case V4L2_IO_METHOD_READ:
- /* Nothing to do. */
- break;
-
- case V4L2_IO_METHOD_MMAP:
- case V4L2_IO_METHOD_USERPTR:
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (p_self->fd != -1 && -1 == _v4l2_xioctl(p_self->fd, VIDIOC_STREAMOFF, &type)) {
- if (p_self->b_started) { // display error only if the device is marked as "started"
- V4L2_DEBUG_ERROR("xioctl(VIDIOC_STREAMOFF) failed: %s error %d", strerror(errno), errno);
- return -1;
- }
- }
- break;
- }
-
- return 0;
+ enum v4l2_buf_type type;
+
+ V4L2_DEBUG_INFO("--- STOP ---");
+
+ switch (p_self->io) {
+ case V4L2_IO_METHOD_READ:
+ /* Nothing to do. */
+ break;
+
+ case V4L2_IO_METHOD_MMAP:
+ case V4L2_IO_METHOD_USERPTR:
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (p_self->fd != -1 && -1 == _v4l2_xioctl(p_self->fd, VIDIOC_STREAMOFF, &type)) {
+ if (p_self->b_started) { // display error only if the device is marked as "started"
+ V4L2_DEBUG_ERROR("xioctl(VIDIOC_STREAMOFF) failed: %s error %d", strerror(errno), errno);
+ return -1;
+ }
+ }
+ break;
+ }
+
+ return 0;
}
static int _v4l2_unprepare(tdav_producer_video_v4l2_t* p_self)
{
- unsigned int i;
- V4L2_DEBUG_INFO("--- UNPREPARE ---");
-
- _v4l2_stop(p_self);
-
- switch (p_self->io) {
- case V4L2_IO_METHOD_READ:
- if (p_self->p_buffers && p_self->p_buffers[0].p_start) {
- free(p_self->p_buffers[0].p_start);
- p_self->p_buffers[0].p_start = NULL;
- }
- break;
- case V4L2_IO_METHOD_MMAP:
- for (i = 0; i < p_self->n_buffers; ++i) {
- if (p_self->p_buffers && p_self->p_buffers[i].p_start) {
- if (-1 == munmap(p_self->p_buffers[i].p_start, p_self->p_buffers[i].n_length)) {
- V4L2_DEBUG_ERROR("munmap(%d) failed", i);
- }
- }
- }
- break;
-
- case V4L2_IO_METHOD_USERPTR:
- for (i = 0; i < p_self->n_buffers; ++i) {
- if (p_self->p_buffers && p_self->p_buffers[i].p_start) {
- free(p_self->p_buffers[i].p_start);
- p_self->p_buffers[i].p_start = NULL;
- }
- }
- break;
- }
-
- if (p_self->p_buffers) {
- free(p_self->p_buffers);
- p_self->p_buffers = NULL;
- }
- p_self->n_buffers = 0;
-
- if (p_self->fd > 0) {
- close(p_self->fd);
- }
- p_self->fd = -1;
-
- return 0;
+ unsigned int i;
+ V4L2_DEBUG_INFO("--- UNPREPARE ---");
+
+ _v4l2_stop(p_self);
+
+ switch (p_self->io) {
+ case V4L2_IO_METHOD_READ:
+ if (p_self->p_buffers && p_self->p_buffers[0].p_start) {
+ free(p_self->p_buffers[0].p_start);
+ p_self->p_buffers[0].p_start = NULL;
+ }
+ break;
+ case V4L2_IO_METHOD_MMAP:
+ for (i = 0; i < p_self->n_buffers; ++i) {
+ if (p_self->p_buffers && p_self->p_buffers[i].p_start) {
+ if (-1 == munmap(p_self->p_buffers[i].p_start, p_self->p_buffers[i].n_length)) {
+ V4L2_DEBUG_ERROR("munmap(%d) failed", i);
+ }
+ }
+ }
+ break;
+
+ case V4L2_IO_METHOD_USERPTR:
+ for (i = 0; i < p_self->n_buffers; ++i) {
+ if (p_self->p_buffers && p_self->p_buffers[i].p_start) {
+ free(p_self->p_buffers[i].p_start);
+ p_self->p_buffers[i].p_start = NULL;
+ }
+ }
+ break;
+ }
+
+ if (p_self->p_buffers) {
+ free(p_self->p_buffers);
+ p_self->p_buffers = NULL;
+ }
+ p_self->n_buffers = 0;
+
+ if (p_self->fd > 0) {
+ close(p_self->fd);
+ }
+ p_self->fd = -1;
+
+ return 0;
}
static int _v4l2_xioctl(int fh, int request, void *arg)
{
- int r;
- do {
- r = ioctl(fh, request, arg);
- } while (-1 == r && EINTR == errno);
- return r;
+ int r;
+ do {
+ r = ioctl(fh, request, arg);
+ }
+ while (-1 == r && EINTR == errno);
+ return r;
}
static int _v4l2_get_best_format(tdav_producer_video_v4l2_t* p_self, const char* device_name, struct v4l2_format* fmt_ret)
{
- struct v4l2_format fmt, fmt_default, fmt_best;
- struct v4l2_fmtdesc fmtdesc;
- int i, j, field, size;
- int ok = 0;
-
- if (!fmt_ret) {
- V4L2_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- // get default format
- V4L2_CLEAR(fmt_default);
- fmt_default.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (_v4l2_xioctl(p_self->fd, VIDIOC_G_FMT, &fmt_default) == -1) {
- V4L2_DEBUG_ERROR("xioctl(%s, VIDIOC_G_FMT) failed: %s error %d", device_name, strerror(errno), errno);
- return -1;
- }
- V4L2_DEBUG_INFO("device '%s' default format: width:%d, height:%d, field:%d, pixelformat:%d",
- device_name, fmt_default.fmt.pix.width, fmt_default.fmt.pix.height, fmt_default.fmt.pix.field, fmt_default.fmt.pix.pixelformat);
-
- /* Best format (using preference) */
- V4L2_CLEAR(fmt);
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- for (i = 0; i < sizeof(pix_format_prefs)/sizeof(pix_format_prefs[0]); ++i) {
- for (size = 0; size < 2; ++size) {
- for (field = 0; field < 2; ++field) {
- fmt.fmt.pix.width = (size == 0) ? TMEDIA_PRODUCER(p_self)->video.width : fmt_default.fmt.pix.width;
- fmt.fmt.pix.height = (size == 0) ? TMEDIA_PRODUCER(p_self)->video.height : fmt_default.fmt.pix.height;
- fmt.fmt.pix.pixelformat = pix_format_prefs[i];
- fmt.fmt.pix.field = (field == 0) ? V4L2_FIELD_NONE : V4L2_FIELD_INTERLACED;
- if ((ok = (_v4l2_xioctl(p_self->fd, VIDIOC_TRY_FMT, &fmt) != -1))) {
- goto bail;
- }
- }
- }
- }
-
- /* Best format (using caps) */
- for (i = 0; ; ++i) {
- V4L2_CLEAR(fmtdesc);
- fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmtdesc.index = i;
-
- if (_v4l2_xioctl(p_self->fd, VIDIOC_ENUM_FMT, &fmtdesc) == -1) {
- break;
- }
- V4L2_DEBUG_INFO("CAPS: device name=%s, fmtdesc index=%d, type=%d, description=%s, pixelformat=%d",
- device_name, fmtdesc.index, fmtdesc.type, fmtdesc.description, fmtdesc.pixelformat);
- for (j = 0; j < sizeof(pix_format_prefs)/sizeof(pix_format_prefs[0]); ++j) {
- if (fmtdesc.pixelformat == pix_format_prefs[j]) {
- for (size = 0; size < 2; ++size) {
- for (field = 0; field < 2; ++field) {
- fmt.fmt.pix.width = (size == 0) ? TMEDIA_PRODUCER(p_self)->video.width : fmt_default.fmt.pix.width;
- fmt.fmt.pix.height = (size == 0) ? TMEDIA_PRODUCER(p_self)->video.height : fmt_default.fmt.pix.height;
- fmt.fmt.pix.pixelformat = pix_format_prefs[i];
- fmt.fmt.pix.field = (field == 0) ? V4L2_FIELD_NONE : V4L2_FIELD_INTERLACED;
- if ((ok = (_v4l2_xioctl(p_self->fd, VIDIOC_TRY_FMT, &fmt) != -1))) {
- goto bail;
- }
- }
- }
- }
- }
- }
+ struct v4l2_format fmt, fmt_default, fmt_best;
+ struct v4l2_fmtdesc fmtdesc;
+ int i, j, field, size;
+ int ok = 0;
+
+ if (!fmt_ret) {
+ V4L2_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ // get default format
+ V4L2_CLEAR(fmt_default);
+ fmt_default.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (_v4l2_xioctl(p_self->fd, VIDIOC_G_FMT, &fmt_default) == -1) {
+ V4L2_DEBUG_ERROR("xioctl(%s, VIDIOC_G_FMT) failed: %s error %d", device_name, strerror(errno), errno);
+ return -1;
+ }
+ V4L2_DEBUG_INFO("device '%s' default format: width:%d, height:%d, field:%d, pixelformat:%d",
+ device_name, fmt_default.fmt.pix.width, fmt_default.fmt.pix.height, fmt_default.fmt.pix.field, fmt_default.fmt.pix.pixelformat);
+
+ /* Best format (using preference) */
+ V4L2_CLEAR(fmt);
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ for (i = 0; i < sizeof(pix_format_prefs)/sizeof(pix_format_prefs[0]); ++i) {
+ for (size = 0; size < 2; ++size) {
+ for (field = 0; field < 2; ++field) {
+ fmt.fmt.pix.width = (size == 0) ? TMEDIA_PRODUCER(p_self)->video.width : fmt_default.fmt.pix.width;
+ fmt.fmt.pix.height = (size == 0) ? TMEDIA_PRODUCER(p_self)->video.height : fmt_default.fmt.pix.height;
+ fmt.fmt.pix.pixelformat = pix_format_prefs[i];
+ fmt.fmt.pix.field = (field == 0) ? V4L2_FIELD_NONE : V4L2_FIELD_INTERLACED;
+ if ((ok = (_v4l2_xioctl(p_self->fd, VIDIOC_TRY_FMT, &fmt) != -1))) {
+ goto bail;
+ }
+ }
+ }
+ }
+
+ /* Best format (using caps) */
+ for (i = 0; ; ++i) {
+ V4L2_CLEAR(fmtdesc);
+ fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmtdesc.index = i;
+
+ if (_v4l2_xioctl(p_self->fd, VIDIOC_ENUM_FMT, &fmtdesc) == -1) {
+ break;
+ }
+ V4L2_DEBUG_INFO("CAPS: device name=%s, fmtdesc index=%d, type=%d, description=%s, pixelformat=%d",
+ device_name, fmtdesc.index, fmtdesc.type, fmtdesc.description, fmtdesc.pixelformat);
+ for (j = 0; j < sizeof(pix_format_prefs)/sizeof(pix_format_prefs[0]); ++j) {
+ if (fmtdesc.pixelformat == pix_format_prefs[j]) {
+ for (size = 0; size < 2; ++size) {
+ for (field = 0; field < 2; ++field) {
+ fmt.fmt.pix.width = (size == 0) ? TMEDIA_PRODUCER(p_self)->video.width : fmt_default.fmt.pix.width;
+ fmt.fmt.pix.height = (size == 0) ? TMEDIA_PRODUCER(p_self)->video.height : fmt_default.fmt.pix.height;
+ fmt.fmt.pix.pixelformat = pix_format_prefs[i];
+ fmt.fmt.pix.field = (field == 0) ? V4L2_FIELD_NONE : V4L2_FIELD_INTERLACED;
+ if ((ok = (_v4l2_xioctl(p_self->fd, VIDIOC_TRY_FMT, &fmt) != -1))) {
+ goto bail;
+ }
+ }
+ }
+ }
+ }
+ }
bail:
- if (ok) {
- memcpy(fmt_ret, &fmt, sizeof(fmt));
- }
- return ok ? 0 : -1;
+ if (ok) {
+ memcpy(fmt_ret, &fmt, sizeof(fmt));
+ }
+ return ok ? 0 : -1;
}
static int _v4l2_init_read(tdav_producer_video_v4l2_t* p_self, unsigned int buffer_size)
{
- if (p_self->p_buffers) {
- V4L2_DEBUG_ERROR("Buffers already initialized");
- return -1;
- }
- if (!buffer_size) {
- V4L2_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- if (!(p_self->p_buffers = calloc(1, sizeof(*p_self->p_buffers)))) {
- V4L2_DEBUG_ERROR("Out of memory");
- return -1;
- }
-
- p_self->p_buffers[0].n_length = buffer_size;
- p_self->p_buffers[0].p_start = tsk_malloc(buffer_size);
-
- if (!p_self->p_buffers[0].p_start) {
- V4L2_DEBUG_ERROR("Out of memory");
- return -1;
- }
-
- return 0;
+ if (p_self->p_buffers) {
+ V4L2_DEBUG_ERROR("Buffers already initialized");
+ return -1;
+ }
+ if (!buffer_size) {
+ V4L2_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (!(p_self->p_buffers = calloc(1, sizeof(*p_self->p_buffers)))) {
+ V4L2_DEBUG_ERROR("Out of memory");
+ return -1;
+ }
+
+ p_self->p_buffers[0].n_length = buffer_size;
+ p_self->p_buffers[0].p_start = tsk_malloc(buffer_size);
+
+ if (!p_self->p_buffers[0].p_start) {
+ V4L2_DEBUG_ERROR("Out of memory");
+ return -1;
+ }
+
+ return 0;
}
static int _v4l2_init_mmap(tdav_producer_video_v4l2_t* p_self, const char* device_name)
{
- struct v4l2_requestbuffers req;
-
- V4L2_CLEAR(req);
-
- req.count = 4;
- req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- req.memory = V4L2_MEMORY_MMAP;
-
- if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_REQBUFS, &req)) {
- if (EINVAL == errno) {
- V4L2_DEBUG_ERROR("%s does not support memory mapping", device_name);
- return -1;
- } else {
- V4L2_DEBUG_ERROR("xioctl(%s, VIDIOC_REQBUFS) failed: %s error %d", device_name, strerror(errno), errno);
- return -1;
- }
- }
-
- if (req.count < 2) {
- V4L2_DEBUG_ERROR("Insufficient buffer memory on %s", device_name);
- return -1;
- }
-
- if (!(p_self->p_buffers = tsk_calloc(req.count, sizeof(*p_self->p_buffers)))) {
- V4L2_DEBUG_ERROR("Out of memory");
- return -1;
- }
-
- for (p_self->n_buffers = 0; p_self->n_buffers < req.count; ++p_self->n_buffers) {
- struct v4l2_buffer buf;
-
- V4L2_CLEAR(buf);
-
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- buf.index = p_self->n_buffers;
-
- if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_QUERYBUF, &buf)) {
- V4L2_DEBUG_ERROR("xioctl(%s, VIDIOC_REQBUFS) failed: %s error %d", device_name, strerror(errno), errno);
- return -1;
- }
-
- p_self->p_buffers[p_self->n_buffers].n_length = buf.length;
- p_self->p_buffers[p_self->n_buffers].p_start = mmap(NULL /* start anywhere */,
- buf.length,
- PROT_READ | PROT_WRITE /* required */,
- MAP_SHARED /* recommended */,
- p_self->fd, buf.m.offset);
-
- if (MAP_FAILED == p_self->p_buffers[p_self->n_buffers].p_start) {
- V4L2_DEBUG_ERROR("mmap(%s) failed: %s error %d", device_name, strerror(errno), errno);
- return -1;
- }
- }
-
- return 0;
+ struct v4l2_requestbuffers req;
+
+ V4L2_CLEAR(req);
+
+ req.count = 4;
+ req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ req.memory = V4L2_MEMORY_MMAP;
+
+ if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_REQBUFS, &req)) {
+ if (EINVAL == errno) {
+ V4L2_DEBUG_ERROR("%s does not support memory mapping", device_name);
+ return -1;
+ }
+ else {
+ V4L2_DEBUG_ERROR("xioctl(%s, VIDIOC_REQBUFS) failed: %s error %d", device_name, strerror(errno), errno);
+ return -1;
+ }
+ }
+
+ if (req.count < 2) {
+ V4L2_DEBUG_ERROR("Insufficient buffer memory on %s", device_name);
+ return -1;
+ }
+
+ if (!(p_self->p_buffers = tsk_calloc(req.count, sizeof(*p_self->p_buffers)))) {
+ V4L2_DEBUG_ERROR("Out of memory");
+ return -1;
+ }
+
+ for (p_self->n_buffers = 0; p_self->n_buffers < req.count; ++p_self->n_buffers) {
+ struct v4l2_buffer buf;
+
+ V4L2_CLEAR(buf);
+
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = p_self->n_buffers;
+
+ if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_QUERYBUF, &buf)) {
+ V4L2_DEBUG_ERROR("xioctl(%s, VIDIOC_REQBUFS) failed: %s error %d", device_name, strerror(errno), errno);
+ return -1;
+ }
+
+ p_self->p_buffers[p_self->n_buffers].n_length = buf.length;
+ p_self->p_buffers[p_self->n_buffers].p_start = mmap(NULL /* start anywhere */,
+ buf.length,
+ PROT_READ | PROT_WRITE /* required */,
+ MAP_SHARED /* recommended */,
+ p_self->fd, buf.m.offset);
+
+ if (MAP_FAILED == p_self->p_buffers[p_self->n_buffers].p_start) {
+ V4L2_DEBUG_ERROR("mmap(%s) failed: %s error %d", device_name, strerror(errno), errno);
+ return -1;
+ }
+ }
+
+ return 0;
}
static int _v4l2_init_userp(tdav_producer_video_v4l2_t* p_self, unsigned int buffer_size, const char* device_name)
{
- struct v4l2_requestbuffers req;
-
- V4L2_CLEAR(req);
-
- req.count = 4;
- req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- req.memory = V4L2_MEMORY_USERPTR;
-
- if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_REQBUFS, &req)) {
- if (EINVAL == errno) {
- V4L2_DEBUG_ERROR("%s does not support user pointer i/o", device_name);
- return -1;
- } else {
- V4L2_DEBUG_ERROR("xioctl(%s, VIDIOC_REQBUFS) failed: %s error %d", device_name, strerror(errno), errno);
- return -1;
- }
- }
-
- if (!(p_self->p_buffers = tsk_calloc(4, sizeof(*p_self->p_buffers)))) {
- V4L2_DEBUG_ERROR("Out of memory");
- return -1;
- }
-
- for (p_self->n_buffers = 0; p_self->n_buffers < 4; ++p_self->n_buffers) {
- p_self->p_buffers[p_self->n_buffers].n_length = buffer_size;
- p_self->p_buffers[p_self->n_buffers].p_start = tsk_malloc(buffer_size);
-
- if (!p_self->p_buffers[p_self->n_buffers].p_start) {
- V4L2_DEBUG_ERROR("Out of memory");
- return -1;
- }
- }
-
- return 0;
+ struct v4l2_requestbuffers req;
+
+ V4L2_CLEAR(req);
+
+ req.count = 4;
+ req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ req.memory = V4L2_MEMORY_USERPTR;
+
+ if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_REQBUFS, &req)) {
+ if (EINVAL == errno) {
+ V4L2_DEBUG_ERROR("%s does not support user pointer i/o", device_name);
+ return -1;
+ }
+ else {
+ V4L2_DEBUG_ERROR("xioctl(%s, VIDIOC_REQBUFS) failed: %s error %d", device_name, strerror(errno), errno);
+ return -1;
+ }
+ }
+
+ if (!(p_self->p_buffers = tsk_calloc(4, sizeof(*p_self->p_buffers)))) {
+ V4L2_DEBUG_ERROR("Out of memory");
+ return -1;
+ }
+
+ for (p_self->n_buffers = 0; p_self->n_buffers < 4; ++p_self->n_buffers) {
+ p_self->p_buffers[p_self->n_buffers].n_length = buffer_size;
+ p_self->p_buffers[p_self->n_buffers].p_start = tsk_malloc(buffer_size);
+
+ if (!p_self->p_buffers[p_self->n_buffers].p_start) {
+ V4L2_DEBUG_ERROR("Out of memory");
+ return -1;
+ }
+ }
+
+ return 0;
}
static int _v4l2_send_frame(tdav_producer_video_v4l2_t* p_self)
{
- struct v4l2_buffer buf;
- unsigned int i;
+ struct v4l2_buffer buf;
+ unsigned int i;
#define V4L2_SEND_BUFF(_buff, _size) \
TMEDIA_PRODUCER(p_self)->enc_cb.callback(TMEDIA_PRODUCER(p_self)->enc_cb.callback_data, (_buff), (_size));
#if V4L2_FAKE_UYVY
- {
- tsk_size_t size = (TMEDIA_PRODUCER(p_self)->video.width * TMEDIA_PRODUCER(p_self)->video.height) << 1;
- uint8_t* buff = (uint8_t*)tsk_malloc(size);
- if (buff) {
- tsk_size_t i;
- for (i = 0; i < size; ++i) {
- buff[i] = rand() & 254;
- }
- V4L2_SEND_BUFF(buff, size);
- tsk_free((void**)&buff);
- }
- return 0;
- }
+ {
+ tsk_size_t size = (TMEDIA_PRODUCER(p_self)->video.width * TMEDIA_PRODUCER(p_self)->video.height) << 1;
+ uint8_t* buff = (uint8_t*)tsk_malloc(size);
+ if (buff) {
+ tsk_size_t i;
+ for (i = 0; i < size; ++i) {
+ buff[i] = rand() & 254;
+ }
+ V4L2_SEND_BUFF(buff, size);
+ tsk_free((void**)&buff);
+ }
+ return 0;
+ }
#endif
- switch (p_self->io) {
- case V4L2_IO_METHOD_READ:
- if (-1 == read(p_self->fd, p_self->p_buffers[0].p_start, p_self->p_buffers[0].n_length)) {
- switch (errno) {
- case EAGAIN:
- return 0;
+ switch (p_self->io) {
+ case V4L2_IO_METHOD_READ:
+ if (-1 == read(p_self->fd, p_self->p_buffers[0].p_start, p_self->p_buffers[0].n_length)) {
+ switch (errno) {
+ case EAGAIN:
+ return 0;
- case EIO:
- /* Could ignore EIO, see spec. */
+ case EIO:
+ /* Could ignore EIO, see spec. */
- /* fall through */
+ /* fall through */
- default:
- V4L2_DEBUG_ERROR("read() failed: %s error %d", strerror(errno), errno);
- break;
- }
- }
+ default:
+ V4L2_DEBUG_ERROR("read() failed: %s error %d", strerror(errno), errno);
+ break;
+ }
+ }
- V4L2_SEND_BUFF(p_self->p_buffers[0].p_start, p_self->p_buffers[0].n_length);
- return 0;
+ V4L2_SEND_BUFF(p_self->p_buffers[0].p_start, p_self->p_buffers[0].n_length);
+ return 0;
- case V4L2_IO_METHOD_MMAP:
- V4L2_CLEAR(buf);
+ case V4L2_IO_METHOD_MMAP:
+ V4L2_CLEAR(buf);
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
- if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_DQBUF, &buf)) {
- switch (errno) {
- case EAGAIN:
- V4L2_DEBUG_INFO("EAGAIN");
- return 0;
+ if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_DQBUF, &buf)) {
+ switch (errno) {
+ case EAGAIN:
+ V4L2_DEBUG_INFO("EAGAIN");
+ return 0;
- case EIO:
- /* Could ignore EIO, see spec. */
+ case EIO:
+ /* Could ignore EIO, see spec. */
- /* fall through */
+ /* fall through */
- default:
- V4L2_DEBUG_ERROR("xioctl(VIDIOC_DQBUF) failed: %s error %d", strerror(errno), errno);
- break;
- }
- }
+ default:
+ V4L2_DEBUG_ERROR("xioctl(VIDIOC_DQBUF) failed: %s error %d", strerror(errno), errno);
+ break;
+ }
+ }
- assert(buf.index < p_self->n_buffers);
+ assert(buf.index < p_self->n_buffers);
- V4L2_SEND_BUFF(p_self->p_buffers[buf.index].p_start, buf.bytesused);
+ V4L2_SEND_BUFF(p_self->p_buffers[buf.index].p_start, buf.bytesused);
- if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_QBUF, &buf)) {
- V4L2_DEBUG_ERROR("xioctl(VIDIOC_DQBUF) failed: %s error %d", strerror(errno), errno);
- break;
- }
- return 0;
+ if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_QBUF, &buf)) {
+ V4L2_DEBUG_ERROR("xioctl(VIDIOC_DQBUF) failed: %s error %d", strerror(errno), errno);
+ break;
+ }
+ return 0;
- case V4L2_IO_METHOD_USERPTR:
- V4L2_CLEAR(buf);
+ case V4L2_IO_METHOD_USERPTR:
+ V4L2_CLEAR(buf);
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_USERPTR;
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_USERPTR;
- if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_DQBUF, &buf)) {
- switch (errno) {
- case EAGAIN:
- V4L2_DEBUG_INFO("EAGAIN");
- return 0;
+ if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_DQBUF, &buf)) {
+ switch (errno) {
+ case EAGAIN:
+ V4L2_DEBUG_INFO("EAGAIN");
+ return 0;
- case EIO:
- /* Could ignore EIO, see spec. */
+ case EIO:
+ /* Could ignore EIO, see spec. */
- /* fall through */
+ /* fall through */
- default:
- V4L2_DEBUG_ERROR("xioctl(VIDIOC_DQBUF) failed: %s error %d", strerror(errno), errno);
- break;
- }
- }
+ default:
+ V4L2_DEBUG_ERROR("xioctl(VIDIOC_DQBUF) failed: %s error %d", strerror(errno), errno);
+ break;
+ }
+ }
- for (i = 0; i < p_self->n_buffers; ++i) {
- if (buf.m.userptr == (unsigned long)p_self->p_buffers[i].p_start && buf.length == p_self->p_buffers[i].n_length) {
- break;
- }
- }
+ for (i = 0; i < p_self->n_buffers; ++i) {
+ if (buf.m.userptr == (unsigned long)p_self->p_buffers[i].p_start && buf.length == p_self->p_buffers[i].n_length) {
+ break;
+ }
+ }
- V4L2_SEND_BUFF((void *)buf.m.userptr, buf.bytesused);
+ V4L2_SEND_BUFF((void *)buf.m.userptr, buf.bytesused);
- if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_QBUF, &buf)) {
- V4L2_DEBUG_ERROR("xioctl(VIDIOC_DQBUF) failed: %s error %d", strerror(errno), errno);
- break;
- }
- return 0;
- }
+ if (-1 == _v4l2_xioctl(p_self->fd, VIDIOC_QBUF, &buf)) {
+ V4L2_DEBUG_ERROR("xioctl(VIDIOC_DQBUF) failed: %s error %d", strerror(errno), errno);
+ break;
+ }
+ return 0;
+ }
- return -1;
+ return -1;
}
static int _tdav_producer_video_v4l2_timer_cb(const void* arg, tsk_timer_id_t timer_id)
{
- tdav_producer_video_v4l2_t* p_v4l2 = (tdav_producer_video_v4l2_t*)arg;
- int ret = 0;
-
- tsk_safeobj_lock(p_v4l2);
-
- if (p_v4l2->id_timer_grab == timer_id) {
- if (ret = _tdav_producer_video_v4l2_grab(p_v4l2)) {
- // goto bail;
- }
- if (p_v4l2->b_started) {
- p_v4l2->id_timer_grab = tsk_timer_manager_schedule(p_v4l2->p_timer_mgr, p_v4l2->u_timout_grab, _tdav_producer_video_v4l2_timer_cb, p_v4l2);
- if (!TSK_TIMER_ID_IS_VALID(p_v4l2->id_timer_grab)) {
- V4L2_DEBUG_ERROR("Failed to schedule timer with timeout=%llu", p_v4l2->u_timout_grab);
- ret = -2;
- goto bail;
- }
- }
- }
+ tdav_producer_video_v4l2_t* p_v4l2 = (tdav_producer_video_v4l2_t*)arg;
+ int ret = 0;
+
+ tsk_safeobj_lock(p_v4l2);
+
+ if (p_v4l2->id_timer_grab == timer_id) {
+ if (ret = _tdav_producer_video_v4l2_grab(p_v4l2)) {
+ // goto bail;
+ }
+ if (p_v4l2->b_started) {
+ p_v4l2->id_timer_grab = tsk_timer_manager_schedule(p_v4l2->p_timer_mgr, p_v4l2->u_timout_grab, _tdav_producer_video_v4l2_timer_cb, p_v4l2);
+ if (!TSK_TIMER_ID_IS_VALID(p_v4l2->id_timer_grab)) {
+ V4L2_DEBUG_ERROR("Failed to schedule timer with timeout=%llu", p_v4l2->u_timout_grab);
+ ret = -2;
+ goto bail;
+ }
+ }
+ }
bail:
- tsk_safeobj_unlock(p_v4l2);
- return ret;
+ tsk_safeobj_unlock(p_v4l2);
+ return ret;
}
static int _tdav_producer_video_v4l2_grab(tdav_producer_video_v4l2_t* p_self)
{
- int ret = 0, r;
- fd_set fds;
- struct timeval tv;
-
- if (!p_self) {
- V4L2_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- tsk_safeobj_lock(p_self);
-
- if (!p_self->b_started) {
- V4L2_DEBUG_ERROR("producer not started yet");
- ret = -2;
- goto bail;
- }
-
- if (!TMEDIA_PRODUCER(p_self)->enc_cb.callback) {
- goto bail;
- }
-
- FD_ZERO(&fds);
- FD_SET(p_self->fd, &fds);
-
- /* Timeout. */
- tv.tv_sec = 0;
- tv.tv_usec = (p_self->id_timer_grab * 1000);
- while (tv.tv_usec >= 1000000) {
- tv.tv_usec -= 1000000;
- tv.tv_sec++;
- }
-
- r = select(p_self->fd + 1, &fds, NULL, NULL, &tv);
-
- if (-1 == r) {
- if (EINTR == errno) {
- V4L2_DEBUG_INFO("select() returned EINTR");
- }
- else {
- V4L2_DEBUG_ERROR("select() failed: %s error %d", strerror(errno), errno);
- }
- goto bail;
- }
-
- if (0 == r) {
- V4L2_DEBUG_INFO("select() timeout: %s error %d", strerror(errno), errno);
- goto bail;
- }
- // Grab a frame
- if ((ret = _v4l2_send_frame(p_self))) {
- goto bail;
- }
+ int ret = 0, r;
+ fd_set fds;
+ struct timeval tv;
+
+ if (!p_self) {
+ V4L2_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(p_self);
+
+ if (!p_self->b_started) {
+ V4L2_DEBUG_ERROR("producer not started yet");
+ ret = -2;
+ goto bail;
+ }
+
+ if (!TMEDIA_PRODUCER(p_self)->enc_cb.callback) {
+ goto bail;
+ }
+
+ FD_ZERO(&fds);
+ FD_SET(p_self->fd, &fds);
+
+ /* Timeout. */
+ tv.tv_sec = 0;
+ tv.tv_usec = (p_self->id_timer_grab * 1000);
+ while (tv.tv_usec >= 1000000) {
+ tv.tv_usec -= 1000000;
+ tv.tv_sec++;
+ }
+
+ r = select(p_self->fd + 1, &fds, NULL, NULL, &tv);
+
+ if (-1 == r) {
+ if (EINTR == errno) {
+ V4L2_DEBUG_INFO("select() returned EINTR");
+ }
+ else {
+ V4L2_DEBUG_ERROR("select() failed: %s error %d", strerror(errno), errno);
+ }
+ goto bail;
+ }
+
+ if (0 == r) {
+ V4L2_DEBUG_INFO("select() timeout: %s error %d", strerror(errno), errno);
+ goto bail;
+ }
+ // Grab a frame
+ if ((ret = _v4l2_send_frame(p_self))) {
+ goto bail;
+ }
bail:
- tsk_safeobj_unlock(p_self);
+ tsk_safeobj_unlock(p_self);
- return ret;
+ return ret;
}
//
@@ -1086,78 +1088,75 @@ bail:
/* constructor */
static tsk_object_t* _tdav_producer_video_v4l2_ctor(tsk_object_t *self, va_list * app)
{
- tdav_producer_video_v4l2_t *p_v4l2 = (tdav_producer_video_v4l2_t *)self;
- if (p_v4l2) {
- /* init base */
- tmedia_producer_init(TMEDIA_PRODUCER(p_v4l2));
- TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_yuv420p;
- /* init self with default values*/
- p_v4l2->fd = -1;
- TMEDIA_PRODUCER(p_v4l2)->video.fps = 15;
- TMEDIA_PRODUCER(p_v4l2)->video.width = 352;
- TMEDIA_PRODUCER(p_v4l2)->video.height = 288;
-
- tsk_safeobj_init(p_v4l2);
- }
- return self;
+ tdav_producer_video_v4l2_t *p_v4l2 = (tdav_producer_video_v4l2_t *)self;
+ if (p_v4l2) {
+ /* init base */
+ tmedia_producer_init(TMEDIA_PRODUCER(p_v4l2));
+ TMEDIA_PRODUCER(p_v4l2)->video.chroma = tmedia_chroma_yuv420p;
+ /* init self with default values*/
+ p_v4l2->fd = -1;
+ TMEDIA_PRODUCER(p_v4l2)->video.fps = 15;
+ TMEDIA_PRODUCER(p_v4l2)->video.width = 352;
+ TMEDIA_PRODUCER(p_v4l2)->video.height = 288;
+
+ tsk_safeobj_init(p_v4l2);
+ }
+ return self;
}
/* destructor */
static tsk_object_t* _tdav_producer_video_v4l2_dtor(tsk_object_t * self)
-{
- tdav_producer_video_v4l2_t *p_v4l2 = (tdav_producer_video_v4l2_t *)self;
- if (p_v4l2) {
- /* stop */
- if (p_v4l2->b_started) {
- _tdav_producer_video_v4l2_stop((tmedia_producer_t*)p_v4l2);
- }
-
- /* deinit base */
- tmedia_producer_deinit(TMEDIA_PRODUCER(p_v4l2));
- /* deinit self */
- _v4l2_unprepare(p_v4l2);
- TSK_OBJECT_SAFE_FREE(p_v4l2->p_timer_mgr);
- tsk_safeobj_deinit(p_v4l2);
-
- V4L2_DEBUG_INFO("*** destroyed ***");
- }
-
- return self;
+{
+ tdav_producer_video_v4l2_t *p_v4l2 = (tdav_producer_video_v4l2_t *)self;
+ if (p_v4l2) {
+ /* stop */
+ if (p_v4l2->b_started) {
+ _tdav_producer_video_v4l2_stop((tmedia_producer_t*)p_v4l2);
+ }
+
+ /* deinit base */
+ tmedia_producer_deinit(TMEDIA_PRODUCER(p_v4l2));
+ /* deinit self */
+ _v4l2_unprepare(p_v4l2);
+ TSK_OBJECT_SAFE_FREE(p_v4l2->p_timer_mgr);
+ tsk_safeobj_deinit(p_v4l2);
+
+ V4L2_DEBUG_INFO("*** destroyed ***");
+ }
+
+ return self;
}
/* object definition */
-static const tsk_object_def_t tdav_producer_video_v4l2_def_s =
-{
- sizeof(tdav_producer_video_v4l2_t),
- _tdav_producer_video_v4l2_ctor,
- _tdav_producer_video_v4l2_dtor,
- tsk_null,
+static const tsk_object_def_t tdav_producer_video_v4l2_def_s = {
+ sizeof(tdav_producer_video_v4l2_t),
+ _tdav_producer_video_v4l2_ctor,
+ _tdav_producer_video_v4l2_dtor,
+ tsk_null,
};
/* plugin definition*/
// Video
-static const tmedia_producer_plugin_def_t tdav_producer_video_v4l2_plugin_def_s =
-{
- &tdav_producer_video_v4l2_def_s,
- tmedia_video,
- "V4L2 video producer",
-
- _tdav_producer_video_v4l2_set,
- _tdav_producer_video_v4l2_prepare,
- _tdav_producer_video_v4l2_start,
- _tdav_producer_video_v4l2_pause,
- _tdav_producer_video_v4l2_stop
+static const tmedia_producer_plugin_def_t tdav_producer_video_v4l2_plugin_def_s = {
+ &tdav_producer_video_v4l2_def_s,
+ tmedia_video,
+ "V4L2 video producer",
+
+ _tdav_producer_video_v4l2_set,
+ _tdav_producer_video_v4l2_prepare,
+ _tdav_producer_video_v4l2_start,
+ _tdav_producer_video_v4l2_pause,
+ _tdav_producer_video_v4l2_stop
};
const tmedia_producer_plugin_def_t *tdav_producer_video_v4l2_plugin_def_t = &tdav_producer_video_v4l2_plugin_def_s;
// Screencast
-static const tmedia_producer_plugin_def_t tdav_producer_screencast_v4l2_plugin_def_s =
-{
- &tdav_producer_video_v4l2_def_s,
- tmedia_bfcp_video,
- "V4L2 screencast producer",
-
- _tdav_producer_video_v4l2_set,
- _tdav_producer_video_v4l2_prepare,
- _tdav_producer_video_v4l2_start,
- _tdav_producer_video_v4l2_pause,
- _tdav_producer_video_v4l2_stop
+static const tmedia_producer_plugin_def_t tdav_producer_screencast_v4l2_plugin_def_s = {
+ &tdav_producer_video_v4l2_def_s,
+ tmedia_bfcp_video,
+ "V4L2 screencast producer",
+
+ _tdav_producer_video_v4l2_set,
+ _tdav_producer_video_v4l2_prepare,
+ _tdav_producer_video_v4l2_start,
+ _tdav_producer_video_v4l2_pause,
+ _tdav_producer_video_v4l2_stop
};
const tmedia_producer_plugin_def_t *tdav_producer_screencast_v4l2_plugin_def_t = &tdav_producer_screencast_v4l2_plugin_def_s;
#endif /* HAVE_LINUX_VIDEODEV2_H */
OpenPOWER on IntegriCloud