|  | /* | 
|  | * 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; | 
|  | } | 
|  |  |