1 /***************************************************************************
2             \file              ADM_ffmpeg_libvap.cpp
3             \brief Decoder using half ffmpeg/half vaapi
4 
5 
6  Very similar to ffmpeg_vdpau
7 
8 
9  ***************************************************************************/
10 
11 /***************************************************************************
12  *                                                                         *
13  *   This program is free software; you can redistribute it and/or modify  *
14  *   it under the terms of the GNU General Public License as published by  *
15  *   the Free Software Foundation; either version 2 of the License, or     *
16  *   (at your option) any later version.                                   *
17  *                                                                         *
18  ***************************************************************************/
19 #include "ADM_cpp.h"
20 #include "BVector.h"
21 #include "ADM_default.h"
22 
23 extern "C" {
24 #include "libavcodec/avcodec.h"
25 #include "libavutil/pixfmt.h"
26 #include "libavutil/pixdesc.h"
27 #include "libavcodec/vaapi.h"
28 }
29 
30 #include "ADM_codec.h"
31 #include "ADM_ffmp43.h"
32 #include "DIA_coreToolkit.h"
33 #include "ADM_dynamicLoading.h"
34 #include "ADM_render/GUI_render.h"
35 #include "prefs.h"
36 #include "ADM_coreLibVA.h"
37 #include "../private_inc/ADM_codecLibVA.h"
38 #include "ADM_threads.h"
39 #include "ADM_vidMisc.h"
40 #include "prefs.h"
41 
42 
43 static bool         libvaWorking=true;
44 static bool         libvaEncoderWorking=false;
45 static admMutex     imageMutex;
46 static int  ADM_LIBVAgetBuffer(AVCodecContext *avctx, AVFrame *pic);
47 static void ADM_LIBVAreleaseBuffer(struct AVCodecContext *avctx, AVFrame *pic);
48 
49 
50 
51 #if 1
52 #define aprintf(...) {}
53 #else
54 #define aprintf ADM_info
55 #endif
56 
57 /**
58  *
59  * @param instance
60  * @param cookie
61  * @return
62  */
libvaMarkSurfaceUsed(void * instance,void * cookie)63 static  bool libvaMarkSurfaceUsed(void *instance,void *cookie)
64 {
65     decoderFFLIBVA *inst=(decoderFFLIBVA *)instance;
66     ADM_vaSurface *s=(ADM_vaSurface *)cookie ;
67     inst->markSurfaceUsed(s);
68     return true;
69 }
70 /**
71  *
72  * @param instance
73  * @param cookie
74  * @return
75  */
libvaMarkSurfaceUnused(void * instance,void * cookie)76 static  bool libvaMarkSurfaceUnused(void *instance,void *cookie)
77 {
78     decoderFFLIBVA *inst=(decoderFFLIBVA *)instance ;
79     ADM_vaSurface *s=(ADM_vaSurface *)cookie ;
80     inst->markSurfaceUnused(s);
81     return true;
82 }
83 
84 /**
85     \fn vdpauRefDownload
86     \brief Convert a VASurface image to a regular image
87 */
libvaRefDownload(ADMImage * image,void * instance,void * cookie)88 static bool libvaRefDownload(ADMImage *image, void *instance, void *cookie)
89 {
90     decoderFFLIBVA *inst=(decoderFFLIBVA *)instance ;
91     ADM_vaSurface *s=(ADM_vaSurface *) cookie;
92     bool r=s->toAdmImage(image);
93     image->refType=ADM_HW_NONE;
94     libvaMarkSurfaceUnused(instance,cookie);
95     return r;
96 }
97 
98 /**
99     \fn libvaUsable
100     \brief Return true if  libva can be used...
101 */
libvaUsable(void)102 bool libvaUsable(void)
103 {
104     bool v=true;
105     if(!libvaWorking) return false;
106     if(!prefs->get(FEATURES_LIBVA,&v))
107     {
108         v=false;
109     }
110     return v;
111 }
112 
allocateADMVaSurface(AVCodecContext * ctx)113 static ADM_vaSurface *allocateADMVaSurface(AVCodecContext *ctx)
114 {
115     int widthToUse = (ctx->coded_width+ 1)  & ~1;
116     int heightToUse= (ctx->coded_height+3)  & ~3;
117     int fmt=VA_RT_FORMAT_YUV420;
118     if(ctx->pix_fmt==AV_PIX_FMT_YUV420P10LE)
119         fmt=VA_RT_FORMAT_YUV420_10BPP;
120     VASurfaceID surface=admLibVA::allocateSurface(widthToUse,heightToUse,fmt);
121     if(surface==VA_INVALID)
122     {
123             ADM_warning("Cannot allocate surface (%d x %d)\n",(int)widthToUse,(int)heightToUse);
124             return NULL;
125     }
126     ADM_vaSurface *img=new ADM_vaSurface(widthToUse,heightToUse);
127     img->surface=surface;
128     return img;
129 }
130 /**
131     \fn libvaProbe
132     \brief Try loading vaapi...
133 */
134 extern bool ADM_initLibVAEncoder(void);
libvaProbe(void)135 bool libvaProbe(void)
136 {
137     ADM_info("Probing for libVA support...\n");
138     GUI_WindowInfo xinfo;
139     void *draw;
140     draw=UI_getDrawWidget();
141     UI_getWindowInfo(draw,&xinfo );
142     if( admCoreCodecSupports(ADM_CORE_CODEC_FEATURE_LIBVA)==false)
143     {
144         GUI_Error_HIG(QT_TRANSLATE_NOOP("adm","Error"),QT_TRANSLATE_NOOP("adm","Core has been compiled without LIBVA support, but the application has been compiled with it.\nInstallation mismatch"));
145         libvaWorking=false;
146         return false;
147     }
148 
149     if(false==admLibVA::init(&xinfo)) return false;
150     libvaWorking=true;
151     { // Only check encoder if decoder is working
152        libvaEncoderWorking = ADM_initLibVAEncoder();
153 
154     }
155     if(libvaEncoderWorking)
156         ADM_info("LIBVA HW encoder is working\n");
157     else
158         ADM_info("LIBVA HW encoder is *NOT* working\n");
159     return true;
160 }
161 
162 /**
163     \fn markSurfaceUsed
164     \brief mark the surfave as used. Can be called multiple time.
165 */
markSurfaceUsed(ADM_vaSurface * s)166 bool decoderFFLIBVA::markSurfaceUsed(ADM_vaSurface *s)
167 {
168     imageMutex.lock();
169     s->refCount++;
170     imageMutex.unlock();
171     return true;
172 
173 }
markSurfaceUnused(VASurfaceID id)174 bool        decoderFFLIBVA::markSurfaceUnused(VASurfaceID id)
175 {
176     aprintf("Freeing surface %x\n",(int)id);
177     ADM_vaSurface *s=lookupBySurfaceId(id);
178     ADM_assert(s);
179     return markSurfaceUnused(s);
180 }
181 /**
182     \fn markSurfaceUnused
183     \brief mark the surfave as unused by the caller. Can be called multiple time.
184 */
markSurfaceUnused(ADM_vaSurface * img)185 bool decoderFFLIBVA::markSurfaceUnused(ADM_vaSurface *img)
186 {
187 
188    imageMutex.lock();
189    img->refCount--;
190    aprintf("Surface %x, Ref count is now %d\n",img->surface,img->refCount);
191    if(!img->refCount)
192    {
193         vaPool.freeSurfaceQueue.append(img);
194    }
195    imageMutex.unlock();
196    return true;
197 }
198 
199 /**
200     \fn ADM_LIBVAgetBuffer
201     \brief trampoline to get a LIBVA surface
202 */
ADM_LIBVAgetBuffer(AVCodecContext * avctx,AVFrame * pic,int flags)203 int ADM_LIBVAgetBuffer(AVCodecContext *avctx, AVFrame *pic,int flags)
204 {
205     decoderFF *ff=(decoderFF *)avctx->opaque;
206     decoderFFLIBVA *dec=(decoderFFLIBVA *)ff->getHwDecoder();
207     ADM_assert(dec);
208     return dec->getBuffer(avctx,pic);
209 }
210 
211 /**
212  * \fn ADM_XVBAreleaseBuffer
213  * @param avctx
214  * @param pic
215  */
ADM_LIBVAreleaseBuffer(void * opaque,uint8_t * data)216 void ADM_LIBVAreleaseBuffer(void *opaque, uint8_t *data)
217 {
218    decoderFFLIBVA *dec=(decoderFFLIBVA *)opaque;
219    ADM_assert(dec);
220    VASurfaceID   surface=*(VASurfaceID *)(data);
221    dec->markSurfaceUnused(surface);
222 }
223 
224 /**
225  *
226  * @param avctx
227  * @param pic
228  * @return
229  */
getBuffer(AVCodecContext * avctx,AVFrame * pic)230 int decoderFFLIBVA::getBuffer(AVCodecContext *avctx, AVFrame *pic)
231 {
232 
233     imageMutex.lock();
234     if(vaPool.freeSurfaceQueue.empty())
235     {
236         aprintf("Allocating new vaSurface\n");
237         ADM_vaSurface *img=allocateADMVaSurface(avctx);
238         if(!img)
239         {
240             imageMutex.unlock();
241             ADM_warning("Cannot allocate new vaSurface!\n");
242             return -1;
243         }
244         vaPool.freeSurfaceQueue.append(img);
245         vaPool.allSurfaceQueue.append(img);
246     }else
247     {
248         aprintf("Reusing vaSurface from pool\n");
249     }
250     ADM_vaSurface *s= vaPool.freeSurfaceQueue[0];
251     vaPool.freeSurfaceQueue.popFront();
252     imageMutex.unlock();
253     s->refCount=0;
254     markSurfaceUsed(s); // 1 ref taken by lavcodec
255 
256     pic->buf[0]=av_buffer_create((uint8_t *)&(s->surface),  // Maybe a memleak here...
257                                      sizeof(s->surface),
258                                      ADM_LIBVAreleaseBuffer,
259                                      (void *)this,
260                                      AV_BUFFER_FLAG_READONLY);
261 
262     aprintf("Alloc Buffer : 0x%llx, surfaceid=%x\n",s,(int)s->surface);
263     pic->data[0]=(uint8_t *)s;
264     pic->data[3]=(uint8_t *)(uintptr_t)s->surface;
265     pic->reordered_opaque= avctx->reordered_opaque;
266     return 0;
267 }
268 
269 /**
270     \fn libvaCleanup
271 */
libvaCleanup(void)272 bool libvaCleanup(void)
273 {
274    return admLibVA::cleanup();
275 }
276 
277 
278 /**
279  * \fn lookupBySurfaceId
280  * @param
281  * @return
282  */
lookupBySurfaceId(VASurfaceID id)283 ADM_vaSurface *decoderFFLIBVA::lookupBySurfaceId(VASurfaceID id)
284 {
285     aprintf("Looking up surface %x\n",(int)id);
286     imageMutex.lock();
287     int n=vaPool.allSurfaceQueue.size();
288     for(int i=0;i<n;i++)
289         if(vaPool.allSurfaceQueue[i]->surface==id)
290         {
291             imageMutex.unlock();
292             return vaPool.allSurfaceQueue[i];
293         }
294     imageMutex.unlock();
295     ADM_warning("Lookup a non existing surface\n");
296     ADM_assert(0);
297     return NULL;
298 
299 }
300 
301 
302 
303 
304 
305 extern "C"
306 {
307 
ADM_LIBVA_getFormat(struct AVCodecContext * avctx,const enum AVPixelFormat * fmt)308 static enum AVPixelFormat ADM_LIBVA_getFormat(struct AVCodecContext *avctx,  const enum AVPixelFormat *fmt)
309 {
310     int i;
311     ADM_info("[LIBVA]: GetFormat\n");
312     AVCodecID id=AV_CODEC_ID_NONE;
313     AVPixelFormat c;
314     AVPixelFormat outPix;
315     for(i=0;fmt[i]!=AV_PIX_FMT_NONE;i++)
316     {
317         c=fmt[i];
318         char name[300]={0};
319         av_get_pix_fmt_string(name,sizeof(name),c);
320         ADM_info("[LIBVA]: Evaluating PIX_FMT %d,%s\n",c,name);
321         av_get_codec_tag_string(name,sizeof(name),avctx->codec_id);
322         ADM_info("\t  Evaluating codec %d,%s\n",avctx->codec_id,name);
323 
324         if(c!=AV_PIX_FMT_VAAPI_VLD) continue;
325 #define FMT_V_CHECK(x,y)      case AV_CODEC_ID_##x:   outPix=AV_PIX_FMT_VAAPI_VLD;id=avctx->codec_id;break;
326 
327 
328         switch(avctx->codec_id)  //AV_CODEC_ID_H265
329         {
330             FMT_V_CHECK(H264,H264)
331             FMT_V_CHECK(H265,H265)
332             FMT_V_CHECK(MPEG1VIDEO,MPEG1)
333             FMT_V_CHECK(MPEG2VIDEO,MPEG2)
334             FMT_V_CHECK(WMV3,WMV3)
335             FMT_V_CHECK(VC1,VC1)
336             FMT_V_CHECK(VP9,VP9)
337             default:
338                 ADM_info("No hw support for format %d\n",avctx->codec_id);
339                 continue;
340                 break;
341         }
342         break;
343     }
344     if(id==AV_CODEC_ID_NONE)
345     {
346 
347         return AV_PIX_FMT_NONE;
348     }
349     // Finish intialization of LIBVA decoder
350 #if 0 // The lavc functions we rely on in ADM_acceleratedDecoderFF::parseHwAccel are no more
351     const AVHWAccel *accel=ADM_acceleratedDecoderFF::parseHwAccel(outPix,id,AV_PIX_FMT_VAAPI_VLD);
352     if(accel)
353     {
354         ADM_info("Found matching hw accelerator : %s\n",accel->name);
355         ADM_info("Successfully setup hw accel\n");
356         return AV_PIX_FMT_VAAPI_VLD;
357     }
358     return AV_PIX_FMT_NONE;
359 #endif
360     return AV_PIX_FMT_VAAPI_VLD;
361 }
362 }
363 
364 /**
365  *
366  * @param w
367  * @param h
368  * @param fcc
369  * @param extraDataLen
370  * @param extraData
371  * @param bpp
372  */
decoderFFLIBVA(AVCodecContext * avctx,decoderFF * parent)373 decoderFFLIBVA::decoderFFLIBVA(AVCodecContext *avctx,decoderFF *parent)
374 : ADM_acceleratedDecoderFF(avctx,parent)
375 {
376 
377 
378     alive=false;
379     _context->slice_flags     = SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
380 
381     for(int i=0;i<ADM_DEFAULT_SURFACE;i++)
382         initSurfaceID[i]=VA_INVALID;
383 
384     for(int i=0;i<ADM_DEFAULT_SURFACE;i++)
385     {
386         ADM_vaSurface *admSurface=allocateADMVaSurface(avctx);
387         if(!admSurface)
388         {
389             ADM_warning("Cannot allocate dummy surface\n");
390             alive=false;
391             return ;
392         }
393         aprintf("Created initial pool, %d : %x\n",i,admSurface->surface);
394         initSurfaceID[i]=admSurface->surface;
395         vaPool.allSurfaceQueue.append(admSurface);
396         vaPool.freeSurfaceQueue.append(admSurface);
397     }
398 
399 
400     // create decoder
401     vaapi_context *va_context=new vaapi_context;
402     memset(va_context,0,sizeof(*va_context)); // dangerous...
403 
404     VAProfile profile;
405     switch(avctx->codec_id)
406     {
407         default:
408         case AV_CODEC_ID_MPEG2VIDEO:
409                                 profile=VAProfileMPEG2Main;
410                                 break;
411 
412         case AV_CODEC_ID_H264:
413                                 profile=VAProfileH264High;
414                                 break;
415 #ifdef LIBVA_HEVC_DEC
416         case AV_CODEC_ID_H265:
417                                 profile=VAProfileHEVCMain; // TODO VAProfileHEVCMain10
418                                 break;
419 #endif
420 #ifdef LIBVA_VP9_DEC
421         case AV_CODEC_ID_VP9:
422                                 profile=VAProfileVP9Profile3;
423                                 break;
424 #endif
425         case AV_CODEC_ID_VC1:
426                                 profile=VAProfileVC1Advanced;
427                                 break;
428 
429     }
430 
431     va_context->context_id=admLibVA::createDecoder(profile,avctx->coded_width,avctx->coded_height,ADM_DEFAULT_SURFACE,initSurfaceID); // this is most likely wrong
432     if(va_context->context_id==VA_INVALID)
433     {
434         ADM_warning("Cannot create decoder\n");
435         delete va_context;
436         va_context=NULL;
437         alive=false;
438         return;
439     }
440 
441 
442     if(!admLibVA::fillContext(profile,va_context))
443     {
444         ADM_warning("Cannot get va context initialized for libavcodec\n");
445         alive=false;
446         return ;
447     }
448 
449     _context->hwaccel_context=va_context;
450     alive=true;
451     _context->get_buffer2     = ADM_LIBVAgetBuffer;
452     _context->draw_horiz_band = NULL;
453     ADM_info("Successfully setup LIBVA hw accel\n");
454 }
455 
456 /**
457  * \fn dtor
458  */
~decoderFFLIBVA()459 decoderFFLIBVA::~decoderFFLIBVA()
460 {
461     imageMutex.lock();
462     int m=vaPool.allSurfaceQueue.size();
463     int n=vaPool.freeSurfaceQueue.size();
464     if(n!=m)
465     {
466         ADM_warning("Some surfaces are not reclaimed! (%d/%d)\n",n,m);
467     }
468     for(int i=0;i<n;i++)
469     {
470         delete vaPool.freeSurfaceQueue[i];
471     }
472     vaPool.freeSurfaceQueue.clear();
473     imageMutex.unlock();
474 }
475 /**
476  * \fn uncompress
477  * \brief
478  * @param in
479  * @param out
480  * @return
481  */
uncompress(ADMCompressedImage * in,ADMImage * out)482 bool decoderFFLIBVA::uncompress (ADMCompressedImage * in, ADMImage * out)
483 {
484 
485     aprintf("==> uncompress %s\n",_context->codec->long_name);
486     if(out->refType==ADM_HW_LIBVA)
487     {
488             ADM_vaSurface *img=(ADM_vaSurface *)out->refDescriptor.refHwImage;
489             markSurfaceUnused(img);
490             out->refType=ADM_HW_NONE;
491     }
492 
493     if(!_parent->getDrainingState() && !in->dataLength) // Null frame, silently skipped
494     {
495         out->_noPicture = 1;
496         out->Pts=ADM_COMPRESSED_NO_PTS;
497         out->refType=ADM_HW_NONE;
498         ADM_info("[LibVa] Nothing to decode -> no Picture\n");
499         return false;
500     }
501 
502    // Put a safe value....
503     out->Pts=in->demuxerPts;
504     _context->reordered_opaque=in->demuxerPts;
505 
506     AVFrame *frame=_parent->getFramePointer();
507     ADM_assert(frame);
508 
509     if(_parent->getDrainingState())
510     {
511         if(_parent->getDrainingInitiated()==false)
512         {
513             avcodec_send_packet(_context, NULL);
514             _parent->setDrainingInitiated(true);
515         }
516     }else if(!handover)
517     {
518         AVPacket pkt;
519         av_init_packet(&pkt);
520         pkt.data=in->data;
521         pkt.size=in->dataLength;
522         if(in->flags&AVI_KEY_FRAME)
523             pkt.flags=AV_PKT_FLAG_KEY;
524         else
525             pkt.flags=0;
526 
527         avcodec_send_packet(_context, &pkt);
528     }else
529     {
530         handover=false;
531     }
532 
533     int ret = avcodec_receive_frame(_context, frame);
534 
535     if(!_parent->decodeErrorHandler(ret))
536         return false;
537 
538     if(frame->pict_type==AV_PICTURE_TYPE_NONE)
539     {
540         out->_noPicture=true;
541         out->refType=ADM_HW_NONE;
542         out->Pts= (uint64_t)(frame->reordered_opaque);
543         ADM_info("[LIBVA] No picture \n");
544         return false;
545     }
546     return readBackBuffer(frame,in,out);
547 }
548 /**
549  *
550  * @param decodedFrame
551  * @param in
552  * @param out
553  * @return
554  */
readBackBuffer(AVFrame * decodedFrame,ADMCompressedImage * in,ADMImage * out)555 bool     decoderFFLIBVA::readBackBuffer(AVFrame *decodedFrame, ADMCompressedImage * in, ADMImage * out)
556 {
557     uint64_t pts_opaque=(uint64_t)(decodedFrame->reordered_opaque);
558     out->Pts= (uint64_t)(pts_opaque);
559     out->flags=admFrameTypeFromLav(decodedFrame);
560     out->refType=ADM_HW_LIBVA;
561     out->refDescriptor.refCodec=this;
562     ADM_vaSurface *img=(ADM_vaSurface *)(decodedFrame->data[0]);
563     out->refDescriptor.refHwImage=img; // the ADM_vaImage in disguise
564     markSurfaceUsed(img); // one ref for us too, it will be free when the image is cycled
565     aprintf("ReadBack: Got image=%x surfaceId=%x\n",(int)(uintptr_t)decodedFrame->data[0],(int)img->surface);
566     out->refDescriptor.refMarkUsed=libvaMarkSurfaceUsed;
567     out->refDescriptor.refMarkUnused=libvaMarkSurfaceUnused;
568     out->refDescriptor.refDownload=libvaRefDownload;
569     return true;
570 }
571 
572 //---
573 
574 class ADM_hwAccelEntryLibVA : public ADM_hwAccelEntry
575 {
576 public:
577                             ADM_hwAccelEntryLibVA();
578      virtual bool           canSupportThis(struct AVCodecContext *avctx,  const enum AVPixelFormat *fmt,enum AVPixelFormat &outputFormat);
579      virtual                ADM_acceleratedDecoderFF *spawn( struct AVCodecContext *avctx,  const enum AVPixelFormat *fmt );
~ADM_hwAccelEntryLibVA()580      virtual                ~ADM_hwAccelEntryLibVA() {};
581 };
582 /**
583  *
584  */
ADM_hwAccelEntryLibVA()585 ADM_hwAccelEntryLibVA::ADM_hwAccelEntryLibVA()
586 {
587     name="VAAPI";
588 }
589 /**
590  *
591  * @param avctx
592  * @param fmt
593  * @param outputFormat
594  * @return
595  */
canSupportThis(struct AVCodecContext * avctx,const enum AVPixelFormat * fmt,enum AVPixelFormat & outputFormat)596 bool           ADM_hwAccelEntryLibVA::canSupportThis(struct AVCodecContext *avctx,  const enum AVPixelFormat *fmt,enum AVPixelFormat &outputFormat)
597 {
598     bool enabled=false;
599     prefs->get(FEATURES_LIBVA,&enabled);
600     if(!enabled)
601     {
602         ADM_info("LibVA not enabled\n");
603         return false;
604     }
605     enum AVPixelFormat ofmt=ADM_LIBVA_getFormat(avctx,fmt);
606     if(ofmt==AV_PIX_FMT_NONE)
607         return false;
608     outputFormat=ofmt;
609     ADM_info("This is maybe supported by LIBVA\n");
610     VAProfile profile=VAProfileNone;
611     switch(avctx->codec_id)
612     {
613        case AV_CODEC_ID_MPEG2VIDEO: profile= VAProfileMPEG2Main;break;
614        case AV_CODEC_ID_H264: profile= VAProfileH264High;break;
615 #ifdef LIBVA_HEVC_DEC
616        case AV_CODEC_ID_H265:
617            switch(avctx->pix_fmt)
618            {
619             case AV_PIX_FMT_YUV420P:
620                 profile= VAProfileHEVCMain;
621                 break;;
622             case AV_PIX_FMT_YUV420P10LE:
623                 ADM_info("10 bits H265\n");
624                 profile= VAProfileHEVCMain10;
625                 break;
626            default:
627                ADM_warning("FF/LibVa: unknown colorspace %d\n",(int)avctx->pix_fmt);
628                return false;
629                break;
630            }
631            break;
632 #endif
633        case AV_CODEC_ID_VC1: profile= VAProfileVC1Advanced;break;
634 #ifdef LIBVA_VP9_DEC
635        case AV_CODEC_ID_VP9: profile= VAProfileVP9Profile3;break;
636 #endif
637        default:
638            ADM_info("Unknown codec (libVA)\n");
639            return false;
640     }
641     if(!admLibVA::supported(profile))
642     {
643         ADM_warning("Not supported by libVA\n");
644         return false;
645     }
646     return true;
647 }
648 
649 
650 /**
651  *
652  * @param avctx
653  * @param fmt
654  * @return
655  */
spawn(struct AVCodecContext * avctx,const enum AVPixelFormat * fmt)656 ADM_acceleratedDecoderFF *ADM_hwAccelEntryLibVA::spawn( struct AVCodecContext *avctx,  const enum AVPixelFormat *fmt )
657 {
658     decoderFF *ff=(decoderFF *)avctx->opaque;
659     return new decoderFFLIBVA(avctx,ff);
660 }
661 static ADM_hwAccelEntryLibVA libvaEntry;
662 /**
663  *
664  * @return
665  */
initLIBVADecoder(void)666 bool initLIBVADecoder(void)
667 {
668     ADM_info("Registering LIBVA hw decoder\n");
669     ADM_hwAccelManager::registerDecoder(&libvaEntry);
670     return true;
671 }
672 
673 // EOF
674