1 /***************************************************************************
2 \file : ADM_coreLibVA.cpp
3 \brief : Wrapper around libVA functions
4 \author : (C) 2013/2016 by mean fixounet@free.fr, derived from xbmc_pvr
5 ***************************************************************************/
6
7 /***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16 #include "ADM_default.h"
17 #include "../include/ADM_coreLibVA.h"
18 #include "va/va_x11.h"
19
20 #ifdef USE_LIBVA
21 #include "../include/ADM_coreLibVA_internal.h"
22 #include "ADM_dynamicLoading.h"
23 #include "ADM_windowInfo.h"
24 #include "libavcodec/vaapi.h"
25 #include "ADM_imageFlags.h"
26
27 #include "fourcc.h"
28 #include <map>
29
30 #define CHECK_WORKING(x) if(!coreLibVAWorking) {ADM_warning("Libva not operationnal\n");return x;}
31
32 #if 0
33 #define aprintf printf
34 #else
35 #define aprintf(...) {}
36 #endif
37
38
39
40
41 /**
42 *
43 */
44
45
46 static std::map <VASurfaceID, bool>listOfAllocatedSurface;
47 typedef std::map<VASurfaceID, bool> surfaceList;
48
49 static std::map <VAImageID, bool>listOfAllocatedVAImage;
50 typedef std::map<VAImageID, bool> vaImageList;
51
52
53
54
55 GUI_WindowInfo admLibVA::myWindowInfo;
56
57 namespace ADM_coreLibVA
58 {
59 void *context;
60 VADisplay display;
61 VAConfigID configH264;
62 VAConfigID configMpeg2;
63 VAConfigID configH265;
64 VAConfigID configH26510Bits;
65 VAConfigID configVC1;
66 VAConfigID configVP9;
67 VAImageFormat imageFormatNV12;
68 VAImageFormat imageFormatYV12;
69 bool directOperation;
70 bool indirectOperationYV12;
71 bool indirectOperationNV12;
72 admLibVA::LIBVA_TRANSFER_MODE transferMode;
73
74 namespace decoders
75 {
76 bool h264;
77 }
78 }
79 namespace ADM_coreLibVAEnc
80 {
81 class vaEncoder
82 {
83 public:
84 bool enabled;
85 VAConfigID configId;
86 bool hasCBR;
87 bool hasVBR;
vaEncoder()88 vaEncoder()
89 {
90 enabled=false;
91 configId=-1;
92 hasCBR=false;
93 hasVBR=false;
94 }
95
96 };
97 namespace encoders
98 {
99 vaEncoder vaH264,vaH265;
100 }
101 }
102 static bool coreLibVAWorking=false;
103
104 #define CLEAR(x) memset(&x,0,sizeof(x))
105 #define CHECK_ERROR(x) {xError=x;displayXError(#x,ADM_coreLibVA::display,xError);if(xError) printf("%d =<%s>\n",xError,vaErrorStr(xError));}
106
107 #include "ADM_coreLibVA_test.cpp"
108 #include "ADM_bitstream.h"
109
110
111 /**
112 * \fn checkSupportedFunctionsAndImageFormat
113 * \brief check if operation through vaDeriveImage is supported and if
114 * YV12 or NV12 is supported
115 * @param func
116 * @param dis
117 * @param er
118 */
checkSupportedFunctionsAndImageFormat(void)119 static bool checkSupportedFunctionsAndImageFormat(void)
120 {
121 bool r=false;
122 ADMImageDefault image1(640,400),image2(640,400);
123 VASurfaceID surface=admLibVA::allocateSurface(640,400); // freed with admSurface
124 ADM_vaSurface admSurface(640,400);
125 admSurface.surface=VA_INVALID;
126
127 if(surface==VA_INVALID)
128 {
129 ADM_info("Cannot allocate a surface => not working\n");
130 return false;
131 }
132 admSurface.surface=surface;
133
134 // Check direct upload/Download works
135 ADM_info("--Trying direct operations --\n");
136 ADM_coreLibVA::directOperation =tryDirect("direct",admSurface, image1, image2);
137 ADM_info("-- Trying indirect (YV12) --\n");
138 ADM_coreLibVA::indirectOperationYV12=tryIndirect(0,admSurface, image1 ,image2);
139 ADM_info("-- Trying indirect (NV12) --\nSKIPPED\n");
140 ADM_coreLibVA::indirectOperationNV12=false; //tryIndirect(1,admSurface, image1, image2 );
141
142 ADM_info("Direct : %d\n",ADM_coreLibVA::directOperation);
143 ADM_info("Indirect NV12 : %d\n",ADM_coreLibVA::indirectOperationNV12);
144 ADM_info("Indirect YV12 : %d\n",ADM_coreLibVA::indirectOperationYV12);
145 if(ADM_coreLibVA::directOperation)
146 ADM_coreLibVA::transferMode=admLibVA::ADM_LIBVA_DIRECT;
147 else if(ADM_coreLibVA::indirectOperationYV12)
148 ADM_coreLibVA::transferMode=admLibVA::ADM_LIBVA_INDIRECT_YV12;
149 else if(ADM_coreLibVA::indirectOperationNV12)
150 ADM_coreLibVA::transferMode=admLibVA::ADM_LIBVA_INDIRECT_NV12;
151 else
152 {
153 ADM_warning("Did not find a usable way to transfer images to/from LibVA\n");
154 ADM_coreLibVA::transferMode=admLibVA::ADM_LIBVA_NONE;
155 return false;
156 }
157 ADM_info("LibVA: All ok\n");
158 return true;
159 }
160
161 /**
162 * \fn displayXError
163 * @param dis
164 * @param er
165 */
displayXError(const char * func,const VADisplay dis,const VAStatus er)166 static void displayXError(const char *func,const VADisplay dis,const VAStatus er)
167 {
168 if(!er) return;
169 ADM_warning("LibVA Error : <%s:%s:%d>\n",func,vaErrorStr(er),(int)er);
170
171
172 }
173 /**
174 *
175 * @return
176 */
getVADisplay()177 VADisplay admLibVA::getVADisplay()
178 {
179 return ADM_coreLibVA::display;
180 }
181
182 /**
183 * \fn setupEncodingConfig
184 * @return
185 */
setupEncodingConfig(void)186 bool admLibVA::setupEncodingConfig(void)
187 {
188 VAStatus xError;
189 VAEntrypoint entrypoints[5];
190 int num_entrypoints;
191 VAConfigAttrib attrib[2];
192
193
194 CHECK_ERROR(vaQueryConfigEntrypoints(ADM_coreLibVA::display, VAProfileH264Main, entrypoints, &num_entrypoints));
195
196 int found=-1;
197 ADM_info("Found %d entry points\n",num_entrypoints);
198 for (int slice_entrypoint = 0; slice_entrypoint < num_entrypoints; slice_entrypoint++)
199 {
200 ADM_info(" %d is a %d\n",slice_entrypoint,entrypoints[slice_entrypoint] );
201 if (entrypoints[slice_entrypoint] == VAEntrypointEncSlice)
202 {
203 found=slice_entrypoint;
204 break;
205 }
206
207 }
208 if(-1 == found)
209 {
210 ADM_warning("Cannot find encoder entry point\n");
211 return false;
212 }
213 /* find out the format for the render target, and rate control mode */
214 attrib[0].type = VAConfigAttribRTFormat;
215 attrib[1].type = VAConfigAttribRateControl;
216 CHECK_ERROR(vaGetConfigAttributes(ADM_coreLibVA::display, VAProfileH264Main, VAEntrypointEncSlice, &attrib[0], 2));
217 int check=0;
218 for(int i=0;i<2;i++)
219 {
220 unsigned int value=attrib[i].value;
221 int type=attrib[i].type;
222 switch(type)
223 {
224 case VAConfigAttribRTFormat:
225 if(value & VA_RT_FORMAT_YUV420)
226 {
227 ADM_info("YUV420 supported\n");
228 check|=1;
229 }
230 break;
231 case VAConfigAttribRateControl:
232 #define MKK(x,y) if(type & x) {ADM_info(#x " is supported\n");y;}
233 MKK(VA_RC_CBR,;);
234 MKK(VA_RC_VBR,check|=2);
235 MKK(VA_RC_CQP,;);
236 MKK(VA_RC_VBR_CONSTRAINED,;);
237 break;
238 default:
239 ADM_warning("Unknown attribute %d\n",type);
240 break;
241
242 }
243
244 }
245 if(check!=3)
246 {
247 ADM_warning("Some configuration are missing, bailing\n");
248 return false;
249 }
250 CHECK_ERROR(vaCreateConfig(ADM_coreLibVA::display, VAProfileH264Main, VAEntrypointEncSlice,
251 &attrib[0], 2,&(ADM_coreLibVAEnc::encoders::vaH264.configId)));
252 if(xError)
253 {
254 ADM_coreLibVAEnc::encoders::vaH264.configId=-1;
255 return false;
256
257 }else
258 {
259 ADM_info("H264 Encoding config created\n");
260 ADM_coreLibVAEnc::encoders::vaH264.enabled=true;
261 }
262 return true;
263 }
264 /**
265 * \fn checkProfile
266 * @param profile
267 * @param cid
268 * @param name
269 * @return
270 */
checkProfile(const VAProfile & profile,VAConfigID * cid,const char * name)271 static bool checkProfile(const VAProfile &profile,VAConfigID *cid,const char *name)
272 {
273 VAStatus xError;
274
275 *cid=-1;
276 VAConfigAttrib attrib;
277 attrib.type = VAConfigAttribRTFormat;
278 ADM_info("--Probing %s ...\n",name);
279 CHECK_ERROR(vaGetConfigAttributes(ADM_coreLibVA::display, profile, VAEntrypointVLD, &attrib, 1));
280 if(xError)
281 {
282 ADM_warning("Cannot get attribute for VAEntrypointVLD %s \n",name);
283 return false;
284 }
285 ADM_info("RT Format =0x%x\n",attrib.value);
286 #define CHECK_RT(x) if(attrib.value & VA_RT_FORMAT_##x ) ADM_info("\t" #x " supported\n");
287 CHECK_RT(YUV420);
288 CHECK_RT(YUV422);
289 CHECK_RT(YUV444);
290 CHECK_RT(YUV420_10BPP);
291 CHECK_RT(RGB32);
292
293 CHECK_ERROR(vaCreateConfig( ADM_coreLibVA::display, profile, VAEntrypointVLD,&attrib, 1,cid));
294 if(xError)
295 {
296 ADM_warning("Cannot create config %s\n",name);
297 *cid=-1;
298 return false;
299 }
300 ADM_info("Config created %s \n",name);
301 return true;
302 }
303 /**
304 * \fn setupConfig
305 * \brief verify that h264 main profile is supported
306 */
setupConfig(void)307 bool admLibVA::setupConfig(void)
308 {
309 VAStatus xError;
310 bool r=false;
311 int nb=vaMaxNumProfiles(ADM_coreLibVA::display);
312 ADM_info("Max config = %d \n",nb);
313 VAProfile *prof=(VAProfile *)admAlloca(sizeof(VAProfile)*nb);
314 int nbProfiles;
315 CHECK_ERROR(vaQueryConfigProfiles (ADM_coreLibVA::display, prof,&nbProfiles));
316
317 // Check supported profiles
318 if(!xError)
319 {
320 ADM_info("Found %d config \n",nbProfiles);
321 for(int i=0;i<nbProfiles;i++)
322 {
323 if(prof[i]==VAProfileH264High)
324 {
325 r=true;
326 ADM_info("H264 high profile found\n");
327 }
328 }
329 }
330 // if H264 is not supported, no need to go further
331 if(!r)
332 return false;
333
334 checkProfile(VAProfileMPEG2Main, &ADM_coreLibVA::configMpeg2, "Mpeg 2 Main");
335 checkProfile(VAProfileH264High, &ADM_coreLibVA::configH264, "H264 Hight");
336 checkProfile(VAProfileVC1Advanced, &ADM_coreLibVA::configVC1 , "VC1");
337 #ifdef LIBVA_HEVC_DEC
338 checkProfile(VAProfileHEVCMain, &ADM_coreLibVA::configH265, "HEVC Main");
339 checkProfile(VAProfileHEVCMain10, &ADM_coreLibVA::configH26510Bits,"H265 10Bits");
340 #endif
341
342 #ifdef LIBVA_VP9_DEC
343 checkProfile(VAProfileVP9Profile3, &ADM_coreLibVA::configVP9 , "VP9");
344 #endif
345 return true;
346 }
347 /**
348 * \fn fourCC_tostring
349 * @param fourcc
350 * @return
351 */
fourCC_tostring(uint32_t fourcc)352 static char *fourCC_tostring(uint32_t fourcc)
353 {
354 static char s[5];
355 s[4] = 0;
356
357 s[3]=((fourcc & 0xff000000)>>24)&0xff;
358 s[2]=((fourcc & 0xff0000)>>16)&0xff;
359 s[1]=((fourcc & 0xff00)>>8)&0xff;
360 s[0]=((fourcc & 0xff)>>0)&0xff;
361
362 return s;
363 }
364
365 /**
366 *
367 * @return
368 */
getDisplay()369 VADisplay admLibVA::getDisplay()
370 {
371 return ADM_coreLibVA::display;
372 }
373 /**
374 * \fn setupImageFormat
375 */
setupImageFormat()376 bool admLibVA::setupImageFormat()
377 {
378 int xError;
379 bool r=false;
380 int nbImage=vaMaxNumImageFormats(ADM_coreLibVA::display);
381 VAImageFormat *list=new VAImageFormat[nbImage];
382 int nb;
383 CHECK_ERROR(vaQueryImageFormats( ADM_coreLibVA::display,list,&nb));
384 if(xError)
385 {
386 r=false;
387 }else
388 {
389 r=false;
390 for(int i=0;i<nb;i++)
391 {
392 aprintf("----------");
393 aprintf("bpp : %d\n",list[i].bits_per_pixel);
394 uint32_t fcc=list[i].fourcc;
395 aprintf("fcc : 0x%x:%s\n",fcc,fourCC_tostring(fcc));
396 switch(fcc)
397 {
398 case VA_FOURCC_NV12:
399 ADM_coreLibVA::imageFormatNV12=list[i];
400 r=true;
401 break;
402 case VA_FOURCC_YV12:
403 ADM_coreLibVA::imageFormatYV12=list[i];
404 r=true;
405 break;
406 }
407 }
408
409 }
410 if(r==false)
411 {
412 ADM_warning("Cannot find supported image format : YV12\n");
413 }
414 delete [] list;
415 return r;
416 }
417 /**
418 * \fn fillContext
419 * @param c
420 * @return
421 */
fillContext(VAProfile profile,vaapi_context * c)422 bool admLibVA::fillContext(VAProfile profile ,vaapi_context *c)
423 {
424 CHECK_WORKING(false);
425 VAConfigID cid;
426 switch(profile)
427 {
428 case VAProfileMPEG2Main: cid=ADM_coreLibVA::configMpeg2;break;
429 case VAProfileH264High: cid=ADM_coreLibVA::configH264;break;
430 case VAProfileVC1Advanced: cid=ADM_coreLibVA::configVC1;break;
431 #ifdef LIBVA_HEVC_DEC
432 case VAProfileHEVCMain: cid=ADM_coreLibVA::configH265;break;
433 case VAProfileHEVCMain10: cid=ADM_coreLibVA::configH26510Bits;break;
434 #endif
435
436 #ifdef LIBVA_VP9_DEC
437 case VAProfileVP9Profile3: cid=ADM_coreLibVA::configVP9;break;
438 #endif
439 default:
440 ADM_assert(0);
441
442 }
443 c->config_id=cid;
444 c->display=ADM_coreLibVA::display;
445 return true;
446 }
447
448
449
450 /**
451 \fn init
452 \brief
453 */
init(GUI_WindowInfo * x)454 bool admLibVA::init(GUI_WindowInfo *x)
455 {
456 Display *dis=(Display *)x->display;
457 ADM_coreLibVA::display=vaGetDisplay(dis);
458 ADM_info("[LIBVA] Initializing LibVA library ...\n");
459
460
461 ADM_coreLibVA::context=NULL;
462 ADM_coreLibVA::decoders::h264=false;
463 ADM_coreLibVA::directOperation=true;
464 ADM_coreLibVA::transferMode=ADM_LIBVA_NONE;
465
466 ADM_coreLibVA::configH265=-1;
467 ADM_coreLibVA::configH26510Bits=-1;
468 ADM_coreLibVA::configVP9=-1;
469
470
471 myWindowInfo=*x;
472 VAStatus xError;
473 int majv,minv;
474 CHECK_ERROR(vaInitialize(ADM_coreLibVA::display,&majv,&minv));
475 if(xError)
476 {
477 ADM_warning("VA: init failed\n");
478 return false;
479 }
480 ADM_info("VA %d.%d, Vendor = %s\n",majv,minv,vaQueryVendorString(ADM_coreLibVA::display));
481
482 if(setupConfig() && setupImageFormat())
483 {
484 coreLibVAWorking=true;
485 }
486
487 if(setupEncodingConfig())
488 {
489 ADM_info("VA: Encoding supported\n");
490 }else
491 {
492 ADM_warning("VA: Encoding not supported\n");
493 }
494 return checkSupportedFunctionsAndImageFormat();
495 }
496 /**
497 \fn cleanup
498 */
cleanup(void)499 bool admLibVA::cleanup(void)
500 {
501 VAStatus xError;
502 ADM_info("[LIBVA] De-Initializing LibVA library ...\n");
503 if(true==coreLibVAWorking)
504 {
505 CHECK_ERROR(vaTerminate(ADM_coreLibVA::display));
506
507 }
508 coreLibVAWorking=false;
509 return true;
510 }
511 /**
512 \fn isOperationnal
513 */
isOperationnal(void)514 bool admLibVA::isOperationnal(void)
515 {
516 return coreLibVAWorking;
517 }
518 /**
519 *
520 * @param profile
521 * @return
522 */
supported(VAProfile profile)523 bool admLibVA::supported(VAProfile profile)
524 {
525 #define SUPSUP(a,b) case a: if(ADM_coreLibVA::b!=-1) return true;break;
526 switch(profile)
527 {
528 SUPSUP(VAProfileMPEG2Main,configMpeg2)
529 SUPSUP(VAProfileH264High,configH264)
530 SUPSUP(VAProfileVC1Advanced,configVC1)
531 #ifdef LIBVA_HEVC_DEC
532 SUPSUP(VAProfileHEVCMain,configH265)
533 SUPSUP(VAProfileHEVCMain10,configH26510Bits)
534 #endif
535
536 #ifdef LIBVA_VP9_DEC
537 SUPSUP(VAProfileVP9Profile3,configVP9)
538 #endif
539 default:
540 ADM_info("This profile is not supported by libva\n");
541 break;
542 }
543 ADM_info("Unknown profile (%d)\n",(int)profile);
544 #ifdef LIBVA_VP9_DEC
545 ADM_info("Compiled with vp9 support, library says %d\n",ADM_coreLibVA::configVP9);
546 #endif
547 return false;
548 }
549
550 /**
551 * \fn createDecoder
552 * @param width
553 * @param height
554 * @return
555 */
556
createDecoder(VAProfile profile,int width,int height,int nbSurface,VASurfaceID * surfaces)557 VAContextID admLibVA::createDecoder(VAProfile profile,int width, int height,int nbSurface, VASurfaceID *surfaces)
558 {
559 int xError=1;
560 CHECK_WORKING(VA_INVALID);
561 VAContextID id;
562 VAConfigID cid;
563
564 switch(profile)
565 {
566 case VAProfileMPEG2Main: cid=ADM_coreLibVA::configMpeg2;break;
567 case VAProfileH264High: cid=ADM_coreLibVA::configH264;break;
568 case VAProfileVC1Advanced: cid=ADM_coreLibVA::configVC1;break;
569 #ifdef LIBVA_HEVC_DEC
570 case VAProfileHEVCMain: cid=ADM_coreLibVA::configH265;break;
571 case VAProfileHEVCMain10: cid=ADM_coreLibVA::configH26510Bits;break;
572 #endif
573 #ifdef LIBVA_VP9_DEC
574 case VAProfileVP9Profile3: cid=ADM_coreLibVA::configVP9;break;
575 #endif
576 default:
577 ADM_assert(0);
578 break;
579
580 }
581 if(cid==-1)
582 {
583 ADM_warning("No VA support for that\n");
584 return VA_INVALID;
585 }
586 CHECK_ERROR(vaCreateContext ( ADM_coreLibVA::display, cid,
587 width, height,
588 VA_PROGRESSIVE, // ?? NOT SURE ??
589 surfaces,
590 nbSurface,
591 &id));
592 if(xError)
593 {
594 ADM_warning("Cannot create decoder\n");
595 return VA_INVALID;
596 }
597 aprintf("Decoder created : %llx\n",(uint64_t)id);
598 return id;
599 }
600 /**
601 * \fn allocateImage
602 * \brief allocate the correct image type for transfer : None, YV12 or NV12
603 * @param w
604 * @param h
605 * @return
606 */
allocateImage(int w,int h)607 VAImage *admLibVA::allocateImage( int w, int h)
608 {
609 switch(ADM_coreLibVA::transferMode)
610 {
611 case admLibVA::ADM_LIBVA_NONE: ADM_warning("No transfer supported\n");
612 case admLibVA::ADM_LIBVA_DIRECT:
613 return NULL;break;
614 case admLibVA::ADM_LIBVA_INDIRECT_NV12:
615 return admLibVA::allocateNV12Image(w,h);break;
616 case admLibVA::ADM_LIBVA_INDIRECT_YV12:
617 return admLibVA::allocateYV12Image(w,h);break;
618 default:ADM_assert(0);
619 }
620 return NULL;
621 }
622
623 /**
624 *
625 * @param w
626 * @param h
627 * @return
628 */
allocateNV12Image(int w,int h)629 VAImage *admLibVA::allocateNV12Image( int w, int h)
630 {
631 int xError=1;
632 CHECK_WORKING(NULL);
633 VAImage *image=new VAImage;
634 memset(image,0,sizeof(*image));
635 CHECK_ERROR(vaCreateImage ( ADM_coreLibVA::display, &ADM_coreLibVA::imageFormatNV12,
636 w, h,
637 image));
638 if(xError)
639 {
640 ADM_warning("Cannot allocate nv12 image\n");
641 delete image;
642 return NULL;
643 }
644 listOfAllocatedVAImage[image->image_id]=true;
645 return image;
646 }
647 /**
648 *
649 * @param w
650 * @param h
651 * @return
652 */
allocateYV12Image(int w,int h)653 VAImage *admLibVA::allocateYV12Image( int w, int h)
654 {
655 int xError=1;
656 CHECK_WORKING(NULL);
657 VAImage *image=new VAImage;
658 memset(image,0,sizeof(*image));
659 CHECK_ERROR(vaCreateImage ( ADM_coreLibVA::display, &ADM_coreLibVA::imageFormatYV12,
660 w, h,
661 image));
662 if(xError)
663 {
664 ADM_warning("Cannot allocate yv12 image\n");
665 delete image;
666 return NULL;
667 }
668 listOfAllocatedVAImage[image->image_id]=true;
669 return image;
670 }
671 /**
672 *
673 * @param surface
674 */
destroyImage(VAImage * image)675 void admLibVA::destroyImage( VAImage *image)
676 {
677 int xError=1;
678 CHECK_WORKING();
679 if(listOfAllocatedVAImage.end()==listOfAllocatedVAImage.find(image->image_id))
680 {
681 ADM_warning("Trying to destroy an unallocated VAImage\n");
682 ADM_assert(0);
683 }
684 listOfAllocatedVAImage.erase(image->image_id);
685
686 CHECK_ERROR(vaDestroyImage(ADM_coreLibVA::display, image->image_id));
687 delete image;
688 if(xError)
689 {
690 ADM_warning("Cannot destroy image\n");
691 return ;
692 }
693 return ;
694 }
695
696 /**
697 * \fn destroySession
698 */
destroyDecoder(VAContextID session)699 bool admLibVA::destroyDecoder(VAContextID session)
700 {
701
702 int xError;
703 CHECK_WORKING(false);
704
705 aprintf("Destroying decoder %x\n",session);
706 CHECK_ERROR(vaDestroyContext(ADM_coreLibVA::display,session));
707 if(!xError)
708 {
709 aprintf("Decoder destroyed\n");
710 return true;
711 }
712 aprintf("Error destroying decoder\n");
713 return false;
714 }
715
716 /**
717 * \fn allocateSurface
718 * @param w
719 * @param h
720 * @return
721 */
allocateSurface(int w,int h,int fmt)722 VASurfaceID admLibVA::allocateSurface(int w, int h, int fmt)
723 {
724 int xError;
725 CHECK_WORKING(VA_INVALID);
726
727 aprintf("Creating surface %d x %d (fmt=%d)\n",w,h,fmt);
728 VASurfaceID s;
729
730 CHECK_ERROR(vaCreateSurfaces(ADM_coreLibVA::display,
731 fmt,
732 w,h,
733 &s,1,
734 NULL,0));
735
736 if(!xError)
737 {
738 surfaceList::iterator already;
739 already=listOfAllocatedSurface.find(s);
740 if(already!=listOfAllocatedSurface.end())
741 {
742 ADM_warning("Doubly allocated va surface\n");
743 ADM_assert(0);
744 }
745 listOfAllocatedSurface[s]=true;
746 return s;
747 }
748 aprintf("Error creating surface\n");
749 return VA_INVALID;
750 }
751 /**
752 * \fn destroySurface
753 * @param session
754 * @param surface
755 */
destroySurface(VASurfaceID surface)756 void admLibVA::destroySurface( VASurfaceID surface)
757 {
758 int xError;
759 CHECK_WORKING();
760
761 surfaceList::iterator already;
762 already=listOfAllocatedSurface.find(surface);
763 if(already==listOfAllocatedSurface.end())
764 {
765 ADM_warning("Trying to destroy an unallocated surface\n");
766 ADM_assert(0);
767 }
768 listOfAllocatedSurface.erase(surface);
769 CHECK_ERROR(vaDestroySurfaces(ADM_coreLibVA::display,&surface,1));
770 if(!xError)
771 {
772 return;
773 }
774 aprintf("Error destroying surface\n");
775 return;
776 }
777
778 /**
779 * \fn surfaceToImage
780 * @param id
781 * @param img
782 * @return
783 */
surfaceToAdmImage(ADMImage * dest,ADM_vaSurface * src,ADMColorScalerSimple * color)784 bool admLibVA::surfaceToAdmImage(ADMImage *dest,ADM_vaSurface *src,ADMColorScalerSimple *color)
785 {
786 int xError;
787 bool r=false;
788 VASurfaceStatus status;
789 CHECK_WORKING(false);
790 uint8_t *ptr=NULL;
791 //--------------------------
792 // Wait for surface to be ready...
793 //--------------------------
794 int countDown=50;
795 bool end=false;
796 while(!end)
797 {
798 CHECK_ERROR(vaQuerySurfaceStatus ( ADM_coreLibVA::display, src->surface,&status));
799 if(xError)
800 {
801 ADM_warning("QuerySurfacStatus failed\n");
802 return false;
803 }
804 aprintf("surface status = %d\n",status);
805 switch(status)
806 {
807 case VASurfaceReady:
808 end=true;
809 continue;
810 break;
811 case VASurfaceSkipped:
812 end=true;
813 continue;
814 break;
815 default:
816 countDown--;
817 if(!countDown)
818 {
819 ADM_warning("Timeout waiting for surface\n");
820 end=true;
821 continue;
822 }
823 ADM_usleep(1000);
824 break;
825 }
826 }
827 if(status!=VASurfaceReady)
828 {
829 ADM_warning("Error getting surface within timeout = %d\n",(int)status);
830 dest->_noPicture=true;
831 return true;
832 }
833 //--------------------------
834 // Derive Image
835 //--------------------------
836 VAImage vaImage;
837 CHECK_ERROR(vaDeriveImage (ADM_coreLibVA::display, src->surface,&vaImage));
838 if(xError)
839 {
840 ADM_warning("Va GetImage failed\n");
841 return false;
842 }
843 switch(vaImage.format.fourcc)
844 {
845 case VA_FOURCC_YV12:break;
846 case VA_FOURCC_NV12:break;
847 case VA_FOURCC_P010:break;
848 default:
849 ADM_warning("Unknown format %s\n",fourCC_tostring(vaImage.format.fourcc));
850 goto dropIt;
851 }
852 // Map image...
853
854 CHECK_ERROR(vaMapBuffer(ADM_coreLibVA::display, vaImage.buf, (void**)&ptr))
855 if(!xError)
856 {
857 switch(vaImage.format.fourcc)
858 {
859 case VA_FOURCC_YV12:
860 {
861 ADMImageRefWrittable ref(dest->_width,dest->_height);
862 for(int i=0;i<3;i++)
863 {
864 ref._planes[i]= ptr+vaImage.offsets[i];
865 ref._planeStride[i]=vaImage.pitches[i];
866 }
867 dest->duplicate(&ref);
868 break;
869 }
870 case VA_FOURCC_NV12:
871 #ifdef VA_10BITS_IS_ACTUALL_8BITS
872 case VA_FOURCC_P010:
873 #endif
874 {
875 dest->convertFromNV12(ptr+vaImage.offsets[0],ptr+vaImage.offsets[1], vaImage.pitches[0], vaImage.pitches[1]);
876 break;
877 }
878 #ifndef VA_10BITS_IS_ACTUALL_8BITS
879 case VA_FOURCC_P010: // It is actually NV12 style All Y, then U/V interleaved
880 {
881 ADM_assert(color);
882 ADMImageRef ref(dest->_width,dest->_height);
883 for(int i=0;i<2;i++)
884 {
885 ref._planes[i]= ptr+vaImage.offsets[i];
886 ref._planeStride[i]=vaImage.pitches[i];
887 }
888 ref._planes[2]=NULL;
889 ref._planeStride[2]=0;
890 color->convertImage(&ref,dest);
891 break;
892 }
893 #endif
894 default:
895 goto dropIt;
896 break;
897 }
898 r=true;
899 CHECK_ERROR(vaUnmapBuffer(ADM_coreLibVA::display, vaImage.buf))
900 }
901 dropIt:
902 CHECK_ERROR(vaDestroyImage (ADM_coreLibVA::display,vaImage.image_id));
903 return r;
904 }
905 /**
906 * \fn putX11Surface
907 * @param img
908 * @param widget
909 * @param displayWidth
910 * @param displayHeight
911 * @return
912 */
putX11Surface(ADM_vaSurface * img,int widget,int displayWidth,int displayHeight)913 bool admLibVA::putX11Surface(ADM_vaSurface *img,int widget,int displayWidth,int displayHeight)
914 {
915 int xError;
916 CHECK_WORKING(false);
917 CHECK_ERROR(vaPutSurface ( ADM_coreLibVA::display, img->surface,(Drawable)widget,0,0,img->w, img->h,0,0,displayWidth,displayHeight,
918 NULL,0 // clip & and num clip
919 ,0)); // flags
920 if(xError)
921 {
922 ADM_warning("putX11Surface failed\n");
923 return false;
924 }
925 return true;
926 }
927
928 /***
929 * \fn imageToSurface
930 */
imageToSurface(VAImage * src,ADM_vaSurface * dst)931 bool admLibVA::imageToSurface(VAImage *src, ADM_vaSurface *dst)
932 {
933
934 int xError;
935 CHECK_WORKING(false);
936 CHECK_ERROR(vaPutImage(ADM_coreLibVA::display,
937 dst->surface,
938 src->image_id,
939 0,0,
940 dst->w,dst->h,
941 0,0,
942 dst->w,dst->h));
943 if(xError)
944 {
945 ADM_warning("[libVa] ImageToSurface failed\n");
946 return false;
947 }
948 return true;
949 }
950
951 /***
952 * \fn imageToSurface
953 */
surfaceToImage(ADM_vaSurface * dst,VAImage * src)954 bool admLibVA::surfaceToImage(ADM_vaSurface *dst,VAImage *src )
955 {
956
957 int xError;
958 CHECK_WORKING(false);
959 CHECK_ERROR(vaGetImage(ADM_coreLibVA::display,
960 dst->surface,
961 0,0,
962 dst->w,dst->h,
963 src->image_id
964 ));
965 if(xError)
966 {
967 ADM_warning("[libVa] surfaceToImage failed\n");
968 return false;
969 }
970 return true;
971 }
972
973 /**
974 * \fn uploadToImage
975 * @param dest
976 * @param src
977 * @return
978 */
uploadToImage(ADMImage * src,VAImage * dest)979 bool admLibVA::uploadToImage( ADMImage *src,VAImage *dest)
980 {
981 int xError;
982 CHECK_WORKING(false);
983 uint8_t *ptr=NULL;
984 CHECK_ERROR(vaMapBuffer(ADM_coreLibVA::display, dest->buf, (void**)&ptr))
985 if(xError)
986 {
987 ADM_warning("Cannot map image\n");
988 return false;
989 }
990 switch(dest->format.fourcc)
991 {
992 case VA_FOURCC_YV12:
993 {
994 ADMImageRefWrittable ref(src->_width,src->_height);
995 for(int i=0;i<3;i++)
996 {
997 ref._planes[i]= ptr+dest->offsets[i];
998 ref._planeStride[i]=dest->pitches[i];
999 }
1000 ref.duplicate(src);
1001 }
1002 break;
1003 case VA_FOURCC_NV12:src->convertToNV12( ptr+dest->offsets[0], ptr+dest->offsets[1],dest->pitches[0],dest->pitches[1]);break;
1004 default: ADM_assert(0);
1005 }
1006 CHECK_ERROR(vaUnmapBuffer (ADM_coreLibVA::display,dest->buf));
1007 return true;
1008 }
1009
1010 /**
1011 * \fn downloadFromImage
1012 * @param dest
1013 * @param src
1014 * @return
1015 */
downloadFromImage(ADMImage * src,VAImage * dest,ADMColorScalerSimple * color)1016 bool admLibVA::downloadFromImage( ADMImage *src,VAImage *dest,ADMColorScalerSimple *color)
1017 {
1018 int xError;
1019 CHECK_WORKING(false);
1020 uint8_t *ptr=NULL;
1021 CHECK_ERROR(vaMapBuffer(ADM_coreLibVA::display, dest->buf, (void**)&ptr))
1022 if(xError)
1023 {
1024 ADM_warning("Cannot map image\n");
1025 return false;
1026 }
1027 switch(dest->format.fourcc)
1028 {
1029 case VA_FOURCC_YV12:
1030 {
1031 ADMImageRef ref(src->_width,src->_height);
1032 ref.copyInfo(src);
1033 for(int i=0;i<3;i++)
1034 {
1035 ref._planes[i]= ptr+dest->offsets[i];
1036 ref._planeStride[i]=dest->pitches[i];
1037 }
1038 src->duplicate(&ref);
1039 }
1040 break;
1041 case VA_FOURCC_P010: // It is actually NV12 style All Y, then U/V interleaved
1042 {
1043 ADM_assert(color);
1044 ADMImageRef ref(src->_width,src->_height);
1045 for(int i=0;i<2;i++)
1046 {
1047 ref._planes[i]= ptr+dest->offsets[i];
1048 ref._planeStride[i]=dest->pitches[i];
1049 }
1050 ref._planes[2]=NULL;
1051 ref._planeStride[2]=0;
1052 color->convertImage(&ref,src);
1053 break;
1054 }
1055 case VA_FOURCC_NV12:
1056 src->convertFromNV12( ptr+dest->offsets[0], ptr+dest->offsets[1],dest->pitches[0],dest->pitches[1]);
1057 break;
1058 default: ADM_assert(0);
1059 }
1060 CHECK_ERROR(vaUnmapBuffer (ADM_coreLibVA::display,dest->buf));
1061 return true;
1062 }
1063 /**
1064 * \fn copyNV12
1065 * @param ptr
1066 * @param dest
1067 * @param src
1068 */
copyNV12(uint8_t * ptr,VAImage * dest,ADMImage * src)1069 static void copyNV12(uint8_t *ptr, VAImage *dest, ADMImage *src)
1070 {
1071 int w=src->_width;
1072
1073 int h=src->_height;
1074 int dstStride= dest->pitches[0];
1075 int srcStride= src->GetPitch(PLANAR_Y);
1076 uint8_t *s= src->GetReadPtr(PLANAR_Y);
1077 uint8_t *d= ptr+dest->offsets[0];
1078 for(int y=0;y<h;y++)
1079 {
1080 memcpy(d,s,w);
1081 s+=srcStride;
1082 d+=dstStride;
1083 }
1084
1085 w=w/2;
1086 h=h/2;
1087 uint8_t *srcu=src->GetReadPtr(PLANAR_U);
1088 uint8_t *srcv=src->GetReadPtr(PLANAR_V);
1089 int uStride=src->GetPitch(PLANAR_U);
1090 int vStride=src->GetPitch(PLANAR_V);
1091 dstStride=dest->pitches[1];
1092 uint8_t *dstPtr= ptr+dest->offsets[1];
1093 for(int y=0;y<h;y++)
1094 {
1095 uint8_t *ssrcu=srcu;
1096 uint8_t *ssrcv=srcv;
1097 uint8_t *d=dstPtr;
1098
1099 srcu+=uStride;
1100 srcv+=vStride;
1101 dstPtr+=dstStride;
1102
1103 for(int x=0;x<w;x++)
1104 {
1105 d[0]=*ssrcv++;
1106 d[1]=*ssrcu++;
1107 d+=2;
1108 }
1109 }
1110 }
1111 /**
1112 * \fn uploadToSurface
1113 * @param src
1114 * @param dest
1115 * @return
1116 */
admImageToSurface(ADMImage * src,ADM_vaSurface * dest)1117 bool admLibVA:: admImageToSurface( ADMImage *src,ADM_vaSurface *dest)
1118 {
1119 int xError;
1120 bool r=false;
1121 CHECK_WORKING(false);
1122 uint8_t *ptr=NULL;
1123
1124 VAImage vaImage;
1125 CHECK_ERROR(vaDeriveImage (ADM_coreLibVA::display, dest->surface,&vaImage));
1126 if(xError)
1127 {
1128 ADM_warning("Va Derive failed\n");
1129 return false;
1130 }
1131 // NV12 or YV12
1132 switch(vaImage.format.fourcc)
1133 {
1134 case VA_FOURCC_YV12:break;
1135 case VA_FOURCC_NV12:break;
1136 default:
1137 ADM_warning("Unknown format %s\n",fourCC_tostring(vaImage.format.fourcc));
1138 goto dontTry;
1139 }
1140
1141 // Map image...
1142
1143 CHECK_ERROR(vaMapBuffer(ADM_coreLibVA::display, vaImage.buf, (void**)&ptr))
1144 if(!xError)
1145 {
1146 r=true;
1147 // NV12 or YV12
1148 switch(vaImage.format.fourcc)
1149 {
1150 case VA_FOURCC_YV12:
1151 {
1152 ADMImageRefWrittable ref(src->_width,src->_height);
1153 for(int i=0;i<3;i++)
1154 {
1155 ref._planes[i]= ptr+vaImage.offsets[i];
1156 ref._planeStride[i]=vaImage.pitches[i];
1157 }
1158 ref.duplicate(src);
1159 }
1160 break;
1161 case VA_FOURCC_NV12:
1162 copyNV12(ptr,&vaImage,src);
1163 break;
1164 default:
1165 ADM_warning("Unknown format %s\n",fourCC_tostring(vaImage.format.fourcc));
1166 break;
1167 }
1168 CHECK_ERROR(vaUnmapBuffer(ADM_coreLibVA::display, vaImage.buf))
1169 }
1170 dontTry:
1171 CHECK_ERROR(vaDestroyImage (ADM_coreLibVA::display,vaImage.image_id));
1172
1173 return r;
1174 }
1175 /**
1176 *
1177 * @param image
1178 * @return
1179 */
fromAdmImage(ADMImage * dest)1180 bool ADM_vaSurface::fromAdmImage (ADMImage *dest)
1181 {
1182 switch(ADM_coreLibVA::transferMode)
1183 {
1184 case admLibVA::ADM_LIBVA_NONE: ADM_warning("No transfer supported\n");return false;break;
1185 case admLibVA::ADM_LIBVA_DIRECT:
1186 //printf("Direct\n");
1187 return admLibVA::admImageToSurface (dest,this);
1188 case admLibVA::ADM_LIBVA_INDIRECT_NV12:
1189 case admLibVA::ADM_LIBVA_INDIRECT_YV12:
1190 ADM_assert(this->image);
1191 //printf("InDirect\n");
1192 if( admLibVA::uploadToImage(dest,this->image))
1193 return admLibVA::imageToSurface(this->image,this);
1194 return false;
1195 break;
1196 default:ADM_assert(0);
1197 }
1198 return false;
1199 }
1200 /**
1201 * allocateWithSurface
1202 * @param w
1203 * @param h
1204 * @return
1205 */
allocateWithSurface(int w,int h,int fmt)1206 ADM_vaSurface *ADM_vaSurface::allocateWithSurface(int w,int h,int fmt)
1207 {
1208 ADM_vaSurface *s=new ADM_vaSurface(w,h);
1209 s->surface=admLibVA::allocateSurface(w,h,fmt);
1210 if(!s->hasValidSurface())
1211 {
1212 delete s;
1213 s=NULL;
1214 ADM_warning("Cannot allocate va surface\n");
1215 return NULL;
1216 }
1217 return s;
1218 }
1219
1220 /**
1221 *
1222 * @return
1223 */
ADM_vaSurface_cleanupCheck(void)1224 bool ADM_vaSurface_cleanupCheck(void)
1225 {
1226 int n=listOfAllocatedSurface.size();
1227 if(!n) return true;
1228
1229 ADM_warning("Some allocated va surface are still in use (%d), clearing them\n",n);
1230 return true;
1231
1232 }
1233 /**
1234 *
1235 * @return
1236 */
ADM_vaImage_cleanupCheck(void)1237 bool ADM_vaImage_cleanupCheck(void)
1238 {
1239 int n=listOfAllocatedVAImage.size();
1240 if(!n) return true;
1241
1242 ADM_warning("Some allocated va images are still in use (%d), clearing them\n",n);
1243 return true;
1244
1245 }
1246 /**
1247 *
1248 * @param w
1249 * @param h
1250 */
ADM_vaSurface(int w,int h)1251 ADM_vaSurface::ADM_vaSurface(int w, int h)
1252 {
1253 surface=VA_INVALID;
1254 refCount=0;
1255 this->w=w;
1256 this->h=h;
1257 image=admLibVA::allocateImage(w,h);
1258 color10bits=new ADMColorScalerSimple(w,h,ADM_COLOR_NV12_10BITS,ADM_COLOR_YV12);
1259 }
1260 /**
1261 *
1262 */
~ADM_vaSurface()1263 ADM_vaSurface:: ~ADM_vaSurface()
1264 {
1265 if(surface!=VA_INVALID)
1266 {
1267 admLibVA::destroySurface(surface);
1268 surface=VA_INVALID;
1269 }
1270 if(image)
1271 {
1272 admLibVA::destroyImage(image);
1273 image=NULL;
1274 }
1275 if(color10bits)
1276 {
1277 delete color10bits;
1278 color10bits=NULL;
1279 }
1280 }
1281
1282 /**
1283 * \fn admLibVa_exitCleanup
1284 */
admLibVa_exitCleanup()1285 bool admLibVa_exitCleanup()
1286 {
1287 ADM_info("VA cleanup begin\n");
1288 ADM_vaSurface_cleanupCheck();
1289 ADM_vaImage_cleanupCheck();
1290 admLibVA::cleanup();
1291 ADM_info("VA cleanup end\n");
1292 return true;
1293 }
1294
1295 /**
1296 *
1297 * @param image
1298 * @return
1299 */
toAdmImage(ADMImage * dest)1300 bool ADM_vaSurface::toAdmImage(ADMImage *dest)
1301 {
1302 switch(ADM_coreLibVA::transferMode)
1303 {
1304 case admLibVA::ADM_LIBVA_NONE: ADM_warning("No transfer supported\n");return false;break;
1305 case admLibVA::ADM_LIBVA_DIRECT:
1306 //printf("Direct\n");
1307 return admLibVA::surfaceToAdmImage(dest,this,color10bits);
1308 case admLibVA::ADM_LIBVA_INDIRECT_NV12:
1309 case admLibVA::ADM_LIBVA_INDIRECT_YV12:
1310 //printf("InDirect\n");
1311 ADM_assert(this->image);
1312 if(admLibVA::surfaceToImage(this,this->image))
1313 return admLibVA::downloadFromImage(dest,this->image,color10bits);
1314 return false;
1315 break;
1316 default:ADM_assert(0);
1317 }
1318 return false;
1319 }
1320 /**
1321 *
1322 * @return
1323 */
createFilterConfig()1324 VAConfigID admLibVA::createFilterConfig()
1325 {
1326 VAStatus xError;
1327 VAConfigID id=VA_INVALID;
1328
1329 if(!coreLibVAWorking) {ADM_warning("Libva not operationnal\n");return VA_INVALID;}
1330
1331 CHECK_ERROR(vaCreateConfig(ADM_coreLibVA::display, VAProfileNone, VAEntrypointVideoProc, 0, 0, &id));
1332 if(xError!=VA_STATUS_SUCCESS)
1333 return VA_INVALID;
1334 return id;
1335 }
1336
1337 /**
1338 *
1339 * @return
1340 */
createFilterContext()1341 VAContextID admLibVA::createFilterContext()
1342 {
1343 return VA_INVALID;
1344 }
1345 /**
1346 *
1347 * @param id
1348 * @return
1349 */
destroyFilterContext(VAContextID & id)1350 bool admLibVA::destroyFilterContext(VAContextID &id)
1351 {
1352 VAStatus xError;
1353 if(!coreLibVAWorking) {ADM_warning("Libva not operationnal\n");return false;}
1354
1355 CHECK_ERROR( vaDestroyContext(ADM_coreLibVA::display, id));
1356 id=VA_INVALID;
1357 return true;
1358 }
1359
1360 /**
1361 *
1362 * @return
1363 */
destroyFilterConfig(VAConfigID & id)1364 bool admLibVA::destroyFilterConfig(VAConfigID &id)
1365 {
1366 VAStatus xError;
1367 if(!coreLibVAWorking) {ADM_warning("Libva not operationnal\n");return false;}
1368
1369 CHECK_ERROR( vaDestroyConfig(ADM_coreLibVA::display, id));
1370 id=VA_INVALID;
1371 return true;
1372 }
1373
1374
1375 #endif
1376