基于android手机实时监控ipcam视频之二:mediastream2

    在项目中用到了mediastream2,mediastream2是一个框架,引擎,它驱动系统的整个流程,从接收rtp媒体流并解析到媒体解码到显示到android手机屏幕上,都是由mediastream2来驱动完成的。

    mediastream2是由一个个filter来完成,我们可以把filter当做一个单独的数据处理模块,它就像一个盒子,有输入和输出接口,数据从输入接口进来,处理完成后,再从输出接口出来进入到下一个filter中,多个filter连接在一起,就组成了一个系统循环。在我们的系统中,主要流程是ipcam发送rtp媒体流,系统接收rtp媒体流并解析,然后进行解码,再显示到android手机屏幕上,因此我们定义了三个filter,分别是:RTP Recv filter(RTP媒体流接收),Video Decoder filter(视频解码)和Android Display filter(视频输出显示),其基本流程如下:



                           RTP Recv----------------->Video Decoder------------------------------> Android Display


    首先我们要调用ms_init()这个函数,这个函数初始化mediastream2。

    void ms_init(){
int i;
MSSndCardManager *cm;


#if defined(ENABLE_NLS)
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
#endif


#if !defined(_WIN32_WCE)
if (getenv("MEDIASTREAMER_DEBUG")!=NULL){
ortp_set_log_level_mask(ORTP_DEBUG|ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
}
#endif
#ifdef ANDROID
ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
ortp_set_log_handler(ms_android_log_handler);
#endif
ms_message("Mediastreamer2 " MEDIASTREAMER_VERSION " (git: " GIT_VERSION ") starting.");
/* register builtin MSFilter's */
for (i=0;ms_filter_descs[i]!=NULL;i++){
ms_filter_register(ms_filter_descs[i]);
}
ms_message("Registering all soundcard handlers");
cm=ms_snd_card_manager_get();
for (i=0;ms_snd_card_descs[i]!=NULL;i++){
ms_snd_card_manager_register_desc(cm,ms_snd_card_descs[i]);
}


#ifdef VIDEO_ENABLED
ms_message("Registering all webcam handlers");
{
MSWebCamManager *wm;
wm=ms_web_cam_manager_get();
for (i=0;ms_web_cam_descs[i]!=NULL;i++){
ms_web_cam_manager_register_desc(wm,ms_web_cam_descs[i]);
}
}
#if !defined(NO_FFMPEG)
ms_ffmpeg_check_init();
__register_ffmpeg_encoders_if_possible();
#endif
#endif
#ifdef PACKAGE_PLUGINS_DIR
ms_message("Loading plugins");
ms_load_plugins(PACKAGE_PLUGINS_DIR);
#endif


#if defined(ANDROID) && defined (VIDEO_ENABLED)
if (1) {
libmsandroidopengldisplay_init();
} else {
if (!libmsandroiddisplay_init()) {
libmsandroiddisplaybad_init();
}
}
#endif
ms_message("ms_init() done");
}

    在这个函数里面,ms_filter_descs定义了目前支持的所有的filter,进一步分析

MSFilterDesc * ms_filter_descs[]={
&ms_alaw_dec_desc,
&ms_alaw_enc_desc,
&ms_ulaw_dec_desc,
&ms_ulaw_enc_desc,
&ms_rtp_send_desc,
&ms_rtp_recv_desc,
&ms_dtmf_gen_desc,
&ms_ice_desc,
&ms_tee_desc,
&ms_conf_desc,
&ms_join_desc,
&ms_volume_desc,
&ms_void_sink_desc,
//&ms_speex_dec_desc,
//&ms_speex_enc_desc,
//&ms_speex_ec_desc,
&ms_file_player_desc,
&ms_file_rec_desc,
//&ms_resample_desc,
&ms_equalizer_desc,
//&ms_gsm_enc_desc,
//&ms_gsm_dec_desc,
&ms_tone_detector_desc,
&ms_audio_mixer_desc,
&ms_g722_dec_desc,
&ms_g722_enc_desc,
#ifdef VIDEO_ENABLED
&ms_mpeg4_enc_desc,
&ms_mpeg4_dec_desc,
&ms_h263_enc_desc,
&ms_h263_dec_desc,
&ms_h264_dec_desc,
&ms_pix_conv_desc,
&ms_size_conv_desc,
//&ms_vp8_enc_desc,
//&ms_vp8_dec_desc,
#endif
NULL
};


我们可以看到系统定义了很多filter,比如ms_rtp_recv_desc是RTP接收filter,ms_h264_dec_desc是H.264解码filter等等。

MSFilterDesc ms_h264_dec_desc={
.id=MS_H264_DEC_ID,
.name="MSH264Dec",
.text="A H264 decoder based on ffmpeg project.",
.category=MS_FILTER_DECODER,
.enc_fmt="H264",
.ninputs=1,
.noutputs=1,
.init=dec_init,
.process=dec_process,
.uninit=dec_uninit,
.methods=h264_dec_methods
};


在filter定义里面,id是用来标示每个filter的唯一标示符;name是起得一个名称;text是描述,上面就表示该filter是基于ffmpeg的H.264解码;category是分类,有解码器,编码器和其它三种类型;enc_fmt表示媒体类型;ninputs表示input个数,可能每个filter有多个输入接口;noutputs表示输出接口;init定义初始化函数,在调用filter之前必须 调用;process是最核心的处理函数,filter从input端接收数据就调用该函数进行数据处理;uninit定义退出函数;methods表示额外定义的一些函数,使用这个接口可以对filter进行一些参数设置工作,比如在上面的h.264解码filter中定义了专门的函数用来设置h.264解码所需要的fmtp信息。除了mediastream2自带的这些filter以外,我们还可以自己定义filter,按照上面的格式来定义,然后通过ms_filter_register函数注册进来就可以使用了。在我们系统中我们使用ms_rtp_recv_desc来完成rtp的接收解析,使用ms_h264_dec_desc来完成视频解码,使用ms_android_opengl_display_desc来完成在android上的显示。

定义完成了3个filter,接收流,解码并显示,这三个filter是如何创建并连接在一起并工作起来呢?见下面的代码注释


MSConnectionHelper ch;
    /*根据ipcam video的codec来创建相应的解码器filter,创建失败,则退出,在我们系统里面一般是h.264,但我们可以根据rtp媒体类型在自适应选择对应的解码filter*/
    stream->decoder=ms_filter_create_decoder(ipcam_get_codec("video")); // 创建解码filter
    if (stream->decoder==NULL)
    {
        /* big problem: we don't have a registered decoderfor this payload...*/
        ms_error("videostream.c: No decoder available  ");
        return -1;
    }


    /*创建rtp接受filter*/
    stream->rtprecv = ms_filter_new (MS_RTP_RECV_ID);//创建RTP接收filter,通过MS_RTP_RECV_ID找到ms_rtp_recv_desc这个filter

   /*创建rtp接收filter,需要设置rtp接收filter的会话,会话主要是接收媒体流的socket,告诉filter再哪个socket上接收rtp数据,并限制接收什么样的rtp数据,通过payload type*/

/*stream->session这个是_RtpSession*, 是mediastream2定义的结构体*/
    ms_filter_call_method(stream->rtprecv,MS_RTP_RECV_SET_SESSION,stream->session);
    ms_message("ssap_ipcam_client_open:session rtpsocket=%d,rtcpsocket=%d",stream->session->rtp.socket,stream->session->rtcp.socket);


    /*创建output filter,默认是MSAndroidDisplay,表示输出到android上,通过MSAndroidDisplay找到ms_android_opengl_display_desc*/
    displayName = ms_strdup("MSAndroidDisplay");
    stream->output=ms_filter_new_from_name(displayName);


    /*以下是设置fmtp,非常重要,如果不添加fmtp,将会解码失败,mpeg4需要的fmtp在rtsp中是在sdp中
    带过来的,因此要获取fmtp*/
    char fmtp[1000];
    memset(fmtp,0,sizeof(fmtp));
    sprintf(fmtp,"config=%s",ipcam_get_fmtp("video"));
    ms_message("ipcam fmtp=%s",fmtp);
    ms_filter_call_method(stream->decoder,MS_FILTER_ADD_FMTP,(void*)fmtp);
    format=MS_YUV420P;
    ms_filter_call_method(stream->decoder,MS_FILTER_SET_PIX_FMT,&format);


    int tmp;
    /*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_message("v2 sam display windows id=%d,stream=%p",stream->window_id,stream);
        /*设置显示的窗口id,在哪个窗口上显示video*/
        ms_filter_call_method(stream->output, MS_VIDEO_DISPLAY_SET_NATIVE_WINDOW_ID,stream->window_id);
    }


 /*以上完成了3个filter的创建,接下来将3个filter串联起来*/
    /* 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);


    ms_connection_helper_link (&ch,stream->output,0,-1);


  /*filter串联起来了以后,开始启动定时器,整个系统流程开始运转起来*/
    /* create the ticker */
    stream->ticker = ms_ticker_new();
    ms_ticker_set_name(stream->ticker,"Video MSTicker");
    /* attach the graphs */
    if (stream->source)
        ms_ticker_attach (stream->ticker, stream->source);
    if (stream->rtprecv)
        ms_ticker_attach (stream->ticker, stream->rtprecv);


至此,mediastream2就开始运转起来了

             

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值