You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

303 lines
10KB

  1. /*
  2. * DXVA2 HW acceleration.
  3. *
  4. * copyright (c) 2010 Laurent Aimar
  5. *
  6. * This file is part of Libav.
  7. *
  8. * Libav is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2.1 of the License, or (at your option) any later version.
  12. *
  13. * Libav is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with Libav; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. */
  22. #include <assert.h>
  23. #include <string.h>
  24. #include "libavutil/log.h"
  25. #include "libavutil/time.h"
  26. #include "avcodec.h"
  27. #include "dxva2_internal.h"
  28. void *ff_dxva2_get_surface(const AVFrame *frame)
  29. {
  30. return frame->data[3];
  31. }
  32. unsigned ff_dxva2_get_surface_index(const AVCodecContext *avctx,
  33. const AVDXVAContext *ctx,
  34. const AVFrame *frame)
  35. {
  36. void *surface = ff_dxva2_get_surface(frame);
  37. unsigned i;
  38. for (i = 0; i < DXVA_CONTEXT_COUNT(avctx, ctx); i++)
  39. #if CONFIG_D3D11VA
  40. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD && ctx->d3d11va.surface[i] == surface) {
  41. D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
  42. ID3D11VideoDecoderOutputView_GetDesc(ctx->d3d11va.surface[i], &viewDesc);
  43. return viewDesc.Texture2D.ArraySlice;
  44. }
  45. #endif
  46. #if CONFIG_DXVA2
  47. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD && ctx->dxva2.surface[i] == surface)
  48. return i;
  49. #endif
  50. assert(0);
  51. return 0;
  52. }
  53. int ff_dxva2_commit_buffer(AVCodecContext *avctx,
  54. AVDXVAContext *ctx,
  55. DECODER_BUFFER_DESC *dsc,
  56. unsigned type, const void *data, unsigned size,
  57. unsigned mb_count)
  58. {
  59. void *dxva_data;
  60. unsigned dxva_size;
  61. int result;
  62. HRESULT hr;
  63. #if CONFIG_D3D11VA
  64. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  65. hr = ID3D11VideoContext_GetDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context,
  66. D3D11VA_CONTEXT(ctx)->decoder,
  67. type,
  68. &dxva_size, &dxva_data);
  69. #endif
  70. #if CONFIG_DXVA2
  71. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
  72. hr = IDirectXVideoDecoder_GetBuffer(DXVA2_CONTEXT(ctx)->decoder, type,
  73. &dxva_data, &dxva_size);
  74. #endif
  75. if (FAILED(hr)) {
  76. av_log(avctx, AV_LOG_ERROR, "Failed to get a buffer for %u: 0x%lx\n",
  77. type, hr);
  78. return -1;
  79. }
  80. if (size <= dxva_size) {
  81. memcpy(dxva_data, data, size);
  82. #if CONFIG_D3D11VA
  83. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  84. D3D11_VIDEO_DECODER_BUFFER_DESC *dsc11 = dsc;
  85. memset(dsc11, 0, sizeof(*dsc11));
  86. dsc11->BufferType = type;
  87. dsc11->DataSize = size;
  88. dsc11->NumMBsInBuffer = mb_count;
  89. }
  90. #endif
  91. #if CONFIG_DXVA2
  92. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  93. DXVA2_DecodeBufferDesc *dsc2 = dsc;
  94. memset(dsc2, 0, sizeof(*dsc2));
  95. dsc2->CompressedBufferType = type;
  96. dsc2->DataSize = size;
  97. dsc2->NumMBsInBuffer = mb_count;
  98. }
  99. #endif
  100. result = 0;
  101. } else {
  102. av_log(avctx, AV_LOG_ERROR, "Buffer for type %u was too small\n", type);
  103. result = -1;
  104. }
  105. #if CONFIG_D3D11VA
  106. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  107. hr = ID3D11VideoContext_ReleaseDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder, type);
  108. #endif
  109. #if CONFIG_DXVA2
  110. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
  111. hr = IDirectXVideoDecoder_ReleaseBuffer(DXVA2_CONTEXT(ctx)->decoder, type);
  112. #endif
  113. if (FAILED(hr)) {
  114. av_log(avctx, AV_LOG_ERROR,
  115. "Failed to release buffer type %u: 0x%lx\n",
  116. type, hr);
  117. result = -1;
  118. }
  119. return result;
  120. }
  121. int ff_dxva2_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
  122. const void *pp, unsigned pp_size,
  123. const void *qm, unsigned qm_size,
  124. int (*commit_bs_si)(AVCodecContext *,
  125. DECODER_BUFFER_DESC *bs,
  126. DECODER_BUFFER_DESC *slice))
  127. {
  128. AVDXVAContext *ctx = avctx->hwaccel_context;
  129. unsigned buffer_count = 0;
  130. #if CONFIG_D3D11VA
  131. D3D11_VIDEO_DECODER_BUFFER_DESC buffer11[4];
  132. #endif
  133. #if CONFIG_DXVA2
  134. DXVA2_DecodeBufferDesc buffer2[4];
  135. #endif
  136. DECODER_BUFFER_DESC *buffer,*buffer_slice;
  137. int result, runs = 0;
  138. HRESULT hr;
  139. unsigned type;
  140. do {
  141. #if CONFIG_D3D11VA
  142. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  143. if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE)
  144. WaitForSingleObjectEx(D3D11VA_CONTEXT(ctx)->context_mutex, INFINITE, FALSE);
  145. hr = ID3D11VideoContext_DecoderBeginFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder,
  146. ff_dxva2_get_surface(frame),
  147. 0, NULL);
  148. }
  149. #endif
  150. #if CONFIG_DXVA2
  151. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
  152. hr = IDirectXVideoDecoder_BeginFrame(DXVA2_CONTEXT(ctx)->decoder,
  153. ff_dxva2_get_surface(frame),
  154. NULL);
  155. #endif
  156. if (hr != E_PENDING || ++runs > 50)
  157. break;
  158. #if CONFIG_D3D11VA
  159. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  160. if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE)
  161. ReleaseMutex(D3D11VA_CONTEXT(ctx)->context_mutex);
  162. #endif
  163. av_usleep(2000);
  164. } while(1);
  165. if (FAILED(hr)) {
  166. av_log(avctx, AV_LOG_ERROR, "Failed to begin frame: 0x%lx\n", hr);
  167. #if CONFIG_D3D11VA
  168. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  169. if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE)
  170. ReleaseMutex(D3D11VA_CONTEXT(ctx)->context_mutex);
  171. #endif
  172. return -1;
  173. }
  174. #if CONFIG_D3D11VA
  175. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  176. buffer = &buffer11[buffer_count];
  177. type = D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS;
  178. }
  179. #endif
  180. #if CONFIG_DXVA2
  181. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  182. buffer = &buffer2[buffer_count];
  183. type = DXVA2_PictureParametersBufferType;
  184. }
  185. #endif
  186. result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
  187. type,
  188. pp, pp_size, 0);
  189. if (result) {
  190. av_log(avctx, AV_LOG_ERROR,
  191. "Failed to add picture parameter buffer\n");
  192. goto end;
  193. }
  194. buffer_count++;
  195. if (qm_size > 0) {
  196. #if CONFIG_D3D11VA
  197. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  198. buffer = &buffer11[buffer_count];
  199. type = D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX;
  200. }
  201. #endif
  202. #if CONFIG_DXVA2
  203. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  204. buffer = &buffer2[buffer_count];
  205. type = DXVA2_InverseQuantizationMatrixBufferType;
  206. }
  207. #endif
  208. result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
  209. type,
  210. qm, qm_size, 0);
  211. if (result) {
  212. av_log(avctx, AV_LOG_ERROR,
  213. "Failed to add inverse quantization matrix buffer\n");
  214. goto end;
  215. }
  216. buffer_count++;
  217. }
  218. #if CONFIG_D3D11VA
  219. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  220. buffer = &buffer11[buffer_count + 0];
  221. buffer_slice = &buffer11[buffer_count + 1];
  222. }
  223. #endif
  224. #if CONFIG_DXVA2
  225. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  226. buffer = &buffer2[buffer_count + 0];
  227. buffer_slice = &buffer2[buffer_count + 1];
  228. }
  229. #endif
  230. result = commit_bs_si(avctx,
  231. buffer,
  232. buffer_slice);
  233. if (result) {
  234. av_log(avctx, AV_LOG_ERROR,
  235. "Failed to add bitstream or slice control buffer\n");
  236. goto end;
  237. }
  238. buffer_count += 2;
  239. /* TODO Film Grain when possible */
  240. assert(buffer_count == 1 + (qm_size > 0) + 2);
  241. #if CONFIG_D3D11VA
  242. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  243. hr = ID3D11VideoContext_SubmitDecoderBuffers(D3D11VA_CONTEXT(ctx)->video_context,
  244. D3D11VA_CONTEXT(ctx)->decoder,
  245. buffer_count, buffer11);
  246. #endif
  247. #if CONFIG_DXVA2
  248. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  249. DXVA2_DecodeExecuteParams exec = {
  250. .NumCompBuffers = buffer_count,
  251. .pCompressedBuffers = buffer2,
  252. .pExtensionData = NULL,
  253. };
  254. hr = IDirectXVideoDecoder_Execute(DXVA2_CONTEXT(ctx)->decoder, &exec);
  255. }
  256. #endif
  257. if (FAILED(hr)) {
  258. av_log(avctx, AV_LOG_ERROR, "Failed to execute: 0x%lx\n", hr);
  259. result = -1;
  260. }
  261. end:
  262. #if CONFIG_D3D11VA
  263. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  264. hr = ID3D11VideoContext_DecoderEndFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder);
  265. if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE)
  266. ReleaseMutex(D3D11VA_CONTEXT(ctx)->context_mutex);
  267. }
  268. #endif
  269. #if CONFIG_DXVA2
  270. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
  271. hr = IDirectXVideoDecoder_EndFrame(DXVA2_CONTEXT(ctx)->decoder, NULL);
  272. #endif
  273. if (FAILED(hr)) {
  274. av_log(avctx, AV_LOG_ERROR, "Failed to end frame: 0x%lx\n", hr);
  275. result = -1;
  276. }
  277. return result;
  278. }