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