summaryrefslogtreecommitdiff
path: root/examples/libva_buffer_sharing/libva_buffer_sharing.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'examples/libva_buffer_sharing/libva_buffer_sharing.cpp')
-rw-r--r--examples/libva_buffer_sharing/libva_buffer_sharing.cpp465
1 files changed, 465 insertions, 0 deletions
diff --git a/examples/libva_buffer_sharing/libva_buffer_sharing.cpp b/examples/libva_buffer_sharing/libva_buffer_sharing.cpp
new file mode 100644
index 00000000..88084fb4
--- /dev/null
+++ b/examples/libva_buffer_sharing/libva_buffer_sharing.cpp
@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) 2012, 2015 Intel Corporation. All Rights Reserved.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <va/va.h>
+#include "va_display.h"
+
+#include <va/va_drmcommon.h>
+#include "utest_helper.hpp"
+
+#include <getopt.h> /* getopt_long() */
+
+typedef cl_mem (OCLCREATEIMAGEFROMLIBVAINTEL)(cl_context, const cl_libva_image *, cl_int *);
+OCLCREATEIMAGEFROMLIBVAINTEL *oclCreateImageFromLibvaIntel = NULL;
+
+const char *input_nv12;
+const char *output_nv12;
+int frame_size;
+int picture_width, picture_height;
+unsigned char *newImageBuffer;
+VADisplay va_dpy;
+cl_int cl_status;
+VAStatus va_status;
+bool putsurface=true;
+
+static const char short_options[] = "i:r:o:h";
+
+static const struct option
+long_options[] = {
+ { "input", required_argument, NULL, 'i' },
+ { "help", no_argument, NULL, 'h' },
+ { "resolution", required_argument, NULL, 'r' },
+ { "output", required_argument, NULL, 'o' },
+ { 0, 0, 0, 0 }
+};
+
+#define WIDTH_DEFAULT 256
+#define HEIGHT_DEFAULT 128
+
+#define CHECK_VASTATUS(va_status,func) \
+ if (va_status != VA_STATUS_SUCCESS) { \
+ fprintf(stderr, "status = %d, %s:%s (%d) failed,exit\n",va_status, __func__, func, __LINE__); \
+ exit(1); \
+ }
+
+#define CHECK_CLSTATUS(status,func) \
+ if (status != CL_SUCCESS) { \
+ fprintf(stderr, "status = %d, %s:%s (%d) failed,exit\n", status, __func__, func, __LINE__); \
+ exit(1); \
+ }
+
+static void usage(FILE *fp, int argc, char **argv)
+{
+ fprintf(fp,
+ "\n"
+ "This example aims to demostrate the usage of gpu buffer sharing between libva and Beignet.\n"
+ "The result will be shown on screen if you haven't specified -o option.\n"
+ "The input and output file are nv12 format.\n"
+ "Please use the following command to see these files:\n"
+ "gst-launch-1.0 filesrc location=file_name ! videoparse format=nv12 width=xxx height=xxx ! imagefreeze ! videoconvert ! video/x-raw, format=BGRx ! ximagesink\n"
+ "(Please install gstreamer1.0-plugins-base, gstreamer1.0-plugins-bad, \n"
+ " gstreamer1.0-x by apt on Ubuntu, in order to use gst-launch-1.0)\n"
+ "For more details, please read docs/howto/libva-buffer-sharing-howto.mdwn.\n"
+ "\nUsage: %s [options]\n\n"
+ "Options:\n"
+ "-i | --input=<file_name> Specify input nv12 file name like /home/xxx/in.nv12\n"
+ "-h | --help Print this message\n"
+ "-r | --resolution=<width,height> Set input resolution\n"
+ "-o | --output=<file_name> Specify input nv12 file name like /home/xxx/out.nv12\n"
+ "",
+ argv[0]);
+}
+
+static void analyse_args(int argc, char *argv[])
+{
+ input_nv12 = NULL;
+ picture_width = 0;
+ picture_height = 0;
+ output_nv12 = NULL;
+ putsurface = true;
+
+ int c, idx;
+ for (;;) {
+
+ c = getopt_long(argc, argv,
+ short_options, long_options, &idx);
+
+ if (-1 == c)
+ break;
+
+ switch (c) {
+ case 0: /* getopt_long() flag */
+ break;
+
+ case 'i':
+ input_nv12 = optarg;
+ break;
+
+ case '?':
+ case 'h':
+ usage(stdout, argc, argv);
+ exit(0);
+
+ case 'r':
+ sscanf(optarg, "%d,%d", &picture_width, &picture_height);
+ break;
+
+ case 'o':
+ output_nv12 = optarg;
+ putsurface = false;
+ break;
+
+ default:
+ usage(stderr, argc, argv);
+ exit(1);
+ }
+ }
+
+ if(!input_nv12){
+ input_nv12 = INPUT_NV12_DEFAULT;
+ }
+ if(picture_width == 0 && picture_height == 0){
+ picture_width = WIDTH_DEFAULT;
+ picture_height = HEIGHT_DEFAULT;
+ }
+ return;
+}
+
+
+static void initialize_va_ocl(){
+ int major_ver, minor_ver;
+
+ printf("\n***********************libva info: ***********************\n");
+ fflush(stdout);
+ va_dpy = va_open_display();
+ va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
+ CHECK_VASTATUS(va_status, "vaInitialize");
+
+ //ocl initialization: basic & create kernel & get extension
+ printf("\n***********************OpenCL info: ***********************\n");
+ if ((cl_status = cl_test_init("runtime_mirror_effect.cl", "runtime_mirror_effect", SOURCE)) != 0){
+ fprintf(stderr, "cl_test_init error\n");
+ exit(1);
+ }
+
+#ifdef CL_VERSION_1_2
+ oclCreateImageFromLibvaIntel = (OCLCREATEIMAGEFROMLIBVAINTEL *)clGetExtensionFunctionAddressForPlatform(platform, "clCreateImageFromLibvaIntel");
+#else
+ oclCreateImageFromLibvaIntel = (OCLCREATEIMAGEFROMLIBVAINTEL *)clGetExtensionFunctionAddress("clCreateImageFromLibvaIntel");
+#endif
+ if(!oclCreateImageFromLibvaIntel){
+ fprintf(stderr, "Failed to get extension clCreateImageFromLibvaIntel\n");
+ exit(1);
+ }
+}
+
+static void upload_nv12_to_surface(FILE *nv12_fp, VASurfaceID surface_id)
+{
+ VAImage surface_image;
+ void *surface_p = NULL;
+ unsigned char *y_src, *u_src;
+ unsigned char *y_dst, *u_dst;
+ int y_size = picture_width * picture_height;
+ int row, col;
+ size_t n_items;
+
+ n_items = fread(newImageBuffer, frame_size, 1, nv12_fp);
+ if(n_items != 1){
+ fprintf(stderr, "Haven't read expected size data from file\n");
+ exit(1);
+ }
+
+ va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
+ CHECK_VASTATUS(va_status,"vaDeriveImage");
+
+ va_status = vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
+ CHECK_VASTATUS(va_status,"vaMapBuffer");
+
+ y_src = newImageBuffer;
+ u_src = newImageBuffer + y_size; /* U offset for NV12 */
+
+ y_dst = (unsigned char *)surface_p + surface_image.offsets[0];
+ u_dst = (unsigned char *)surface_p + surface_image.offsets[1]; /* U offset for NV12 */
+
+ /* Y plane */
+ for (row = 0; row < surface_image.height; row++) {
+ memcpy(y_dst, y_src, surface_image.width);
+ y_dst += surface_image.pitches[0];
+ y_src += picture_width;
+ }
+
+ assert(surface_image.format.fourcc == VA_FOURCC_NV12); /* UV plane */
+ for (row = 0; row < surface_image.height / 2; row++) {
+ for (col = 0; col < surface_image.width / 2; col++) {
+ u_dst[col * 2] = u_src[col * 2];
+ u_dst[col * 2 + 1] = u_src[col * 2 + 1];
+ }
+ u_dst += surface_image.pitches[1];
+ u_src += picture_width;
+ }
+
+ vaUnmapBuffer(va_dpy, surface_image.buf);
+ vaDestroyImage(va_dpy, surface_image.image_id);
+}
+
+static void create_y_image_object_from_libva(VAImage *surface_image,
+ VABufferInfo *buf_info,
+ cl_mem *yio_p)
+{
+ cl_libva_image info_image;
+ info_image.bo_name = buf_info->handle;
+ info_image.offset = surface_image->offsets[0];
+ info_image.width = surface_image->width;
+ info_image.height = surface_image->height;
+ info_image.fmt.image_channel_order = CL_R;
+ info_image.fmt.image_channel_data_type = CL_UNSIGNED_INT8;
+ info_image.row_pitch = surface_image->pitches[0];
+ *yio_p = oclCreateImageFromLibvaIntel(ctx, &info_image, &cl_status);
+ CHECK_CLSTATUS(cl_status, "oclCreateImageFromLibvaIntel");
+ printf("\nSuccessfully create ocl image object from y plane of VASurface...\n");
+}
+
+static void create_uv_image_object_from_libva(VAImage *surface_image,
+ VABufferInfo *buf_info,
+ cl_mem *yio_p)
+{
+ cl_libva_image info_image;
+ info_image.bo_name = buf_info->handle;
+ info_image.offset = surface_image->offsets[1];
+ info_image.width = surface_image->width / 2;
+ info_image.height = surface_image->height / 2;
+ info_image.fmt.image_channel_order = CL_R;
+ info_image.fmt.image_channel_data_type = CL_UNSIGNED_INT16;
+ info_image.row_pitch = surface_image->pitches[1];
+ *yio_p = oclCreateImageFromLibvaIntel(ctx, &info_image, &cl_status);
+ CHECK_CLSTATUS(cl_status, "oclCreateImageFromLibvaIntel");
+ printf("\nSuccessfully create ocl image object from uv plane of VASurface...\n");
+}
+
+static void store_surface_to_nv12(VASurfaceID surface_id, FILE *nv12_fp)
+{
+ VAImage surface_image;
+ void *surface_p = NULL;
+ unsigned char *y_src, *u_src;
+ unsigned char *y_dst, *u_dst;
+ int y_size = picture_width * picture_height;
+ int row, col;
+
+ va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
+ CHECK_VASTATUS(va_status,"vaDeriveImage");
+
+ va_status = vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
+ CHECK_VASTATUS(va_status,"vaMapBuffer");
+
+ y_src = (unsigned char *)surface_p + surface_image.offsets[0];
+ u_src = (unsigned char *)surface_p + surface_image.offsets[1]; /* U offset for NV12 */
+
+ y_dst = newImageBuffer;
+ u_dst = newImageBuffer + y_size; /* U offset for NV12 */
+
+ /* Y plane */
+ for (row = 0; row < surface_image.height; row++) {
+ memcpy(y_dst, y_src, surface_image.width);
+ y_src += surface_image.pitches[0];
+ y_dst += picture_width;
+ }
+
+ assert(surface_image.format.fourcc == VA_FOURCC_NV12); /* UV plane */
+ for (row = 0; row < surface_image.height / 2; row++) {
+ for (col = 0; col < surface_image.width / 2; col++) {
+ u_dst[col * 2] = u_src[col * 2];
+ u_dst[col * 2 + 1] = u_src[col * 2 + 1];
+ }
+ u_src += surface_image.pitches[1];
+ u_dst += picture_width;
+ }
+
+ fwrite(newImageBuffer, frame_size, 1, nv12_fp);
+
+ vaUnmapBuffer(va_dpy, surface_image.buf);
+ vaDestroyImage(va_dpy, surface_image.image_id);
+}
+
+static void load_process_store_nv12()
+{
+ frame_size = picture_width * picture_height + ((picture_width * picture_height) >> 1) ;
+ newImageBuffer = (unsigned char *)malloc(frame_size);
+
+ VASurfaceID src_surface_id;
+ VASurfaceAttrib forcc;
+ forcc.type =VASurfaceAttribPixelFormat;
+ forcc.flags=VA_SURFACE_ATTRIB_SETTABLE;
+ forcc.value.type=VAGenericValueTypeInteger;
+ forcc.value.value.i = VA_FOURCC_NV12;
+ va_status = vaCreateSurfaces(va_dpy, VA_RT_FORMAT_YUV420,
+ picture_width, picture_height,
+ &src_surface_id, 1, &forcc, 1);
+ CHECK_VASTATUS(va_status, "vaCreateSurfaces");
+
+ //load
+ FILE *in_nv12_fp;
+ in_nv12_fp = fopen(input_nv12, "rb");
+ if (in_nv12_fp == NULL){
+ fprintf(stderr, "Can't open input nv12 file\n");
+ exit(1);
+ }
+ fseek(in_nv12_fp, 0l, SEEK_END);
+ off_t file_size = ftell(in_nv12_fp);
+
+ if ((file_size < frame_size) || (file_size % frame_size) ) {
+ fclose(in_nv12_fp);
+ fprintf(stderr, "The nv12 file's size is not correct\n");
+ exit(1);
+ }
+ fseek(in_nv12_fp, 0l, SEEK_SET);
+ upload_nv12_to_surface(in_nv12_fp, src_surface_id);
+ fclose(in_nv12_fp);
+ printf("\nSuccessfully load source nv12 file(\"%s\") to VASurface...\n", input_nv12);
+
+
+ //create two corresponding ocl image objects from source VASurface
+ VAImage src_surface_image;
+ va_status = vaDeriveImage(va_dpy, src_surface_id, &src_surface_image);
+ CHECK_VASTATUS(va_status,"vaDeriveImage");
+ VABufferInfo buf_info;
+ buf_info.mem_type = VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM;
+ va_status = vaAcquireBufferHandle(va_dpy, src_surface_image.buf, &buf_info);
+ CHECK_VASTATUS(va_status,"vaAcquireBufferHandle");
+ cl_mem src_y, src_uv;
+ create_y_image_object_from_libva(&src_surface_image, &buf_info, &src_y);
+ OCL_CALL (clSetKernelArg, kernel, 0, sizeof(cl_mem), &src_y);
+
+ create_uv_image_object_from_libva(&src_surface_image, &buf_info, &src_uv);
+ OCL_CALL (clSetKernelArg, kernel, 1, sizeof(cl_mem), &src_uv);
+
+
+ //create one target VASurface & create corresponding target ocl image object from it
+ VASurfaceID dst_surface_id;
+ va_status = vaCreateSurfaces(va_dpy,VA_RT_FORMAT_YUV420,
+ picture_width,picture_height,
+ &dst_surface_id, 1, &forcc, 1);
+ CHECK_VASTATUS(va_status, "vaCreateSurfaces");
+
+ VAImage dst_surface_image;
+ va_status = vaDeriveImage(va_dpy, dst_surface_id, &dst_surface_image);
+ CHECK_VASTATUS(va_status,"vaDeriveImage");
+ va_status = vaAcquireBufferHandle(va_dpy, dst_surface_image.buf, &buf_info);
+ CHECK_VASTATUS(va_status,"vaAcquireBufferHandle");
+ cl_mem dst_y, dst_uv;
+ create_y_image_object_from_libva(&dst_surface_image, &buf_info, &dst_y);
+ OCL_CALL (clSetKernelArg, kernel, 2, sizeof(cl_mem), &dst_y);
+ create_uv_image_object_from_libva(&dst_surface_image, &buf_info, &dst_uv);
+ OCL_CALL (clSetKernelArg, kernel, 3, sizeof(cl_mem), &dst_uv);
+ OCL_CALL (clSetKernelArg, kernel, 4, sizeof(int), &picture_height);
+
+
+ size_t global_size[2];
+ global_size[0] = picture_width;
+ global_size[1] = picture_height;
+ OCL_CALL (clEnqueueNDRangeKernel, queue, kernel, 2, NULL,
+ global_size, NULL, 0, NULL, NULL);
+ OCL_CALL (clFinish, queue);
+ printf("\nSuccessfully use ocl to do processing...\n");
+
+ va_status = vaReleaseBufferHandle(va_dpy, src_surface_image.buf);
+ CHECK_VASTATUS(va_status,"vaReleaseBufferHandle");
+ va_status = vaReleaseBufferHandle(va_dpy, dst_surface_image.buf);
+ CHECK_VASTATUS(va_status,"vaReleaseBufferHandle");
+
+ OCL_CALL (clReleaseMemObject, src_y);
+ OCL_CALL (clReleaseMemObject, src_uv);
+ OCL_CALL (clReleaseMemObject, dst_y);
+ OCL_CALL (clReleaseMemObject, dst_uv);
+ vaDestroyImage(va_dpy, src_surface_image.image_id);
+ vaDestroyImage(va_dpy, dst_surface_image.image_id);
+ cl_kernel_destroy();
+ cl_ocl_destroy();
+
+
+ if (putsurface) {
+ VARectangle src_rect, dst_rect;
+
+ src_rect.x = 0;
+ src_rect.y = 0;
+ src_rect.width = picture_width;
+ src_rect.height = picture_height;
+ dst_rect = src_rect;
+
+ //XXX There is a bug of X server which will cause va_put_surface showing
+ //incorrect result. So call va_put_surface twice times to workaround this
+ //bug.
+ va_status = va_put_surface(va_dpy, dst_surface_id, &src_rect, &dst_rect);
+ va_status = va_put_surface(va_dpy, dst_surface_id, &src_rect, &dst_rect);
+ CHECK_VASTATUS(va_status, "vaPutSurface");
+ printf("press any key to exit\n");
+ getchar();
+ }
+ else{
+ //store
+ FILE *out_nv12_fp;
+ out_nv12_fp = fopen(output_nv12,"wb");
+ if ( out_nv12_fp == NULL){
+ fprintf(stderr, "Can't open output nv12 file\n");
+ exit(1);
+ }
+ store_surface_to_nv12(dst_surface_id, out_nv12_fp);
+ fclose(out_nv12_fp);
+ printf("\nSuccessfully store VASurface to dst nv12 file(\"%s\")...\n", output_nv12);
+ printf("\nNote: The input and output file are nv12 format.\n");
+ printf("Please use the following command to see the result:\n");
+ printf("gst-launch-1.0 filesrc location=%s ! videoparse format=nv12 width=%d height=%d ! imagefreeze ! videoconvert ! video/x-raw, format=BGRx ! ximagesink\n", output_nv12, picture_width, picture_height);
+ printf("(Please install gstreamer1.0-plugins-base, gstreamer1.0-plugins-bad,\ngstreamer1.0-x by apt on Ubuntu, in order to use gst-launch-1.0)\n");
+ }
+
+ //release resources
+ vaDestroySurfaces(va_dpy,&src_surface_id,1);
+ vaDestroySurfaces(va_dpy,&dst_surface_id,1);
+
+ vaTerminate(va_dpy);
+ va_close_display(va_dpy);
+}
+
+
+int main(int argc, char *argv[])
+{
+ analyse_args(argc, argv);
+
+ initialize_va_ocl();
+
+ load_process_store_nv12();
+
+ printf("\nExample run successfully!\n");
+
+ return 0;
+}