さきゅばす/いんきゅばす用libav(実験的)
リビジョン | a3effb29d9ff2b8982335c895de74d4f91ce0f4d (tree) |
---|---|
日時 | 2011-05-22 20:24:40 |
作者 | yukihane <yukihane.feather@gmai...> |
コミッター | yukihane |
patch for saccubus
@@ -48,6 +48,7 @@ | ||
48 | 48 | # include "libavfilter/avfilter.h" |
49 | 49 | # include "libavfilter/avfiltergraph.h" |
50 | 50 | # include "libavfilter/vsrc_buffer.h" |
51 | +# include "libavfilter/avtool.h" | |
51 | 52 | #endif |
52 | 53 | |
53 | 54 | #if HAVE_SYS_RESOURCE_H |
@@ -2245,6 +2246,7 @@ static int transcode(AVFormatContext **output_files, | ||
2245 | 2246 | ist->decoding_needed = 1; |
2246 | 2247 | |
2247 | 2248 | #if CONFIG_AVFILTER |
2249 | + tool_registerInfo(is, recording_time); | |
2248 | 2250 | if (configure_video_filters(ist, ost)) { |
2249 | 2251 | fprintf(stderr, "Error opening filters!\n"); |
2250 | 2252 | exit(1); |
@@ -4346,7 +4348,8 @@ static const OptionDef options[] = { | ||
4346 | 4348 | { "vstats", OPT_EXPERT | OPT_VIDEO, {(void*)&opt_vstats}, "dump video coding statistics to file" }, |
4347 | 4349 | { "vstats_file", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_vstats_file}, "dump video coding statistics to file", "file" }, |
4348 | 4350 | #if CONFIG_AVFILTER |
4349 | - { "vf", OPT_STRING | HAS_ARG, {(void*)&vfilters}, "video filters", "filter list" }, | |
4351 | +// さきゅばすインタフェース互換性維持のため処置 引数を新しいvfでなく古いvfiltersのままとする | |
4352 | + { "vfilters", OPT_STRING | HAS_ARG, {(void*)&vfilters}, "video filters", "filter list" }, | |
4350 | 4353 | #endif |
4351 | 4354 | { "intra_matrix", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_intra_matrix}, "specify intra matrix coeffs", "matrix" }, |
4352 | 4355 | { "inter_matrix", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_inter_matrix}, "specify inter matrix coeffs", "matrix" }, |
@@ -64,4 +64,7 @@ OBJS-$(CONFIG_NULLSINK_FILTER) += vsink_nullsink.o | ||
64 | 64 | |
65 | 65 | DIRS = x86 |
66 | 66 | |
67 | +OBJS-$(CONFIG_VHEXT_FILTER) += avtool.o | |
68 | +OBJS-$(CONFIG_VHEXT_FILTER) += vf_vhext.o | |
69 | + | |
67 | 70 | include $(SUBDIR)../subdir.mak |
@@ -78,4 +78,6 @@ void avfilter_register_all(void) | ||
78 | 78 | REGISTER_FILTER (NULLSRC, nullsrc, vsrc); |
79 | 79 | |
80 | 80 | REGISTER_FILTER (NULLSINK, nullsink, vsink); |
81 | + | |
82 | + REGISTER_FILTER (VHEXT, vhext, vf); | |
81 | 83 | } |
@@ -0,0 +1,32 @@ | ||
1 | +/* | |
2 | + * avtool | |
3 | + * copyright (c) 2008 ψ(プサイ) | |
4 | + * | |
5 | + * さきゅばす用に拡張されたVhookライブラリから | |
6 | + * 使われるライブラリです。 | |
7 | + * | |
8 | + * このファイルは「さきゅばす」の一部であり、 | |
9 | + * このソースコードはGPLライセンスで配布されますです。 | |
10 | + */ | |
11 | +#include <stdio.h> | |
12 | +#include "common/framehook_ext.h" | |
13 | +#include "avtool.h" | |
14 | + | |
15 | +static toolbox Box = { | |
16 | + .version = TOOLBOX_VERSION, | |
17 | + .video_length = 0.0f | |
18 | +}; | |
19 | + | |
20 | +/* こちらはffmpeg側から呼ばれる関数 */ | |
21 | + | |
22 | +int tool_registerInfo(AVFormatContext *in_file,int64_t rec_time){ | |
23 | + if(in_file->duration > rec_time && rec_time > 0){ | |
24 | + Box.video_length = ((double)rec_time) / AV_TIME_BASE; | |
25 | + } | |
26 | + Box.video_length = ((double)in_file->duration)/AV_TIME_BASE; | |
27 | + return 0; | |
28 | +} | |
29 | + | |
30 | +const toolbox* tool_getToolBox(){ | |
31 | + return &Box; | |
32 | +} |
@@ -0,0 +1,19 @@ | ||
1 | +/* | |
2 | + * avtool | |
3 | + * copyright (c) 2008 ψ(プサイ) | |
4 | + * | |
5 | + * さきゅばす用に拡張されたFFmpegから | |
6 | + * 使われるライブラリです。 | |
7 | + * | |
8 | + * このファイルは「さきゅばす」の一部であり、 | |
9 | + * このソースコードはGPLライセンスで配布されますです。 | |
10 | + */ | |
11 | +#ifndef SACCUBUS_AVINFO_H | |
12 | +#define SACCUBUS_AVINFO_H | |
13 | +#include "common/framehook_ext.h" | |
14 | +#include <libavformat/avformat.h> | |
15 | + | |
16 | +int tool_registerInfo(AVFormatContext *in_file,int64_t rec_time); | |
17 | +const toolbox* tool_getToolBox(void); | |
18 | + | |
19 | +#endif /* SACCUBUS_AVINFO_H */ |
@@ -0,0 +1,57 @@ | ||
1 | +/* | |
2 | + * 拡張Vhookフィルタ | |
3 | + * copyright (c) 2008 ψ(プサイ) | |
4 | + * | |
5 | + * さきゅばす用に拡張されたVhookライブラリを | |
6 | + * ビルドするためのヘッダです。 | |
7 | + * | |
8 | + * このファイルは「さきゅばす」の一部であり、 | |
9 | + * このソースコードはGPLライセンスで配布されますです。 | |
10 | + */ | |
11 | +#ifndef SACCUBUS_VF_VHEXT_H | |
12 | +#define SACCUBUS_VF_VHEXT_H | |
13 | +/* | |
14 | + * ツールボックスのバージョン | |
15 | + * DLLの中で確認しといた方がいい。 | |
16 | + */ | |
17 | +#define TOOLBOX_VERSION 2 | |
18 | + | |
19 | +/* | |
20 | + * 呼ばれるときに一緒についてくるtoolbox. | |
21 | + * ここから動画の情報なんかも取得できる。 | |
22 | + */ | |
23 | +typedef struct toolbox{ | |
24 | + //バージョン | |
25 | + int version; | |
26 | + double video_length; | |
27 | +} toolbox; | |
28 | + | |
29 | +typedef struct vhext_frame{ | |
30 | + void *data; | |
31 | + int linesize; | |
32 | + int w; | |
33 | + int h; | |
34 | + double pts; | |
35 | +} vhext_frame; | |
36 | + | |
37 | + | |
38 | +/* | |
39 | + * 拡張vhookライブラリ用関数群定義 | |
40 | + */ | |
41 | + | |
42 | +//configure用 | |
43 | +typedef int (FrameHookExtConfigure)(void **ctxp,const toolbox *tbox, int argc, char *argv[]); | |
44 | +typedef FrameHookExtConfigure *FrameHookExtConfigureFn; | |
45 | +extern FrameHookExtConfigure ExtConfigure; | |
46 | + | |
47 | +//フレーム用 | |
48 | +typedef void (FrameHookExtProcess)(void *ctx,const toolbox *tbox,vhext_frame *pict); | |
49 | +typedef FrameHookExtProcess *FrameHookExtProcessFn; | |
50 | +extern FrameHookExtProcess ExtProcess; | |
51 | + | |
52 | +//終了時に呼ぶ | |
53 | +typedef void (FrameHookExtRelease)(void *ctx,const toolbox *tbox); | |
54 | +typedef FrameHookExtRelease *FrameHookExtReleaseFn; | |
55 | +extern FrameHookExtRelease ExtRelease; | |
56 | + | |
57 | +#endif /* SACCUBUS_VF_VHEXT_H */ |
@@ -0,0 +1,372 @@ | ||
1 | +/* | |
2 | + * video expand filter (alternative to pad syntax) | |
3 | + * copyright (c) 2008 Ryo Hirafuji <http://ledyba.ddo.jp/> | |
4 | + * | |
5 | + * This file is part of FFmpeg. | |
6 | + * | |
7 | + * FFmpeg is free software; you can redistribute it and/or | |
8 | + * modify it under the terms of the GNU Lesser General Public | |
9 | + * License as published by the Free Software Foundation; either | |
10 | + * version 2.1 of the License, or (at your option) any later version. | |
11 | + * | |
12 | + * FFmpeg is distributed in the hope that it will be useful, | |
13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | + * Lesser General Public License for more details. | |
16 | + * | |
17 | + * You should have received a copy of the GNU Lesser General Public | |
18 | + * License along with FFmpeg; if not, write to the Free Software | |
19 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | + */ | |
21 | + | |
22 | +#include <stdio.h> | |
23 | + | |
24 | +#include "avfilter.h" | |
25 | +#define INDEX_X 0 | |
26 | +#define INDEX_Y 1 | |
27 | +#define INDEX_MAX 2 | |
28 | + | |
29 | +typedef struct{ | |
30 | + int size[INDEX_MAX]; | |
31 | + int offset[INDEX_MAX]; | |
32 | + int shift[INDEX_MAX]; | |
33 | + | |
34 | + int osd; ///< checked, but not used in this version. | |
35 | + double aspect; | |
36 | + int round; | |
37 | + | |
38 | + int bpp; ///< bytes per pixel | |
39 | + int is_yuv; | |
40 | +} ExpandContext; | |
41 | + | |
42 | +static int init(AVFilterContext *ctx, const char *args, void *opaque) | |
43 | +{ | |
44 | + ExpandContext *expand = ctx->priv; | |
45 | + int i; | |
46 | + | |
47 | + /* default parameters */ | |
48 | + for(i=0;i<INDEX_MAX;i++){ | |
49 | + expand->offset[i] = -1; | |
50 | + expand->size[i] = -1; | |
51 | + expand->shift[i] = 0; | |
52 | + } | |
53 | + expand->osd = 0; | |
54 | + expand->aspect = 0.0f; | |
55 | + expand->round = 0; | |
56 | + | |
57 | + expand->bpp = 0; | |
58 | + expand->is_yuv = 0; | |
59 | + | |
60 | + if(args){ | |
61 | + int length = strlen(args); | |
62 | + char* osd_tmp = av_malloc(length); | |
63 | + char* aspect_tmp = av_malloc(length); | |
64 | + if(!osd_tmp || !aspect_tmp){ | |
65 | + av_log(ctx, AV_LOG_ERROR, "Failed to malloc.\n"); | |
66 | + } | |
67 | + | |
68 | + sscanf(args,"%d:%d:%d:%d:%255[^:]:%255[^:]:%d", | |
69 | + &expand->size[INDEX_X],&expand->size[INDEX_Y],&expand->offset[INDEX_X],&expand->offset[INDEX_Y], | |
70 | + osd_tmp,aspect_tmp,&expand->round | |
71 | + ); | |
72 | + | |
73 | + if(osd_tmp && strlen(osd_tmp) > 0){ //checked, but not used in this version. | |
74 | + if(!strncmp(osd_tmp,"true",4)){ | |
75 | + expand->osd = 1; | |
76 | + }else{ | |
77 | + expand->osd = atoi(osd_tmp); | |
78 | + } | |
79 | + } | |
80 | + | |
81 | + if(aspect_tmp && strlen(aspect_tmp) > 0){ | |
82 | + char* cp = strchr(aspect_tmp, '/'); | |
83 | + if(cp){ // rational | |
84 | + AVRational rat; | |
85 | + char* cpp; | |
86 | + rat.num = strtol(aspect_tmp, &cpp, 10); | |
87 | + if(cpp != aspect_tmp || cpp == cp){ | |
88 | + rat.den = strtol(cp+1, &cpp, 10); | |
89 | + }else{ | |
90 | + rat.num = 0; | |
91 | + } | |
92 | + if(rat.num && rat.den){ | |
93 | + double eval = ((double)rat.num) / rat.den; | |
94 | + if(eval > 0.0f){ | |
95 | + expand->aspect = eval; | |
96 | + } | |
97 | + } | |
98 | + }else{ // double | |
99 | + double eval = strtod(aspect_tmp, 0); | |
100 | + if(eval > 0.0f){ | |
101 | + expand->aspect = eval; | |
102 | + } | |
103 | + } | |
104 | + } | |
105 | + | |
106 | + av_log(ctx, AV_LOG_INFO, "Expand: %dx%d , (%d,%d) , osd: %d, aspect: %lf, round: %d\n", | |
107 | + expand->size[INDEX_X], expand->size[INDEX_Y], expand->offset[INDEX_X], expand->offset[INDEX_Y], expand->osd, expand->aspect, expand->round); | |
108 | + | |
109 | + av_free(osd_tmp); | |
110 | + av_free(aspect_tmp); | |
111 | + } | |
112 | + | |
113 | + return 0; | |
114 | +} | |
115 | + | |
116 | +static int query_formats(AVFilterContext *ctx){ | |
117 | + avfilter_set_common_formats(ctx,avfilter_make_format_list(30, // out of 38 | |
118 | + PIX_FMT_YUV420P, | |
119 | + PIX_FMT_YUV422P, | |
120 | + PIX_FMT_YUV444P, | |
121 | + PIX_FMT_YUV410P, | |
122 | + PIX_FMT_YUV411P, | |
123 | + PIX_FMT_YUV440P, | |
124 | + PIX_FMT_YUVJ420P, | |
125 | + PIX_FMT_YUVJ422P, | |
126 | + PIX_FMT_YUVJ444P, | |
127 | + PIX_FMT_YUVJ440P, | |
128 | + PIX_FMT_YUVA420P, | |
129 | + PIX_FMT_NV12, | |
130 | + PIX_FMT_NV21, | |
131 | + PIX_FMT_RGB24, | |
132 | + PIX_FMT_BGR24, | |
133 | + PIX_FMT_RGB32, | |
134 | + PIX_FMT_BGR32, | |
135 | + PIX_FMT_RGB32_1, | |
136 | + PIX_FMT_BGR32_1, | |
137 | + PIX_FMT_GRAY16BE, | |
138 | + PIX_FMT_GRAY16LE, | |
139 | + PIX_FMT_BGR555, | |
140 | + PIX_FMT_BGR565, | |
141 | + PIX_FMT_RGB555, | |
142 | + PIX_FMT_RGB565, | |
143 | + //PIX_FMT_YUYV422, // not supported. | |
144 | + //PIX_FMT_UYVY422, // not supported. | |
145 | + //PIX_FMT_UYYVYY411, // not supported. | |
146 | + PIX_FMT_RGB8, | |
147 | + PIX_FMT_BGR8, | |
148 | + PIX_FMT_RGB4_BYTE, | |
149 | + PIX_FMT_BGR4_BYTE, | |
150 | + PIX_FMT_GRAY8 | |
151 | + //PIX_FMT_RGB4, //not supported | |
152 | + //PIX_FMT_BGR4, //not supported | |
153 | + //PIX_FMT_MONOWHITE, // not supported | |
154 | + //PIX_FMT_MONOBLACK, // not supported | |
155 | + //PIX_FMT_PAL8, // not supported | |
156 | + )); | |
157 | + return 0; | |
158 | +} | |
159 | + | |
160 | + | |
161 | +static int config_input(AVFilterLink *link) | |
162 | +{ | |
163 | + ExpandContext *expand = link->dst->priv; | |
164 | + int i; | |
165 | + int size[INDEX_MAX]; | |
166 | + | |
167 | + size[INDEX_X] = link->w; | |
168 | + size[INDEX_Y] = link->h; | |
169 | + | |
170 | + for(i=0;i<INDEX_MAX;i++){ | |
171 | + if (expand->size[i] == -1){ | |
172 | + expand->size[i]=size[i]; | |
173 | + } else if (expand->size[i] < -1){ | |
174 | + expand->size[i]=size[i] - expand->size[i]; | |
175 | + } else if (expand->size[INDEX_X] < size[i]){ | |
176 | + expand->size[i]=size[i]; | |
177 | + } | |
178 | + } | |
179 | + | |
180 | + if (expand->aspect > 0.0f) { | |
181 | + if (expand->size[INDEX_Y] < (expand->size[INDEX_X] / expand->aspect)) { | |
182 | + expand->size[INDEX_Y] = (expand->size[INDEX_X] / expand->aspect) + 0.5; | |
183 | + } else { | |
184 | + expand->size[INDEX_X] = (expand->size[INDEX_Y] * expand->aspect) + 0.5; | |
185 | + } | |
186 | + } | |
187 | + | |
188 | + for(i=0;i<INDEX_MAX;i++){ | |
189 | + if (expand->round > 1) { | |
190 | + expand->size[i] = (1+(expand->size[i]-1)/expand->round)*expand->round; | |
191 | + } | |
192 | + if(expand->offset[i] < 0 || (expand->offset[i]+size[i]) > expand->size[i]){ | |
193 | + expand->offset[i] = (expand->size[INDEX_X] - size[i])>>1; | |
194 | + } | |
195 | + } | |
196 | + | |
197 | + avcodec_get_chroma_sub_sample(link->format, &expand->shift[INDEX_X], &expand->shift[INDEX_Y]); | |
198 | + for(i=0;i<INDEX_MAX;i++){ | |
199 | + expand->offset[i] &= ~((1 << expand->shift[i]) - 1); | |
200 | + expand->size[i] &= ~((1 << expand->shift[i]) - 1); | |
201 | + } | |
202 | + | |
203 | + switch(link->format) { | |
204 | + case PIX_FMT_YUV420P: | |
205 | + case PIX_FMT_YUV422P: | |
206 | + case PIX_FMT_YUV444P: | |
207 | + case PIX_FMT_YUV410P: | |
208 | + case PIX_FMT_YUV411P: | |
209 | + case PIX_FMT_YUV440P: | |
210 | + case PIX_FMT_YUVJ420P: | |
211 | + case PIX_FMT_YUVJ422P: | |
212 | + case PIX_FMT_YUVJ444P: | |
213 | + case PIX_FMT_YUVJ440P: | |
214 | + case PIX_FMT_YUVA420P: | |
215 | + case PIX_FMT_NV12: | |
216 | + case PIX_FMT_NV21: | |
217 | + expand->is_yuv = 1; | |
218 | + case PIX_FMT_RGB8: | |
219 | + case PIX_FMT_BGR8: | |
220 | + case PIX_FMT_RGB4_BYTE: | |
221 | + case PIX_FMT_BGR4_BYTE: | |
222 | + case PIX_FMT_GRAY8: | |
223 | + expand->bpp = 1; | |
224 | + break; | |
225 | + case PIX_FMT_RGB24: | |
226 | + case PIX_FMT_BGR24: | |
227 | + expand->bpp = 3; | |
228 | + break; | |
229 | + case PIX_FMT_RGB32: | |
230 | + case PIX_FMT_BGR32: | |
231 | + case PIX_FMT_RGB32_1: | |
232 | + case PIX_FMT_BGR32_1: | |
233 | + expand->bpp = 4; | |
234 | + break; | |
235 | + case PIX_FMT_GRAY16BE: | |
236 | + case PIX_FMT_GRAY16LE: | |
237 | + case PIX_FMT_BGR555: | |
238 | + case PIX_FMT_BGR565: | |
239 | + case PIX_FMT_RGB555: | |
240 | + case PIX_FMT_RGB565: | |
241 | + expand->bpp = 2; | |
242 | + break; | |
243 | + // not supported. | |
244 | + //case PIX_FMT_YUYV422: | |
245 | + //case PIX_FMT_UYVY422: | |
246 | + //case PIX_FMT_UYYVYY411: | |
247 | + //case PIX_FMT_RGB4: | |
248 | + //case PIX_FMT_BGR4: | |
249 | + //case PIX_FMT_MONOWHITE: | |
250 | + //case PIX_FMT_MONOBLACK: | |
251 | + //case PIX_FMT_PAL8: | |
252 | + default: // invalid or not supported format | |
253 | + return -1; | |
254 | + } | |
255 | + | |
256 | + return 0; | |
257 | +} | |
258 | + | |
259 | +static int config_output(AVFilterLink *link) | |
260 | +{ | |
261 | + ExpandContext *expand = link->src->priv; | |
262 | + | |
263 | + link->w = expand->size[INDEX_X]; | |
264 | + link->h = expand->size[INDEX_Y]; | |
265 | + | |
266 | + return 0; | |
267 | +} | |
268 | + | |
269 | +static void start_frame(AVFilterLink *link, AVFilterPicRef *picref) | |
270 | +{ | |
271 | + AVFilterLink *out = link->dst->outputs[0]; | |
272 | + out->outpic = avfilter_get_video_buffer(out, AV_PERM_WRITE); | |
273 | + out->outpic->pts = picref->pts; | |
274 | + avfilter_start_frame(out, avfilter_ref_pic(out->outpic, ~0)); | |
275 | +} | |
276 | + | |
277 | +static void draw_slice(AVFilterLink *link, int y, int h) | |
278 | +{ | |
279 | + ExpandContext *expand = link->dst->priv; | |
280 | + AVFilterPicRef *outpic = link->dst->outputs[0]->outpic; | |
281 | + AVFilterPicRef *inpic = link->cur_pic; | |
282 | + int i; | |
283 | + int is_first = (y <= 0); | |
284 | + int is_end = (y+h >= inpic->h); | |
285 | + | |
286 | + for(i=0;i<4;i++) { | |
287 | + if(outpic->data[i]) { | |
288 | + int j; | |
289 | + char* out_buff = outpic->data[i]; | |
290 | + const char* in_buff = inpic->data[i]; | |
291 | + | |
292 | + int copy_length; | |
293 | + int y_add; | |
294 | + int padcolor; | |
295 | + int x_shift,y_shift; | |
296 | + | |
297 | + if(!expand->is_yuv || i == 3){ // not YUV, or alpha channel of YUVA | |
298 | + padcolor = 0; | |
299 | + x_shift = y_shift = 0; | |
300 | + }else{ | |
301 | + padcolor = (i == 0) ? 16 : 128; | |
302 | + x_shift = (i == 0) ? 0 : expand->shift[INDEX_X]; | |
303 | + y_shift = (i == 0) ? 0 : expand->shift[INDEX_Y]; | |
304 | + } | |
305 | + | |
306 | + copy_length = (inpic->w >> x_shift) * expand->bpp; | |
307 | + y_add = 1<<y_shift; | |
308 | + | |
309 | + if(is_first){ | |
310 | + int size = (expand->offset[INDEX_Y] >> y_shift) * outpic->linesize[i]; | |
311 | + memset(out_buff,padcolor,size); | |
312 | + out_buff += size; | |
313 | + }else{ | |
314 | + int y_skip = expand->offset[INDEX_Y] >> y_shift; | |
315 | + out_buff += outpic->linesize[i] * y_skip; | |
316 | + in_buff += inpic->linesize[i] * y_skip; | |
317 | + } | |
318 | + | |
319 | + for(j=0;j<h;j+=y_add){ | |
320 | + int size,total_size = 0; | |
321 | + size = (expand->offset[INDEX_X] >> x_shift) * expand->bpp; | |
322 | + memset(out_buff,padcolor,size); | |
323 | + out_buff += size; | |
324 | + total_size += size; | |
325 | + | |
326 | + memcpy(out_buff,in_buff,copy_length); | |
327 | + out_buff += copy_length; | |
328 | + total_size += copy_length; | |
329 | + | |
330 | + size = outpic->linesize[i]-total_size; | |
331 | + memset(out_buff,padcolor,size); | |
332 | + out_buff += size; | |
333 | + | |
334 | + in_buff += inpic->linesize[i]; | |
335 | + } | |
336 | + | |
337 | + if(is_end){ | |
338 | + memset(out_buff,padcolor,((outpic->h-expand->offset[INDEX_Y]-inpic->h) >> y_shift) * outpic->linesize[i]); | |
339 | + } | |
340 | + | |
341 | + } | |
342 | + } | |
343 | + if(is_first && is_end){ | |
344 | + avfilter_draw_slice(link->dst->outputs[0], 0, outpic->h); | |
345 | + }else if(is_first){ | |
346 | + avfilter_draw_slice(link->dst->outputs[0], 0, expand->offset[INDEX_Y] + h); | |
347 | + }else if(is_end){ | |
348 | + avfilter_draw_slice(link->dst->outputs[0], expand->offset[INDEX_Y] + y, outpic->h - expand->offset[INDEX_Y] - y); | |
349 | + }else{ | |
350 | + avfilter_draw_slice(link->dst->outputs[0], expand->offset[INDEX_Y] + y, h); | |
351 | + } | |
352 | +} | |
353 | + | |
354 | +AVFilter avfilter_vf_expand = { | |
355 | + .name = "expand", | |
356 | + .priv_size = sizeof(ExpandContext), | |
357 | + | |
358 | + .init = init, | |
359 | + .query_formats = query_formats, | |
360 | + | |
361 | + .inputs = (AVFilterPad[]) {{ .name = "default", | |
362 | + .type = CODEC_TYPE_VIDEO, | |
363 | + .start_frame = start_frame, | |
364 | + .draw_slice = draw_slice, | |
365 | + .config_props = config_input, }, | |
366 | + { .name = NULL}}, | |
367 | + .outputs = (AVFilterPad[]) {{ .name = "default", | |
368 | + .type = CODEC_TYPE_VIDEO, | |
369 | + .config_props = config_output, }, | |
370 | + { .name = NULL}}, | |
371 | +}; | |
372 | + |
@@ -0,0 +1,256 @@ | ||
1 | +/* | |
2 | + * 拡張Vhookフィルタ | |
3 | + * copyright (c) 2008 ψ(プサイ) | |
4 | + * | |
5 | + * さきゅばす用に拡張されたVhookライブラリを | |
6 | + * 駆動させるためのフィルタです。 | |
7 | + * | |
8 | + * このファイルは「さきゅばす」の一部であり、 | |
9 | + * このソースコードはGPLライセンスで配布されますです。 | |
10 | + */ | |
11 | +#include "avfilter.h" | |
12 | +#include "common/framehook_ext.h" | |
13 | +#include "avtool.h" | |
14 | +#include <string.h> | |
15 | +#include <stdio.h> | |
16 | +#include <ctype.h> | |
17 | + | |
18 | +#ifdef HAVE_DLFCN_H | |
19 | +#include <dlfcn.h> | |
20 | +#else | |
21 | +//dlfcn.hの無いWindows Mingw環境用 | |
22 | +#define dlopen(a) ((void*)LoadLibrary(a)) | |
23 | +#define dlsym(a,b) ((void*)GetProcAddress((HMODULE)(a),(b))) | |
24 | +#define dlclose(a) FreeLibrary((HMODULE)(a)); | |
25 | +#endif | |
26 | + | |
27 | +//デリミタ。MEncoder側とは同じにしといた方がよさそう。 | |
28 | +#define VHEXT_DELIM '|' | |
29 | + | |
30 | +typedef struct{ | |
31 | + //引数はあとあと使うので確保。 | |
32 | + char* args; | |
33 | + char** argv; | |
34 | + int argc; | |
35 | + //ツールボックス | |
36 | + const toolbox* Box; | |
37 | + //ダイナミックライブラリへのポインタ | |
38 | + void* Dynamic; | |
39 | + //関数へのポインタ | |
40 | + FrameHookExtConfigureFn ExtConfigure; | |
41 | + FrameHookExtProcessFn ExtProcess; | |
42 | + FrameHookExtReleaseFn ExtRelease; | |
43 | + //FrameHookの使うポインタ | |
44 | + void* Context; | |
45 | +} Context; | |
46 | + | |
47 | +/* | |
48 | + * この中でだけ使う関数定義 | |
49 | + */ | |
50 | + | |
51 | +char** split(char* str,int str_len,int* argc,char delim); | |
52 | +int decode(char* s,int len); | |
53 | + | |
54 | +/* | |
55 | + * AVFilter構造体に格納される関数群 | |
56 | + */ | |
57 | + | |
58 | +static int init(AVFilterContext *ctx, const char *args, void *opaque){ | |
59 | + //Contextをとりあえず確保 | |
60 | + Context *context= ctx->priv; | |
61 | + av_log(ctx, AV_LOG_ERROR, "[libavfilter/VhookExt Filter]called with args = %s.\n",args); | |
62 | + | |
63 | + //引数がNULLなのはおかしい | |
64 | + if(!args) { | |
65 | + av_log(ctx, AV_LOG_ERROR, "[libavfilter/VhookExt Filter]Invalid arguments.\n"); | |
66 | + return -1; | |
67 | + } | |
68 | + int arg_len = strlen(args); | |
69 | + //引数のコピー | |
70 | + context->args = (char*)av_malloc(arg_len+1); | |
71 | + if(!context->args){ | |
72 | + av_log(ctx, AV_LOG_ERROR, "[libavfilter/VhookExt Filter]Failed to malloc memory for args.\n"); | |
73 | + return -1; | |
74 | + } | |
75 | + memcpy(context->args,args,arg_len); | |
76 | + context->args[arg_len]='\0';//NULLで最後を埋める。 | |
77 | + | |
78 | + //デコード | |
79 | + decode(context->args,arg_len); | |
80 | + //引数の展開 | |
81 | + context->argv = split(context->args,arg_len,&context->argc,VHEXT_DELIM); | |
82 | + if(!context->argv){ | |
83 | + av_log(ctx, AV_LOG_ERROR, "[libavfilter/VhookExt Filter]Failed to split args.\n"); | |
84 | + return -1; | |
85 | + } | |
86 | + | |
87 | + //ツールボックスを取得 | |
88 | + context->Box = tool_getToolBox(); | |
89 | + if(!context->Box){ | |
90 | + av_log(ctx, AV_LOG_ERROR, "[libavfilter/VhookExt Filter]Failed to get ToolBox.\n"); | |
91 | + return -1; | |
92 | + } | |
93 | + | |
94 | + //DLL読み込み | |
95 | + context->Dynamic = dlopen(context->argv[0], RTLD_NOW); | |
96 | + if (!context->Dynamic) { | |
97 | + av_log(NULL, AV_LOG_ERROR, "[libavfilter/VhookExt Filter][Lib:%s]Failed to open lib: %s\nMSG:%s\n",context->argv[0],context->argv[0], dlerror()); | |
98 | + return -1; | |
99 | + } | |
100 | + //各関数を取得 | |
101 | + context->ExtConfigure = dlsym(context->Dynamic, "ExtConfigure"); | |
102 | + context->ExtProcess = dlsym(context->Dynamic, "ExtProcess"); | |
103 | + context->ExtRelease = dlsym(context->Dynamic, "ExtRelease"); | |
104 | + if(!context->ExtConfigure){ | |
105 | + av_log(ctx, AV_LOG_ERROR, "[libavfilter/VhookExt Filter]Failed to get ExtConfigure.\n"); | |
106 | + return -1; | |
107 | + } | |
108 | + if(!context->ExtProcess){ | |
109 | + av_log(ctx, AV_LOG_ERROR, "[libavfilter/VhookExt Filter]Failed to get ExtProcess.\n"); | |
110 | + return -1; | |
111 | + } | |
112 | + if(!context->ExtRelease){ | |
113 | + av_log(ctx, AV_LOG_ERROR, "[libavfilter/VhookExt Filter]Failed to get ExtRelease.\n"); | |
114 | + return -1; | |
115 | + } | |
116 | + | |
117 | + //Configureを呼び出す | |
118 | + int code; | |
119 | + if((code = context->ExtConfigure(&context->Context,context->Box,context->argc,context->argv))){ | |
120 | + av_log(ctx, AV_LOG_ERROR, "[libavfilter/VhookExt Filter]Failed to configure.Code:%d\n",code); | |
121 | + return -1; | |
122 | + } | |
123 | + return 0; | |
124 | +} | |
125 | + | |
126 | +static void uninit(AVFilterContext *ctx){ | |
127 | + //Contextをとりあえず確保 | |
128 | + Context *context= ctx->priv; | |
129 | + //開放する。 | |
130 | + context->ExtRelease(context->Context,context->Box); | |
131 | + //引数も開放する。 | |
132 | + if(!context->args){ | |
133 | + av_free(context->args); | |
134 | + } | |
135 | + if(!context->argv){ | |
136 | + av_free(context->argv); | |
137 | + } | |
138 | + //DLLも閉じる | |
139 | + dlclose(context->Dynamic); | |
140 | +} | |
141 | + | |
142 | +static int query_formats(AVFilterContext *ctx){ | |
143 | + //SDLで使いやすくするためにRGB24フォーマットを要求する。 | |
144 | + enum PixelFormat pix_fmts[] = { PIX_FMT_RGB24, PIX_FMT_NONE }; | |
145 | + avfilter_set_common_formats(ctx,avfilter_make_format_list(pix_fmts)); | |
146 | + return 0; | |
147 | +} | |
148 | + | |
149 | +/* | |
150 | + * AVFilterPadのInput側に呼ばれる関数 | |
151 | + */ | |
152 | + | |
153 | +static void start_frame(AVFilterLink *link, AVFilterBufferRef *bufref){ | |
154 | + //おまじない | |
155 | + avfilter_start_frame(link->dst->outputs[0], bufref); | |
156 | +} | |
157 | + | |
158 | +static void end_frame(AVFilterLink *link){ | |
159 | + //ポインタは基本 | |
160 | + Context *context = link->dst->priv; | |
161 | + //よくわからないけどとりあえずおまじない(えー | |
162 | + AVFilterLink* output = link->dst->outputs[0]; | |
163 | + AVFilterBufferRef *buf = link->cur_buf; | |
164 | + //独自構造体に代入 | |
165 | + vhext_frame frame; | |
166 | + frame.data = buf->data[0]; | |
167 | + frame.linesize = buf->linesize[0]; | |
168 | + frame.w = buf->video->w; | |
169 | + frame.h = buf->video->h; | |
170 | + frame.pts = ((double)buf->pts) / AV_TIME_BASE; | |
171 | + //ライブラリを呼び出す。 | |
172 | + context->ExtProcess(context->Context,context->Box,&frame); | |
173 | + | |
174 | + //おなじくおなじまい(えええ | |
175 | + avfilter_draw_slice(output, 0, buf->video->h, 1); | |
176 | + avfilter_end_frame(output); | |
177 | +} | |
178 | + | |
179 | +AVFilter avfilter_vf_vhext= | |
180 | +{ | |
181 | + .name = "vhext", | |
182 | + | |
183 | + .priv_size = sizeof(Context), | |
184 | + | |
185 | + .init = init, | |
186 | + .uninit = uninit, | |
187 | + | |
188 | + .query_formats = query_formats, | |
189 | + .inputs = (AVFilterPad[]) {{ .name = "default", | |
190 | + .type = AVMEDIA_TYPE_VIDEO, | |
191 | + .start_frame = start_frame, | |
192 | + .end_frame = end_frame, | |
193 | + .min_perms = AV_PERM_WRITE | | |
194 | + AV_PERM_READ, | |
195 | + .rej_perms = AV_PERM_REUSE | | |
196 | + AV_PERM_REUSE2}, | |
197 | + { .name = NULL}}, | |
198 | + .outputs = (AVFilterPad[]) {{ .name = "default", | |
199 | + .type = AVMEDIA_TYPE_VIDEO, }, | |
200 | + { .name = NULL}}, | |
201 | +}; | |
202 | + | |
203 | +/* | |
204 | + * この中でのみ使われる関数 | |
205 | + */ | |
206 | + | |
207 | +//文字列を特定の文字によって分けます。 | |
208 | +char** split(char* str,int str_len,int* argc,char delim){ | |
209 | + //チェック | |
210 | + if(!str || delim=='\0' || str_len < 0){ | |
211 | + return 0; | |
212 | + } | |
213 | + //確保 | |
214 | + char** argv = av_malloc(sizeof(char*)); | |
215 | + if(!argv){ | |
216 | + return 0; | |
217 | + } | |
218 | + //ループ開始 | |
219 | + int last = 0; | |
220 | + int i; | |
221 | + int arg_cnt = 0; | |
222 | + for(i=0;i<str_len;i++){ | |
223 | + if(str[i] == delim){//デリミタに達した | |
224 | + str[i] = '\0'; | |
225 | + argv[arg_cnt] = &str[last]; | |
226 | + arg_cnt++; | |
227 | + last = i+1; | |
228 | + argv = av_realloc(argv,sizeof(char*) * (arg_cnt+1)); | |
229 | + } | |
230 | + } | |
231 | + argv[arg_cnt] = &str[last]; | |
232 | + *argc = arg_cnt + 1; | |
233 | + return argv; | |
234 | +} | |
235 | + | |
236 | +//URエンコード記法が使えます。 | |
237 | +int decode(char* s,int len){ | |
238 | + int i,j; | |
239 | + char buf,*s1; | |
240 | + if(len==0)return(-1); | |
241 | + s1=(char*)av_malloc(len); | |
242 | + for(i=0,j=0;i<len;i++,j++) | |
243 | + { | |
244 | + if(s[i]=='+'){s1[j]=' ';continue;} | |
245 | + if(s[i]!='%') {s1[j]=s[i];continue;} | |
246 | + buf=((s[++i]>='A') ? s[i]-'A'+10 : s[i]-'0'); | |
247 | + buf*=16; | |
248 | + buf+=((s[++i]>='A') ? s[i]-'A'+10 : s[i]-'0'); | |
249 | + s1[j]=buf; | |
250 | + } | |
251 | + for(i=0;i<j;i++) s[i]=s1[i]; | |
252 | + s[i]='\0'; | |
253 | + av_free(s1); | |
254 | + return(0); | |
255 | +} | |
256 | + |