树莓派sip视频电话-5:baresip-0.5.10

在gitbub中找到baresip这个软件,经过修改可以在树莓派上稳定运行。
一、存在问题:
1.在使用libomxcam(github上)库时候,1080p@30时候帧速只能达到15,且有蓝边。不知道什么原因造成的。
2.在使用webapp模块(修改github上的)时候,退出时候有异常。
3.可能还有其他不稳定情况。
二、编译修改过程:
代码已上传至github上:https://github.com/yangaphero/baresip-rpi

1.安装re
  (1)make
  (2)sudo make install

2.安装rem
  (1)make
  (2)sudo make install

3.安装baresip
  (1)make
  (2)sudo make install  可省
注意配置文件在~/.baresip/config中修改
  (3)debug and release
    Build with debug enabled
    $ make
    $ sudo make install

    Build with release
    $ make RELEASE=1
    $ sudo make RELEASE=1 install

4.错误修改
(1)alsa播放程序时候出现alsa: write: wrote 80 of 160 samples
在err = alsa_reset()函数下面添加一下代码
在alsa模块中alsa_play.c中初始化部分,添加以下代码:解决
snd_pcm_set_params(st->write,
                    SND_PCM_FORMAT_S16_LE,//SND_PCM_FORMAT_U8,
                    SND_PCM_ACCESS_RW_INTERLEAVED,/* snd_pcm_readi/snd_pcm_writei access */
                    1, //Channels
                    8000, //sample rate in Hz
                    1, //soft_resample
                    500000);
(2)在vidloop停止时候
    1.出现~~~~ Videoloop summary: ~~~~~段错误 (核心已转储)
    是因为re_hprintf时候无法解析 vs->name  也就是module模块名称
    同时在vidloop时候,也出现Enable video-loop on ,: 1280 x 720   模块名称为空
    解决办法:在vidloop模块中暂时屏蔽掉vs->name,后面再处理
    2.在video_debug时候出现:
            --- Video stream ---
             started: yes
             tx: encode: H264 ?
            段错误 (核心已转储)
    解决办法:在src/video.c中的vtx_debug函数中修改:注释掉名称,同时增加了send-frames=%d=vtx->frames这个变量值显示,在debug时候查看是否25帧时候5秒钟是否可以达到125个,即为25帧速率
    //err |= re_hprintf(pf, "     source: %s %u x %u, fps=%.2f"
    //          " frames=%llu\n",
    //          vtx->vsrc ? vidsrc_get(vtx->vsrc)->name : "none",
    err |= re_hprintf(pf, "     source: %u x %u, fps=%.2f"
              " frames=%llu send-frames=%d\n",
              //vtx->vsrc ? vidsrc_get(vtx->vsrc)->name : "none",
              vtx->vsrc_size.w,
              vtx->vsrc_size.h, vtx->vsrc_prm.fps,
              vtx->stats.src_frames,vtx->frames);
(3)使用omx硬件编码器的问题
修改avcodec模块中的encode.c,添加sps pps发送
    (1)修改avcodec模块module.mk,注释掉#USE_X264,这样才能使用omx硬件编码,
    重要:omx编码器阻塞的问题,即avcodec_send_frame()后阻塞进程,不往下走
    根据2018-3-9:记录:关于编码器阻塞的问题: 基本解决,分2部分:(搞死我啦!!!!!!!!!!!!)
    a.在打开解码器中添加:open_encoder函数中
    在#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(5<<8)+0)
    st->pict->format = pix_fmt;
    st->pict->width = size->w;
    st->pict->height = size->h; 下面添加:
        ret = av_frame_get_buffer(st->pict, 32);
        if (ret < 0)    debug("avcodec: Could not allocate the video frame data\n");
    b.在循环编码中添加:在encode函数中,在    for (i=0; i<4; i++) {之前添加:
        ret = av_frame_make_writable(st->pict);
        if (ret < 0)  debug("avcodec: Could not av_frame_make_writable\n");

    (2)添加cbr固定速率控制  在open_encoder函数中
        av_opt_set_defaults(st->ctx);
        //cbr固定速率
        st->ctx->bit_rate  = prm->bitrate;
        st->ctx->rc_min_rate =prm->bitrate;
        st->ctx->rc_max_rate = prm->bitrate;
        st->ctx->bit_rate_tolerance = prm->bitrate;
        st->ctx->rc_buffer_size=prm->bitrate;
        st->ctx->rc_initial_buffer_occupancy = st->ctx->rc_buffer_size*3/4;
        //st->ctx->rc_buffer_aggressivity= (float)1.0;
        //st->ctx->rc_initial_cplx= 0.5;
    (3)添加编码质量控制:不知道起不起作用 在open_encoder函数中
        st->ctx->max_qdiff = 4;
        //by aphero
        //av_opt_set(st->ctx, "preset", "veryslow", 0);
        av_opt_set(st->ctx, "crf", "18.000", 0);
        //av_opt_set(st->ctx, "preset", "slow", 0);
        av_opt_set(st->ctx, "preset", "superfast", 0);
        av_opt_set(st->ctx, "tune", "zerolatency", 0);
        //av_opt_set(st->ctx, "profile", "baseline", 0);   //有错误    

    (4)添加extradata信息:下一步发送sps pps要用到
        st->ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;//by aphero,添加后ffmpeg会将sps pps存入到extradata中,
    
    (5)添加关键帧判断,主要是判断I帧,然后在I帧前发送sps pps:
        (a):在encode函数开头申明部分添加
            int key_frame=0;//by aphero
        (b):在这个
            err = mbuf_write_mem(st->mb, pkt->data, pkt->size);
            st->mb->pos = 0;下面添加
            if(pkt->flags & AV_PKT_FLAG_KEY){//by aphero
                key_frame=1;
            }
        (c):在
            case AV_CODEC_ID_H264:下面添加
                if((st->ctx->extradata)&&(key_frame==1)){//by aphero
                    err = h264_packetize(ts, st->ctx->extradata, st->ctx->extradata_size, st->encprm.pktsize, st->pkth, st->arg);
                    key_frame=0;
        (6)修改
            enum {
                DEFAULT_GOP_SIZE =   25,//by aphero
            };
        (7)修改
if (st->codec_id == AV_CODEC_ID_H264) {
        //av_opt_set(st->ctx->priv_data, "profile", "baseline", 0);//by aphero 注释掉
(5)修改src/video.c文件,里面的发送过程分析,见原0.5.8版本中的video.c文件中有分析过程
    1.enum {
        //    MEDIA_POLL_RATE = 250,                 /**< in [Hz]             */
        MEDIA_POLL_RATE = 200,                 /**< in [Hz]             */每隔4ms调度
        BURST_MAX       = 81920*2,                /**< in bytes            *///by aphero    添加
    2.在vidqueue_poll函数中
        注释掉下面部分,添加突发为最大
            //bandwidth_kbps = vtx->video->cfg.bitrate / 1000;
            //burst = (1 + jfs - prev_jfs) * bandwidth_kbps / 4;
            //burst = min(burst, BURST_MAX);
            burst = BURST_MAX;//by aphero,重要
    3.在video_encoder_set函数中修改
        prm.pktsize = 1400;//by aphero 原来是:1024
    4.在encode_rtp_send()函数中修改
        if (!sendq_empty) {//sendq_empty=0跳过帧,队列不为空就跳过此帧 by aphero
            //info("video:send frame skipc=%d sendq=%d \n",vtx->skipc,list_count(&vtx->sendq));
            ++vtx->skipc;
            //return;//这里为什么要返回,继续发送不行吗****暂时禁止,继续编码,存入队列*******这里意思应该是,上一包(整个帧)未发送完成,就跳过本包***********************
        }

(6)修改omx_render不能切换视频问题
        在omx_display_enable函数中
            (1):运行中切换视频,需要先关闭端口,再释放内存
                在OMX_ERRORTYPE err = 0;下面添加
                OMX_STATETYPE eState;//by ahpero
                info("omx:omx_update_size %d %d\n", width, height);
                
                //by aphero 2018-2-23    
                OMX_GetState(st->video_render, &eState);
                if (eState == OMX_StateExecuting) {
                    err = OMX_SendCommand(st->video_render,OMX_CommandStateSet, OMX_StateIdle, NULL);//可以不用设置
                    //info("OMX_SendCommand  OMX_StateIdle err=%d\n",err);
                    err = OMX_SendCommand(st->video_render,OMX_CommandStateSet, OMX_StateLoaded, NULL);//可以不用设置
                    //info("OMX_SendCommand  err=%d\n",err);
                    err = OMX_SendCommand(st->video_render,OMX_CommandFlush, VIDEO_RENDER_PORT, NULL);
                    //info("OMX_CommandFlush  err=%d\n",err);
                    err = OMX_SendCommand(st->video_render,OMX_CommandPortDisable, VIDEO_RENDER_PORT, NULL);//必须关闭端口使能,否则无法设置端口
                    //if (err) warning("OMX_CommandPortDisable: err\n");
                    
                    //释放渲染器的缓存空间,这里必须释放,否则vidframe_init_buf出现段错误
                    if (st->buffers) {
                        OMX_FreeBuffer(st->video_render, VIDEO_RENDER_PORT,st->buffers[0]); //默认是3个,portdef.nBufferCountActual=3
                        OMX_FreeBuffer(st->video_render, VIDEO_RENDER_PORT,st->buffers[1]);
                        OMX_FreeBuffer(st->video_render, VIDEO_RENDER_PORT,st->buffers[2]);
                        free(st->buffers);
                        st->buffers=NULL;
                        st->num_buffers = 0;
                        st->current_buffer = 0;
                    }
                }
                info("omx_update_size %d %d\n", width, height);
            (2):如果端口关闭,需再次打开
                info("1-omx port definition: h=%d w=%d s=%d sh=%d bEnabled=%d\n",    portdef.format.video.nFrameWidth,portdef.format.video.nFrameHeight,               portdef.format.video.nStride,portdef.format.video.nSliceHeight,portdef.bEnabled);

                    if(portdef.bEnabled != 1){//如果端口关闭就打开
                        err |=OMX_SendCommand(st->video_render,OMX_CommandPortEnable, VIDEO_RENDER_PORT, NULL);//前面关闭了,一定要打开,aphero
                    }
            (3):1080P不能播放问题:出现端口定义出错
                修改端口定义,但是视频下面有一道蓝边
                portdef.format.video.nStride = 0;//设置为0,1080p不出错 原portdef.format.video.nStride = stride;
                portdef.format.video.nSliceHeight = 0;//设置为0,原portdef.format.video.nSliceHeight = height;
            (4)也可以修改显示窗口大小,好像有问题
                #ifdef RASPBERRY_PI
                    memset(&config, 0, sizeof(OMX_CONFIG_DISPLAYREGIONTYPE));
                    config.nSize = sizeof(OMX_CONFIG_DISPLAYREGIONTYPE);
                    config.nVersion.nVersion = OMX_VERSION;
                    config.nPortIndex = VIDEO_RENDER_PORT;
                    config.fullscreen = 1;
                    config.set = OMX_DISPLAY_SET_FULLSCREEN;
                    //config.fullscreen = OMX_FALSE;
                    //config.noaspect   = OMX_TRUE;
                    //config.set                 = (OMX_DISPLAYSETTYPE)(OMX_DISPLAY_SET_DEST_RECT|OMX_DISPLAY_SET_SRC_RECT|OMX_DISPLAY_SET_FULLSCREEN|OMX_DISPLAY_SET_NOASPECT);
                    //config.dest_rect.x_offset  = 0;
                    //config.dest_rect.y_offset  = 0;
                    //config.dest_rect.width     = 1920;
                    //config.dest_rect.height    = 1080;
(7)avformat修改
    1.在alloc()函数中:int input_fps = 0;下面添加:
    char h264dec[64];
    AVDictionary* options = NULL;
    av_dict_set(&options, "buffer_size", "4096000", 0);
    av_dict_set(&options, "max_delay", "500000", 0);
    av_dict_set(&options, "stimeout", "20000000", 0);  //设置超时断开连接时间
    //av_dict_set(&options, "rtsp_transport", "tcp", 0);  //以udp方式打开,如果以tcp方式打开将udp替换为tcp  
    //av_dict_set(&options, "probesize", "4096", 0);
    2.在alloc()函数st->fps    = prm->fps;下面添加    
    avformat_network_init(); //by aphero
    3.在alloc()函数中添加硬件解码,因为AVformat是先解码成yuv格式后,在编码,不管以前是不是h264还是MP4等
    修改这部分代码:if (ctx->codec_id != AV_CODEC_ID_NONE) {
            st->codec = avcodec_find_decoder(ctx->codec_id);
    修改如下:
        if (0 == conf_get_str(conf_cur(), "avcodec_h264dec", h264dec, sizeof(h264dec))) {
                info("avformat: using h264 decoder by name (%s)\n", h264dec);
             st->codec = avcodec_find_decoder_by_name("h264_mmal");//by aphero  直接指定了解码器,不妥
        }else{
                        st->codec = avcodec_find_decoder(ctx->codec_id);
       }
    4.    添加参数
        //ret = avformat_open_input(&st->ic, dev, NULL, NULL);
        ret = avformat_open_input(&st->ic, dev, NULL, &options);//by phero
    5.显示文件信息
        #if 1 //by aphero 改为1
            av_dump_format(st->ic, 0, dev, 0);
        #endif
(8)baresip-0.5.10版本中已添加视频源切换功能,/vidsrc ....
    /vidsrc avformat,/home/pi/aidedaijia.mkv

(9)修改src/stream.c文件
    1.修改接收缓存大小
    enum {
        //RTP_RECV_SIZE = 8192,
        RTP_RECV_SIZE = 81920,//by aphero
    2.在stream_sock_alloc()函数中添加
    //udp_sockbuf_set(rtp_sock(s->rtp), 65536);
    udp_sockbuf_set(rtp_sock(s->rtp), 20*1024*1024);//by aphero
5.安装自定义模块
(1)安装omxcam摄像头模块
1.安装libomxcam库
   a.make -f Makefile-shared
   用动态连接库,静态或直接编译有问题,注意关闭调试debug
   b.复制so文件和h文件到/usr/local/lib include
2.在modules.mk中添加2部分内容
USE_OMXCAM := $(shell [ -f $(SYSROOT)/include/omxcam.h ] || \
    [ -f $(SYSROOT)/local/include/omxcam.h ] || \
    [ -f $(SYSROOT)/include/$(MACHINE)/omxcam.h ] || \
    [ -f $(SYSROOT_ALT)/include/omxcam.h ] && echo "yes")

    ifneq ($(USE_OMXCAM),)
    MODULES   += omxcam
    endif
3.修改代码,在0.5.10版本中发送帧函数参数发生变化
    st->frameh(&frame,timestamp, st->arg);增加了timestamp参数
    参考cairo模块代码改写
    开头定义uint64_t ts = 0, ts_start;
    在on_data_time函数中
    if (current == frame_size){//接收到一个完整的帧
        uint64_t now;
        uint64_t timestamp;
        now = tmr_jiffies();
        if (!ts) {
            ts = ts_start = now;
        }
        if (ts > now) return;
        timestamp = (ts - ts_start) * VIDEO_TIMEBASE / 1000;
        timestamp = (ts - ts_start) * 90000 / 1000;//应该是这个
        

        在结束处修改:
        st->frameh(&frame,timestamp, st->arg);//这里直接发送yuv帧,会导致帧速率下降,采用线程有一定的缓解,但是还是达不到满速率
        ts += 1000/st->prm.fps;

(2)安装webapp控制界面,生成的配置文件在~/.baresip/下json文件
   1. 在mk/modules.mk中MODULES   += menu contact vumeter mwi account natpmp httpd 添加
    MODULES   += menu contact vumeter mwi account natpmp httpd webapp
    2.网页文件采用16进制方式,在module-aphero/webapp-html文件夹下使用htmltohex.py或html-hex.py将原html文件转换成hex,然后复制到modules/webapp/assets/相应的h文件中,需手动计算长度len

----------------------------2018年7月18日-上午-----------------
程序在切换视频源的时候还有问题,1是切换花屏,2是有时候切换后半天不出图像,卡住不动,真妈的!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
问题原因:因为新版改写了发送时候使用采集时候的时间戳,导致切换视频后,时间戳重新开始计数,导致freeswitch不能及时回传给客户端。
原来版本0.5.8中切换视频时间戳继续增量,不重新计数。
解决办法:使用0.5.8版本中的方法,不使用采集时间戳,采用编码器中pts自增量
在avcodec中encode.c
1.添加
struct videnc_state {
    AVCodec *codec;
    AVCodecContext *ctx;
    AVFrame *pict;
    struct mbuf *mb;
    size_t sz_max; /* todo: figure out proper buffer size */
    int64_t pts;//by aphero   增加
2.    不使用采集时间戳
    //st->pict->pts = timestamp;
    st->pict->pts = st->pts++;//by aphero
3.计算时间戳
    //ts = video_calc_rtp_timestamp_fix(pts);
    ts = video_calc_rtp_timestamp(pts, st->encprm.fps);//by aphero
这个baresip-aphero-0.5.10-20180718.tar.gz为修改后版本,可正常使用

-----------------------------------------2018年7月18日下午-------------------------------------------
1.添加vidosd模块,用于显示台标----目前使用cairo现实,cpu有点高
        1.复制vidosd文件夹到modules目录下,修改mk/modules.mk文件添加
        ifneq ($(USE_CAIRO),)
        MODULES   += cairo
        MODULES   += vidinfo
        MODULES   += vidosd
        2.修改中文字体 ,在panel_osd.c文件中
            cairo_select_font_face (panel->cr, "WenQuanYi Micro Hei Mono",//下载中文字体,使用 "fc-list" 命令查看系统所安装字体
                        CAIRO_FONT_SLANT_NORMAL,
                        CAIRO_FONT_WEIGHT_NORMAL);
        需下载中文字体,使用 "fc-list" 命令查看系统所安装字体https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.3.tar.gz
        sudo apt-get install ttf-wqy-microhei  #文泉驿-微米黑
        sudo apt-get install ttf-wqy-zenhei  #文泉驿-正黑
        sudo apt-get install xfonts-wqy #文泉驿-点阵宋体
        3.设置osd台标,在vidosd.c中encode()函数中
        err = panel_alloc_osd(&st->panel, "树莓派视频电话", 0, width, height);
        4.在config中设置
        # Video filter Modules (in encoding order)
        module            vidosd.so
        module            selfview.so
2.树莓派支持omx和sdl2两种显示模式
    sudo apt-get install libsdl2-dev
    有问题,暂时不管了,提示找不到设备
-----------------------------------------2018年7月24日晚-------------------------------------------
关于SDL2的问题
树莓派中默认是SDL1.2,即使sudo apt-get install libsdl2-dev,没有找到libsdl2.so这个文件,可能有。
SDL2已经支持树莓派了,使用opengles,可实现硬件加速,但是没有直接使用omx显示的速率高,有点卡顿,vidloop h264自环时候fps为15左右
安装方法:不能使用apt-get安装
1.下载4个源码包,只要SDL2这个包也行
SDL2:https://www.libsdl.org/release/SDL2-2.0.8.tar.gz
SDL_mixer:https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-2.0.2.tar.gz
SDL2_ttf:https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-2.0.14.tar.gz
SDL2_net:https://www.libsdl.org/projects/SDL_net/release/SDL2_net-2.0.1.tar.gz
SDL2_image:https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.3.tar.gz
2.编译
  ./autogen.sh   ./configure  能够自动识别树莓派  make   sudo make install
3.修改baresip的SDL2的mk文件,如下:
    MOD        := sdl2
    $(MOD)_SRCS    += sdl.c
    $(MOD)_CFLAGS    := -g -O2 -D_REENTRANT -I/usr/local/include/SDL2 -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux  -DHAVE_OPENGLES -DHAVE_OPENGLES2 -DHAVE_OPENGL -DHAVE_SDL_TTF -g
    $(MOD)_LFLAGS    += -L/usr/local/lib -Wl,-rpath,/usr/local/lib -Wl,--enable-new-dtags -lSDL2

    include mk/mod.mk
就不会出现编译sdl2.so成功,但出现(没有有效的视频设备)
但是有点卡

SDL2隐藏鼠标:在display函数中添加SDL_ShowCursor(0);

-----------------------------------------2018年7月25日晚-------------------------------------------
添加树莓派gpio控制
    1.在mk/modules.mk中添加
    USE_OMX_GPIO := $(shell [ -f /opt/vc/include/bcm_host.h ] || \
        [ -f /usr/include/wiringPi.h ] \
        && echo "yes")

    ifneq ($(USE_OMX_GPIO),)
    MODULES   += gpio
    endif
    不使用wiringpi情况下可直接添加:MODULES   += gpio
    2.在config文件中添加
    module_app        gpio.so

    3.在gpio的mk文件中
    添加:$(MOD)_LFLAGS    += -lpthread -lwiringPi
使用lwiringPi 需要root权限,最后还是使用了/sys/class/gpio 的方式控制

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值