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.

367 lines
11KB

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