diff --git a/src/buffer.c b/src/buffer.c index 23fab00..8636369 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -46,15 +46,9 @@ VAStatus SunxiCedrusCreateBuffer(VADriverContextP context, struct sunxi_cedrus_driver_data *driver_data = (struct sunxi_cedrus_driver_data *) context->pDriverData; struct object_buffer *buffer_object = NULL; - struct object_context *context_object; void *buffer_data; - void *map_data; - unsigned int map_size; - unsigned int length; - unsigned int offset; VAStatus status; VABufferID id; - int rc; switch (type) { case VAPictureParameterBufferType: @@ -76,42 +70,20 @@ VAStatus SunxiCedrusCreateBuffer(VADriverContextP context, goto error; } - if(buffer_object->type == VASliceDataBufferType) { - context_object = CONTEXT(context_id); - if (context_object == NULL) { - status = VA_STATUS_ERROR_INVALID_CONTEXT; - goto error; - } - - rc = v4l2_request_buffer(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, context_object->num_rendered_surfaces % INPUT_BUFFERS_NB, &length, &offset); - if (rc < 0) { - status = VA_STATUS_ERROR_ALLOCATION_FAILED; - goto error; - } - - map_size = driver_data->slice_offset[context_object->num_rendered_surfaces % INPUT_BUFFERS_NB] + size * count; - map_data = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, - driver_data->video_fd, offset); - - buffer_data = map_data + driver_data->slice_offset[context_object->num_rendered_surfaces % INPUT_BUFFERS_NB]; - driver_data->slice_offset[context_object->num_rendered_surfaces % INPUT_BUFFERS_NB] += size * count; - } else { - buffer_data = malloc(size * count); - map_size = 0; - map_data = NULL; + buffer_data = malloc(size * count); + if (buffer_data == NULL) { + status = VA_STATUS_ERROR_ALLOCATION_FAILED; + goto error; } - if (data) - memcpy(map_data, data, size * count); + if (data != NULL) + memcpy(buffer_data, data, size * count); buffer_object->type = type; buffer_object->initial_count = count; buffer_object->count = count; - buffer_object->data = buffer_data; - buffer_object->map = map_data; buffer_object->size = size; - buffer_object->map_size = map_size; *buffer_id = id; @@ -137,12 +109,8 @@ VAStatus SunxiCedrusDestroyBuffer(VADriverContextP context, if (buffer_object == NULL) return VA_STATUS_ERROR_INVALID_BUFFER; - if (buffer_object->data != NULL) { - if (buffer_object->type != VASliceDataBufferType) - free(buffer_object->data); - else if (buffer_object->map != NULL && buffer_object->map_size > 0) - munmap(buffer_object->map, buffer_object->map_size); - } + if (buffer_object->data != NULL) + free(buffer_object->data); object_heap_free(&driver_data->buffer_heap, (struct object_base *) buffer_object); diff --git a/src/buffer.h b/src/buffer.h index 32b4b6e..620a0d7 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -43,9 +43,6 @@ struct object_buffer { void *data; unsigned int size; - - void *map; - unsigned int map_size; }; VAStatus SunxiCedrusCreateBuffer(VADriverContextP context, diff --git a/src/context.c b/src/context.c index 8cc0367..d9b21f2 100644 --- a/src/context.c +++ b/src/context.c @@ -34,6 +34,7 @@ #include #include +#include #include @@ -49,6 +50,9 @@ VAStatus SunxiCedrusCreateContext(VADriverContextP context, struct object_config *config_object; struct object_surface *surface_object; struct object_context *context_object = NULL; + unsigned int length; + unsigned int offset; + void *source_data = MAP_FAILED; VASurfaceID *ids = NULL; VAContextID id; VAStatus status; @@ -69,22 +73,6 @@ VAStatus SunxiCedrusCreateContext(VADriverContextP context, goto error; } - ids = malloc(surfaces_count * sizeof(VASurfaceID)); - if (ids == NULL) { - status = VA_STATUS_ERROR_ALLOCATION_FAILED; - goto error; - } - - for (i = 0; i < surfaces_count; i++) { - surface_object = SURFACE(surfaces_ids[i]); - if (surface_object == NULL) { - status = VA_STATUS_ERROR_INVALID_SURFACE; - goto error; - } - - ids[i] = surfaces_ids[i]; - } - switch (config_object->profile) { case VAProfileMPEG2Simple: case VAProfileMPEG2Main: @@ -101,12 +89,44 @@ VAStatus SunxiCedrusCreateContext(VADriverContextP context, goto error; } - rc = v4l2_create_buffers(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, INPUT_BUFFERS_NB); + rc = v4l2_create_buffers(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, surfaces_count); if (rc < 0) { status = VA_STATUS_ERROR_ALLOCATION_FAILED; goto error; } + ids = malloc(surfaces_count * sizeof(VASurfaceID)); + if (ids == NULL) { + status = VA_STATUS_ERROR_ALLOCATION_FAILED; + goto error; + } + + for (i = 0; i < surfaces_count; i++) { + surface_object = SURFACE(surfaces_ids[i]); + if (surface_object == NULL) { + status = VA_STATUS_ERROR_INVALID_SURFACE; + goto error; + } + + rc = v4l2_request_buffer(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, i, &length, &offset); + if (rc < 0) { + status = VA_STATUS_ERROR_ALLOCATION_FAILED; + goto error; + } + + source_data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, driver_data->video_fd, offset); + if (source_data == MAP_FAILED) { + status = VA_STATUS_ERROR_ALLOCATION_FAILED; + goto error; + } + + surface_object->source_index = i; + surface_object->source_data = source_data; + surface_object->source_size = length; + + ids[i] = surfaces_ids[i]; + } + rc = v4l2_set_stream(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, true); if (rc < 0) { status = VA_STATUS_ERROR_OPERATION_FAILED; @@ -128,6 +148,8 @@ VAStatus SunxiCedrusCreateContext(VADriverContextP context, goto complete; error: + if (source_data != MAP_FAILED) + munmap(source_data, length); if (ids != NULL) free(ids); diff --git a/src/context.h b/src/context.h index a0d67e3..0530952 100644 --- a/src/context.h +++ b/src/context.h @@ -30,9 +30,6 @@ #include "object_heap.h" -#define INPUT_BUFFER_MAX_SIZE 131072 -#define INPUT_BUFFERS_NB 6 - #define CONTEXT(id) ((struct object_context *) object_heap_lookup(&driver_data->context_heap, id)) #define CONTEXT_ID_OFFSET 0x02000000 @@ -47,9 +44,6 @@ struct object_context { int picture_width; int picture_height; int flags; - - struct v4l2_ctrl_mpeg2_frame_hdr mpeg2_frame_hdr; - uint32_t num_rendered_surfaces; }; VAStatus SunxiCedrusCreateContext(VADriverContextP context, diff --git a/src/image.c b/src/image.c index 07906cd..7121419 100644 --- a/src/image.c +++ b/src/image.c @@ -125,8 +125,8 @@ VAStatus SunxiCedrusDeriveImage(VADriverContextP context, return VA_STATUS_ERROR_INVALID_BUFFER; /* TODO: Use an appropriate DRM plane instead */ - tiled_to_planar(driver_data->luma_bufs[surface_object->output_buf_index], buffer_object->data, image->pitches[0], image->width, image->height); - tiled_to_planar(driver_data->chroma_bufs[surface_object->output_buf_index], buffer_object->data + image->width*image->height, image->pitches[1], image->width, image->height/2); + 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); surface_object->status = VASurfaceReady; diff --git a/src/mpeg2.c b/src/mpeg2.c index f60a5b1..29df34a 100644 --- a/src/mpeg2.c +++ b/src/mpeg2.c @@ -39,7 +39,7 @@ int mpeg2_fill_picture_parameters(struct sunxi_cedrus_driver_data *driver_data, struct object_surface *surface_object, VAPictureParameterBufferMPEG2 *parameters) { - struct v4l2_ctrl_mpeg2_frame_hdr *header = &context_object->mpeg2_frame_hdr; + struct v4l2_ctrl_mpeg2_frame_hdr *header = &surface_object->mpeg2_header; struct object_surface *forward_reference_surface; struct object_surface *backward_reference_surface; @@ -65,15 +65,15 @@ int mpeg2_fill_picture_parameters(struct sunxi_cedrus_driver_data *driver_data, forward_reference_surface = SURFACE(parameters->forward_reference_picture); if (forward_reference_surface != NULL) - header->forward_ref_index = forward_reference_surface->output_buf_index; + header->forward_ref_index = forward_reference_surface->destination_index; else - header->forward_ref_index = surface_object->output_buf_index; + header->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->output_buf_index; + header->backward_ref_index = backward_reference_surface->destination_index; else - header->backward_ref_index = surface_object->output_buf_index; + header->backward_ref_index = surface_object->destination_index; header->width = context_object->picture_width; header->height = context_object->picture_height; @@ -85,5 +85,17 @@ int mpeg2_fill_slice_data(struct sunxi_cedrus_driver_data *driver_data, struct object_context *context_object, struct object_surface *surface_object, void *data, unsigned int size) { + unsigned char *p = (unsigned char *) surface_object->source_data + + surface_object->slices_size; + + /* + * Since there is no guarantee that the allocation order is the same as + * the submission order (via RenderPicture), we can't use a V4L2 buffer + * directly and have to copy from a regular buffer. + * */ + memcpy(p, data, size); + + surface_object->slices_size += size; + return 0; } diff --git a/src/picture.c b/src/picture.c index 202b8c6..a2f22fb 100644 --- a/src/picture.c +++ b/src/picture.c @@ -65,9 +65,7 @@ VAStatus SunxiCedrusBeginPicture(VADriverContextP context, SunxiCedrusSyncSurface(context, surface_id); surface_object->status = VASurfaceRendering; - surface_object->input_buf_index = context_object->num_rendered_surfaces % INPUT_BUFFERS_NB; context_object->render_surface_id = surface_id; - context_object->num_rendered_surfaces++; return VA_STATUS_SUCCESS; } @@ -160,24 +158,24 @@ VAStatus SunxiCedrusEndPicture(VADriverContextP context, if (surface_object == NULL) return VA_STATUS_ERROR_INVALID_SURFACE; - request_fd = driver_data->request_fds[surface_object->input_buf_index]; + request_fd = surface_object->request_fd; if (request_fd < 0) { request_fd = media_request_alloc(driver_data->media_fd); if (request_fd < 0) return VA_STATUS_ERROR_OPERATION_FAILED; - driver_data->request_fds[surface_object->input_buf_index] = request_fd; + surface_object->request_fd = request_fd; } switch (config_object->profile) { case VAProfileMPEG2Simple: case VAProfileMPEG2Main: - context_object->mpeg2_frame_hdr.slice_pos = 0; - context_object->mpeg2_frame_hdr.slice_len = driver_data->slice_offset[surface_object->input_buf_index] * 8; + surface_object->mpeg2_header.slice_pos = 0; + surface_object->mpeg2_header.slice_len = surface_object->slices_size * 8; control_id = V4L2_CID_MPEG_VIDEO_MPEG2_FRAME_HDR; - control_data = &context_object->mpeg2_frame_hdr; - control_size = sizeof(context_object->mpeg2_frame_hdr); + control_data = &surface_object->mpeg2_header; + control_size = sizeof(surface_object->mpeg2_header); break; default: @@ -188,15 +186,15 @@ VAStatus SunxiCedrusEndPicture(VADriverContextP context, if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; - rc = v4l2_queue_buffer(driver_data->video_fd, request_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, surface_object->output_buf_index, 0); + rc = v4l2_queue_buffer(driver_data->video_fd, request_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, surface_object->destination_index, 0); 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->input_buf_index, driver_data->slice_offset[surface_object->input_buf_index]); + rc = v4l2_queue_buffer(driver_data->video_fd, request_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, surface_object->source_index, surface_object->slices_size); if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; - driver_data->slice_offset[surface_object->input_buf_index] = 0; + surface_object->slices_size = 0; context_object->render_surface_id = VA_INVALID_ID; diff --git a/src/sunxi_cedrus.c b/src/sunxi_cedrus.c index 60e7b32..e04aae0 100644 --- a/src/sunxi_cedrus.c +++ b/src/sunxi_cedrus.c @@ -61,7 +61,6 @@ VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context) struct VADriverVTable *vtable = context->vtable; struct v4l2_capability capability; VAStatus status; - unsigned int i; int video_fd = -1; int media_fd = -1; char *video_path; @@ -160,11 +159,6 @@ VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context) driver_data->video_fd = video_fd; driver_data->media_fd = media_fd; - for (i = 0; i < INPUT_BUFFERS_NB; i++) { - driver_data->request_fds[i] = -1; - driver_data->slice_offset[i] = 0; - } - status = VA_STATUS_SUCCESS; goto complete; @@ -191,11 +185,6 @@ VAStatus SunxiCedrusTerminate(VADriverContextP context) struct object_context *context_object; struct object_config *config_object; object_heap_iterator iterator; - unsigned int i; - - for (i = 0; i < INPUT_BUFFERS_NB; i++) - if (driver_data->request_fds[i] >= 0) - close(driver_data->request_fds[i]); close(driver_data->video_fd); close(driver_data->media_fd); diff --git a/src/sunxi_cedrus.h b/src/sunxi_cedrus.h index 0ddb484..d6edf58 100644 --- a/src/sunxi_cedrus.h +++ b/src/sunxi_cedrus.h @@ -47,13 +47,8 @@ struct sunxi_cedrus_driver_data { struct object_heap surface_heap; struct object_heap buffer_heap; struct object_heap image_heap; - char *luma_bufs[VIDEO_MAX_FRAME]; - char *chroma_bufs[VIDEO_MAX_FRAME]; - unsigned int num_dst_bufs; int video_fd; int media_fd; - int request_fds[INPUT_BUFFERS_NB]; - int slice_offset[INPUT_BUFFERS_NB]; }; VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context); diff --git a/src/surface.c b/src/surface.c index c75c5fa..860d099 100644 --- a/src/surface.c +++ b/src/surface.c @@ -50,9 +50,10 @@ VAStatus SunxiCedrusCreateSurfaces(VADriverContextP context, int width, struct object_surface *surface_object; unsigned int length[2]; unsigned int offset[2]; + void *destination_data[2]; VASurfaceID id; + unsigned int i, j; int rc; - int i; if (format != VA_RT_FORMAT_YUV420) return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT; @@ -71,33 +72,37 @@ VAStatus SunxiCedrusCreateSurfaces(VADriverContextP context, int width, if (surface_object == NULL) return VA_STATUS_ERROR_ALLOCATION_FAILED; + memset(surface_object, 0, sizeof(*surface_object)); + surfaces_ids[i] = id; rc = v4l2_request_buffer(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, i, length, offset); if (rc < 0) return VA_STATUS_ERROR_ALLOCATION_FAILED; - driver_data->luma_bufs[i] = mmap(NULL, length[0], PROT_READ | PROT_WRITE, MAP_SHARED, - driver_data->video_fd, offset[0]); - if (driver_data->luma_bufs[i] == MAP_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; - driver_data->chroma_bufs[i] = mmap(NULL, length[1], PROT_READ | PROT_WRITE, MAP_SHARED, - driver_data->video_fd, offset[1]); - if (driver_data->chroma_bufs[i] == MAP_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) return VA_STATUS_ERROR_ALLOCATION_FAILED; surface_object->status = VASurfaceReady; surface_object->width = width; surface_object->height = height; - surface_object->input_buf_index = 0; - surface_object->output_buf_index = i; + surface_object->destination_index = i; + + for (j = 0; j < 2; j++) { + surface_object->destination_data[j] = destination_data[j]; + surface_object->destination_size[j] = length[j]; + } + + surface_object->request_fd = -1; surfaces_ids[i] = id; } - driver_data->num_dst_bufs = surfaces_count; - return VA_STATUS_SUCCESS; } @@ -107,13 +112,20 @@ VAStatus SunxiCedrusDestroySurfaces(VADriverContextP context, struct sunxi_cedrus_driver_data *driver_data = (struct sunxi_cedrus_driver_data *) context->pDriverData; struct object_surface *surface_object; - int i; + unsigned int i, j; for (i = 0; i < surfaces_count; i++) { surface_object = (struct object_surface *) object_heap_lookup(&driver_data->surface_heap, surfaces_ids[i]); if (surface_object == NULL) return VA_STATUS_ERROR_INVALID_SURFACE; + if (surface_object->source_data != NULL && surface_object->source_size > 0) + munmap(surface_object->source_data, surface_object->source_size); + + 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]); + object_heap_free(&driver_data->surface_heap, (struct object_base *) surface_object); } @@ -136,7 +148,7 @@ VAStatus SunxiCedrusSyncSurface(VADriverContextP context, if (surface_object->status == VASurfaceSkipped) return VA_STATUS_ERROR_UNKNOWN; - request_fd = driver_data->request_fds[surface_object->input_buf_index]; + request_fd = surface_object->request_fd; if (request_fd < 0) return VA_STATUS_ERROR_UNKNOWN; @@ -152,11 +164,11 @@ VAStatus SunxiCedrusSyncSurface(VADriverContextP context, if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; - rc = v4l2_dequeue_buffer(driver_data->video_fd, request_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, surface_object->input_buf_index); + rc = v4l2_dequeue_buffer(driver_data->video_fd, request_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, surface_object->source_index); if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; - rc = v4l2_dequeue_buffer(driver_data->video_fd, request_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, surface_object->output_buf_index); + rc = v4l2_dequeue_buffer(driver_data->video_fd, request_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, surface_object->destination_index); if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; @@ -220,7 +232,7 @@ VAStatus SunxiCedrusPutSurface(VADriverContextP context, VASurfaceID surface_id, for(x=dst_x; x < dst_x+dst_width; x++) { for(y=dst_y; y < dst_y+dst_height; y++) { - char lum = driver_data->luma_bufs[surface_object->output_buf_index][x+src_width*y]; + char lum = ((char *) surface_object->destination_data[0])[x+src_width*y]; xcolor.red = xcolor.green = xcolor.blue = lum*colorratio; XAllocColor(display, cm, &xcolor); XSetForeground(display, gc, xcolor.pixel); diff --git a/src/surface.h b/src/surface.h index 0a37ca2..71bb617 100644 --- a/src/surface.h +++ b/src/surface.h @@ -41,9 +41,18 @@ struct object_surface { int width; int height; - uint32_t request; - uint32_t input_buf_index; - uint32_t output_buf_index; + unsigned int source_index; + void *source_data; + unsigned int source_size; + + unsigned int destination_index; + void *destination_data[2]; + unsigned int destination_size[2]; + + struct v4l2_ctrl_mpeg2_frame_hdr mpeg2_header; + unsigned int slices_size; + + int request_fd; }; VAStatus SunxiCedrusCreateSurfaces(VADriverContextP context, int width,