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.

217 lines
6.0KB

  1. /*
  2. * This file is part of Libav.
  3. *
  4. * Libav 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. * Libav 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 Libav; 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. ff_formats_ref(infmts, &avctx->inputs[0]->out_formats);
  52. ff_formats_ref(outfmts, &avctx->outputs[0]->in_formats);
  53. return 0;
  54. }
  55. static int hwdownload_config_input(AVFilterLink *inlink)
  56. {
  57. AVFilterContext *avctx = inlink->dst;
  58. HWDownloadContext *ctx = avctx->priv;
  59. av_buffer_unref(&ctx->hwframes_ref);
  60. if (!inlink->hw_frames_ctx) {
  61. av_log(ctx, AV_LOG_ERROR, "The input must have a hardware frame "
  62. "reference.\n");
  63. return AVERROR(EINVAL);
  64. }
  65. ctx->hwframes_ref = av_buffer_ref(inlink->hw_frames_ctx);
  66. if (!ctx->hwframes_ref)
  67. return AVERROR(ENOMEM);
  68. ctx->hwframes = (AVHWFramesContext*)ctx->hwframes_ref->data;
  69. return 0;
  70. }
  71. static int hwdownload_config_output(AVFilterLink *outlink)
  72. {
  73. AVFilterContext *avctx = outlink->src;
  74. AVFilterLink *inlink = avctx->inputs[0];
  75. HWDownloadContext *ctx = avctx->priv;
  76. enum AVPixelFormat *formats;
  77. int err, i, found;
  78. if (!ctx->hwframes_ref)
  79. return AVERROR(EINVAL);
  80. err = av_hwframe_transfer_get_formats(ctx->hwframes_ref,
  81. AV_HWFRAME_TRANSFER_DIRECTION_FROM,
  82. &formats, 0);
  83. if (err < 0)
  84. return err;
  85. found = 0;
  86. for (i = 0; formats[i] != AV_PIX_FMT_NONE; i++) {
  87. if (formats[i] == outlink->format) {
  88. found = 1;
  89. break;
  90. }
  91. }
  92. av_freep(&formats);
  93. if (!found) {
  94. av_log(ctx, AV_LOG_ERROR, "Invalid output format %s for hwframe "
  95. "download.\n", av_get_pix_fmt_name(outlink->format));
  96. return AVERROR(EINVAL);
  97. }
  98. outlink->w = inlink->w;
  99. outlink->h = inlink->h;
  100. return 0;
  101. }
  102. static int hwdownload_filter_frame(AVFilterLink *link, AVFrame *input)
  103. {
  104. AVFilterContext *avctx = link->dst;
  105. AVFilterLink *outlink = avctx->outputs[0];
  106. HWDownloadContext *ctx = avctx->priv;
  107. AVFrame *output = NULL;
  108. int err;
  109. if (!ctx->hwframes_ref || !input->hw_frames_ctx) {
  110. av_log(ctx, AV_LOG_ERROR, "Input frames must have hardware context.\n");
  111. err = AVERROR(EINVAL);
  112. goto fail;
  113. }
  114. if ((void*)ctx->hwframes != input->hw_frames_ctx->data) {
  115. av_log(ctx, AV_LOG_ERROR, "Input frame is not the in the configured "
  116. "hwframe context.\n");
  117. err = AVERROR(EINVAL);
  118. goto fail;
  119. }
  120. output = ff_get_video_buffer(outlink, ctx->hwframes->width,
  121. ctx->hwframes->height);
  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. output->width = outlink->w;
  132. output->height = outlink->h;
  133. err = av_frame_copy_props(output, input);
  134. if (err < 0)
  135. goto fail;
  136. av_frame_free(&input);
  137. return ff_filter_frame(avctx->outputs[0], output);
  138. fail:
  139. av_frame_free(&input);
  140. av_frame_free(&output);
  141. return err;
  142. }
  143. static av_cold void hwdownload_uninit(AVFilterContext *avctx)
  144. {
  145. HWDownloadContext *ctx = avctx->priv;
  146. av_buffer_unref(&ctx->hwframes_ref);
  147. }
  148. static const AVClass hwdownload_class = {
  149. .class_name = "hwdownload",
  150. .item_name = av_default_item_name,
  151. .option = NULL,
  152. .version = LIBAVUTIL_VERSION_INT,
  153. };
  154. static const AVFilterPad hwdownload_inputs[] = {
  155. {
  156. .name = "default",
  157. .type = AVMEDIA_TYPE_VIDEO,
  158. .config_props = hwdownload_config_input,
  159. .filter_frame = hwdownload_filter_frame,
  160. },
  161. { NULL }
  162. };
  163. static const AVFilterPad hwdownload_outputs[] = {
  164. {
  165. .name = "default",
  166. .type = AVMEDIA_TYPE_VIDEO,
  167. .config_props = hwdownload_config_output,
  168. },
  169. { NULL }
  170. };
  171. AVFilter ff_vf_hwdownload = {
  172. .name = "hwdownload",
  173. .description = NULL_IF_CONFIG_SMALL("Download a hardware frame to a normal frame"),
  174. .uninit = hwdownload_uninit,
  175. .query_formats = hwdownload_query_formats,
  176. .priv_size = sizeof(HWDownloadContext),
  177. .priv_class = &hwdownload_class,
  178. .inputs = hwdownload_inputs,
  179. .outputs = hwdownload_outputs,
  180. .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
  181. };