• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (c) 2009-2021, 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 scaling and several surface format conversion.
25  * Usage: ./vppscaling_csc process_scaling_csc.cfg
26  */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdint.h>
32 #include <time.h>
33 #include <assert.h>
34 #include <va/va.h>
35 #include <va/va_vpp.h>
36 #include "va_display.h"
37 
38 #ifndef VA_FOURCC_I420
39 #define VA_FOURCC_I420 0x30323449
40 #endif
41 
42 #define MAX_LEN   1024
43 
44 #define CHECK_VASTATUS(va_status,func)                                      \
45   if (va_status != VA_STATUS_SUCCESS) {                                     \
46       fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \
47       exit(1);                                                              \
48   }
49 
50 /* indicate the pipleine is scaling -> 3dlut, two seperate calls */
51 #define VA_SCALING_3DLUT 0
52 /* indicate the pipleine is 3dlut -> scaling, by default in one call */
53 #define VA_3DLUT_SCALING 1
54 #define VA_SCALING_ONLY  2
55 
56 static VADisplay va_dpy = NULL;
57 static VAContextID context_id = 0;
58 static VAConfigID  config_id = 0;
59 static VASurfaceID g_in_surface_id = VA_INVALID_ID;
60 static VASurfaceID g_out_surface_id = VA_INVALID_ID;
61 /* only for VA_SCALING_3DLUT scaled surface */
62 static VASurfaceID g_inter_surface_id = VA_INVALID_ID;
63 static VASurfaceID g_3dlut_surface_id = VA_INVALID_ID;
64 
65 static FILE* g_config_file_fd = NULL;
66 static FILE* g_src_file_fd = NULL;
67 static FILE* g_dst_file_fd = NULL;
68 
69 static char g_config_file_name[MAX_LEN];
70 static char g_src_file_name[MAX_LEN];
71 static char g_dst_file_name[MAX_LEN];
72 
73 static uint32_t g_in_pic_width = 352;
74 static uint32_t g_in_pic_height = 288;
75 static uint32_t g_out_pic_width = 352;
76 static uint32_t g_out_pic_height = 288;
77 
78 static uint32_t g_in_fourcc  = VA_FOURCC('N', 'V', '1', '2');
79 static uint32_t g_in_format  = VA_RT_FORMAT_YUV420;
80 static uint32_t g_out_fourcc = VA_FOURCC('N', 'V', '1', '2');
81 static uint32_t g_out_format = VA_RT_FORMAT_YUV420;
82 static uint32_t g_src_file_fourcc = VA_FOURCC('I', '4', '2', '0');
83 static uint32_t g_dst_file_fourcc = VA_FOURCC('N', 'V', '1', '2');
84 
85 static uint32_t g_frame_count = 1;
86 static uint32_t g_pipeline_sequence = VA_3DLUT_SCALING;
87 
88 static char g_3dlut_file_name[MAX_LEN];
89 static uint16_t g_3dlut_seg_size = 65;
90 static uint16_t g_3dlut_mul_size = 128;
91 static uint32_t g_3dlut_channel_mapping = 1;
92 
93 #if VA_CHECK_VERSION(1, 12, 0)
94 
95 static int8_t
read_value_string(FILE * fp,const char * field_name,char * value)96 read_value_string(FILE *fp, const char* field_name, char* value)
97 {
98     char strLine[MAX_LEN];
99     char* field = NULL;
100     char* str = NULL;
101     uint16_t i;
102 
103     if (!fp || !field_name || !value)  {
104         printf("Invalid fuction parameters\n");
105         return -1;
106     }
107 
108     rewind(fp);
109 
110     while (!feof(fp)) {
111         if (!fgets(strLine, MAX_LEN, fp))
112             continue;
113 
114         for (i = 0; i < MAX_LEN && strLine[i]; i++)
115             if (strLine[i] != ' ') break;
116 
117         if (i == MAX_LEN || strLine[i] == '#' || strLine[i] == '\n')
118             continue;
119 
120         field = strtok(&strLine[i], ":");
121         if (strncmp(field, field_name, strlen(field_name)))
122             continue;
123 
124         if (!(str = strtok(NULL, ":")))
125             continue;
126 
127         /* skip blank space in string */
128         while (*str == ' ')
129             str++;
130 
131         *(str + strlen(str) - 1) = '\0';
132         strcpy(value, str);
133 
134         return 0;
135     }
136 
137     return -1;
138 }
139 
140 static int8_t
read_value_uint32(FILE * fp,const char * field_name,uint32_t * value)141 read_value_uint32(FILE* fp, const char* field_name, uint32_t* value)
142 {
143     char str[MAX_LEN];
144 
145     if (read_value_string(fp, field_name, str)) {
146         printf("Failed to find integer field: %s", field_name);
147         return -1;
148     }
149 
150     *value = (uint32_t)atoi(str);
151     return 0;
152 }
153 
154 static int8_t
read_value_uint16(FILE * fp,const char * field_name,uint16_t * value)155 read_value_uint16(FILE* fp, const char* field_name, uint16_t* value)
156 {
157     char str[MAX_LEN];
158 
159     if (read_value_string(fp, field_name, str)) {
160         printf("Failed to find integer field: %s", field_name);
161         return -1;
162     }
163 
164     *value = (uint16_t)atoi(str);
165     return 0;
166 }
167 
168 /* Load yuv frame to NV12/YV12/I420 surface*/
169 static VAStatus
upload_yuv_frame_to_yuv_surface(FILE * fp,VASurfaceID surface_id)170 upload_yuv_frame_to_yuv_surface(FILE *fp,
171                                 VASurfaceID surface_id)
172 {
173     VAStatus va_status;
174     VAImage surface_image;
175     unsigned char *y_src = NULL;
176     unsigned char *u_src = NULL;
177     unsigned char *v_src = NULL;
178     unsigned char *y_dst = NULL;
179     unsigned char *u_dst = NULL;
180     unsigned char *v_dst = NULL;
181     void *surface_p = NULL;
182     uint32_t frame_size, row, col;
183     size_t n_items;
184     unsigned char * newImageBuffer = NULL;
185     va_status = vaSyncSurface(va_dpy, surface_id);
186     CHECK_VASTATUS(va_status, "vaSyncSurface");
187 
188     va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
189     CHECK_VASTATUS(va_status, "vaDeriveImage");
190 
191     va_status = vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
192     CHECK_VASTATUS(va_status, "vaMapBuffer");
193 
194     if (surface_image.format.fourcc == VA_FOURCC_YV12 ||
195         surface_image.format.fourcc == VA_FOURCC_I420 ||
196         surface_image.format.fourcc == VA_FOURCC_NV12) {
197 
198         frame_size = surface_image.width * surface_image.height * 3 / 2;
199         newImageBuffer = (unsigned char*)malloc(frame_size);
200         assert(newImageBuffer);
201 
202         do {
203             n_items = fread(newImageBuffer, frame_size, 1, fp);
204         } while (n_items != 1);
205 
206         y_src = newImageBuffer;
207         if (g_src_file_fourcc == VA_FOURCC_I420) {
208             u_src = newImageBuffer + surface_image.width * surface_image.height;
209             v_src = newImageBuffer + surface_image.width * surface_image.height * 5 / 4;
210         } else if (g_src_file_fourcc == VA_FOURCC_YV12) {
211             v_src = newImageBuffer + surface_image.width * surface_image.height;
212             u_src = newImageBuffer + surface_image.width * surface_image.height * 5 / 4;
213         } else if (g_src_file_fourcc == VA_FOURCC_NV12) {
214             u_src = newImageBuffer + surface_image.width * surface_image.height;
215             v_src = u_src;
216         } else {
217             printf("Not supported YUV fourcc for input file !!!\n");
218             free(newImageBuffer);
219             return VA_STATUS_ERROR_INVALID_SURFACE;
220         }
221 
222         y_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]);
223 
224         if (surface_image.format.fourcc == VA_FOURCC_YV12) {
225             v_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
226             u_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]);
227         } else if (surface_image.format.fourcc == VA_FOURCC_I420) {
228             u_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
229             v_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]);
230         } else {
231             u_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
232             v_dst = u_dst;
233         }
234 
235         /* Y plane, directly copy */
236         for (row = 0; row < surface_image.height; row++) {
237             memcpy(y_dst, y_src, surface_image.width);
238             y_dst += surface_image.pitches[0];
239             y_src += surface_image.width;
240         }
241 
242         /* UV plane */
243         if (surface_image.format.fourcc == VA_FOURCC_YV12 ||
244             surface_image.format.fourcc == VA_FOURCC_I420) {
245             for (row = 0; row < surface_image.height / 2; row ++) {
246                 if (g_src_file_fourcc == VA_FOURCC_I420 ||
247                     g_src_file_fourcc == VA_FOURCC_YV12) {
248                     memcpy(v_dst, v_src, surface_image.width / 2);
249                     memcpy(u_dst, u_src, surface_image.width / 2);
250 
251                     v_src += surface_image.width / 2;
252                     u_src += surface_image.width / 2;
253                 } else {
254                     for (col = 0; col < surface_image.width / 2; col++) {
255                         u_dst[col] = u_src[col * 2];
256                         v_dst[col] = u_src[col * 2 + 1];
257                     }
258 
259                     u_src += surface_image.width;
260                     v_src = u_src;
261                 }
262 
263                 if (surface_image.format.fourcc == VA_FOURCC_YV12) {
264                     v_dst += surface_image.pitches[1];
265                     u_dst += surface_image.pitches[2];
266                 } else {
267                     v_dst += surface_image.pitches[2];
268                     u_dst += surface_image.pitches[1];
269                 }
270             }
271         } else if (surface_image.format.fourcc == VA_FOURCC_NV12) {
272             for (row = 0; row < surface_image.height / 2; row++) {
273                 if (g_src_file_fourcc == VA_FOURCC_I420 ||
274                     g_src_file_fourcc == VA_FOURCC_YV12) {
275                     for (col = 0; col < surface_image.width / 2; col++) {
276                         u_dst[col * 2] = u_src[col];
277                         u_dst[col * 2 + 1] = v_src[col];
278                     }
279 
280                     u_src += (surface_image.width / 2);
281                     v_src += (surface_image.width / 2);
282                 } else {
283                     memcpy(u_dst, u_src, surface_image.width);
284                     u_src += surface_image.width;
285                     v_src = u_src;
286                 }
287 
288                 u_dst += surface_image.pitches[1];
289             }
290         }
291     } else if ((surface_image.format.fourcc == VA_FOURCC_YUY2 &&
292                 g_src_file_fourcc == VA_FOURCC_YUY2) ||
293                (surface_image.format.fourcc == VA_FOURCC_UYVY &&
294                 g_src_file_fourcc == VA_FOURCC_UYVY)) {
295         frame_size = surface_image.width * surface_image.height * 2;
296         newImageBuffer = (unsigned char*)malloc(frame_size);
297         assert(newImageBuffer);
298 
299         do {
300             n_items = fread(newImageBuffer, frame_size, 1, fp);
301         } while (n_items != 1);
302 
303         y_src = newImageBuffer;
304         y_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]);
305 
306         /* plane 0, directly copy */
307         for (row = 0; row < surface_image.height; row++) {
308             memcpy(y_dst, y_src, surface_image.width * 2);
309             y_src += surface_image.width * 2;
310             y_dst += surface_image.pitches[0];
311         }
312     } else if ((surface_image.format.fourcc == VA_FOURCC_P010 &&
313                 g_src_file_fourcc == VA_FOURCC_P010) ||
314                (surface_image.format.fourcc == VA_FOURCC_I010 &&
315                 g_src_file_fourcc == VA_FOURCC_I010)) {
316         frame_size = surface_image.width * surface_image.height * 3;
317         newImageBuffer = (unsigned char*)malloc(frame_size);
318         assert(newImageBuffer);
319 
320         do {
321             n_items = fread(newImageBuffer, frame_size, 1, fp);
322         } while (n_items != 1);
323 
324         y_src = newImageBuffer;
325         y_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]);
326 
327         /* plane 0, directly copy */
328         for (row = 0; row < surface_image.height; row++) {
329             memcpy(y_dst, y_src, surface_image.width * 2);
330             y_src += surface_image.width * 2;
331             y_dst += surface_image.pitches[0];
332         }
333 
334         /* UV plane */
335         if (surface_image.format.fourcc == VA_FOURCC_I010) {
336             assert(g_src_file_fourcc == VA_FOURCC_I010);
337 
338             u_src = newImageBuffer + surface_image.width * surface_image.height * 2;
339             v_src = newImageBuffer + surface_image.width * surface_image.height * 5 / 2;
340 
341             u_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
342             v_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]);
343 
344             for (row = 0; row < surface_image.height / 2; row++) {
345                 memcpy(u_dst, u_src, surface_image.width);
346                 memcpy(v_dst, v_src, surface_image.width);
347 
348                 u_src += surface_image.width;
349                 v_src += surface_image.width;
350 
351                 u_dst += surface_image.pitches[1];
352                 v_dst += surface_image.pitches[2];
353             }
354         } else if (surface_image.format.fourcc == VA_FOURCC_P010) {
355             assert(g_src_file_fourcc == VA_FOURCC_P010);
356 
357             u_src = newImageBuffer + surface_image.width * surface_image.height * 2;
358             v_src = u_src;
359 
360             u_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
361             v_dst = u_dst;
362 
363             for (row = 0; row < surface_image.height / 2; row++) {
364                 memcpy(u_dst, u_src, surface_image.width * 2);
365 
366                 u_src += surface_image.width * 2;
367                 v_src = u_src;
368 
369                 u_dst += surface_image.pitches[1];
370                 v_dst = u_dst;
371             }
372         }
373     }  else if ((surface_image.format.fourcc == VA_FOURCC_RGBA &&
374                  g_src_file_fourcc == VA_FOURCC_RGBA) ||
375                 (surface_image.format.fourcc == VA_FOURCC_RGBX &&
376                  g_src_file_fourcc == VA_FOURCC_RGBX) ||
377                 (surface_image.format.fourcc == VA_FOURCC_BGRA &&
378                  g_src_file_fourcc == VA_FOURCC_BGRA) ||
379                 (surface_image.format.fourcc == VA_FOURCC_BGRX &&
380                  g_src_file_fourcc == VA_FOURCC_BGRX)) {
381         frame_size = surface_image.width * surface_image.height * 4;
382         newImageBuffer = (unsigned char*)malloc(frame_size);
383         assert(newImageBuffer);
384 
385         do {
386             n_items = fread(newImageBuffer, frame_size, 1, fp);
387         } while (n_items != 1);
388 
389         y_src = newImageBuffer;
390         y_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]);
391 
392         /* plane 0, directly copy */
393         for (row = 0; row < surface_image.height; row++) {
394             memcpy(y_dst, y_src, surface_image.width * 4);
395             y_src += surface_image.width * 4;
396             y_dst += surface_image.pitches[0];
397         }
398     } else {
399         printf("Not supported YUV surface fourcc !!! \n");
400         return VA_STATUS_ERROR_INVALID_SURFACE;
401     }
402 
403     if (newImageBuffer) {
404         free(newImageBuffer);
405         newImageBuffer = NULL;
406     }
407 
408     vaUnmapBuffer(va_dpy, surface_image.buf);
409     vaDestroyImage(va_dpy, surface_image.image_id);
410 
411     return VA_STATUS_SUCCESS;
412 }
413 
414 /* Store NV12/YV12/I420 surface to yv12 file */
415 static VAStatus
store_yuv_surface_to_yv12_file(FILE * fp,VASurfaceID surface_id)416 store_yuv_surface_to_yv12_file(FILE *fp,
417                                VASurfaceID surface_id)
418 {
419     VAStatus va_status;
420     VAImage surface_image;
421     void *surface_p = NULL;
422     unsigned char *y_src = NULL;
423     unsigned char *u_src = NULL;
424     unsigned char *v_src = NULL;
425     unsigned char *y_dst = NULL;
426     unsigned char *u_dst = NULL;
427     unsigned char *v_dst = NULL;
428     uint32_t row, col;
429     int32_t n_items;
430     unsigned char * newImageBuffer = NULL;
431     va_status = vaSyncSurface(va_dpy, surface_id);
432     CHECK_VASTATUS(va_status, "vaSyncSurface");
433 
434     va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
435     CHECK_VASTATUS(va_status, "vaDeriveImage");
436 
437     va_status = vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
438     CHECK_VASTATUS(va_status, "vaMapBuffer");
439 
440     /* store the surface to one YV12 file or one bmp file*/
441     if (surface_image.format.fourcc == VA_FOURCC_YV12 ||
442         surface_image.format.fourcc == VA_FOURCC_I420 ||
443         surface_image.format.fourcc == VA_FOURCC_NV12) {
444 
445         uint32_t y_size = surface_image.width * surface_image.height;
446         uint32_t u_size = y_size / 4;
447 
448         newImageBuffer = (unsigned char*)malloc(y_size * 3 / 2);
449         assert(newImageBuffer);
450 
451         /* stored as YV12 format */
452         y_dst = newImageBuffer;
453         v_dst = newImageBuffer + y_size;
454         u_dst = newImageBuffer + y_size + u_size;
455 
456         y_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]);
457         if (surface_image.format.fourcc == VA_FOURCC_YV12) {
458             v_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
459             u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]);
460         } else if (surface_image.format.fourcc == VA_FOURCC_I420) {
461             u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
462             v_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]);
463         } else if (surface_image.format.fourcc == VA_FOURCC_NV12) {
464             u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
465             v_src = u_src;
466         }
467 
468         /* Y plane copy */
469         for (row = 0; row < surface_image.height; row++) {
470             memcpy(y_dst, y_src, surface_image.width);
471             y_src += surface_image.pitches[0];
472             y_dst += surface_image.width;
473         }
474 
475         /* UV plane copy */
476         if (surface_image.format.fourcc == VA_FOURCC_YV12 ||
477             surface_image.format.fourcc == VA_FOURCC_I420) {
478             for (row = 0; row < surface_image.height / 2; row ++) {
479                 memcpy(v_dst, v_src, surface_image.width / 2);
480                 memcpy(u_dst, u_src, surface_image.width / 2);
481 
482                 v_dst += surface_image.width / 2;
483                 u_dst += surface_image.width / 2;
484 
485                 if (surface_image.format.fourcc == VA_FOURCC_YV12) {
486                     v_src += surface_image.pitches[1];
487                     u_src += surface_image.pitches[2];
488                 } else {
489                     v_src += surface_image.pitches[2];
490                     u_src += surface_image.pitches[1];
491                 }
492             }
493         } else if (surface_image.format.fourcc == VA_FOURCC_NV12) {
494             for (row = 0; row < surface_image.height / 2; row++) {
495                 for (col = 0; col < surface_image.width / 2; col++) {
496                     u_dst[col] = u_src[col * 2];
497                     v_dst[col] = u_src[col * 2 + 1];
498                 }
499 
500                 u_src += surface_image.pitches[1];
501                 u_dst += (surface_image.width / 2);
502                 v_dst += (surface_image.width / 2);
503             }
504         }
505 
506         /* write frame to file */
507         do {
508             n_items = fwrite(newImageBuffer, y_size * 3 / 2, 1, fp);
509         } while (n_items != 1);
510 
511     } else {
512         printf("Not supported YUV surface fourcc !!! \n");
513         return VA_STATUS_ERROR_INVALID_SURFACE;
514     }
515 
516     if (newImageBuffer) {
517         free(newImageBuffer);
518         newImageBuffer = NULL;
519     }
520 
521     vaUnmapBuffer(va_dpy, surface_image.buf);
522     vaDestroyImage(va_dpy, surface_image.image_id);
523 
524     return VA_STATUS_SUCCESS;
525 }
526 
527 static VAStatus
store_yuv_surface_to_i420_file(FILE * fp,VASurfaceID surface_id)528 store_yuv_surface_to_i420_file(FILE *fp,
529                                VASurfaceID surface_id)
530 {
531     VAStatus va_status;
532     VAImage surface_image;
533     void *surface_p = NULL;
534     unsigned char *y_src = NULL;
535     unsigned char *u_src = NULL;
536     unsigned char *v_src = NULL;
537     unsigned char *y_dst = NULL;
538     unsigned char *u_dst = NULL;
539     unsigned char *v_dst = NULL;
540     uint32_t row, col;
541     int32_t n_items;
542     unsigned char * newImageBuffer = NULL;
543     va_status = vaSyncSurface(va_dpy, surface_id);
544     CHECK_VASTATUS(va_status, "vaSyncSurface");
545 
546     va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
547     CHECK_VASTATUS(va_status, "vaDeriveImage");
548 
549     va_status = vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
550     CHECK_VASTATUS(va_status, "vaMapBuffer");
551 
552     /* store the surface to one i420 file */
553     if (surface_image.format.fourcc == VA_FOURCC_YV12 ||
554         surface_image.format.fourcc == VA_FOURCC_I420 ||
555         surface_image.format.fourcc == VA_FOURCC_NV12) {
556 
557         uint32_t y_size = surface_image.width * surface_image.height;
558         uint32_t u_size = y_size / 4;
559 
560         newImageBuffer = (unsigned char*)malloc(y_size * 3 / 2);
561         assert(newImageBuffer);
562 
563         /* stored as YV12 format */
564         y_dst = newImageBuffer;
565         u_dst = newImageBuffer + y_size;
566         v_dst = newImageBuffer + y_size + u_size;
567 
568         y_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]);
569         if (surface_image.format.fourcc == VA_FOURCC_YV12) {
570             v_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
571             u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]);
572         } else if (surface_image.format.fourcc == VA_FOURCC_I420) {
573             u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
574             v_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]);
575         } else if (surface_image.format.fourcc == VA_FOURCC_NV12) {
576             u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
577             v_src = u_src;
578         }
579 
580         /* Y plane copy */
581         for (row = 0; row < surface_image.height; row++) {
582             memcpy(y_dst, y_src, surface_image.width);
583             y_src += surface_image.pitches[0];
584             y_dst += surface_image.width;
585         }
586 
587         /* UV plane copy */
588         if (surface_image.format.fourcc == VA_FOURCC_YV12 ||
589             surface_image.format.fourcc == VA_FOURCC_I420) {
590             for (row = 0; row < surface_image.height / 2; row ++) {
591                 memcpy(v_dst, v_src, surface_image.width / 2);
592                 memcpy(u_dst, u_src, surface_image.width / 2);
593 
594                 v_dst += surface_image.width / 2;
595                 u_dst += surface_image.width / 2;
596 
597                 if (surface_image.format.fourcc == VA_FOURCC_YV12) {
598                     v_src += surface_image.pitches[1];
599                     u_src += surface_image.pitches[2];
600                 } else {
601                     v_src += surface_image.pitches[2];
602                     u_src += surface_image.pitches[1];
603                 }
604             }
605         } else if (surface_image.format.fourcc == VA_FOURCC_NV12) {
606             for (row = 0; row < surface_image.height / 2; row++) {
607                 for (col = 0; col < surface_image.width / 2; col++) {
608                     u_dst[col] = u_src[col * 2];
609                     v_dst[col] = u_src[col * 2 + 1];
610                 }
611 
612                 u_src += surface_image.pitches[1];
613                 u_dst += (surface_image.width / 2);
614                 v_dst += (surface_image.width / 2);
615             }
616         }
617 
618         /* write frame to file */
619         do {
620             n_items = fwrite(newImageBuffer, y_size * 3 / 2, 1, fp);
621         } while (n_items != 1);
622 
623     } else {
624         printf("Not supported YUV surface fourcc !!! \n");
625         return VA_STATUS_ERROR_INVALID_SURFACE;
626     }
627 
628     if (newImageBuffer) {
629         free(newImageBuffer);
630         newImageBuffer = NULL;
631     }
632 
633     vaUnmapBuffer(va_dpy, surface_image.buf);
634     vaDestroyImage(va_dpy, surface_image.image_id);
635 
636     return VA_STATUS_SUCCESS;
637 }
638 
639 static VAStatus
store_yuv_surface_to_nv12_file(FILE * fp,VASurfaceID surface_id)640 store_yuv_surface_to_nv12_file(FILE *fp,
641                                VASurfaceID surface_id)
642 {
643     VAStatus va_status;
644     VAImage surface_image;
645     void *surface_p = NULL;
646     unsigned char *y_src = NULL;
647     unsigned char *u_src = NULL;
648     unsigned char *v_src = NULL;
649     unsigned char *y_dst = NULL;
650     unsigned char *u_dst = NULL;
651     unsigned char *v_dst = NULL;
652     uint32_t row, col;
653     int32_t n_items;
654     unsigned char * newImageBuffer = NULL;
655     va_status = vaSyncSurface(va_dpy, surface_id);
656     CHECK_VASTATUS(va_status, "vaSyncSurface");
657 
658     va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
659     CHECK_VASTATUS(va_status, "vaDeriveImage");
660 
661     va_status = vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
662     CHECK_VASTATUS(va_status, "vaMapBuffer");
663 
664     /* store the surface to one nv12 file */
665     if (surface_image.format.fourcc == VA_FOURCC_YV12 ||
666         surface_image.format.fourcc == VA_FOURCC_I420 ||
667         surface_image.format.fourcc == VA_FOURCC_NV12) {
668 
669         uint32_t y_size = surface_image.width * surface_image.height;
670 
671         newImageBuffer = (unsigned char*)malloc(y_size * 3 / 2);
672         assert(newImageBuffer);
673 
674         /* stored as YV12 format */
675         y_dst = newImageBuffer;
676         u_dst = v_dst = newImageBuffer + y_size;
677 
678         y_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]);
679 
680         if (surface_image.format.fourcc == VA_FOURCC_YV12) {
681             v_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
682             u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]);
683         } else if (surface_image.format.fourcc == VA_FOURCC_I420) {
684             u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
685             v_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]);
686         } else if (surface_image.format.fourcc == VA_FOURCC_NV12) {
687             u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
688             v_src = u_src;
689         }
690 
691         /* Y plane copy */
692         for (row = 0; row < surface_image.height; row++) {
693             memcpy(y_dst, y_src, surface_image.width);
694             y_src += surface_image.pitches[0];
695             y_dst += surface_image.width;
696         }
697 
698         /* UV plane copy */
699         if (surface_image.format.fourcc == VA_FOURCC_YV12 ||
700             surface_image.format.fourcc == VA_FOURCC_I420) {
701             for (row = 0; row < surface_image.height / 2; row ++) {
702                 for (col = 0; col < surface_image.width / 2; col++) {
703                     u_dst[col * 2] = u_src[col];
704                     u_dst[col * 2 + 1] = v_src[col];
705                 }
706 
707                 u_dst += surface_image.width;
708 
709                 if (surface_image.format.fourcc == VA_FOURCC_YV12) {
710                     v_src += surface_image.pitches[1];
711                     u_src += surface_image.pitches[2];
712                 } else {
713                     v_src += surface_image.pitches[2];
714                     u_src += surface_image.pitches[1];
715                 }
716             }
717         } else if (surface_image.format.fourcc == VA_FOURCC_NV12) {
718             for (row = 0; row < surface_image.height / 2; row++) {
719                 memcpy(u_dst, u_src, surface_image.width);
720                 u_dst += surface_image.width;
721                 u_src += surface_image.pitches[1];
722             }
723         }
724 
725         /* write frame to file */
726         do {
727             n_items = fwrite(newImageBuffer, y_size * 3 / 2, 1, fp);
728         } while (n_items != 1);
729 
730     } else {
731         printf("Not supported YUV surface fourcc !!! \n");
732         return VA_STATUS_ERROR_INVALID_SURFACE;
733     }
734 
735     if (newImageBuffer) {
736         free(newImageBuffer);
737         newImageBuffer = NULL;
738     }
739 
740     vaUnmapBuffer(va_dpy, surface_image.buf);
741     vaDestroyImage(va_dpy, surface_image.image_id);
742 
743     return VA_STATUS_SUCCESS;
744 }
745 
746 static VAStatus
store_packed_yuv_surface_to_packed_file(FILE * fp,VASurfaceID surface_id)747 store_packed_yuv_surface_to_packed_file(FILE *fp,
748                                         VASurfaceID surface_id)
749 {
750     VAStatus va_status;
751     VAImage surface_image;
752     void *surface_p = NULL;
753     unsigned char *y_src = NULL;
754     unsigned char *y_dst = NULL;
755     uint32_t row;
756     int32_t n_items;
757     unsigned char * newImageBuffer = NULL;
758     va_status = vaSyncSurface(va_dpy, surface_id);
759     CHECK_VASTATUS(va_status, "vaSyncSurface");
760 
761     va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
762     CHECK_VASTATUS(va_status, "vaDeriveImage");
763 
764     va_status = vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
765     CHECK_VASTATUS(va_status, "vaMapBuffer");
766 
767     /* store the surface to one YUY2 or UYVY file */
768     if (surface_image.format.fourcc == VA_FOURCC_YUY2 ||
769         surface_image.format.fourcc == VA_FOURCC_UYVY) {
770         uint32_t frame_size = surface_image.width * surface_image.height * 2;
771 
772         newImageBuffer = (unsigned char*)malloc(frame_size);
773         assert(newImageBuffer);
774         memset(newImageBuffer, 0, frame_size);
775 
776         /* stored as YUY2 or UYVY format */
777         y_dst = newImageBuffer;
778 
779         y_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]);
780 
781         /* Plane 0 copy */
782         for (row = 0; row < surface_image.height; row++) {
783             memcpy(y_dst, y_src, surface_image.width * 2);
784             y_src += surface_image.pitches[0];
785             y_dst += surface_image.width * 2;
786         }
787 
788         /* write frame to file */
789         do {
790             n_items = fwrite(newImageBuffer, frame_size, 1, fp);
791         } while (n_items != 1);
792 
793     } else {
794         printf("Not supported YUV surface fourcc !!! \n");
795         return VA_STATUS_ERROR_INVALID_SURFACE;
796     }
797 
798     if (newImageBuffer) {
799         free(newImageBuffer);
800         newImageBuffer = NULL;
801     }
802 
803     vaUnmapBuffer(va_dpy, surface_image.buf);
804     vaDestroyImage(va_dpy, surface_image.image_id);
805 
806     return VA_STATUS_SUCCESS;
807 }
808 
809 static VAStatus
store_yuv_surface_to_10bit_file(FILE * fp,VASurfaceID surface_id)810 store_yuv_surface_to_10bit_file(FILE *fp, VASurfaceID surface_id)
811 {
812     VAStatus va_status;
813     VAImage surface_image;
814     void *surface_p = NULL;
815     unsigned char *y_src = NULL;
816     unsigned char *u_src = NULL;
817     unsigned char *v_src = NULL;
818     unsigned char *y_dst = NULL;
819     unsigned char *u_dst = NULL;
820     unsigned char *v_dst = NULL;
821     uint32_t row;
822     int32_t n_items;
823     unsigned char * newImageBuffer = NULL;
824     va_status = vaSyncSurface(va_dpy, surface_id);
825     CHECK_VASTATUS(va_status, "vaSyncSurface");
826 
827     va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
828     CHECK_VASTATUS(va_status, "vaDeriveImage");
829 
830     va_status = vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
831     CHECK_VASTATUS(va_status, "vaMapBuffer");
832 
833     /* store the surface to one 10bit file */
834     uint32_t y_size = surface_image.width * surface_image.height * 2;
835     uint32_t u_size = y_size / 4;
836 
837     newImageBuffer = (unsigned char*)malloc(y_size * 3);
838     assert(newImageBuffer);
839     y_dst = newImageBuffer;
840 
841     y_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]);
842 
843     /* Y plane copy */
844     for (row = 0; row < surface_image.height; row++) {
845         memcpy(y_dst, y_src, surface_image.width * 2);
846         y_src += surface_image.pitches[0];
847         y_dst += surface_image.width * 2;
848     }
849 
850     if (surface_image.format.fourcc == VA_FOURCC_I010) {
851         u_dst = newImageBuffer + y_size;
852         v_dst = newImageBuffer + y_size + u_size;
853 
854         u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
855         v_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]);
856 
857         for (row = 0; row < surface_image.height / 2; row++) {
858             memcpy(u_dst, u_src, surface_image.width);
859             memcpy(v_dst, v_src, surface_image.width);
860 
861             u_dst += surface_image.width;
862             v_dst += surface_image.width;
863 
864             u_src += surface_image.pitches[1];
865             v_src += surface_image.pitches[2];
866         }
867     } else if (surface_image.format.fourcc == VA_FOURCC_P010) {
868         u_dst = newImageBuffer + y_size;
869         v_dst = u_dst;
870 
871         u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
872         v_src = u_src;
873 
874         for (row = 0; row < surface_image.height / 2; row++) {
875             memcpy(u_dst, u_src, surface_image.width * 2);
876             u_dst += surface_image.width * 2;
877             u_src += surface_image.pitches[1];
878         }
879     } else {
880         printf("Not supported YUV surface fourcc !!! \n");
881         free(newImageBuffer);
882         return VA_STATUS_ERROR_INVALID_SURFACE;
883     }
884 
885     /* write frame to file */
886     do {
887         n_items = fwrite(newImageBuffer, y_size * 3 / 2, 1, fp);
888     } while (n_items != 1);
889 
890     if (newImageBuffer) {
891         free(newImageBuffer);
892         newImageBuffer = NULL;
893     }
894 
895     vaUnmapBuffer(va_dpy, surface_image.buf);
896     vaDestroyImage(va_dpy, surface_image.image_id);
897 
898     return VA_STATUS_SUCCESS;
899 }
900 
901 static VAStatus
store_rgb_surface_to_rgb_file(FILE * fp,VASurfaceID surface_id)902 store_rgb_surface_to_rgb_file(FILE *fp, VASurfaceID surface_id)
903 {
904     VAStatus va_status;
905     VAImage surface_image;
906     void *surface_p = NULL;
907     unsigned char *y_src = NULL;
908     unsigned char *y_dst = NULL;
909     uint32_t frame_size, row;
910     int32_t n_items;
911     unsigned char * newImageBuffer = NULL;
912     va_status = vaSyncSurface(va_dpy, surface_id);
913     CHECK_VASTATUS(va_status, "vaSyncSurface");
914 
915     va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
916     CHECK_VASTATUS(va_status, "vaDeriveImage");
917 
918     va_status = vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
919     CHECK_VASTATUS(va_status, "vaMapBuffer");
920 
921     frame_size = surface_image.width * surface_image.height * 4;
922     newImageBuffer = (unsigned char*)malloc(frame_size);
923     assert(newImageBuffer);
924     y_dst = newImageBuffer;
925 
926     y_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]);
927 
928     for (row = 0; row < surface_image.height; row++) {
929         memcpy(y_dst, y_src, surface_image.width * 4);
930         y_src += surface_image.pitches[0];
931         y_dst += surface_image.width * 4;
932     }
933 
934     /* write frame to file */
935     do {
936         n_items = fwrite(newImageBuffer, frame_size, 1, fp);
937     } while (n_items != 1);
938 
939     if (newImageBuffer) {
940         free(newImageBuffer);
941         newImageBuffer = NULL;
942     }
943 
944     vaUnmapBuffer(va_dpy, surface_image.buf);
945     vaDestroyImage(va_dpy, surface_image.image_id);
946 
947     return VA_STATUS_SUCCESS;
948 }
949 
950 static VAStatus
store_yuv_surface_to_file(FILE * fp,VASurfaceID surface_id)951 store_yuv_surface_to_file(FILE *fp,
952                           VASurfaceID surface_id)
953 {
954     if (g_out_fourcc == VA_FOURCC_YV12 ||
955         g_out_fourcc == VA_FOURCC_I420 ||
956         g_out_fourcc == VA_FOURCC_NV12) {
957         if (g_dst_file_fourcc == VA_FOURCC_YV12)
958             return store_yuv_surface_to_yv12_file(fp, surface_id);
959         else if (g_dst_file_fourcc == VA_FOURCC_I420)
960             return store_yuv_surface_to_i420_file(fp, surface_id);
961         else if (g_dst_file_fourcc == VA_FOURCC_NV12)
962             return store_yuv_surface_to_nv12_file(fp, surface_id);
963         else {
964             printf("Not supported YUV fourcc for output !!!\n");
965             return VA_STATUS_ERROR_INVALID_SURFACE;
966         }
967     } else if ((g_out_fourcc == VA_FOURCC_YUY2 &&
968                 g_dst_file_fourcc == VA_FOURCC_YUY2) ||
969                (g_out_fourcc == VA_FOURCC_UYVY &&
970                 g_dst_file_fourcc == VA_FOURCC_UYVY)) {
971         return store_packed_yuv_surface_to_packed_file(fp, surface_id);
972     } else if ((g_out_fourcc == VA_FOURCC_I010 &&
973                 g_dst_file_fourcc == VA_FOURCC_I010) ||
974                (g_out_fourcc == VA_FOURCC_P010 &&
975                 g_dst_file_fourcc == VA_FOURCC_P010)) {
976         return store_yuv_surface_to_10bit_file(fp, surface_id);
977     } else if ((g_out_fourcc == VA_FOURCC_RGBA &&
978                 g_dst_file_fourcc == VA_FOURCC_RGBA) ||
979                (g_out_fourcc == VA_FOURCC_RGBX &&
980                 g_dst_file_fourcc == VA_FOURCC_RGBX) ||
981                (g_out_fourcc == VA_FOURCC_RGBA &&
982                 g_dst_file_fourcc == VA_FOURCC_BGRA) ||
983                (g_out_fourcc == VA_FOURCC_BGRX &&
984                 g_dst_file_fourcc == VA_FOURCC_BGRX)) {
985         return store_rgb_surface_to_rgb_file(fp, surface_id);
986     } else {
987         printf("Not supported YUV fourcc for output !!!\n");
988         return VA_STATUS_ERROR_INVALID_SURFACE;
989     }
990 }
991 
992 static VAStatus
upload_data_to_3dlut(FILE * fp,VASurfaceID & surface_id)993 upload_data_to_3dlut(FILE *fp,
994                      VASurfaceID &surface_id)
995 {
996     VAStatus va_status;
997     VAImage surface_image;
998     void *surface_p = NULL;
999     uint32_t frame_size, lut3d_size;
1000     unsigned char * newImageBuffer = NULL;
1001     va_status = vaSyncSurface(va_dpy, surface_id);
1002     CHECK_VASTATUS(va_status, "vaSyncSurface");
1003 
1004     va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
1005     CHECK_VASTATUS(va_status, "vaDeriveImage");
1006 
1007     va_status = vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
1008     CHECK_VASTATUS(va_status, "vaMapBuffer");
1009 
1010     if (surface_image.format.fourcc == VA_FOURCC_RGBA  && fp) {
1011         /* 3DLUT surface is allocated to 32 bit RGB */
1012         frame_size = surface_image.width * surface_image.height * 4;
1013         newImageBuffer = (unsigned char*)malloc(frame_size);
1014         assert(newImageBuffer);
1015 
1016         fseek(fp, 0L, SEEK_END);
1017         lut3d_size = ftell(fp);
1018         rewind(fp);
1019 
1020         uint32_t real_size = (frame_size > lut3d_size) ? lut3d_size : frame_size;
1021 
1022         if (fread(newImageBuffer, real_size, 1, fp) != 0) {
1023             memcpy(surface_p, newImageBuffer, real_size);
1024             printf("upload_data_to_3dlut: 3DLUT surface width %d, height %d, pitch %d, frame size %d, 3dlut file size: %d\n", surface_image.width, surface_image.height, surface_image.pitches[0], frame_size, lut3d_size);
1025         }
1026     }
1027 
1028     if (newImageBuffer)  {
1029         free(newImageBuffer);
1030         newImageBuffer = NULL;
1031     }
1032 
1033     vaUnmapBuffer(va_dpy, surface_image.buf);
1034     vaDestroyImage(va_dpy, surface_image.image_id);
1035 
1036     return VA_STATUS_SUCCESS;
1037 }
1038 
1039 static VAStatus
create_surface(VASurfaceID * p_surface_id,uint32_t width,uint32_t height,uint32_t fourCC,uint32_t format)1040 create_surface(VASurfaceID * p_surface_id,
1041                uint32_t width, uint32_t height,
1042                uint32_t fourCC, uint32_t format)
1043 {
1044     VAStatus va_status;
1045     VASurfaceAttrib    surface_attrib;
1046     surface_attrib.type =  VASurfaceAttribPixelFormat;
1047     surface_attrib.flags = VA_SURFACE_ATTRIB_SETTABLE;
1048     surface_attrib.value.type = VAGenericValueTypeInteger;
1049     surface_attrib.value.value.i = fourCC;
1050 
1051     va_status = vaCreateSurfaces(va_dpy,
1052                                  format,
1053                                  width,
1054                                  height,
1055                                  p_surface_id,
1056                                  1,
1057                                  &surface_attrib,
1058                                  1);
1059     return va_status;
1060 }
1061 
1062 static VAStatus
lut3D_filter_init(VABufferID & filter_param_buf_id)1063 lut3D_filter_init(VABufferID &filter_param_buf_id)
1064 {
1065     VAStatus va_status;
1066     VAProcFilterParameterBuffer3DLUT lut3d_param;
1067     VABufferID lut3d_param_buf_id;
1068     uint32_t num_caps = 10;
1069     bool bSupported = false;
1070 
1071     VAProcFilterCap3DLUT caps[num_caps];
1072     memset(&caps, 0, sizeof(VAProcFilterCap3DLUT)*num_caps);
1073     va_status = vaQueryVideoProcFilterCaps(va_dpy, context_id,
1074                                            VAProcFilter3DLUT,
1075                                            (void *)caps, &num_caps);
1076     CHECK_VASTATUS(va_status, "vaQueryVideoProcFilterCaps");
1077     printf("vaQueryVideoProcFilterCaps num_caps %d\n", num_caps);
1078 
1079     /* check if the input parameters are supported */
1080     for (uint32_t index = 0; index < num_caps; index++) {
1081         // check lut_size and lut_stride
1082         if ((caps[index].lut_size = g_3dlut_seg_size) &&
1083             (caps[index].lut_stride[0] == g_3dlut_seg_size) &&
1084             (caps[index].lut_stride[1] == g_3dlut_seg_size) &&
1085             (caps[index].lut_stride[2] == g_3dlut_mul_size)) {
1086             bSupported = true;
1087         }
1088     }
1089 
1090     if (bSupported) {
1091         lut3d_param.type  = VAProcFilter3DLUT;
1092         lut3d_param.lut_surface   = g_3dlut_surface_id;
1093         lut3d_param.lut_size      = g_3dlut_seg_size;
1094         lut3d_param.lut_stride[0] = g_3dlut_seg_size;
1095         lut3d_param.lut_stride[1] = g_3dlut_seg_size;
1096         lut3d_param.lut_stride[2] = g_3dlut_mul_size;
1097         lut3d_param.bit_depth     = 16;
1098         lut3d_param.num_channel   = 4;
1099         lut3d_param.channel_mapping = g_3dlut_channel_mapping;
1100 
1101         /* create 3dlut fitler buffer */
1102         va_status = vaCreateBuffer(va_dpy, context_id,
1103                                    VAProcFilterParameterBufferType, sizeof(lut3d_param), 1,
1104                                    &lut3d_param, &lut3d_param_buf_id);
1105 
1106         filter_param_buf_id = lut3d_param_buf_id;
1107     }
1108 
1109     return va_status;
1110 }
1111 
1112 static VAStatus
video_frame_process_3dlut(VASurfaceID in_surface_id,VASurfaceID out_surface_id)1113 video_frame_process_3dlut(VASurfaceID in_surface_id,
1114                           VASurfaceID out_surface_id)
1115 {
1116     VAStatus va_status;
1117     VAProcPipelineParameterBuffer pipeline_param;
1118     VARectangle surface_region, output_region;
1119     VABufferID pipeline_param_buf_id = VA_INVALID_ID;
1120     VABufferID filter_param_buf_id = VA_INVALID_ID;
1121 
1122     /*Create 3DLUT Filter*/
1123     lut3D_filter_init(filter_param_buf_id);
1124 
1125     /* Fill pipeline buffer */
1126     surface_region.x = 0;
1127     surface_region.y = 0;
1128     surface_region.width = g_in_pic_width;
1129     surface_region.height = g_in_pic_height;
1130     output_region.x = 0;
1131     output_region.y = 0;
1132     output_region.width = g_out_pic_width;
1133     output_region.height = g_out_pic_height;
1134 
1135     memset(&pipeline_param, 0, sizeof(pipeline_param));
1136     pipeline_param.surface = in_surface_id;
1137     pipeline_param.surface_region = &surface_region;
1138     pipeline_param.output_region = &output_region;
1139     pipeline_param.filter_flags = 0;
1140     pipeline_param.filters = &filter_param_buf_id;
1141     pipeline_param.num_filters  = 1;
1142     /* input is bt2020 */
1143     pipeline_param.surface_color_standard = VAProcColorStandardBT2020;
1144     pipeline_param.output_color_standard = VAProcColorStandardBT709;
1145 
1146     va_status = vaCreateBuffer(va_dpy,
1147                                context_id,
1148                                VAProcPipelineParameterBufferType,
1149                                sizeof(pipeline_param),
1150                                1,
1151                                &pipeline_param,
1152                                &pipeline_param_buf_id);
1153     CHECK_VASTATUS(va_status, "vaCreateBuffer");
1154 
1155     va_status = vaBeginPicture(va_dpy,
1156                                context_id,
1157                                out_surface_id);
1158     CHECK_VASTATUS(va_status, "vaBeginPicture");
1159 
1160     va_status = vaRenderPicture(va_dpy,
1161                                 context_id,
1162                                 &pipeline_param_buf_id,
1163                                 1);
1164     CHECK_VASTATUS(va_status, "vaRenderPicture");
1165 
1166     va_status = vaEndPicture(va_dpy, context_id);
1167     CHECK_VASTATUS(va_status, "vaEndPicture");
1168 
1169     if (pipeline_param_buf_id != VA_INVALID_ID) {
1170         vaDestroyBuffer(va_dpy, pipeline_param_buf_id);
1171     }
1172 
1173     if (filter_param_buf_id != VA_INVALID_ID) {
1174         vaDestroyBuffer(va_dpy, filter_param_buf_id);
1175     }
1176 
1177     return va_status;
1178 }
1179 
1180 static VAStatus
video_frame_process_scaling(VASurfaceID in_surface_id,VASurfaceID out_surface_id)1181 video_frame_process_scaling(VASurfaceID in_surface_id,
1182                             VASurfaceID out_surface_id)
1183 {
1184     VAStatus va_status;
1185     VAProcPipelineParameterBuffer pipeline_param;
1186     VARectangle surface_region, output_region;
1187     VABufferID pipeline_param_buf_id = VA_INVALID_ID;
1188 
1189     /* Fill pipeline buffer */
1190     surface_region.x = 0;
1191     surface_region.y = 0;
1192     surface_region.width = g_in_pic_width;
1193     surface_region.height = g_in_pic_height;
1194     output_region.x = 0;
1195     output_region.y = 0;
1196     output_region.width = g_out_pic_width;
1197     output_region.height = g_out_pic_height;
1198 
1199     memset(&pipeline_param, 0, sizeof(pipeline_param));
1200     pipeline_param.surface = in_surface_id;
1201     pipeline_param.surface_region = &surface_region;
1202     pipeline_param.output_region = &output_region;
1203     /* Default is going to SFC */
1204     // pipeline_param.filter_flags = 0;
1205     // pipeline_param.filters = &filter_param_buf_id;
1206     pipeline_param.num_filters  = 0;
1207     /* input is bt2020 */
1208     // pipeline_param.surface_color_standard = VAProcColorStandardBT2020;
1209     // pipeline_param.output_color_standard = VAProcColorStandardBT709;
1210 
1211     va_status = vaCreateBuffer(va_dpy,
1212                                context_id,
1213                                VAProcPipelineParameterBufferType,
1214                                sizeof(pipeline_param),
1215                                1,
1216                                &pipeline_param,
1217                                &pipeline_param_buf_id);
1218     CHECK_VASTATUS(va_status, "vaCreateBuffer");
1219 
1220     va_status = vaBeginPicture(va_dpy,
1221                                context_id,
1222                                out_surface_id);
1223     CHECK_VASTATUS(va_status, "vaBeginPicture");
1224 
1225     va_status = vaRenderPicture(va_dpy,
1226                                 context_id,
1227                                 &pipeline_param_buf_id,
1228                                 1);
1229     CHECK_VASTATUS(va_status, "vaRenderPicture");
1230 
1231     va_status = vaEndPicture(va_dpy, context_id);
1232     CHECK_VASTATUS(va_status, "vaEndPicture");
1233 
1234     if (pipeline_param_buf_id != VA_INVALID_ID) {
1235         vaDestroyBuffer(va_dpy, pipeline_param_buf_id);
1236     }
1237 
1238     return va_status;
1239 }
1240 
1241 static VAStatus
vpp_context_create()1242 vpp_context_create()
1243 {
1244     VAStatus va_status = VA_STATUS_SUCCESS;
1245     int32_t j;
1246 
1247     /* VA driver initialization */
1248     va_dpy = va_open_display();
1249     int32_t major_ver, minor_ver;
1250     va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
1251     assert(va_status == VA_STATUS_SUCCESS);
1252 
1253     /* Check whether VPP is supported by driver */
1254     VAEntrypoint entrypoints[5];
1255     int32_t num_entrypoints;
1256     num_entrypoints = vaMaxNumEntrypoints(va_dpy);
1257     va_status = vaQueryConfigEntrypoints(va_dpy,
1258                                          VAProfileNone,
1259                                          entrypoints,
1260                                          &num_entrypoints);
1261     CHECK_VASTATUS(va_status, "vaQueryConfigEntrypoints");
1262 
1263     for (j = 0; j < num_entrypoints; j++) {
1264         if (entrypoints[j] == VAEntrypointVideoProc)
1265             break;
1266     }
1267 
1268     if (j == num_entrypoints) {
1269         printf("VPP is not supported by driver\n");
1270         assert(0);
1271     }
1272 
1273     /* Render target surface format check */
1274     VAConfigAttrib attrib;
1275     attrib.type = VAConfigAttribRTFormat;
1276     va_status = vaGetConfigAttributes(va_dpy,
1277                                       VAProfileNone,
1278                                       VAEntrypointVideoProc,
1279                                       &attrib,
1280                                       1);
1281     CHECK_VASTATUS(va_status, "vaGetConfigAttributes");
1282     if (!(attrib.value & g_out_format)) {
1283         printf("RT format %d is not supported by VPP !\n", g_out_format);
1284         assert(0);
1285     }
1286 
1287     /* Create surface/config/context for VPP pipeline */
1288     va_status = create_surface(&g_in_surface_id, g_in_pic_width, g_in_pic_height,
1289                                g_in_fourcc, g_in_format);
1290     CHECK_VASTATUS(va_status, "vaCreateSurfaces for input");
1291 
1292     if (g_pipeline_sequence == VA_SCALING_3DLUT) {
1293         /* Create intermediate surface for scaling + 3DLUT */
1294         va_status = create_surface(&g_inter_surface_id, g_out_pic_width, g_out_pic_height,
1295                                    g_in_fourcc, g_in_format);
1296         CHECK_VASTATUS(va_status, "vaCreateSurfaces for input");
1297     }
1298 
1299     va_status = create_surface(&g_out_surface_id, g_out_pic_width, g_out_pic_height,
1300                                g_out_fourcc, g_out_format);
1301     CHECK_VASTATUS(va_status, "vaCreateSurfaces for output");
1302 
1303     if (g_pipeline_sequence != VA_SCALING_ONLY) {
1304         uint32_t lut3d_size = g_3dlut_seg_size * g_3dlut_seg_size * g_3dlut_mul_size * (16 / 8) * 4;
1305         printf("3dlut file name: %s, 3dlut size: %d\n", g_3dlut_file_name, lut3d_size);
1306         /* create 3dlut surface and fill it with the data in 3dlut file */
1307         va_status = create_surface(&g_3dlut_surface_id, g_3dlut_seg_size * g_3dlut_mul_size, g_3dlut_seg_size * 2,
1308                                    VA_FOURCC_RGBA, VA_RT_FORMAT_RGB32);
1309         CHECK_VASTATUS(va_status, "vaCreateSurfaces for 3dlut.");
1310         /* fill 3dlut with the 3dlut file data */
1311         FILE *lut3d_file = NULL;
1312         lut3d_file = fopen(g_3dlut_file_name, "rb");
1313         upload_data_to_3dlut(lut3d_file, g_3dlut_surface_id);
1314         if (lut3d_file) {
1315             fclose(lut3d_file);
1316             lut3d_file = NULL;
1317         }
1318     }
1319 
1320     va_status = vaCreateConfig(va_dpy,
1321                                VAProfileNone,
1322                                VAEntrypointVideoProc,
1323                                &attrib,
1324                                1,
1325                                &config_id);
1326     CHECK_VASTATUS(va_status, "vaCreateConfig");
1327 
1328     va_status = vaCreateContext(va_dpy,
1329                                 config_id,
1330                                 g_out_pic_width,
1331                                 g_out_pic_height,
1332                                 VA_PROGRESSIVE,
1333                                 &g_out_surface_id,
1334                                 1,
1335                                 &context_id);
1336     CHECK_VASTATUS(va_status, "vaCreateContext");
1337     return va_status;
1338 }
1339 
1340 static void
vpp_context_destroy()1341 vpp_context_destroy()
1342 {
1343     /* Release resource */
1344     printf("vaDestroySurfaces input and output surface!\n");
1345     vaDestroySurfaces(va_dpy, &g_in_surface_id, 1);
1346     vaDestroySurfaces(va_dpy, &g_out_surface_id, 1);
1347     if (g_pipeline_sequence == VA_SCALING_3DLUT) {
1348         printf("vaDestroySurfaces intermediate surface for Scaling->3DLUT!\n");
1349         vaDestroySurfaces(va_dpy, &g_inter_surface_id, 1);
1350     }
1351     if (g_pipeline_sequence != VA_SCALING_ONLY) {
1352         printf("vaDestroySurfaces 3dlut surface for Scaling!\n");
1353         vaDestroySurfaces(va_dpy, &g_3dlut_surface_id, 1);
1354     }
1355     printf("vaDestroyContext!\n");
1356     vaDestroyContext(va_dpy, context_id);
1357     printf("vaDestroyConfig!\n");
1358     vaDestroyConfig(va_dpy, config_id);
1359 
1360     printf("vaTerminate!\n");
1361     vaTerminate(va_dpy);
1362     printf("va_close_display!\n");
1363     va_close_display(va_dpy);
1364 }
1365 
1366 static int8_t
parse_fourcc_and_format(char * str,uint32_t * fourcc,uint32_t * format)1367 parse_fourcc_and_format(char *str, uint32_t *fourcc, uint32_t *format)
1368 {
1369     uint32_t tfourcc = VA_FOURCC('N', 'V', '1', '2');
1370     uint32_t tformat = VA_RT_FORMAT_YUV420;
1371 
1372     if (!strcmp(str, "YV12")) {
1373         tfourcc = VA_FOURCC('Y', 'V', '1', '2');
1374     } else if (!strcmp(str, "I420")) {
1375         tfourcc = VA_FOURCC('I', '4', '2', '0');
1376     } else if (!strcmp(str, "NV12")) {
1377         tfourcc = VA_FOURCC('N', 'V', '1', '2');
1378     } else if (!strcmp(str, "YUY2") || !strcmp(str, "YUYV")) {
1379         tfourcc = VA_FOURCC('Y', 'U', 'Y', '2');
1380     } else if (!strcmp(str, "UYVY")) {
1381         tfourcc = VA_FOURCC('U', 'Y', 'V', 'Y');
1382     } else if (!strcmp(str, "P010")) {
1383         tfourcc = VA_FOURCC('P', '0', '1', '0');
1384     } else if (!strcmp(str, "I010")) {
1385         tfourcc = VA_FOURCC('I', '0', '1', '0');
1386     } else if (!strcmp(str, "RGBA")) {
1387         tfourcc = VA_FOURCC_RGBA;
1388     } else if (!strcmp(str, "RGBX")) {
1389         tfourcc = VA_FOURCC_RGBX;
1390     } else if (!strcmp(str, "BGRA")) {
1391         tfourcc = VA_FOURCC_BGRA;
1392     } else if (!strcmp(str, "BGRX")) {
1393         tfourcc = VA_FOURCC_BGRX;
1394     } else {
1395         printf("Not supported format: %s! Currently only support following format: %s\n",
1396                str, "YV12, I420, NV12, YUY2(YUYV), UYVY, P010, I010, RGBA, RGBX, BGRA or BGRX");
1397         assert(0);
1398     }
1399 
1400     if (fourcc)
1401         *fourcc = tfourcc;
1402 
1403     if (format)
1404         *format = tformat;
1405 
1406     return 0;
1407 }
1408 
1409 static int8_t
parse_basic_parameters()1410 parse_basic_parameters()
1411 {
1412     char str[MAX_LEN];
1413 
1414     /* Read src frame file information */
1415     read_value_string(g_config_file_fd, "SRC_FILE_NAME", g_src_file_name);
1416     read_value_uint32(g_config_file_fd, "SRC_FRAME_WIDTH", &g_in_pic_width);
1417     read_value_uint32(g_config_file_fd, "SRC_FRAME_HEIGHT", &g_in_pic_height);
1418     read_value_string(g_config_file_fd, "SRC_FRAME_FORMAT", str);
1419     parse_fourcc_and_format(str, &g_in_fourcc, &g_in_format);
1420 
1421     /* Read dst frame file information */
1422     read_value_string(g_config_file_fd, "DST_FILE_NAME", g_dst_file_name);
1423     read_value_uint32(g_config_file_fd, "DST_FRAME_WIDTH", &g_out_pic_width);
1424     read_value_uint32(g_config_file_fd, "DST_FRAME_HEIGHT", &g_out_pic_height);
1425     read_value_string(g_config_file_fd, "DST_FRAME_FORMAT", str);
1426     parse_fourcc_and_format(str, &g_out_fourcc, &g_out_format);
1427 
1428     read_value_string(g_config_file_fd, "SRC_FILE_FORMAT", str);
1429     parse_fourcc_and_format(str, &g_src_file_fourcc, NULL);
1430 
1431     read_value_string(g_config_file_fd, "DST_FILE_FORMAT", str);
1432     parse_fourcc_and_format(str, &g_dst_file_fourcc, NULL);
1433 
1434     read_value_uint32(g_config_file_fd, "FRAME_SUM", &g_frame_count);
1435 
1436     read_value_uint32(g_config_file_fd, "3DLUT_SCALING", &g_pipeline_sequence);
1437 
1438     if (read_value_string(g_config_file_fd, "3DLUT_FILE_NAME", g_3dlut_file_name)) {
1439         printf("Read 3DLUT file failed, exit.");
1440     }
1441 
1442     if (read_value_uint16(g_config_file_fd, "3DLUT_SEG_SIZE", &g_3dlut_seg_size)) {
1443         printf("Read segment_size failed, exit.");
1444     }
1445 
1446     if (read_value_uint16(g_config_file_fd, "3DLUT_MUL_SIZE", &g_3dlut_mul_size)) {
1447         printf("Read multiple_size failed, exit.");
1448     }
1449 
1450     if (read_value_uint32(g_config_file_fd, "3DLUT_CHANNEL_MAPPING", &g_3dlut_channel_mapping)) {
1451         printf("Read channel_mapping failed, exit.");
1452     }
1453 
1454     if (g_in_pic_width != g_out_pic_width ||
1455         g_in_pic_height != g_out_pic_height)
1456         printf("Scaling will be done : from %4d x %4d to %4d x %4d \n",
1457                g_in_pic_width, g_in_pic_height,
1458                g_out_pic_width, g_out_pic_height);
1459 
1460     if (g_in_fourcc != g_out_fourcc)
1461         printf("Format conversion will be done: from %d to %d \n",
1462                g_in_fourcc, g_out_fourcc);
1463 
1464     return 0;
1465 }
1466 
1467 static void
print_help()1468 print_help()
1469 {
1470     printf("The app is used to test the scaling and csc feature.\n");
1471     printf("Cmd Usage: ./vpp3dlut process_3dlut.cfg\n");
1472     printf("The configure file process_scaling_csc.cfg is used to configure the para.\n");
1473     printf("You can refer process_scaling_csc.cfg.template for each para meaning and create the configure file.\n");
1474 }
1475 
main(int32_t argc,char * argv[])1476 int32_t main(int32_t argc, char *argv[])
1477 {
1478     VAStatus va_status;
1479     uint32_t i;
1480 
1481     if (argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
1482         print_help();
1483         return -1;
1484     }
1485 
1486     /* Parse the configure file for video process*/
1487     strncpy(g_config_file_name, argv[1], MAX_LEN);
1488     g_config_file_name[MAX_LEN - 1] = '\0';
1489 
1490     if (NULL == (g_config_file_fd = fopen(g_config_file_name, "r"))) {
1491         printf("Open configure file %s failed!\n", g_config_file_name);
1492         assert(0);
1493     }
1494 
1495     /* Parse basic parameters */
1496     if (parse_basic_parameters()) {
1497         printf("Parse parameters in configure file error\n");
1498         assert(0);
1499     }
1500 
1501     va_status = vpp_context_create();
1502     if (va_status != VA_STATUS_SUCCESS) {
1503         printf("vpp context create failed \n");
1504         assert(0);
1505     }
1506 
1507     /* Video frame fetch, process and store */
1508     if (NULL == (g_src_file_fd = fopen(g_src_file_name, "r"))) {
1509         printf("Open SRC_FILE_NAME: %s failed, please specify it in config file: %s !\n",
1510                g_src_file_name, g_config_file_name);
1511         assert(0);
1512     }
1513 
1514     if (NULL == (g_dst_file_fd = fopen(g_dst_file_name, "w"))) {
1515         printf("Open DST_FILE_NAME: %s failed, please specify it in config file: %s !\n",
1516                g_dst_file_name, g_config_file_name);
1517         assert(0);
1518     }
1519 
1520     for (i = 0; i < g_frame_count; i ++) {
1521         upload_yuv_frame_to_yuv_surface(g_src_file_fd, g_in_surface_id);
1522         if (g_pipeline_sequence == VA_3DLUT_SCALING) {
1523             printf("process frame #%d in VA_3DLUT_SCALING\n", i);
1524             video_frame_process_3dlut(g_in_surface_id, g_out_surface_id);
1525         } else if (g_pipeline_sequence == VA_SCALING_3DLUT) {
1526             printf("process frame #%d in VA_SCALING_3DLUT\n", i);
1527             video_frame_process_scaling(g_in_surface_id, g_inter_surface_id);
1528             video_frame_process_3dlut(g_inter_surface_id, g_out_surface_id);
1529         } else if (g_pipeline_sequence == VA_SCALING_ONLY) {
1530             printf("process frame #%d in VA_SCALING_ONLY\n", i);
1531             video_frame_process_scaling(g_in_surface_id, g_out_surface_id);
1532         } else {
1533             printf("Unknown pipeline sequence, default is 3DLUT->scaling!\n");
1534         }
1535         store_yuv_surface_to_file(g_dst_file_fd, g_out_surface_id);
1536     }
1537 
1538     if (g_src_file_fd)
1539         fclose(g_src_file_fd);
1540 
1541     if (g_dst_file_fd)
1542         fclose(g_dst_file_fd);
1543 
1544     if (g_config_file_fd)
1545         fclose(g_config_file_fd);
1546 
1547     vpp_context_destroy();
1548 
1549     return 0;
1550 }
1551 
1552 #endif
1553