视频流传输并做实时分析过程记录

最近完成了实时视频流做图像算法分析的工程,记录下整体流程和关键步骤。

1.项目中使用RTP协议H264载荷传输视频数据,流媒体服务器收到流数据解封装提取出H264数据进行解码,解码函数:

int CITStreamTrans::StreamDec(unsigned char* buffer_in, int32_t bufferLen_in, unsigned char** yuv_out,int32_t &bufferLen_out){

int ret;

    AVPacket packet = { 0 };

    packet.data = (uint8_t*)buffer_in;   

    packet.size = bufferLen_in; 


packet.pts = FRAME_TIMESTAMP * m_nFrameCounter++;

    ret = avcodec_send_packet(_pDecCodecContext, &packet);

    //return ret;

    if (avcodec_receive_frame(_pDecCodecContext, _pFrameYuv) == 0)

    {

    m_nCodecID = m_nCodecID == 0 ? _pDecCodecContext->codec_id: m_nCodecID;

m_nWidth = m_nWidth == 0 ? _pDecCodecContext->width : m_nWidth;

m_nHeight = m_nHeight == 0 ? _pDecCodecContext->height : m_nHeight;

m_nFps = m_nFps == 0 ? ENCODE_DEFAULT_FRAMERATE : m_nFps;

m_nMbps = m_nMbps == 0 ? ENCODE_DEAULT_BITRATES : m_nMbps;

_pFrameYuv->pts = _pFrameYuv->best_effort_timestamp;

        //int height = _pCodecContext->height;

        //int width = _pCodecContext->width;

        av_packet_unref(&packet);

if(false){

//禁用硬解码

AVFrame *tmp_frame = NULL;

if (_pFrameYuv->format == hw_pix_fmt)

{

/* retrieve data from GPU to CPU */

if ((ret = av_hwframe_transfer_data(m_pSWFrame, _pFrameYuv, 0)) < 0)

{

printf("Error transferring the data to system memory\n");

return -1;

}

//tmp_frame = m_pSWFrame;

}

//else

// tmp_frame = m_pSrcFrame;

if(alloc_rgb_buf_size ==0)

alloc_rgb_buf_size = av_image_alloc(dst_data, dst_linesize,m_nWidth, m_nHeight, AV_PIX_FMT_BGR24, 1);

if (yuvtorgb_ctx == NULL) {

yuvtorgb_ctx = sws_getContext(m_nWidth, m_nHeight,(AVPixelFormat)m_pSWFrame->format, m_nWidth, m_nHeight, AV_PIX_FMT_BGR24,

  SWS_BICUBIC, NULL, NULL, NULL);

}

sws_scale(yuvtorgb_ctx, (const uint8_t* const*)m_pSWFrame->data,m_pSWFrame->linesize,0, m_nHeight, dst_data, dst_linesize);

*yuv_out = dst_data[0];

//*yuv_out  = m_pSWFrame->data[0];

bufferLen_out = m_nWidth*m_nHeight*3;

return 0;

}

else{

if(alloc_rgb_buf_size ==0)

alloc_rgb_buf_size = av_image_alloc(dst_data, dst_linesize,m_nWidth, m_nHeight, AV_PIX_FMT_BGR24, 1);

if (yuvtorgb_ctx == NULL) {

//yuvtorgb_ctx = sws_getContext(m_nWidth, m_nHeight,AV_PIX_FMT_YUV420P, m_nWidth, m_nHeight, AV_PIX_FMT_BGR24,

//   SWS_BICUBIC, NULL, NULL, NULL);

yuvtorgb_ctx = sws_getContext(m_nWidth, m_nHeight,AV_PIX_FMT_YUV420P, m_nWidth, m_nHeight, AV_PIX_FMT_BGR24,

  SWS_BICUBIC, NULL, NULL, NULL);

}

sws_scale(yuvtorgb_ctx, (const uint8_t* const*)_pFrameYuv->data,_pFrameYuv->linesize,0, m_nHeight, dst_data, dst_linesize);

*yuv_out = dst_data[0];

bufferLen_out = m_nWidth*m_nHeight*3;

//memcpy(yuv_out,_pFrameRgb->data,bufferLen_out);

        return 0;

}

    }else{

return -1;

}

}

由于算法分析使用RGB数据,上述函数中直接将YUV数据转成RGB输出。

2.实时视频的图像算法处理分析,算法分析需要耗时。所以为了避免出现线程阻塞和累计视频延迟问题,需要将发送分析和接受分析分开处理。异步模式需要处理好数据同步。

3.取到算法分析后的数据后,进行滤镜处理最后编码发送

int CITStreamTrans::StreamEnc(unsigned char * buffer_in, int32_t bufferLen_in, unsigned char ** pkt_out, int32_t & bufferLen_out,bool bfilter){

av_image_fill_arrays(av_frame_enc_src->data, av_frame_enc_src->linesize, buffer_in, AV_PIX_FMT_BGR24, m_nWidth,\

                        m_nHeight, 1);

if (rgbtoyuv_ctx == NULL) {

        rgbtoyuv_ctx = sws_getContext(m_nWidth, m_nHeight, AV_PIX_FMT_BGR24, m_nWidth, m_nHeight, \

            AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR, NULL, NULL, NULL);

}

sws_scale(rgbtoyuv_ctx,(const uint8_t* const*)av_frame_enc_src->data,av_frame_enc_src->linesize,0,m_nHeight,av_frame_enc->data,av_frame_enc->linesize);

int ret = -1;

if(bfilter)

{

Filterinit(av_frame_enc->width,av_frame_enc->height);

av_frame_enc->pts = av_frame_enc->best_effort_timestamp;

if (av_buffersrc_add_frame_flags(buffersrc_ctx, av_frame_enc, AV_BUFFERSRC_FLAG_KEEP_REF) < 0) {

av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraph\n");

return -1;

}

while(1){

ret = av_buffersink_get_frame(buffersink_ctx, filter_frame_out);

if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)

                        return 1;

                if (ret < 0){

return -1;

}

//encoder

av_init_packet(&_pEncpkt);

ret=avcodec_send_frame(_pEncCodecContext, filter_frame_out);

while(ret>=0){

        ret = avcodec_receive_packet(_pEncCodecContext, &_pEncpkt);

        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)

            return 1;

        else if (ret < 0) {

            return -1;

        }

_pEncpkt.pts = av_rescale_q_rnd(_pEncpkt.pts, _pEncCodecContext->time_base, _pEncCodecContext->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));

_pEncpkt.dts = av_rescale_q_rnd(_pEncpkt.dts, _pEncCodecContext->time_base, _pEncCodecContext->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));

_pEncpkt.duration = av_rescale_q(_pEncpkt.duration, _pEncCodecContext->time_base, _pEncCodecContext->time_base);

_pEncpkt.pos = -1;

        _pEncpkt.stream_index = 0;

        memcpy(pEncBuff,_pEncpkt.data,_pEncpkt.size);

*pkt_out = pEncBuff;

        bufferLen_out = _pEncpkt.size;

        av_packet_unref(&_pEncpkt);

    }

av_frame_unref(filter_frame_out);

}

av_frame_unref(filter_in);

}

else{

av_init_packet(&_pEncpkt);

ret=avcodec_send_frame(_pEncCodecContext, av_frame_enc);

    while(ret>=0){

        ret = avcodec_receive_packet(_pEncCodecContext, &_pEncpkt);

        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)

            return 1;

        else if (ret < 0) {

            return -1;

        }

_pEncpkt.pts = av_rescale_q_rnd(_pEncpkt.pts, _pEncCodecContext->time_base, _pEncCodecContext->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));

_pEncpkt.dts = av_rescale_q_rnd(_pEncpkt.dts, _pEncCodecContext->time_base, _pEncCodecContext->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));

_pEncpkt.duration = av_rescale_q(_pEncpkt.duration, _pEncCodecContext->time_base, _pEncCodecContext->time_base);

_pEncpkt.pos = -1;

      _pEncpkt.stream_index = 0;

        memcpy(pEncBuff,_pEncpkt.data,_pEncpkt.size);

*pkt_out = pEncBuff;

        bufferLen_out = _pEncpkt.size;

        av_packet_unref(&_pEncpkt);

        //return 0;

    }

}

}

同样的上述函数为了方便直接将算法的RGB数据转换成YUV数据,然后根据传参是否需要进行图片或文字叠加功能

csdn地址:https://blog.csdn.net/rose5996/article/details/115213349

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352