OSDN Git Service

画面でプロファイル作成処理
[coroid/inqubus.git] / ffmpeg_extension / libavfilter / vf_expand.c
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