Freeswitch的mod_av模块优化

最近在解决一个Freeswitch录制视频后出现视频文件播放花屏问题,大概梳理mod_av模块的录制流程,并做了一些流程上的优化。

mod_av的录制流程如下:

收到的RTP音视频包-> 解码 -> 然后写文件(首先是编码-> 然后调用ffmpeg的音视频混合接口输出为mp4文件)

首先做的流程优化,去掉画中横线的两个流程,直接将接收到的编码帧写文件:

收到的RTP音视频包-> 解码 -> 然后写文件(首先是编码-> 调用ffmpeg的音视频混合接口输出为mp4文件)


然后把录制出来的文件播放,发现还是花屏,多次尝试后发现,是在调用av_packet_rescale_ts后,才调用av_interleaved_write_frame,而av_packet_rescale_ts函数则是把AVCodecContext 的time_base转换为AVStream的time_base,先看看time_base的理解:ffmpeg存在多个时间基准(time_base),对应不同的阶段(结构体),每个time_base具体的值不一样,ffmpeg提供函数在各个time_base中进行切换。

AVStream->time_base比AVCodecContext->time_base精度要高(数值要小),比如AVStream->time_base为1/90000,而AVCodecContext->time_base为1/30(假设frame_rate为30);同样的pts和dts,以AVStream->time_base为单位,数值要比以AVCodecContext->time_base为单位要大。

编码后,pkt.pts、pkt.dts使用AVCodecContext->time_base为单位,后通过调用"av_packet_rescale_ts"转换为AVStream->time_base为单位。

首先修改time_base的初始化赋值:

原来的值:

        mst->st->time_base.den = 1000;
        mst->st->time_base.num = 1;
        c->time_base.den = 1000;
        c->time_base.num = 1;


修改为:

        mst->st->time_base.den = 90000;
        mst->st->time_base.num = 1;
        c->time_base.den = 25;
        c->time_base.num = 1;


从网络接收到的rtp包是编码后的包,首先需要把多个rtp包组成一个完整的frame的包,然后pts需要重设,代码:


                   if (frame->m) {
                        AVPacket *pkt = (AVPacket *)malloc(sizeof(AVPacket));
                        uint32_t size = switch_buffer_inuse(context_temp->nalu_buffer);
                            if (size > 0){
                                uint8_t *temp_data;         
                                static uint8_t ff_input_buffer_padding[FF_INPUT_BUFFER_PADDING_SIZE] = { 0};
 
                                switch_buffer_write(context_temp->nalu_buffer, ff_input_buffer_padding, sizeof(ff_input_buffer_padding));  //lyz delete
 
                                switch_buffer_peek_zerocopy(context_temp->nalu_buffer, (const void **)&temp_data);
 
                                av_init_packet(pkt);
                                av_new_packet(pkt, size);
                                pkt->size = size;
 
                                if (switch_test_flag(frame, SFF_WAIT_KEY_FRAME)){
                                        pkt->flags        |= AV_PKT_FLAG_KEY;
                                }
 
                                pkt->pts = context_temp->pts++;//context_temp->pts + 40;//((frame->timestamp - context_temp->last_received_timestamp)/90);
                                pkt->dts = pkt->pts; 
                                //pkt->duration = 40;
 
                                //context_temp->pts = pkt->pts;
                                
                                memcpy((unsigned char *)pkt->data, (unsigned char *)temp_data, size);
                                /*
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "write video stream,pkt:%08x, data:%08x, pkt->pts:%d, data[0]:%02x, data[1]:%02x, data[2]:%02x, data[3]:%02x, data[4]:%02x\n", 
                                    pkt, 
                                    pkt->data, 
                                    pkt->pts, 
                                    pkt->data[0],
                                    pkt->data[1],
                                    pkt->data[2],
                                    pkt->data[3],
                                    pkt->data[4]);
                                    */
 
                                context_temp->last_received_timestamp = frame->timestamp;
                                context_temp->last_received_complete_picture = frame->m ? SWITCH_TRUE : SWITCH_FALSE;
 
                                switch_queue_push(context->eh.video_queue, pkt);
                            }
                        
                        switch_buffer_zero(context_temp->nalu_buffer);
                   }


注释掉mod_av原来设置pts的代码,


if (switch_queue_pop(eh->video_queue, &pop) == SWITCH_STATUS_SUCCESS) {
                     switch_img_free(&img);
 
            if (!pop) {
                goto endfor;
            }
 
                    pkt = (AVPacket *)pop;
 
 
 
            ret = write_frame(eh->fc, &eh->video_st->st->codec->time_base, eh->video_st->st, pkt);

后来发现,不修改录制流程,只修改编码时pts的值也能解决这个问题,只需要把eh->video_st->frame->pts每次累加即可。

--------------------- 
作者:twoconk 
来源:CSDN 
原文:https://blog.csdn.net/twoconk/article/details/54575134 
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: freeswitch是一款流媒体通讯服务器,其中包含了很多方便实用的模块mod_av是其中之一,它提供了音视频媒体的处理能力。RTMP协议是一种用于流媒体传输的协议。因此,freeswitch中的mod_av模块可以用来录制RTMP流。 在使用freeswitch录制RTMP流的过程中,需要先安装并配置好mod_av模块。然后,通过freeswitch提供的API接口,指定要录制的RTMP流地址、录制文件的保存路径、录制时长等信息。使用指定的录制参数启动录制后,freeswitch会自动将指定的RTMP流数据进行录制,并将录制的数据保存到指定的路径中。 需要注意的是,在使用freeswitch录制RTMP流的过程中,需要保证录制环境的稳定性和流畅性。特别是在网络条件不好的情况下,可能会影响到录制效果。因此需要根据实际情况进行有针对性的配置和优化。 总之,freeswitch mod_av模块能够方便地实现RTMP流的录制,是在流媒体应用中的一项重要功能。 ### 回答2: Freeswitch是一款开源的电话软交换平台。它提供了丰富的语音通信功能,包括SIP和其他语音协议的呼叫管理、音频编解码和流处理、媒体转码和路由等功能。Mod_avFreeswitch提供的一个模块,它提供了一系列的媒体功能,包括音频流的录制、转码和回放等。 RTMP是一种流媒体协议,它主要用于在线视频直播和点播。RTMP通过一组可靠的传输协议,在网络上传输视频和音频流。RTMP支持低延迟、多路复用、流控和安全传输等功能,在在线视频直播和点播中得到广泛应用。 Freeswitch mod_av支持通过RTMP协议录制音频和视频流。使用mod_av录制RTMP流需要在Freeswitch中配置一个录制计划。可以通过Freeswitch提供的命令行工具路由呼叫到这个计划,实现录制功能。录制计划中需要指定录制格式、音频编解码、视频编解码、录制文件名等参数。 通过Freeswitch mod_av录制RTMP流可以实现实时录制音视频直播,并将录制文件保存到本地或远程服务器。录制文件可以用于后续处理、回放和存档等用途。同时,通过Freeswitch的扩展性,可以将录制功能与其他语音通信功能结合使用,实现更为丰富的语音应用场景。 综上所述,Freeswitch mod_av支持通过RTMP协议录制音视频流,为在线视频直播和点播提供了可靠的录制功能。它的使用需要一定的配置和命令行操作,但是具备良好的扩展性和丰富的媒体功能,可以满足不同应用场景的需求。 ### 回答3: freeswitch是一个功能强大的开源通信软件,支持视频会议和流媒体通信等多种功能。而mod_avfreeswitch中的模块之一,它可以用来录制音频和视频。而在录制音频和视频时,我们可能会需要使用到rtmp协议。那么,如何使用freeswitch mod_av录制rtmp呢? 首先,要使用freeswitch mod_av录制rtmp,我们需要在mod_av模块中设置相关参数。具体来说,我们需要设置以下参数: 1. av_format:指定录制的文件格式,通常为mp4或flv格式。 2. av_mode:指定录制的模式,可以是in、out或all。其中,in表示只录制输入流,out表示只录制输出流,all表示录制所有流。 3. av_codec:指定录制的编码格式。通常可以选择h.264或AAC。 接下来,我们需要将mod_av模块与rtmp绑定。具体来说,我们可以在freeswitch的配置文件中,将rtmp的地址和mod_av的相关参数加入到录制规则中。 例如,在录制出站呼叫的过程中,我们可以将rtmp的地址和mod_av的参数设置如下: <record name="outcall" max-size="100M" format="$${av_format}" mode="$${av_mode}" codec="$${av_codec}"> <param name="path" value="$${base_dir}/recordings/${caller_id_number}_${strftime(%Y%m%d%H%M%S)}.mp4"/> <param name="rtmp_url" value="rtmp://127.0.0.1/recordings/${caller_id_number}_${strftime(%Y%m%d%H%M%S)}.mp4"/> </record> 其中,rtmp_url参数指定了rtmp的地址,用于将录制的音视频数据实时传输到指定的地址。 最后,启动freeswitch并测试录制功能。如果一切正常,我们就可以在指定的rtmp地址上看到实时录制的音视频数据了。 综上所述,使用freeswitch mod_av录制rtmp需要设置相关的参数,并将mod_av模块与rtmp绑定。只有这样,我们才能实现高效、可靠的音视频录制功能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值