1 /***************************************************************************
2     \file             : ADM_coreDXVA2.cpp
3     \brief            : Wrapper around DXVA2 functions
4     \author           : (C) 2016 by mean fixounet@free.fr
5 
6         This code is strongly derived from ffmpeg_dxva2 from ffmpeg
7 
8  ***************************************************************************/
9 
10 /***************************************************************************
11  *                                                                         *
12  *   This program is free software; you can redistribute it and/or modify  *
13  *   it under the terms of the GNU General Public License as published by  *
14  *   the Free Software Foundation; either version 2 of the License, or     *
15  *   (at your option) any later version.                                   *
16  *                                                                         *
17  ***************************************************************************/
18 #include "ADM_coreD3DApi.h" // Must be the 1st included
19 #include "ADM_default.h"
20 #include "ADM_coreD3D.h"
21 #ifdef USE_DXVA2
22 
23 #define DUMP_GUID
24 #if 0
25 #define aprintf printf
26 #else
27 #define aprintf(...) {}
28 #endif
29 
30 
31 
32 #include "ADM_dynamicLoading.h"
33 #include <map>
34 
35 #include "../include/ADM_coreDxva2.h"
36 
37 typedef IDirect3D9* WINAPI pDirect3DCreate9(UINT);
38 typedef HRESULT     WINAPI pCreateDeviceManager9(UINT *, IDirect3DDeviceManager9 **);
39 
40 static bool                  coreDxva2Working=false;
41 
42 static ADM_LibWrapper        dxva2DynaLoader;
43 
44 static pCreateDeviceManager9 *createDeviceManager = NULL;
45 
46 static IDirect3DDevice9            *d3d9device  =NULL;
47 static IDirect3DDeviceManager9     *d3d9devmgr  =NULL;
48 static IDirectXVideoDecoderService *decoder_service=NULL;
49 static HANDLE                       deviceHandle=INVALID_HANDLE_VALUE;
50 
51 #include <initguid.h>
52 DEFINE_GUID(IID_IDirectXVideoDecoderService, 0xfc51a551,0xd5e7,0x11d9,0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02);
53 
54 DEFINE_GUID(DXVA2_ModeMPEG2_VLD,      0xee27417f, 0x5e28,0x4e65,0xbe,0xea,0x1d,0x26,0xb5,0x08,0xad,0xc9);
55 DEFINE_GUID(DXVA2_ModeMPEG2and1_VLD,  0x86695f12, 0x340e,0x4f04,0x9f,0xd3,0x92,0x53,0xdd,0x32,0x74,0x60);
56 DEFINE_GUID(DXVA2_ModeH264_E,         0x1b81be68, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
57 DEFINE_GUID(DXVA2_ModeH264_F,         0x1b81be69, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
58 DEFINE_GUID(DXVADDI_Intel_ModeH264_E, 0x604F8E68, 0x4951,0x4C54,0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
59 DEFINE_GUID(DXVA2_ModeVC1_D,          0x1b81beA3, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
60 DEFINE_GUID(DXVA2_ModeVC1_D2010,      0x1b81beA4, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
61 DEFINE_GUID(DXVA2_ModeHEVC_VLD_Main,  0x5b11d51b, 0x2f4c,0x4452,0xbc,0xc3,0x09,0xf2,0xa1,0x16,0x0c,0xc0);
62 DEFINE_GUID(DXVA2_ModeVP9_VLD_Profile0, 0x463707f8, 0xa1d0,0x4585,0x87,0x6d,0x83,0xaa,0x6d,0x60,0xb8,0x9e);
63 DEFINE_GUID(DXVA2_NoEncrypt,          0x1b81beD0, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
64 DEFINE_GUID(DXVA2_ModeHEVC_VLD_Main10,0x107af0e0, 0xef1a,0x4d19,0xab,0xa8,0x67,0xa1,0x63,0x07,0x3d,0x13);
65 DEFINE_GUID(GUID_NULL,                0x00000000, 0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
66 /**
67  */
68 typedef struct dxva2_mode
69 {
70   const GUID     *guid;
71   enum AVCodecID codec;
72   int            bitsPerChannel;
73 } dxva2_mode;
74 /**
75  */
ALIGN(int x,int align,bool verbose=false)76 static int ALIGN(int x,int align,bool verbose=false)
77 {
78     int y= ((x+(align-1)) &(~(align-1)));
79     if(verbose)
80         printf("Align %d,%d => %d\n",x,align,y);
81     return y;
82 }
83 
84 /**
85  */
86 static const dxva2_mode dxva2_modes[] =
87 {
88     /* MPEG-2 */
89     { &DXVA2_ModeMPEG2_VLD,      AV_CODEC_ID_MPEG2VIDEO ,8},
90     { &DXVA2_ModeMPEG2and1_VLD,  AV_CODEC_ID_MPEG2VIDEO ,8},
91 
92     /* H.264 */
93     { &DXVA2_ModeH264_F,         AV_CODEC_ID_H264 ,8},
94     { &DXVA2_ModeH264_E,         AV_CODEC_ID_H264 ,8},
95     /* Intel specific H.264 mode */
96     { &DXVADDI_Intel_ModeH264_E, AV_CODEC_ID_H264 ,8},
97 
98     /* VC-1 / WMV3 */
99     { &DXVA2_ModeVC1_D2010,      AV_CODEC_ID_VC1  ,8},
100     { &DXVA2_ModeVC1_D2010,      AV_CODEC_ID_WMV3 ,8},
101     { &DXVA2_ModeVC1_D,          AV_CODEC_ID_VC1  ,8},
102     { &DXVA2_ModeVC1_D,          AV_CODEC_ID_WMV3 ,8},
103 
104     /* HEVC/H.265 */
105     { &DXVA2_ModeHEVC_VLD_Main,   AV_CODEC_ID_HEVC ,8},
106     { &DXVA2_ModeHEVC_VLD_Main10, AV_CODEC_ID_HEVC ,10},
107 
108     /* VP8/9 */
109     { &DXVA2_ModeVP9_VLD_Profile0,AV_CODEC_ID_VP9 ,8},
110 
111     { NULL,                      (AVCodecID)0 ,0},
112 };
113 typedef struct
114 {
115      enum AVCodecID  codec;
116      bool            enabled;
117      DXVA2_VideoDesc desc;
118      DXVA2_ConfigPictureDecode pictureDecode;
119            GUID      device_guid;
120            GUID      guid;
121 }Dxv2SupportMap;
122 
123 static Dxv2SupportMap dxva2H265={AV_CODEC_ID_HEVC,false};
124 static Dxv2SupportMap dxva2H264={AV_CODEC_ID_H264,false};
125 static Dxv2SupportMap dxva2H265_10Bits={AV_CODEC_ID_HEVC,false};
126 
127 /**
128   \fn dxvaBitsToFormat
129   \brief returns D3D format depending on bits per component
130 */
dxvaBitsToFormat(int bits)131 static D3DFORMAT dxvaBitsToFormat(int bits)
132 {
133   switch(bits)
134   {
135     case 8: return (D3DFORMAT)MKTAG('N','V','1','2');break;
136     case 10:return (D3DFORMAT)MKTAG('P','0','1','0');break;
137     default:
138         ADM_assert(0); break;
139   }
140   return (D3DFORMAT)MKTAG('N','V','1','2');
141 }
142 /**
143  */
dumpGUID(const char * name,const GUID & guid)144 static void dumpGUID(const char *name,const GUID &guid)
145 {
146     printf("%s :\n",name);
147     printf("0x%lx 0x%lx 0x%lx ",guid.Data1,guid.Data2,guid.Data3);
148     for(int i=0;i<8;i++) printf(" %02x ",guid.Data4[i]);
149     printf("\n");
150 }
151 
152 /**
153  */
ADM_FAILED(HRESULT hr)154 static bool ADM_FAILED(HRESULT hr)
155 {
156     int r=(int)hr;
157     if(r<0)
158     {
159         ADM_warning("Failed with error code=0x%x\n",r);
160         return true;
161     }
162     return false;
163 }
164 /**
165   \fn checkDecoder
166   \brief check if the decoder advertised is actually working
167 */
checkDecoderConfiguration(const GUID * guid,Dxv2SupportMap * context)168 static bool checkDecoderConfiguration(  const GUID *guid,Dxv2SupportMap *context)
169 {
170     HRESULT hr;
171     unsigned int cfg_count = 0, best_score = 0;
172     DXVA2_ConfigPictureDecode *cfg_list = NULL;
173     bool   found=false;
174     const D3DFORMAT target_format = (const D3DFORMAT) MKTAG('N','V','1','2');
175 
176     // initialize desc with dummy values
177     context->desc.SampleWidth=1920;
178     context->desc.SampleHeight=1080;
179     context->desc.Format=target_format;
180 
181     hr = D3DCall(IDirectXVideoDecoderService,GetDecoderConfigurations,decoder_service, *guid, &(context->desc), NULL, &cfg_count, &cfg_list);
182     if (ADM_FAILED(hr)) {
183         ADM_warning("Unable to retrieve decoder configurations\n");
184         return false;
185     }
186 
187     for (int i = 0; i < cfg_count; i++)
188     {
189         DXVA2_ConfigPictureDecode *cfg = &cfg_list[i];
190 
191         unsigned score;
192         if (cfg->ConfigBitstreamRaw == 1)
193         {
194             ADM_info("\t has raw bistream\n");
195             score = 1;
196         }
197         else if (context->codec == AV_CODEC_ID_H264 && cfg->ConfigBitstreamRaw == 2)
198         {
199             ADM_info("\t has h264 raw bistream2\n");
200             score = 2;
201         }
202         else
203             continue;
204         if (IsEqualGUID(cfg->guidConfigBitstreamEncryption, DXVA2_NoEncrypt))
205         {
206             ADM_info("\t has no encrypt\n");
207             score += 16;
208         }
209         if (score > best_score)
210         {
211             best_score    = score;
212             context->pictureDecode = *cfg;
213             found=true;
214             ADM_info("\t best score\n");
215         }
216     }
217     CoTaskMemFree(cfg_list);
218 
219     if (! found )
220     {
221         ADM_warning( "No valid decoder configuration available\n");
222         return false;
223     }
224     return true;
225 }
226 /**
227  * \fn lookupCodec
228  * \brief find and populate the configuration for a given codec
229  */
lookupCodec(const char * codecName,Dxv2SupportMap * context,unsigned int guid_count,GUID * guid_list,int bitsPerComponent)230 static bool lookupCodec(const char *codecName,Dxv2SupportMap *context,unsigned int guid_count,GUID *guid_list, int bitsPerComponent)
231 {
232     HRESULT hr;
233     D3DFORMAT target_format = (D3DFORMAT) 0;
234 
235     for (int i = 0; dxva2_modes[i].guid; i++)
236     {
237         D3DFORMAT *target_list = NULL;
238         unsigned target_count = 0;
239         const dxva2_mode *mode = &dxva2_modes[i];
240         if (mode->codec != context->codec)
241             continue;
242         int j;
243         for (j = 0; j < guid_count; j++)
244         {
245             if (IsEqualGUID( *(mode->guid), guid_list[j]))
246                 break;
247         }
248 #ifdef DUMP_GUID
249     dumpGUID("Potential device_guid",*(mode->guid));
250 #endif
251 
252         if (j == guid_count)
253             continue;
254 
255         hr = D3DCall(IDirectXVideoDecoderService,GetDecoderRenderTargets,decoder_service,*( mode->guid), &target_count, &target_list);
256         if (ADM_FAILED(hr))
257         {
258             continue;
259         }
260         D3DFORMAT tgt;
261         tgt=dxvaBitsToFormat(bitsPerComponent);
262         for (j = 0; j < target_count; j++)
263         {
264             const D3DFORMAT format = target_list[j];
265             if (format ==tgt)
266             {
267                 target_format = format;
268                 break;
269             }
270         }
271 
272         CoTaskMemFree(target_list);
273         if (target_format)
274         {
275             if(checkDecoderConfiguration(mode->guid,context)) // does it work ?
276             {
277               context->device_guid = *(mode->guid);
278               break;
279             }
280         }
281     }
282 
283     // Did we find a working one ?
284     if (IsEqualGUID(context->device_guid, GUID_NULL))
285     {
286         ADM_info("No decoder device for codec %s found\n",codecName);
287         return false;
288     }
289 
290     //--
291 
292     ADM_info("DXVA2 support for  %s found\n",codecName);
293     context->enabled=true;
294     return true;
295 }
296 /**
297  * \fn init
298  * \brief initialize the low level common part of dxva2
299  */
init(GUI_WindowInfo * x)300 bool admDxva2::init(GUI_WindowInfo *x)
301 {
302    if(!admD3D::isOperationnal())
303    {
304      ADM_warning("No D3D, skipping DXVA2\n");
305      return false;
306    }
307    if(!admD3D::getDevice())
308    {
309      ADM_warning("No D3D device, skipping DXVA2\n");
310      return false;
311    }
312     UINT adapter = D3DADAPTER_DEFAULT;
313     D3DDISPLAYMODE        d3ddm;
314     D3DPRESENT_PARAMETERS d3dpp = {0};
315 
316     HRESULT hr;
317     unsigned int resetToken = 0;
318 
319     // Load dxva2 dll
320     if(false==dxva2DynaLoader.loadLibrary("dxva2.dll"))
321     {
322         ADM_warning("Dxva2: Cannot load dxva2.dll\n");
323         goto failInit;
324     }
325 
326     createDeviceManager=(pCreateDeviceManager9 *)dxva2DynaLoader.getSymbol("DXVA2CreateDirect3DDeviceManager9");
327     if(!createDeviceManager)
328     {
329         ADM_warning("Dxva2: Cannot get symbol  createDeviceManager\n");
330         goto failInit;
331     }
332     hr = createDeviceManager(&resetToken, &d3d9devmgr);
333     if (ADM_FAILED(hr))
334     {
335         ADM_warning( "Failed to create Direct3D device manager\n");
336         goto failInit;
337     }
338     hr = D3DCall(IDirect3DDeviceManager9,ResetDevice,d3d9devmgr, admD3D::getDevice(), resetToken);
339     if (ADM_FAILED(hr))
340     {
341         ADM_warning( "Failed to bind Direct3D device to device manager\n");
342         goto failInit;
343     }
344     ADM_info("Dxva2 init step1\n");
345     hr = D3DCall(IDirect3DDeviceManager9,OpenDeviceHandle,d3d9devmgr, &deviceHandle);
346     if (ADM_FAILED(hr)) {
347          ADM_warning("Failed to open device handle\n");
348         goto failInit;
349     }
350 
351     hr = D3DCall(IDirect3DDeviceManager9,GetVideoService,d3d9devmgr, deviceHandle, (REFIID )IID_IDirectXVideoDecoderService, (void **)&decoder_service);
352     if (ADM_FAILED(hr)) {
353         ADM_warning("Failed to create IDirectXVideoDecoderService\n");
354         goto failInit;
355     }
356 
357     coreDxva2Working=true;
358     ADM_info("Dxva2 core successfully initialized\n");
359     ADM_info("Decoder service=%p\n",decoder_service);
360     // Look up what is supported
361     {
362         unsigned int guid_count = 0;
363         GUID *guid_list = NULL;
364 
365         hr = D3DCall(IDirectXVideoDecoderService,GetDecoderDeviceGuids,decoder_service, &guid_count, &guid_list);
366         if (ADM_FAILED(hr)) {
367             ADM_warning("Failed to retrieve decoder device GUIDs\n");
368             goto failInit;
369         }
370         lookupCodec("H264",&dxva2H264,guid_count,guid_list,8);
371         lookupCodec("H265",&dxva2H265,guid_count,guid_list,8);
372         lookupCodec("H265",&dxva2H265_10Bits,guid_count,guid_list,10);
373         CoTaskMemFree(guid_list);
374     }
375     ADM_info("Scanning supported format done\n");
376     return true;
377 failInit:
378     // cleanup
379     cleanup();
380     return false;
381 }
382 /**
383  */
duplicateForMe(IDirect3DDevice9 * me)384 admDx2Surface         *admDx2Surface::duplicateForMe(IDirect3DDevice9 *me)
385 {
386 #if 0
387     HRESULT hr;
388     LPDIRECT3DSURFACE9 surfaces=NULL;
389     HANDLE sh=NULL;
390     sh=this->sharedHandle;
391     if(!sh)
392         return NULL;
393     hr = D3DCall(IDirect3DDevice9Ex,CreateOffscreenPlainSurface,
394                                                    (IDirect3DDevice9Ex *)me,
395                                                    this->width,
396                                                    this->height,
397                                                    this->format,
398                                                    D3DPOOL_DEFAULT,
399                                                    &surfaces, &sh);
400     if(ADM_FAILED(hr))
401     {
402         ADM_warning("Cannot duplicate surface\n");
403         return NULL;
404      }
405     admDx2Surface *s=new admDx2Surface(this->parent,this->alignment);
406     s->width=this->width;
407     s->height=this->height;
408     s->parent=NULL;
409     s->sharedHandle=NULL;
410     s->surface=surfaces;
411     return s;
412 #endif
413 return NULL;
414 }
415 
416 /**
417  */
allocateDecoderSurface(void * parent,int w,int h,int align,int num,LPDIRECT3DSURFACE9 * surfaces,std::vector<admDx2Surface * > & listOf,int bits)418 bool admDxva2::allocateDecoderSurface(void *parent,int w, int h,int align,int num, LPDIRECT3DSURFACE9 *surfaces, std::vector<admDx2Surface *>&listOf,int bits)
419 {
420     HRESULT hr;
421     HANDLE sh=NULL;
422     int width=ALIGN(w,align);
423     int height=ALIGN(h,align);
424     D3DFORMAT fmt;
425     fmt=dxvaBitsToFormat(bits);
426 
427     bool share=admD3D::isDirect9Ex();
428     if(share)
429     {
430      hr = D3DCall(IDirectXVideoDecoderService,CreateSurface,decoder_service,
431                                                    width,
432                                                    height,
433                                                    num-1,
434                                                    fmt, D3DPOOL_DEFAULT, 0,
435                                                    DXVA2_VideoDecoderRenderTarget,
436                                                    surfaces, &sh);
437         if(ADM_FAILED(hr))
438         {
439             // Requesting resource sharing on Windows 7 may result in a failure to allocate surfaces.
440             // On Windows 10, not requesting a shared handle seems to impact energy efficiency.
441             ADM_warning("Cannot allocate D3D9 surfaces with resource sharing, retrying without.\n");
442             share=false;
443         }
444     }
445     if(!share)
446     {
447      hr = D3DCall(IDirectXVideoDecoderService,CreateSurface,decoder_service,
448                                                    width,
449                                                    height,
450                                                    num-1,
451                                                    fmt, D3DPOOL_DEFAULT, 0,
452                                                    DXVA2_VideoDecoderRenderTarget,
453                                                    surfaces, NULL);
454     }
455      if(ADM_FAILED(hr))
456      {
457          ADM_warning("Cannot allocate D3D9 surfaces\n");
458          return false;
459      }
460      ADM_info("Allocated surface %p with shared handle=%p\n",surfaces,sh);
461      for(int i=0;i<num;i++)
462      {
463          admDx2Surface *s=new admDx2Surface(parent,align);
464          s->surface=surfaces[i];
465          s->width=width;
466          s->height=height;
467          s->format=fmt;
468          s->sharedHandle=sh;
469          listOf.push_back(s);
470      }
471      return true;
472 }
473 /**
474  */
destroyD3DSurface(int num,void * zsurfaces)475 bool admDxva2::destroyD3DSurface(int num, void *zsurfaces)
476 {
477     LPDIRECT3DSURFACE9 *surfaces=(LPDIRECT3DSURFACE9 *)zsurfaces;
478     for(int i=0;i<num;i++)
479     {
480          if (surfaces[i])
481          {
482                 D3DCallNoArg(IDirect3DSurface9,Release,surfaces[i]);
483                 surfaces[i]=NULL;
484          }
485     }
486     return true;
487 }
488 
489 /**
490     \fn isOperationnal
491 */
isOperationnal(void)492 bool admDxva2::isOperationnal(void)
493 {
494     ADM_warning("This binary has no working DXVA2 support\n");
495     return coreDxva2Working;
496 }
497 /**
498  */
cleanup(void)499 bool admDxva2::cleanup(void)
500 {
501     ADM_warning("This binary has no DXVA2 support\n");
502 
503     if (decoder_service)
504     {
505         D3DCallNoArg(IDirectXVideoDecoderService,Release,decoder_service);
506         decoder_service=NULL;
507     }
508     if (d3d9devmgr && deviceHandle != INVALID_HANDLE_VALUE)
509     {
510         D3DCall(IDirect3DDeviceManager9,CloseDeviceHandle,d3d9devmgr, deviceHandle);
511         deviceHandle=INVALID_HANDLE_VALUE;
512     }
513 
514     if (d3d9devmgr)
515     {
516         D3DCallNoArg(IDirect3DDeviceManager9,Release,d3d9devmgr);
517         d3d9devmgr  =NULL;
518     }
519 
520     if (d3d9device)
521     {
522         D3DCallNoArg(IDirect3DDevice9,Release,d3d9device);
523         d3d9device  =NULL;
524     }
525 
526 
527     coreDxva2Working=false;
528 
529     // small memleak  d3dDynaLoader;
530     // small memleak dxva2DynaLoader;
531     return true;
532 }
533 /**
534  *
535  */
supported(AVCodecID codec,int bits)536 bool        admDxva2::supported(AVCodecID codec,int bits)
537 {
538 #define SUPSUP(a,b,c) if(codec==a && bits==c) return (b.enabled) ;
539     SUPSUP(AV_CODEC_ID_H264,dxva2H264,8)
540     SUPSUP(AV_CODEC_ID_HEVC,dxva2H265,8)
541     SUPSUP(AV_CODEC_ID_HEVC,dxva2H265_10Bits,10)
542     return false;
543 }
544 /**
545  * \fn getDecoderConfig
546  */
getDecoderConfig(AVCodecID codec,int bits)547 DXVA2_ConfigPictureDecode *admDxva2::getDecoderConfig(AVCodecID codec,int bits)
548 {
549     Dxv2SupportMap *cmap;
550     switch(codec)
551     {
552         case AV_CODEC_ID_H264: cmap=&dxva2H264;break;
553         case AV_CODEC_ID_H265:
554               if(10==bits)
555                 cmap=&dxva2H265_10Bits;
556               else
557                 cmap=&dxva2H265;
558               break;
559         default:
560             ADM_assert(0);
561             break;
562     }
563     if(!cmap->enabled)
564     {
565         ADM_warning("This decoder is not enabled\n");
566         ADM_assert(0);
567     }
568     return &(cmap->pictureDecode);
569 }
570 
571 /**
572  * \fn createDecoder
573  */
createDecoder(AVCodecID codec,int with,int height,int numSurface,LPDIRECT3DSURFACE9 * surface,int align,int bits)574 IDirectXVideoDecoder  *admDxva2::createDecoder(AVCodecID codec, int with, int height, int numSurface, LPDIRECT3DSURFACE9 *surface,int align,int bits)
575 {
576     Dxv2SupportMap *cmap;
577     int paddedWidth=ALIGN(with,align,true);
578     int paddedHeight=ALIGN(height,align,true);
579     switch(codec)
580     {
581         case AV_CODEC_ID_H264:
582                 ADM_info("Creating decoder DXVA2/H264/8 Bits\n");
583                 cmap=&dxva2H264;
584                 break;
585         case AV_CODEC_ID_H265:
586                 if(bits==10)
587                 {
588                     ADM_info("Creating decoder DXVA2/H264/10 Bits\n");
589                     cmap=&dxva2H265_10Bits;
590                 }
591                 else
592                 {
593                     ADM_info("Creating decoder DXVA2/H264/8 Bits\n");
594                     cmap=&dxva2H265;
595                 }
596                 break;
597         default:
598             ADM_assert(0);
599             break;
600     }
601     if(!cmap->enabled)
602     {
603         ADM_warning("This decoder is not enabled\n");
604         ADM_assert(0);
605     }
606     HRESULT hr;
607     IDirectXVideoDecoder *decoder=NULL;
608 #ifdef DUMP_GUID
609     dumpGUID("device_guid",cmap->device_guid);
610     dumpGUID("       guid",cmap->guid);
611     printf("Decoder service = %p\n",decoder_service);
612 
613 #endif
614     // update with real values
615     cmap->desc.SampleWidth=paddedWidth; // does not work with multiple video ?
616     cmap->desc.SampleHeight=paddedHeight;
617     //
618     hr = D3DCall(IDirectXVideoDecoderService,CreateVideoDecoder,decoder_service,
619                                                          (cmap->device_guid),
620                                                          &(cmap->desc),
621                                                          &(cmap->pictureDecode),
622                                                          surface,
623                                                          numSurface,
624                                                          &decoder);
625      if(ADM_FAILED(hr))
626      {
627          ADM_warning("Cannot create decoder\n");
628          return NULL;
629      }
630      return decoder;
631 }
632 /**
633  * \fn createDecoder
634  */
destroyDecoder(IDirectXVideoDecoder * decoder)635 bool admDxva2::destroyDecoder(IDirectXVideoDecoder *decoder)
636 {
637     D3DCallNoArg(IDirectXVideoDecoder,Release,decoder);
638     return true;
639 }
640 
641 /**
642  * \fn admLibVa_exitCleanup
643  */
admDxva2_exitCleanup()644 bool admDxva2_exitCleanup()
645 {
646     ADM_info("Dxva2 cleanup begin\n");
647     admDxva2::cleanup();
648     ADM_info("Dxva2 cleanup end\n");
649     return true;
650 }
651 /**
652  * \fn ctor
653  */
admDx2Surface(void * par,int alig)654 admDx2Surface::admDx2Surface(void *par,int alig)
655 {
656     parent=par;
657     alignment=alig;
658     surface=NULL;
659     decoder=NULL;
660     refCount=0;
661     color10Bits=NULL;
662     width=height=0;
663     format=D3DFMT_UNKNOWN;
664     sharedHandle=NULL;
665 }
666 /**
667  * \fn dtor
668  */
~admDx2Surface()669 admDx2Surface::~admDx2Surface()
670 {
671     parent=NULL;
672     surface=NULL;
673     decoder=NULL;
674     if(color10Bits)
675     {
676         delete color10Bits;
677         color10Bits=NULL;
678     }
679 }
680 /**
681  * \fn addRef
682  */
addRef()683 bool admDx2Surface::addRef()
684 {
685     D3DCallNoArg(IDirect3DSurface9,AddRef,surface);
686     return true;
687 }
688 /**
689  * \fn removeRef
690  */
removeRef()691 bool admDx2Surface::removeRef()
692 {
693      D3DCallNoArg(IDirect3DSurface9,Release,surface); // ???
694      return true;
695 }
696 
697 
698 /**
699  * \fn ADM_DXVA2_readBack
700  */
surfaceToAdmImage(ADMImage * out)701 bool  admDx2Surface::surfaceToAdmImage( ADMImage *out)
702 {
703     D3DSURFACE_DESC    surfaceDesc;
704     D3DLOCKED_RECT     LockedRect;
705     HRESULT            hr;
706     int bits=8;
707     bool r=true;
708     D3DCall(IDirect3DSurface9,GetDesc,surface, &surfaceDesc);
709     if(surfaceDesc.Format==(D3DFORMAT)MKTAG('P','0','1','0'))
710     {
711       bits=10;
712     }
713     aprintf("Surface to admImage = %p\n",surface);
714     hr = D3DCall(IDirect3DSurface9,LockRect,surface, &LockedRect, NULL, D3DLOCK_READONLY);
715     if (ADM_FAILED(hr))
716     {
717         ADM_warning("Unable to lock DXVA2 surface\n");
718         return false;
719     }
720     aprintf("Retrieving image pitch=%d width=%d height=%d\n",LockedRect.Pitch,out->GetWidth(PLANAR_Y), out->GetHeight(PLANAR_Y));
721 
722     uint8_t *data=(uint8_t*)LockedRect.pBits;
723     int sourcePitch=LockedRect.Pitch;
724     switch(bits)
725     {
726       case 8:   out->convertFromNV12(data,data+sourcePitch*ALIGN(out->GetHeight(PLANAR_Y),alignment), sourcePitch, sourcePitch);
727                 break;
728       case 10:
729               {
730               if(!color10Bits)
731                     color10Bits=new ADMColorScalerSimple(out->GetWidth(PLANAR_Y),out->GetHeight(PLANAR_Y),ADM_COLOR_NV12_10BITS,ADM_COLOR_YV12);
732               ADMImageRef ref(out->GetWidth(PLANAR_Y),out->GetHeight(PLANAR_Y));
733               ADMImageRefWrittable target(out->GetWidth(PLANAR_Y),out->GetHeight(PLANAR_Y));
734               ref._planes[0]=data;
735               ref._planeStride[0]=sourcePitch;
736               ref._planes[1]=data+((surfaceDesc.Height)*sourcePitch);
737               ref._planeStride[1]=sourcePitch;
738               ref._planes[2]=NULL;
739               ref._planeStride[2]=0;
740               // U &  V are inverted...
741               for(int i=0;i<3;i++)
742               {
743                   int j=i;
744                   if(j) j=j^3;
745                   target._planes[j]=out->GetWritePtr((ADM_PLANE)i);
746                   target._planeStride[j]=out->_planeStride[i];
747               }
748               color10Bits->convertImage(&ref,&target);
749               }
750               break;
751 
752       default: ADM_warning("Unsupported bit depth");break;
753     }
754     D3DCallNoArg(IDirect3DSurface9,UnlockRect,surface);
755     return r;
756 }
757 
758 /**
759  */
decoderAddRef(IDirectXVideoDecoder * decoder)760 bool admDxva2::decoderAddRef(IDirectXVideoDecoder *decoder)
761 {
762     HRESULT            hr=D3DCallNoArg(IDirectXVideoDecoder,AddRef,decoder);
763     return true;
764 }
765 /**
766  */
decoderRemoveRef(IDirectXVideoDecoder * decoder)767 bool admDxva2::decoderRemoveRef(IDirectXVideoDecoder *decoder)
768 {
769     HRESULT            hr=D3DCallNoArg(IDirectXVideoDecoder,Release,decoder);
770     return true;
771 }
772 
773 
774 #endif
775 // EOF
776