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.

274 lines
8.9KB

  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. D3D11_VIDEO_DECODER_BUFFER_DESC buffer11[4];
  123. DXVA2_DecodeBufferDesc buffer2[4];
  124. DECODER_BUFFER_DESC *buffer,*buffer_slice;
  125. int result, runs = 0;
  126. HRESULT hr;
  127. unsigned type;
  128. do {
  129. #if CONFIG_D3D11VA
  130. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  131. hr = ID3D11VideoContext_DecoderBeginFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder,
  132. ff_dxva2_get_surface(frame),
  133. 0, NULL);
  134. #endif
  135. #if CONFIG_DXVA2
  136. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
  137. hr = IDirectXVideoDecoder_BeginFrame(DXVA2_CONTEXT(ctx)->decoder,
  138. ff_dxva2_get_surface(frame),
  139. NULL);
  140. #endif
  141. if (hr == E_PENDING)
  142. av_usleep(2000);
  143. } while (hr == E_PENDING && ++runs < 50);
  144. if (FAILED(hr)) {
  145. av_log(avctx, AV_LOG_ERROR, "Failed to begin frame: 0x%lx\n", hr);
  146. return -1;
  147. }
  148. #if CONFIG_D3D11VA
  149. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  150. buffer = &buffer11[buffer_count];
  151. type = D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS;
  152. }
  153. #endif
  154. #if CONFIG_DXVA2
  155. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  156. buffer = &buffer2[buffer_count];
  157. type = DXVA2_PictureParametersBufferType;
  158. }
  159. #endif
  160. result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
  161. type,
  162. pp, pp_size, 0);
  163. if (result) {
  164. av_log(avctx, AV_LOG_ERROR,
  165. "Failed to add picture parameter buffer\n");
  166. goto end;
  167. }
  168. buffer_count++;
  169. if (qm_size > 0) {
  170. #if CONFIG_D3D11VA
  171. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  172. buffer = &buffer11[buffer_count];
  173. type = D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX;
  174. }
  175. #endif
  176. #if CONFIG_DXVA2
  177. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  178. buffer = &buffer2[buffer_count];
  179. type = DXVA2_InverseQuantizationMatrixBufferType;
  180. }
  181. #endif
  182. result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
  183. type,
  184. qm, qm_size, 0);
  185. if (result) {
  186. av_log(avctx, AV_LOG_ERROR,
  187. "Failed to add inverse quantization matrix buffer\n");
  188. goto end;
  189. }
  190. buffer_count++;
  191. }
  192. #if CONFIG_D3D11VA
  193. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  194. buffer = &buffer11[buffer_count + 0];
  195. buffer_slice = &buffer11[buffer_count + 1];
  196. }
  197. #endif
  198. #if CONFIG_DXVA2
  199. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  200. buffer = &buffer2[buffer_count + 0];
  201. buffer_slice = &buffer2[buffer_count + 1];
  202. }
  203. #endif
  204. result = commit_bs_si(avctx,
  205. buffer,
  206. buffer_slice);
  207. if (result) {
  208. av_log(avctx, AV_LOG_ERROR,
  209. "Failed to add bitstream or slice control buffer\n");
  210. goto end;
  211. }
  212. buffer_count += 2;
  213. /* TODO Film Grain when possible */
  214. assert(buffer_count == 1 + (qm_size > 0) + 2);
  215. #if CONFIG_D3D11VA
  216. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  217. hr = ID3D11VideoContext_SubmitDecoderBuffers(D3D11VA_CONTEXT(ctx)->video_context,
  218. D3D11VA_CONTEXT(ctx)->decoder,
  219. buffer_count, buffer11);
  220. #endif
  221. #if CONFIG_DXVA2
  222. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  223. DXVA2_DecodeExecuteParams exec = {
  224. .NumCompBuffers = buffer_count,
  225. .pCompressedBuffers = buffer2,
  226. .pExtensionData = NULL,
  227. };
  228. hr = IDirectXVideoDecoder_Execute(DXVA2_CONTEXT(ctx)->decoder, &exec);
  229. }
  230. #endif
  231. if (FAILED(hr)) {
  232. av_log(avctx, AV_LOG_ERROR, "Failed to execute: 0x%lx\n", hr);
  233. result = -1;
  234. }
  235. end:
  236. #if CONFIG_D3D11VA
  237. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  238. hr = ID3D11VideoContext_DecoderEndFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder);
  239. #endif
  240. #if CONFIG_DXVA2
  241. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
  242. hr = IDirectXVideoDecoder_EndFrame(DXVA2_CONTEXT(ctx)->decoder, NULL);
  243. #endif
  244. if (FAILED(hr)) {
  245. av_log(avctx, AV_LOG_ERROR, "Failed to end frame: 0x%lx\n", hr);
  246. result = -1;
  247. }
  248. return result;
  249. }