vf_hwdownload.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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/buffer.h"
  19. #include "libavutil/hwcontext.h"
  20. #include "libavutil/log.h"
  21. #include "libavutil/mem.h"
  22. #include "libavutil/opt.h"
  23. #include "libavutil/pixdesc.h"
  24. #include "avfilter.h"
  25. #include "formats.h"
  26. #include "internal.h"
  27. #include "video.h"
  28. typedef struct HWDownloadContext {
  29. const AVClass *class;
  30. AVBufferRef *hwframes_ref;
  31. AVHWFramesContext *hwframes;
  32. } HWDownloadContext;
  33. static int hwdownload_query_formats(AVFilterContext *avctx)
  34. {
  35. AVFilterFormats *infmts = NULL;
  36. AVFilterFormats *outfmts = NULL;
  37. const AVPixFmtDescriptor *desc;
  38. int err;
  39. for (desc = av_pix_fmt_desc_next(NULL); desc;
  40. desc = av_pix_fmt_desc_next(desc)) {
  41. if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL)
  42. err = ff_add_format(&infmts, av_pix_fmt_desc_get_id(desc));
  43. else
  44. err = ff_add_format(&outfmts, av_pix_fmt_desc_get_id(desc));
  45. if (err) {
  46. ff_formats_unref(&infmts);
  47. ff_formats_unref(&outfmts);
  48. return err;
  49. }
  50. }
  51. if ((err = ff_formats_ref(infmts, &avctx->inputs[0]->out_formats)) < 0 ||
  52. (err = ff_formats_ref(outfmts, &avctx->outputs[0]->in_formats)) < 0)
  53. return err;
  54. return 0;
  55. }
  56. static int hwdownload_config_input(AVFilterLink *inlink)
  57. {
  58. AVFilterContext *avctx = inlink->dst;
  59. HWDownloadContext *ctx = avctx->priv;
  60. av_buffer_unref(&ctx->hwframes_ref);
  61. if (!inlink->hw_frames_ctx) {
  62. av_log(ctx, AV_LOG_ERROR, "The input must have a hardware frame "
  63. "reference.\n");
  64. return AVERROR(EINVAL);
  65. }
  66. ctx->hwframes_ref = av_buffer_ref(inlink->hw_frames_ctx);
  67. if (!ctx->hwframes_ref)
  68. return AVERROR(ENOMEM);
  69. ctx->hwframes = (AVHWFramesContext*)ctx->hwframes_ref->data;
  70. return 0;
  71. }
  72. static int hwdownload_config_output(AVFilterLink *outlink)
  73. {
  74. AVFilterContext *avctx = outlink->src;
  75. AVFilterLink *inlink = avctx->inputs[0];
  76. HWDownloadContext *ctx = avctx->priv;
  77. enum AVPixelFormat *formats;
  78. int err, i, found;
  79. if (!ctx->hwframes_ref)
  80. return AVERROR(EINVAL);
  81. err = av_hwframe_transfer_get_formats(ctx->hwframes_ref,
  82. AV_HWFRAME_TRANSFER_DIRECTION_FROM,
  83. &formats, 0);
  84. if (err < 0)
  85. return err;
  86. found = 0;
  87. for (i = 0; formats[i] != AV_PIX_FMT_NONE; i++) {
  88. if (formats[i] == outlink->format) {
  89. found = 1;
  90. break;
  91. }
  92. }
  93. av_freep(&formats);
  94. if (!found) {
  95. av_log(ctx, AV_LOG_ERROR, "Invalid output format %s for hwframe "
  96. "download.\n", av_get_pix_fmt_name(outlink->format));
  97. return AVERROR(EINVAL);
  98. }
  99. outlink->w = inlink->w;
  100. outlink->h = inlink->h;
  101. return 0;
  102. }
  103. static int hwdownload_filter_frame(AVFilterLink *link, AVFrame *input)
  104. {
  105. AVFilterContext *avctx = link->dst;
  106. AVFilterLink *outlink = avctx->outputs[0];
  107. HWDownloadContext *ctx = avctx->priv;
  108. AVFrame *output = NULL;
  109. int err;
  110. if (!ctx->hwframes_ref || !input->hw_frames_ctx) {
  111. av_log(ctx, AV_LOG_ERROR, "Input frames must have hardware context.\n");
  112. err = AVERROR(EINVAL);
  113. goto fail;
  114. }
  115. if ((void*)ctx->hwframes != input->hw_frames_ctx->data) {
  116. av_log(ctx, AV_LOG_ERROR, "Input frame is not the in the configured "
  117. "hwframe context.\n");
  118. err = AVERROR(EINVAL);
  119. goto fail;
  120. }
  121. output = ff_get_video_buffer(outlink, outlink->w, outlink->h);
  122. if (!output) {
  123. err = AVERROR(ENOMEM);
  124. goto fail;
  125. }
  126. err = av_hwframe_transfer_data(output, input, 0);
  127. if (err < 0) {
  128. av_log(ctx, AV_LOG_ERROR, "Failed to download frame: %d.\n", err);
  129. goto fail;
  130. }
  131. err = av_frame_copy_props(output, input);
  132. if (err < 0)
  133. goto fail;
  134. av_frame_free(&input);
  135. return ff_filter_frame(avctx->outputs[0], output);
  136. fail:
  137. av_frame_free(&input);
  138. av_frame_free(&output);
  139. return err;
  140. }
  141. static av_cold void hwdownload_uninit(AVFilterContext *avctx)
  142. {
  143. HWDownloadContext *ctx = avctx->priv;
  144. av_buffer_unref(&ctx->hwframes_ref);
  145. }
  146. static const AVClass hwdownload_class = {
  147. .class_name = "hwdownload",
  148. .item_name = av_default_item_name,
  149. .option = NULL,
  150. .version = LIBAVUTIL_VERSION_INT,
  151. };
  152. static const AVFilterPad hwdownload_inputs[] = {
  153. {
  154. .name = "default",
  155. .type = AVMEDIA_TYPE_VIDEO,
  156. .config_props = hwdownload_config_input,
  157. .filter_frame = hwdownload_filter_frame,
  158. },
  159. { NULL }
  160. };
  161. static const AVFilterPad hwdownload_outputs[] = {
  162. {
  163. .name = "default",
  164. .type = AVMEDIA_TYPE_VIDEO,
  165. .config_props = hwdownload_config_output,
  166. },
  167. { NULL }
  168. };
  169. AVFilter ff_vf_hwdownload = {
  170. .name = "hwdownload",
  171. .description = NULL_IF_CONFIG_SMALL("Download a hardware frame to a normal frame"),
  172. .uninit = hwdownload_uninit,
  173. .query_formats = hwdownload_query_formats,
  174. .priv_size = sizeof(HWDownloadContext),
  175. .priv_class = &hwdownload_class,
  176. .inputs = hwdownload_inputs,
  177. .outputs = hwdownload_outputs,
  178. };