Skip to content
Snippets Groups Projects
Commit 05ddbeb1 authored by fryshorts's avatar fryshorts
Browse files

Add function to prepare frame structure to v4l2 plugin.

This adds a function to prepare the source_frame struct for use
with obs_source_output_video. Since all of the values except for
the timestamp and data pointers are known in before it makes
little sense to compute them over and over again.

Due to the fact that v4l2 uses a single continuous memory segment
for multi planar formats we can also precompute memory offsets for
the planes.
parent a5e53d5a
No related branches found
No related tags found
No related merge requests found
......@@ -253,12 +253,69 @@ static void v4l2_destroy_mmap(struct v4l2_data *data)
bfree(data->buf);
}
/**
* Prepare the output frame structure for obs and compute plane offsets
*
* Basically all data apart from memory pointers and the timestamp is known
* before the capture starts. This function prepares the source_frame struct
* with all the data that is already known.
*
* v4l2 uses a continuous memory segment for all planes so we simply compute
* offsets to add to the start address in order to give obs the correct data
* pointers for the individual planes.
*/
static void v4l2_prep_obs_frame(struct v4l2_data *data,
struct source_frame *frame, size_t *plane_offsets)
{
memset(frame, 0, sizeof(struct source_frame));
memset(plane_offsets, 0, sizeof(size_t) * MAX_AV_PLANES);
frame->width = data->width;
frame->height = data->height;
frame->format = v4l2_to_obs_video_format(data->pixelformat);
video_format_get_parameters(VIDEO_CS_DEFAULT, VIDEO_RANGE_PARTIAL,
frame->color_matrix, frame->color_range_min,
frame->color_range_max);
switch(data->pixelformat) {
case V4L2_PIX_FMT_NV12:
frame->linesize[0] = data->linesize;
frame->linesize[1] = data->linesize / 2;
plane_offsets[1] = data->linesize * data->height;
break;
case V4L2_PIX_FMT_YVU420:
frame->linesize[0] = data->linesize;
frame->linesize[1] = data->linesize / 2;
frame->linesize[2] = data->linesize / 2;
plane_offsets[1] = data->linesize * data->height * 5 / 4;
plane_offsets[2] = data->linesize * data->height;
break;
case V4L2_PIX_FMT_YUV420:
frame->linesize[0] = data->linesize;
frame->linesize[1] = data->linesize / 2;
frame->linesize[2] = data->linesize / 2;
plane_offsets[1] = data->linesize * data->height;
plane_offsets[2] = data->linesize * data->height * 5 / 4;
break;
default:
frame->linesize[0] = data->linesize;
break;
}
}
/*
* Worker thread to get video data
*/
static void *v4l2_thread(void *vptr)
{
V4L2_DATA(vptr);
int r;
fd_set fds;
uint8_t *start;
struct timeval tv;
struct v4l2_buffer buf;
struct source_frame out;
size_t plane_offsets[MAX_AV_PLANES];
if (v4l2_start_capture(data) < 0)
goto exit;
......@@ -266,20 +323,12 @@ static void *v4l2_thread(void *vptr)
data->frames = 0;
blog(LOG_INFO, "Started recording from %s", data->device);
uint_fast8_t cb = (data->pixelformat == V4L2_PIX_FMT_YUV420) ? 1 : 2;
uint_fast8_t cr = (cb == 1) ? 2 : 1;
while (os_event_try(data->event) == EAGAIN) {
int r;
fd_set fds;
uint8_t *start;
struct timeval tv;
struct v4l2_buffer buf;
struct source_frame out;
FD_ZERO(&fds);
FD_SET(data->dev, &fds);
FD_ZERO(&fds);
FD_SET(data->dev, &fds);
v4l2_prep_obs_frame(data, &out, plane_offsets);
while (os_event_try(data->event) == EAGAIN) {
tv.tv_sec = 1;
tv.tv_usec = 0;
......@@ -304,40 +353,10 @@ static void *v4l2_thread(void *vptr)
break;
}
video_format_get_parameters(VIDEO_CS_DEFAULT,
VIDEO_RANGE_PARTIAL, out.color_matrix,
out.color_range_min, out.color_range_max);
start = (uint8_t *) data->buf[buf.index].start;
switch (data->pixelformat) {
case V4L2_PIX_FMT_NV12:
out.data[0] = start;
out.data[1] = start + data->linesize * data->height;
out.linesize[0] = data->linesize;
out.linesize[1] = data->linesize / 2;
break;
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_YUV420: {
out.data[0] = start;
out.data[cb] = start + data->linesize * data->height;
out.data[cr] = start + data->linesize * data->height
* 5 / 4;
out.linesize[0] = data->linesize;
out.linesize[cb] = data->linesize / 2;
out.linesize[cr] = data->linesize / 2;
break;
}
default:
out.data[0] = start;
out.linesize[0] = data->linesize;
break;
}
out.width = data->width;
out.height = data->height;
out.timestamp = timeval2ns(buf.timestamp);
out.format = v4l2_to_obs_video_format(data->pixelformat);
start = (uint8_t *) data->buf[buf.index].start;
for (uint_fast32_t i = 0; i < MAX_AV_PLANES; ++i)
out.data[i] = start + plane_offsets[i];
obs_source_output_video(data->source, &out);
if (v4l2_ioctl(data->dev, VIDIOC_QBUF, &buf) < 0) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment