Skip to content
This repository
Browse code

added: intial dxva2 decoder support for vc1/h264

Decoder is not enabled by default as it still has issues.

Working:
VC1 has worked for all samples i've tried (not that many)
x264 encoded h264 all seem to work fine

Known issues:
Apple encoded h264 => green screen or corrupt green screen
Raw blueray h264 => weird corruption of bottom half of video

git-svn-id: https://xbmc.svn.sourceforge.net/svnroot/xbmc/trunk@27376 568bbfeb-2a22-0410-94d2-cc84cf5bfa90
  • Loading branch information...
commit a829e510f0df637679ce6bc42a698c90c93e2869 1 parent 3805a54
authored February 02, 2010
3  language/English/strings.xml
@@ -2186,4 +2186,7 @@
2186 2186
   <string id="34000">Lame</string>
2187 2187
   <string id="34001">Vorbis</string>
2188 2188
   <string id="34002">Wav</string>
  2189
+  <string id="34003">DXVA</string>
  2190
+
  2191
+
2189 2192
 </strings>
8  project/VS2008Express/XBMC.vcproj
@@ -1051,6 +1051,14 @@
1051 1051
 								>
1052 1052
 							</File>
1053 1053
 						</Filter>
  1054
+						<File
  1055
+							RelativePath="..\..\xbmc\cores\dvdplayer\DVDCodecs\Video\DXVA.cpp"
  1056
+							>
  1057
+						</File>
  1058
+						<File
  1059
+							RelativePath="..\..\xbmc\cores\dvdplayer\DVDCodecs\Video\DXVA.h"
  1060
+							>
  1061
+						</File>
1054 1062
 					</Filter>
1055 1063
 					<Filter
1056 1064
 						Name="Overlay"
4  xbmc/GUISettings.cpp
@@ -545,6 +545,10 @@ void CGUISettings::Initialize()
545 545
   if (CCrystalHD::GetInstance()->DevicePresent())
546 546
     renderers.insert(make_pair(13425, RENDER_METHOD_CRYSTALHD));
547 547
 #endif
  548
+
  549
+#ifdef HAS_DX
  550
+  renderers.insert(make_pair(34003, RENDER_METHOD_DXVA));
  551
+#endif
548 552
   AddInt(3, "videoplayer.rendermethod", 13415, RENDER_METHOD_AUTO, renderers, SPIN_CONTROL_TEXT);
549 553
 
550 554
 #ifdef HAS_GL
1  xbmc/GUISettings.h
@@ -35,6 +35,7 @@ class TiXmlElement;
35 35
 #define RENDER_METHOD_SOFTWARE  3
36 36
 #define RENDER_METHOD_VDPAU     4
37 37
 #define RENDER_METHOD_CRYSTALHD 5
  38
+#define RENDER_METHOD_DXVA      6
38 39
 #define RENDER_OVERLAYS         99   // to retain compatibility
39 40
 
40 41
 // Scaling options.
2  xbmc/cores/VideoRenderers/RenderFlags.h
@@ -50,5 +50,5 @@
50 50
 #define CONF_FLAGS_FORMAT_NV12   0x02000
51 51
 #define CONF_FLAGS_FORMAT_UYVY   0x04000 /* place holder for future expansion */
52 52
 #define CONF_FLAGS_FORMAT_YUY2   0x08000 /* place holder for future expansion */
53  
-
  53
+#define CONF_FLAGS_FORMAT_DXVA   0x10000
54 54
 #endif
9  xbmc/cores/VideoRenderers/RenderManager.h
@@ -82,6 +82,15 @@ class CXBMCRenderManager
82 82
   unsigned int PreInit();
83 83
   void UnInit();
84 84
 
  85
+#ifdef HAS_DX
  86
+  void AddProcessor(DXVA::CProcessor* processor, int64_t id)
  87
+  {
  88
+    CSharedLock lock(m_sharedSection);
  89
+    if (m_pRenderer)
  90
+      m_pRenderer->AddProcessor(processor, id);
  91
+  }
  92
+#endif
  93
+
85 94
   void AddOverlay(CDVDOverlay* o, double pts)
86 95
   {
87 96
     CSharedLock lock(m_sharedSection);
57  xbmc/cores/VideoRenderers/WinRenderer.cpp
@@ -33,6 +33,7 @@
33 33
 #include "FileSystem/File.h"
34 34
 #include "MathUtils.h"
35 35
 #include "VideoShaders/ConvolutionKernels.h"
  36
+#include "cores/dvdplayer/DVDCodecs/Video/DXVA.h"
36 37
 
37 38
 // http://www.martinreddy.net/gfx/faqs/colorconv.faq
38 39
 
@@ -143,6 +144,17 @@ int CWinRenderer::NextYV12Texture()
143 144
     return -1;
144 145
 }
145 146
 
  147
+void CWinRenderer::AddProcessor(DXVA::CProcessor* processor, int64_t id)
  148
+
  149
+{
  150
+  int source = NextYV12Texture();
  151
+  if(source < 0)
  152
+    return;
  153
+  m_Processor[source].Clear();
  154
+  m_Processor[source].proc = processor->Acquire();
  155
+  m_Processor[source].id   = id;
  156
+}
  157
+
146 158
 int CWinRenderer::GetImage(YV12Image *image, int source, bool readonly)
147 159
 {
148 160
   /* take next available buffer */
@@ -218,6 +230,8 @@ void CWinRenderer::FlipPage(int source)
218 230
   if(source == AUTOSOURCE)
219 231
     source = NextYV12Texture();
220 232
 
  233
+  m_Processor[m_iYV12RenderBuffer].Clear();
  234
+
221 235
   if( source >= 0 && source < m_NumYV12Buffers )
222 236
     m_iYV12RenderBuffer = source;
223 237
   else
@@ -329,7 +343,10 @@ void CWinRenderer::UnInit()
329 343
   m_bFilterInitialized = false;
330 344
 
331 345
   for(int i = 0; i < NUM_BUFFERS; i++)
  346
+  {
332 347
     DeleteYV12Texture(i);
  348
+    m_Processor[i].Clear();
  349
+  }
333 350
 
334 351
   m_NumYV12Buffers = 0;
335 352
 }
@@ -455,6 +472,12 @@ void CWinRenderer::UpdateVideoFilter()
455 472
 
456 473
 void CWinRenderer::Render(DWORD flags)
457 474
 {
  475
+  if(CONF_FLAGS_FORMAT_MASK(m_flags) == CONF_FLAGS_FORMAT_DXVA)
  476
+  {
  477
+    CWinRenderer::RenderProcessor(flags);
  478
+    return;
  479
+  }
  480
+
458 481
   UpdateVideoFilter();
459 482
 
460 483
   //If the GUI is active or we don't need scaling use the bilinear filter.
@@ -642,6 +665,31 @@ void CWinRenderer::RenderLowMem(CD3DEffect &effect, DWORD flags)
642 665
   pD3DDevice->SetPixelShader( NULL );
643 666
 }
644 667
 
  668
+void CWinRenderer::RenderProcessor(DWORD flags)
  669
+{
  670
+  CSingleLock lock(g_graphicsContext);
  671
+  RECT rect;
  672
+  rect.top    = m_destRect.y1;
  673
+  rect.bottom = m_destRect.y2;
  674
+  rect.left   = m_destRect.x1;
  675
+  rect.right  = m_destRect.x2;
  676
+
  677
+  SProcessImage& image = m_Processor[m_iYV12RenderBuffer];
  678
+  if(image.proc == NULL)
  679
+    return;
  680
+
  681
+  IDirect3DSurface9* target;
  682
+  if(FAILED(g_Windowing.Get3DDevice()->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &target)))
  683
+  {
  684
+    CLog::Log(LOGERROR, "CWinRenderer::RenderSurface - failed to get back buffer");
  685
+    return;
  686
+  }
  687
+
  688
+  image.proc->Render(rect, target, image.id);
  689
+
  690
+  target->Release();
  691
+}
  692
+
645 693
 void CWinRenderer::CreateThumbnail(CBaseTexture *texture, unsigned int width, unsigned int height)
646 694
 {
647 695
   CSingleLock lock(g_graphicsContext);
@@ -768,6 +816,13 @@ bool CWinRenderer::Supports(ESCALINGMETHOD method)
768 816
   return false;
769 817
 }
770 818
 
  819
+void CWinRenderer::SProcessImage::Clear()
  820
+{
  821
+  SAFE_RELEASE(proc);
  822
+  id = 0;
  823
+}
  824
+
  825
+
771 826
 CPixelShaderRenderer::CPixelShaderRenderer()
772 827
     : CWinRenderer()
773 828
 {
@@ -788,4 +843,6 @@ void CPixelShaderRenderer::Render(DWORD flags)
788 843
   CWinRenderer::Render(flags);
789 844
 }
790 845
 
  846
+
  847
+
791 848
 #endif
22  xbmc/cores/VideoRenderers/WinRenderer.h
@@ -73,6 +73,8 @@
73 73
 
74 74
 class CBaseTexture;
75 75
 
  76
+namespace DXVA { class CProcessor; }
  77
+
76 78
 struct DRAWRECT
77 79
 {
78 80
   float left;
@@ -115,6 +117,7 @@ class CWinRenderer : public CBaseRenderer
115 117
   virtual int          GetImage(YV12Image *image, int source = AUTOSOURCE, bool readonly = false);
116 118
   virtual void         ReleaseImage(int source, bool preserve = false);
117 119
   virtual unsigned int DrawSlice(unsigned char *src[], int stride[], int w, int h, int x, int y);
  120
+  virtual void         AddProcessor(DXVA::CProcessor* processor, int64_t id);
118 121
   virtual void         FlipPage(int source);
119 122
   virtual unsigned int PreInit();
120 123
   virtual void         UnInit();
@@ -146,6 +149,7 @@ class CWinRenderer : public CBaseRenderer
146 149
 
147 150
   // low memory renderer (default PixelShaderRenderer)
148 151
   void RenderLowMem(CD3DEffect &effect, DWORD flags);
  152
+  void RenderProcessor(DWORD flags);
149 153
   int m_iYV12RenderBuffer;
150 154
   int m_NumYV12Buffers;
151 155
 
@@ -171,6 +175,24 @@ class CWinRenderer : public CBaseRenderer
171 175
   YUVVIDEOBUFFERS m_YUVVideoTexture;
172 176
   YUVMEMORYBUFFERS m_YUVMemoryTexture;
173 177
 
  178
+  struct SProcessImage
  179
+  {
  180
+    SProcessImage()
  181
+    {
  182
+      proc = NULL;
  183
+      id   = 0;
  184
+    }
  185
+
  186
+   ~SProcessImage()
  187
+    {
  188
+      Clear();
  189
+    }
  190
+    void Clear();
  191
+
  192
+    DXVA::CProcessor* proc;
  193
+    int64_t           id;
  194
+  } m_Processor[NUM_BUFFERS];
  195
+
174 196
   CD3DTexture m_HQKernelTexture;
175 197
   CD3DEffect  m_YUV2RGBEffect;
176 198
   CD3DEffect  m_YUV2RGBHQScalerEffect;
18  xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
@@ -32,13 +32,24 @@
32 32
 #define FRAME_TYPE_B 3
33 33
 #define FRAME_TYPE_D 4
34 34
 
  35
+namespace DXVA { class CProcessor; }
35 36
 
36 37
 // should be entirely filled by all codecs
37 38
 struct DVDVideoPicture
38 39
 {
39 40
   double pts; // timestamp in seconds, used in the CDVDPlayer class to keep track of pts
40  
-  BYTE* data[4];      // [4] = alpha channel, currently not used
41  
-  int iLineSize[4];   // [4] = alpha channel, currently not used
  41
+
  42
+  union
  43
+  {
  44
+    struct {
  45
+      BYTE* data[4];      // [4] = alpha channel, currently not used
  46
+      int iLineSize[4];   // [4] = alpha channel, currently not used
  47
+    };
  48
+    struct {
  49
+      DXVA::CProcessor* proc;
  50
+      int64_t           proc_id;
  51
+    };
  52
+  };
42 53
 
43 54
   unsigned int iFlags;
44 55
 
@@ -59,7 +70,8 @@ struct DVDVideoPicture
59 70
     FMT_VDPAU,
60 71
     FMT_NV12,
61 72
     FMT_UYVY,       // place holder for future expansion
62  
-    FMT_YUY2        //place holder for future expansion
  73
+    FMT_YUY2,       //place holder for future expansion
  74
+    FMT_DXVA,
63 75
   } format;
64 76
 };
65 77
 
17  xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
@@ -48,6 +48,9 @@
48 48
 #ifdef HAVE_LIBVDPAU
49 49
 #include "VDPAU.h"
50 50
 #endif
  51
+#ifdef HAS_DX
  52
+#include "DXVA.h"
  53
+#endif
51 54
 
52 55
 enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx
53 56
                                                 , const PixelFormat * fmt )
@@ -80,6 +83,20 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx
80 83
       return *cur;
81 84
     }
82 85
 #endif
  86
+#ifdef HAS_DX
  87
+  if(DXVA::CDecoder::Supports(*cur)
  88
+  && method == RENDER_METHOD_DXVA)
  89
+  {
  90
+    DXVA::CDecoder* dec = new DXVA::CDecoder();
  91
+    if(dec->Open(avctx, *cur))
  92
+    {
  93
+      ctx->SetHardware(dec);
  94
+      return *cur;
  95
+    }
  96
+    else
  97
+      delete dec;
  98
+  }
  99
+#endif
83 100
     cur++;
84 101
   }
85 102
   return ctx->m_dllAvCodec.avcodec_default_get_format(avctx, fmt);
837  xbmc/cores/dvdplayer/DVDCodecs/Video/DXVA.cpp
... ...
@@ -0,0 +1,837 @@
  1
+/*
  2
+ *      Copyright (C) 2005-2009 Team XBMC
  3
+ *      http://www.xbmc.org
  4
+ *
  5
+ *  This Program is free software; you can redistribute it and/or modify
  6
+ *  it under the terms of the GNU General Public License as published by
  7
+ *  the Free Software Foundation; either version 2, or (at your option)
  8
+ *  any later version.
  9
+ *
  10
+ *  This Program is distributed in the hope that it will be useful,
  11
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13
+ *  GNU General Public License for more details.
  14
+ *
  15
+ *  You should have received a copy of the GNU General Public License
  16
+ *  along with XBMC; see the file COPYING.  If not, write to
  17
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  18
+ *  http://www.gnu.org/copyleft/gpl.html
  19
+ *
  20
+ */
  21
+
  22
+#include <windows.h>
  23
+#include <d3d9.h>
  24
+#include <Initguid.h>
  25
+#include <dxva2api.h>
  26
+#include "libavcodec/dxva2.h"
  27
+
  28
+#include "DXVA.h"
  29
+#include "WindowingFactory.h"
  30
+#include "Settings.h"
  31
+
  32
+#pragma comment (lib,"dxva2.lib")
  33
+
  34
+using namespace DXVA;
  35
+
  36
+static void RelBufferS(AVCodecContext *avctx, AVFrame *pic)
  37
+{ ((CDecoder*)((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetHardware())->RelBuffer(avctx, pic); }
  38
+
  39
+static int GetBufferS(AVCodecContext *avctx, AVFrame *pic) 
  40
+{  return ((CDecoder*)((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetHardware())->GetBuffer(avctx, pic); }
  41
+
  42
+
  43
+DEFINE_GUID(DXVADDI_Intel_ModeH264_A, 0x604F8E64,0x4951,0x4c54,0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
  44
+DEFINE_GUID(DXVADDI_Intel_ModeH264_C, 0x664F8E66,0x4951,0x4c54,0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
  45
+DEFINE_GUID(DXVADDI_Intel_ModeH264_E, 0x664F8E68,0x4951,0x4c54,0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
  46
+DEFINE_GUID(DXVADDI_Intel_ModeVC1_E , 0xBCC5DB6D,0xA2B6,0x4AF0,0xAC,0xE4,0xAD,0xB1,0xF7,0x87,0xBC,0x89);
  47
+
  48
+typedef struct {
  49
+    const char   *name;
  50
+    const GUID   *guid;
  51
+    int          codec;
  52
+} dxva2_mode_t;
  53
+
  54
+/* XXX Prefered modes must come first */
  55
+static const dxva2_mode_t dxva2_modes[] = {
  56
+    { "MPEG2 VLD",    &DXVA2_ModeMPEG2_VLD,     0 },
  57
+    { "MPEG2 MoComp", &DXVA2_ModeMPEG2_MoComp,  0 },
  58
+    { "MPEG2 IDCT",   &DXVA2_ModeMPEG2_IDCT,    0 },
  59
+
  60
+    { "H.264 variable-length decoder (VLD), FGT",               &DXVA2_ModeH264_F, CODEC_ID_H264 },
  61
+    { "H.264 VLD, no FGT",                                      &DXVA2_ModeH264_E, CODEC_ID_H264 },
  62
+    { "H.264 IDCT, FGT",                                        &DXVA2_ModeH264_D, 0,            },
  63
+    { "H.264 inverse discrete cosine transform (IDCT), no FGT", &DXVA2_ModeH264_C, 0,            },
  64
+    { "H.264 MoComp, FGT",                                      &DXVA2_ModeH264_B, 0,            },
  65
+    { "H.264 motion compensation (MoComp), no FGT",             &DXVA2_ModeH264_A, 0,            },
  66
+
  67
+    { "Intel H.264 VLD, no FGT",                                      &DXVADDI_Intel_ModeH264_E, CODEC_ID_H264 },
  68
+    { "Intel H.264 inverse discrete cosine transform (IDCT), no FGT", &DXVADDI_Intel_ModeH264_C, 0,            },
  69
+    { "Intel H.264 motion compensation (MoComp), no FGT",             &DXVADDI_Intel_ModeH264_A, 0,            },
  70
+
  71
+    { "Windows Media Video 8 MoComp",           &DXVA2_ModeWMV8_B, 0 },
  72
+    { "Windows Media Video 8 post processing",  &DXVA2_ModeWMV8_A, 0 },
  73
+
  74
+    { "Windows Media Video 9 IDCT",             &DXVA2_ModeWMV9_C, 0 },
  75
+    { "Windows Media Video 9 MoComp",           &DXVA2_ModeWMV9_B, 0 },
  76
+    { "Windows Media Video 9 post processing",  &DXVA2_ModeWMV9_A, 0 },
  77
+
  78
+    { "VC-1 VLD",             &DXVA2_ModeVC1_D, CODEC_ID_VC1 },
  79
+    { "VC-1 IDCT",            &DXVA2_ModeVC1_C, 0 },
  80
+    { "VC-1 MoComp",          &DXVA2_ModeVC1_B, 0 },
  81
+    { "VC-1 post processing", &DXVA2_ModeVC1_A, 0 },
  82
+
  83
+    { "Intel VC-1 VLD",       &DXVADDI_Intel_ModeVC1_E, CODEC_ID_VC1 },
  84
+
  85
+    { NULL, NULL, 0 }
  86
+};
  87
+
  88
+static const dxva2_mode_t *dxva2_find(const GUID *guid)
  89
+{
  90
+    for (unsigned i = 0; dxva2_modes[i].name; i++) {
  91
+        if (IsEqualGUID(*dxva2_modes[i].guid, *guid))
  92
+            return &dxva2_modes[i];
  93
+    }
  94
+    return NULL;
  95
+}
  96
+
  97
+static inline unsigned dxva2_align(unsigned value)
  98
+{
  99
+  // untill somebody gives me a sample where this is required
  100
+  // i'd rather not do this alignment as it will mess with
  101
+  // output not being cropped correctly
  102
+#if 0
  103
+  return (value + 15) & ~15;
  104
+#else
  105
+  return value;
  106
+#endif
  107
+}
  108
+
  109
+
  110
+CDecoder::SVideoBuffer::SVideoBuffer()
  111
+{
  112
+  surface = NULL;
  113
+  Clear();
  114
+}
  115
+
  116
+CDecoder::SVideoBuffer::~SVideoBuffer()
  117
+{
  118
+  Clear();
  119
+}
  120
+
  121
+void CDecoder::SVideoBuffer::Clear()
  122
+{
  123
+  SAFE_RELEASE(surface);
  124
+  age     = 0;
  125
+  used    = 0;
  126
+}
  127
+
  128
+CDecoder::CDecoder()
  129
+ : m_event(true)
  130
+{
  131
+  m_event.Set();
  132
+  m_state     = DXVA_OPEN;
  133
+  m_service   = NULL;
  134
+  m_device    = NULL;
  135
+  m_decoder   = NULL;
  136
+  m_processor = NULL;
  137
+  m_buffer_count = 0;
  138
+  memset(&m_format, 0, sizeof(m_format));
  139
+  m_context          = (dxva_context*)calloc(1, sizeof(dxva_context));
  140
+  m_context->cfg     = (DXVA2_ConfigPictureDecode*)calloc(1, sizeof(DXVA2_ConfigPictureDecode));
  141
+  m_context->surface = (IDirect3DSurface9**)calloc(m_buffer_max, sizeof(IDirect3DSurface9*));
  142
+  g_Windowing.Register(this);
  143
+}
  144
+
  145
+CDecoder::~CDecoder()
  146
+{
  147
+  g_Windowing.Unregister(this);
  148
+  Close();
  149
+  free(m_context->surface);
  150
+  free(const_cast<DXVA2_ConfigPictureDecode*>(m_context->cfg)); // yes this is foobar
  151
+  free(m_context);
  152
+}
  153
+
  154
+void CDecoder::Close()
  155
+{
  156
+  CSingleLock lock(m_section);
  157
+  SAFE_RELEASE(m_decoder);
  158
+  SAFE_RELEASE(m_service);
  159
+  SAFE_RELEASE(m_processor);
  160
+  for(unsigned i = 0; i < m_buffer_count; i++)
  161
+    m_buffer[i].Clear();
  162
+  m_buffer_count = 0;
  163
+  memset(&m_format, 0, sizeof(m_format));
  164
+  CProcessor* proc = m_processor;
  165
+  m_processor = NULL;
  166
+  lock.Leave();
  167
+
  168
+  if(proc)
  169
+  {
  170
+    CSingleExit leave(m_section);
  171
+    proc->Release();
  172
+  }
  173
+}
  174
+
  175
+#define CHECK(a) \
  176
+do { \
  177
+  HRESULT res = a; \
  178
+  if(FAILED(res)) \
  179
+  { \
  180
+    CLog::Log(LOGERROR, "DXVA - failed executing "#a" at line %d with error %x", __LINE__, res); \
  181
+    return false; \
  182
+  } \
  183
+} while(0);
  184
+
  185
+
  186
+bool CDecoder::Open(AVCodecContext *avctx, enum PixelFormat fmt)
  187
+{
  188
+  CSingleLock lock(m_section);
  189
+  Close();
  190
+
  191
+  if(m_state == DXVA_LOST)
  192
+  {
  193
+    CLog::Log(LOGDEBUG, "DXVA - device is in lost state, we can't start");
  194
+    return false;
  195
+  }
  196
+
  197
+  CHECK(DXVA2CreateVideoService(g_Windowing.Get3DDevice(), IID_IDirectXVideoDecoderService, (void**)&m_service))
  198
+
  199
+  UINT  input_count;
  200
+  GUID *input_list;
  201
+
  202
+  CHECK(m_service->GetDecoderDeviceGuids(&input_count, &input_list))
  203
+
  204
+  for(unsigned i = 0; i < input_count; i++)
  205
+  {
  206
+    const GUID *g            = &input_list[i];
  207
+    const dxva2_mode_t *mode = dxva2_find(g);
  208
+    if(mode)
  209
+      CLog::Log(LOGDEBUG, "DXVA - supports '%s'", mode->name);
  210
+    else
  211
+      CLog::Log(LOGDEBUG, "DXVA - supports %08X-%04x-%04x-XXXX\n"
  212
+                        , g->Data1
  213
+                        , g->Data2
  214
+                        , g->Data3);
  215
+  }
  216
+
  217
+  m_format.Format = D3DFMT_UNKNOWN;
  218
+  for(const dxva2_mode_t* mode = dxva2_modes; mode->name; mode++)
  219
+  {
  220
+    if(mode->codec != avctx->codec_id)
  221
+      continue;
  222
+
  223
+    for(unsigned j = 0; j < input_count; j++)
  224
+    {
  225
+      if(!IsEqualGUID(input_list[j], *mode->guid))
  226
+        continue;
  227
+
  228
+      CLog::Log(LOGDEBUG, "DXVA - trying '%s'", mode->name);
  229
+      if(OpenTarget(input_list[j]))
  230
+      {
  231
+        m_input = input_list[j];
  232
+        break;
  233
+      }
  234
+    }
  235
+  }
  236
+  CoTaskMemFree(input_list);
  237
+
  238
+  if(m_format.Format == D3DFMT_UNKNOWN)
  239
+  {
  240
+    CLog::Log(LOGDEBUG, "DXVA - unable to find an input/output format combination");
  241
+    return false;
  242
+  }
  243
+
  244
+  if(!OpenDecoder(avctx))
  245
+    return false;
  246
+
  247
+  m_state = DXVA_OPEN;
  248
+
  249
+  { CSingleExit leave(m_section);
  250
+    CProcessor* processor = new CProcessor();
  251
+    leave.Restore();
  252
+    m_processor = processor;
  253
+  }
  254
+
  255
+  if(m_state == DXVA_RESET)
  256
+  {
  257
+    CLog::Log(LOGDEBUG, "DXVA - decoder was reset while trying to create a processor, retrying");
  258
+    if(!Open(avctx, fmt))
  259
+      return false;
  260
+  }
  261
+
  262
+  if(m_state == DXVA_LOST)
  263
+  {
  264
+    CLog::Log(LOGERROR, "DXVA - device was lost while trying to create a processor");
  265
+    return false;
  266
+  }
  267
+
  268
+  if(!m_processor->Open(m_format, 4))
  269
+    return false;
  270
+
  271
+  avctx->get_buffer      = GetBufferS;
  272
+  avctx->release_buffer  = RelBufferS;
  273
+  avctx->hwaccel_context = m_context;
  274
+
  275
+  return true;
  276
+}
  277
+
  278
+int CDecoder::Decode(AVCodecContext* avctx, AVFrame* frame)
  279
+{
  280
+  CSingleLock lock(m_section);
  281
+  int result = Check(avctx);
  282
+  if(result)
  283
+    return result;
  284
+
  285
+  if(frame)
  286
+  {
  287
+    for(unsigned i = 0; i < m_buffer_count; i++)
  288
+    {
  289
+      if(m_buffer[i].surface == (IDirect3DSurface9*)frame->data[3])
  290
+        return VC_BUFFER | VC_PICTURE;
  291
+    }
  292
+    CLog::Log(LOGWARNING, "DXVA - ignoring invalid surface");
  293
+    return VC_BUFFER;
  294
+  }
  295
+  else
  296
+    return 0;
  297
+}
  298
+
  299
+bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture)
  300
+{
  301
+  CSingleLock lock(m_section);
  302
+  picture->format = DVDVideoPicture::FMT_DXVA;
  303
+  picture->proc    = m_processor;
  304
+  picture->proc_id = m_processor->Add((IDirect3DSurface9*)frame->data[3]);
  305
+  return true;
  306
+}
  307
+
  308
+int CDecoder::Check(AVCodecContext* avctx)
  309
+{
  310
+  CSingleLock lock(m_section);
  311
+
  312
+  if(m_state == DXVA_RESET)
  313
+    Close();
  314
+
  315
+  if(m_state == DXVA_LOST)
  316
+  {
  317
+    Close();
  318
+    lock.Leave();
  319
+    m_event.WaitMSec(2000);
  320
+    lock.Enter();
  321
+    if(m_state == DXVA_LOST)
  322
+    {
  323
+      CLog::Log(LOGERROR, "CDecoder::Check - device didn't reset in reasonable time");
  324
+      return VC_ERROR;
  325
+    }
  326
+  }
  327
+
  328
+  if(m_format.SampleWidth  == 0
  329
+  || m_format.SampleHeight == 0)
  330
+  {
  331
+    if(!Open(avctx, avctx->pix_fmt))
  332
+    {
  333
+      CLog::Log(LOGERROR, "CDecoder::Check - decoder was not able to reset");
  334
+      Close();
  335
+      return VC_ERROR;
  336
+    }
  337
+    return VC_FLUSHED;
  338
+  }
  339
+  return 0;
  340
+}
  341
+
  342
+bool CDecoder::OpenTarget(const GUID &guid)
  343
+{
  344
+  UINT       output_count = 0;
  345
+  D3DFORMAT *output_list  = NULL;
  346
+  CHECK(m_service->GetDecoderRenderTargets(guid, &output_count, &output_list))
  347
+
  348
+  for(unsigned k = 0; k < output_count; k++)
  349
+  {
  350
+    if(output_list[k] == MAKEFOURCC('Y','V','1','2')
  351
+    || output_list[k] == MAKEFOURCC('N','V','1','2'))
  352
+    {
  353
+      m_format.Format = output_list[k];
  354
+      CoTaskMemFree(output_list);
  355
+      return true;
  356
+    }
  357
+  }
  358
+  CoTaskMemFree(output_list);
  359
+  return false;
  360
+}
  361
+
  362
+bool CDecoder::OpenDecoder(AVCodecContext *avctx)
  363
+{
  364
+  m_format.SampleWidth  = dxva2_align(avctx->width);
  365
+  m_format.SampleHeight = dxva2_align(avctx->height);
  366
+  m_format.SampleFormat.SampleFormat           = DXVA2_SampleProgressiveFrame;
  367
+  m_format.SampleFormat.VideoLighting          = DXVA2_VideoLighting_dim;
  368
+
  369
+  if     (avctx->color_range == AVCOL_RANGE_JPEG)
  370
+    m_format.SampleFormat.NominalRange = DXVA2_NominalRange_0_255;
  371
+  else if(avctx->color_range == AVCOL_RANGE_MPEG)
  372
+    m_format.SampleFormat.NominalRange = DXVA2_NominalRange_16_235;
  373
+  else
  374
+    m_format.SampleFormat.NominalRange = DXVA2_NominalRange_Unknown;
  375
+
  376
+  switch(avctx->chroma_sample_location)
  377
+  {
  378
+    case AVCHROMA_LOC_LEFT:
  379
+      m_format.SampleFormat.VideoChromaSubsampling = DXVA2_VideoChromaSubsampling_Horizontally_Cosited 
  380
+                                                   | DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes;
  381
+      break;
  382
+    case AVCHROMA_LOC_CENTER:
  383
+      m_format.SampleFormat.VideoChromaSubsampling = DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes;
  384
+      break;
  385
+    case AVCHROMA_LOC_TOPLEFT:
  386
+      m_format.SampleFormat.VideoChromaSubsampling = DXVA2_VideoChromaSubsampling_Horizontally_Cosited 
  387
+                                                   | DXVA2_VideoChromaSubsampling_Vertically_Cosited;
  388
+      break;
  389
+    default:
  390
+      m_format.SampleFormat.VideoChromaSubsampling = DXVA2_VideoChromaSubsampling_Unknown;      
  391
+  }
  392
+
  393
+  switch(avctx->colorspace)
  394
+  {
  395
+    case AVCOL_SPC_BT709:
  396
+      m_format.SampleFormat.VideoTransferMatrix = DXVA2_VideoTransferMatrix_BT709;
  397
+      break;
  398
+    case AVCOL_SPC_BT470BG:
  399
+    case AVCOL_SPC_SMPTE170M:
  400
+      m_format.SampleFormat.VideoTransferMatrix = DXVA2_VideoTransferMatrix_BT601;
  401
+      break;
  402
+    case AVCOL_SPC_SMPTE240M:
  403
+      m_format.SampleFormat.VideoTransferMatrix = DXVA2_VideoTransferMatrix_SMPTE240M;
  404
+      break;
  405
+    case AVCOL_SPC_FCC:
  406
+    case AVCOL_SPC_UNSPECIFIED:
  407
+    case AVCOL_SPC_RGB:
  408
+    default:
  409
+      m_format.SampleFormat.VideoTransferMatrix = DXVA2_VideoTransferMatrix_Unknown;
  410
+  }
  411
+
  412
+  switch(avctx->color_primaries)
  413
+  {
  414
+    case AVCOL_PRI_BT709:
  415
+      m_format.SampleFormat.VideoPrimaries = DXVA2_VideoPrimaries_BT709;
  416
+      break;
  417
+    case AVCOL_PRI_BT470M:
  418
+      m_format.SampleFormat.VideoPrimaries = DXVA2_VideoPrimaries_BT470_2_SysM;
  419
+      break;
  420
+    case AVCOL_PRI_BT470BG:
  421
+      m_format.SampleFormat.VideoPrimaries = DXVA2_VideoPrimaries_BT470_2_SysBG;
  422
+      break;
  423
+    case AVCOL_PRI_SMPTE170M:
  424
+      m_format.SampleFormat.VideoPrimaries = DXVA2_VideoPrimaries_SMPTE170M;
  425
+      break;
  426
+    case AVCOL_PRI_SMPTE240M:
  427
+      m_format.SampleFormat.VideoPrimaries = DXVA2_VideoPrimaries_SMPTE240M;
  428
+      break;
  429
+    case AVCOL_PRI_FILM:
  430
+    case AVCOL_PRI_UNSPECIFIED:
  431
+    default:
  432
+      m_format.SampleFormat.VideoPrimaries = DXVA2_VideoPrimaries_Unknown;
  433
+  }
  434
+
  435
+  switch(avctx->color_trc)
  436
+  {
  437
+    case AVCOL_TRC_BT709:
  438
+      m_format.SampleFormat.VideoTransferFunction = DXVA2_VideoTransFunc_709;
  439
+      break;
  440
+    case AVCOL_TRC_GAMMA22:
  441
+      m_format.SampleFormat.VideoTransferFunction = DXVA2_VideoTransFunc_22;
  442
+      break;
  443
+    case AVCOL_TRC_GAMMA28:
  444
+      m_format.SampleFormat.VideoTransferFunction = DXVA2_VideoTransFunc_28;
  445
+      break;
  446
+    default:
  447
+      m_format.SampleFormat.VideoTransferFunction = DXVA2_VideoTransFunc_Unknown;
  448
+  }
  449
+
  450
+  if (avctx->time_base.den > 0 && avctx->time_base.num > 0)
  451
+  {
  452
+    m_format.InputSampleFreq.Numerator   = avctx->time_base.num;
  453
+    m_format.InputSampleFreq.Denominator = avctx->time_base.den;
  454
+  } 
  455
+  m_format.OutputFrameFreq = m_format.InputSampleFreq;
  456
+  m_format.UABProtectionLevel = FALSE;
  457
+  m_format.Reserved = 0;
  458
+
  459
+  if(avctx->codec_id == CODEC_ID_H264)
  460
+    m_context->surface_count = 16 + 1 + 1; // 16 ref + 1 decode + 1 libavcodec safety
  461
+  else
  462
+    m_context->surface_count = 2  + 1 + 1; // 2  ref + 1 decode + 1 libavcodec safety
  463
+
  464
+  CHECK(m_service->CreateSurface( m_format.SampleWidth
  465
+                                , m_format.SampleHeight
  466
+                                , m_context->surface_count - 1
  467
+                                , m_format.Format
  468
+                                , D3DPOOL_DEFAULT
  469
+                                , 0
  470
+                                , DXVA2_VideoDecoderRenderTarget
  471
+                                , m_context->surface, NULL ));
  472
+
  473
+  m_buffer_count = m_context->surface_count;
  474
+  m_buffer_age   = 0;
  475
+  for(unsigned i = 0; i < m_buffer_count; i++)
  476
+    m_buffer[i].surface = m_context->surface[i];
  477
+
  478
+  UINT                       cfg_count = 0;
  479
+  DXVA2_ConfigPictureDecode *cfg_list  = NULL;
  480
+  CHECK(m_service->GetDecoderConfigurations(m_input
  481
+                                          , &m_format
  482
+                                          , NULL
  483
+                                          , &cfg_count
  484
+                                          , &cfg_list))
  485
+
  486
+  DXVA2_ConfigPictureDecode config = {};
  487
+  for(unsigned i = 0; i< cfg_count; i++)
  488
+  {
  489
+    CLog::Log(LOGDEBUG, "DXVA - bitstream type %d", cfg_list[i].ConfigBitstreamRaw);
  490
+    if(config.ConfigBitstreamRaw == 0 && cfg_list[i].ConfigBitstreamRaw)
  491
+      config = cfg_list[i];
  492
+    if(config.ConfigBitstreamRaw == 1 && cfg_list[i].ConfigBitstreamRaw == 2)
  493
+      config = cfg_list[i];
  494
+  }
  495
+  CoTaskMemFree(cfg_list);
  496
+
  497
+  if(!config.ConfigBitstreamRaw)
  498
+  {
  499
+    CLog::Log(LOGDEBUG, "DXVA - failed to find a raw input bitstream");
  500
+    return false;
  501
+  }
  502
+
  503
+  CHECK(m_service->CreateVideoDecoder(m_input, &m_format, &config
  504
+                                    , m_context->surface
  505
+                                    , m_context->surface_count
  506
+                                    , &m_decoder))
  507
+
  508
+  *const_cast<DXVA2_ConfigPictureDecode*>(m_context->cfg) = config;
  509
+  m_context->decoder = m_decoder;
  510
+
  511
+  return true;
  512
+}
  513
+
  514
+bool CDecoder::Supports(enum PixelFormat fmt)
  515
+{
  516
+  if(fmt == PIX_FMT_DXVA2_VLD)
  517
+    return true;
  518
+  return false;
  519
+}
  520
+
  521
+void CDecoder::RelBuffer(AVCodecContext *avctx, AVFrame *pic)
  522
+{
  523
+  CSingleLock lock(m_section);
  524
+  IDirect3DSurface9* surface = (IDirect3DSurface9*)pic->data[3];
  525
+
  526
+  for(unsigned i = 0; i < m_buffer_count; i++)
  527
+  {
  528
+    if(m_buffer[i].surface == surface)
  529
+    {
  530
+      m_buffer[i].used = false;
  531
+      m_buffer[i].age  = ++m_buffer_age;
  532
+      break;
  533
+    }
  534
+  }
  535
+  for(unsigned i = 0; i < 4; i++)
  536
+    pic->data[i] = NULL;
  537
+}
  538
+
  539
+int CDecoder::GetBuffer(AVCodecContext *avctx, AVFrame *pic)
  540
+{
  541
+  CSingleLock lock(m_section);
  542
+  if(dxva2_align(avctx->width)  != m_format.SampleWidth
  543
+  || dxva2_align(avctx->height) != m_format.SampleHeight)
  544
+  {
  545
+    Close();
  546
+    if(!Open(avctx, avctx->pix_fmt))
  547
+    {
  548
+      Close();
  549
+      return -1;
  550
+    }
  551
+  }
  552
+
  553
+  SVideoBuffer* buf_old = NULL;
  554
+  SVideoBuffer* buf     = NULL;
  555
+  for(unsigned i = 0; i < m_buffer_count; i++)
  556
+  {
  557
+    if(!m_buffer[i].used)
  558
+    {
  559
+      if(!buf || buf->age > m_buffer[i].age)
  560
+        buf = m_buffer+i;
  561
+    }
  562
+
  563
+    if(!buf_old || buf_old->age > m_buffer[i].age)
  564
+      buf_old = m_buffer+i;
  565
+  }
  566
+
  567
+  if(!buf)
  568
+  {
  569
+    if(buf_old)
  570
+      CLog::Log(LOGERROR, "DXVA - unable to find new unused buffer");
  571
+    else
  572
+    {
  573
+      CLog::Log(LOGERROR, "DXVA - unable to find any buffer");    
  574
+      return -1;
  575
+    }
  576
+    buf = buf_old;
  577
+  }
  578
+
  579
+
  580
+  pic->reordered_opaque = avctx->reordered_opaque;
  581
+  pic->type = FF_BUFFER_TYPE_USER;
  582
+  pic->age  = 256*256*256*64; // as everybody else, i've got no idea about this one
  583
+  for(unsigned i = 0; i < 4; i++)
  584
+  {
  585
+    pic->data[i] = NULL;
  586
+    pic->linesize[i] = 0;
  587
+  }
  588
+
  589
+  pic->data[0] = (uint8_t*)buf->surface;
  590
+  pic->data[3] = (uint8_t*)buf->surface;
  591
+  buf->used = true;
  592
+
  593
+  return 0;
  594
+}
  595
+
  596
+//---------------------------------------------------------------------------
  597
+//---------------------------------------------------------------------------
  598
+//------------------------ PROCESSING SERVICE -------------------------------
  599
+//---------------------------------------------------------------------------
  600
+//---------------------------------------------------------------------------
  601
+
  602
+CProcessor::CProcessor()
  603
+{
  604
+  m_service = NULL;
  605
+  m_process = NULL;
  606
+  m_time    = 0;
  607
+  m_references = 1;
  608
+  g_Windowing.Register(this);
  609
+}
  610
+
  611
+CProcessor::~CProcessor()
  612
+{
  613
+  g_Windowing.Unregister(this);
  614
+  ASSERT(m_references == 0);
  615
+  Close();
  616
+}
  617
+
  618
+void CProcessor::Close()
  619
+{
  620
+  CSingleLock lock(m_section);
  621
+  SAFE_RELEASE(m_process);
  622
+  SAFE_RELEASE(m_service);
  623
+  for(unsigned i = 0; i < m_sample.size(); i++)
  624
+    SAFE_RELEASE(m_sample[i].SrcSurface);
  625
+  m_sample.clear();
  626
+}
  627
+
  628
+
  629
+bool CProcessor::Open(const DXVA2_VideoDesc& dsc, unsigned size)
  630
+{
  631
+  CSingleLock lock(m_section);
  632
+  m_desc = dsc;
  633
+  m_size = size;
  634
+
  635
+  CHECK(DXVA2CreateVideoService(g_Windowing.Get3DDevice(), IID_IDirectXVideoProcessorService, (void**)&m_service));
  636
+
  637
+  GUID*    guid_list;
  638
+  unsigned guid_count;
  639
+  CHECK(m_service->GetVideoProcessorDeviceGuids(&m_desc, &guid_count, &guid_list));
  640
+
  641
+  if(guid_count == 0)
  642
+  {
  643
+    CLog::Log(LOGDEBUG, "DXVA - unable to find any processors");
  644
+    CoTaskMemFree(guid_list);
  645
+    return false;
  646
+  }
  647
+
  648
+  m_device = guid_list[0];
  649
+  for(unsigned i = 0; i < guid_count; i++)
  650
+  {
  651
+    GUID* g = &guid_list[i];
  652
+    CLog::Log(LOGDEBUG, "DXVA - processor found %08X-%04x-%04x-XXXX\n"
  653
+                      , g->Data1
  654
+                      , g->Data2
  655
+                      , g->Data3);
  656
+
  657
+    if(IsEqualGUID(*g, DXVA2_VideoProcProgressiveDevice))
  658
+      m_device = *g;
  659
+  }
  660
+  CoTaskMemFree(guid_list);
  661
+
  662
+  CLog::Log(LOGDEBUG, "DXVA - processor selected %08X-%04x-%04x-XXXX\n"
  663
+                    , m_device.Data1
  664
+                    , m_device.Data2
  665
+                    , m_device.Data3);
  666
+
  667
+
  668
+  D3DFORMAT output = D3DFMT_X8R8G8B8;
  669
+
  670
+  CHECK(m_service->GetProcAmpRange(m_device, &m_desc, output, DXVA2_ProcAmp_Brightness, &m_brightness));
  671
+  CHECK(m_service->GetProcAmpRange(m_device, &m_desc, output, DXVA2_ProcAmp_Contrast  , &m_contrast));
  672
+  CHECK(m_service->GetProcAmpRange(m_device, &m_desc, output, DXVA2_ProcAmp_Hue       , &m_hue));
  673
+  CHECK(m_service->GetProcAmpRange(m_device, &m_desc, output, DXVA2_ProcAmp_Saturation, &m_saturation));
  674
+  CHECK(m_service->CreateVideoProcessor(m_device, &m_desc, output, 0, &m_process));
  675
+
  676
+  m_time = 0;
  677
+  return true;
  678
+}
  679
+
  680
+REFERENCE_TIME CProcessor::Add(IDirect3DSurface9* source)
  681
+{
  682
+  CSingleLock lock(m_section);
  683
+
  684
+  m_time += 2;
  685
+
  686
+  DXVA2_VideoSample vs = {};
  687
+  vs.Start          = m_time;
  688
+  vs.End            = 0; 
  689
+  vs.SampleFormat   = m_desc.SampleFormat;
  690
+  vs.SrcRect.left   = 0;
  691
+  vs.SrcRect.right  = m_desc.SampleWidth;
  692
+  vs.SrcRect.top    = 0;
  693
+  vs.SrcRect.bottom = m_desc.SampleHeight;
  694
+  vs.PlanarAlpha    = DXVA2_Fixed32OpaqueAlpha();
  695
+  vs.SampleData     = 0;
  696
+  vs.SrcSurface     = source;
  697
+  vs.SrcSurface->AddRef();
  698
+
  699
+  if(!m_sample.empty())
  700
+    m_sample.front().End = vs.Start;
  701
+
  702
+  m_sample.push_front(vs);
  703
+  if(m_sample.size() > m_size)
  704
+  {
  705
+    SAFE_RELEASE(m_sample.back().SrcSurface);
  706
+    m_sample.pop_back();
  707
+  }
  708
+
  709
+  return m_time;
  710
+}
  711
+
  712
+static DXVA2_Fixed32 ConvertRange(const DXVA2_ValueRange& range, int value, int min, int max, int def)
  713
+{
  714
+  if(value > def)
  715
+    return DXVA2FloatToFixed( DXVA2FixedToFloat(range.DefaultValue)
  716
+                            + (DXVA2FixedToFloat(range.MaxValue) - DXVA2FixedToFloat(range.DefaultValue))
  717
+                            * (value - def) / (max - def) );
  718
+  else if(value < def)
  719
+    return DXVA2FloatToFixed( DXVA2FixedToFloat(range.DefaultValue)
  720
+                            + (DXVA2FixedToFloat(range.MinValue) - DXVA2FixedToFloat(range.DefaultValue)) 
  721
+                            * (value - def) / (max - def) );
  722
+  else
  723
+    return range.DefaultValue;
  724
+}
  725
+
  726
+void CProcessor::CropSource(RECT& src, RECT& dst, const D3DSURFACE_DESC& desc)
  727
+{
  728
+  if(dst.left < 0)
  729
+  {
  730
+    src.left -= dst.left 
  731
+              * (src.right - src.left) 
  732
+              / (dst.right - dst.left);
  733
+    dst.left  = 0;
  734
+  }
  735
+  if(dst.top < 0)
  736
+  {
  737
+    src.top -= dst.top 
  738
+             * (src.bottom - src.top) 
  739
+             / (dst.bottom - dst.top);
  740
+    dst.top  = 0;
  741
+  }
  742
+  if(dst.right > (LONG)desc.Width)
  743
+  {
  744
+    src.right -= (dst.right - desc.Width)
  745
+               * (src.right - src.left) 
  746
+               / (dst.right - dst.left);
  747
+    dst.right  = desc.Width;
  748
+  }
  749
+  if(dst.bottom > (LONG)desc.Height)
  750
+  {
  751
+    src.bottom -= (dst.bottom - desc.Height)
  752
+                * (src.bottom - src.top) 
  753
+                / (dst.bottom - dst.top);
  754
+    dst.bottom  = desc.Height;
  755
+  }
  756
+}
  757
+
  758
+bool CProcessor::Render(const RECT &dst, IDirect3DSurface9* target, REFERENCE_TIME time)
  759
+{
  760
+  CSingleLock lock(m_section);
  761
+
  762
+  if(m_sample.empty())
  763
+    return false;
  764
+
  765
+  SSamples::iterator it = m_sample.begin();
  766
+  for(; it != m_sample.end(); it++)
  767
+  {
  768
+    if(it->Start <= time)
  769
+      break;
  770
+  }
  771
+
  772
+  if(it == m_sample.end())
  773
+  {
  774
+    CLog::Log(LOGERROR, "DXVA - failed to find image, all images newer or no images");
  775
+    return false;
  776
+  }
  777
+
  778
+  DXVA2_VideoSample vs;
  779
+  vs = *it;
  780
+  vs.DstRect = dst;
  781
+  if(vs.End == 0)
  782
+    vs.End = vs.Start + 2;
  783
+
  784
+  if(time <  vs.Start
  785
+  || time >= vs.End)
  786
+    CLog::Log(LOGWARNING, "DXVA - image to render is outside of bounds [%"PRId64":%"PRId64") was %"PRId64,vs.Start, vs.End, time);
  787
+
  788
+  D3DSURFACE_DESC desc;
  789
+  CHECK(target->GetDesc(&desc));
  790
+
  791
+  CropSource(vs.SrcRect, vs.DstRect, desc);
  792
+
  793
+  DXVA2_VideoProcessBltParams blt = {};
  794
+  blt.TargetFrame = vs.Start;