| 1 | /* |
|---|
| 2 | mediastreamer2 library - modular sound and video processing and streaming |
|---|
| 3 | Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) |
|---|
| 4 | |
|---|
| 5 | This program is free software; you can redistribute it and/or |
|---|
| 6 | modify it under the terms of the GNU General Public License |
|---|
| 7 | as published by the Free Software Foundation; either version 2 |
|---|
| 8 | of the License, or (at your option) any later version. |
|---|
| 9 | |
|---|
| 10 | This program is distributed in the hope that it will be useful, |
|---|
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | GNU General Public License for more details. |
|---|
| 14 | |
|---|
| 15 | You should have received a copy of the GNU General Public License |
|---|
| 16 | along with this program; if not, write to the Free Software |
|---|
| 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 18 | */ |
|---|
| 19 | |
|---|
| 20 | #ifdef HAVE_CONFIG_H |
|---|
| 21 | #include "mediastreamer-config.h" |
|---|
| 22 | #endif |
|---|
| 23 | |
|---|
| 24 | #include "mediastreamer2/msfilter.h" |
|---|
| 25 | #include "mediastreamer2/msticker.h" |
|---|
| 26 | #include "mediastreamer2/msvideo.h" |
|---|
| 27 | |
|---|
| 28 | #include "ffmpeg-priv.h" |
|---|
| 29 | |
|---|
| 30 | typedef struct SizeConvState{ |
|---|
| 31 | MSVideoSize target_vsize; |
|---|
| 32 | MSVideoSize in_vsize; |
|---|
| 33 | YuvBuf outbuf; |
|---|
| 34 | struct SwsContext *sws_ctx; |
|---|
| 35 | mblk_t *om; |
|---|
| 36 | float fps; |
|---|
| 37 | float start_time; |
|---|
| 38 | int frame_count; |
|---|
| 39 | queue_t rq; |
|---|
| 40 | } SizeConvState; |
|---|
| 41 | |
|---|
| 42 | |
|---|
| 43 | /*this MSFilter will do on the fly picture size conversion. It attempts to guess the picture size from the yuv buffer size. YUV420P is assumed on input. |
|---|
| 44 | For now it only supports QCIF->CIF, QVGA->CIF and CIF->CIF (does nothing in this case)*/ |
|---|
| 45 | |
|---|
| 46 | static void size_conv_init(MSFilter *f){ |
|---|
| 47 | SizeConvState *s=(SizeConvState *)ms_new(SizeConvState,1); |
|---|
| 48 | s->target_vsize.width = MS_VIDEO_SIZE_CIF_W; |
|---|
| 49 | s->target_vsize.height = MS_VIDEO_SIZE_CIF_H; |
|---|
| 50 | s->in_vsize.width=0; |
|---|
| 51 | s->in_vsize.height=0; |
|---|
| 52 | s->sws_ctx=NULL; |
|---|
| 53 | s->om=NULL; |
|---|
| 54 | s->start_time=0; |
|---|
| 55 | s->frame_count=-1; |
|---|
| 56 | s->fps=-1; /* default to process ALL frames */ |
|---|
| 57 | qinit(&s->rq); |
|---|
| 58 | f->data=s; |
|---|
| 59 | } |
|---|
| 60 | |
|---|
| 61 | static void size_conv_uninit(MSFilter *f){ |
|---|
| 62 | SizeConvState *s=(SizeConvState*)f->data; |
|---|
| 63 | ms_free(s); |
|---|
| 64 | } |
|---|
| 65 | |
|---|
| 66 | static void size_conv_postprocess(MSFilter *f){ |
|---|
| 67 | SizeConvState *s=(SizeConvState*)f->data; |
|---|
| 68 | if (s->sws_ctx!=NULL) { |
|---|
| 69 | sws_freeContext(s->sws_ctx); |
|---|
| 70 | s->sws_ctx=NULL; |
|---|
| 71 | } |
|---|
| 72 | if (s->om!=NULL){ |
|---|
| 73 | freemsg(s->om); |
|---|
| 74 | s->om=NULL; |
|---|
| 75 | } |
|---|
| 76 | flushq(&s->rq,0); |
|---|
| 77 | s->frame_count=-1; |
|---|
| 78 | } |
|---|
| 79 | |
|---|
| 80 | static mblk_t *size_conv_alloc_mblk(SizeConvState *s){ |
|---|
| 81 | if (s->om!=NULL){ |
|---|
| 82 | int ref=s->om->b_datap->db_ref; |
|---|
| 83 | if (ref==1){ |
|---|
| 84 | return dupmsg(s->om); |
|---|
| 85 | }else{ |
|---|
| 86 | /*the last msg is still referenced by somebody else*/ |
|---|
| 87 | ms_message("size_conv_alloc_mblk: Somebody still retaining yuv buffer (ref=%i)",ref); |
|---|
| 88 | freemsg(s->om); |
|---|
| 89 | s->om=NULL; |
|---|
| 90 | } |
|---|
| 91 | } |
|---|
| 92 | s->om=yuv_buf_alloc(&s->outbuf,s->target_vsize.width,s->target_vsize.height); |
|---|
| 93 | return dupmsg(s->om); |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | static struct SwsContext * get_resampler(SizeConvState *s, int w, int h){ |
|---|
| 97 | if (s->in_vsize.width!=w || |
|---|
| 98 | s->in_vsize.height!=h || s->sws_ctx==NULL){ |
|---|
| 99 | if (s->sws_ctx!=NULL){ |
|---|
| 100 | sws_freeContext(s->sws_ctx); |
|---|
| 101 | s->sws_ctx=NULL; |
|---|
| 102 | } |
|---|
| 103 | s->sws_ctx=sws_getContext(w,h,PIX_FMT_YUV420P, |
|---|
| 104 | s->target_vsize.width,s->target_vsize.height,PIX_FMT_YUV420P, |
|---|
| 105 | SWS_FAST_BILINEAR,NULL, NULL, NULL); |
|---|
| 106 | s->in_vsize.width=w; |
|---|
| 107 | s->in_vsize.height=h; |
|---|
| 108 | } |
|---|
| 109 | return s->sws_ctx; |
|---|
| 110 | } |
|---|
| 111 | |
|---|
| 112 | static void size_conv_process(MSFilter *f){ |
|---|
| 113 | SizeConvState *s=(SizeConvState*)f->data; |
|---|
| 114 | YuvBuf inbuf; |
|---|
| 115 | mblk_t *im; |
|---|
| 116 | int cur_frame; |
|---|
| 117 | |
|---|
| 118 | ms_filter_lock(f); |
|---|
| 119 | |
|---|
| 120 | if (s->frame_count==-1){ |
|---|
| 121 | s->start_time=f->ticker->time; |
|---|
| 122 | s->frame_count=0; |
|---|
| 123 | } |
|---|
| 124 | while((im=ms_queue_get(f->inputs[0]))!=NULL ){ |
|---|
| 125 | putq(&s->rq, im); |
|---|
| 126 | } |
|---|
| 127 | |
|---|
| 128 | cur_frame=((f->ticker->time-s->start_time)*s->fps/1000.0); |
|---|
| 129 | if (cur_frame<=s->frame_count && s->fps>=0) { |
|---|
| 130 | /* too much frame */ |
|---|
| 131 | while(s->rq.q_mcount>1){ |
|---|
| 132 | ms_message("MSSizeConv: extra frame removed."); |
|---|
| 133 | im=getq(&s->rq); |
|---|
| 134 | freemsg(im); |
|---|
| 135 | } |
|---|
| 136 | ms_filter_unlock(f); |
|---|
| 137 | return; |
|---|
| 138 | } |
|---|
| 139 | |
|---|
| 140 | if (cur_frame>s->frame_count && s->fps>=0) { |
|---|
| 141 | /*keep the most recent frame if several frames have been captured */ |
|---|
| 142 | while(s->rq.q_mcount>1){ |
|---|
| 143 | ms_message("MSSizeConv: extra frame removed."); |
|---|
| 144 | im=getq(&s->rq); |
|---|
| 145 | freemsg(im); |
|---|
| 146 | } |
|---|
| 147 | } |
|---|
| 148 | while((im=getq(&s->rq))!=NULL ){ |
|---|
| 149 | if (yuv_buf_init_from_mblk(&inbuf,im)==0){ |
|---|
| 150 | if (inbuf.w==s->target_vsize.width && |
|---|
| 151 | inbuf.h==s->target_vsize.height){ |
|---|
| 152 | ms_queue_put(f->outputs[0],im); |
|---|
| 153 | }else{ |
|---|
| 154 | struct SwsContext *sws_ctx=get_resampler(s,inbuf.w,inbuf.h); |
|---|
| 155 | mblk_t *om=size_conv_alloc_mblk(s); |
|---|
| 156 | if (sws_scale(sws_ctx,inbuf.planes,inbuf.strides, 0, |
|---|
| 157 | inbuf.h, s->outbuf.planes, s->outbuf.strides)<0){ |
|---|
| 158 | ms_error("MSSizeConv: error in sws_scale()."); |
|---|
| 159 | } |
|---|
| 160 | ms_queue_put(f->outputs[0],om); |
|---|
| 161 | freemsg(im); |
|---|
| 162 | } |
|---|
| 163 | s->frame_count++; |
|---|
| 164 | }else freemsg(im); |
|---|
| 165 | } |
|---|
| 166 | |
|---|
| 167 | ms_filter_unlock(f); |
|---|
| 168 | } |
|---|
| 169 | |
|---|
| 170 | |
|---|
| 171 | static int sizeconv_set_vsize(MSFilter *f, void*arg){ |
|---|
| 172 | SizeConvState *s=(SizeConvState*)f->data; |
|---|
| 173 | ms_filter_lock(f); |
|---|
| 174 | s->target_vsize=*(MSVideoSize*)arg; |
|---|
| 175 | freemsg(s->om); |
|---|
| 176 | s->om=NULL; |
|---|
| 177 | if (s->sws_ctx!=NULL) { |
|---|
| 178 | sws_freeContext(s->sws_ctx); |
|---|
| 179 | s->sws_ctx=NULL; |
|---|
| 180 | } |
|---|
| 181 | ms_filter_unlock(f); |
|---|
| 182 | return 0; |
|---|
| 183 | } |
|---|
| 184 | |
|---|
| 185 | static int sizeconv_set_fps(MSFilter *f, void *arg){ |
|---|
| 186 | SizeConvState *s=(SizeConvState*)f->data; |
|---|
| 187 | s->fps=*((float*)arg); |
|---|
| 188 | s->frame_count=-1; /* reset counter used for fps */ |
|---|
| 189 | return 0; |
|---|
| 190 | } |
|---|
| 191 | |
|---|
| 192 | |
|---|
| 193 | static MSFilterMethod methods[]={ |
|---|
| 194 | { MS_FILTER_SET_FPS , sizeconv_set_fps }, |
|---|
| 195 | { MS_FILTER_SET_VIDEO_SIZE, sizeconv_set_vsize }, |
|---|
| 196 | { 0 , NULL } |
|---|
| 197 | }; |
|---|
| 198 | |
|---|
| 199 | #ifdef _MSC_VER |
|---|
| 200 | |
|---|
| 201 | MSFilterDesc ms_size_conv_desc={ |
|---|
| 202 | MS_SIZE_CONV_ID, |
|---|
| 203 | "MSSizeConv", |
|---|
| 204 | N_("A video size converter"), |
|---|
| 205 | MS_FILTER_OTHER, |
|---|
| 206 | NULL, |
|---|
| 207 | 1, |
|---|
| 208 | 1, |
|---|
| 209 | size_conv_init, |
|---|
| 210 | NULL, |
|---|
| 211 | size_conv_process, |
|---|
| 212 | size_conv_postprocess, |
|---|
| 213 | size_conv_uninit, |
|---|
| 214 | methods |
|---|
| 215 | }; |
|---|
| 216 | |
|---|
| 217 | #else |
|---|
| 218 | |
|---|
| 219 | MSFilterDesc ms_size_conv_desc={ |
|---|
| 220 | .id=MS_SIZE_CONV_ID, |
|---|
| 221 | .name="MSSizeConv", |
|---|
| 222 | .text=N_("a small video size converter"), |
|---|
| 223 | .ninputs=1, |
|---|
| 224 | .noutputs=1, |
|---|
| 225 | .init=size_conv_init, |
|---|
| 226 | .process=size_conv_process, |
|---|
| 227 | .postprocess=size_conv_postprocess, |
|---|
| 228 | .uninit=size_conv_uninit, |
|---|
| 229 | .methods=methods |
|---|
| 230 | }; |
|---|
| 231 | |
|---|
| 232 | #endif |
|---|
| 233 | |
|---|
| 234 | MS_FILTER_DESC_EXPORT(ms_size_conv_desc) |
|---|
| 235 | |
|---|