add Mediacopy Sample code
diff --git a/videoprocess/Makefile.am b/videoprocess/Makefile.am index 1a37269..7ee8c3b 100644 --- a/videoprocess/Makefile.am +++ b/videoprocess/Makefile.am
@@ -20,7 +20,7 @@ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -bin_PROGRAMS = vavpp vppscaling_csc vppdenoise vppsharpness vppchromasitting vppblending vppscaling_n_out_usrptr +bin_PROGRAMS = vavpp vppscaling_csc vppdenoise vppsharpness vppchromasitting vppblending vppscaling_n_out_usrptr vacopy AM_CPPFLAGS = \ -Wall \ @@ -57,6 +57,9 @@ vppscaling_n_out_usrptr_SOURCES = vppscaling_n_out_usrptr.cpp vppscaling_n_out_usrptr_LDADD = $(TEST_LIBS) + +vacopy_SOURCES = vacopy.cpp +vacopy_LDADD = $(TEST_LIBS) valgrind:(bin_PROGRAMS) for a in(bin_PROGRAMS); do \ valgrind --leak-check=full --show-reachable=yes .libs/$$a; \
diff --git a/videoprocess/process_va_copy.cfg.template b/videoprocess/process_va_copy.cfg.template new file mode 100644 index 0000000..69ee03e --- /dev/null +++ b/videoprocess/process_va_copy.cfg.template
@@ -0,0 +1,43 @@ +# Configuration information for video process test case. +# This application will firstly load yuv frames to one type of surface(NV12/RBGP) +# you require. After GPU HW copy, the processed content (NV12/RGBP surface) +# will be stored to frames. +# Supported features include intput/ouput internal surface and external(usrptr surface) copy. +# you can modify this configuration file to set the corresponding parameters. + +#1.Source YUV(RGB) file information +SRC_FILE_NAME: ./src_480x320.nv12 +SRC_FRAME_WIDTH: 480 +SRC_FRAME_HEIGHT: 320 +SRC_FRAME_FORMAT: NV12 + +#Note .nv12 files are in NV12 format +SRC_FILE_FORMAT: NV12 + +# source surface memory type +# supported type: (CPU, VA), default: VA +SRC_SURFACE_MEMORY_TYPE: VA + +#if use usrptr CPU memory type, can support customization align size +SRC_SURFACE_CPU_ALIGN_SIZE: 1 + +#2.Destination YUV(RGB) file information +DST_FILE_NAME: ./dst_480x320.nv12 +DST_FRAME_WIDTH: 480 +DST_FRAME_HEIGHT: 320 +DST_FRAME_FORMAT: NV12 + +#Note .nv12 files are in NV12 format +DST_FILE_FORMAT: NV12 + +# destination surface memory type +# supported type: (CPU, VA), default: VA +DST_SURFACE_MEMORY_TYPE: VA + +#if use usrptr CPU memory type, can support customization align size +DST_SURFACE_CPU_ALIGN_SIZE: 128 + +FRAME_SUM: 1 + +# hw engine select, 0:balance 1:perf, 2 powersaving +COPY_METHOD: 1
diff --git a/videoprocess/vacopy.cpp b/videoprocess/vacopy.cpp new file mode 100644 index 0000000..8bee4c6 --- /dev/null +++ b/videoprocess/vacopy.cpp
@@ -0,0 +1,858 @@ +/* +* Copyright (c) 2009-2018, Intel Corporation +* +* 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, sublicense, +* 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 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 NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS 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. +*/ +/* + * Video process test case based on LibVA. + * This test covers different surface format copy. + * Usage: ./vacopy process_copy.cfg + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <iostream> +#include <time.h> +#include <assert.h> +#include <va/va.h> +#include <va/va_vpp.h> +#include "va_display.h" + +#ifndef VA_FOURCC_I420 +#define VA_FOURCC_I420 0x30323449 +#endif + +#define MAX_LEN 1024 + +#define CHECK_VASTATUS(va_status,func) \ + if (va_status != VA_STATUS_SUCCESS) { \ + fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \ + exit(1); \ + } +using namespace std; +static VADisplay va_dpy = NULL; +static VAContextID context_id = 0; + +typedef struct _SurfInfo +{ + FILE *fd; + char name[MAX_LEN]; + uint32_t width; + uint32_t height; + uint32_t fourCC; + uint32_t format; + uint32_t memtype; + uint32_t alignsize; + void *pBuf; + uint8_t *pBufBase; + uintptr_t ptrb; +}SurfInfo; + +static SurfInfo g_src; +static SurfInfo g_dst; + +static VAConfigID config_id = 0; +static FILE* g_config_file_fd = NULL; +static char g_config_file_name[MAX_LEN]; + +static VASurfaceID g_in_surface_id = VA_INVALID_ID; +static VASurfaceID g_out_surface_id = VA_INVALID_ID; + +static uint32_t g_src_file_fourcc = VA_FOURCC('I', '4', '2', '0'); +static uint32_t g_dst_file_fourcc = VA_FOURCC('Y', 'V', '1', '2'); + +#define _FREE(p) \ + if(p != NULL){ \ + free(p); p = NULL; \ + } + +static uint32_t g_frame_count = 0; +static uint32_t g_copy_method = 0; //0 blance, 1 perf. 2 power_saving + +static int8_t +parse_memtype_format(char *str,uint32_t *dst_memtype) +{ + uint32_t tmemtype = VA_SURFACE_ATTRIB_MEM_TYPE_VA; + + if (!strcmp(str, "VA")){ + tmemtype = VA_SURFACE_ATTRIB_MEM_TYPE_VA; + } else if(!strcmp(str, "CPU")){ + tmemtype = VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR; + }else{ + printf("Not supported format: %s! Currently only support following format: %s\n", + str, "VA,CPU"); + assert(0); + } + if(dst_memtype) + *dst_memtype = tmemtype; + return 0; +} + +static int8_t +read_value_string(FILE *fp, const char* field_name, char* value) +{ + char strLine[MAX_LEN]; + char* field = NULL; + char* str = NULL; + uint16_t i; + + if (!fp || !field_name || !value) { + printf("Invalid fuction parameters\n"); + return -1; + } + + rewind(fp); + + while (!feof(fp)) { + if (!fgets(strLine, MAX_LEN, fp)) + continue; + + for (i = 0; i < MAX_LEN && strLine[i]; i++) + if (strLine[i] != ' ') break; + + if (i == MAX_LEN || strLine[i] == '#' || strLine[i] == '\n') + continue; + + field = strtok(&strLine[i], ":"); + if (strncmp(field, field_name, strlen(field_name))) + continue; + + if (!(str = strtok(NULL, ":"))) + continue; + + /* skip blank space in string */ + while (*str == ' ') + str++; + + *(str + strlen(str)-1) = '\0'; + strcpy(value, str); + + return 0; + } + + return -1; +} + +static int8_t +read_value_uint32(FILE* fp, const char* field_name, uint32_t* value) +{ + char str[MAX_LEN]; + + if (read_value_string(fp, field_name, str)) { + printf("Failed to find integer field: %s", field_name); + return -1; + } + + *value = (uint32_t)atoi(str); + return 0; +} + +static VAStatus +create_surface(VASurfaceID * p_surface_id,SurfInfo &surf) +{ + VAStatus va_status = VA_STATUS_ERROR_INVALID_PARAMETER; + if (surf.memtype == VA_SURFACE_ATTRIB_MEM_TYPE_VA) + { + VASurfaceAttrib surface_attrib; + surface_attrib.type = VASurfaceAttribPixelFormat; + surface_attrib.flags = VA_SURFACE_ATTRIB_SETTABLE; + surface_attrib.value.type = VAGenericValueTypeInteger; + surface_attrib.value.value.i = surf.fourCC; + + va_status = vaCreateSurfaces(va_dpy, + surf.format, + surf.width , + surf.height, + p_surface_id, + 1, + &surface_attrib, + 1); + } + else if (surf.memtype == VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR) + { + VASurfaceAttrib surfaceAttrib[3]; + VASurfaceAttribExternalBuffers extBuffer; + uint32_t base_addr_align = 0x1000; + uint32_t size = 0; + surfaceAttrib[0].flags = VA_SURFACE_ATTRIB_SETTABLE; + surfaceAttrib[0].type = VASurfaceAttribPixelFormat; + surfaceAttrib[0].value.type = VAGenericValueTypeInteger; + surfaceAttrib[0].value.value.i = surf.fourCC; + + surfaceAttrib[1].flags = VA_SURFACE_ATTRIB_SETTABLE; + surfaceAttrib[1].type = VASurfaceAttribMemoryType; + surfaceAttrib[1].value.type = VAGenericValueTypeInteger; + surfaceAttrib[1].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR; + + surfaceAttrib[2].flags = VA_SURFACE_ATTRIB_SETTABLE; + surfaceAttrib[2].type = VASurfaceAttribExternalBufferDescriptor; + surfaceAttrib[2].value.type = VAGenericValueTypePointer; + surfaceAttrib[2].value.value.p = (void *)&extBuffer; + memset(&extBuffer, 0, sizeof(extBuffer)); + + uint32_t pitch_align = surf.alignsize; + switch(surf.fourCC) + { + case VA_FOURCC_NV12: + extBuffer.pitches[0] = ((surf.width + pitch_align -1)/pitch_align) * pitch_align; + size = (extBuffer.pitches[0] * surf.height) * 3/2;// frame size align with pitch. + size = (size+base_addr_align-1)/base_addr_align*base_addr_align;// frame size align as 4K page. + extBuffer.offsets[0] = 0;// Y channel + extBuffer.offsets[1] = extBuffer.pitches[0] * surf.height; // UV channel. + extBuffer.pitches[1] = extBuffer.pitches[0]; + extBuffer.num_planes =2; + break; + case VA_FOURCC_RGBP: + extBuffer.pitches[0] = ((surf.width + pitch_align -1)/pitch_align) * pitch_align; + size = (extBuffer.pitches[0] * surf.height) * 3;// frame size align with pitch. + size = (size+base_addr_align-1)/base_addr_align*base_addr_align;// frame size align as 4K page. + extBuffer.offsets[0] = 0;// Y channel + extBuffer.offsets[1] = extBuffer.pitches[0] * surf.height; // U channel. + extBuffer.pitches[1] = extBuffer.pitches[0]; + extBuffer.offsets[2] = extBuffer.pitches[0] * surf.height * 2; // V channel. + extBuffer.pitches[2] = extBuffer.pitches[0]; + extBuffer.num_planes = 3; + break; + default : + std::cout << surf.fourCC <<"format doesn't support!"<<endl; + return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT; + } + if (!surf.pBuf && !surf.pBufBase) + { + surf.pBuf = malloc(size+base_addr_align); + surf.pBufBase = (uint8_t*)((((uint64_t)(surf.pBuf) + base_addr_align-1)/base_addr_align)*base_addr_align); + + extBuffer.pixel_format = surf.fourCC; + extBuffer.width = surf.width; + extBuffer.height = surf.height; + extBuffer.data_size = size; + extBuffer.num_buffers = 1; + extBuffer.buffers = &(surf.ptrb); + extBuffer.buffers[0] = (uintptr_t)(surf.pBufBase); + extBuffer.flags = VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR; + + va_status = vaCreateSurfaces(va_dpy, surf.format, surf.width, surf.height,p_surface_id, 1, surfaceAttrib, 3); + CHECK_VASTATUS(va_status, "vaCreateSurfaces"); + } + else + { + std::cout<<"previous frame buffer hasn't be released!"<<endl; + } + } + + return va_status; +} + +/* Load frame to surface*/ +static VAStatus +upload_frame_to_surface(FILE *fp, + VASurfaceID surface_id) +{ + VAStatus va_status; + VAImage surface_image; + unsigned char *y_src = NULL; + unsigned char *u_src = NULL; + unsigned char *v_src = NULL; + unsigned char *y_dst = NULL; + unsigned char *u_dst = NULL; + unsigned char *v_dst = NULL; + void *surface_p = NULL; + uint32_t frame_size, row; + size_t n_items; + unsigned char * newImageBuffer = NULL; + va_status = vaSyncSurface (va_dpy,surface_id); + CHECK_VASTATUS(va_status, "vaSyncSurface"); + + 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"); + + if (g_src.memtype == VA_SURFACE_ATTRIB_MEM_TYPE_VA) + { + std::cout<<"2D src surface width = "<<g_src.width<<" pitch = "<<surface_image.pitches[0]<<endl; + } + else + { + std::cout<<"linear src surface width = "<<g_src.width<<" pitch = "<<surface_image.pitches[0]<<((g_src.width%surface_image.pitches[0])?" it is 2D linear":" it is 1D linear")<<endl; + } + + if (surface_image.format.fourcc == VA_FOURCC_RGBP) + { + frame_size = surface_image.width * surface_image.height * 3; + newImageBuffer = (unsigned char*)malloc(frame_size); + assert(newImageBuffer); + + do { + n_items = fread(newImageBuffer, frame_size, 1, fp); + } while (n_items != 1); + + y_src = newImageBuffer; + u_src = newImageBuffer + surface_image.width * surface_image.height; + v_src = newImageBuffer + surface_image.width * surface_image.height * 2; + + y_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]); + u_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]); + v_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]); + + for (row = 0; row < surface_image.height; row++) { + memcpy(y_dst, y_src, surface_image.width); + y_dst += surface_image.pitches[0]; + y_src += surface_image.width; + + memcpy(u_dst, u_src, surface_image.width); + u_dst += surface_image.pitches[0]; + u_src += surface_image.width; + + memcpy(v_dst, v_src, surface_image.width); + v_dst += surface_image.pitches[0]; + v_src += surface_image.width; + } + } + else if (surface_image.format.fourcc == VA_FOURCC_NV12) + { + frame_size = surface_image.width * surface_image.height * 3 / 2; + newImageBuffer = (unsigned char*)malloc(frame_size); + assert(newImageBuffer); + + do { + n_items = fread(newImageBuffer, frame_size, 1, fp); + } while (n_items != 1); + + y_src = newImageBuffer; + u_src = newImageBuffer + surface_image.width * surface_image.height; + v_src = u_src; + + y_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]); + u_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]); + v_dst = u_dst; + + /* Y plane, directly copy */ + for (row = 0; row < surface_image.height; row++) { + memcpy(y_dst, y_src, surface_image.width); + y_dst += surface_image.pitches[0]; + y_src += surface_image.width; + } + + /* UV plane */ + for (row = 0; row < surface_image.height / 2; row++) + { + memcpy(u_dst, u_src, surface_image.width); + u_src += surface_image.width; + v_src = u_src; + u_dst += surface_image.pitches[1]; + } + } + + if (newImageBuffer){ + free(newImageBuffer); + newImageBuffer = NULL; + } + + vaUnmapBuffer(va_dpy, surface_image.buf); + vaDestroyImage(va_dpy, surface_image.image_id); + + return VA_STATUS_SUCCESS; +} + +static VAStatus +store_surface_to_file(FILE *fp, + VASurfaceID surface_id) +{ + VAStatus va_status; + VAImage surface_image; + void *surface_p = NULL; + unsigned char *y_src = NULL; + unsigned char *u_src = NULL; + unsigned char *v_src = NULL; + unsigned char *y_dst = NULL; + unsigned char *u_dst = NULL; + unsigned char *v_dst = NULL; + uint32_t row; + int32_t n_items; + unsigned char * newImageBuffer = NULL; + va_status = vaSyncSurface (va_dpy,surface_id); + CHECK_VASTATUS(va_status, "vaSyncSurface"); + + 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"); + + if (g_dst.memtype == VA_SURFACE_ATTRIB_MEM_TYPE_VA) + { + std::cout<<"2D dst surface width = "<<g_dst.width<<" pitch = "<<surface_image.pitches[0]<<endl; + } + else + { + std::cout<<"linear dst surface width = "<<g_dst.width<<" pitch = "<<surface_image.pitches[0]<<((g_dst.width%surface_image.pitches[0])?" it is 2D linear":" it is 1D linear")<<endl; + } + + /* store the surface to one nv12 file */ + if (surface_image.format.fourcc == VA_FOURCC_NV12 || + surface_image.format.fourcc == VA_FOURCC_RGBP ){ + + y_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]); + + if (surface_image.format.fourcc == VA_FOURCC_RGBP){ + u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]); + v_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]); + } else if(surface_image.format.fourcc == VA_FOURCC_NV12){ + u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]); + v_src = u_src; + } + + if(g_dst.memtype == VA_SURFACE_ATTRIB_MEM_TYPE_VA) + { + if (surface_image.format.fourcc == VA_FOURCC_NV12) + { + uint32_t y_size = surface_image.width * surface_image.height; + newImageBuffer = (unsigned char*)malloc(y_size * 3 / 2); + assert(newImageBuffer); + + y_dst = newImageBuffer; + u_dst = v_dst = newImageBuffer + y_size; + + /* Y plane copy */ + for (row = 0; row < surface_image.height; row++) { + memcpy(y_dst, y_src, surface_image.width); + y_src += surface_image.pitches[0]; + y_dst += surface_image.width; + } + // UV plane + for (row = 0; row < surface_image.height / 2; row++) { + memcpy(u_dst, u_src, surface_image.width); + u_dst += surface_image.width; + u_src += surface_image.pitches[1]; + } + + /* write frame to file */ + do { + n_items = fwrite(newImageBuffer, y_size * 3 / 2, 1, fp); + } while (n_items != 1); + } + else if (surface_image.format.fourcc == VA_FOURCC_RGBP) + { + uint32_t y_size = surface_image.width * surface_image.height; + newImageBuffer = (unsigned char*)malloc(y_size * 3); + assert(newImageBuffer); + + y_dst = newImageBuffer; + u_dst = newImageBuffer + y_size; + v_dst = newImageBuffer + y_size *2; + + for (row = 0; row < surface_image.height; row++) { + memcpy(y_dst, y_src, surface_image.width); + y_src += surface_image.pitches[0]; + y_dst += surface_image.width; + + memcpy(u_dst, u_src, surface_image.width); + u_dst += surface_image.width; + u_src += surface_image.pitches[0]; + + memcpy(v_dst, v_src, surface_image.width); + v_dst += surface_image.width; + v_src += surface_image.pitches[0]; + } + + do { + n_items = fwrite(newImageBuffer, y_size * 3, 1, fp); + } while (n_items != 1); + } + } + else // usrptr surface. + { + if (surface_image.format.fourcc == VA_FOURCC_NV12) + { + // directly copy NV12 1D/2D surface. skip derive and map image. + uint32_t y_size = surface_image.height * surface_image.pitches[0]; + newImageBuffer = (unsigned char*)malloc(y_size * 3 / 2); + assert(newImageBuffer); + memcpy(newImageBuffer, g_dst.pBufBase, (y_size * 3 / 2)); + + do { + n_items = fwrite(newImageBuffer, y_size * 3 / 2, 1, fp); + } while (n_items != 1); + } + else if (surface_image.format.fourcc == VA_FOURCC_RGBP) + { + uint32_t y_size = surface_image.height * surface_image.pitches[0]; + newImageBuffer = (unsigned char*)malloc(y_size * 3); + assert(newImageBuffer); + memcpy(newImageBuffer, g_dst.pBufBase, (y_size * 3)); + + do { + n_items = fwrite(newImageBuffer, y_size * 3, 1, fp); + } while (n_items != 1); + } + } + } + else { + printf("Not supported surface fourcc !!! \n"); + return VA_STATUS_ERROR_INVALID_SURFACE; + } + + if (newImageBuffer){ + free(newImageBuffer); + newImageBuffer = NULL; + } + + vaUnmapBuffer(va_dpy, surface_image.buf); + vaDestroyImage(va_dpy, surface_image.image_id); + + return VA_STATUS_SUCCESS; +} + +static VAStatus +video_frame_process( VASurfaceID in_surface_id, + VASurfaceID out_surface_id) +{ + VAStatus va_status; +#if VA_CHECK_VERSION(1, 10, 0) + VACopyObject src_obj, dst_obj; + VACopyOption option; + memset(&src_obj, 0, sizeof(src_obj)); + memset(&dst_obj, 0, sizeof(dst_obj)); + memset(&option, 0, sizeof(option)); + + src_obj.obj_type = VACopyObjectSurface; + src_obj.object.surface_id = in_surface_id; + dst_obj.obj_type = VACopyObjectSurface; + dst_obj.object.surface_id = out_surface_id; + option.bits.va_copy_mode = g_copy_method; // VA_COPY_MODE_BALANCE; + + va_status = vaCopy(va_dpy, &dst_obj, &src_obj, option); +#else + printf("incorrect libva version!\n"); + va_status = VA_STATUS_ERROR_OPERATION_FAILED; +#endif + return va_status; +} + +static VAStatus +vpp_context_create() +{ + VAStatus va_status = VA_STATUS_SUCCESS; + int32_t j; + + /* VA driver initialization */ + va_dpy = va_open_display(); + int32_t major_ver, minor_ver; + va_status = vaInitialize(va_dpy, &major_ver, &minor_ver); + assert(va_status == VA_STATUS_SUCCESS); + + /* Check whether VPP is supported by driver */ + VAEntrypoint entrypoints[5]; + int32_t num_entrypoints; + num_entrypoints = vaMaxNumEntrypoints(va_dpy); + va_status = vaQueryConfigEntrypoints(va_dpy, + VAProfileNone, + entrypoints, + &num_entrypoints); + CHECK_VASTATUS(va_status, "vaQueryConfigEntrypoints"); + + for (j = 0; j < num_entrypoints; j++) { + if (entrypoints[j] == VAEntrypointVideoProc) + break; + } + + if (j == num_entrypoints) { + printf("VPP is not supported by driver\n"); + assert(0); + } + + /* Render target surface format check */ + VAConfigAttrib attrib; + attrib.type = VAConfigAttribRTFormat; + va_status = vaGetConfigAttributes(va_dpy, + VAProfileNone, + VAEntrypointVideoProc, + &attrib, + 1); + CHECK_VASTATUS(va_status, "vaGetConfigAttributes"); + if (!(attrib.value & g_dst.format)) { + printf("RT format %d is not supported by VPP !\n",g_dst.format); + assert(0); + } + + /* Create surface/config/context for VPP pipeline */ + va_status = create_surface(&g_in_surface_id, g_src); + CHECK_VASTATUS(va_status, "vaCreateSurfaces for input"); + + va_status = create_surface(&g_out_surface_id, g_dst); + CHECK_VASTATUS(va_status, "vaCreateSurfaces for output"); + + va_status = vaCreateConfig(va_dpy, + VAProfileNone, + VAEntrypointVideoProc, + &attrib, + 1, + &config_id); + CHECK_VASTATUS(va_status, "vaCreateConfig"); + + va_status = vaCreateContext(va_dpy, + config_id, + g_dst.width, + g_dst.height, + VA_PROGRESSIVE, + &g_out_surface_id, + 1, + &context_id); + CHECK_VASTATUS(va_status, "vaCreateContext"); + return va_status; +} + +static void +vpp_context_destroy() +{ + /* Release resource */ + vaDestroySurfaces(va_dpy, &g_in_surface_id, 1); + vaDestroySurfaces(va_dpy, &g_out_surface_id, 1); + vaDestroyContext(va_dpy, context_id); + vaDestroyConfig(va_dpy, config_id); + + vaTerminate(va_dpy); + va_close_display(va_dpy); + + _FREE(g_src.pBuf); + _FREE(g_dst.pBuf); +} + +static int8_t +parse_fourcc_and_format(char *str, uint32_t *fourcc, uint32_t *format) +{ + uint32_t tfourcc = VA_FOURCC('N', 'V', '1', '2'); + uint32_t tformat = VA_RT_FORMAT_YUV420; + + if (!strcmp(str, "YV12")){ + tfourcc = VA_FOURCC('Y', 'V', '1', '2'); + } else if(!strcmp(str, "I420")){ + tfourcc = VA_FOURCC('I', '4', '2', '0'); + } else if(!strcmp(str, "NV12")){ + tfourcc = VA_FOURCC('N', 'V', '1', '2'); + } else if(!strcmp(str, "YUY2") || !strcmp(str, "YUYV")) { + tfourcc = VA_FOURCC('Y', 'U', 'Y', '2'); + } else if(!strcmp(str, "UYVY")){ + tfourcc = VA_FOURCC('U', 'Y', 'V', 'Y'); + } else if (!strcmp(str, "P010")) { + tfourcc = VA_FOURCC('P', '0', '1', '0'); + } else if (!strcmp(str, "I010")) { + tfourcc = VA_FOURCC('I', '0', '1', '0'); + } else if (!strcmp(str, "RGBA")) { + tfourcc = VA_FOURCC_RGBA; + } else if (!strcmp(str, "RGBX")) { + tfourcc = VA_FOURCC_RGBX; + } else if (!strcmp(str, "BGRA")) { + tfourcc = VA_FOURCC_BGRA; + } else if (!strcmp(str, "BGRX")) { + tfourcc = VA_FOURCC_BGRX; + } else if (!strcmp(str, "RGBP")) { + tfourcc = VA_FOURCC_RGBP; + } else if (!strcmp(str, "BGRP")) { + tfourcc = VA_FOURCC_BGRP; + } else{ + printf("Not supported format: %s! Currently only support following format: %s\n", + str, "YV12, I420, NV12, YUY2(YUYV), UYVY, P010, I010, RGBA, RGBX, BGRA or BGRX"); + assert(0); + } + + if (fourcc) + *fourcc = tfourcc; + + if (format) + *format = tformat; + + return 0; +} + +static int8_t +parse_basic_parameters() +{ + char str[MAX_LEN]; + memset(&g_src, 0, sizeof(g_src)); + memset(&g_dst, 0, sizeof(g_dst)); + + /* Read src frame file information */ + read_value_string(g_config_file_fd, "SRC_FILE_NAME", g_src.name); + read_value_uint32(g_config_file_fd, "SRC_FRAME_WIDTH", &g_src.width); + read_value_uint32(g_config_file_fd, "SRC_FRAME_HEIGHT", &g_src.height); + read_value_string(g_config_file_fd, "SRC_FRAME_FORMAT", str); + parse_fourcc_and_format(str, &g_src.fourCC, &g_src.format); + read_value_string(g_config_file_fd, "SRC_SURFACE_MEMORY_TYPE", str); + parse_memtype_format(str,&g_src.memtype); + read_value_uint32(g_config_file_fd, "SRC_SURFACE_CPU_ALIGN_SIZE", &g_src.alignsize); + + /* Read dst frame file information */ + read_value_string(g_config_file_fd, "DST_FILE_NAME", g_dst.name); + read_value_uint32(g_config_file_fd, "DST_FRAME_WIDTH", &g_dst.width); + read_value_uint32(g_config_file_fd, "DST_FRAME_HEIGHT",&g_dst.height); + read_value_string(g_config_file_fd, "DST_FRAME_FORMAT", str); + parse_fourcc_and_format(str, &g_dst.fourCC, &g_dst.format); + read_value_string(g_config_file_fd, "DST_SURFACE_MEMORY_TYPE", str); + parse_memtype_format(str,&g_dst.memtype); + read_value_uint32(g_config_file_fd, "DST_SURFACE_CPU_ALIGN_SIZE", &g_dst.alignsize); + + read_value_string(g_config_file_fd, "SRC_FILE_FORMAT", str); + parse_fourcc_and_format(str, &g_src_file_fourcc, NULL); + + read_value_string(g_config_file_fd, "DST_FILE_FORMAT", str); + parse_fourcc_and_format(str, &g_dst_file_fourcc, NULL); + + read_value_uint32(g_config_file_fd, "FRAME_SUM", &g_frame_count); + read_value_uint32(g_config_file_fd, "COPY_METHOD", &g_copy_method); + + if (g_src.width != g_dst.width || + g_src.height != g_dst.height) + { + std::cout<<"va copy doesn't support resize!"<<endl; + return -1; + } + + if (g_src.fourCC != g_dst.fourCC) + { + std::cout<<"va copy doesn't support CSC!" <<endl; + return -1; + } + + std::cout<<"=========Media Copy========="<<endl; + + if (g_src.memtype == VA_SURFACE_ATTRIB_MEM_TYPE_VA) + { + std::cout<<"copy from 2D tile surface to "; + } + else + { + if (g_src.alignsize == 1 || !(g_src.width%g_src.alignsize)) + std::cout<<"copy from 1D linear surface to "; + else + std::cout<<"copy from 2D linear surface with pitch_align "<<g_src.alignsize<<" to "; + } + + if (g_dst.memtype == VA_SURFACE_ATTRIB_MEM_TYPE_VA) + { + std::cout<<"2D tile surface."<<endl; + } + else + { + if (g_dst.alignsize == 1 || !(g_dst.width%g_dst.alignsize)) + std::cout<<"1D linear surface."<<endl; + else + std::cout<<"2D linear surface with pitch_align "<<g_dst.alignsize<<endl; + } + std::cout << "prefer hw engine is "<<g_copy_method<<". notification, 0: blanance(vebox), 1: perf(EU), 2 powersaving(blt)"<<endl; + + return 0; +} + +static void +print_help() +{ + printf("The app is used to test the scaling and csc feature.\n"); + printf("Cmd Usage: ./vacopy process_copy.cfg\n"); + printf("The configure file process_copy.cfg is used to configure the para.\n"); + printf("You can refer process_copy.cfg.template for each para meaning and create the configure file.\n"); +} +int32_t main(int32_t argc, char *argv[]) +{ + VAStatus va_status; + uint32_t i; + + if (argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){ + print_help(); + return -1; + } + + /* Parse the configure file for video process*/ + strncpy(g_config_file_name, argv[1], MAX_LEN); + g_config_file_name[MAX_LEN - 1] = '\0'; + + if (NULL == (g_config_file_fd = fopen(g_config_file_name, "r"))){ + printf("Open configure file %s failed!\n",g_config_file_name); + assert(0); + } + + /* Parse basic parameters */ + if (parse_basic_parameters()){ + printf("Parse parameters in configure file error\n"); + assert(0); + } + + va_status = vpp_context_create(); + if (va_status != VA_STATUS_SUCCESS) { + printf("vpp context create failed \n"); + assert(0); + } + + /* Video frame fetch, process and store */ + if (NULL == (g_src.fd = fopen(g_src.name, "r"))){ + printf("Open SRC_FILE_NAME: %s failed, please specify it in config file: %s !\n", + g_src.name, g_config_file_name); + assert(0); + } + + if (NULL == (g_dst.fd = fopen(g_dst.name, "w"))){ + printf("Open DST_FILE_NAME: %s failed, please specify it in config file: %s !\n", + g_dst.name, g_config_file_name); + assert(0); + } + + printf("\nStart to process, ...\n"); + struct timespec Pre_time; + struct timespec Cur_time; + unsigned int duration = 0; + clock_gettime(CLOCK_MONOTONIC, &Pre_time); + + for (i = 0; i < g_frame_count; i ++){ + upload_frame_to_surface(g_src.fd, g_in_surface_id); + if (VA_STATUS_SUCCESS != video_frame_process(g_in_surface_id, g_out_surface_id)) + { + std::cout<<"***vaCopy failed***"<<std::endl; + } + store_surface_to_file(g_dst.fd, g_out_surface_id); + } + + clock_gettime(CLOCK_MONOTONIC, &Cur_time); + duration = (Cur_time.tv_sec - Pre_time.tv_sec) * 1000; + if (Cur_time.tv_nsec > Pre_time.tv_nsec) { + duration += (Cur_time.tv_nsec - Pre_time.tv_nsec) / 1000000; + } else { + duration += (Cur_time.tv_nsec + 1000000000 - Pre_time.tv_nsec) / 1000000 - 1000; + } + + printf("Finish processing, performance: \n" ); + printf("%d frames processed in: %d ms, ave time = %d ms\n",g_frame_count, duration, duration/g_frame_count); + + if (g_src.fd) + fclose(g_src.fd); + + if (g_dst.fd) + fclose(g_dst.fd); + + if (g_config_file_fd) + fclose(g_config_file_fd); + + vpp_context_destroy(); + + return 0; +} +