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_tile.c
Go to the documentation of this file.
1
/*
2
* Copyright (c) 2012 Nicolas George
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
/**
22
* @file
23
* tile video filter
24
*/
25
26
#include "
libavutil/opt.h
"
27
#include "
libavutil/pixdesc.h
"
28
#include "
avfilter.h
"
29
#include "
drawutils.h
"
30
#include "
formats.h
"
31
#include "
video.h
"
32
#include "
internal.h
"
33
34
typedef
struct
{
35
const
AVClass
*
class
;
36
unsigned
w
, h;
37
unsigned
margin
;
38
unsigned
padding
;
39
unsigned
current
;
40
unsigned
nb_frames
;
41
FFDrawContext
draw
;
42
FFDrawColor
blank
;
43
AVFrame
*
out_ref
;
44
uint8_t
rgba_color[4];
45
}
TileContext
;
46
47
#define REASONABLE_SIZE 1024
48
49
#define OFFSET(x) offsetof(TileContext, x)
50
#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
51
52
static
const
AVOption
tile_options
[] = {
53
{
"layout"
,
"set grid size"
,
OFFSET
(w),
AV_OPT_TYPE_IMAGE_SIZE
,
54
{.str =
"6x5"
}, 0, 0,
FLAGS
},
55
{
"nb_frames"
,
"set maximum number of frame to render"
,
OFFSET
(nb_frames),
56
AV_OPT_TYPE_INT
, {.i64 = 0}, 0, INT_MAX,
FLAGS
},
57
{
"margin"
,
"set outer border margin in pixels"
,
OFFSET
(margin),
58
AV_OPT_TYPE_INT
, {.i64 = 0}, 0, 1024,
FLAGS
},
59
{
"padding"
,
"set inner border thickness in pixels"
,
OFFSET
(padding),
60
AV_OPT_TYPE_INT
, {.i64 = 0}, 0, 1024,
FLAGS
},
61
{
"color"
,
"set the color of the unused area"
,
OFFSET
(rgba_color),
AV_OPT_TYPE_COLOR
, {.str =
"black"
}, .flags =
FLAGS
},
62
{
NULL
}
63
};
64
65
AVFILTER_DEFINE_CLASS
(tile);
66
67
static
av_cold
int
init
(
AVFilterContext
*ctx)
68
{
69
TileContext
*tile = ctx->
priv
;
70
71
if
(tile->
w
>
REASONABLE_SIZE
|| tile->
h
>
REASONABLE_SIZE
) {
72
av_log
(ctx,
AV_LOG_ERROR
,
"Tile size %ux%u is insane.\n"
,
73
tile->
w
, tile->
h
);
74
return
AVERROR
(EINVAL);
75
}
76
77
if
(tile->
nb_frames
== 0) {
78
tile->
nb_frames
= tile->
w
* tile->
h
;
79
}
else
if
(tile->
nb_frames
> tile->
w
* tile->
h
) {
80
av_log
(ctx,
AV_LOG_ERROR
,
"nb_frames must be less than or equal to %dx%d=%d\n"
,
81
tile->
w
, tile->
h
, tile->
w
* tile->
h
);
82
return
AVERROR
(EINVAL);
83
}
84
85
return
0;
86
}
87
88
static
int
query_formats
(
AVFilterContext
*ctx)
89
{
90
ff_set_common_formats
(ctx,
ff_draw_supported_pixel_formats
(0));
91
return
0;
92
}
93
94
static
int
config_props
(
AVFilterLink
*outlink)
95
{
96
AVFilterContext
*ctx = outlink->
src
;
97
TileContext
*tile = ctx->
priv
;
98
AVFilterLink
*inlink = ctx->
inputs
[0];
99
const
unsigned
total_margin_w = (tile->
w
- 1) * tile->
padding
+ 2*tile->
margin
;
100
const
unsigned
total_margin_h = (tile->
h
- 1) * tile->
padding
+ 2*tile->
margin
;
101
102
if
(inlink->
w
> (INT_MAX - total_margin_w) / tile->
w
) {
103
av_log
(ctx,
AV_LOG_ERROR
,
"Total width %ux%u is too much.\n"
,
104
tile->
w
, inlink->
w
);
105
return
AVERROR
(EINVAL);
106
}
107
if
(inlink->
h
> (INT_MAX - total_margin_h) / tile->
h
) {
108
av_log
(ctx,
AV_LOG_ERROR
,
"Total height %ux%u is too much.\n"
,
109
tile->
h
, inlink->
h
);
110
return
AVERROR
(EINVAL);
111
}
112
outlink->
w
= tile->
w
* inlink->
w
+ total_margin_w;
113
outlink->
h
= tile->
h
* inlink->
h
+ total_margin_h;
114
outlink->
sample_aspect_ratio
= inlink->
sample_aspect_ratio
;
115
outlink->
frame_rate
=
av_mul_q
(inlink->
frame_rate
,
116
av_make_q
(1, tile->
nb_frames
));
117
ff_draw_init
(&tile->
draw
, inlink->
format
, 0);
118
ff_draw_color
(&tile->
draw
, &tile->
blank
, tile->
rgba_color
);
119
120
outlink->
flags
|=
FF_LINK_FLAG_REQUEST_LOOP
;
121
122
return
0;
123
}
124
125
static
void
get_current_tile_pos
(
AVFilterContext
*ctx,
unsigned
*x,
unsigned
*
y
)
126
{
127
TileContext
*tile = ctx->
priv
;
128
AVFilterLink
*inlink = ctx->
inputs
[0];
129
const
unsigned
tx = tile->
current
% tile->
w
;
130
const
unsigned
ty = tile->
current
/ tile->
w
;
131
132
*x = tile->
margin
+ (inlink->
w
+ tile->
padding
) * tx;
133
*y = tile->
margin
+ (inlink->
h
+ tile->
padding
) * ty;
134
}
135
136
static
void
draw_blank_frame
(
AVFilterContext
*ctx,
AVFrame
*out_buf)
137
{
138
TileContext
*tile = ctx->
priv
;
139
AVFilterLink
*inlink = ctx->
inputs
[0];
140
unsigned
x0, y0;
141
142
get_current_tile_pos
(ctx, &x0, &y0);
143
ff_fill_rectangle
(&tile->
draw
, &tile->
blank
,
144
out_buf->
data
, out_buf->
linesize
,
145
x0, y0, inlink->
w
, inlink->
h
);
146
tile->
current
++;
147
}
148
static
int
end_last_frame
(
AVFilterContext
*ctx)
149
{
150
TileContext
*tile = ctx->
priv
;
151
AVFilterLink
*outlink = ctx->
outputs
[0];
152
AVFrame
*out_buf = tile->
out_ref
;
153
int
ret
;
154
155
while
(tile->
current
< tile->
nb_frames
)
156
draw_blank_frame
(ctx, out_buf);
157
ret =
ff_filter_frame
(outlink, out_buf);
158
tile->
current
= 0;
159
return
ret
;
160
}
161
162
/* Note: direct rendering is not possible since there is no guarantee that
163
* buffers are fed to filter_frame in the order they were obtained from
164
* get_buffer (think B-frames). */
165
166
static
int
filter_frame
(
AVFilterLink
*inlink,
AVFrame
*picref)
167
{
168
AVFilterContext
*ctx = inlink->
dst
;
169
TileContext
*tile = ctx->
priv
;
170
AVFilterLink
*outlink = ctx->
outputs
[0];
171
unsigned
x0, y0;
172
173
if
(!tile->
current
) {
174
tile->
out_ref
=
ff_get_video_buffer
(outlink, outlink->
w
, outlink->
h
);
175
if
(!tile->
out_ref
) {
176
av_frame_free
(&picref);
177
return
AVERROR
(ENOMEM);
178
}
179
av_frame_copy_props
(tile->
out_ref
, picref);
180
tile->
out_ref
->
width
= outlink->
w
;
181
tile->
out_ref
->
height
= outlink->
h
;
182
183
/* fill surface once for margin/padding */
184
if
(tile->
margin
|| tile->
padding
)
185
ff_fill_rectangle
(&tile->
draw
, &tile->
blank
,
186
tile->
out_ref
->
data
,
187
tile->
out_ref
->
linesize
,
188
0, 0, outlink->
w
, outlink->
h
);
189
}
190
191
get_current_tile_pos
(ctx, &x0, &y0);
192
ff_copy_rectangle2
(&tile->
draw
,
193
tile->
out_ref
->
data
, tile->
out_ref
->
linesize
,
194
picref->
data
, picref->
linesize
,
195
x0, y0, 0, 0, inlink->
w
, inlink->
h
);
196
197
av_frame_free
(&picref);
198
if
(++tile->
current
== tile->
nb_frames
)
199
return
end_last_frame
(ctx);
200
201
return
0;
202
}
203
204
static
int
request_frame
(
AVFilterLink
*outlink)
205
{
206
AVFilterContext
*ctx = outlink->
src
;
207
TileContext
*tile = ctx->
priv
;
208
AVFilterLink
*inlink = ctx->
inputs
[0];
209
int
r
;
210
211
r =
ff_request_frame
(inlink);
212
if
(r ==
AVERROR_EOF
&& tile->
current
)
213
r =
end_last_frame
(ctx);
214
return
r
;
215
}
216
217
static
const
AVFilterPad
tile_inputs
[] = {
218
{
219
.
name
=
"default"
,
220
.type =
AVMEDIA_TYPE_VIDEO
,
221
.filter_frame =
filter_frame
,
222
},
223
{
NULL
}
224
};
225
226
static
const
AVFilterPad
tile_outputs
[] = {
227
{
228
.
name
=
"default"
,
229
.type =
AVMEDIA_TYPE_VIDEO
,
230
.config_props =
config_props
,
231
.request_frame =
request_frame
,
232
},
233
{
NULL
}
234
};
235
236
AVFilter
ff_vf_tile
= {
237
.
name
=
"tile"
,
238
.description =
NULL_IF_CONFIG_SMALL
(
"Tile several successive frames together."
),
239
.init =
init
,
240
.query_formats =
query_formats
,
241
.priv_size =
sizeof
(
TileContext
),
242
.
inputs
= tile_inputs,
243
.
outputs
= tile_outputs,
244
.priv_class = &tile_class,
245
};
Generated on Sun Mar 8 2015 02:35:08 for FFmpeg by
1.8.2