[FFmpeg-soc] expand filter (alternative to pad syntax)

Vitor Sessak vitor1001 at gmail.com
Sat May 10 19:04:34 CEST 2008


Hi, and thanks for the patch!

Ryo Hirafuji wrote:
> Oh, I'm sorry.
> Here is a patch.
> It includes changes of allfilters.c and Makefile.

I'll give a first look:

> Index: vf_expand.c
> ===================================================================
> --- vf_expand.c	(revision 0)
> +++ vf_expand.c	(revision 0)
> @@ -0,0 +1,317 @@
> +/*
> +* video expand filter (replacement of pad syntax)

Bad aligned "*"

> +static char** split(char* str,int str_len,int* argc,char delim){
> +	if(!str || delim=='\0' || str_len < 0){
> +		return 0;
> +	}
> +	char** argv = av_malloc(sizeof(char*));

Declaration after code is forbidden in C99

> +	if(!argv){
> +		return 0;
> +	}
> +	int last = 0;
> +	int i;
> +	int arg_cnt = 0;
> +	for(i=0;i<str_len;i++){
> +		if(str[i] == delim){
> +			str[i] = '\0';
> +			argv[arg_cnt] = &str[last];
> +			arg_cnt++;
> +			last = i+1;
> +			argv = av_realloc(argv,sizeof(char*) * (arg_cnt+1));
> +		}
> +	}
> +	argv[arg_cnt] = &str[last];
> +	*argc = arg_cnt + 1;
> +	return argv;
> +}
> +
> +static int init(AVFilterContext *ctx, const char *args, void *opaque){
> +    Context *expand = ctx->priv;
> +
> +    /* default parameters */
> +    expand->x =  -1;
> +    expand->y =  -1;
> +    expand->ew = -1;
> +    expand->eh = -1;
> +	expand->osd = 0;
> +	expand->aspect = 0.0f;
> +	expand->round = 0;
> +
> +	expand->bpp = 0;
> +	expand->hsub = 0;
> +	expand->vsub = 0;
> +
> +	if(args){
> +		int argc;
> +		int length = strlen(args);
> +		char* copy_arg = av_malloc(length+1);
> +
> +		memcpy(copy_arg,args,length);
> +		copy_arg[length] = '\0';
> +
> +		char** argv = split(copy_arg,length,&argc,':');
> +		if(argc >= 1 && strlen(argv[0]) > 0){
> +			expand->ew = atoi(argv[0]);
> +		}
> +		if(argc >= 2 && strlen(argv[1]) > 0){
> +			expand->eh = atoi(argv[1]);
> +		}
> +		if(argc >= 3 && strlen(argv[2]) > 0){
> +			expand->x = atoi(argv[2]);
> +		}
> +		if(argc >= 4 && strlen(argv[3]) > 0){
> +			expand->y = atoi(argv[3]);
> +		}
> +
> +		if(argc >= 5 &&  strlen(argv[4]) > 0){ //checked, but not used in this version.
> +			if(!strncmp(argv[4],"true",4)){
> +				expand->osd = 1;
> +			}else{
> +				expand->osd = atoi(argv[4]);
> +			}
> +		}
> +
> +		if(argc >= 6 &&  strlen(argv[5]) > 0){
> +			int a,b;
> +			double eval;
> +
> +			sscanf(argv[5],"%d/%d",&a,&b);
> +			if(a != 0 && b != 0 && (a*b) > 0){
> +				expand->aspect = ((double)a)/b;
> +			}else if((eval = atof(argv[5])) >= 0.0f){
> +				expand->aspect = eval;

See av_parse_video_frame_rate() and AVRational.

> +			}else{
> +			}
> +		}
> +
> +		if(argc >= 7 &&  strlen(argv[6]) > 0){
> +			expand->round = atoi(argv[6]);
> +		}

I agree with the others that this could be much simplified using
sscanf() or similars.

> +		av_log(0, AV_LOG_INFO, "Expand: %dx%d , (%d,%d) , osd: %d, aspect: %lf, round: %d\n",
> +	    expand->ew, expand->eh, expand->x, expand->y, expand->osd, expand->aspect, expand->round);

When using av_log(), always give a context (in this case it could be
ctx), instead of NULL.

> +static int config_input(AVFilterLink *link){
> +    Context *expand = link->dst->priv;
> +	int width = link->w;
> +	int height = link->h;
> +
> +	if (expand->ew == -1){
> +		expand->ew=width;
> +	} else if (expand->ew < -1){
> +		expand->ew=width - expand->ew;
> +	} else if (expand->ew < width){
> +		expand->ew=width;
> +	}
> +
> +	if (expand->eh == -1){
> +		expand->eh=height;
> +	} else if (expand->eh < -1){
> +		expand->eh=height - expand->eh;
> +	} else if (expand->eh < height){
> +		expand->eh=height;
> +	}

It might be a matter of taste, but I think it would like much better
without the braces.

> +	av_log(0, AV_LOG_INFO, "x:%d y:%d\n",expand->x,expand->y);

context missing

> +static void start_frame(AVFilterLink *link, AVFilterPicRef *picref){
> +    Context *expand = link->dst->priv;
> +	AVFilterLink *out = link->dst->outputs[0];
> +	int i;
> +	int is_yuv;
> +	out->outpic      = avfilter_get_video_buffer(out, AV_PERM_WRITE);
> +    out->outpic->pts = picref->pts;
> +	is_yuv = out->outpic->data[1] != 0;
> +	if(is_yuv){

I suppose you mean is_planar? Also you should see pix_fmt_info

> +       	char* mem = out->outpic->data[0];
> +		for(i=0;i<out->outpic->h;i++){
> +			memset(mem,16,out->outpic->w);
> +			mem += out->outpic->linesize[0];
> +		}

Aren't you drawing some pixels to overwrite them latter? It's faster to
paint just the borders...

> +		for(i=1;i<3;i++) {

What about YUVA (YUV+alpha)?

> +	        if(out->outpic->data[i]) {
> +	        	int j;
> +	        	int h = out->outpic->h;
> +	        	mem = out->outpic->data[i];
> +	        	for(j=0;j<h;j+=(1<<expand->vsub)){
> +	        		memset(mem,128,out->outpic->w >> expand->hsub);
> +	        		mem += out->outpic->linesize[i];
> +				}
> +
> +	        }
> +		}

Maybe you can merge the loops for luma and chroma...

> +static void draw_slice(AVFilterLink *link, int y, int h){
> +    Context *expand = link->dst->priv;
> +	AVFilterPicRef *pic = link->dst->outputs[0]->outpic;
> +	AVFilterPicRef *cur_pic = link->cur_pic;

Maybe inpic and outpic are better names

> +	int i;
> +	unsigned int out_linesize = pic->linesize[0];
> +	unsigned char* out_buff = pic->data[0];
> +	unsigned int in_linesize = cur_pic->linesize[0];
> +	const unsigned char* in_buff = cur_pic->data[0];
> +	int copy_length = cur_pic->w * expand->bpp;

Maybe the code would be more readable to use pic->linesize[0] directly?
Maybe some of the others vars could be removed too (if it make the code
more clear, of course).

> +	for(i=0;i<h;i++){
> +		memcpy(out_buff,in_buff,cur_pic->w * expand->bpp);
> +		out_buff += out_linesize;
> +		in_buff += in_linesize;
> +	}
> +	for(i=1;i<4;i++) {

I think it'll be more simple if those two loops are merged

> +AVFilter avfilter_vf_expand = {
> +    .name      = "expand",
> +    .priv_size = sizeof(Context),
> +
> +    .init      = init,
> +
> +    .inputs    = (AVFilterPad[]) {{ .name            = "default",
> +                                    .type            = CODEC_TYPE_VIDEO,
> +                                    .start_frame     = start_frame,
> +                                    .draw_slice      = draw_slice,
> +                                    .end_frame       = end_frame,
> +                                    .config_props    = config_input, },
> +                                  { .name = NULL}},
> +    .outputs   = (AVFilterPad[]) {{ .name            = "default",
> +                                    .type            = CODEC_TYPE_VIDEO,
> +                                    .config_props    = config_output, },
> +                                  { .name = NULL}},
> +};

You don't set *AVFilter.formats. That means that your filter will accept
any format as input, but it don't handle PAL8 or 1 bit per pixel
blackwhite or other esoteric formats.







More information about the FFmpeg-soc mailing list