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