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