2 * Copyright (c) 2012 Steven Robertson
4 * This file is part of FFmpeg.
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.
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.
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
23 * copy an alpha component from another video's luma
28 #include "libavutil/pixfmt.h"
30 #include "bufferqueue.h"
31 #include "drawutils.h"
42 struct FFBufQueue queue_main
;
43 struct FFBufQueue queue_alpha
;
46 static av_cold
void uninit(AVFilterContext
*ctx
)
48 AlphaMergeContext
*merge
= ctx
->priv
;
49 ff_bufqueue_discard_all(&merge
->queue_main
);
50 ff_bufqueue_discard_all(&merge
->queue_alpha
);
53 static int query_formats(AVFilterContext
*ctx
)
55 static const enum AVPixelFormat main_fmts
[] = {
56 AV_PIX_FMT_YUVA444P
, AV_PIX_FMT_YUVA422P
, AV_PIX_FMT_YUVA420P
,
57 AV_PIX_FMT_RGBA
, AV_PIX_FMT_BGRA
, AV_PIX_FMT_ARGB
, AV_PIX_FMT_ABGR
,
60 static const enum AVPixelFormat alpha_fmts
[] = { AV_PIX_FMT_GRAY8
, AV_PIX_FMT_NONE
};
61 AVFilterFormats
*main_formats
= ff_make_format_list(main_fmts
);
62 AVFilterFormats
*alpha_formats
= ff_make_format_list(alpha_fmts
);
63 ff_formats_ref(main_formats
, &ctx
->inputs
[0]->out_formats
);
64 ff_formats_ref(alpha_formats
, &ctx
->inputs
[1]->out_formats
);
65 ff_formats_ref(main_formats
, &ctx
->outputs
[0]->in_formats
);
69 static int config_input_main(AVFilterLink
*inlink
)
71 AlphaMergeContext
*merge
= inlink
->dst
->priv
;
72 merge
->is_packed_rgb
=
73 ff_fill_rgba_map(merge
->rgba_map
, inlink
->format
) >= 0;
77 static int config_output(AVFilterLink
*outlink
)
79 AVFilterContext
*ctx
= outlink
->src
;
80 AVFilterLink
*mainlink
= ctx
->inputs
[0];
81 AVFilterLink
*alphalink
= ctx
->inputs
[1];
82 if (mainlink
->w
!= alphalink
->w
|| mainlink
->h
!= alphalink
->h
) {
83 av_log(ctx
, AV_LOG_ERROR
,
84 "Input frame sizes do not match (%dx%d vs %dx%d).\n",
85 mainlink
->w
, mainlink
->h
,
86 alphalink
->w
, alphalink
->h
);
87 return AVERROR(EINVAL
);
90 outlink
->w
= mainlink
->w
;
91 outlink
->h
= mainlink
->h
;
92 outlink
->time_base
= mainlink
->time_base
;
93 outlink
->sample_aspect_ratio
= mainlink
->sample_aspect_ratio
;
94 outlink
->frame_rate
= mainlink
->frame_rate
;
98 static void draw_frame(AVFilterContext
*ctx
,
102 AlphaMergeContext
*merge
= ctx
->priv
;
103 int h
= main_buf
->height
;
105 if (merge
->is_packed_rgb
) {
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] + merge
->rgba_map
[A
];
111 for (x
= 0; x
< main_buf
->width
; x
++) {
119 const int main_linesize
= main_buf
->linesize
[A
];
120 const int alpha_linesize
= alpha_buf
->linesize
[Y
];
121 for (y
= 0; y
< h
&& y
< alpha_buf
->height
; y
++) {
122 memcpy(main_buf
->data
[A
] + y
* main_linesize
,
123 alpha_buf
->data
[Y
] + y
* alpha_linesize
,
124 FFMIN(main_linesize
, alpha_linesize
));
129 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*buf
)
131 AVFilterContext
*ctx
= inlink
->dst
;
132 AlphaMergeContext
*merge
= ctx
->priv
;
135 int is_alpha
= (inlink
== ctx
->inputs
[1]);
136 struct FFBufQueue
*queue
=
137 (is_alpha
? &merge
->queue_alpha
: &merge
->queue_main
);
138 ff_bufqueue_add(ctx
, queue
, buf
);
141 AVFrame
*main_buf
, *alpha_buf
;
143 if (!ff_bufqueue_peek(&merge
->queue_main
, 0) ||
144 !ff_bufqueue_peek(&merge
->queue_alpha
, 0)) break;
146 main_buf
= ff_bufqueue_get(&merge
->queue_main
);
147 alpha_buf
= ff_bufqueue_get(&merge
->queue_alpha
);
149 merge
->frame_requested
= 0;
150 draw_frame(ctx
, main_buf
, alpha_buf
);
151 ret
= ff_filter_frame(ctx
->outputs
[0], main_buf
);
152 av_frame_free(&alpha_buf
);
157 static int request_frame(AVFilterLink
*outlink
)
159 AVFilterContext
*ctx
= outlink
->src
;
160 AlphaMergeContext
*merge
= ctx
->priv
;
163 merge
->frame_requested
= 1;
164 while (merge
->frame_requested
) {
165 in
= ff_bufqueue_peek(&merge
->queue_main
, 0) ? 1 : 0;
166 ret
= ff_request_frame(ctx
->inputs
[in
]);
173 static const AVFilterPad alphamerge_inputs
[] = {
176 .type
= AVMEDIA_TYPE_VIDEO
,
177 .config_props
= config_input_main
,
178 .filter_frame
= filter_frame
,
182 .type
= AVMEDIA_TYPE_VIDEO
,
183 .filter_frame
= filter_frame
,
188 static const AVFilterPad alphamerge_outputs
[] = {
191 .type
= AVMEDIA_TYPE_VIDEO
,
192 .config_props
= config_output
,
193 .request_frame
= request_frame
,
198 AVFilter ff_vf_alphamerge
= {
199 .name
= "alphamerge",
200 .description
= NULL_IF_CONFIG_SMALL("Copy the luma value of the second "
201 "input into the alpha channel of the first input."),
203 .priv_size
= sizeof(AlphaMergeContext
),
204 .query_formats
= query_formats
,
205 .inputs
= alphamerge_inputs
,
206 .outputs
= alphamerge_outputs
,