使用c++编写,ffmpegrtsp取流且实现重连

关于使用C++编写FFmpeg RTSP取流并实现重连的问题,我可以给出以下解答。

首先,需要使用FFmpeg库进行RTSP取流,可以使用下面的代码示例:

#include <iostream>
extern "C"
{
    #include <libavutil/imgutils.h>
    #include <libavformat/avformat.h>
    #include <libswscale/swscale.h>
}
int main(int argc, char* argv[])
{
    //输入URL(RTSP地址)
    char* url = "rtsp://192.168.1.100/test.sdp";
    //注册所有可用的文件格式和编解码器
    av_register_all();
    //打开RTSP流
    AVFormatContext* fmtCtx = NULL;
    AVDictionary* options = NULL;
    av_dict_set(&options, "rtsp_transport", "tcp", 0);
    av_dict_set(&options, "stimeout", "2000000", 0);
    av_dict_set(&options, "max_delay", "500000", 0);
    if (avformat_open_input(&fmtCtx, url, NULL, &options) != 0)
    {
        std::cerr << "Could not open input file." << std::endl;
        return -1;
    }
    //查找RTSP流信息
    if (avformat_find_stream_info(fmtCtx, NULL) < 0)
    {
        std::cerr << "Failed to retrieve input stream information." << std::endl;
        return -1;
    }
    //打印视频相关信息
    av_dump_format(fmtCtx, 0, url, 0);
    //找到包含视频流的流索引
    int videoStreamIndex = -1;
    for (int i = 0; i < fmtCtx->nb_streams; i++)
    {
        if (fmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            videoStreamIndex = i;
            break;
        }
    }
    if (videoStreamIndex == -1)
    {
        std::cerr<<"Could not find video stream."<<std::endl;
        return -1;
    }
    //获取视频流的解码参数
    AVCodecParameters* codecParams = fmtCtx->streams[videoStreamIndex]->codecpar;
    //查找视频解码器
    AVCodec* pCodec = avcodec_find_decoder(codecParams->codec_id);
    if (pCodec == NULL)
    {
        std::cerr << "Could not find codec." << std::endl;
        return -1;
    }
    //创建并初始化解码器上下文
    AVCodecContext* codecCtx = avcodec_alloc_context3(pCodec);
    if (codecCtx == NULL)
    {
        std::cerr << "Could not allocate codec context." << std::endl;
        return -1;
    }
    if (avcodec_parameters_to_context(codecCtx, codecParams) < 0)
    {
        std::cerr << "Could not copy codec parameters to context." << std::endl;
        return -1;
    }
    if (avcodec_open2(codecCtx, pCodec, NULL) < 0)
    {
        std::cerr << "Could not open codec." << std::endl;
        return -1;
    }
    //读取视频帧并显示
    AVPacket pkt;
    av_init_packet(&pkt);
    AVFrame* pFrame = av_frame_alloc();
    AVFrame* pFrameRGB = av_frame_alloc();
    uint8_t* buffer = NULL;
    int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, codecCtx->width, codecCtx->height, 1);
    buffer = (uint8_t*)av_malloc(numBytes);
    av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, buffer, AV_PIX_FMT_RGB24, codecCtx->width, codecCtx->height, 1);
    struct SwsContext* sws_ctx = sws_getContext(codecCtx->width, codecCtx->height, codecCtx->pix_fmt, codecCtx->width, codecCtx->height, AV_PIX_FMT_RGB24, SWS_BILINEAR, NULL, NULL, NULL);
    int frameCount = 0;
    while (frameCount < 100)
    {
        if (av_read_frame(fmtCtx, &pkt) < 0)
        {
            std::cerr << "Error reading frame." << std::endl;
            break;
        }
        if (pkt.stream_index == videoStreamIndex)
        {
            //解码视频帧
int gotPicture = 0;
            if (avcodec_decode_video2(codecCtx, pFrame, &gotPicture, &pkt) < 0)
            {
                std::cerr << "Error decoding frame." << std::endl;
                av_packet_unref(&pkt);
                continue;
            }
            if (gotPicture)
            {
                //转换RGB格式
sws_scale(sws_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, codecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
                //处理RGB帧
std::cout << "Processed frame " << frameCount << std::endl;
                frameCount++;
            }
        }
        av_packet_unref(&pkt);
    }
    //释放资源
av_free(buffer);
    av_frame_free(&pFrameRGB);
    av_frame_free(&pFrame);
    avcodec_free_context(&codecCtx);
    avformat_close_input(&fmtCtx);
    return 0;
}

以上代码使用FFmpeg库打开指定的RTSP流,获取视频流相关的信息,找到视频流的解码器,读取视频帧进行解码,然后转换成RGB格式并进行处理,最后释放资源。

需要实现重连时,可以在读取帧的过程中增加一个重连的逻辑,如下所示:

int maxRetryCount = 3;  //最大重试次数
int retryCount = 0; //当前重试次数
while (frameCount < 100)
{
    if (av_read_frame(fmtCtx, &pkt) < 0)
    {
        std::cerr << "Error reading frame." << std::endl;
        if (retryCount < maxRetryCount)
        {
            //重连
            std::cout << "Retry..." << std::endl;
            av_usleep(1000*1000);  //等待1秒钟
            avformat_close_input(&fmtCtx);
            if (avformat_open_input(&fmtCtx, url, NULL, &options) != 0)
            {
                std::cerr << "Could not open input file." << std::endl;
                return -1;
            }
            if (avformat_find_stream_info(fmtCtx, NULL) < 0)
            {
                std::cerr << "Failed to retrieve input stream information." << std::endl;
                return -1;
            }
            av_dict_set(&options, "stimeout", "2000000", 0);
            av_dict_set(&options, "max_delay", "500000", 0);
            av_dict_set(&options, "rtsp_transport", "tcp", 0);
            avformat_find_stream_info(fmtCtx, NULL);
            av_dump_format(fmtCtx, 0, url, 0);
            retryCount++;
            continue;
        }
        else
        {
            break;
        }
    }
    retryCount = 0;
    if (pkt.stream_index == videoStreamIndex)
    {
        //解码视频帧
        int gotPicture = 0;
        if (avcodec_decode_video2(codecCtx, pFrame, &gotPicture, &pkt) < 0)
        {
            std::cerr << "Error decoding frame." << std::endl;
            av_packet_unref(&pkt);
            continue;
        }
        if (gotPicture)
        {
            //转换RGB格式
            sws_scale(sws_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, codecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
            //处理RGB帧
            std::cout << "Processed frame " << frameCount << std::endl;
            frameCount++;
        }
    }
    av_packet_unref(&pkt);
}

以上代码在发生读取错误时增加了重试的逻辑,最多重试3次,并使用av_usleep函数等待1秒钟再尝试打开RTSP流进行重连。

需要注意的是,以上代码只是示例代码,实际的应用中还需要增加更多的错误处理和异常情况的处理。

posted @   阿风小子  阅读(1152)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示