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.

228 lines
6.7KB

  1. /*
  2. * Copyright (c) 2012 Steven Robertson
  3. *
  4. * This file is part of FFmpeg.
  5. *
  6. * FFmpeg is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * FFmpeg is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with FFmpeg; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. */
  20. /**
  21. * @file
  22. * copy an alpha component from another video's luma
  23. */
  24. #include <string.h>
  25. #include "libavutil/imgutils.h"
  26. #include "libavutil/opt.h"
  27. #include "libavutil/pixfmt.h"
  28. #include "avfilter.h"
  29. #include "drawutils.h"
  30. #include "formats.h"
  31. #include "filters.h"
  32. #include "internal.h"
  33. #include "video.h"
  34. enum { Y, U, V, A };
  35. typedef struct AlphaMergeContext {
  36. const AVClass *class;
  37. int is_packed_rgb;
  38. uint8_t rgba_map[4];
  39. AVFrame *main_frame;
  40. AVFrame *alpha_frame;
  41. } AlphaMergeContext;
  42. static int query_formats(AVFilterContext *ctx)
  43. {
  44. static const enum AVPixelFormat main_fmts[] = {
  45. AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
  46. AV_PIX_FMT_GBRAP,
  47. AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA, AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR,
  48. AV_PIX_FMT_NONE
  49. };
  50. static const enum AVPixelFormat alpha_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE };
  51. AVFilterFormats *main_formats = NULL, *alpha_formats = NULL;
  52. int ret;
  53. if (!(main_formats = ff_make_format_list(main_fmts)) ||
  54. !(alpha_formats = ff_make_format_list(alpha_fmts))) {
  55. ret = AVERROR(ENOMEM);
  56. goto fail;
  57. }
  58. if ((ret = ff_formats_ref(main_formats , &ctx->inputs[0]->out_formats)) < 0 ||
  59. (ret = ff_formats_ref(alpha_formats, &ctx->inputs[1]->out_formats)) < 0 ||
  60. (ret = ff_formats_ref(main_formats , &ctx->outputs[0]->in_formats)) < 0)
  61. goto fail;
  62. return 0;
  63. fail:
  64. if (main_formats)
  65. av_freep(&main_formats->formats);
  66. av_freep(&main_formats);
  67. if (alpha_formats)
  68. av_freep(&alpha_formats->formats);
  69. av_freep(&alpha_formats);
  70. return ret;
  71. }
  72. static int config_input_main(AVFilterLink *inlink)
  73. {
  74. AlphaMergeContext *s = inlink->dst->priv;
  75. s->is_packed_rgb =
  76. ff_fill_rgba_map(s->rgba_map, inlink->format) >= 0 &&
  77. inlink->format != AV_PIX_FMT_GBRAP;
  78. return 0;
  79. }
  80. static int config_output(AVFilterLink *outlink)
  81. {
  82. AVFilterContext *ctx = outlink->src;
  83. AVFilterLink *mainlink = ctx->inputs[0];
  84. AVFilterLink *alphalink = ctx->inputs[1];
  85. if (mainlink->w != alphalink->w || mainlink->h != alphalink->h) {
  86. av_log(ctx, AV_LOG_ERROR,
  87. "Input frame sizes do not match (%dx%d vs %dx%d).\n",
  88. mainlink->w, mainlink->h,
  89. alphalink->w, alphalink->h);
  90. return AVERROR(EINVAL);
  91. }
  92. outlink->w = mainlink->w;
  93. outlink->h = mainlink->h;
  94. outlink->time_base = mainlink->time_base;
  95. outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
  96. outlink->frame_rate = mainlink->frame_rate;
  97. return 0;
  98. }
  99. static void draw_frame(AVFilterContext *ctx,
  100. AVFrame *main_buf,
  101. AVFrame *alpha_buf)
  102. {
  103. AlphaMergeContext *s = ctx->priv;
  104. int h = main_buf->height;
  105. if (s->is_packed_rgb) {
  106. int x, y;
  107. uint8_t *pin, *pout;
  108. for (y = 0; y < h; y++) {
  109. pin = alpha_buf->data[0] + y * alpha_buf->linesize[0];
  110. pout = main_buf->data[0] + y * main_buf->linesize[0] + s->rgba_map[A];
  111. for (x = 0; x < main_buf->width; x++) {
  112. *pout = *pin;
  113. pin += 1;
  114. pout += 4;
  115. }
  116. }
  117. } else {
  118. const int main_linesize = main_buf->linesize[A];
  119. const int alpha_linesize = alpha_buf->linesize[Y];
  120. av_image_copy_plane(main_buf->data[A], main_linesize,
  121. alpha_buf->data[Y], alpha_linesize,
  122. FFMIN(main_linesize, alpha_linesize), alpha_buf->height);
  123. }
  124. }
  125. static int activate(AVFilterContext *ctx)
  126. {
  127. AVFilterLink *outlink = ctx->outputs[0];
  128. AlphaMergeContext *s = ctx->priv;
  129. int ret;
  130. FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx);
  131. if (!s->main_frame) {
  132. ret = ff_inlink_consume_frame(ctx->inputs[0], &s->main_frame);
  133. if (ret < 0)
  134. return ret;
  135. }
  136. if (!s->alpha_frame) {
  137. ret = ff_inlink_consume_frame(ctx->inputs[1], &s->alpha_frame);
  138. if (ret < 0)
  139. return ret;
  140. }
  141. if (s->main_frame && s->alpha_frame) {
  142. if (!ctx->is_disabled)
  143. draw_frame(ctx, s->main_frame, s->alpha_frame);
  144. ret = ff_filter_frame(outlink, s->main_frame);
  145. av_frame_free(&s->alpha_frame);
  146. s->main_frame = NULL;
  147. return ret;
  148. }
  149. FF_FILTER_FORWARD_STATUS(ctx->inputs[0], outlink);
  150. FF_FILTER_FORWARD_STATUS(ctx->inputs[1], outlink);
  151. if (ff_outlink_frame_wanted(ctx->outputs[0]) &&
  152. !ff_outlink_get_status(ctx->inputs[0]) &&
  153. !s->main_frame) {
  154. ff_inlink_request_frame(ctx->inputs[0]);
  155. return 0;
  156. }
  157. if (ff_outlink_frame_wanted(ctx->outputs[0]) &&
  158. !ff_outlink_get_status(ctx->inputs[1]) &&
  159. !s->alpha_frame) {
  160. ff_inlink_request_frame(ctx->inputs[1]);
  161. return 0;
  162. }
  163. return FFERROR_NOT_READY;
  164. }
  165. static const AVFilterPad alphamerge_inputs[] = {
  166. {
  167. .name = "main",
  168. .type = AVMEDIA_TYPE_VIDEO,
  169. .config_props = config_input_main,
  170. .needs_writable = 1,
  171. },{
  172. .name = "alpha",
  173. .type = AVMEDIA_TYPE_VIDEO,
  174. },
  175. { NULL }
  176. };
  177. static const AVFilterPad alphamerge_outputs[] = {
  178. {
  179. .name = "default",
  180. .type = AVMEDIA_TYPE_VIDEO,
  181. .config_props = config_output,
  182. },
  183. { NULL }
  184. };
  185. static const AVOption alphamerge_options[] = {
  186. { NULL }
  187. };
  188. AVFILTER_DEFINE_CLASS(alphamerge);
  189. AVFilter ff_vf_alphamerge = {
  190. .name = "alphamerge",
  191. .description = NULL_IF_CONFIG_SMALL("Copy the luma value of the second "
  192. "input into the alpha channel of the first input."),
  193. .priv_size = sizeof(AlphaMergeContext),
  194. .priv_class = &alphamerge_class,
  195. .query_formats = query_formats,
  196. .inputs = alphamerge_inputs,
  197. .outputs = alphamerge_outputs,
  198. .activate = activate,
  199. .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
  200. };