From 9f2c069f76260c344839f4522fa6c0887055ae53 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Wed, 11 Jul 2018 15:16:52 +0200 Subject: [PATCH] Rework buffer management to be more generic and support untiled format Signed-off-by: Paul Kocialkowski --- src/Makefile.am | 4 +- src/context.c | 2 +- src/image.c | 45 +++++++++++++++------- src/mpeg2.c | 40 ++++++++++---------- src/picture.c | 14 +++---- src/sunxi_cedrus.h | 4 ++ src/surface.c | 79 +++++++++++++++++++++++++++----------- src/surface.h | 15 ++++++-- src/v4l2.c | 94 ++++++++++++++++++++++++++++++++-------------- src/v4l2.h | 12 ++++-- src/video.c | 72 +++++++++++++++++++++++++++++++++++ src/video.h | 49 ++++++++++++++++++++++++ 12 files changed, 330 insertions(+), 100 deletions(-) create mode 100644 src/video.c create mode 100644 src/video.h diff --git a/src/Makefile.am b/src/Makefile.am index f8a0108..d5c1247 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,12 +5,12 @@ backend_ldflags = -module -avoid-version -no-undefined -Wl,--no-undefined backend_libs = -lpthread -ldl $(DRM_LIBS) $(LIBVA_DEPS_LIBS) backend_c = sunxi_cedrus.c object_heap.c config.c surface.c context.c buffer.c \ - mpeg2.c picture.c subpicture.c image.c v4l2.c media.c utils.c + mpeg2.c picture.c subpicture.c image.c v4l2.c video.c media.c utils.c backend_s = tiled_yuv.S backend_h = sunxi_cedrus.h object_heap.h config.h surface.h context.h buffer.h \ - mpeg2.h picture.h subpicture.h image.h v4l2.h media.h utils.h \ + mpeg2.h picture.h subpicture.h image.h v4l2.h video.h media.h utils.h \ tiled_yuv.h sunxi_cedrus_drv_video_la_LTLIBRARIES = sunxi_cedrus_drv_video.la diff --git a/src/context.c b/src/context.c index 80d0fc2..812f8e9 100644 --- a/src/context.c +++ b/src/context.c @@ -109,7 +109,7 @@ VAStatus SunxiCedrusCreateContext(VADriverContextP context, goto error; } - rc = v4l2_request_buffer(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, i, &length, &offset); + rc = v4l2_request_buffer(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, i, &length, &offset, 1); if (rc < 0) { status = VA_STATUS_ERROR_ALLOCATION_FAILED; goto error; diff --git a/src/image.c b/src/image.c index 71353d1..44a678e 100644 --- a/src/image.c +++ b/src/image.c @@ -31,28 +31,41 @@ #include #include +#include "v4l2.h" #include "tiled_yuv.h" +#include "utils.h" VAStatus SunxiCedrusCreateImage(VADriverContextP context, VAImageFormat *format, int width, int height, VAImage *image) { struct sunxi_cedrus_driver_data *driver_data = (struct sunxi_cedrus_driver_data *) context->pDriverData; + unsigned int destination_sizes[VIDEO_MAX_PLANES]; + unsigned int destination_bytesperlines[VIDEO_MAX_PLANES]; + unsigned int destination_planes_count; + unsigned int size; struct object_image *image_object; VABufferID buffer_id; VAImageID id; VAStatus status; - int sizeY, sizeUV; + unsigned int i; + int rc; - sizeY = width * height; - sizeUV = (width * (height + 1) / 2); + rc = v4l2_get_format(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, NULL, NULL, destination_bytesperlines, destination_sizes, &destination_planes_count); + if (rc < 0) + return VA_STATUS_ERROR_OPERATION_FAILED; + + size = 0; + + for (i = 0; i < destination_planes_count; i++) + size += destination_sizes[i]; id = object_heap_allocate(&driver_data->image_heap); image_object = IMAGE(id); if (image_object == NULL) return VA_STATUS_ERROR_ALLOCATION_FAILED; - status = SunxiCedrusCreateBuffer(context, 0, VAImageBufferType, sizeY + sizeUV, 1, NULL, &buffer_id); + status = SunxiCedrusCreateBuffer(context, 0, VAImageBufferType, size, 1, NULL, &buffer_id); if (status != VA_STATUS_SUCCESS) { object_heap_free(&driver_data->image_heap, (struct object_base *) image_object); return status; @@ -65,15 +78,17 @@ VAStatus SunxiCedrusCreateImage(VADriverContextP context, VAImageFormat *format, image->format = *format; image->width = width; image->height = height; - image->num_planes = 2; - image->pitches[0] = (width + 31) & ~31; - image->pitches[1] = (width + 31) & ~31; - image->offsets[0] = 0; - image->offsets[1] = sizeY; - image->data_size = sizeY + sizeUV; image->buf = buffer_id; image->image_id = id; + image->num_planes = destination_planes_count; + image->data_size = size; + + for (i = 0; i < image->num_planes; i++) { + image->pitches[i] = destination_bytesperlines[i]; + image->offsets[i] = i > 0 ? destination_sizes[i-1] : 0; + } + return VA_STATUS_SUCCESS; } @@ -104,6 +119,7 @@ VAStatus SunxiCedrusDeriveImage(VADriverContextP context, (struct sunxi_cedrus_driver_data *) context->pDriverData; struct object_surface *surface_object; struct object_buffer *buffer_object; + unsigned int i; VAImageFormat format; VAStatus status; @@ -129,9 +145,12 @@ VAStatus SunxiCedrusDeriveImage(VADriverContextP context, if (buffer_object == NULL) return VA_STATUS_ERROR_INVALID_BUFFER; - /* TODO: Use an appropriate DRM plane instead */ - tiled_to_planar(surface_object->destination_data[0], buffer_object->data, image->pitches[0], image->width, image->height); - tiled_to_planar(surface_object->destination_data[1], buffer_object->data + image->width*image->height, image->pitches[1], image->width, image->height/2); + for (i = 0; i < surface_object->destination_planes_count; i++) { + if (driver_data->tiled_format) + tiled_to_planar(surface_object->destination_data[i], buffer_object->data + image->offsets[i], image->pitches[i], image->width, i == 0 ? image->height : image->height / 2); + else + memcpy(buffer_object->data + image->offsets[i], surface_object->destination_data[i], surface_object->destination_sizes[i]); + } surface_object->status = VASurfaceReady; diff --git a/src/mpeg2.c b/src/mpeg2.c index 02f18dc..acb200d 100644 --- a/src/mpeg2.c +++ b/src/mpeg2.c @@ -39,39 +39,39 @@ int mpeg2_fill_picture_parameters(struct sunxi_cedrus_driver_data *driver_data, struct object_surface *surface_object, VAPictureParameterBufferMPEG2 *parameters) { - struct v4l2_ctrl_mpeg2_slice_header *header = &surface_object->mpeg2_header; + struct v4l2_ctrl_mpeg2_slice_params *slice_params = &surface_object->mpeg2_slice_params; struct object_surface *forward_reference_surface; struct object_surface *backward_reference_surface; - header->width = context_object->picture_width; - header->height = context_object->picture_height; + slice_params->width = context_object->picture_width; + slice_params->height = context_object->picture_height; - header->picture_coding_type = parameters->picture_coding_type; - header->f_code[0][0] = (parameters->f_code >> 12) & 0x0f; - header->f_code[0][1] = (parameters->f_code >> 8) & 0x0f; - header->f_code[1][0] = (parameters->f_code >> 4) & 0x0f; - header->f_code[1][1] = (parameters->f_code >> 0) & 0x0f; + slice_params->slice_type = parameters->picture_coding_type; + slice_params->f_code[0][0] = (parameters->f_code >> 12) & 0x0f; + slice_params->f_code[0][1] = (parameters->f_code >> 8) & 0x0f; + slice_params->f_code[1][0] = (parameters->f_code >> 4) & 0x0f; + slice_params->f_code[1][1] = (parameters->f_code >> 0) & 0x0f; - header->intra_dc_precision = parameters->picture_coding_extension.bits.intra_dc_precision; - header->picture_structure = parameters->picture_coding_extension.bits.picture_structure; - header->top_field_first = parameters->picture_coding_extension.bits.top_field_first; - header->frame_pred_frame_dct = parameters->picture_coding_extension.bits.frame_pred_frame_dct; - header->concealment_motion_vectors = parameters->picture_coding_extension.bits.concealment_motion_vectors; - header->q_scale_type = parameters->picture_coding_extension.bits.q_scale_type; - header->intra_vlc_format = parameters->picture_coding_extension.bits.intra_vlc_format; - header->alternate_scan = parameters->picture_coding_extension.bits.alternate_scan; + slice_params->intra_dc_precision = parameters->picture_coding_extension.bits.intra_dc_precision; + slice_params->picture_structure = parameters->picture_coding_extension.bits.picture_structure; + slice_params->top_field_first = parameters->picture_coding_extension.bits.top_field_first; + slice_params->frame_pred_frame_dct = parameters->picture_coding_extension.bits.frame_pred_frame_dct; + slice_params->concealment_motion_vectors = parameters->picture_coding_extension.bits.concealment_motion_vectors; + slice_params->q_scale_type = parameters->picture_coding_extension.bits.q_scale_type; + slice_params->intra_vlc_format = parameters->picture_coding_extension.bits.intra_vlc_format; + slice_params->alternate_scan = parameters->picture_coding_extension.bits.alternate_scan; forward_reference_surface = SURFACE(parameters->forward_reference_picture); if (forward_reference_surface != NULL) - header->forward_ref_index = forward_reference_surface->destination_index; + slice_params->forward_ref_index = forward_reference_surface->destination_index; else - header->forward_ref_index = surface_object->destination_index; + slice_params->forward_ref_index = surface_object->destination_index; backward_reference_surface = SURFACE(parameters->backward_reference_picture); if (backward_reference_surface != NULL) - header->backward_ref_index = backward_reference_surface->destination_index; + slice_params->backward_ref_index = backward_reference_surface->destination_index; else - header->backward_ref_index = surface_object->destination_index; + slice_params->backward_ref_index = surface_object->destination_index; return 0; } diff --git a/src/picture.c b/src/picture.c index 58ab79b..6740fe4 100644 --- a/src/picture.c +++ b/src/picture.c @@ -168,12 +168,12 @@ VAStatus SunxiCedrusEndPicture(VADriverContextP context, switch (config_object->profile) { case VAProfileMPEG2Simple: case VAProfileMPEG2Main: - surface_object->mpeg2_header.slice_pos = 0; - surface_object->mpeg2_header.slice_len = surface_object->slices_size * 8; + surface_object->mpeg2_slice_params.slice_pos = 0; + surface_object->mpeg2_slice_params.slice_len = surface_object->slices_size * 8; - control_id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_HEADER; - control_data = &surface_object->mpeg2_header; - control_size = sizeof(surface_object->mpeg2_header); + control_id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS; + control_data = &surface_object->mpeg2_slice_params; + control_size = sizeof(surface_object->mpeg2_slice_params); break; default: @@ -184,11 +184,11 @@ VAStatus SunxiCedrusEndPicture(VADriverContextP context, if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; - rc = v4l2_queue_buffer(driver_data->video_fd, -1, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, surface_object->destination_index, 0); + rc = v4l2_queue_buffer(driver_data->video_fd, -1, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, surface_object->destination_index, 0, surface_object->destination_buffers_count); if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; - rc = v4l2_queue_buffer(driver_data->video_fd, request_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, surface_object->source_index, surface_object->slices_size); + rc = v4l2_queue_buffer(driver_data->video_fd, request_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, surface_object->source_index, surface_object->slices_size, 1); if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; diff --git a/src/sunxi_cedrus.h b/src/sunxi_cedrus.h index d6edf58..68a4136 100644 --- a/src/sunxi_cedrus.h +++ b/src/sunxi_cedrus.h @@ -26,6 +26,8 @@ #ifndef _SUNXI_CEDRUS_H_ #define _SUNXI_CEDRUS_H_ +#include + #include #include "object_heap.h" #include "context.h" @@ -49,6 +51,8 @@ struct sunxi_cedrus_driver_data { struct object_heap image_heap; int video_fd; int media_fd; + + bool tiled_format; }; VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context); diff --git a/src/surface.c b/src/surface.c index 5250c02..c28b75f 100644 --- a/src/surface.c +++ b/src/surface.c @@ -38,6 +38,7 @@ #include #include "v4l2.h" +#include "video.h" #include "media.h" #include "utils.h" @@ -47,17 +48,33 @@ VAStatus SunxiCedrusCreateSurfaces(VADriverContextP context, int width, struct sunxi_cedrus_driver_data *driver_data = (struct sunxi_cedrus_driver_data *) context->pDriverData; struct object_surface *surface_object; - unsigned int length[2]; - unsigned int offset[2]; - void *destination_data[2]; - VASurfaceID id; + struct video_format *video_format; + unsigned int destination_sizes[VIDEO_MAX_PLANES]; + unsigned int destination_bytesperlines[VIDEO_MAX_PLANES]; + unsigned int destination_planes_count; unsigned int i, j; + VASurfaceID id; + bool found; int rc; if (format != VA_RT_FORMAT_YUV420) return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT; - rc = v4l2_set_format(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, V4L2_PIX_FMT_MB32_NV12, width, height); + driver_data->tiled_format = true; + + found = v4l2_find_format(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, V4L2_PIX_FMT_NV12); + if (found) + driver_data->tiled_format = false; + + video_format = video_format_find(driver_data->tiled_format); + if (video_format == NULL) + return VA_STATUS_ERROR_OPERATION_FAILED; + + rc = v4l2_set_format(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, video_format->v4l2_format, width, height); + if (rc < 0) + return VA_STATUS_ERROR_OPERATION_FAILED; + + rc = v4l2_get_format(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, NULL, NULL, destination_bytesperlines, destination_sizes, &destination_planes_count); if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; @@ -71,33 +88,50 @@ VAStatus SunxiCedrusCreateSurfaces(VADriverContextP context, int width, if (surface_object == NULL) return VA_STATUS_ERROR_ALLOCATION_FAILED; - rc = v4l2_request_buffer(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, i, length, offset); + rc = v4l2_request_buffer(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, i, surface_object->destination_map_lengths, surface_object->destination_map_offsets, video_format->v4l2_buffers_count); if (rc < 0) return VA_STATUS_ERROR_ALLOCATION_FAILED; - destination_data[0] = mmap(NULL, length[0], PROT_READ | PROT_WRITE, MAP_SHARED, driver_data->video_fd, offset[0]); - if (destination_data[0] == MAP_FAILED) - return VA_STATUS_ERROR_ALLOCATION_FAILED; + for (j = 0; j < video_format->v4l2_buffers_count; j++) { + surface_object->destination_map[j] = mmap(NULL, surface_object->destination_map_lengths[j], PROT_READ | PROT_WRITE, MAP_SHARED, driver_data->video_fd, surface_object->destination_map_offsets[j]); + if (surface_object->destination_map[j] == MAP_FAILED) + return VA_STATUS_ERROR_ALLOCATION_FAILED; + } - destination_data[1] = mmap(NULL, length[1], PROT_READ | PROT_WRITE, MAP_SHARED, driver_data->video_fd, offset[1]); - if (destination_data[1] == MAP_FAILED) + if (video_format->v4l2_buffers_count == 1) { + for (j = 0; j < destination_planes_count; j++) { + surface_object->destination_offsets[j] = j > 0 ? destination_sizes[j-1] : 0; + surface_object->destination_data[j] = (void *) ((unsigned char *) surface_object->destination_map[0] + surface_object->destination_offsets[j]); + surface_object->destination_sizes[j] = destination_sizes[j]; + surface_object->destination_bytesperlines[j] = destination_bytesperlines[j]; + } + } else if (video_format->v4l2_buffers_count == destination_planes_count) { + for (j = 0; j < destination_planes_count; j++) { + surface_object->destination_offsets[j] = 0; + surface_object->destination_data[j] = surface_object->destination_map[j]; + surface_object->destination_sizes[j] = destination_sizes[j]; + surface_object->destination_bytesperlines[j] = destination_bytesperlines[j]; + } + } else { return VA_STATUS_ERROR_ALLOCATION_FAILED; + } surface_object->status = VASurfaceReady; surface_object->width = width; surface_object->height = height; + surface_object->source_index = 0; surface_object->source_data = NULL; surface_object->source_size = 0; + surface_object->destination_index = 0; - for (j = 0; j < 2; j++) { - surface_object->destination_data[j] = destination_data[j]; - surface_object->destination_size[j] = length[j]; - } + surface_object->destination_planes_count = destination_planes_count; + surface_object->destination_buffers_count = video_format->v4l2_buffers_count; - memset(&surface_object->mpeg2_header, 0, sizeof(surface_object->mpeg2_header)); + memset(&surface_object->mpeg2_slice_params, 0, sizeof(surface_object->mpeg2_slice_params)); surface_object->slices_size = 0; + surface_object->request_fd = -1; surfaces_ids[i] = id; @@ -125,9 +159,12 @@ VAStatus SunxiCedrusDestroySurfaces(VADriverContextP context, if (surface_object->request_fd >= 0) close(surface_object->request_fd); - for (j = 0; j < 2; j++) - if (surface_object->destination_data[j] != NULL && surface_object->destination_size[j] > 0) - munmap(surface_object->destination_data[j], surface_object->destination_size[j]); + for (j = 0; j < surface_object->destination_buffers_count; j++) + if (surface_object->destination_map[j] != NULL && surface_object->destination_map_lengths[j] > 0) + munmap(surface_object->destination_map[j], surface_object->destination_map_lengths[j]); + + if (surface_object->request_fd > 0) + close(surface_object->request_fd); object_heap_free(&driver_data->surface_heap, (struct object_base *) surface_object); } @@ -180,13 +217,13 @@ VAStatus SunxiCedrusSyncSurface(VADriverContextP context, goto error; } - rc = v4l2_dequeue_buffer(driver_data->video_fd, -1, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, surface_object->source_index); + rc = v4l2_dequeue_buffer(driver_data->video_fd, -1, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, surface_object->source_index, 1); if (rc < 0) { status = VA_STATUS_ERROR_OPERATION_FAILED; goto error; } - rc = v4l2_dequeue_buffer(driver_data->video_fd, -1, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, surface_object->destination_index); + rc = v4l2_dequeue_buffer(driver_data->video_fd, -1, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, surface_object->destination_index, surface_object->destination_buffers_count); if (rc < 0) { status = VA_STATUS_ERROR_OPERATION_FAILED; goto error; diff --git a/src/surface.h b/src/surface.h index 1bbd868..b749c58 100644 --- a/src/surface.h +++ b/src/surface.h @@ -26,6 +26,8 @@ #ifndef _SURFACE_H_ #define _SURFACE_H_ +#include + #include #include "object_heap.h" @@ -45,10 +47,17 @@ struct object_surface { unsigned int source_size; unsigned int destination_index; - void *destination_data[2]; - unsigned int destination_size[2]; + void *destination_map[VIDEO_MAX_PLANES]; + unsigned int destination_map_lengths[VIDEO_MAX_PLANES]; + unsigned int destination_map_offsets[VIDEO_MAX_PLANES]; + void *destination_data[VIDEO_MAX_PLANES]; + unsigned int destination_sizes[VIDEO_MAX_PLANES]; + unsigned int destination_offsets[VIDEO_MAX_PLANES]; + unsigned int destination_bytesperlines[VIDEO_MAX_PLANES]; + unsigned int destination_planes_count; + unsigned int destination_buffers_count; - struct v4l2_ctrl_mpeg2_slice_header mpeg2_header; + struct v4l2_ctrl_mpeg2_slice_params mpeg2_slice_params; unsigned int slices_size; int request_fd; diff --git a/src/v4l2.c b/src/v4l2.c index dde1509..3d02954 100644 --- a/src/v4l2.c +++ b/src/v4l2.c @@ -65,10 +65,8 @@ int v4l2_set_format(int video_fd, unsigned int type, unsigned int pixelformat, format.type = type; format.fmt.pix_mp.width = width; format.fmt.pix_mp.height = height; - format.fmt.pix_mp.plane_fmt[0].sizeimage = type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? DESTINATION_SIZE_MAX : 0; + format.fmt.pix_mp.plane_fmt[0].sizeimage = type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? SOURCE_SIZE_MAX : 0; format.fmt.pix_mp.pixelformat = pixelformat; - format.fmt.pix_mp.field = V4L2_FIELD_ANY; - format.fmt.pix_mp.num_planes = type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? 2 : 1; rc = ioctl(video_fd, VIDIOC_S_FMT, &format); if (rc < 0) { @@ -79,6 +77,50 @@ int v4l2_set_format(int video_fd, unsigned int type, unsigned int pixelformat, return 0; } +int v4l2_get_format(int video_fd, unsigned int type, unsigned int *width, + unsigned int *height, unsigned int *bytesperline, unsigned int *sizes, + unsigned int *planes_count) +{ + struct v4l2_format format; + unsigned int count; + unsigned int i; + int rc; + + memset(&format, 0, sizeof(format)); + format.type = type; + + rc = ioctl(video_fd, VIDIOC_G_FMT, &format); + if (rc < 0) { + sunxi_cedrus_log("Unable to get format for type %d: %s\n", type, strerror(errno)); + return -1; + } + + count = format.fmt.pix_mp.num_planes; + + if (width != NULL) + *width = format.fmt.pix_mp.width; + + if (height != NULL) + *height = format.fmt.pix_mp.height; + + if (planes_count != NULL) + if (*planes_count > 0 && *planes_count < count) + count = *planes_count; + + if (bytesperline != NULL) + for (i = 0; i < count; i++) + bytesperline[i] = format.fmt.pix_mp.plane_fmt[i].bytesperline; + + if (sizes != NULL) + for (i = 0; i < count; i++) + sizes[i] = format.fmt.pix_mp.plane_fmt[i].sizeimage; + + if (planes_count != NULL) + *planes_count = count; + + return 0; +} + int v4l2_create_buffers(int video_fd, unsigned int type, unsigned int buffers_count) { @@ -106,10 +148,12 @@ int v4l2_create_buffers(int video_fd, unsigned int type, } int v4l2_request_buffer(int video_fd, unsigned int type, unsigned int index, - unsigned int *length, unsigned int *offset) + unsigned int *lengths, unsigned int *offsets, + unsigned int buffers_count) { - struct v4l2_plane planes[2]; + struct v4l2_plane planes[buffers_count]; struct v4l2_buffer buffer; + unsigned int i; int rc; memset(planes, 0, sizeof(planes)); @@ -118,7 +162,7 @@ int v4l2_request_buffer(int video_fd, unsigned int type, unsigned int index, buffer.type = type; buffer.memory = V4L2_MEMORY_MMAP; buffer.index = index; - buffer.length = type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? 2 : 1; + buffer.length = buffers_count; buffer.m.planes = planes; rc = ioctl(video_fd, VIDIOC_QUERYBUF, &buffer); @@ -127,32 +171,23 @@ int v4l2_request_buffer(int video_fd, unsigned int type, unsigned int index, return -1; } - if (length != NULL) { - if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - length[0] = buffer.m.planes[0].length; - length[1] = buffer.m.planes[1].length; - } else { - *length = buffer.m.planes[0].length; - } - } + if (lengths != NULL) + for (i = 0; i < buffer.length; i++) + lengths[i] = buffer.m.planes[i].length; - if (offset != NULL) { - if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - offset[0] = buffer.m.planes[0].m.mem_offset; - offset[1] = buffer.m.planes[1].m.mem_offset; - } else { - *offset = buffer.m.planes[0].m.mem_offset; - } - } + if (offsets != NULL) + for (i = 0; i < buffer.length; i++) + offsets[i] = buffer.m.planes[i].m.mem_offset; return 0; } int v4l2_queue_buffer(int video_fd, int request_fd, unsigned int type, - unsigned int index, unsigned int size) + unsigned int index, unsigned int size, unsigned int buffers_count) { - struct v4l2_plane planes[2]; + struct v4l2_plane planes[buffers_count]; struct v4l2_buffer buffer; + unsigned int i; int rc; memset(planes, 0, sizeof(planes)); @@ -161,10 +196,11 @@ int v4l2_queue_buffer(int video_fd, int request_fd, unsigned int type, buffer.type = type; buffer.memory = V4L2_MEMORY_MMAP; buffer.index = index; - buffer.length = type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? 2 : 1; + buffer.length = buffers_count; buffer.m.planes = planes; - buffer.m.planes[0].bytesused = size; + for (i = 0; i < buffers_count; i++) + buffer.m.planes[i].bytesused = size; if (request_fd >= 0) { buffer.flags = V4L2_BUF_FLAG_REQUEST_FD; @@ -181,9 +217,9 @@ int v4l2_queue_buffer(int video_fd, int request_fd, unsigned int type, } int v4l2_dequeue_buffer(int video_fd, int request_fd, unsigned int type, - unsigned int index) + unsigned int index, unsigned int buffers_count) { - struct v4l2_plane planes[2]; + struct v4l2_plane planes[buffers_count]; struct v4l2_buffer buffer; int rc; @@ -193,7 +229,7 @@ int v4l2_dequeue_buffer(int video_fd, int request_fd, unsigned int type, buffer.type = type; buffer.memory = V4L2_MEMORY_MMAP; buffer.index = index; - buffer.length = type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? 2 : 1; + buffer.length = buffers_count; buffer.m.planes = planes; if (request_fd >= 0) { diff --git a/src/v4l2.h b/src/v4l2.h index 2ee6b46..703d17a 100644 --- a/src/v4l2.h +++ b/src/v4l2.h @@ -27,20 +27,24 @@ #include -#define DESTINATION_SIZE_MAX (1024 * 1024) +#define SOURCE_SIZE_MAX (1024 * 1024) bool v4l2_find_format(int video_fd, unsigned int type, unsigned int pixelformat); int v4l2_set_format(int video_fd, unsigned int type, unsigned int pixelformat, unsigned int width, unsigned int height); +int v4l2_get_format(int video_fd, unsigned int type, unsigned int *width, + unsigned int *height, unsigned int *bytesperline, unsigned int *sizes, + unsigned int *planes_count); int v4l2_create_buffers(int video_fd, unsigned int type, unsigned int buffers_count); int v4l2_request_buffer(int video_fd, unsigned int type, unsigned int index, - unsigned int *length, unsigned int *offset); + unsigned int *lengths, unsigned int *offsets, + unsigned int buffers_count); int v4l2_queue_buffer(int video_fd, int request_fd, unsigned int type, - unsigned int index, unsigned int size); + unsigned int index, unsigned int size, unsigned int buffers_count); int v4l2_dequeue_buffer(int video_fd, int request_fd, unsigned int type, - unsigned int index); + unsigned int index, unsigned int buffers_count); int v4l2_set_control(int video_fd, int request_fd, unsigned int id, void *data, unsigned int size); int v4l2_set_stream(int video_fd, unsigned int type, bool enable); diff --git a/src/video.c b/src/video.c new file mode 100644 index 0000000..2b30e08 --- /dev/null +++ b/src/video.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2018 Paul Kocialkowski + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "video.h" +#include "utils.h" + +static struct video_format formats[] = { + { + .description = "NV12 YUV", + .v4l2_format = V4L2_PIX_FMT_NV12, + .v4l2_buffers_count = 1, + .drm_format = DRM_FORMAT_NV12, + .drm_modifier = DRM_FORMAT_MOD_NONE, + .drm_planes_count = 2, + .bpp = 16, + }, + { + .description = "MB32-tiled NV12 YUV", + .v4l2_format = V4L2_PIX_FMT_MB32_NV12, + .v4l2_buffers_count = 1, + .drm_format = DRM_FORMAT_NV12, + .drm_modifier = DRM_FORMAT_MOD_ALLWINNER_MB32_TILED, + .drm_planes_count = 2, + .bpp = 16 + }, +}; + +static unsigned int formats_count = sizeof(formats) / sizeof(formats[0]); + +struct video_format *video_format_find(bool tiled_format) +{ + unsigned int pixelformat; + unsigned int i; + + pixelformat = video_v4l2_format(tiled_format); + + for (i = 0; i < formats_count; i++) + if (formats[i].v4l2_format == pixelformat) + return &formats[i]; + + return NULL; +} diff --git a/src/video.h b/src/video.h new file mode 100644 index 0000000..2b7f5bd --- /dev/null +++ b/src/video.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2018 Paul Kocialkowski + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _VIDEO_H_ +#define _VIDEO_H_ + +#include + +#define ALIGN(x, y) ((x + (y - 1)) & ~(y - 1)) + +struct video_format { + char *description; + unsigned int v4l2_format; + unsigned int v4l2_buffers_count; + unsigned int drm_format; + uint64_t drm_modifier; + unsigned int drm_planes_count; + unsigned int bpp; +}; + +inline unsigned int video_v4l2_format(bool tiled_format) +{ + return tiled_format ? V4L2_PIX_FMT_MB32_NV12 : V4L2_PIX_FMT_NV12; +} + +struct video_format *video_format_find(bool tiled_format); + +#endif