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.

175 lines
5.3KB

  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 struct dxva_context *ctx,
  34. const AVFrame *frame)
  35. {
  36. void *surface = ff_dxva2_get_surface(frame);
  37. unsigned i;
  38. for (i = 0; i < ctx->surface_count; i++)
  39. if (ctx->surface[i] == surface)
  40. return i;
  41. assert(0);
  42. return 0;
  43. }
  44. int ff_dxva2_commit_buffer(AVCodecContext *avctx,
  45. struct dxva_context *ctx,
  46. DXVA2_DecodeBufferDesc *dsc,
  47. unsigned type, const void *data, unsigned size,
  48. unsigned mb_count)
  49. {
  50. void *dxva_data;
  51. unsigned dxva_size;
  52. int result;
  53. HRESULT hr;
  54. hr = IDirectXVideoDecoder_GetBuffer(ctx->decoder, type,
  55. &dxva_data, &dxva_size);
  56. if (FAILED(hr)) {
  57. av_log(avctx, AV_LOG_ERROR, "Failed to get a buffer for %u: 0x%lx\n",
  58. type, hr);
  59. return -1;
  60. }
  61. if (size <= dxva_size) {
  62. memcpy(dxva_data, data, size);
  63. memset(dsc, 0, sizeof(*dsc));
  64. dsc->CompressedBufferType = type;
  65. dsc->DataSize = size;
  66. dsc->NumMBsInBuffer = mb_count;
  67. result = 0;
  68. } else {
  69. av_log(avctx, AV_LOG_ERROR, "Buffer for type %u was too small\n", type);
  70. result = -1;
  71. }
  72. hr = IDirectXVideoDecoder_ReleaseBuffer(ctx->decoder, type);
  73. if (FAILED(hr)) {
  74. av_log(avctx, AV_LOG_ERROR,
  75. "Failed to release buffer type %u: 0x%lx\n",
  76. type, hr);
  77. result = -1;
  78. }
  79. return result;
  80. }
  81. int ff_dxva2_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
  82. const void *pp, unsigned pp_size,
  83. const void *qm, unsigned qm_size,
  84. int (*commit_bs_si)(AVCodecContext *,
  85. DXVA2_DecodeBufferDesc *bs,
  86. DXVA2_DecodeBufferDesc *slice))
  87. {
  88. struct dxva_context *ctx = avctx->hwaccel_context;
  89. unsigned buffer_count = 0;
  90. DXVA2_DecodeBufferDesc buffer[4];
  91. DXVA2_DecodeExecuteParams exec = { 0 };
  92. int result, runs = 0;
  93. HRESULT hr;
  94. do {
  95. hr = IDirectXVideoDecoder_BeginFrame(ctx->decoder,
  96. ff_dxva2_get_surface(frame),
  97. NULL);
  98. if (hr == E_PENDING)
  99. av_usleep(2000);
  100. } while (hr == E_PENDING && ++runs < 50);
  101. if (FAILED(hr)) {
  102. av_log(avctx, AV_LOG_ERROR, "Failed to begin frame: 0x%lx\n", hr);
  103. return -1;
  104. }
  105. result = ff_dxva2_commit_buffer(avctx, ctx, &buffer[buffer_count],
  106. DXVA2_PictureParametersBufferType,
  107. pp, pp_size, 0);
  108. if (result) {
  109. av_log(avctx, AV_LOG_ERROR,
  110. "Failed to add picture parameter buffer\n");
  111. goto end;
  112. }
  113. buffer_count++;
  114. if (qm_size > 0) {
  115. result = ff_dxva2_commit_buffer(avctx, ctx, &buffer[buffer_count],
  116. DXVA2_InverseQuantizationMatrixBufferType,
  117. qm, qm_size, 0);
  118. if (result) {
  119. av_log(avctx, AV_LOG_ERROR,
  120. "Failed to add inverse quantization matrix buffer\n");
  121. goto end;
  122. }
  123. buffer_count++;
  124. }
  125. result = commit_bs_si(avctx,
  126. &buffer[buffer_count + 0],
  127. &buffer[buffer_count + 1]);
  128. if (result) {
  129. av_log(avctx, AV_LOG_ERROR,
  130. "Failed to add bitstream or slice control buffer\n");
  131. goto end;
  132. }
  133. buffer_count += 2;
  134. /* TODO Film Grain when possible */
  135. assert(buffer_count == 1 + (qm_size > 0) + 2);
  136. exec.NumCompBuffers = buffer_count;
  137. exec.pCompressedBuffers = buffer;
  138. exec.pExtensionData = NULL;
  139. hr = IDirectXVideoDecoder_Execute(ctx->decoder, &exec);
  140. if (FAILED(hr)) {
  141. av_log(avctx, AV_LOG_ERROR, "Failed to execute: 0x%lx\n", hr);
  142. result = -1;
  143. }
  144. end:
  145. hr = IDirectXVideoDecoder_EndFrame(ctx->decoder, NULL);
  146. if (FAILED(hr)) {
  147. av_log(avctx, AV_LOG_ERROR, "Failed to end frame: 0x%lx\n", hr);
  148. result = -1;
  149. }
  150. return result;
  151. }