ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Freeswitch的mod_av模块优化

2019-07-25 16:02:29  阅读:264  来源: 互联网

标签:temp pkt pts av base time Freeswitch data mod


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

标签:temp,pkt,pts,av,base,time,Freeswitch,data,mod
来源: https://blog.csdn.net/ddddffffggggg/article/details/97268550

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有