ffmpeg_cuvid.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /*
  2. * This file is part of FFmpeg.
  3. *
  4. * FFmpeg is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * FFmpeg is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with FFmpeg; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include "libavutil/hwcontext.h"
  19. #include "ffmpeg.h"
  20. typedef struct CUVIDContext {
  21. AVBufferRef *hw_frames_ctx;
  22. } CUVIDContext;
  23. static void cuvid_uninit(AVCodecContext *avctx)
  24. {
  25. InputStream *ist = avctx->opaque;
  26. CUVIDContext *ctx = ist->hwaccel_ctx;
  27. if (ctx) {
  28. av_buffer_unref(&ctx->hw_frames_ctx);
  29. av_freep(&ctx);
  30. }
  31. av_buffer_unref(&ist->hw_frames_ctx);
  32. ist->hwaccel_ctx = 0;
  33. ist->hwaccel_uninit = 0;
  34. }
  35. int cuvid_init(AVCodecContext *avctx)
  36. {
  37. InputStream *ist = avctx->opaque;
  38. CUVIDContext *ctx = ist->hwaccel_ctx;
  39. av_log(NULL, AV_LOG_TRACE, "Initializing cuvid hwaccel\n");
  40. if (!ctx) {
  41. av_log(NULL, AV_LOG_ERROR, "CUVID transcoding is not initialized. "
  42. "-hwaccel cuvid should only be used for one-to-one CUVID transcoding "
  43. "with no (software) filters.\n");
  44. return AVERROR(EINVAL);
  45. }
  46. return 0;
  47. }
  48. int cuvid_transcode_init(OutputStream *ost)
  49. {
  50. InputStream *ist;
  51. const enum AVPixelFormat *pix_fmt;
  52. AVHWFramesContext *hwframe_ctx;
  53. AVBufferRef *device_ref = NULL;
  54. CUVIDContext *ctx = NULL;
  55. int ret = 0;
  56. av_log(NULL, AV_LOG_TRACE, "Initializing cuvid transcoding\n");
  57. if (ost->source_index < 0)
  58. return 0;
  59. ist = input_streams[ost->source_index];
  60. /* check if the encoder supports CUVID */
  61. if (!ost->enc->pix_fmts)
  62. goto cancel;
  63. for (pix_fmt = ost->enc->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++)
  64. if (*pix_fmt == AV_PIX_FMT_CUDA)
  65. break;
  66. if (*pix_fmt == AV_PIX_FMT_NONE)
  67. goto cancel;
  68. /* check if the decoder supports CUVID */
  69. if (ist->hwaccel_id != HWACCEL_CUVID || !ist->dec || !ist->dec->pix_fmts)
  70. goto cancel;
  71. for (pix_fmt = ist->dec->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++)
  72. if (*pix_fmt == AV_PIX_FMT_CUDA)
  73. break;
  74. if (*pix_fmt == AV_PIX_FMT_NONE)
  75. goto cancel;
  76. av_log(NULL, AV_LOG_VERBOSE, "Setting up CUVID transcoding\n");
  77. if (ist->hwaccel_ctx) {
  78. ctx = ist->hwaccel_ctx;
  79. } else {
  80. ctx = av_mallocz(sizeof(*ctx));
  81. if (!ctx) {
  82. ret = AVERROR(ENOMEM);
  83. goto error;
  84. }
  85. }
  86. if (!ctx->hw_frames_ctx) {
  87. ret = av_hwdevice_ctx_create(&device_ref, AV_HWDEVICE_TYPE_CUDA,
  88. ist->hwaccel_device, NULL, 0);
  89. if (ret < 0)
  90. goto error;
  91. ctx->hw_frames_ctx = av_hwframe_ctx_alloc(device_ref);
  92. if (!ctx->hw_frames_ctx) {
  93. av_log(NULL, AV_LOG_ERROR, "av_hwframe_ctx_alloc failed\n");
  94. ret = AVERROR(ENOMEM);
  95. goto error;
  96. }
  97. av_buffer_unref(&device_ref);
  98. ist->hw_frames_ctx = av_buffer_ref(ctx->hw_frames_ctx);
  99. if (!ist->hw_frames_ctx) {
  100. av_log(NULL, AV_LOG_ERROR, "av_buffer_ref failed\n");
  101. ret = AVERROR(ENOMEM);
  102. goto error;
  103. }
  104. ist->hwaccel_ctx = ctx;
  105. ist->resample_pix_fmt = AV_PIX_FMT_CUDA;
  106. ist->hwaccel_uninit = cuvid_uninit;
  107. /* This is a bit hacky, av_hwframe_ctx_init is called by the cuvid decoder
  108. * once it has probed the necessary format information. But as filters/nvenc
  109. * need to know the format/sw_format, set them here so they are happy.
  110. * This is fine as long as CUVID doesn't add another supported pix_fmt.
  111. */
  112. hwframe_ctx = (AVHWFramesContext*)ctx->hw_frames_ctx->data;
  113. hwframe_ctx->format = AV_PIX_FMT_CUDA;
  114. hwframe_ctx->sw_format = AV_PIX_FMT_NV12;
  115. }
  116. return 0;
  117. error:
  118. av_freep(&ctx);
  119. av_buffer_unref(&device_ref);
  120. return ret;
  121. cancel:
  122. if (ist->hwaccel_id == HWACCEL_CUVID) {
  123. av_log(NULL, AV_LOG_ERROR, "CUVID hwaccel requested, but impossible to achieve.\n");
  124. return AVERROR(EINVAL);
  125. }
  126. return 0;
  127. }