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.

336 lines
10KB

  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/opt.h"
  22. #include "libavutil/pixdesc.h"
  23. #include "avfilter.h"
  24. #include "formats.h"
  25. #include "internal.h"
  26. #include "video.h"
  27. typedef struct HWMapContext {
  28. const AVClass *class;
  29. AVBufferRef *hwdevice_ref;
  30. AVBufferRef *hwframes_ref;
  31. int mode;
  32. int map_backwards;
  33. } HWMapContext;
  34. static int hwmap_query_formats(AVFilterContext *avctx)
  35. {
  36. ff_formats_ref(ff_all_formats(AVMEDIA_TYPE_VIDEO),
  37. &avctx->inputs[0]->out_formats);
  38. ff_formats_ref(ff_all_formats(AVMEDIA_TYPE_VIDEO),
  39. &avctx->outputs[0]->in_formats);
  40. return 0;
  41. }
  42. static int hwmap_config_output(AVFilterLink *outlink)
  43. {
  44. AVFilterContext *avctx = outlink->src;
  45. HWMapContext *ctx = avctx->priv;
  46. AVFilterLink *inlink = avctx->inputs[0];
  47. AVHWFramesContext *hwfc;
  48. const AVPixFmtDescriptor *desc;
  49. int err;
  50. av_log(avctx, AV_LOG_DEBUG, "Configure hwmap %s -> %s.\n",
  51. av_get_pix_fmt_name(inlink->format),
  52. av_get_pix_fmt_name(outlink->format));
  53. if (inlink->hw_frames_ctx) {
  54. hwfc = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
  55. desc = av_pix_fmt_desc_get(outlink->format);
  56. if (!desc)
  57. return AVERROR(EINVAL);
  58. if (inlink->format == hwfc->format &&
  59. (desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) {
  60. // Map between two hardware formats (including the case of
  61. // undoing an existing mapping).
  62. ctx->hwdevice_ref = av_buffer_ref(avctx->hw_device_ctx);
  63. if (!ctx->hwdevice_ref) {
  64. err = AVERROR(ENOMEM);
  65. goto fail;
  66. }
  67. err = av_hwframe_ctx_create_derived(&ctx->hwframes_ref,
  68. outlink->format,
  69. ctx->hwdevice_ref,
  70. inlink->hw_frames_ctx, 0);
  71. if (err < 0)
  72. goto fail;
  73. } else if ((outlink->format == hwfc->format &&
  74. inlink->format == hwfc->sw_format) ||
  75. inlink->format == hwfc->format) {
  76. // Map from a hardware format to a software format, or
  77. // undo an existing such mapping.
  78. ctx->hwdevice_ref = NULL;
  79. ctx->hwframes_ref = av_buffer_ref(inlink->hw_frames_ctx);
  80. if (!ctx->hwframes_ref) {
  81. err = AVERROR(ENOMEM);
  82. goto fail;
  83. }
  84. } else {
  85. // Non-matching formats - not supported.
  86. av_log(avctx, AV_LOG_ERROR, "Unsupported formats for "
  87. "hwmap: from %s (%s) to %s.\n",
  88. av_get_pix_fmt_name(inlink->format),
  89. av_get_pix_fmt_name(hwfc->format),
  90. av_get_pix_fmt_name(outlink->format));
  91. err = AVERROR(EINVAL);
  92. goto fail;
  93. }
  94. } else if (avctx->hw_device_ctx) {
  95. // Map from a software format to a hardware format. This
  96. // creates a new hwframe context like hwupload, but then
  97. // returns frames mapped from that to the previous link in
  98. // order to fill them without an additional copy.
  99. ctx->map_backwards = 1;
  100. ctx->hwdevice_ref = av_buffer_ref(avctx->hw_device_ctx);
  101. if (!ctx->hwdevice_ref) {
  102. err = AVERROR(ENOMEM);
  103. goto fail;
  104. }
  105. ctx->hwframes_ref = av_hwframe_ctx_alloc(ctx->hwdevice_ref);
  106. if (!ctx->hwframes_ref) {
  107. err = AVERROR(ENOMEM);
  108. goto fail;
  109. }
  110. hwfc = (AVHWFramesContext*)ctx->hwframes_ref->data;
  111. hwfc->format = outlink->format;
  112. hwfc->sw_format = inlink->format;
  113. hwfc->width = inlink->w;
  114. hwfc->height = inlink->h;
  115. err = av_hwframe_ctx_init(ctx->hwframes_ref);
  116. if (err < 0) {
  117. av_log(avctx, AV_LOG_ERROR, "Failed to create frame "
  118. "context for backward mapping: %d.\n", err);
  119. goto fail;
  120. }
  121. } else {
  122. av_log(avctx, AV_LOG_ERROR, "Mapping requires a hardware "
  123. "context (a device, or frames on input).\n");
  124. return AVERROR(EINVAL);
  125. }
  126. outlink->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref);
  127. if (!outlink->hw_frames_ctx) {
  128. err = AVERROR(ENOMEM);
  129. goto fail;
  130. }
  131. outlink->w = inlink->w;
  132. outlink->h = inlink->h;
  133. return 0;
  134. fail:
  135. av_buffer_unref(&ctx->hwframes_ref);
  136. av_buffer_unref(&ctx->hwdevice_ref);
  137. return err;
  138. }
  139. static AVFrame *hwmap_get_buffer(AVFilterLink *inlink, int w, int h)
  140. {
  141. AVFilterContext *avctx = inlink->dst;
  142. AVFilterLink *outlink = avctx->outputs[0];
  143. HWMapContext *ctx = avctx->priv;
  144. if (ctx->map_backwards) {
  145. AVFrame *src, *dst;
  146. int err;
  147. src = ff_get_video_buffer(outlink, w, h);
  148. if (!src) {
  149. av_log(avctx, AV_LOG_ERROR, "Failed to allocate source "
  150. "frame for software mapping.\n");
  151. return NULL;
  152. }
  153. dst = av_frame_alloc();
  154. if (!dst) {
  155. av_frame_free(&src);
  156. return NULL;
  157. }
  158. err = av_hwframe_map(dst, src, ctx->mode);
  159. if (err) {
  160. av_log(avctx, AV_LOG_ERROR, "Failed to map frame to "
  161. "software: %d.\n", err);
  162. av_frame_free(&src);
  163. av_frame_free(&dst);
  164. return NULL;
  165. }
  166. av_frame_free(&src);
  167. return dst;
  168. } else {
  169. return ff_default_get_video_buffer(inlink, w, h);
  170. }
  171. }
  172. static int hwmap_filter_frame(AVFilterLink *link, AVFrame *input)
  173. {
  174. AVFilterContext *avctx = link->dst;
  175. AVFilterLink *outlink = avctx->outputs[0];
  176. HWMapContext *ctx = avctx->priv;
  177. AVFrame *map = NULL;
  178. int err;
  179. av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n",
  180. av_get_pix_fmt_name(input->format),
  181. input->width, input->height, input->pts);
  182. map = av_frame_alloc();
  183. if (!map) {
  184. err = AVERROR(ENOMEM);
  185. goto fail;
  186. }
  187. map->format = outlink->format;
  188. map->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref);
  189. if (!map->hw_frames_ctx) {
  190. err = AVERROR(ENOMEM);
  191. goto fail;
  192. }
  193. if (ctx->map_backwards && !input->hw_frames_ctx) {
  194. // If we mapped backwards from hardware to software, we need
  195. // to attach the hardware frame context to the input frame to
  196. // make the mapping visible to av_hwframe_map().
  197. input->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref);
  198. if (!input->hw_frames_ctx) {
  199. err = AVERROR(ENOMEM);
  200. goto fail;
  201. }
  202. }
  203. err = av_hwframe_map(map, input, ctx->mode);
  204. if (err < 0) {
  205. av_log(avctx, AV_LOG_ERROR, "Failed to map frame: %d.\n", err);
  206. goto fail;
  207. }
  208. err = av_frame_copy_props(map, input);
  209. if (err < 0)
  210. goto fail;
  211. av_frame_free(&input);
  212. av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n",
  213. av_get_pix_fmt_name(map->format),
  214. map->width, map->height, map->pts);
  215. return ff_filter_frame(outlink, map);
  216. fail:
  217. av_frame_free(&input);
  218. av_frame_free(&map);
  219. return err;
  220. }
  221. static av_cold void hwmap_uninit(AVFilterContext *avctx)
  222. {
  223. HWMapContext *ctx = avctx->priv;
  224. av_buffer_unref(&ctx->hwframes_ref);
  225. av_buffer_unref(&ctx->hwdevice_ref);
  226. }
  227. #define OFFSET(x) offsetof(HWMapContext, x)
  228. #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM)
  229. static const AVOption hwmap_options[] = {
  230. { "mode", "Frame mapping mode",
  231. OFFSET(mode), AV_OPT_TYPE_FLAGS,
  232. { .i64 = AV_HWFRAME_MAP_READ | AV_HWFRAME_MAP_WRITE },
  233. 0, INT_MAX, FLAGS, "mode" },
  234. { "read", "Mapping should be readable",
  235. 0, AV_OPT_TYPE_CONST, { .i64 = AV_HWFRAME_MAP_READ },
  236. INT_MIN, INT_MAX, FLAGS, "mode" },
  237. { "write", "Mapping should be writeable",
  238. 0, AV_OPT_TYPE_CONST, { .i64 = AV_HWFRAME_MAP_WRITE },
  239. INT_MIN, INT_MAX, FLAGS, "mode" },
  240. { "overwrite", "Mapping will always overwrite the entire frame",
  241. 0, AV_OPT_TYPE_CONST, { .i64 = AV_HWFRAME_MAP_OVERWRITE },
  242. INT_MIN, INT_MAX, FLAGS, "mode" },
  243. { "direct", "Mapping should not involve any copying",
  244. 0, AV_OPT_TYPE_CONST, { .i64 = AV_HWFRAME_MAP_DIRECT },
  245. INT_MIN, INT_MAX, FLAGS, "mode" },
  246. { NULL },
  247. };
  248. static const AVClass hwmap_class = {
  249. .class_name = "hwmap",
  250. .item_name = av_default_item_name,
  251. .option = hwmap_options,
  252. .version = LIBAVUTIL_VERSION_INT,
  253. };
  254. static const AVFilterPad hwmap_inputs[] = {
  255. {
  256. .name = "default",
  257. .type = AVMEDIA_TYPE_VIDEO,
  258. .get_video_buffer = &hwmap_get_buffer,
  259. .filter_frame = &hwmap_filter_frame,
  260. },
  261. { NULL }
  262. };
  263. static const AVFilterPad hwmap_outputs[] = {
  264. {
  265. .name = "default",
  266. .type = AVMEDIA_TYPE_VIDEO,
  267. .config_props = &hwmap_config_output,
  268. },
  269. { NULL }
  270. };
  271. AVFilter ff_vf_hwmap = {
  272. .name = "hwmap",
  273. .description = NULL_IF_CONFIG_SMALL("Map hardware frames"),
  274. .uninit = &hwmap_uninit,
  275. .priv_size = sizeof(HWMapContext),
  276. .priv_class = &hwmap_class,
  277. .query_formats = &hwmap_query_formats,
  278. .inputs = hwmap_inputs,
  279. .outputs = hwmap_outputs,
  280. .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
  281. };