FFmpeg
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
Examples
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
libavfilter
vf_mergeplanes.c
Go to the documentation of this file.
1
/*
2
* Copyright (c) 2013 Paul B Mahol
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
#include "
libavutil/avassert.h
"
22
#include "
libavutil/avstring.h
"
23
#include "
libavutil/imgutils.h
"
24
#include "
libavutil/opt.h
"
25
#include "
libavutil/pixdesc.h
"
26
#include "
avfilter.h
"
27
#include "
internal.h
"
28
#include "
framesync.h
"
29
30
typedef
struct
InputParam
{
31
int
depth
[4];
32
int
nb_planes
;
33
int
planewidth
[4];
34
int
planeheight
[4];
35
}
InputParam
;
36
37
typedef
struct
MergePlanesContext
{
38
const
AVClass
*
class
;
39
int64_t
mapping
;
40
const
enum
AVPixelFormat
out_fmt
;
41
int
nb_inputs
;
42
int
nb_planes
;
43
int
planewidth
[4];
44
int
planeheight
[4];
45
int
map
[4][2];
46
const
AVPixFmtDescriptor
*
outdesc
;
47
48
FFFrameSync
fs
;
49
FFFrameSyncIn
fsin
[3];
/* must be immediately after fs */
50
}
MergePlanesContext
;
51
52
#define OFFSET(x) offsetof(MergePlanesContext, x)
53
#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
54
static
const
AVOption
mergeplanes_options
[] = {
55
{
"mapping"
,
"set input to output plane mapping"
,
OFFSET
(mapping),
AV_OPT_TYPE_INT
, {.i64=0}, 0, 0x33333333,
FLAGS
},
56
{
"format"
,
"set output pixel format"
,
OFFSET
(out_fmt),
AV_OPT_TYPE_PIXEL_FMT
, {.i64=
AV_PIX_FMT_YUVA444P
}, 0, INT_MAX, .flags=
FLAGS
},
57
{ NULL }
58
};
59
60
AVFILTER_DEFINE_CLASS
(mergeplanes);
61
62
static
int
filter_frame
(
AVFilterLink
*inlink,
AVFrame
*
in
)
63
{
64
MergePlanesContext
*
s
= inlink->
dst
->
priv
;
65
return
ff_framesync_filter_frame
(&s->
fs
, inlink, in);
66
}
67
68
static
av_cold
int
init
(
AVFilterContext
*ctx)
69
{
70
MergePlanesContext
*
s
= ctx->
priv
;
71
int64_t
m
= s->
mapping
;
72
int
i,
ret
;
73
74
s->
outdesc
=
av_pix_fmt_desc_get
(s->
out_fmt
);
75
if
(!(s->
outdesc
->
flags
&
AV_PIX_FMT_FLAG_PLANAR
) ||
76
s->
outdesc
->
nb_components
< 2) {
77
av_log
(ctx,
AV_LOG_ERROR
,
"Only planar formats with more than one component are supported.\n"
);
78
return
AVERROR
(EINVAL);
79
}
80
s->
nb_planes
=
av_pix_fmt_count_planes
(s->
out_fmt
);
81
82
for
(i = s->
nb_planes
- 1; i >= 0; i--) {
83
s->
map
[i][0] = m & 0xf;
84
m >>= 4;
85
s->
map
[i][1] = m & 0xf;
86
m >>= 4;
87
88
if
(s->
map
[i][0] > 3 || s->
map
[i][1] > 3) {
89
av_log
(ctx,
AV_LOG_ERROR
,
"Mapping with out of range input and/or plane number.\n"
);
90
return
AVERROR
(EINVAL);
91
}
92
93
s->
nb_inputs
=
FFMAX
(s->
nb_inputs
, s->
map
[i][1] + 1);
94
}
95
96
av_assert0
(s->
nb_inputs
&& s->
nb_inputs
<= 4);
97
98
for
(i = 0; i < s->
nb_inputs
; i++) {
99
AVFilterPad
pad = { 0 };
100
101
pad.
type
=
AVMEDIA_TYPE_VIDEO
;
102
pad.
name
=
av_asprintf
(
"in%d"
, i);
103
if
(!pad.
name
)
104
return
AVERROR
(ENOMEM);
105
pad.
filter_frame
=
filter_frame
;
106
107
if
((ret =
ff_insert_inpad
(ctx, i, &pad)) < 0){
108
av_freep
(&pad.
name
);
109
return
ret
;
110
}
111
}
112
113
return
0;
114
}
115
116
static
int
query_formats
(
AVFilterContext
*ctx)
117
{
118
MergePlanesContext
*
s
= ctx->
priv
;
119
AVFilterFormats
*
formats
= NULL;
120
int
i;
121
122
s->
outdesc
=
av_pix_fmt_desc_get
(s->
out_fmt
);
123
for
(i = 0;
av_pix_fmt_desc_get
(i); i++) {
124
const
AVPixFmtDescriptor
*desc =
av_pix_fmt_desc_get
(i);
125
if
(desc->
comp
[0].
depth_minus1
== s->
outdesc
->
comp
[0].
depth_minus1
&&
126
av_pix_fmt_count_planes
(i) == desc->
nb_components
)
127
ff_add_format
(&formats, i);
128
}
129
130
for
(i = 0; i < s->
nb_inputs
; i++)
131
ff_formats_ref
(formats, &ctx->
inputs
[i]->
out_formats
);
132
133
formats = NULL;
134
ff_add_format
(&formats, s->
out_fmt
);
135
ff_formats_ref
(formats, &ctx->
outputs
[0]->
in_formats
);
136
137
return
0;
138
}
139
140
static
int
process_frame
(
FFFrameSync
*fs)
141
{
142
AVFilterContext
*ctx = fs->
parent
;
143
AVFilterLink
*outlink = ctx->
outputs
[0];
144
MergePlanesContext
*
s
= fs->
opaque
;
145
AVFrame
*
in
[4] = { NULL };
146
AVFrame
*
out
;
147
int
i,
ret
;
148
149
for
(i = 0; i < s->
nb_inputs
; i++) {
150
if
((ret =
ff_framesync_get_frame
(&s->
fs
, i, &in[i], 0)) < 0)
151
return
ret
;
152
}
153
154
out =
ff_get_video_buffer
(outlink, outlink->
w
, outlink->
h
);
155
if
(!out)
156
return
AVERROR
(ENOMEM);
157
out->
pts
=
av_rescale_q
(s->
fs
.
pts
, s->
fs
.
time_base
, outlink->
time_base
);
158
159
for
(i = 0; i < s->
nb_planes
; i++) {
160
const
int
input = s->
map
[i][1];
161
const
int
plane = s->
map
[i][0];
162
163
av_image_copy_plane
(out->
data
[i], out->
linesize
[i],
164
in[input]->
data
[plane], in[input]->
linesize
[plane],
165
s->
planewidth
[i], s->
planeheight
[i]);
166
}
167
168
return
ff_filter_frame
(outlink, out);
169
}
170
171
static
int
config_output
(
AVFilterLink
*outlink)
172
{
173
AVFilterContext
*ctx = outlink->
src
;
174
MergePlanesContext
*
s
= ctx->
priv
;
175
InputParam
inputsp[4];
176
FFFrameSyncIn
*
in
;
177
int
i;
178
179
ff_framesync_init
(&s->
fs
, ctx, s->
nb_inputs
);
180
in = s->
fs
.
in
;
181
s->
fs
.
opaque
=
s
;
182
s->
fs
.
on_event
=
process_frame
;
183
184
outlink->
w
= ctx->
inputs
[0]->
w
;
185
outlink->
h
= ctx->
inputs
[0]->
h
;
186
outlink->
time_base
= ctx->
inputs
[0]->
time_base
;
187
outlink->
frame_rate
= ctx->
inputs
[0]->
frame_rate
;
188
outlink->
sample_aspect_ratio
= ctx->
inputs
[0]->
sample_aspect_ratio
;
189
190
s->
planewidth
[1] =
191
s->
planewidth
[2] =
FF_CEIL_RSHIFT
(outlink->
w
, s->
outdesc
->
log2_chroma_w
);
192
s->
planewidth
[0] =
193
s->
planewidth
[3] = outlink->
w
;
194
s->
planeheight
[1] =
195
s->
planeheight
[2] =
FF_CEIL_RSHIFT
(outlink->
h
, s->
outdesc
->
log2_chroma_h
);
196
s->
planeheight
[0] =
197
s->
planeheight
[3] = outlink->
h
;
198
199
for
(i = 0; i < s->
nb_inputs
; i++) {
200
InputParam
*inputp = &inputsp[i];
201
AVFilterLink
*inlink = ctx->
inputs
[i];
202
const
AVPixFmtDescriptor
*indesc =
av_pix_fmt_desc_get
(inlink->
format
);
203
int
j;
204
205
if
(outlink->
sample_aspect_ratio
.
num
!= inlink->
sample_aspect_ratio
.
num
||
206
outlink->
sample_aspect_ratio
.
den
!= inlink->
sample_aspect_ratio
.
den
) {
207
av_log
(ctx,
AV_LOG_ERROR
,
"input #%d link %s SAR %d:%d "
208
"does not match output link %s SAR %d:%d\n"
,
209
i, ctx->
input_pads
[i].
name
,
210
inlink->
sample_aspect_ratio
.
num
,
211
inlink->
sample_aspect_ratio
.
den
,
212
ctx->
output_pads
[0].
name
,
213
outlink->
sample_aspect_ratio
.
num
,
214
outlink->
sample_aspect_ratio
.
den
);
215
return
AVERROR
(EINVAL);
216
}
217
218
inputp->
planewidth
[1] =
219
inputp->
planewidth
[2] =
FF_CEIL_RSHIFT
(inlink->
w
, indesc->
log2_chroma_w
);
220
inputp->
planewidth
[0] =
221
inputp->
planewidth
[3] = inlink->
w
;
222
inputp->
planeheight
[1] =
223
inputp->
planeheight
[2] =
FF_CEIL_RSHIFT
(inlink->
h
, indesc->
log2_chroma_h
);
224
inputp->
planeheight
[0] =
225
inputp->
planeheight
[3] = inlink->
h
;
226
inputp->
nb_planes
=
av_pix_fmt_count_planes
(inlink->
format
);
227
228
for
(j = 0; j < inputp->
nb_planes
; j++)
229
inputp->
depth
[j] = indesc->
comp
[j].
depth_minus1
+ 1;
230
231
in[i].
time_base
= inlink->
time_base
;
232
in[i].
sync
= 1;
233
in[i].
before
=
EXT_STOP
;
234
in[i].
after
=
EXT_STOP
;
235
}
236
237
for
(i = 0; i < s->
nb_planes
; i++) {
238
const
int
input = s->
map
[i][1];
239
const
int
plane = s->
map
[i][0];
240
InputParam
*inputp = &inputsp[input];
241
242
if
(plane + 1 > inputp->
nb_planes
) {
243
av_log
(ctx,
AV_LOG_ERROR
,
"input %d does not have %d plane\n"
,
244
input, plane);
245
goto
fail;
246
}
247
if
(s->
outdesc
->
comp
[i].
depth_minus1
+ 1 != inputp->
depth
[plane]) {
248
av_log
(ctx,
AV_LOG_ERROR
,
"output plane %d depth %d does not "
249
"match input %d plane %d depth %d\n"
,
250
i, s->
outdesc
->
comp
[i].
depth_minus1
+ 1,
251
input, plane, inputp->
depth
[plane]);
252
goto
fail;
253
}
254
if
(s->
planewidth
[i] != inputp->
planewidth
[plane]) {
255
av_log
(ctx,
AV_LOG_ERROR
,
"output plane %d width %d does not "
256
"match input %d plane %d width %d\n"
,
257
i, s->
planewidth
[i],
258
input, plane, inputp->
planewidth
[plane]);
259
goto
fail;
260
}
261
if
(s->
planeheight
[i] != inputp->
planeheight
[plane]) {
262
av_log
(ctx,
AV_LOG_ERROR
,
"output plane %d height %d does not "
263
"match input %d plane %d height %d\n"
,
264
i, s->
planeheight
[i],
265
input, plane, inputp->
planeheight
[plane]);
266
goto
fail;
267
}
268
}
269
270
return
ff_framesync_configure
(&s->
fs
);
271
fail:
272
return
AVERROR
(EINVAL);
273
}
274
275
static
int
request_frame
(
AVFilterLink
*outlink)
276
{
277
MergePlanesContext
*
s
= outlink->
src
->
priv
;
278
return
ff_framesync_request_frame
(&s->
fs
, outlink);
279
}
280
281
static
av_cold
void
uninit
(
AVFilterContext
*ctx)
282
{
283
MergePlanesContext
*
s
= ctx->
priv
;
284
int
i;
285
286
ff_framesync_uninit
(&s->
fs
);
287
288
for
(i = 0; i < ctx->
nb_inputs
; i++)
289
av_freep
(&ctx->
input_pads
[i].
name
);
290
}
291
292
static
const
AVFilterPad
mergeplanes_outputs
[] = {
293
{
294
.
name
=
"default"
,
295
.type =
AVMEDIA_TYPE_VIDEO
,
296
.config_props =
config_output
,
297
.request_frame =
request_frame
,
298
},
299
{ NULL }
300
};
301
302
AVFilter
ff_vf_mergeplanes
= {
303
.
name
=
"mergeplanes"
,
304
.description =
NULL_IF_CONFIG_SMALL
(
"Merge planes."
),
305
.priv_size =
sizeof
(
MergePlanesContext
),
306
.priv_class = &mergeplanes_class,
307
.
init
=
init
,
308
.
uninit
=
uninit
,
309
.
query_formats
=
query_formats
,
310
.
inputs
= NULL,
311
.
outputs
= mergeplanes_outputs,
312
.
flags
=
AVFILTER_FLAG_DYNAMIC_INPUTS
,
313
};
Generated on Sun Jul 20 2014 23:06:01 for FFmpeg by
1.8.2