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