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.

278 lines
9.0KB

  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 "mpegvideo.h"
  28. #include "dxva2_internal.h"
  29. void *ff_dxva2_get_surface(const AVFrame *frame)
  30. {
  31. return frame->data[3];
  32. }
  33. unsigned ff_dxva2_get_surface_index(const AVCodecContext *avctx,
  34. const AVDXVAContext *ctx,
  35. const AVFrame *frame)
  36. {
  37. void *surface = ff_dxva2_get_surface(frame);
  38. unsigned i;
  39. for (i = 0; i < DXVA_CONTEXT_COUNT(avctx, ctx); i++)
  40. if (DXVA_CONTEXT_SURFACE(avctx, ctx, i) == surface)
  41. return i;
  42. assert(0);
  43. return 0;
  44. }
  45. int ff_dxva2_commit_buffer(AVCodecContext *avctx,
  46. AVDXVAContext *ctx,
  47. DECODER_BUFFER_DESC *dsc,
  48. unsigned type, const void *data, unsigned size,
  49. unsigned mb_count)
  50. {
  51. void *dxva_data;
  52. unsigned dxva_size;
  53. int result;
  54. HRESULT hr;
  55. #if CONFIG_D3D11VA
  56. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  57. hr = ID3D11VideoContext_GetDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context,
  58. D3D11VA_CONTEXT(ctx)->decoder,
  59. type,
  60. &dxva_size, &dxva_data);
  61. #endif
  62. #if CONFIG_DXVA2
  63. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
  64. hr = IDirectXVideoDecoder_GetBuffer(DXVA2_CONTEXT(ctx)->decoder, type,
  65. &dxva_data, &dxva_size);
  66. #endif
  67. if (FAILED(hr)) {
  68. av_log(avctx, AV_LOG_ERROR, "Failed to get a buffer for %u: 0x%lx\n",
  69. type, hr);
  70. return -1;
  71. }
  72. if (size <= dxva_size) {
  73. memcpy(dxva_data, data, size);
  74. #if CONFIG_D3D11VA
  75. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  76. D3D11_VIDEO_DECODER_BUFFER_DESC *dsc11 = dsc;
  77. memset(dsc11, 0, sizeof(*dsc11));
  78. dsc11->BufferType = type;
  79. dsc11->DataSize = size;
  80. dsc11->NumMBsInBuffer = mb_count;
  81. }
  82. #endif
  83. #if CONFIG_DXVA2
  84. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  85. DXVA2_DecodeBufferDesc *dsc2 = dsc;
  86. memset(dsc2, 0, sizeof(*dsc2));
  87. dsc2->CompressedBufferType = type;
  88. dsc2->DataSize = size;
  89. dsc2->NumMBsInBuffer = mb_count;
  90. }
  91. #endif
  92. result = 0;
  93. } else {
  94. av_log(avctx, AV_LOG_ERROR, "Buffer for type %u was too small\n", type);
  95. result = -1;
  96. }
  97. #if CONFIG_D3D11VA
  98. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  99. hr = ID3D11VideoContext_ReleaseDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder, type);
  100. #endif
  101. #if CONFIG_DXVA2
  102. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
  103. hr = IDirectXVideoDecoder_ReleaseBuffer(DXVA2_CONTEXT(ctx)->decoder, type);
  104. #endif
  105. if (FAILED(hr)) {
  106. av_log(avctx, AV_LOG_ERROR,
  107. "Failed to release buffer type %u: 0x%lx\n",
  108. type, hr);
  109. result = -1;
  110. }
  111. return result;
  112. }
  113. int ff_dxva2_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
  114. const void *pp, unsigned pp_size,
  115. const void *qm, unsigned qm_size,
  116. int (*commit_bs_si)(AVCodecContext *,
  117. DECODER_BUFFER_DESC *bs,
  118. DECODER_BUFFER_DESC *slice))
  119. {
  120. AVDXVAContext *ctx = avctx->hwaccel_context;
  121. unsigned buffer_count = 0;
  122. #if CONFIG_D3D11VA
  123. D3D11_VIDEO_DECODER_BUFFER_DESC buffer11[4];
  124. #endif
  125. #if CONFIG_DXVA2
  126. DXVA2_DecodeBufferDesc buffer2[4];
  127. #endif
  128. DECODER_BUFFER_DESC *buffer,*buffer_slice;
  129. int result, runs = 0;
  130. HRESULT hr;
  131. unsigned type;
  132. do {
  133. #if CONFIG_D3D11VA
  134. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  135. hr = ID3D11VideoContext_DecoderBeginFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder,
  136. ff_dxva2_get_surface(frame),
  137. 0, NULL);
  138. #endif
  139. #if CONFIG_DXVA2
  140. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
  141. hr = IDirectXVideoDecoder_BeginFrame(DXVA2_CONTEXT(ctx)->decoder,
  142. ff_dxva2_get_surface(frame),
  143. NULL);
  144. #endif
  145. if (hr == E_PENDING)
  146. av_usleep(2000);
  147. } while (hr == E_PENDING && ++runs < 50);
  148. if (FAILED(hr)) {
  149. av_log(avctx, AV_LOG_ERROR, "Failed to begin frame: 0x%lx\n", hr);
  150. return -1;
  151. }
  152. #if CONFIG_D3D11VA
  153. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  154. buffer = &buffer11[buffer_count];
  155. type = D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS;
  156. }
  157. #endif
  158. #if CONFIG_DXVA2
  159. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  160. buffer = &buffer2[buffer_count];
  161. type = DXVA2_PictureParametersBufferType;
  162. }
  163. #endif
  164. result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
  165. type,
  166. pp, pp_size, 0);
  167. if (result) {
  168. av_log(avctx, AV_LOG_ERROR,
  169. "Failed to add picture parameter buffer\n");
  170. goto end;
  171. }
  172. buffer_count++;
  173. if (qm_size > 0) {
  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_INVERSE_QUANTIZATION_MATRIX;
  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_InverseQuantizationMatrixBufferType;
  184. }
  185. #endif
  186. result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
  187. type,
  188. qm, qm_size, 0);
  189. if (result) {
  190. av_log(avctx, AV_LOG_ERROR,
  191. "Failed to add inverse quantization matrix buffer\n");
  192. goto end;
  193. }
  194. buffer_count++;
  195. }
  196. #if CONFIG_D3D11VA
  197. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  198. buffer = &buffer11[buffer_count + 0];
  199. buffer_slice = &buffer11[buffer_count + 1];
  200. }
  201. #endif
  202. #if CONFIG_DXVA2
  203. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  204. buffer = &buffer2[buffer_count + 0];
  205. buffer_slice = &buffer2[buffer_count + 1];
  206. }
  207. #endif
  208. result = commit_bs_si(avctx,
  209. buffer,
  210. buffer_slice);
  211. if (result) {
  212. av_log(avctx, AV_LOG_ERROR,
  213. "Failed to add bitstream or slice control buffer\n");
  214. goto end;
  215. }
  216. buffer_count += 2;
  217. /* TODO Film Grain when possible */
  218. assert(buffer_count == 1 + (qm_size > 0) + 2);
  219. #if CONFIG_D3D11VA
  220. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  221. hr = ID3D11VideoContext_SubmitDecoderBuffers(D3D11VA_CONTEXT(ctx)->video_context,
  222. D3D11VA_CONTEXT(ctx)->decoder,
  223. buffer_count, buffer11);
  224. #endif
  225. #if CONFIG_DXVA2
  226. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  227. DXVA2_DecodeExecuteParams exec = {
  228. .NumCompBuffers = buffer_count,
  229. .pCompressedBuffers = buffer2,
  230. .pExtensionData = NULL,
  231. };
  232. hr = IDirectXVideoDecoder_Execute(DXVA2_CONTEXT(ctx)->decoder, &exec);
  233. }
  234. #endif
  235. if (FAILED(hr)) {
  236. av_log(avctx, AV_LOG_ERROR, "Failed to execute: 0x%lx\n", hr);
  237. result = -1;
  238. }
  239. end:
  240. #if CONFIG_D3D11VA
  241. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  242. hr = ID3D11VideoContext_DecoderEndFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder);
  243. #endif
  244. #if CONFIG_DXVA2
  245. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
  246. hr = IDirectXVideoDecoder_EndFrame(DXVA2_CONTEXT(ctx)->decoder, NULL);
  247. #endif
  248. if (FAILED(hr)) {
  249. av_log(avctx, AV_LOG_ERROR, "Failed to end frame: 0x%lx\n", hr);
  250. result = -1;
  251. }
  252. return result;
  253. }