最近在解决一个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 
版权声明:本文为博主原创文章,转载请附上博文链接!

Freeswitch的mod_av模块优化相关推荐

  1. Android计步模块优化(今日步数)

    简书地址:https://www.jianshu.com/p/cfc2a200e46d github地址:https://github.com/jiahongfei/TodayStepCounter ...

  2. 新一代FreeSWITCH电话机器人模块

    介绍 FreeSWITCH 电话机器人模块,包含脚本解析引擎和话术编辑器2部分.如果需要测试可以联系我的微信:cdevelop 话术编辑器 话术编辑器是一个图形化的应用程序,通过图形化编辑话术流程,生 ...

  3. FreeSWITCH之SIP 模块 - mod_sofia

    转自:http://www.freeswitch.org.cn/2010/08/03/di-qi-zhang-sip-mo-kuai-mod_sofia.html SIP 模块是 FreeSWITCH ...

  4. FreeSWITCH 背景音模块

    FreeSWITCH 背景音模块,可以给通话,添加一个背景音,比如办公室的噪音,键盘敲击声,等. FreeSWITCH 背景音模块,有什么用处?你肯定想不到吧. 我们电话机器人一般都是人工录音,机器人 ...

  5. nginx strip模块优化页面

    为什么80%的码农都做不了架构师?>>>    nginx strip模块删除不必要的空格 在nginx官方wiki的第三方模块中看到nginx strip模块,简单的看下功能,大意 ...

  6. php的优化模块,php memcache模块优化配置详解

    在php中memcache是一个缓存功能,可以提高数据访问性能同时减少机器负载,下面我来介绍php中memcache优化方法吧. memcache support enabled Active per ...

  7. freeswitch修改mod_sofia模块并上报自定义头域

    概述 在之前的文章中,我们介绍了如何使用fs的event事件机制来获取呼叫的各种信息. 这些event事件一般都是底层模块定义好的,其中的各种信息已经很完备了,日常的开发需求都可以满足. 但是,总有一 ...

  8. FreeSWITCH的SIP模块mod_sofia详解

    为什么80%的码农都做不了架构师?>>> mod_sofia模块是FreeSWITCH默认使用的SIP协议栈,FreeSWITCH默认带了三个Profile(也就是三个UA),其配置 ...

  9. freeswitch 变声模块mod_soundtouch、mod_ladspa

    官方地址: https://freeswitch.org/confluence/display/FREESWITCH/mod_soundtouch app使用demo: <action appl ...

最新文章

  1. Android系统源码导入Android studio
  2. 读jQuery源码释疑笔记
  3. element手机验证格式_基于Vue+elementUI实现动态表单的校验功能(根据条件动态切换校验格式)...
  4. Android 系统性能优化(23)---绘制性能优化
  5. HALCON 20.11:深度学习笔记(3)---Data(数据)
  6. 上海交大计算机专硕学费2018,2018年上海交通大学博士研究生学费与相关奖助政策...
  7. ABP开发框架前后端开发系列---(2)框架的初步介绍
  8. 张宇1000题高等数学 第十三章 多元函数微分学
  9. 安装CLOVER引导器到硬盘EFI分区
  10. iphone6连接电脑后计算机不显示器,苹果手机怎么连接电脑没反应
  11. matlab传递函数状态方程转换,利用matlab对状态方程与传递函数转换
  12. 美丽的夜,一个程序员的思考
  13. 仿真软件scaner studio上手基础操作(一)
  14. 1.2样本空间和随机事件
  15. 嵌入式开发要学习哪些知识
  16. vue中通过定时器设置倒计时,5秒倒计时
  17. 计算机考英语一数学二,这所院校初试科目调整为数一英一!又有专业计划停招!这些信息21考研人一定要知道!...
  18. 实现童年宝可梦,教你用Python画一只属于自己的皮卡丘
  19. imaplib 模块登陆163邮箱及下载
  20. oracle11如何生成aw r,(Oracle)自定义调用AWRamp;ADDM

热门文章

  1. python语言编程函数_Python编程语言的函数功能
  2. 二维码解码芯片最新三款的二维码芯片MCU不同之处
  3. 最大公约数和最小公倍数、判断两数互质
  4. 修改 SSH 端口号
  5. Scratch精通之积木的使用
  6. python合并excel的多个sheet
  7. python panda用法_Python Pandas用法入门
  8. 基于Java毕业设计校园面包超市系统源码+系统+mysql+lw文档+部署软件
  9. manjaro-i3wm 新装系统没有声音问题解决
  10. 基础矩阵和极点、极线关系