videostream.c 19.3 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
/*
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.
*/

#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/msfilter.h"
#include "mediastreamer2/msvideo.h"
#include "mediastreamer2/msrtp.h"
#include "mediastreamer2/msvideoout.h"
25
#include "mediastreamer2/msextdisplay.h"
aymeric's avatar
aymeric committed
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49

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

extern RtpSession * create_duplex_rtpsession( int locport, bool_t ipv6);

#define MAX_RTP_SIZE	UDP_MAX_SIZE

/* this code is not part of the library itself, it is part of the mediastream program */
void video_stream_free (VideoStream * stream)
{
	if (stream->session!=NULL){
		rtp_session_unregister_event_queue(stream->session,stream->evq);
		rtp_session_destroy(stream->session);
	}
	if (stream->rtprecv != NULL)
		ms_filter_destroy (stream->rtprecv);
	if (stream->rtpsend!=NULL) 
		ms_filter_destroy (stream->rtpsend);
	if (stream->source != NULL)
		ms_filter_destroy (stream->source);
	if (stream->output != NULL)
		ms_filter_destroy (stream->output);
50 51
	if (stream->encoder != NULL)
		ms_filter_destroy (stream->encoder);
aymeric's avatar
aymeric committed
52 53
	if (stream->decoder != NULL)
		ms_filter_destroy (stream->decoder);
54 55
	if (stream->sizeconv != NULL)
		ms_filter_destroy (stream->sizeconv);
aymeric's avatar
aymeric committed
56 57 58 59
	if (stream->pixconv!=NULL)
		ms_filter_destroy(stream->pixconv);
	if (stream->tee!=NULL)
		ms_filter_destroy(stream->tee);
60 61 62 63
	if (stream->tee2!=NULL)
		ms_filter_destroy(stream->tee2);
	if (stream->jpegwriter!=NULL)
		ms_filter_destroy(stream->jpegwriter);
aymeric's avatar
aymeric committed
64 65 66 67
	if (stream->ticker != NULL)
		ms_ticker_destroy (stream->ticker);
	if (stream->evq!=NULL)
		ortp_ev_queue_destroy(stream->evq);
68 69 70
	if (stream->display_name!=NULL)
		ms_free(stream->display_name);
	
aymeric's avatar
aymeric committed
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
	ms_free (stream);
}

/*this function must be called from the MSTicker thread:
it replaces one filter by another one.
This is a dirty hack that works anyway.
It would be interesting to have something that does the job
simplier within the MSTicker api
*/
void video_stream_change_decoder(VideoStream *stream, int payload){
	RtpSession *session=stream->session;
	RtpProfile *prof=rtp_session_get_profile(session);
	PayloadType *pt=rtp_profile_get_payload(prof,payload);
	if (pt!=NULL){
		MSFilter *dec=ms_filter_create_decoder(pt->mime_type);
		if (dec!=NULL){
			ms_filter_unlink(stream->rtprecv, 0, stream->decoder, 0);
			ms_filter_unlink(stream->decoder,0,stream->output,0);
			ms_filter_postprocess(stream->decoder);
			ms_filter_destroy(stream->decoder);
			stream->decoder=dec;
			if (pt->recv_fmtp!=NULL)
				ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,(void*)pt->recv_fmtp);
			ms_filter_link (stream->rtprecv, 0, stream->decoder, 0);
			ms_filter_link (stream->decoder,0 , stream->output, 0);
			ms_filter_preprocess(stream->decoder,stream->ticker);
			
		}else{
			ms_warning("No decoder found for %s",pt->mime_type);
		}
	}else{
		ms_warning("No payload defined with number %i",payload);
	}
}

static void video_stream_adapt_bitrate(VideoStream *stream, int jitter, float lost){
	if (stream->encoder!=NULL){
		if (lost>10){
			int bitrate=0;
			int new_bitrate;
			ms_warning("Remote reports bad receiving experience, trying to reduce bitrate of video encoder.");
			
			ms_filter_call_method(stream->encoder,MS_FILTER_GET_BITRATE,&bitrate);
			if (bitrate==0){
				ms_error("Video encoder does not implement MS_FILTER_GET_BITRATE.");
				return;
			}
			if (bitrate>=20000){
				new_bitrate=bitrate-10000;
				ms_warning("Encoder bitrate reduced from %i to %i b/s.",bitrate,new_bitrate);
				ms_filter_call_method(stream->encoder,MS_FILTER_SET_BITRATE,&new_bitrate);
			}else{
				ms_warning("Video encoder bitrate already at minimum.");
			}
			
		}
	}
}

static void video_steam_process_rtcp(VideoStream *stream, mblk_t *m){
	do{
		if (rtcp_is_SR(m)){
			const report_block_t *rb;
			ms_message("video_steam_process_rtcp: receiving RTCP SR");
			rb=rtcp_SR_get_report_block(m,0);
			if (rb){
				unsigned int ij;
				float flost;
				ij=report_block_get_interarrival_jitter(rb);
aymeric's avatar
aymeric committed
140
				flost=(float)(100.0*report_block_get_fraction_lost(rb)/256.0);
aymeric's avatar
aymeric committed
141 142 143 144 145 146 147 148
				ms_message("interarrival jitter=%u , lost packets percentage since last report=%f ",ij,flost);
				if (stream->adapt_bitrate) video_stream_adapt_bitrate(stream,ij,flost);
			}
		}
	}while(rtcp_next_packet(m));
}

void video_stream_iterate(VideoStream *stream){
149
	/*
aymeric's avatar
aymeric committed
150 151 152
	if (stream->output!=NULL)
		ms_filter_call_method_noarg(stream->output,
			MS_VIDEO_OUT_HANDLE_RESIZING);
153
	*/
aymeric's avatar
aymeric committed
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
	if (stream->evq){
		OrtpEvent *ev=ortp_ev_queue_get(stream->evq);
		if (ev!=NULL){
			if (ortp_event_get_type(ev)==ORTP_EVENT_RTCP_PACKET_RECEIVED){
				OrtpEventData *evd=ortp_event_get_data(ev);
				video_steam_process_rtcp(stream,evd->packet);
			}
			ortp_event_destroy(ev);
		}
	}
}

static void payload_type_changed(RtpSession *session, unsigned long data){
	VideoStream *stream=(VideoStream*)data;
	int pt=rtp_session_get_recv_payload_type(stream->session);
	video_stream_change_decoder(stream,pt);
}

172 173 174 175 176 177 178 179
static void choose_display_name(VideoStream *stream){
#ifdef WIN32
	stream->display_name=ms_strdup("MSDrawDibDisplay");
#else
	stream->display_name=ms_strdup("MSVideoOut");
#endif
}

aymeric's avatar
aymeric committed
180 181 182 183 184 185
VideoStream *video_stream_new(int locport, bool_t use_ipv6){
	VideoStream *stream = (VideoStream *)ms_new0 (VideoStream, 1);
	stream->session=create_duplex_rtpsession(locport,use_ipv6);
	stream->evq=ortp_ev_queue_new();
	stream->rtpsend=ms_filter_new(MS_RTP_SEND_ID);
	rtp_session_register_event_queue(stream->session,stream->evq);
smorlat's avatar
smorlat committed
186 187
	stream->sent_vsize.width=MS_VIDEO_SIZE_CIF_W;
	stream->sent_vsize.height=MS_VIDEO_SIZE_CIF_H;
188
	stream->dir=VideoStreamSendRecv;
189 190
	choose_display_name(stream);

aymeric's avatar
aymeric committed
191 192 193
	return stream;
}

smorlat's avatar
smorlat committed
194
void video_stream_set_sent_video_size(VideoStream *stream, MSVideoSize vsize){
195
	ms_message("Setting video size %dx%d", vsize.width, vsize.height);
smorlat's avatar
smorlat committed
196 197 198
	stream->sent_vsize=vsize;
}

aymeric's avatar
aymeric committed
199 200 201 202
void video_stream_set_relay_session_id(VideoStream *stream, const char *id){
	ms_filter_call_method(stream->rtpsend, MS_RTP_SEND_SET_RELAY_SESSION_ID,(void*)id);
}

smorlat's avatar
smorlat committed
203 204 205 206
void video_stream_enable_self_view(VideoStream *stream, bool_t val){
	MSFilter *out=stream->output;
	stream->corner=val ? 0 : -1;
	if (out){
207
		ms_filter_call_method(out,MS_VIDEO_DISPLAY_SET_LOCAL_VIEW_MODE,&stream->corner);
smorlat's avatar
smorlat committed
208 209
	}
}
aymeric's avatar
aymeric committed
210 211 212 213 214

void video_stream_enable_adaptive_bitrate_control(VideoStream *s, bool_t yesno){
	s->adapt_bitrate=yesno;
}

215 216 217 218 219
void video_stream_set_render_callback (VideoStream *s, VideoStreamRenderCallback cb, void *user_pointer){
	s->rendercb=cb;
	s->render_pointer=user_pointer;
}

220 221 222 223 224 225 226 227 228
void video_stream_set_display_filter_name(VideoStream *s, const char *fname){
	if (s->display_name!=NULL){
		ms_free(s->display_name);
		s->display_name=NULL;
	}
	if (fname!=NULL)
		s->display_name=ms_strdup(fname);
}

229 230 231 232 233 234 235 236 237 238
static void ext_display_cb(void *ud, unsigned int event, void *eventdata){
	MSExtDisplayOutput *output=(MSExtDisplayOutput*)eventdata;
	VideoStream *st=(VideoStream*)ud;
	if (st->rendercb!=NULL){
		st->rendercb(st->render_pointer,
		            output->local_view.w!=0 ? &output->local_view : NULL,
		            output->remote_view.w!=0 ? &output->remote_view : NULL);
	}
}

239 240 241 242
void video_stream_set_direction(VideoStream *vs, VideoStreamDir dir){
	vs->dir=dir;
}

243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
static void configure_video_source(VideoStream *stream){
	MSVideoSize vsize,cam_vsize;
	float fps=15;
	MSPixFmt format;
	
	ms_filter_call_method(stream->encoder,MS_FILTER_GET_VIDEO_SIZE,&vsize);
	vsize=ms_video_size_min(vsize,stream->sent_vsize);
	ms_filter_call_method(stream->encoder,MS_FILTER_SET_VIDEO_SIZE,&vsize);
	ms_filter_call_method(stream->encoder,MS_FILTER_GET_FPS,&fps);
	ms_message("Setting sent vsize=%ix%i, fps=%f",vsize.width,vsize.height,fps);
	/* configure the filters */
	if (ms_filter_get_id(stream->source)!=MS_STATIC_IMAGE_ID) {
		ms_filter_call_method(stream->source,MS_FILTER_SET_FPS,&fps);
	}
	ms_filter_call_method(stream->source,MS_FILTER_SET_VIDEO_SIZE,&vsize);
	/* get the output format for webcam reader */
	ms_filter_call_method(stream->source,MS_FILTER_GET_PIX_FMT,&format);
	if (format==MS_MJPEG){
		stream->pixconv=ms_filter_new(MS_MJPEG_DEC_ID);
	}else{
		stream->pixconv = ms_filter_new(MS_PIX_CONV_ID);
		/*set it to the pixconv */
		ms_filter_call_method(stream->pixconv,MS_FILTER_SET_PIX_FMT,&format);
		ms_filter_call_method(stream->source,MS_FILTER_GET_VIDEO_SIZE,&cam_vsize);
		ms_filter_call_method(stream->pixconv,MS_FILTER_SET_VIDEO_SIZE,&cam_vsize);
	}
	stream->sizeconv=ms_filter_new(MS_SIZE_CONV_ID);
	ms_filter_call_method(stream->sizeconv,MS_FILTER_SET_VIDEO_SIZE,&vsize);
}

aymeric's avatar
aymeric committed
273
int video_stream_start (VideoStream *stream, RtpProfile *profile, const char *remip, int remport,
smorlat's avatar
smorlat committed
274
	int rem_rtcp_port, int payload, int jitt_comp, MSWebCam *cam){
aymeric's avatar
aymeric committed
275 276 277
	PayloadType *pt;
	RtpSession *rtps=stream->session;
	MSPixFmt format;
278
	MSVideoSize disp_size;
smorlat's avatar
smorlat committed
279 280 281
	int tmp;
	JBParameters jbp;
	const int socket_buf_size=2000000;
aymeric's avatar
aymeric committed
282

283 284 285 286 287
	if (cam==NULL){
		cam=ms_web_cam_manager_get_default_cam (
		      ms_web_cam_manager_get());                                
	}

aymeric's avatar
aymeric committed
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
	pt=rtp_profile_get_payload(profile,payload);
	if (pt==NULL){
		ms_error("videostream.c: undefined payload type.");
		return -1;
	}
	
	rtp_session_set_profile(rtps,profile);
	if (remport>0) rtp_session_set_remote_addr_full(rtps,remip,remport,rem_rtcp_port);
	rtp_session_set_payload_type(rtps,payload);
	rtp_session_set_jitter_compensation(rtps,jitt_comp);

	rtp_session_signal_connect(stream->session,"payload_type_changed",
			(RtpCallback)payload_type_changed,(unsigned long)stream);

	rtp_session_set_recv_buf_size(stream->session,MAX_RTP_SIZE);

smorlat's avatar
smorlat committed
304 305 306 307 308
	rtp_session_get_jitter_buffer_params(stream->session,&jbp);
	jbp.max_packets=1000;//needed for high resolution video
	rtp_session_set_jitter_buffer_params(stream->session,&jbp);
	rtp_session_set_rtp_socket_recv_buffer_size(stream->session,socket_buf_size);
	rtp_session_set_rtp_socket_send_buffer_size(stream->session,socket_buf_size);
aymeric's avatar
aymeric committed
309
	
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
	if (stream->dir==VideoStreamSendRecv || stream->dir==VideoStreamSendOnly){
		/*plumb the outgoing stream */

		if (remport>0) ms_filter_call_method(stream->rtpsend,MS_RTP_SEND_SET_SESSION,stream->session);
		stream->encoder=ms_filter_create_encoder(pt->mime_type);
		if ((stream->encoder==NULL) ){
			/* big problem: we don't have a registered codec for this payload...*/
			ms_error("videostream.c: No encoder available for payload %i:%s.",payload,pt->mime_type);
			return -1;
		}
		/* creates the filters */
		stream->source = ms_web_cam_create_reader(cam);
		stream->tee = ms_filter_new(MS_TEE_ID);
		
		if (pt->normal_bitrate>0){
			ms_message("Limiting bitrate of video encoder to %i bits/s",pt->normal_bitrate);
			ms_filter_call_method(stream->encoder,MS_FILTER_SET_BITRATE,&pt->normal_bitrate);
		}
		if (pt->send_fmtp){
			ms_filter_call_method(stream->encoder,MS_FILTER_ADD_FMTP,pt->send_fmtp);
		}
331
		configure_video_source (stream);
332 333 334 335 336 337
			/* and then connect all */
		ms_filter_link (stream->source, 0, stream->pixconv, 0);
		ms_filter_link (stream->pixconv, 0, stream->sizeconv, 0);
		ms_filter_link (stream->sizeconv, 0, stream->tee, 0);
		ms_filter_link (stream->tee, 0 ,stream->encoder, 0 );
		ms_filter_link (stream->encoder,0, stream->rtpsend,0);
aymeric's avatar
aymeric committed
338
	}
339
	if (stream->dir==VideoStreamSendRecv || stream->dir==VideoStreamRecvOnly){
340
		MSConnectionHelper ch;
341 342 343 344 345 346 347 348 349
		/*plumb the incoming stream */
		stream->decoder=ms_filter_create_decoder(pt->mime_type);
		if ((stream->decoder==NULL) ){
			/* big problem: we don't have a registered decoderfor this payload...*/
			ms_error("videostream.c: No decoder available for payload %i:%s.",payload,pt->mime_type);
			return -1;
		}
		stream->rtprecv = ms_filter_new (MS_RTP_RECV_ID);
		ms_filter_call_method(stream->rtprecv,MS_RTP_RECV_SET_SESSION,stream->session);
350

351 352 353
		stream->tee2=ms_filter_new(MS_TEE_ID);
		stream->jpegwriter=ms_filter_new(MS_JPEG_WRITER_ID);

354 355 356 357 358 359 360 361 362 363 364 365
		if (stream->rendercb!=NULL){
			stream->output=ms_filter_new(MS_EXT_DISPLAY_ID);
			ms_filter_set_notify_callback (stream->output,ext_display_cb,stream);
		}else{
			stream->output=ms_filter_new_from_name (stream->display_name);
		}
		/* set parameters to the decoder*/
		if (pt->send_fmtp){
			ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,pt->send_fmtp);
		}
		if (pt->recv_fmtp!=NULL)
			ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,(void*)pt->recv_fmtp);
366
	
367 368 369 370 371 372 373 374 375 376 377 378 379 380
		/*force the decoder to output YUV420P */
		format=MS_YUV420P;
		ms_filter_call_method(stream->decoder,MS_FILTER_SET_PIX_FMT,&format);

		/*configure the display window */
		disp_size.width=MS_VIDEO_SIZE_CIF_W;
		disp_size.height=MS_VIDEO_SIZE_CIF_H;
		tmp=1;
		ms_filter_call_method(stream->output,MS_FILTER_SET_VIDEO_SIZE,&disp_size);
		ms_filter_call_method(stream->output,MS_VIDEO_DISPLAY_ENABLE_AUTOFIT,&tmp);
		ms_filter_call_method(stream->output,MS_FILTER_SET_PIX_FMT,&format);
		ms_filter_call_method(stream->output,MS_VIDEO_DISPLAY_SET_LOCAL_VIEW_MODE,&stream->corner);

		/* and connect the filters */
381 382 383 384 385 386 387 388
		ms_connection_helper_start (&ch);
		ms_connection_helper_link (&ch,stream->rtprecv,-1,0);
		ms_connection_helper_link (&ch,stream->decoder,0,0);
		if (stream->tee2){
			ms_connection_helper_link (&ch,stream->tee2,0,0);
			ms_filter_link(stream->tee2,1,stream->jpegwriter,0);
		}
		ms_connection_helper_link (&ch,stream->output,0,-1);
389 390 391
		/* the video source must be send for preview , if it exists*/
		if (stream->tee!=NULL)
			ms_filter_link(stream->tee,1,stream->output,1);
aymeric's avatar
aymeric committed
392
	}
393

aymeric's avatar
aymeric committed
394
	/* create the ticker */
smorlat's avatar
smorlat committed
395 396
	stream->ticker = ms_ticker_new();
	ms_ticker_set_name(stream->ticker,"Video MSTicker");
397 398 399 400 401
	/* attach the graphs */
	if (stream->source)
		ms_ticker_attach (stream->ticker, stream->source);
	if (stream->rtprecv)
		ms_ticker_attach (stream->ticker, stream->rtprecv);
aymeric's avatar
aymeric committed
402 403 404
	return 0;
}

405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
void video_stream_change_camera(VideoStream *stream, MSWebCam *cam){
	if (stream->ticker && stream->source){
		ms_ticker_detach(stream->ticker,stream->source);
		/*unlink source filters and subsequent post processin filters */
		ms_filter_unlink (stream->source, 0, stream->pixconv, 0);
		ms_filter_unlink (stream->pixconv, 0, stream->sizeconv, 0);
		ms_filter_unlink (stream->sizeconv, 0, stream->tee, 0);
		/*destroy the filters */
		ms_filter_destroy(stream->source);
		ms_filter_destroy(stream->pixconv);
		ms_filter_destroy(stream->sizeconv);

		/*re create new ones and configure them*/
		stream->source = ms_web_cam_create_reader(cam);
		configure_video_source(stream);
420 421 422
		ms_filter_link (stream->source, 0, stream->pixconv, 0);
		ms_filter_link (stream->pixconv, 0, stream->sizeconv, 0);
		ms_filter_link (stream->sizeconv, 0, stream->tee, 0);
423 424 425 426 427
		
		ms_ticker_attach(stream->ticker,stream->source);
	}
}

aymeric's avatar
aymeric committed
428 429 430 431 432 433 434 435 436
void video_stream_send_vfu(VideoStream *stream){
	if (stream->encoder)
		ms_filter_call_method_noarg(stream->encoder,MS_FILTER_REQ_VFU);
}

void
video_stream_stop (VideoStream * stream)
{
	if (stream->ticker){
437 438 439 440
		if (stream->source)
			ms_ticker_detach(stream->ticker,stream->source);
		if (stream->rtprecv)
			ms_ticker_detach(stream->ticker,stream->rtprecv);
aymeric's avatar
aymeric committed
441 442
	
		rtp_stats_display(rtp_session_get_stats(stream->session),"Video session's RTP statistics");
443 444 445 446 447 448 449 450 451

		if (stream->source){
			ms_filter_unlink(stream->source,0,stream->pixconv,0);
			ms_filter_unlink (stream->pixconv, 0, stream->sizeconv, 0);
			ms_filter_unlink (stream->sizeconv, 0, stream->tee, 0);
			ms_filter_unlink(stream->tee,0,stream->encoder,0);
			ms_filter_unlink(stream->encoder, 0, stream->rtpsend,0);
		}
		if (stream->rtprecv){
452 453 454 455 456 457 458 459 460
			MSConnectionHelper h;
			ms_connection_helper_start (&h);
			ms_connection_helper_unlink (&h,stream->rtprecv,-1,0);
			ms_connection_helper_unlink (&h,stream->decoder,0,0);
			if (stream->tee2){
				ms_connection_helper_unlink (&h,stream->tee2,0,0);
				ms_filter_unlink(stream->tee2,1,stream->jpegwriter,0);
			}
			ms_connection_helper_unlink (&h,stream->output,0,-1);
461 462 463
			if (stream->tee)
				ms_filter_unlink(stream->tee,1,stream->output,1);
		}
aymeric's avatar
aymeric committed
464 465 466 467 468 469 470 471 472 473 474 475
	}
	video_stream_free (stream);
}


void video_stream_set_rtcp_information(VideoStream *st, const char *cname, const char *tool){
	if (st->session!=NULL){
		rtp_session_set_source_description(st->session,cname,NULL,NULL,NULL,NULL,tool,
											"This is free software (GPL) !");
	}
}

476 477 478
unsigned long video_stream_get_native_window_id(VideoStream *stream){
	unsigned long id;
	if (stream->output){
unknown's avatar
unknown committed
479
		if (ms_filter_call_method(stream->output,MS_VIDEO_DISPLAY_GET_NATIVE_WINDOW_ID,&id)==0)
480 481 482 483
			return id;
	}
	return 0;
}
aymeric's avatar
aymeric committed
484 485


smorlat's avatar
smorlat committed
486
VideoStream * video_preview_start(MSWebCam *device, MSVideoSize disp_size){
aymeric's avatar
aymeric committed
487
	VideoStream *stream = (VideoStream *)ms_new0 (VideoStream, 1);
smorlat's avatar
smorlat committed
488
	MSVideoSize vsize=disp_size;
aymeric's avatar
aymeric committed
489
	MSPixFmt format;
aymeric's avatar
aymeric committed
490
	float fps=(float)29.97;
smorlat's avatar
smorlat committed
491
	int mirroring=1;
Simon Morlat's avatar
Simon Morlat committed
492
	int corner=-1;
aymeric's avatar
aymeric committed
493 494

	/* creates the filters */
495
	choose_display_name(stream);
aymeric's avatar
aymeric committed
496
	stream->source = ms_web_cam_create_reader(device);
497

498
	stream->output=ms_filter_new_from_name (stream->display_name);
499

aymeric's avatar
aymeric committed
500
	/* configure the filters */
smorlat's avatar
smorlat committed
501
	ms_filter_call_method(stream->source,MS_FILTER_SET_VIDEO_SIZE,&vsize);
502 503
	if (ms_filter_get_id(stream->source)!=MS_STATIC_IMAGE_ID)
		ms_filter_call_method(stream->source,MS_FILTER_SET_FPS,&fps);
smorlat's avatar
smorlat committed
504
	ms_filter_call_method(stream->source,MS_FILTER_GET_PIX_FMT,&format);
505
	ms_filter_call_method(stream->source,MS_FILTER_GET_VIDEO_SIZE,&vsize);
aymeric's avatar
aymeric committed
506 507 508 509 510 511 512
	if (format==MS_MJPEG){
		stream->pixconv=ms_filter_new(MS_MJPEG_DEC_ID);
	}else{
		stream->pixconv=ms_filter_new(MS_PIX_CONV_ID);
		ms_filter_call_method(stream->pixconv,MS_FILTER_SET_PIX_FMT,&format);
		ms_filter_call_method(stream->pixconv,MS_FILTER_SET_VIDEO_SIZE,&vsize);
	}
513

aymeric's avatar
aymeric committed
514 515
	format=MS_YUV420P;
	ms_filter_call_method(stream->output,MS_FILTER_SET_PIX_FMT,&format);
smorlat's avatar
smorlat committed
516
	ms_filter_call_method(stream->output,MS_FILTER_SET_VIDEO_SIZE,&disp_size);
Simon Morlat's avatar
Simon Morlat committed
517
	ms_filter_call_method(stream->output,MS_VIDEO_DISPLAY_ENABLE_MIRRORING,&mirroring);
518
	ms_filter_call_method(stream->output,MS_VIDEO_DISPLAY_SET_LOCAL_VIEW_MODE,&corner);
aymeric's avatar
aymeric committed
519
	/* and then connect all */
520

aymeric's avatar
aymeric committed
521
	ms_filter_link(stream->source,0, stream->pixconv,0);
522 523
	ms_filter_link(stream->pixconv, 0, stream->output, 0);

aymeric's avatar
aymeric committed
524
	/* create the ticker */
smorlat's avatar
smorlat committed
525 526
	stream->ticker = ms_ticker_new();
	ms_ticker_set_name(stream->ticker,"Video MSTicker");
aymeric's avatar
aymeric committed
527 528 529 530 531 532 533 534 535 536 537 538
	ms_ticker_attach (stream->ticker, stream->source);
	return stream;
}

void video_preview_stop(VideoStream *stream){
	ms_ticker_detach(stream->ticker, stream->source);
	ms_filter_unlink(stream->source,0,stream->pixconv,0);
	ms_filter_unlink(stream->pixconv,0,stream->output,0);
	
	video_stream_free(stream);
}

539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
int video_stream_recv_only_start(VideoStream *videostream, RtpProfile *profile, const char *addr, int port, int used_pt, int jitt_comp){
	video_stream_set_direction(videostream,VideoStreamRecvOnly);
	return video_stream_start(videostream,profile,addr,port,port+1,used_pt,jitt_comp,NULL);
}

int video_stream_send_only_start(VideoStream *videostream,
				RtpProfile *profile, const char *addr, int port, int rtcp_port, 
				int used_pt, int  jitt_comp, MSWebCam *device){
	video_stream_set_direction (videostream,VideoStreamSendOnly);
	return video_stream_start(videostream,profile,addr,port,rtcp_port,used_pt,jitt_comp,device);
}


void video_stream_recv_only_stop(VideoStream *vs){
	video_stream_stop(vs);
}

void video_stream_send_only_stop(VideoStream *vs){
	video_stream_stop(vs);
}