// 构造 source --> decoder --> sink static MSFilter *build_simple_chain(ZonekeyYUVSinkCallbackParam *yuvcb) { MSFilter *f_source = ms_filter_new_from_name("ZonekeyH264Source"); MSFilter *f_decoder = ms_filter_new(MS_H264_DEC_ID); MSFilter *f_sink = ms_filter_new_from_name("ZonekeyYUVSink"); ms_filter_call_method(f_sink, ZONEKEY_METHOD_YUV_SINK_SET_CALLBACK_PARAM, yuvcb); ms_filter_link(f_source, 0, f_decoder, 0); ms_filter_link(f_decoder, 0, f_sink, 0); return f_source; }
// 构造发送 source --> rtp session static MSFilter *build_sender_chain(const char *ip, int port) { MSFilter *f_source = ms_filter_new_from_name("ZonekeyH264Source"); MSFilter *f_rtp = ms_filter_new(MS_RTP_SEND_ID); fprintf(stdout, "sendto %s:%d\n", ip, port); RtpSession *rtp = rtp_session_new(RTP_SESSION_SENDONLY); rtp_session_set_rtp_socket_send_buffer_size(rtp, 3*1024*1024); rtp_session_set_remote_addr_and_port(rtp, ip, port, port+1); rtp_session_set_payload_type(rtp, 100); //rtp_session_enable_jitter_buffer(rtp, 0); // 禁用的 JBParameters jb; jb.adaptive = 1; jb.max_packets = -1; jb.max_size = -1; jb.min_size = jb.nom_size = 300; rtp_session_set_jitter_buffer_params(rtp, &jb); ms_filter_call_method(f_rtp, MS_RTP_SEND_SET_SESSION, rtp); ms_filter_link(f_source, 0, f_rtp, 0); return f_source; }
static void _create_sinks(MSMediaPlayer *obj) { int sink_sample_rate, sample_rate, nchannels; if(obj->audio_pin_fmt.fmt && obj->snd_card) { sample_rate = obj->audio_pin_fmt.fmt->rate; nchannels = obj->audio_pin_fmt.fmt->nchannels; if((obj->audio_sink = ms_snd_card_create_writer(obj->snd_card))) { if(ms_filter_call_method(obj->audio_sink, MS_FILTER_SET_SAMPLE_RATE, &sample_rate) == -1) { ms_warning("The sound card (%s) does not support %dHz", obj->snd_card->name, sample_rate); ms_filter_call_method(obj->audio_sink, MS_FILTER_GET_SAMPLE_RATE, &sink_sample_rate); ms_message("Resampling to %dHz", sink_sample_rate); obj->resampler = ms_filter_new(MS_RESAMPLE_ID); ms_filter_call_method(obj->resampler, MS_FILTER_SET_SAMPLE_RATE, &sample_rate); ms_filter_call_method(obj->resampler, MS_FILTER_SET_OUTPUT_SAMPLE_RATE, &sink_sample_rate); ms_filter_call_method(obj->resampler, MS_FILTER_SET_NCHANNELS, &nchannels); } ms_filter_call_method(obj->audio_sink, MS_FILTER_SET_NCHANNELS, &nchannels); } else { ms_error("Could not create audio sink. Soundcard=%s", obj->snd_card->name); } } if(obj->video_pin_fmt.fmt) { if(obj->video_display) { obj->video_sink = ms_filter_new_from_name(obj->video_display); if(obj->video_sink) { if(obj->window_id) ms_filter_call_method(obj->video_sink, MS_VIDEO_DISPLAY_SET_NATIVE_WINDOW_ID, &obj->window_id); } else { ms_error("Could not create video sink: %s", obj->video_display); } } } }
SinkBase::SinkBase(int payload, const char *mcu_ip, int mcu_rtp_port, int mcu_rtcp_port, void (*data)(void *opaque, double stamp, void *data, int len, bool key), void *opaque) : cb_data_(data) , opaque_(opaque) , mcu_ip_(mcu_ip) , mcu_rtp_port_(mcu_rtp_port) , mcu_rtcp_port_(mcu_rtcp_port) , payload_(payload) { rtp_ = rtp_session_new(RTP_SESSION_RECVONLY); if (payload == 100) { rtp_session_set_rtp_socket_recv_buffer_size(rtp_, 1024*1024); } rtp_session_set_remote_addr_and_port(rtp_, mcu_ip, mcu_rtp_port, mcu_rtcp_port); rtp_session_set_payload_type(rtp_, payload); rtp_session_enable_jitter_buffer(rtp_, false); f_recv_ = ms_filter_new(MS_RTP_RECV_ID); ms_filter_call_method(f_recv_, MS_RTP_RECV_SET_SESSION, rtp_); f_void_ = ms_filter_new_from_name("ZonekeyVoidSink"); ZonekeyVoidSinkCallback cbs = { this, cb_data }; ms_filter_call_method(f_void_, ZONEKEY_METHOD_VOID_SINK_SET_CALLBACK, &cbs); ticker_ = ms_ticker_new(); ms_queue_init(&queue_); }
static MSFilter *get_render() { const char *name = choose_display_name(); fprintf(stderr, "using render '%s'\n", name); MSFilter *render = ms_filter_new_from_name(name); return render; }
/** 接收为 iLBC,输出需要转换为 AAC */ SinkiLBC::SinkiLBC(const char *mcu_ip, int mcu_rtp_port, int mcu_rtcp_port, void (*data)(void *opaque, double stamp, void *data, int len, bool key), void *opaque) : SinkBase(102, mcu_ip, mcu_rtp_port, mcu_rtcp_port, data, opaque) { f_resample_ = ms_filter_new(MS_RESAMPLE_ID); int in_sample = 8000, in_ch = 1; int out_sample = 32000, out_ch = 1; ms_filter_call_method(f_resample_, MS_FILTER_SET_SAMPLE_RATE, &in_sample); ms_filter_call_method(f_resample_, MS_FILTER_SET_NCHANNELS, &in_ch); ms_filter_call_method(f_resample_, MS_FILTER_SET_OUTPUT_SAMPLE_RATE, &out_sample); ms_filter_call_method(f_resample_, MS_FILTER_SET_OUTPUT_NCHANNELS, &out_ch); f_ilbc_decoder_ = ms_filter_new_from_name("MSIlbcDec"); f_aac_encoder_ = ms_filter_new_from_name("ZonekeyAACEnc"); ms_filter_link(f_ilbc_decoder_, 0, f_resample_, 0); ms_filter_link(f_resample_, 0, f_aac_encoder_, 0); }
DirectorConference::DirectorConference(int id, int livingcast) : Conference(id) { filter_tee_ = ms_filter_new(MS_TEE_ID); filter_sink_ = ms_filter_new_from_name("ZonekeyVoidSink"); log("%s: ... id=%d \n", __FUNCTION__, id); #if 1 audio_mixer_ = ms_filter_new_from_name("ZonekeyAudioMixer"); int rate = 16000; ms_filter_call_method(audio_mixer_, MS_FILTER_SET_SAMPLE_RATE, &rate); #else audio_mixer_ = ms_filter_new(MS_AUDIO_MIXER_ID); int tmp = 1, rate = 16000; ms_filter_call_method(audio_mixer_, MS_AUDIO_MIXER_ENABLE_CONFERENCE_MODE, &tmp); ms_filter_call_method(audio_mixer_, MS_FILTER_SET_SAMPLE_RATE, &rate); #endif video_mixer_ = ms_filter_new_from_name("ZonekeyVideoMixer"); audio_publisher_ = ms_filter_new_from_name("ZonekeyPublisher"); video_publisher_ = ms_filter_new_from_name("ZonekeyPublisher"); audio_resample_ = ms_filter_new(MS_RESAMPLE_ID); audio_encoder_ = ms_filter_new_from_name("MSIlbcEnc"); video_tee_ = ms_filter_new(MS_TEE_ID); // 是否启用 video mixer ms_filter_call_method(video_mixer_, ZONEKEY_METHOD_VIDEO_MIXER_ENABLE, (void*)livingcast); audio_ticker_ = ms_ticker_new(); video_ticker_ = ms_ticker_new(); /// 总是将 audio mixer 的 preview 使用 iLBC 输出 int in_sample = 16000, in_ch = 1; int out_sample = 8000, out_ch = 1; ms_filter_call_method(audio_resample_, MS_FILTER_SET_SAMPLE_RATE, &in_sample); ms_filter_call_method(audio_resample_, MS_FILTER_SET_NCHANNELS, &in_ch); ms_filter_call_method(audio_resample_, MS_FILTER_SET_OUTPUT_SAMPLE_RATE, &out_sample); ms_filter_call_method(audio_resample_, MS_FILTER_SET_OUTPUT_NCHANNELS, &out_ch); // simple link ms_filter_link(audio_mixer_, ZONEKEY_AUDIO_MIXER_PREVIEW_PIN, audio_resample_, 0); ms_filter_link(audio_resample_, 0, audio_encoder_, 0); ms_filter_link(audio_encoder_, 0, audio_publisher_, 0); ms_filter_link(video_mixer_, 1, video_tee_, 0); ms_filter_link(video_tee_, MAX_STREAMS, video_publisher_, 0); audio_stream_cnt_ = 0; video_stream_cnt_ = 0; resume_audio(); resume_video(); log("ok\n"); }
void video_preview_start(VideoPreview *stream, MSWebCam *device){ MSPixFmt format; float fps=(float)29.97; int mirroring=1; int corner=-1; MSVideoSize disp_size=stream->sent_vsize; MSVideoSize vsize=disp_size; const char *displaytype=stream->display_name; stream->source = ms_web_cam_create_reader(device); /* configure the filters */ ms_filter_call_method(stream->source,MS_FILTER_SET_VIDEO_SIZE,&vsize); 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_GET_PIX_FMT,&format); ms_filter_call_method(stream->source,MS_FILTER_GET_VIDEO_SIZE,&vsize); 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); } format=MS_YUV420P; stream->output2=ms_filter_new_from_name (displaytype); ms_filter_call_method(stream->output2,MS_FILTER_SET_PIX_FMT,&format); ms_filter_call_method(stream->output2,MS_FILTER_SET_VIDEO_SIZE,&disp_size); ms_filter_call_method(stream->output2,MS_VIDEO_DISPLAY_ENABLE_MIRRORING,&mirroring); ms_filter_call_method(stream->output2,MS_VIDEO_DISPLAY_SET_LOCAL_VIEW_MODE,&corner); /* and then connect all */ ms_filter_link(stream->source,0, stream->pixconv,0); ms_filter_link(stream->pixconv, 0, stream->output2, 0); if (stream->preview_window_id!=0){ video_stream_set_native_preview_window_id(stream, stream->preview_window_id); } /* create the ticker */ stream->ms.ticker = ms_ticker_new(); ms_ticker_set_name(stream->ms.ticker,"Video MSTicker"); ms_ticker_attach (stream->ms.ticker, stream->source); }
void VodWnd::vod(const char *ip, int rtp_port, int rtcp_port) { server_ip_ = ip; server_rtp_port_ = rtp_port; server_rtcp_port_ = rtcp_port; rtp_ = rtp_session_new(RTP_SESSION_RECVONLY); rtp_session_set_payload_type(rtp_, 100); rtp_session_set_local_addr(rtp_, util_get_myip(), 0, 0); rtp_session_set_remote_addr_and_port(rtp_, ip, rtp_port, rtcp_port); JBParameters jb; jb.adaptive = 1; jb.max_packets = 3000; jb.max_size = -1; jb.min_size = jb.nom_size = 300; rtp_session_set_jitter_buffer_params(rtp_, &jb); rtp_session_enable_jitter_buffer(rtp_, 0); evq_ = ortp_ev_queue_new(); rtp_session_register_event_queue(rtp_, evq_); ticker_ = ms_ticker_new(); filter_rtp_ = ms_filter_new(MS_RTP_RECV_ID); ms_filter_call_method(filter_rtp_, MS_RTP_RECV_SET_SESSION, rtp_); filter_decoder_ = ms_filter_new(MS_H264_DEC_ID); ZonekeyYUVSinkCallbackParam cbp; cbp.ctx = this; cbp.push = cb_yuv; filter_sink_ = ms_filter_new_from_name("ZonekeyYUVSink"); ms_filter_call_method(filter_sink_, ZONEKEY_METHOD_YUV_SINK_SET_CALLBACK_PARAM, &cbp); ms_filter_link(filter_rtp_, 0, filter_decoder_, 0); ms_filter_link(filter_decoder_, 0, filter_sink_, 0); ms_ticker_attach(ticker_, filter_rtp_); }
int video_stream_start (VideoStream *stream, RtpProfile *profile, const char *rem_rtp_ip, int rem_rtp_port, const char *rem_rtcp_ip, int rem_rtcp_port, int payload, int jitt_comp, MSWebCam *cam){ PayloadType *pt; RtpSession *rtps=stream->ms.session; MSPixFmt format; MSVideoSize disp_size; int tmp; JBParameters jbp; const int socket_buf_size=2000000; if (cam==NULL){ cam=ms_web_cam_manager_get_default_cam ( ms_web_cam_manager_get()); } pt=rtp_profile_get_payload(profile,payload); if (pt==NULL){ ms_error("videostream.c: undefined payload type."); return -1; } if ((cam != NULL) && (cam->desc->encode_to_mime_type != NULL) && (cam->desc->encode_to_mime_type(cam, pt->mime_type) == TRUE)) { stream->source_performs_encoding = TRUE; } rtp_session_set_profile(rtps,profile); if (rem_rtp_port>0) rtp_session_set_remote_addr_full(rtps,rem_rtp_ip,rem_rtp_port,rem_rtcp_ip,rem_rtcp_port); rtp_session_set_payload_type(rtps,payload); rtp_session_set_jitter_compensation(rtps,jitt_comp); rtp_session_signal_connect(stream->ms.session,"payload_type_changed", (RtpCallback)mediastream_payload_type_changed,(unsigned long)&stream->ms); rtp_session_get_jitter_buffer_params(stream->ms.session,&jbp); jbp.max_packets=1000;//needed for high resolution video rtp_session_set_jitter_buffer_params(stream->ms.session,&jbp); rtp_session_set_rtp_socket_recv_buffer_size(stream->ms.session,socket_buf_size); rtp_session_set_rtp_socket_send_buffer_size(stream->ms.session,socket_buf_size); if (stream->dir==VideoStreamSendRecv || stream->dir==VideoStreamSendOnly){ MSConnectionHelper ch; /*plumb the outgoing stream */ if (rem_rtp_port>0) ms_filter_call_method(stream->ms.rtpsend,MS_RTP_SEND_SET_SESSION,stream->ms.session); if (stream->source_performs_encoding == FALSE) { stream->ms.encoder=ms_filter_create_encoder(pt->mime_type); if ((stream->ms.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->cam=cam; stream->source = ms_web_cam_create_reader(cam); stream->tee = ms_filter_new(MS_TEE_ID); if (stream->source_performs_encoding == TRUE) { stream->ms.encoder = stream->source; /* Consider the encoder is the source */ } if (pt->normal_bitrate>0){ MSVideoConfiguration *vconf_list = NULL; ms_message("Limiting bitrate of video encoder to %i bits/s",pt->normal_bitrate); ms_filter_call_method(stream->ms.encoder, MS_VIDEO_ENCODER_GET_CONFIGURATION_LIST, &vconf_list); if (vconf_list != NULL) { MSVideoConfiguration vconf = ms_video_find_best_configuration_for_bitrate(vconf_list, pt->normal_bitrate); ms_filter_call_method(stream->ms.encoder, MS_VIDEO_ENCODER_SET_CONFIGURATION, &vconf); } else { ms_filter_call_method(stream->ms.encoder, MS_FILTER_SET_BITRATE, &pt->normal_bitrate); } } if (pt->send_fmtp){ ms_filter_call_method(stream->ms.encoder,MS_FILTER_ADD_FMTP,pt->send_fmtp); } if (stream->use_preview_window){ if (stream->rendercb==NULL){ stream->output2=ms_filter_new_from_name (stream->display_name); } } configure_video_source (stream); /* and then connect all */ ms_connection_helper_start(&ch); ms_connection_helper_link(&ch, stream->source, -1, 0); if (stream->pixconv) { ms_connection_helper_link(&ch, stream->pixconv, 0, 0); } if (stream->sizeconv) { ms_connection_helper_link(&ch, stream->sizeconv, 0, 0); } ms_connection_helper_link(&ch, stream->tee, 0, 0); if (stream->source_performs_encoding == FALSE) { ms_connection_helper_link(&ch, stream->ms.encoder, 0, 0); } ms_connection_helper_link(&ch, stream->ms.rtpsend, 0, -1); if (stream->output2){ if (stream->preview_window_id!=0){ ms_filter_call_method(stream->output2, MS_VIDEO_DISPLAY_SET_NATIVE_WINDOW_ID,&stream->preview_window_id); } ms_filter_link(stream->tee,1,stream->output2,0); } } if (stream->dir==VideoStreamSendRecv || stream->dir==VideoStreamRecvOnly){ MSConnectionHelper ch; MSVideoDisplayDecodingSupport decoding_support; 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); } /* Don't allow null output */ if(stream->output == NULL) { ms_fatal("No video display filter could be instantiated. Please check build-time configuration"); } /* Check if the output filter can perform the decoding process */ decoding_support.mime_type = pt->mime_type; decoding_support.supported = FALSE; ms_filter_call_method(stream->output, MS_VIDEO_DISPLAY_SUPPORT_DECODING, &decoding_support); stream->output_performs_decoding = decoding_support.supported; /*plumb the incoming stream */ if (stream->output_performs_decoding == TRUE) { stream->ms.decoder = stream->output; /* Consider the decoder is the output */ } else { stream->ms.decoder=ms_filter_create_decoder(pt->mime_type); if ((stream->ms.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); ms_filter_destroy(stream->output); return -1; } } ms_filter_set_notify_callback(stream->ms.decoder, event_cb, stream); stream->ms.rtprecv = ms_filter_new (MS_RTP_RECV_ID); ms_filter_call_method(stream->ms.rtprecv,MS_RTP_RECV_SET_SESSION,stream->ms.session); if (stream->output_performs_decoding == FALSE) { stream->jpegwriter=ms_filter_new(MS_JPEG_WRITER_ID); if (stream->jpegwriter) stream->tee2=ms_filter_new(MS_TEE_ID); } /* set parameters to the decoder*/ if (pt->send_fmtp){ ms_filter_call_method(stream->ms.decoder,MS_FILTER_ADD_FMTP,pt->send_fmtp); } if (pt->recv_fmtp!=NULL) ms_filter_call_method(stream->ms.decoder,MS_FILTER_ADD_FMTP,(void*)pt->recv_fmtp); /*force the decoder to output YUV420P */ format=MS_YUV420P; ms_filter_call_method(stream->ms.decoder,MS_FILTER_SET_PIX_FMT,&format); /*configure the display window */ if(stream->output != NULL) { 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); if (stream->window_id!=0){ ms_filter_call_method(stream->output, MS_VIDEO_DISPLAY_SET_NATIVE_WINDOW_ID,&stream->window_id); } if (stream->display_filter_auto_rotate_enabled) { ms_filter_call_method(stream->output,MS_VIDEO_DISPLAY_SET_DEVICE_ORIENTATION,&stream->device_orientation); } } /* and connect the filters */ ms_connection_helper_start (&ch); ms_connection_helper_link (&ch,stream->ms.rtprecv,-1,0); if (stream->output_performs_decoding == FALSE) { ms_connection_helper_link (&ch,stream->ms.decoder,0,0); } if (stream->tee2){ ms_connection_helper_link (&ch,stream->tee2,0,0); ms_filter_link(stream->tee2,1,stream->jpegwriter,0); } if (stream->output!=NULL) ms_connection_helper_link (&ch,stream->output,0,-1); /* the video source must be send for preview , if it exists*/ if (stream->tee!=NULL && stream->output!=NULL && stream->output2==NULL) ms_filter_link(stream->tee,1,stream->output,1); } if (stream->dir == VideoStreamSendOnly) { stream->ms.rtprecv = ms_filter_new (MS_RTP_RECV_ID); ms_filter_call_method(stream->ms.rtprecv, MS_RTP_RECV_SET_SESSION, stream->ms.session); stream->ms.voidsink = ms_filter_new(MS_VOID_SINK_ID); ms_filter_link(stream->ms.rtprecv, 0, stream->ms.voidsink, 0); } /* create the ticker */ if (stream->ms.ticker==NULL) start_ticker(&stream->ms); stream->ms.start_time=ms_time(NULL); stream->ms.is_beginning=TRUE; /* attach the graphs */ if (stream->source) ms_ticker_attach (stream->ms.ticker, stream->source); if (stream->ms.rtprecv) ms_ticker_attach (stream->ms.ticker, stream->ms.rtprecv); return 0; }
int video_mail_record_start(VideoMailRecord *vp, MSSndCard *sndcard,MSWebCam *webcam,unsigned long video_window_id,const char *filename){ MSConnectionHelper h; MSPixFmt format=MS_YUV420P; { strcpy(vp->filename, filename); vp->os = video_recoder_new(); video_recoder_init(vp->os); video_recoder_set_vsize(vp->os,vp->vsize); video_recoder_set_rate(vp->os,vp->rate); video_recoder_set_audio_bit_rate(vp->os, get_bit_rate_by_samples_rate(vp->rate)); video_recoder_set_video_bit_rate(vp->os, vp->bit_rate - get_bit_rate_by_samples_rate(vp->rate)); video_recoder_set_nbchannels(vp->os,vp->nchannels); if(video_recoder_open_file(vp->os,vp->filename)<0){ video_recoder_destory(vp->os); vp->os=NULL; return -1; } video_mail_record_set_audio_sink(vp,video_recoder_create_audio_filter(vp->os)); video_mail_record_set_video_sink(vp,video_recoder_create_video_filter(vp->os)); video_recoder_start(vp->os); } { if (sndcard!=NULL) vp->snd_read=ms_snd_card_create_reader(sndcard); if(vp->snd_read){ ms_filter_call_method(vp->snd_read,MS_FILTER_SET_NCHANNELS,&vp->nchannels); ms_filter_call_method(vp->snd_read,MS_FILTER_SET_SAMPLE_RATE,&vp->rate); } } { if (webcam==NULL){ webcam=ms_web_cam_manager_get_default_cam ( ms_web_cam_manager_get()); } vp->video_source = ms_web_cam_create_reader(webcam); vp->video_tee = ms_filter_new(MS_TEE_ID); ms_message("Setting sent vsize=%ix%i, fps=%f",vp->vsize.width,vp->vsize.height,vp->fps); /* configure the filters */ if (ms_filter_get_id(vp->video_source)!=MS_STATIC_IMAGE_ID) { ms_filter_call_method(vp->video_source,MS_FILTER_SET_FPS,&vp->fps); } ms_filter_call_method(vp->video_source,MS_FILTER_SET_VIDEO_SIZE,&vp->vsize); ms_filter_call_method(vp->video_source,MS_FILTER_GET_PIX_FMT,&format); if (format==MS_MJPEG){ vp->pixconv=ms_filter_new(MS_MJPEG_DEC_ID); }else{ vp->pixconv = ms_filter_new(MS_PIX_CONV_ID); /*set it to the pixconv */ ms_filter_call_method(vp->pixconv,MS_FILTER_SET_PIX_FMT,&format); ms_filter_call_method(vp->video_source,MS_FILTER_GET_VIDEO_SIZE,&vp->vsize); ms_filter_call_method(vp->pixconv,MS_FILTER_SET_VIDEO_SIZE,&vp->vsize); } vp->sizeconv=ms_filter_new(MS_SIZE_CONV_ID); ms_filter_call_method(vp->sizeconv,MS_FILTER_SET_VIDEO_SIZE,&vp->vsize); choose_display_name(vp); vp->video_output=ms_filter_new_from_name (vp->display_name); if (video_window_id!=0) ms_filter_call_method(vp->video_output, MS_VIDEO_DISPLAY_SET_NATIVE_WINDOW_ID,&video_window_id); } if(vp->snd_read!=NULL && vp->snd_sink!=NULL){ ms_filter_link(vp->snd_read,0,vp->snd_sink,0); } if(vp->video_source!=NULL && vp->video_output!=NULL) { ms_connection_helper_start(&h); ms_connection_helper_link(&h,vp->video_source,-1,0); ms_connection_helper_link(&h,vp->pixconv,0,0); ms_connection_helper_link(&h,vp->sizeconv,0,0); ms_connection_helper_link(&h,vp->video_tee,0,0); ms_filter_link(vp->video_tee,1,vp->video_output,0); ms_connection_helper_link(&h,vp->video_sink,0,-1); } vp->ticker = ms_ticker_new(); ms_ticker_set_name(vp->ticker,"VideoMailRecord"); if(vp->snd_read!=NULL && vp->snd_sink!=NULL) ms_ticker_attach(vp->ticker,vp->snd_read); if(vp->video_source!=NULL && vp->video_output!=NULL) ms_ticker_attach(vp->ticker,vp->video_source); return 0; }
int main(int argc, char **argv) { ortp_init(); ms_init(); zk_xmpp_uac_init(); ortp_set_log_level_mask(ORTP_MESSAGE); if (argc < 2) { fprintf(stderr, "usage: %s <zqpkt src url> [s]\n", argv[0]); return -1; } bool stream_mode = false; if (argc == 3 && argv[2][0] == 's') stream_mode = true; _stream_mode = stream_mode; if (stream_mode) fprintf(stdout, "=== STREAMING MODE ===\n\n"); else fprintf(stdout, "=== SOURCING MODE ===\n\n"); _url = argv[1]; _env = CreateEvent(0, 0, 0, 0); fprintf(stdout, "%s: using zqpkt src '%s', just wait mcu .....\n", argv[0], argv[1]); // 使用 normaluser 登录 cb_xmpp_uac cbs = { 0, 0, 0, 0, cb_connect_notify }; _uac = zk_xmpp_uac_log_in(get_user_jid(), "ddkk1212", &cbs, 0); WaitForSingleObject(_env, 10000); if (_sid == -1) { fprintf(stderr, ":( somthing err, exit!\n"); } else { SetConsoleCtrlHandler(signal_ctrl_c, 1); const char *src_url = argv[1]; const char *target_ip = _ip.c_str(); int target_port = _rtp_port; int target_port2 = _rtcp_port; //fprintf(stdout, "target ip=%s\ntarget port=%d\n\n", target_ip, target_port); // only support h264 rtp_profile_set_payload(&av_profile,100, &payload_type_h264); /// 使用 zonekey.h264.source filter zonekey_h264_source_register(); MSFilterDesc *desc = ms_filter_lookup_by_name("ZonekeyH264Source"); MSFilter *source = ms_filter_new_from_desc(desc); if (_stream_mode) zonekey_yuv_sink_register(); // 获取 writer_params ZonekeyH264SourceWriterParam writer_param; ms_filter_call_method(source, ZONEKEY_METHOD_H264_SOURCE_GET_WRITER_PARAM, &writer_param); // RTP Session RtpSession *rtpsess = rtp_session_new(RTP_SESSION_SENDRECV); // rtp_session_set_local_addr(rtpsess, "0.0.0.0", -1, -1); // 随机端口 rtp_session_set_remote_addr_and_port(rtpsess, target_ip, target_port, target_port2); rtp_session_set_payload_type(rtpsess, 100); // h264 JBParameters jb; jb.adaptive = 1; jb.max_packets = 3000; jb.max_size = -1; jb.min_size = jb.nom_size = 300; rtp_session_set_jitter_buffer_params(rtpsess, &jb); // disable video jitter control rtp_session_enable_jitter_buffer(rtpsess, 0); /// rtp sender MSFilter *rtp_sender = ms_filter_new(MS_RTP_SEND_ID); ms_filter_call_method(rtp_sender, MS_RTP_SEND_SET_SESSION, rtpsess); // connect source --> rtp sender ms_filter_link(source, 0, rtp_sender, 0); // MSTicker MSTicker *ticker = ms_ticker_new(); // attach ticker ms_ticker_attach(ticker, source); if (_stream_mode) { // FIXME: recv, but .... MSFilter *rtp_recver = ms_filter_new(MS_RTP_RECV_ID); ms_filter_call_method(rtp_recver, MS_RTP_RECV_SET_SESSION, rtpsess); MSFilter *decoder = ms_filter_new(MS_H264_DEC_ID); MSFilter *sink = ms_filter_new_from_name("ZonekeyYUVSink"); ms_filter_link(rtp_recver, 0, decoder, 0); ms_filter_link(decoder, 0, sink, 0); MSTicker *tk = ms_ticker_new(); //ms_ticker_attach(tk, rtp_recver); } // 利用 libzqpkt 接收 h264 数据,并且调用 zonekey h264 source 的 writer() void *zqp = 0; if (zqpsrc_open(&zqp, src_url) < 0) { fprintf(stderr, "to open src err\n"); return -1; } while (!_quit) { zq_pkt *pkt = zqpsrc_getpkt(zqp); if (pkt) { if (pkt->type == 1) { // h264 writer_param.write(writer_param.ctx, pkt->ptr, pkt->len, pkt->pts / 45000.0); } zqpsrc_freepkt(zqp, pkt); } else break; } // 发送删除 sid 的命令 char options[128], *cmd="test.fc.del_source"; if (_stream_mode) { snprintf(options, sizeof(options), "streamid=%d", _sid); cmd = "test.dc.del_stream"; } else snprintf(options, sizeof(options), "sid=%d", _sid); zk_xmpp_uac_send_cmd(_uac, get_mcu_jid(), cmd, options, 0, cb_response); fprintf(stderr, "\n\nen. to del sid=%d\n\n", _sid); zqpsrc_close(zqp); fprintf(stderr, "END!\n"); WaitForSingleObject(_env, 3000); // 等待 test.fc.de_source 发送成功 } return 0; }
void conf_stream_start(LinphoneConferenceStream *stream,bool_t video_monitor) { bool_t ptt = stream->ptt_mode; int tmp; { stream->audio_ticker = ms_ticker_new(); ms_cond_init(&stream->audio_ticker->cond,NULL); ms_ticker_set_name(stream->audio_ticker,"Audio Mixer MSTicker"); stream->audio_mixer = ms_filter_new(MS_CONF_ID); stream->audio_filerecorder = ms_filter_new(MS_FILE_REC_ID); stream->audio_fileplayer = ms_filter_new(MS_FILE_PLAYER_ID); ms_filter_call_method(stream->audio_mixer,MS_FILTER_SET_SAMPLE_RATE,&stream->sample_rate); ms_filter_call_method (stream->audio_fileplayer , MS_FILTER_SET_SAMPLE_RATE,&stream->sample_rate); tmp = 1; /*默认采用单声道会议*/ ms_filter_call_method (stream->audio_fileplayer , MS_FILTER_SET_NCHANNELS,&tmp); /*设置会议音频采样率,8k,16k,32k*/ ms_filter_call_method(stream->audio_filerecorder,MS_FILTER_SET_SAMPLE_RATE,&stream->sample_rate); ms_message("Link audio filter list!!!"); /*创建录制端口*/ { int audio_mixer_pin = NB_AUDIO_MAX_OUPUT_PINS-2; stream->audio_record_sink = ms_filter_new(MS_CONF_ITC_SINK_ID); ms_filter_link(stream->audio_mixer,audio_mixer_pin,stream->audio_record_sink,0); } {/*创建音频对接端口*/ int max_ports = stream->max_ports; for(int i=0; i< max_ports; i++) { ConfAudioPort *port = audio_slot_new(); audio_slot_init(port,i); stream->audio_ports = ms_list_append(stream->audio_ports, port); /*顺序连接音频对接端口*/ ms_filter_link(port->audio_itc_source,0,stream->audio_mixer,i);// <--- call[i].sink <--- call[i].decode <--- call[i].rtp_recv ms_filter_link(stream->audio_mixer,i,port->audio_itc_sink,0); // ---> call[i].itc_source --->call[i].encode --->call[i].rtp_send } /*将音频播放,及录制连接至最末端端口*/ ms_filter_link(stream->audio_fileplayer,0,stream->audio_mixer,stream->max_ports); ms_filter_link(stream->audio_mixer,stream->max_ports,stream->audio_filerecorder,0); } /*启动音频mixer线程*/ ms_ticker_attach(stream->audio_ticker,stream->audio_mixer); } if(stream->has_video) { ms_message("Link video filter list!!!"); MSPixFmt format=MS_YUV420P; MSVideoSize vsize,cam_vsize,disp_size; stream->video_mixer=ms_filter_new_from_name("MSVideoMixer"); if(stream->video_mixer==NULL){ ms_error("Not have MSVideoStitcher, Can't to Video Conference!!!"); return; } stream->video_ticker = ms_ticker_new(); ms_cond_init(&stream->video_ticker->cond,NULL); ms_ticker_set_name(stream->video_ticker,"Video Mixer MSTicker"); /*设置视频会议的输出尺寸*/ ms_filter_call_method(stream->video_mixer,MS_FILTER_SET_VIDEO_SIZE,&stream->sent_vsize); /*添加服务器端视频监视,可添加jpeg画面截取filer,用于web端实时会议的画面截取*/ if(video_monitor) stream->video_output=ms_filter_new_from_name (stream->display_name); /*配置监视器*/ if(stream->video_output!=NULL){ disp_size = stream->sent_vsize; tmp=1; ms_filter_call_method(stream->video_output,MS_FILTER_SET_VIDEO_SIZE,&disp_size); ms_filter_call_method(stream->video_output,MS_VIDEO_DISPLAY_ENABLE_AUTOFIT,&tmp); ms_filter_call_method(stream->video_output,MS_FILTER_SET_PIX_FMT,&format); /*在已有窗口上绘图,或创建新window*/ if (stream->video_window_id!=0) ms_filter_call_method(stream->video_output, MS_VIDEO_DISPLAY_SET_NATIVE_WINDOW_ID,&stream->video_window_id); /*设置服务器端 视频监视filter,将其连接至视频Mixer输出最后的端口上*/ ms_filter_link (stream->video_mixer,VIDEO_MIXER_MAX_OUTPUTS-1, stream->video_output, 0); } /*输出录制端口*/ { int video_mixer_pin = VIDEO_MIXER_MAX_OUTPUTS-2; stream->video_record_sink = ms_filter_new(MS_CONF_ITC_SINK_ID); ms_filter_link(stream->video_mixer,video_mixer_pin,stream->video_record_sink,0); } /*创建无信号输出时,显示的图片*/ stream->video_static_image = ms_web_cam_create_reader(get_image_webcam_device()); if(stream->static_image_path!=NULL) ms_filter_call_method(stream->video_static_image, MS_STATIC_IMAGE_SET_IMAGE,(void *)stream->static_image_path); ms_filter_call_method(stream->video_static_image, MS_FILTER_SET_FPS,&stream->fps); ms_filter_call_method(stream->video_static_image,MS_FILTER_SET_VIDEO_SIZE,&stream->sent_vsize); /*并行输出至所有视频端口*/ stream->video_static_image_tee = ms_filter_new(MS_TEE_ID); ms_filter_link (stream->video_static_image, 0, stream->video_static_image_tee, 0); /*最大视频端口,需小于视频Mixer最大布局数,当前最大为 9 画面*/ int max_ports = (stream->max_ports > NB_MAX_VIDEO_LAYOUT)? NB_MAX_VIDEO_LAYOUT:stream->max_ports; int static_pic_index=0; /*创建端口连接插座*/ for(int i=0; i<max_ports; i++) { ConfVideoPort *port = video_slot_new(); video_slot_init(port,i); stream->video_ports = ms_list_append(stream->video_ports, port); /** * 视频采集输入源 和 静态图片 同时 join 至mixer的输入端口, * 当视频流有效时需MUTE 静态图片的输入,反之则输入静态图片 * * video_input -------> join ------> mixer ----> video_output * | * static_pic ----------+ * **/ ms_filter_link (port->video_itc_source, 0, port->video_input_join,0); ms_filter_link (stream->video_static_image_tee, static_pic_index++, port->video_input_join,1); /*自动布局模式下除了0号端口外,均不输出静态图片*/ if(stream->auto_layout && (static_pic_index > 0)){ ms_filter_call_method(stream->video_static_image_tee,MS_TEE_MUTE,&static_pic_index); } ms_filter_link (port->video_input_join, 0, stream->video_mixer,i); ms_filter_link (stream->video_mixer,i, port->video_itc_sink,0); } ms_ticker_attach(stream->video_ticker,stream->video_mixer); } }
void CameraStream::init() { /** 获取第一帧图像,初始化 sws_,创建 h264 encoder .... */ IplImage *img = cvQueryFrame(cap_); // FIXME: 未必是 rgb24 吧??? sws_ = sws_getContext(img->width, img->height, PIX_FMT_RGB24, WIDTH, HEIGHT, PIX_FMT_YUV420P, SWS_FAST_BILINEAR, 0, 0, 0); x264_param_t param; x264_param_default_preset(¶m, "veryfast", "zerolatency"); param.i_threads = 0; param.i_width = WIDTH; param.i_height = HEIGHT; param.i_keyint_max = FPS * 2; param.i_fps_den = 1; param.i_fps_num = FPS; param.i_slice_max_size = 1300; param.b_repeat_headers = 1; param.b_annexb = 1; param.rc.i_rc_method = X264_RC_ABR; param.rc.i_bitrate = KBPS; param.rc.i_vbv_max_bitrate = KBPS*1.1; encoder_ = x264_encoder_open(¶m); avpicture_alloc(&pic_, PIX_FMT_YUV420P, WIDTH, HEIGHT); rtp_ = rtp_session_new(RTP_SESSION_SENDRECV); rtp_session_set_payload_type(rtp_, 100); rtp_session_set_remote_addr_and_port(rtp_, server_ip_.c_str(), server_rtp_port_, server_rtcp_port_); rtp_session_set_local_addr(rtp_, util_get_myip(), 0, 0); JBParameters jb; jb.adaptive = 1; jb.max_packets = 500; jb.max_size = -1; jb.min_size = jb.nom_size = 300; rtp_session_set_jitter_buffer_params(rtp_, &jb); filter_rtp_sender_ = ms_filter_new(MS_RTP_SEND_ID); ms_filter_call_method(filter_rtp_sender_, MS_RTP_SEND_SET_SESSION, rtp_); filter_h264_sender_ = ms_filter_new_from_name("ZonekeyH264Source"); ms_filter_call_method(filter_h264_sender_, ZONEKEY_METHOD_H264_SOURCE_GET_WRITER_PARAM, &sender_params_); filter_rtp_recver_ = ms_filter_new(MS_RTP_RECV_ID); ms_filter_call_method(filter_rtp_recver_, MS_RTP_RECV_SET_SESSION, rtp_); filter_decoder_ = ms_filter_new(MS_H264_DEC_ID); filter_yuv_sink_ = ms_filter_new_from_name("ZonekeyYUVSink"); // TODO: 显示 ... ms_filter_link(filter_rtp_recver_, 0, filter_decoder_, 0); ms_filter_link(filter_decoder_, 0, filter_yuv_sink_, 0); ticker_recver_ = ms_ticker_new(); ms_ticker_attach(ticker_recver_, filter_rtp_recver_); ms_filter_link(filter_h264_sender_, 0, filter_rtp_sender_, 0); ticker_sender_ = ms_ticker_new(); ms_ticker_attach(ticker_sender_, filter_h264_sender_); }
static void setup_media_streams(MediastreamDatas *args) { MSConnectionHelper h; MSTickerParams params = {0}; /*create the rtp session */ ortp_init(); if (args->is_verbose) { ortp_set_log_level_mask(ORTP_DEBUG | ORTP_MESSAGE | ORTP_WARNING | ORTP_ERROR | ORTP_FATAL); } else { ortp_set_log_level_mask(ORTP_MESSAGE | ORTP_WARNING | ORTP_ERROR | ORTP_FATAL); } rtp_profile_set_payload(&av_profile, 110, &payload_type_speex_nb); rtp_profile_set_payload(&av_profile, 111, &payload_type_speex_wb); rtp_profile_set_payload(&av_profile, 112, &payload_type_ilbc); rtp_profile_set_payload(&av_profile, 113, &payload_type_amr); rtp_profile_set_payload(&av_profile, 115, &payload_type_lpc1015); #ifdef VIDEO_ENABLED rtp_profile_set_payload(&av_profile, 26, &payload_type_jpeg); rtp_profile_set_payload(&av_profile, 98, &payload_type_h263_1998); rtp_profile_set_payload(&av_profile, 97, &payload_type_theora); rtp_profile_set_payload(&av_profile, 99, &payload_type_mp4v); rtp_profile_set_payload(&av_profile, 100, &payload_type_x_snow); rtp_profile_set_payload(&av_profile, 102, &payload_type_h264); rtp_profile_set_payload(&av_profile, 103, &payload_type_vp8); #endif args->profile = rtp_profile_clone_full(&av_profile); ms_init(); ms_filter_enable_statistics(TRUE); ms_filter_reset_statistics(); signal(SIGINT, stop_handler); if (args->pt==NULL) args->pt = rtp_profile_get_payload(args->profile, args->payload); if (args->pt == NULL) { printf("Error: no payload defined with number %i.", args->payload); exit(-1); } if (args->pt->type == PAYLOAD_VIDEO) { #ifdef VIDEO_ENABLED const char *display_name; MSPixFmt format; MSVideoSize disp_size; int tmp = 1; #if defined(HAVE_GL) display_name = "MSGLXVideo"; #elif defined(HAVE_XV) display_name = "MSX11Video"; #elif __APPLE__ && !defined(__ios) display_name ="MSOSXGLDisplay"; #else display_name = "MSVideoOut"; #endif args->read = ms_filter_new(MS_FILE_PLAYER_ID); args->write = ms_filter_new_from_name(display_name); args->decoder = ms_filter_create_decoder(args->pt->mime_type); ms_filter_call_method_noarg(args->read, MS_FILE_PLAYER_CLOSE); ms_filter_call_method(args->read, MS_FILE_PLAYER_OPEN, args->infile); ms_filter_call_method(args->read, MS_FILTER_SET_SAMPLE_RATE, &args->pt->clock_rate); ms_filter_call_method_noarg(args->read, MS_FILE_PLAYER_START); ms_filter_add_notify_callback(args->read, reader_notify_cb, NULL,FALSE); /*force the decoder to output YUV420P */ format = MS_YUV420P; ms_filter_call_method(args->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; ms_filter_call_method(args->write, MS_FILTER_SET_VIDEO_SIZE, &disp_size); ms_filter_call_method(args->write, MS_VIDEO_DISPLAY_ENABLE_AUTOFIT, &tmp); ms_filter_call_method(args->write, MS_FILTER_SET_PIX_FMT, &format); params.name = "Video MSTicker"; params.prio = MS_TICKER_PRIO_REALTIME; args->ticker = ms_ticker_new_with_params(¶ms); ms_connection_helper_start(&h); ms_connection_helper_link(&h, args->read, -1, 0); ms_connection_helper_link(&h, args->decoder, 0, 0); ms_connection_helper_link(&h, args->write, 0, -1); ms_ticker_attach(args->ticker, args->read); #else printf("Error: video support not compiled.\n"); #endif } else { MSSndCardManager *manager = ms_snd_card_manager_get(); MSSndCard *play = args->playback_card == NULL ? ms_snd_card_manager_get_default_playback_card(manager) : ms_snd_card_manager_get_card(manager, args->playback_card); args->read = ms_filter_new(MS_FILE_PLAYER_ID); args->write = ms_snd_card_create_writer(play); args->decoder = ms_filter_create_decoder(args->pt->mime_type); ms_filter_call_method_noarg(args->read, MS_FILE_PLAYER_CLOSE); ms_filter_call_method(args->read, MS_FILE_PLAYER_OPEN, args->infile); ms_filter_call_method_noarg(args->read, MS_FILE_PLAYER_START); ms_filter_call_method(args->read, MS_FILTER_SET_SAMPLE_RATE, &args->pt->clock_rate); ms_filter_call_method(args->decoder, MS_FILTER_SET_SAMPLE_RATE, &args->pt->clock_rate); ms_filter_call_method(args->decoder, MS_FILTER_SET_NCHANNELS, &args->pt->channels); ms_filter_call_method(args->write, MS_FILTER_SET_SAMPLE_RATE, &args->pt->clock_rate); ms_filter_call_method(args->write, MS_FILTER_SET_NCHANNELS, &args->pt->channels); params.name = "Audio MSTicker"; params.prio = MS_TICKER_PRIO_REALTIME; args->ticker = ms_ticker_new_with_params(¶ms); ms_connection_helper_start(&h); ms_connection_helper_link(&h, args->read, -1, 0); ms_connection_helper_link(&h, args->decoder, 0, 0); ms_connection_helper_link(&h, args->write, 0, -1); ms_ticker_attach(args->ticker, args->read); } }
int video_stream_start (VideoStream *stream, RtpProfile *profile, const char *remip, int remport, int rem_rtcp_port, int payload, int jitt_comp, MSWebCam *cam){ PayloadType *pt; RtpSession *rtps=stream->session; MSPixFmt format; MSVideoSize disp_size; int tmp; JBParameters jbp; const int socket_buf_size=2000000; if (cam==NULL){ cam=ms_web_cam_manager_get_default_cam ( ms_web_cam_manager_get()); } 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); 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); 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); } if (stream->use_preview_window){ if (stream->rendercb==NULL){ stream->output2=ms_filter_new_from_name (stream->display_name); } } configure_video_source (stream); /* 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); if (stream->output2){ if (stream->window_id!=0){ ms_filter_call_method(stream->output2, MS_VIDEO_DISPLAY_SET_NATIVE_WINDOW_ID,&stream->preview_window_id); } ms_filter_link(stream->tee,1,stream->output2,0); } } if (stream->dir==VideoStreamSendRecv || stream->dir==VideoStreamRecvOnly){ MSConnectionHelper ch; /*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); if(stream->conf_mode==FALSE) { stream->tee2=ms_filter_new(MS_TEE_ID); stream->jpegwriter=ms_filter_new(MS_JPEG_WRITER_ID); } 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{ if(stream->conf_mode) stream->output=ms_filter_new(MS_VOID_SINK_ID); 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); /*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); if (stream->window_id!=0){ ms_filter_call_method(stream->output, MS_VIDEO_DISPLAY_SET_NATIVE_WINDOW_ID,&stream->window_id); } /* and connect the filters */ 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); //Êä³öÊÓƵ¼ÖÆÖ¡. if(stream->video_record) ms_filter_link(stream->tee2,2,stream->video_record,0); } ms_connection_helper_link (&ch,stream->output,0,-1); /* the video source must be send for preview , if it exists*/ if (stream->tee!=NULL && stream->output2==NULL) ms_filter_link(stream->tee,1,stream->output,1); } /* create the ticker */ stream->ticker = ms_ticker_new(); ms_ticker_set_name(stream->ticker,"Video MSTicker"); //¼æÈÝPVX Ðëµ÷Õû±àÂë¼ä¸ô //stream->ticker->interval = 3; #ifdef ENABLE_UDT if(stream->enable_udt){ stream->udt = ms_filter_new(MS_UDT_TRANSPORT_ID); ms_filter_call_method(stream->udt,MS_UDT_SET_RTP_SESSION,stream->session); } #endif //ENABLE_UDT /* attach the graphs */ if (stream->source) ms_ticker_attach (stream->ticker, stream->source); if (stream->rtprecv) ms_ticker_attach (stream->ticker, stream->rtprecv); #ifdef ENABLE_UDT //×îºóÔËÐУ¬±ÜÃâ×èÈûUI if (stream->udt) ms_ticker_attach (stream->ticker, stream->udt); #endif // ENABLE_UDT return 0; }