]> sjero.net Git - linphone/blob - linphone/mediastreamer2/src/videostream.c
remote ortp and add it as a submodule instead.
[linphone] / linphone / mediastreamer2 / src / videostream.c
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 #include "mediastreamer2/mediastream.h"
21 #include "mediastreamer2/msfilter.h"
22 #include "mediastreamer2/msvideo.h"
23 #include "mediastreamer2/msrtp.h"
24 #include "mediastreamer2/msvideoout.h"
25
26
27 #ifdef HAVE_CONFIG_H
28 #include "mediastreamer-config.h"
29 #endif
30
31 extern RtpSession * create_duplex_rtpsession( int locport, bool_t ipv6);
32
33 #define MAX_RTP_SIZE    UDP_MAX_SIZE
34
35 /* this code is not part of the library itself, it is part of the mediastream program */
36 void video_stream_free (VideoStream * stream)
37 {
38         if (stream->session!=NULL){
39                 rtp_session_unregister_event_queue(stream->session,stream->evq);
40                 rtp_session_destroy(stream->session);
41         }
42         if (stream->rtprecv != NULL)
43                 ms_filter_destroy (stream->rtprecv);
44         if (stream->rtpsend!=NULL) 
45                 ms_filter_destroy (stream->rtpsend);
46         if (stream->source != NULL)
47                 ms_filter_destroy (stream->source);
48         if (stream->output != NULL)
49                 ms_filter_destroy (stream->output);
50         if (stream->decoder != NULL)
51                 ms_filter_destroy (stream->decoder);
52         if (stream->sizeconv != NULL)
53                 ms_filter_destroy (stream->sizeconv);
54         if (stream->pixconv!=NULL)
55                 ms_filter_destroy(stream->pixconv);
56         if (stream->tee!=NULL)
57                 ms_filter_destroy(stream->tee);
58         if (stream->ticker != NULL)
59                 ms_ticker_destroy (stream->ticker);
60         if (stream->evq!=NULL)
61                 ortp_ev_queue_destroy(stream->evq);
62         ms_free (stream);
63 }
64
65 /*this function must be called from the MSTicker thread:
66 it replaces one filter by another one.
67 This is a dirty hack that works anyway.
68 It would be interesting to have something that does the job
69 simplier within the MSTicker api
70 */
71 void video_stream_change_decoder(VideoStream *stream, int payload){
72         RtpSession *session=stream->session;
73         RtpProfile *prof=rtp_session_get_profile(session);
74         PayloadType *pt=rtp_profile_get_payload(prof,payload);
75         if (pt!=NULL){
76                 MSFilter *dec=ms_filter_create_decoder(pt->mime_type);
77                 if (dec!=NULL){
78                         ms_filter_unlink(stream->rtprecv, 0, stream->decoder, 0);
79                         ms_filter_unlink(stream->decoder,0,stream->output,0);
80                         ms_filter_postprocess(stream->decoder);
81                         ms_filter_destroy(stream->decoder);
82                         stream->decoder=dec;
83                         if (pt->recv_fmtp!=NULL)
84                                 ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,(void*)pt->recv_fmtp);
85                         ms_filter_link (stream->rtprecv, 0, stream->decoder, 0);
86                         ms_filter_link (stream->decoder,0 , stream->output, 0);
87                         ms_filter_preprocess(stream->decoder,stream->ticker);
88                         
89                 }else{
90                         ms_warning("No decoder found for %s",pt->mime_type);
91                 }
92         }else{
93                 ms_warning("No payload defined with number %i",payload);
94         }
95 }
96
97 static void video_stream_adapt_bitrate(VideoStream *stream, int jitter, float lost){
98         if (stream->encoder!=NULL){
99                 if (lost>10){
100                         int bitrate=0;
101                         int new_bitrate;
102                         ms_warning("Remote reports bad receiving experience, trying to reduce bitrate of video encoder.");
103                         
104                         ms_filter_call_method(stream->encoder,MS_FILTER_GET_BITRATE,&bitrate);
105                         if (bitrate==0){
106                                 ms_error("Video encoder does not implement MS_FILTER_GET_BITRATE.");
107                                 return;
108                         }
109                         if (bitrate>=20000){
110                                 new_bitrate=bitrate-10000;
111                                 ms_warning("Encoder bitrate reduced from %i to %i b/s.",bitrate,new_bitrate);
112                                 ms_filter_call_method(stream->encoder,MS_FILTER_SET_BITRATE,&new_bitrate);
113                         }else{
114                                 ms_warning("Video encoder bitrate already at minimum.");
115                         }
116                         
117                 }
118         }
119 }
120
121 static void video_steam_process_rtcp(VideoStream *stream, mblk_t *m){
122         do{
123                 if (rtcp_is_SR(m)){
124                         const report_block_t *rb;
125                         ms_message("video_steam_process_rtcp: receiving RTCP SR");
126                         rb=rtcp_SR_get_report_block(m,0);
127                         if (rb){
128                                 unsigned int ij;
129                                 float flost;
130                                 ij=report_block_get_interarrival_jitter(rb);
131                                 flost=(float)(100.0*report_block_get_fraction_lost(rb)/256.0);
132                                 ms_message("interarrival jitter=%u , lost packets percentage since last report=%f ",ij,flost);
133                                 if (stream->adapt_bitrate) video_stream_adapt_bitrate(stream,ij,flost);
134                         }
135                 }
136         }while(rtcp_next_packet(m));
137 }
138
139 void video_stream_iterate(VideoStream *stream){
140         
141         if (stream->output!=NULL)
142                 ms_filter_call_method_noarg(stream->output,
143                         MS_VIDEO_OUT_HANDLE_RESIZING);
144         
145         if (stream->evq){
146                 OrtpEvent *ev=ortp_ev_queue_get(stream->evq);
147                 if (ev!=NULL){
148                         if (ortp_event_get_type(ev)==ORTP_EVENT_RTCP_PACKET_RECEIVED){
149                                 OrtpEventData *evd=ortp_event_get_data(ev);
150                                 video_steam_process_rtcp(stream,evd->packet);
151                         }
152                         ortp_event_destroy(ev);
153                 }
154         }
155 }
156
157 static void payload_type_changed(RtpSession *session, unsigned long data){
158         VideoStream *stream=(VideoStream*)data;
159         int pt=rtp_session_get_recv_payload_type(stream->session);
160         video_stream_change_decoder(stream,pt);
161 }
162
163 VideoStream *video_stream_new(int locport, bool_t use_ipv6){
164         VideoStream *stream = (VideoStream *)ms_new0 (VideoStream, 1);
165         stream->session=create_duplex_rtpsession(locport,use_ipv6);
166         stream->evq=ortp_ev_queue_new();
167         stream->rtpsend=ms_filter_new(MS_RTP_SEND_ID);
168         rtp_session_register_event_queue(stream->session,stream->evq);
169         stream->sent_vsize.width=MS_VIDEO_SIZE_CIF_W;
170         stream->sent_vsize.height=MS_VIDEO_SIZE_CIF_H;
171         return stream;
172 }
173
174 void video_stream_set_sent_video_size(VideoStream *stream, MSVideoSize vsize){
175   ms_message("Setting vidoe size %dx%d", vsize.width, vsize.height);
176         stream->sent_vsize=vsize;
177 }
178
179 void video_stream_set_relay_session_id(VideoStream *stream, const char *id){
180         ms_filter_call_method(stream->rtpsend, MS_RTP_SEND_SET_RELAY_SESSION_ID,(void*)id);
181 }
182
183 void video_stream_enable_self_view(VideoStream *stream, bool_t val){
184         MSFilter *out=stream->output;
185         stream->corner=val ? 0 : -1;
186         if (out){
187                 ms_filter_call_method(out,MS_VIDEO_OUT_SET_CORNER,&stream->corner);
188         }
189 }
190
191 void video_stream_enable_adaptive_bitrate_control(VideoStream *s, bool_t yesno){
192         s->adapt_bitrate=yesno;
193 }
194
195 int video_stream_start (VideoStream *stream, RtpProfile *profile, const char *remip, int remport,
196         int rem_rtcp_port, int payload, int jitt_comp, MSWebCam *cam){
197         PayloadType *pt;
198         RtpSession *rtps=stream->session;
199         MSPixFmt format;
200         MSVideoSize vsize,cam_vsize,disp_size;
201         float fps=15;
202         int tmp;
203         JBParameters jbp;
204         const int socket_buf_size=2000000;
205
206         ms_message("%s entry", __FUNCTION__);
207
208         pt=rtp_profile_get_payload(profile,payload);
209         if (pt==NULL){
210                 ms_error("videostream.c: undefined payload type.");
211                 return -1;
212         }
213         stream->encoder=ms_filter_create_encoder(pt->mime_type);
214         stream->decoder=ms_filter_create_decoder(pt->mime_type);
215         if ((stream->encoder==NULL) || (stream->decoder==NULL)){
216                 /* big problem: we have not a registered codec for this payload...*/
217                 ms_error("videostream.c: No codecs available for payload %i:%s.",payload,pt->mime_type);
218                 return -1;
219         }
220         
221         rtp_session_set_profile(rtps,profile);
222         if (remport>0) rtp_session_set_remote_addr_full(rtps,remip,remport,rem_rtcp_port);
223         rtp_session_set_payload_type(rtps,payload);
224         rtp_session_set_jitter_compensation(rtps,jitt_comp);
225
226         rtp_session_signal_connect(stream->session,"payload_type_changed",
227                         (RtpCallback)payload_type_changed,(unsigned long)stream);
228
229         rtp_session_set_recv_buf_size(stream->session,MAX_RTP_SIZE);
230
231         rtp_session_get_jitter_buffer_params(stream->session,&jbp);
232         jbp.max_packets=1000;//needed for high resolution video
233         rtp_session_set_jitter_buffer_params(stream->session,&jbp);
234
235         rtp_session_set_rtp_socket_recv_buffer_size(stream->session,socket_buf_size);
236         rtp_session_set_rtp_socket_send_buffer_size(stream->session,socket_buf_size);
237
238         /* creates two rtp filters to recv send streams (remote part) */
239         if (remport>0) ms_filter_call_method(stream->rtpsend,MS_RTP_SEND_SET_SESSION,stream->session);
240         
241         stream->rtprecv = ms_filter_new (MS_RTP_RECV_ID);
242         ms_filter_call_method(stream->rtprecv,MS_RTP_RECV_SET_SESSION,stream->session);
243
244         /* creates the filters */
245         stream->source = ms_web_cam_create_reader(cam);
246         stream->tee = ms_filter_new(MS_TEE_ID);
247         stream->output=ms_filter_new(MS_VIDEO_OUT_ID);
248         stream->sizeconv=ms_filter_new(MS_SIZE_CONV_ID);
249         
250         if (pt->normal_bitrate>0){
251                 ms_message("Limiting bitrate of video encoder to %i bits/s",pt->normal_bitrate);
252                 ms_filter_call_method(stream->encoder,MS_FILTER_SET_BITRATE,&pt->normal_bitrate);
253         }
254         /* set parameters to the encoder and decoder*/
255         if (pt->send_fmtp){
256                 ms_filter_call_method(stream->encoder,MS_FILTER_ADD_FMTP,pt->send_fmtp);
257                 ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,pt->send_fmtp);
258         }
259         ms_filter_call_method(stream->encoder,MS_FILTER_GET_VIDEO_SIZE,&vsize);
260         vsize=ms_video_size_min(vsize,stream->sent_vsize);
261         ms_filter_call_method(stream->encoder,MS_FILTER_SET_VIDEO_SIZE,&vsize);
262         ms_filter_call_method(stream->encoder,MS_FILTER_GET_FPS,&fps);
263         ms_message("Setting vsize=%ix%i, fps=%f",vsize.width,vsize.height,fps);
264         /* configure the filters */
265         ms_filter_call_method(stream->source,MS_FILTER_SET_FPS,&fps);
266         ms_filter_call_method(stream->source,MS_FILTER_SET_VIDEO_SIZE,&vsize);
267
268         /* get the output format for webcam reader */
269         ms_filter_call_method(stream->source,MS_FILTER_GET_PIX_FMT,&format);
270         if (format==MS_MJPEG){
271                 stream->pixconv=ms_filter_new(MS_MJPEG_DEC_ID);
272         }else{
273                 stream->pixconv = ms_filter_new(MS_PIX_CONV_ID);
274                 /*set it to the pixconv */
275                 ms_filter_call_method(stream->pixconv,MS_FILTER_SET_PIX_FMT,&format);
276
277                 ms_filter_call_method(stream->source,MS_FILTER_GET_VIDEO_SIZE,&cam_vsize);
278         
279                 ms_filter_call_method(stream->pixconv,MS_FILTER_SET_VIDEO_SIZE,&cam_vsize);
280         }
281
282         ms_filter_call_method(stream->sizeconv,MS_FILTER_SET_VIDEO_SIZE,&vsize);
283
284         /*force the decoder to output YUV420P */
285         format=MS_YUV420P;
286         ms_filter_call_method(stream->decoder,MS_FILTER_SET_PIX_FMT,&format);
287
288         disp_size.width=MS_VIDEO_SIZE_CIF_W;
289         disp_size.height=MS_VIDEO_SIZE_CIF_H;
290         tmp=1;
291         ms_filter_call_method(stream->output,MS_FILTER_SET_VIDEO_SIZE,&disp_size);
292         ms_filter_call_method(stream->output,MS_VIDEO_OUT_AUTO_FIT,&tmp);
293         ms_filter_call_method(stream->output,MS_FILTER_SET_PIX_FMT,&format);
294         ms_filter_call_method(stream->output,MS_VIDEO_OUT_SET_CORNER,&stream->corner);
295
296         if (pt->recv_fmtp!=NULL)
297                 ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,(void*)pt->recv_fmtp);
298
299         /* and then connect all */
300         ms_filter_link (stream->source, 0, stream->pixconv, 0);
301         ms_filter_link (stream->pixconv, 0, stream->sizeconv, 0);
302         ms_filter_link (stream->sizeconv, 0, stream->tee, 0);
303         ms_filter_link (stream->tee, 0 ,stream->encoder, 0 );
304         ms_filter_link (stream->encoder,0, stream->rtpsend,0);
305         
306         ms_filter_link (stream->rtprecv, 0, stream->decoder, 0);
307         ms_filter_link (stream->decoder,0 , stream->output, 0);
308         /* the source video must be send for preview */
309         ms_filter_link(stream->tee,1,stream->output,1);
310
311         /* create the ticker */
312         stream->ticker = ms_ticker_new();
313         ms_ticker_set_name(stream->ticker,"Video MSTicker");
314         /* attach it the graph */
315         ms_ticker_attach (stream->ticker, stream->source);
316         return 0;
317 }
318
319 void video_stream_send_vfu(VideoStream *stream){
320         if (stream->encoder)
321                 ms_filter_call_method_noarg(stream->encoder,MS_FILTER_REQ_VFU);
322 }
323
324 void
325 video_stream_stop (VideoStream * stream)
326 {
327         if (stream->ticker){
328                 ms_ticker_detach(stream->ticker,stream->source);
329         
330                 rtp_stats_display(rtp_session_get_stats(stream->session),"Video session's RTP statistics");
331                 
332                 ms_filter_unlink(stream->source,0,stream->pixconv,0);
333                 ms_filter_unlink (stream->pixconv, 0, stream->sizeconv, 0);
334                 ms_filter_unlink (stream->sizeconv, 0, stream->tee, 0);
335                 ms_filter_unlink(stream->tee,0,stream->encoder,0);
336                 ms_filter_unlink(stream->encoder, 0, stream->rtpsend,0);
337                 ms_filter_unlink(stream->rtprecv, 0, stream->decoder, 0);
338                 ms_filter_unlink(stream->decoder,0,stream->output,0);
339                 ms_filter_unlink(stream->tee,1,stream->output,1);
340         }
341         video_stream_free (stream);
342 }
343
344
345 void video_stream_set_rtcp_information(VideoStream *st, const char *cname, const char *tool){
346         if (st->session!=NULL){
347                 rtp_session_set_source_description(st->session,cname,NULL,NULL,NULL,NULL,tool,
348                                                                                         "This is free software (GPL) !");
349         }
350 }
351
352 unsigned long video_stream_get_native_window_id(VideoStream *stream){
353         unsigned long id;
354         if (stream->output){
355                 if (ms_filter_call_method(stream->output,MS_VIDEO_OUT_GET_NATIVE_WINDOW_ID,&id)==0)
356                         return id;
357         }
358         return 0;
359 }
360
361
362 VideoStream * video_preview_start(MSWebCam *device, MSVideoSize disp_size){
363         VideoStream *stream = (VideoStream *)ms_new0 (VideoStream, 1);
364         MSVideoSize vsize=disp_size;
365         MSPixFmt format;
366         float fps=(float)29.97;
367         int mirroring=1;
368
369         /* creates the filters */
370         stream->source = ms_web_cam_create_reader(device);
371         stream->output = ms_filter_new(MS_VIDEO_OUT_ID);
372
373
374         /* configure the filters */
375         ms_filter_call_method(stream->source,MS_FILTER_SET_VIDEO_SIZE,&vsize);
376         ms_filter_call_method(stream->source,MS_FILTER_SET_FPS,&fps);
377         ms_filter_call_method(stream->source,MS_FILTER_GET_PIX_FMT,&format);
378         ms_filter_call_method(stream->source,MS_FILTER_GET_VIDEO_SIZE,&vsize);
379         if (format==MS_MJPEG){
380                 stream->pixconv=ms_filter_new(MS_MJPEG_DEC_ID);
381         }else{
382                 stream->pixconv=ms_filter_new(MS_PIX_CONV_ID);
383                 ms_filter_call_method(stream->pixconv,MS_FILTER_SET_PIX_FMT,&format);
384                 ms_filter_call_method(stream->pixconv,MS_FILTER_SET_VIDEO_SIZE,&vsize);
385         }
386
387         format=MS_YUV420P;
388         ms_filter_call_method(stream->output,MS_FILTER_SET_PIX_FMT,&format);
389         ms_filter_call_method(stream->output,MS_FILTER_SET_VIDEO_SIZE,&disp_size);
390         ms_filter_call_method(stream->output,MS_VIDEO_OUT_ENABLE_MIRRORING,&mirroring);
391         /* and then connect all */
392
393         ms_filter_link(stream->source,0, stream->pixconv,0);
394         ms_filter_link(stream->pixconv, 0, stream->output, 0);
395
396         /* create the ticker */
397         stream->ticker = ms_ticker_new();
398         ms_ticker_set_name(stream->ticker,"Video MSTicker");
399         ms_ticker_attach (stream->ticker, stream->source);
400         return stream;
401 }
402
403 void video_preview_stop(VideoStream *stream){
404         ms_ticker_detach(stream->ticker, stream->source);
405         ms_filter_unlink(stream->source,0,stream->pixconv,0);
406         ms_filter_unlink(stream->pixconv,0,stream->output,0);
407         
408         video_stream_free(stream);
409 }
410
411
412 int video_stream_send_only_start(VideoStream* stream, RtpProfile *profile, const char *remip, int remport,
413         int rem_rtcp_port, int payload, int jitt_comp, MSWebCam *device){
414         PayloadType *pt;
415         MSPixFmt format;
416         MSVideoSize vsize;
417         RtpSession *rtps=stream->session;
418         float fps=15;
419
420         vsize.width=MS_VIDEO_SIZE_CIF_W;
421         vsize.height=MS_VIDEO_SIZE_CIF_H;
422
423         rtp_session_set_profile(rtps,profile);
424         if (remport>0) rtp_session_set_remote_addr_full(rtps,remip,remport,rem_rtcp_port);
425         rtp_session_set_payload_type(rtps,payload);
426         rtp_session_set_jitter_compensation(rtps,jitt_comp);
427         
428         /* creates rtp filter to send streams (remote part) */
429         rtp_session_set_recv_buf_size(rtps,MAX_RTP_SIZE);
430         stream->rtpsend =ms_filter_new(MS_RTP_SEND_ID);
431         if (remport>0) ms_filter_call_method(stream->rtpsend,MS_RTP_SEND_SET_SESSION,stream->session);
432
433         /* creates the filters */
434         pt=rtp_profile_get_payload(profile,payload);
435         if (pt==NULL){
436                 video_stream_free(stream);
437                 ms_error("videostream.c: undefined payload type.");
438                 return -1;
439         }
440         stream->encoder=ms_filter_create_encoder(pt->mime_type);
441         if ((stream->encoder==NULL)){
442                 /* big problem: we have not a registered codec for this payload...*/
443                 video_stream_free(stream);
444                 ms_error("videostream.c: No codecs available for payload %i.",payload);
445                 return -1;
446         }
447
448         /* creates the filters */
449         stream->source = ms_web_cam_create_reader(device);
450         stream->sizeconv=ms_filter_new(MS_SIZE_CONV_ID);
451
452         /* configure the filters */
453         if (pt->send_fmtp)
454                 ms_filter_call_method(stream->encoder,MS_FILTER_ADD_FMTP,pt->send_fmtp);
455
456         if (pt->normal_bitrate>0){
457                 ms_message("Limiting bitrate of video encoder to %i bits/s",pt->normal_bitrate);
458                 ms_filter_call_method(stream->encoder,MS_FILTER_SET_BITRATE,&pt->normal_bitrate);
459         }
460
461         ms_filter_call_method(stream->encoder,MS_FILTER_GET_FPS,&fps);
462         ms_filter_call_method(stream->encoder,MS_FILTER_GET_VIDEO_SIZE,&vsize);
463         vsize=ms_video_size_min(vsize,stream->sent_vsize);
464         ms_filter_call_method(stream->encoder,MS_FILTER_SET_VIDEO_SIZE,&vsize);
465
466         ms_filter_call_method(stream->source,MS_FILTER_SET_FPS,&fps);
467         ms_filter_call_method(stream->source,MS_FILTER_SET_VIDEO_SIZE,&vsize);
468         
469         /* get the output format for webcam reader */
470         ms_filter_call_method(stream->source,MS_FILTER_GET_PIX_FMT,&format);
471         /*set it to the pixconv */
472
473         /* bug fix from AMD: What about MJPEG mode???*/
474         if (format==MS_MJPEG){
475                 stream->pixconv=ms_filter_new(MS_MJPEG_DEC_ID);
476         }else{
477                 stream->pixconv=ms_filter_new(MS_PIX_CONV_ID);
478                 ms_filter_call_method(stream->pixconv,MS_FILTER_SET_PIX_FMT,&format);
479
480                 ms_filter_call_method(stream->source,MS_FILTER_GET_VIDEO_SIZE,&vsize);
481                 ms_filter_call_method(stream->pixconv,MS_FILTER_SET_VIDEO_SIZE,&vsize);
482         }
483
484         ms_filter_call_method(stream->encoder,MS_FILTER_GET_VIDEO_SIZE,&vsize);
485         ms_filter_call_method(stream->sizeconv,MS_FILTER_SET_VIDEO_SIZE,&vsize);
486         
487         ms_message("vsize=%ix%i, fps=%f, send format: %s, capture format: %d, bitrate: %d",
488                         vsize.width,vsize.height,fps,pt->send_fmtp,format, pt->normal_bitrate);
489
490         /* and then connect all */
491         ms_filter_link (stream->source, 0, stream->pixconv, 0);
492         ms_filter_link (stream->pixconv, 0, stream->sizeconv, 0);
493         ms_filter_link (stream->sizeconv, 0, stream->encoder, 0);
494         ms_filter_link (stream->encoder,0, stream->rtpsend,0);
495
496         /* create the ticker */
497         stream->ticker = ms_ticker_new(); 
498         /* attach it the graph */
499         ms_ticker_attach (stream->ticker, stream->source);
500         return 0;
501 }
502
503 void video_stream_send_only_stop(VideoStream *stream){
504         if (stream->ticker){
505                 ms_ticker_detach (stream->ticker, stream->source);
506                 ms_filter_unlink(stream->source,0,stream->pixconv,0);
507                 ms_filter_unlink (stream->pixconv, 0, stream->sizeconv, 0);
508                 ms_filter_unlink (stream->sizeconv, 0, stream->encoder, 0);
509                 ms_filter_unlink(stream->encoder,0,stream->rtpsend,0);
510         }
511         video_stream_free(stream);
512 }
513
514 int video_stream_recv_only_start (VideoStream *stream, RtpProfile *profile, const char *remip, int remport,int payload, int jitt_comp){
515         PayloadType *pt;
516         MSPixFmt format;
517         MSVideoSize vsize;
518         RtpSession *rtps=stream->session;
519         
520         vsize.width=MS_VIDEO_SIZE_CIF_W;
521         vsize.height=MS_VIDEO_SIZE_CIF_H;
522
523         rtp_session_set_profile(rtps,profile);
524         if (remport>0) rtp_session_set_remote_addr(rtps,remip,remport);
525         rtp_session_set_payload_type(rtps,payload);
526         rtp_session_set_jitter_compensation(rtps,jitt_comp);
527         
528         /* creates rtp filters to recv streams */
529         rtp_session_set_recv_buf_size(rtps,MAX_RTP_SIZE);
530         stream->rtprecv = ms_filter_new (MS_RTP_RECV_ID);
531         ms_filter_call_method(stream->rtprecv,MS_RTP_RECV_SET_SESSION,rtps);
532
533         /* creates the filters */
534         pt=rtp_profile_get_payload(profile,payload);
535         if (pt==NULL){
536                 ms_error("videostream.c: undefined payload type.");
537                 return -1;
538         }
539         stream->decoder=ms_filter_create_decoder(pt->mime_type);
540         if (stream->decoder==NULL){
541                 /* big problem: we have not a registered codec for this payload...*/
542                 ms_error("videostream.c: No codecs available for payload %i:%s.",payload,pt->mime_type);
543                 return -1;
544         }
545         stream->output=ms_filter_new(MS_VIDEO_OUT_ID);
546
547         /*force the decoder to output YUV420P */
548         format=MS_YUV420P;
549         /*ask the size-converter to always output CIF */
550         vsize.width=MS_VIDEO_SIZE_CIF_W;
551         vsize.height=MS_VIDEO_SIZE_CIF_H;
552         ms_message("Setting output vsize=%ix%i",vsize.width,vsize.height);
553         
554         ms_filter_call_method(stream->decoder,MS_FILTER_SET_PIX_FMT,&format);
555         ms_filter_call_method(stream->output,MS_FILTER_SET_PIX_FMT,&format);
556         ms_filter_call_method(stream->output,MS_FILTER_SET_VIDEO_SIZE,&vsize);
557
558         if (pt->recv_fmtp!=NULL) {
559                 ms_message("pt->recv_fmtp: %s", pt->recv_fmtp);
560                 ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,(void*)pt->recv_fmtp);
561         }
562
563         /* and then connect all */
564         ms_filter_link (stream->rtprecv, 0, stream->decoder, 0);
565         ms_filter_link (stream->decoder,0 , stream->output, 0);
566
567         /* create the ticker */
568         stream->ticker = ms_ticker_new(); 
569         /* attach it the graph */
570         ms_ticker_attach (stream->ticker, stream->rtprecv);
571         return 0;
572 }
573
574 void video_stream_recv_only_stop (VideoStream * stream){
575         if (stream->ticker!=NULL){
576                 ms_ticker_detach(stream->ticker, stream->rtprecv);
577                 rtp_stats_display(rtp_session_get_stats(stream->session),"Video session's RTP statistics");
578                 ms_filter_unlink(stream->rtprecv, 0, stream->decoder, 0);
579                 ms_filter_unlink(stream->decoder,0,stream->output,0);
580         }
581         video_stream_free (stream);
582 }
583