• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (c) 2009-2018, Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22 /*
23  * Video process test case based on LibVA.
24  * This test covers different surface format copy.
25  * Usage: ./vacopy process_copy.cfg
26  */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdint.h>
32 #include <iostream>
33 #include <time.h>
34 #include <assert.h>
35 #include <va/va.h>
36 #include <va/va_vpp.h>
37 #include "va_display.h"
38 
39 #ifndef VA_FOURCC_I420
40 #define VA_FOURCC_I420 0x30323449
41 #endif
42 
43 #define MAX_LEN   1024
44 
45 #define CHECK_VASTATUS(va_status,func)                                      \
46   if (va_status != VA_STATUS_SUCCESS) {                                     \
47       fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \
48       exit(1);                                                              \
49   }
50 using namespace std;
51 static VADisplay va_dpy = NULL;
52 static VAContextID context_id = 0;
53 
54 typedef struct _SurfInfo {
55     FILE        *fd;
56     char        name[MAX_LEN];
57     uint32_t    width;
58     uint32_t    height;
59     uint32_t    fourCC;
60     uint32_t    format;
61     uint32_t    memtype;
62     uint32_t    alignsize;
63     void        *pBuf;
64     uint8_t     *pBufBase;
65     uintptr_t   ptrb;
66 } SurfInfo;
67 
68 static SurfInfo g_src;
69 static SurfInfo g_dst;
70 
71 static VAConfigID  config_id = 0;
72 static FILE* g_config_file_fd = NULL;
73 static char g_config_file_name[MAX_LEN];
74 
75 static VASurfaceID g_in_surface_id = VA_INVALID_ID;
76 static VASurfaceID g_out_surface_id = VA_INVALID_ID;
77 
78 static uint32_t g_src_file_fourcc = VA_FOURCC('I', '4', '2', '0');
79 static uint32_t g_dst_file_fourcc = VA_FOURCC('Y', 'V', '1', '2');
80 
81 #define _FREE(p)                       \
82     if(p != NULL){                      \
83         free(p);  p = NULL;                        \
84     }
85 
86 static uint32_t g_frame_count = 0;
87 static uint32_t g_copy_method = 0; //0 blance, 1 perf. 2 power_saving
88 
89 static int8_t
parse_memtype_format(char * str,uint32_t * dst_memtype)90 parse_memtype_format(char *str, uint32_t *dst_memtype)
91 {
92     uint32_t tmemtype = VA_SURFACE_ATTRIB_MEM_TYPE_VA;
93 
94     if (!strcmp(str, "VA")) {
95         tmemtype = VA_SURFACE_ATTRIB_MEM_TYPE_VA;
96     } else if (!strcmp(str, "CPU")) {
97         tmemtype = VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR;
98     } else {
99         printf("Not supported format: %s! Currently only support following format: %s\n",
100                str, "VA,CPU");
101         assert(0);
102     }
103     if (dst_memtype)
104         *dst_memtype = tmemtype;
105     return 0;
106 }
107 
108 static int8_t
read_value_string(FILE * fp,const char * field_name,char * value)109 read_value_string(FILE *fp, const char* field_name, char* value)
110 {
111     char strLine[MAX_LEN];
112     char* field = NULL;
113     char* str = NULL;
114     uint16_t i;
115 
116     if (!fp || !field_name || !value)  {
117         printf("Invalid fuction parameters\n");
118         return -1;
119     }
120 
121     rewind(fp);
122 
123     while (!feof(fp)) {
124         if (!fgets(strLine, MAX_LEN, fp))
125             continue;
126 
127         for (i = 0; i < MAX_LEN && strLine[i]; i++)
128             if (strLine[i] != ' ') break;
129 
130         if (i == MAX_LEN || strLine[i] == '#' || strLine[i] == '\n')
131             continue;
132 
133         field = strtok(&strLine[i], ":");
134         if (strncmp(field, field_name, strlen(field_name)))
135             continue;
136 
137         if (!(str = strtok(NULL, ":")))
138             continue;
139 
140         /* skip blank space in string */
141         while (*str == ' ')
142             str++;
143 
144         *(str + strlen(str) - 1) = '\0';
145         strcpy(value, str);
146 
147         return 0;
148     }
149 
150     return -1;
151 }
152 
153 static int8_t
read_value_uint32(FILE * fp,const char * field_name,uint32_t * value)154 read_value_uint32(FILE* fp, const char* field_name, uint32_t* value)
155 {
156     char str[MAX_LEN];
157 
158     if (read_value_string(fp, field_name, str)) {
159         printf("Failed to find integer field: %s", field_name);
160         return -1;
161     }
162 
163     *value = (uint32_t)atoi(str);
164     return 0;
165 }
166 
167 static VAStatus
create_surface(VASurfaceID * p_surface_id,SurfInfo & surf)168 create_surface(VASurfaceID * p_surface_id, SurfInfo &surf)
169 {
170     VAStatus va_status = VA_STATUS_ERROR_INVALID_PARAMETER;
171     if (surf.memtype == VA_SURFACE_ATTRIB_MEM_TYPE_VA) {
172         VASurfaceAttrib    surface_attrib;
173         surface_attrib.type =  VASurfaceAttribPixelFormat;
174         surface_attrib.flags = VA_SURFACE_ATTRIB_SETTABLE;
175         surface_attrib.value.type = VAGenericValueTypeInteger;
176         surface_attrib.value.value.i = surf.fourCC;
177 
178         va_status = vaCreateSurfaces(va_dpy,
179                                      surf.format,
180                                      surf.width,
181                                      surf.height,
182                                      p_surface_id,
183                                      1,
184                                      &surface_attrib,
185                                      1);
186     } else if (surf.memtype == VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR) {
187         VASurfaceAttrib surfaceAttrib[3];
188         VASurfaceAttribExternalBuffers extBuffer;
189         uint32_t base_addr_align = 0x1000;
190         uint32_t size = 0;
191         surfaceAttrib[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
192         surfaceAttrib[0].type = VASurfaceAttribPixelFormat;
193         surfaceAttrib[0].value.type = VAGenericValueTypeInteger;
194         surfaceAttrib[0].value.value.i = surf.fourCC;
195 
196         surfaceAttrib[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
197         surfaceAttrib[1].type = VASurfaceAttribMemoryType;
198         surfaceAttrib[1].value.type = VAGenericValueTypeInteger;
199         surfaceAttrib[1].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR;
200 
201         surfaceAttrib[2].flags = VA_SURFACE_ATTRIB_SETTABLE;
202         surfaceAttrib[2].type = VASurfaceAttribExternalBufferDescriptor;
203         surfaceAttrib[2].value.type = VAGenericValueTypePointer;
204         surfaceAttrib[2].value.value.p = (void *)&extBuffer;
205         memset(&extBuffer, 0, sizeof(extBuffer));
206 
207         uint32_t pitch_align = surf.alignsize;
208         switch (surf.fourCC) {
209         case VA_FOURCC_NV12:
210             extBuffer.pitches[0] = ((surf.width + pitch_align - 1) / pitch_align) * pitch_align;
211             size = (extBuffer.pitches[0] * surf.height) * 3 / 2; // frame size align with pitch.
212             size = (size + base_addr_align - 1) / base_addr_align * base_addr_align; // frame size align as 4K page.
213             extBuffer.offsets[0] = 0;// Y channel
214             extBuffer.offsets[1] = extBuffer.pitches[0] * surf.height; // UV channel.
215             extBuffer.pitches[1] = extBuffer.pitches[0];
216             extBuffer.num_planes = 2;
217             break;
218         case VA_FOURCC_RGBP:
219             extBuffer.pitches[0] = ((surf.width + pitch_align - 1) / pitch_align) * pitch_align;
220             size = (extBuffer.pitches[0] * surf.height) * 3;// frame size align with pitch.
221             size = (size + base_addr_align - 1) / base_addr_align * base_addr_align; // frame size align as 4K page.
222             extBuffer.offsets[0] = 0;// Y channel
223             extBuffer.offsets[1] = extBuffer.pitches[0] * surf.height; // U channel.
224             extBuffer.pitches[1] = extBuffer.pitches[0];
225             extBuffer.offsets[2] = extBuffer.pitches[0] * surf.height * 2; // V channel.
226             extBuffer.pitches[2] = extBuffer.pitches[0];
227             extBuffer.num_planes = 3;
228             break;
229         default :
230             std::cout << surf.fourCC << "format doesn't support!" << endl;
231             return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
232         }
233         if (!surf.pBuf && !surf.pBufBase) {
234             surf.pBuf = malloc(size + base_addr_align);
235             surf.pBufBase = (uint8_t*)((((uint64_t)(surf.pBuf) + base_addr_align - 1) / base_addr_align) * base_addr_align);
236 
237             extBuffer.pixel_format = surf.fourCC;
238             extBuffer.width = surf.width;
239             extBuffer.height = surf.height;
240             extBuffer.data_size = size;
241             extBuffer.num_buffers = 1;
242             extBuffer.buffers = &(surf.ptrb);
243             extBuffer.buffers[0] = (uintptr_t)(surf.pBufBase);
244             extBuffer.flags = VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR;
245 
246             va_status = vaCreateSurfaces(va_dpy, surf.format, surf.width, surf.height, p_surface_id, 1, surfaceAttrib, 3);
247             CHECK_VASTATUS(va_status, "vaCreateSurfaces");
248         } else {
249             std::cout << "previous frame buffer hasn't be released!" << endl;
250         }
251     }
252 
253     return va_status;
254 }
255 
256 /* Load frame to surface*/
257 static VAStatus
upload_frame_to_surface(FILE * fp,VASurfaceID surface_id)258 upload_frame_to_surface(FILE *fp,
259                         VASurfaceID surface_id)
260 {
261     VAStatus va_status;
262     VAImage surface_image;
263     unsigned char *y_src = NULL;
264     unsigned char *u_src = NULL;
265     unsigned char *v_src = NULL;
266     unsigned char *y_dst = NULL;
267     unsigned char *u_dst = NULL;
268     unsigned char *v_dst = NULL;
269     void *surface_p = NULL;
270     uint32_t frame_size, row;
271     size_t n_items;
272     unsigned char * newImageBuffer = NULL;
273     va_status = vaSyncSurface(va_dpy, surface_id);
274     CHECK_VASTATUS(va_status, "vaSyncSurface");
275 
276     va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
277     CHECK_VASTATUS(va_status, "vaDeriveImage");
278 
279     va_status = vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
280     CHECK_VASTATUS(va_status, "vaMapBuffer");
281 
282     if (g_src.memtype == VA_SURFACE_ATTRIB_MEM_TYPE_VA) {
283         std::cout << "2D src surface width = " << g_src.width << " pitch = " << surface_image.pitches[0] << endl;
284     } else {
285         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;
286     }
287 
288     if (surface_image.format.fourcc == VA_FOURCC_RGBP) {
289         frame_size = surface_image.width * surface_image.height * 3;
290         newImageBuffer = (unsigned char*)malloc(frame_size);
291         assert(newImageBuffer);
292 
293         do {
294             n_items = fread(newImageBuffer, frame_size, 1, fp);
295         } while (n_items != 1);
296 
297         y_src = newImageBuffer;
298         u_src = newImageBuffer + surface_image.width * surface_image.height;
299         v_src = newImageBuffer + surface_image.width * surface_image.height * 2;
300 
301         y_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]);
302         u_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
303         v_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]);
304 
305         for (row = 0; row < surface_image.height; row++) {
306             memcpy(y_dst, y_src, surface_image.width);
307             y_dst += surface_image.pitches[0];
308             y_src += surface_image.width;
309 
310             memcpy(u_dst, u_src, surface_image.width);
311             u_dst += surface_image.pitches[0];
312             u_src += surface_image.width;
313 
314             memcpy(v_dst, v_src, surface_image.width);
315             v_dst += surface_image.pitches[0];
316             v_src += surface_image.width;
317         }
318     } else if (surface_image.format.fourcc == VA_FOURCC_NV12) {
319         frame_size = surface_image.width * surface_image.height * 3 / 2;
320         newImageBuffer = (unsigned char*)malloc(frame_size);
321         assert(newImageBuffer);
322 
323         do {
324             n_items = fread(newImageBuffer, frame_size, 1, fp);
325         } while (n_items != 1);
326 
327         y_src = newImageBuffer;
328         u_src = newImageBuffer + surface_image.width * surface_image.height;
329         v_src = u_src;
330 
331         y_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]);
332         u_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
333         v_dst = u_dst;
334 
335         /* Y plane, directly copy */
336         for (row = 0; row < surface_image.height; row++) {
337             memcpy(y_dst, y_src, surface_image.width);
338             y_dst += surface_image.pitches[0];
339             y_src += surface_image.width;
340         }
341 
342         /* UV plane */
343         for (row = 0; row < surface_image.height / 2; row++) {
344             memcpy(u_dst, u_src, surface_image.width);
345             u_src += surface_image.width;
346             v_src = u_src;
347             u_dst += surface_image.pitches[1];
348         }
349     }
350 
351     if (newImageBuffer) {
352         free(newImageBuffer);
353         newImageBuffer = NULL;
354     }
355 
356     vaUnmapBuffer(va_dpy, surface_image.buf);
357     vaDestroyImage(va_dpy, surface_image.image_id);
358 
359     return VA_STATUS_SUCCESS;
360 }
361 
362 static VAStatus
store_surface_to_file(FILE * fp,VASurfaceID surface_id)363 store_surface_to_file(FILE *fp,
364                       VASurfaceID surface_id)
365 {
366     VAStatus va_status;
367     VAImage surface_image;
368     void *surface_p = NULL;
369     unsigned char *y_src = NULL;
370     unsigned char *u_src = NULL;
371     unsigned char *v_src = NULL;
372     unsigned char *y_dst = NULL;
373     unsigned char *u_dst = NULL;
374     unsigned char *v_dst = NULL;
375     uint32_t row;
376     int32_t n_items;
377     unsigned char * newImageBuffer = NULL;
378     va_status = vaSyncSurface(va_dpy, surface_id);
379     CHECK_VASTATUS(va_status, "vaSyncSurface");
380 
381     va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
382     CHECK_VASTATUS(va_status, "vaDeriveImage");
383 
384     va_status = vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
385     CHECK_VASTATUS(va_status, "vaMapBuffer");
386 
387     if (g_dst.memtype == VA_SURFACE_ATTRIB_MEM_TYPE_VA) {
388         std::cout << "2D dst surface width = " << g_dst.width << " pitch = " << surface_image.pitches[0] << endl;
389     } else {
390         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;
391     }
392 
393     /* store the surface to one nv12 file */
394     if (surface_image.format.fourcc == VA_FOURCC_NV12 ||
395         surface_image.format.fourcc == VA_FOURCC_RGBP) {
396 
397         y_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]);
398 
399         if (surface_image.format.fourcc == VA_FOURCC_RGBP) {
400             u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
401             v_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]);
402         } else if (surface_image.format.fourcc == VA_FOURCC_NV12) {
403             u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
404             v_src = u_src;
405         }
406 
407         if (g_dst.memtype == VA_SURFACE_ATTRIB_MEM_TYPE_VA) {
408             if (surface_image.format.fourcc == VA_FOURCC_NV12) {
409                 uint32_t y_size = surface_image.width * surface_image.height;
410                 newImageBuffer = (unsigned char*)malloc(y_size * 3 / 2);
411                 assert(newImageBuffer);
412 
413                 y_dst = newImageBuffer;
414                 u_dst = v_dst = newImageBuffer + y_size;
415 
416                 /* Y plane copy */
417                 for (row = 0; row < surface_image.height; row++) {
418                     memcpy(y_dst, y_src, surface_image.width);
419                     y_src += surface_image.pitches[0];
420                     y_dst += surface_image.width;
421                 }
422                 // UV plane
423                 for (row = 0; row < surface_image.height / 2; row++) {
424                     memcpy(u_dst, u_src, surface_image.width);
425                     u_dst += surface_image.width;
426                     u_src += surface_image.pitches[1];
427                 }
428 
429                 /* write frame to file */
430                 do {
431                     n_items = fwrite(newImageBuffer, y_size * 3 / 2, 1, fp);
432                 } while (n_items != 1);
433             } else if (surface_image.format.fourcc == VA_FOURCC_RGBP) {
434                 uint32_t y_size = surface_image.width * surface_image.height;
435                 newImageBuffer = (unsigned char*)malloc(y_size * 3);
436                 assert(newImageBuffer);
437 
438                 y_dst = newImageBuffer;
439                 u_dst = newImageBuffer + y_size;
440                 v_dst = newImageBuffer + y_size * 2;
441 
442                 for (row = 0; row < surface_image.height; row++) {
443                     memcpy(y_dst, y_src, surface_image.width);
444                     y_src += surface_image.pitches[0];
445                     y_dst += surface_image.width;
446 
447                     memcpy(u_dst, u_src, surface_image.width);
448                     u_dst += surface_image.width;
449                     u_src += surface_image.pitches[0];
450 
451                     memcpy(v_dst, v_src, surface_image.width);
452                     v_dst += surface_image.width;
453                     v_src += surface_image.pitches[0];
454                 }
455 
456                 do {
457                     n_items = fwrite(newImageBuffer, y_size * 3, 1, fp);
458                 } while (n_items != 1);
459             }
460         } else { // usrptr surface.
461             if (surface_image.format.fourcc == VA_FOURCC_NV12) {
462                 // directly copy NV12 1D/2D surface. skip derive and map image.
463                 uint32_t y_size = surface_image.height * surface_image.pitches[0];
464                 newImageBuffer = (unsigned char*)malloc(y_size * 3 / 2);
465                 assert(newImageBuffer);
466                 memcpy(newImageBuffer, g_dst.pBufBase, (y_size * 3 / 2));
467 
468                 do {
469                     n_items = fwrite(newImageBuffer, y_size * 3 / 2, 1, fp);
470                 } while (n_items != 1);
471             } else if (surface_image.format.fourcc == VA_FOURCC_RGBP) {
472                 uint32_t y_size = surface_image.height * surface_image.pitches[0];
473                 newImageBuffer = (unsigned char*)malloc(y_size * 3);
474                 assert(newImageBuffer);
475                 memcpy(newImageBuffer, g_dst.pBufBase, (y_size * 3));
476 
477                 do {
478                     n_items = fwrite(newImageBuffer, y_size * 3, 1, fp);
479                 } while (n_items != 1);
480             }
481         }
482     } else {
483         printf("Not supported surface fourcc !!! \n");
484         return VA_STATUS_ERROR_INVALID_SURFACE;
485     }
486 
487     if (newImageBuffer) {
488         free(newImageBuffer);
489         newImageBuffer = NULL;
490     }
491 
492     vaUnmapBuffer(va_dpy, surface_image.buf);
493     vaDestroyImage(va_dpy, surface_image.image_id);
494 
495     return VA_STATUS_SUCCESS;
496 }
497 
498 static VAStatus
video_frame_process(VASurfaceID in_surface_id,VASurfaceID out_surface_id)499 video_frame_process(VASurfaceID in_surface_id,
500                     VASurfaceID out_surface_id)
501 {
502     VAStatus va_status;
503 #if VA_CHECK_VERSION(1, 10, 0)
504     VACopyObject src_obj, dst_obj;
505     VACopyOption option;
506     memset(&src_obj, 0, sizeof(src_obj));
507     memset(&dst_obj, 0, sizeof(dst_obj));
508     memset(&option, 0, sizeof(option));
509 
510     src_obj.obj_type = VACopyObjectSurface;
511     src_obj.object.surface_id = in_surface_id;
512     dst_obj.obj_type = VACopyObjectSurface;
513     dst_obj.object.surface_id = out_surface_id;
514     option.bits.va_copy_mode = g_copy_method; // VA_COPY_MODE_BALANCE;
515 
516     va_status = vaCopy(va_dpy, &dst_obj, &src_obj, option);
517 #else
518     printf("incorrect libva version!\n");
519     va_status = VA_STATUS_ERROR_OPERATION_FAILED;
520 #endif
521     return va_status;
522 }
523 
524 static VAStatus
vpp_context_create()525 vpp_context_create()
526 {
527     VAStatus va_status = VA_STATUS_SUCCESS;
528     int32_t j;
529 
530     /* VA driver initialization */
531     va_dpy = va_open_display();
532     int32_t major_ver, minor_ver;
533     va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
534     assert(va_status == VA_STATUS_SUCCESS);
535 
536     /* Check whether VPP is supported by driver */
537     VAEntrypoint entrypoints[5];
538     int32_t num_entrypoints;
539     num_entrypoints = vaMaxNumEntrypoints(va_dpy);
540     va_status = vaQueryConfigEntrypoints(va_dpy,
541                                          VAProfileNone,
542                                          entrypoints,
543                                          &num_entrypoints);
544     CHECK_VASTATUS(va_status, "vaQueryConfigEntrypoints");
545 
546     for (j = 0; j < num_entrypoints; j++) {
547         if (entrypoints[j] == VAEntrypointVideoProc)
548             break;
549     }
550 
551     if (j == num_entrypoints) {
552         printf("VPP is not supported by driver\n");
553         assert(0);
554     }
555 
556     /* Render target surface format check */
557     VAConfigAttrib attrib;
558     attrib.type = VAConfigAttribRTFormat;
559     va_status = vaGetConfigAttributes(va_dpy,
560                                       VAProfileNone,
561                                       VAEntrypointVideoProc,
562                                       &attrib,
563                                       1);
564     CHECK_VASTATUS(va_status, "vaGetConfigAttributes");
565     if (!(attrib.value & g_dst.format)) {
566         printf("RT format %d is not supported by VPP !\n", g_dst.format);
567         assert(0);
568     }
569 
570     /* Create surface/config/context for VPP pipeline */
571     va_status = create_surface(&g_in_surface_id, g_src);
572     CHECK_VASTATUS(va_status, "vaCreateSurfaces for input");
573 
574     va_status = create_surface(&g_out_surface_id, g_dst);
575     CHECK_VASTATUS(va_status, "vaCreateSurfaces for output");
576 
577     va_status = vaCreateConfig(va_dpy,
578                                VAProfileNone,
579                                VAEntrypointVideoProc,
580                                &attrib,
581                                1,
582                                &config_id);
583     CHECK_VASTATUS(va_status, "vaCreateConfig");
584 
585     va_status = vaCreateContext(va_dpy,
586                                 config_id,
587                                 g_dst.width,
588                                 g_dst.height,
589                                 VA_PROGRESSIVE,
590                                 &g_out_surface_id,
591                                 1,
592                                 &context_id);
593     CHECK_VASTATUS(va_status, "vaCreateContext");
594     return va_status;
595 }
596 
597 static void
vpp_context_destroy()598 vpp_context_destroy()
599 {
600     /* Release resource */
601     vaDestroySurfaces(va_dpy, &g_in_surface_id, 1);
602     vaDestroySurfaces(va_dpy, &g_out_surface_id, 1);
603     vaDestroyContext(va_dpy, context_id);
604     vaDestroyConfig(va_dpy, config_id);
605 
606     vaTerminate(va_dpy);
607     va_close_display(va_dpy);
608 
609     _FREE(g_src.pBuf);
610     _FREE(g_dst.pBuf);
611 }
612 
613 static int8_t
parse_fourcc_and_format(char * str,uint32_t * fourcc,uint32_t * format)614 parse_fourcc_and_format(char *str, uint32_t *fourcc, uint32_t *format)
615 {
616     uint32_t tfourcc = VA_FOURCC('N', 'V', '1', '2');
617     uint32_t tformat = VA_RT_FORMAT_YUV420;
618 
619     if (!strcmp(str, "YV12")) {
620         tfourcc = VA_FOURCC('Y', 'V', '1', '2');
621     } else if (!strcmp(str, "I420")) {
622         tfourcc = VA_FOURCC('I', '4', '2', '0');
623     } else if (!strcmp(str, "NV12")) {
624         tfourcc = VA_FOURCC('N', 'V', '1', '2');
625     } else if (!strcmp(str, "YUY2") || !strcmp(str, "YUYV")) {
626         tfourcc = VA_FOURCC('Y', 'U', 'Y', '2');
627     } else if (!strcmp(str, "UYVY")) {
628         tfourcc = VA_FOURCC('U', 'Y', 'V', 'Y');
629     } else if (!strcmp(str, "P010")) {
630         tfourcc = VA_FOURCC('P', '0', '1', '0');
631     } else if (!strcmp(str, "I010")) {
632         tfourcc = VA_FOURCC('I', '0', '1', '0');
633     } else if (!strcmp(str, "RGBA")) {
634         tfourcc = VA_FOURCC_RGBA;
635     } else if (!strcmp(str, "RGBX")) {
636         tfourcc = VA_FOURCC_RGBX;
637     } else if (!strcmp(str, "BGRA")) {
638         tfourcc = VA_FOURCC_BGRA;
639     } else if (!strcmp(str, "BGRX")) {
640         tfourcc = VA_FOURCC_BGRX;
641     } else if (!strcmp(str, "RGBP")) {
642         tfourcc = VA_FOURCC_RGBP;
643     } else if (!strcmp(str, "BGRP")) {
644         tfourcc = VA_FOURCC_BGRP;
645     } else {
646         printf("Not supported format: %s! Currently only support following format: %s\n",
647                str, "YV12, I420, NV12, YUY2(YUYV), UYVY, P010, I010, RGBA, RGBX, BGRA or BGRX");
648         assert(0);
649     }
650 
651     if (fourcc)
652         *fourcc = tfourcc;
653 
654     if (format)
655         *format = tformat;
656 
657     return 0;
658 }
659 
660 static int8_t
parse_basic_parameters()661 parse_basic_parameters()
662 {
663     char str[MAX_LEN];
664     memset(&g_src, 0, sizeof(g_src));
665     memset(&g_dst, 0, sizeof(g_dst));
666 
667     /* Read src frame file information */
668     read_value_string(g_config_file_fd, "SRC_FILE_NAME", g_src.name);
669     read_value_uint32(g_config_file_fd, "SRC_FRAME_WIDTH", &g_src.width);
670     read_value_uint32(g_config_file_fd, "SRC_FRAME_HEIGHT", &g_src.height);
671     read_value_string(g_config_file_fd, "SRC_FRAME_FORMAT", str);
672     parse_fourcc_and_format(str, &g_src.fourCC, &g_src.format);
673     read_value_string(g_config_file_fd, "SRC_SURFACE_MEMORY_TYPE", str);
674     parse_memtype_format(str, &g_src.memtype);
675     read_value_uint32(g_config_file_fd, "SRC_SURFACE_CPU_ALIGN_SIZE", &g_src.alignsize);
676 
677     /* Read dst frame file information */
678     read_value_string(g_config_file_fd, "DST_FILE_NAME", g_dst.name);
679     read_value_uint32(g_config_file_fd, "DST_FRAME_WIDTH", &g_dst.width);
680     read_value_uint32(g_config_file_fd, "DST_FRAME_HEIGHT", &g_dst.height);
681     read_value_string(g_config_file_fd, "DST_FRAME_FORMAT", str);
682     parse_fourcc_and_format(str, &g_dst.fourCC, &g_dst.format);
683     read_value_string(g_config_file_fd, "DST_SURFACE_MEMORY_TYPE", str);
684     parse_memtype_format(str, &g_dst.memtype);
685     read_value_uint32(g_config_file_fd, "DST_SURFACE_CPU_ALIGN_SIZE", &g_dst.alignsize);
686 
687     read_value_string(g_config_file_fd, "SRC_FILE_FORMAT", str);
688     parse_fourcc_and_format(str, &g_src_file_fourcc, NULL);
689 
690     read_value_string(g_config_file_fd, "DST_FILE_FORMAT", str);
691     parse_fourcc_and_format(str, &g_dst_file_fourcc, NULL);
692 
693     read_value_uint32(g_config_file_fd, "FRAME_SUM", &g_frame_count);
694     read_value_uint32(g_config_file_fd, "COPY_METHOD", &g_copy_method);
695 
696     if (g_src.width != g_dst.width ||
697         g_src.height != g_dst.height) {
698         std::cout << "va copy doesn't support resize!" << endl;
699         return -1;
700     }
701 
702     if (g_src.fourCC != g_dst.fourCC) {
703         std::cout << "va copy doesn't support CSC!" << endl;
704         return -1;
705     }
706 
707     std::cout << "=========Media Copy=========" << endl;
708 
709     if (g_src.memtype == VA_SURFACE_ATTRIB_MEM_TYPE_VA) {
710         std::cout << "copy from 2D tile surface to ";
711     } else {
712         if (g_src.alignsize == 1 || !(g_src.width % g_src.alignsize))
713             std::cout << "copy from 1D linear surface to ";
714         else
715             std::cout << "copy from 2D linear surface with pitch_align " << g_src.alignsize << " to ";
716     }
717 
718     if (g_dst.memtype == VA_SURFACE_ATTRIB_MEM_TYPE_VA) {
719         std::cout << "2D tile surface." << endl;
720     } else {
721         if (g_dst.alignsize == 1 || !(g_dst.width % g_dst.alignsize))
722             std::cout << "1D linear surface." << endl;
723         else
724             std::cout << "2D linear surface with pitch_align " << g_dst.alignsize << endl;
725     }
726     std::cout << "prefer hw engine is " << g_copy_method << ". notification, 0: blanance(vebox), 1: perf(EU), 2 powersaving(blt)" << endl;
727 
728     return 0;
729 }
730 
731 static void
print_help()732 print_help()
733 {
734     printf("The app is used to test the scaling and csc feature.\n");
735     printf("Cmd Usage: ./vacopy process_copy.cfg\n");
736     printf("The configure file process_copy.cfg is used to configure the para.\n");
737     printf("You can refer process_copy.cfg.template for each para meaning and create the configure file.\n");
738 }
main(int32_t argc,char * argv[])739 int32_t main(int32_t argc, char *argv[])
740 {
741     VAStatus va_status;
742     uint32_t i;
743 
744     if (argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
745         print_help();
746         return -1;
747     }
748 
749     /* Parse the configure file for video process*/
750     strncpy(g_config_file_name, argv[1], MAX_LEN);
751     g_config_file_name[MAX_LEN - 1] = '\0';
752 
753     if (NULL == (g_config_file_fd = fopen(g_config_file_name, "r"))) {
754         printf("Open configure file %s failed!\n", g_config_file_name);
755         assert(0);
756     }
757 
758     /* Parse basic parameters */
759     if (parse_basic_parameters()) {
760         printf("Parse parameters in configure file error\n");
761         assert(0);
762     }
763 
764     va_status = vpp_context_create();
765     if (va_status != VA_STATUS_SUCCESS) {
766         printf("vpp context create failed \n");
767         assert(0);
768     }
769 
770     /* Video frame fetch, process and store */
771     if (NULL == (g_src.fd = fopen(g_src.name, "r"))) {
772         printf("Open SRC_FILE_NAME: %s failed, please specify it in config file: %s !\n",
773                g_src.name, g_config_file_name);
774         assert(0);
775     }
776 
777     if (NULL == (g_dst.fd = fopen(g_dst.name, "w"))) {
778         printf("Open DST_FILE_NAME: %s failed, please specify it in config file: %s !\n",
779                g_dst.name, g_config_file_name);
780         assert(0);
781     }
782 
783     printf("\nStart to process, ...\n");
784     struct timespec Pre_time;
785     struct timespec Cur_time;
786     unsigned int duration = 0;
787     clock_gettime(CLOCK_MONOTONIC, &Pre_time);
788 
789     for (i = 0; i < g_frame_count; i ++) {
790         upload_frame_to_surface(g_src.fd, g_in_surface_id);
791         if (VA_STATUS_SUCCESS != video_frame_process(g_in_surface_id, g_out_surface_id)) {
792             std::cout << "***vaCopy failed***" << std::endl;
793         }
794         store_surface_to_file(g_dst.fd, g_out_surface_id);
795     }
796 
797     clock_gettime(CLOCK_MONOTONIC, &Cur_time);
798     duration = (Cur_time.tv_sec - Pre_time.tv_sec) * 1000;
799     if (Cur_time.tv_nsec > Pre_time.tv_nsec) {
800         duration += (Cur_time.tv_nsec - Pre_time.tv_nsec) / 1000000;
801     } else {
802         duration += (Cur_time.tv_nsec + 1000000000 - Pre_time.tv_nsec) / 1000000 - 1000;
803     }
804 
805     printf("Finish processing, performance: \n");
806     printf("%d frames processed in: %d ms, ave time = %d ms\n", g_frame_count, duration, duration / g_frame_count);
807 
808     if (g_src.fd)
809         fclose(g_src.fd);
810 
811     if (g_dst.fd)
812         fclose(g_dst.fd);
813 
814     if (g_config_file_fd)
815         fclose(g_config_file_fd);
816 
817     vpp_context_destroy();
818 
819     return 0;
820 }
821 
822