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.

305 lines
10KB

  1. /*
  2. * DXVA2 HW acceleration.
  3. *
  4. * copyright (c) 2010 Laurent Aimar
  5. *
  6. * This file is part of FFmpeg.
  7. *
  8. * FFmpeg 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. * FFmpeg 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 FFmpeg; 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. static void *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 = 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. {
  42. D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
  43. ID3D11VideoDecoderOutputView_GetDesc(ctx->d3d11va.surface[i], &viewDesc);
  44. return viewDesc.Texture2D.ArraySlice;
  45. }
  46. #endif
  47. #if CONFIG_DXVA2
  48. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD && ctx->dxva2.surface[i] == surface)
  49. return i;
  50. #endif
  51. }
  52. assert(0);
  53. return 0;
  54. }
  55. int ff_dxva2_commit_buffer(AVCodecContext *avctx,
  56. AVDXVAContext *ctx,
  57. DECODER_BUFFER_DESC *dsc,
  58. unsigned type, const void *data, unsigned size,
  59. unsigned mb_count)
  60. {
  61. void *dxva_data;
  62. unsigned dxva_size;
  63. int result;
  64. HRESULT hr = 0;
  65. #if CONFIG_D3D11VA
  66. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  67. hr = ID3D11VideoContext_GetDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context,
  68. D3D11VA_CONTEXT(ctx)->decoder,
  69. type,
  70. &dxva_size, &dxva_data);
  71. #endif
  72. #if CONFIG_DXVA2
  73. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
  74. hr = IDirectXVideoDecoder_GetBuffer(DXVA2_CONTEXT(ctx)->decoder, type,
  75. &dxva_data, &dxva_size);
  76. #endif
  77. if (FAILED(hr)) {
  78. av_log(avctx, AV_LOG_ERROR, "Failed to get a buffer for %u: 0x%lx\n",
  79. type, hr);
  80. return -1;
  81. }
  82. if (size <= dxva_size) {
  83. memcpy(dxva_data, data, size);
  84. #if CONFIG_D3D11VA
  85. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  86. D3D11_VIDEO_DECODER_BUFFER_DESC *dsc11 = dsc;
  87. memset(dsc11, 0, sizeof(*dsc11));
  88. dsc11->BufferType = type;
  89. dsc11->DataSize = size;
  90. dsc11->NumMBsInBuffer = mb_count;
  91. }
  92. #endif
  93. #if CONFIG_DXVA2
  94. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  95. DXVA2_DecodeBufferDesc *dsc2 = dsc;
  96. memset(dsc2, 0, sizeof(*dsc2));
  97. dsc2->CompressedBufferType = type;
  98. dsc2->DataSize = size;
  99. dsc2->NumMBsInBuffer = mb_count;
  100. }
  101. #endif
  102. result = 0;
  103. } else {
  104. av_log(avctx, AV_LOG_ERROR, "Buffer for type %u was too small\n", type);
  105. result = -1;
  106. }
  107. #if CONFIG_D3D11VA
  108. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  109. hr = ID3D11VideoContext_ReleaseDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder, type);
  110. #endif
  111. #if CONFIG_DXVA2
  112. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
  113. hr = IDirectXVideoDecoder_ReleaseBuffer(DXVA2_CONTEXT(ctx)->decoder, type);
  114. #endif
  115. if (FAILED(hr)) {
  116. av_log(avctx, AV_LOG_ERROR,
  117. "Failed to release buffer type %u: 0x%lx\n",
  118. type, hr);
  119. result = -1;
  120. }
  121. return result;
  122. }
  123. int ff_dxva2_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
  124. const void *pp, unsigned pp_size,
  125. const void *qm, unsigned qm_size,
  126. int (*commit_bs_si)(AVCodecContext *,
  127. DECODER_BUFFER_DESC *bs,
  128. DECODER_BUFFER_DESC *slice))
  129. {
  130. AVDXVAContext *ctx = avctx->hwaccel_context;
  131. unsigned buffer_count = 0;
  132. #if CONFIG_D3D11VA
  133. D3D11_VIDEO_DECODER_BUFFER_DESC buffer11[4];
  134. #endif
  135. #if CONFIG_DXVA2
  136. DXVA2_DecodeBufferDesc buffer2[4];
  137. #endif
  138. DECODER_BUFFER_DESC *buffer = NULL, *buffer_slice = NULL;
  139. int result, runs = 0;
  140. HRESULT hr;
  141. unsigned type;
  142. do {
  143. #if CONFIG_D3D11VA
  144. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  145. if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE)
  146. WaitForSingleObjectEx(D3D11VA_CONTEXT(ctx)->context_mutex, INFINITE, FALSE);
  147. hr = ID3D11VideoContext_DecoderBeginFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder,
  148. get_surface(frame),
  149. 0, NULL);
  150. }
  151. #endif
  152. #if CONFIG_DXVA2
  153. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
  154. hr = IDirectXVideoDecoder_BeginFrame(DXVA2_CONTEXT(ctx)->decoder,
  155. get_surface(frame),
  156. NULL);
  157. #endif
  158. if (hr != E_PENDING || ++runs > 50)
  159. break;
  160. #if CONFIG_D3D11VA
  161. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  162. if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE)
  163. ReleaseMutex(D3D11VA_CONTEXT(ctx)->context_mutex);
  164. #endif
  165. av_usleep(2000);
  166. } while(1);
  167. if (FAILED(hr)) {
  168. av_log(avctx, AV_LOG_ERROR, "Failed to begin frame: 0x%lx\n", hr);
  169. #if CONFIG_D3D11VA
  170. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  171. if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE)
  172. ReleaseMutex(D3D11VA_CONTEXT(ctx)->context_mutex);
  173. #endif
  174. return -1;
  175. }
  176. #if CONFIG_D3D11VA
  177. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  178. buffer = &buffer11[buffer_count];
  179. type = D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS;
  180. }
  181. #endif
  182. #if CONFIG_DXVA2
  183. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  184. buffer = &buffer2[buffer_count];
  185. type = DXVA2_PictureParametersBufferType;
  186. }
  187. #endif
  188. result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
  189. type,
  190. pp, pp_size, 0);
  191. if (result) {
  192. av_log(avctx, AV_LOG_ERROR,
  193. "Failed to add picture parameter buffer\n");
  194. goto end;
  195. }
  196. buffer_count++;
  197. if (qm_size > 0) {
  198. #if CONFIG_D3D11VA
  199. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  200. buffer = &buffer11[buffer_count];
  201. type = D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX;
  202. }
  203. #endif
  204. #if CONFIG_DXVA2
  205. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  206. buffer = &buffer2[buffer_count];
  207. type = DXVA2_InverseQuantizationMatrixBufferType;
  208. }
  209. #endif
  210. result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
  211. type,
  212. qm, qm_size, 0);
  213. if (result) {
  214. av_log(avctx, AV_LOG_ERROR,
  215. "Failed to add inverse quantization matrix buffer\n");
  216. goto end;
  217. }
  218. buffer_count++;
  219. }
  220. #if CONFIG_D3D11VA
  221. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  222. buffer = &buffer11[buffer_count + 0];
  223. buffer_slice = &buffer11[buffer_count + 1];
  224. }
  225. #endif
  226. #if CONFIG_DXVA2
  227. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  228. buffer = &buffer2[buffer_count + 0];
  229. buffer_slice = &buffer2[buffer_count + 1];
  230. }
  231. #endif
  232. result = commit_bs_si(avctx,
  233. buffer,
  234. buffer_slice);
  235. if (result) {
  236. av_log(avctx, AV_LOG_ERROR,
  237. "Failed to add bitstream or slice control buffer\n");
  238. goto end;
  239. }
  240. buffer_count += 2;
  241. /* TODO Film Grain when possible */
  242. assert(buffer_count == 1 + (qm_size > 0) + 2);
  243. #if CONFIG_D3D11VA
  244. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
  245. hr = ID3D11VideoContext_SubmitDecoderBuffers(D3D11VA_CONTEXT(ctx)->video_context,
  246. D3D11VA_CONTEXT(ctx)->decoder,
  247. buffer_count, buffer11);
  248. #endif
  249. #if CONFIG_DXVA2
  250. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
  251. DXVA2_DecodeExecuteParams exec = {
  252. .NumCompBuffers = buffer_count,
  253. .pCompressedBuffers = buffer2,
  254. .pExtensionData = NULL,
  255. };
  256. hr = IDirectXVideoDecoder_Execute(DXVA2_CONTEXT(ctx)->decoder, &exec);
  257. }
  258. #endif
  259. if (FAILED(hr)) {
  260. av_log(avctx, AV_LOG_ERROR, "Failed to execute: 0x%lx\n", hr);
  261. result = -1;
  262. }
  263. end:
  264. #if CONFIG_D3D11VA
  265. if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
  266. hr = ID3D11VideoContext_DecoderEndFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder);
  267. if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE)
  268. ReleaseMutex(D3D11VA_CONTEXT(ctx)->context_mutex);
  269. }
  270. #endif
  271. #if CONFIG_DXVA2
  272. if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
  273. hr = IDirectXVideoDecoder_EndFrame(DXVA2_CONTEXT(ctx)->decoder, NULL);
  274. #endif
  275. if (FAILED(hr)) {
  276. av_log(avctx, AV_LOG_ERROR, "Failed to end frame: 0x%lx\n", hr);
  277. result = -1;
  278. }
  279. return result;
  280. }