pixconv.c 4.14 KB
Newer Older
aymeric's avatar
aymeric committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#ifdef HAVE_CONFIG_H
#include "mediastreamer-config.h"
#endif

#include "mediastreamer2/msfilter.h"
#include "mediastreamer2/msvideo.h"



typedef struct PixConvState{
	YuvBuf outbuf;
	mblk_t *yuv_msg;
32
	MSScalerContext *scaler;
aymeric's avatar
aymeric committed
33
	MSVideoSize size;
34 35
	MSPixFmt  in_fmt;
	MSPixFmt out_fmt;
36
	unsigned long number_of_allocated_yuv_buf;
aymeric's avatar
aymeric committed
37 38 39
}PixConvState;

static void pixconv_init(MSFilter *f){
40
	PixConvState *s=ms_new0(PixConvState,1);
aymeric's avatar
aymeric committed
41 42 43
	s->yuv_msg=NULL;
	s->size.width = MS_VIDEO_SIZE_CIF_W;
	s->size.height = MS_VIDEO_SIZE_CIF_H;
44 45 46
	s->in_fmt=MS_YUV420P;
	s->out_fmt=MS_YUV420P;
	s->scaler=NULL;
47
	s->number_of_allocated_yuv_buf=0;
aymeric's avatar
aymeric committed
48 49 50 51 52
	f->data=s;
}

static void pixconv_uninit(MSFilter *f){
	PixConvState *s=(PixConvState*)f->data;
53 54 55
	if (s->scaler!=NULL){
		ms_scaler_context_free(s->scaler);
		s->scaler=NULL;
aymeric's avatar
aymeric committed
56 57
	}
	if (s->yuv_msg!=NULL) freemsg(s->yuv_msg);
58 59
	if (s->number_of_allocated_yuv_buf>1)
		ms_warning("Pixconf allocated [%lu] yuv buff",s->number_of_allocated_yuv_buf);
aymeric's avatar
aymeric committed
60 61 62 63 64 65 66 67 68 69
	ms_free(s);
}

static mblk_t * pixconv_alloc_mblk(PixConvState *s){
	if (s->yuv_msg!=NULL){
		int ref=s->yuv_msg->b_datap->db_ref;
		if (ref==1){
			return dupmsg(s->yuv_msg);
		}else{
			/*the last msg is still referenced by somebody else*/
70 71
			/*ms_message("Somebody still retaining yuv buffer (ref=%i)",ref);
			 * seems to be the default situation at least on macosx, removing traces*/
aymeric's avatar
aymeric committed
72 73 74 75
			freemsg(s->yuv_msg);
			s->yuv_msg=NULL;
		}
	}
Simon Morlat's avatar
Simon Morlat committed
76
	s->yuv_msg=ms_yuv_buf_alloc(&s->outbuf,s->size.width,s->size.height);
77
	s->number_of_allocated_yuv_buf++;
aymeric's avatar
aymeric committed
78 79 80 81
	return dupmsg(s->yuv_msg);
}

static void pixconv_process(MSFilter *f){
82
	mblk_t *im,*om=NULL;
aymeric's avatar
aymeric committed
83 84 85 86 87 88
	PixConvState *s=(PixConvState*)f->data;

	while((im=ms_queue_get(f->inputs[0]))!=NULL){
		if (s->in_fmt==s->out_fmt){
			om=im;
		}else{
89
			MSPicture inbuf;
90
			if (ms_picture_init_from_mblk_with_size(&inbuf,im,s->in_fmt,s->size.width,s->size.height)==0){
91 92 93 94 95 96 97 98 99 100 101 102 103
				om=pixconv_alloc_mblk(s);
				if (s->scaler==NULL){
					s->scaler=ms_scaler_create_context(inbuf.w, inbuf.h,
						s->in_fmt,inbuf.w,inbuf.h,
						s->out_fmt,MS_SCALER_METHOD_BILINEAR);
				}
				if (s->in_fmt==MS_RGB24_REV){
					inbuf.planes[0]+=inbuf.strides[0]*(inbuf.h-1);
					inbuf.strides[0]=-inbuf.strides[0];
				}
				if (ms_scaler_process (s->scaler,inbuf.planes,inbuf.strides, s->outbuf.planes, s->outbuf.strides)<0){
					ms_error("MSPixConv: Error in ms_sws_scale().");
				}
aymeric's avatar
aymeric committed
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
			}
			freemsg(im);
		}
		if (om!=NULL) ms_queue_put(f->outputs[0],om);
	}
}

static int pixconv_set_vsize(MSFilter *f, void*arg){
	PixConvState *s=(PixConvState*)f->data;
	s->size=*(MSVideoSize*)arg;
	return 0;
}

static int pixconv_set_pixfmt(MSFilter *f, void *arg){
	MSPixFmt fmt=*(MSPixFmt*)arg;
	PixConvState *s=(PixConvState*)f->data;
120
	s->in_fmt=fmt;
aymeric's avatar
aymeric committed
121 122 123 124 125 126 127 128 129 130 131 132 133 134
	return 0;
}

static MSFilterMethod methods[]={
	{	MS_FILTER_SET_VIDEO_SIZE, pixconv_set_vsize	},
	{	MS_FILTER_SET_PIX_FMT,	pixconv_set_pixfmt	},
	{	0	,	NULL }
};

#ifdef _MSC_VER

MSFilterDesc ms_pix_conv_desc={
	MS_PIX_CONV_ID,
	"MSPixConv",
135
	N_("A pixel format converter"),
aymeric's avatar
aymeric committed
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
	MS_FILTER_OTHER,
	NULL,
	1,
	1,
	pixconv_init,
	NULL,
	pixconv_process,
	NULL,
	pixconv_uninit,
	methods
};

#else

MSFilterDesc ms_pix_conv_desc={
	.id=MS_PIX_CONV_ID,
	.name="MSPixConv",
153
	.text=N_("A pixel format converter"),
aymeric's avatar
aymeric committed
154 155 156 157 158 159 160 161 162 163 164 165 166
	.category=MS_FILTER_OTHER,
	.ninputs=1,
	.noutputs=1,
	.init=pixconv_init,
	.process=pixconv_process,
	.uninit=pixconv_uninit,
	.methods=methods
};

#endif

MS_FILTER_DESC_EXPORT(ms_pix_conv_desc)