Qt+ffmpeg接受rtsp并显示

标签: ffmpeg  Qt  rtsp

效果

在这里插入图片描述

接受

#include "rtspplayer.h"
#include <QDebug>
VideoPlayer::VideoPlayer()
{

}

VideoPlayer::~VideoPlayer()
{
}

void VideoPlayer::run()
{
    //变量
    AVFormatContext *pFormatCtx;
    char filepath[] = "rtsp://192.168.0.188:554/stream/main";
    //AVPacket *packet;
    //初始化
    av_register_all();
    avformat_network_init();
    pFormatCtx = avformat_alloc_context();
    AVDictionary* options = NULL;
    av_dict_set(&options, "buffer_size", "1024000", 0); //设置缓存大小,1080p可将值调大
    av_dict_set(&options, "rtsp_transport", "udp", 0); //以udp方式打开,如果以tcp方式打开将udp替换为tcp
    av_dict_set(&options, "stimeout", "20000000", 0); //设置超时断开连接时间,单位微秒
    av_dict_set(&options, "max_delay", "500000", 0); //设置最大时延
    //av_dict_set(&options, "fps", "30", 0); //设置帧数
    //packet = (AVPacket *)av_malloc(sizeof(AVPacket));
    //打开网络流或文件流
    if (avformat_open_input(&pFormatCtx, filepath, NULL, &options) != 0)
    {
        printf("Couldn't open input stream.\n");
        return;
    }

    //查找码流信息
    //设置查找时间以避免耗时过长
    pFormatCtx->probesize = 1000;
    pFormatCtx->max_analyze_duration = AV_TIME_BASE;
    if (avformat_find_stream_info(pFormatCtx, NULL)<0)
    {
        printf("Couldn't find stream information.\n");
        return;
    }
    //查找码流中是否有视频流
    int videoindex = -1;
    for (int i = 0; i<pFormatCtx->nb_streams; i++)
        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            videoindex = i;
            break;
        }
    if (videoindex == -1)
    {
        printf("Didn't find a video stream.\n");
        return;
    }
    printf("-----------rtsp流输入信息--------------\n");
    av_dump_format(pFormatCtx, 0, filepath,0);
    printf("---------------------------------------\n");
    /*********************************************/
    AVCodecContext *pAVCodecContext;
       AVFrame *pAVFrame;
       SwsContext * pSwsContext;
       AVPicture  pAVPicture;
    //获取视频流的分辨率大小
        pAVCodecContext = pFormatCtx->streams[0]->codec;
        int videoWidth=pAVCodecContext->width;
        int videoHeight=pAVCodecContext->height;

        avpicture_alloc(&pAVPicture,AV_PIX_FMT_RGB32,videoWidth,videoHeight);

        AVCodec *pAVCodec;

        //获取视频流解码器
        pAVCodec = avcodec_find_decoder(pAVCodecContext->codec_id);
        pSwsContext = sws_getContext(videoWidth,videoHeight,pAVCodecContext->pix_fmt,videoWidth,videoHeight,AV_PIX_FMT_RGB32,SWS_BICUBIC,0,0,0);

        //打开对应解码器
        int result=avcodec_open2(pAVCodecContext,pAVCodec,NULL);
        if (result<0){
            qDebug()<<"打开解码器失败";
            return;
        }

        pAVFrame = av_frame_alloc();
        int y_size = pAVCodecContext->width * pAVCodecContext->height;
            AVPacket *packet = (AVPacket *) malloc(sizeof(AVPacket)); //分配一个packet
            av_new_packet(packet, y_size); //分配packet的数据
        qDebug()<<"初始化视频流成功" <<","<<videoWidth << "," << videoHeight << "," ;
    //
      //  return;
    //保存一段时间的视频流,写入文件中
    //FILE  * fpSave;
    //fopen_s(&fpSave, "geth264.h264", "wb");
        int m_i_frameFinished =-1;
        int ret =-1;
//    for (int i = 0; i < 1000; i++)   //这边可以调整i的大小来改变文件中的视频时间
//    {

       while(av_read_frame(pFormatCtx, packet) >= 0)
       {
            if (packet->stream_index == videoindex)
            {
                //printf("pts : %d     size :%d one pkt\n",packet->pts,packet->size);
                //fwrite(packet->data, 1, packet->size, fpSave);
                qDebug() << "pkt pts:" << packet->pts;
                ret = avcodec_decode_video2(pAVCodecContext, pAVFrame, &m_i_frameFinished, packet);
                if(ret < 0)
                {
                    qDebug() << "解码失败!!";
                    return;
                }
                if (m_i_frameFinished)
                {

                    sws_scale(pSwsContext,(const uint8_t* const *)pAVFrame->data,pAVFrame->linesize,0,videoHeight,pAVPicture.data,pAVPicture.linesize);
                    //发送获取一帧图像信号

                    QImage image(pAVPicture.data[0],videoWidth,videoHeight,QImage::Format_RGB32);
                    emit sig_GetOneFrame(image);
                }
             }
         }
       // av_packet_unref(packet);
        av_free_packet(packet);
         msleep(0.02);
    //}

      //}
       // fclose(fpSave);
        if(pFormatCtx)
            avformat_close_input(&pFormatCtx);
        //av_free(packet);
        av_frame_free(&pAVFrame);
        sws_freeContext(pSwsContext);
        av_free(pAVFrame);
        printf("is end  !!! \n");
}

显示

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    m_player = new VideoPlayer;
    connect(m_player,SIGNAL(sig_GetOneFrame(QImage)),this,SLOT(slotGetOneFrame(QImage)));
    m_player->start();
}

MainWindow::~MainWindow()
{
    delete m_player;
    delete ui;
}


void MainWindow::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setBrush(Qt::black);
    painter.drawRect(0, 0, this->width(), this->height()); //先画成黑色

    if (mImage.size().width() <= 0) return;

    ///将图像按比例缩放成和窗口一样大小
    QImage img = mImage.scaled(this->size(),Qt::KeepAspectRatio);

    int x = this->width() - img.width();
    int y = this->height() - img.height();

    x /= 2;
    y /= 2;

    painter.drawImage(QPoint(x,y),img); //画出图像

}

void MainWindow::slotGetOneFrame(QImage img)
{
    mImage = img;
    this->update(); //调用update将执行 paintEvent函数
}
版权声明:本文为qq_34940879原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_34940879/article/details/103136020

智能推荐

AtCoder Beginner Contest 174 E.Logs

AtCoder Beginner Contest 174 E.Logs 题目链接 到最后才发现是二分,菜菜的我/(ㄒoㄒ)/~~ 我们直接二分 [1,max{a[i]}][1,max\lbrace a[i]\rbrace][1,max{a[i]}] 即可,对每一个 midmidmid,每个数 a[i]a[i]a[i] 只需要切 a[i]−1mid\frac{a[i]-1}{mid}mi...

小程序基础与实战案例

小程序开发工具与基础 小程序开发准备: 申请小程序账号( appid ) 下载并安装微信开发者工具 具体步骤如下: 先进入 微信公众平台 ,下拉页面,把鼠标悬浮在小程序图标上 然后点击 小程序开发文档 照着里面给的步骤,就可以申请到小程序账号了。 然后就可以下载 开发者工具 了 下载完打开后的界面就是这个样子 下面让我们来新建一个小程序开发项目: 在AppID输入自己刚刚注册的AppID就可以,或...

VMware centOS7 下通过minikube部署Kubernetes

1、环境准备: VMware CentOS-7-x86_64 CPU:2*2core 内存:8G 宿主机和虚拟机需网络互通,虚拟机外网访问正常 Centos发行版版本查看:cat /etc/centos-release root用户操作 2、禁用swap分区 Kubernetes 1.8开始要求关闭系统的Swap,可暂时关闭或永久禁用, 使用 $ free -m 确认swap是否为开启状态 $ s...

逻辑回归与scikit-learn

欢迎关注本人的微信公众号AI_Engine LogisticRegression 算法原理 一句话概括:逻辑回归假设数据服从伯努利分布,通过极大化似然函数(损失函数)的方法,运用梯度下降或其他优化算法来求解参数,来达到将数据二分类的目的。 定义:逻辑回归(Logistic Regression)是一种用于解决二分类(0 or 1)问题的机器学习方法,用于估计某种事物的可能性(不是概率)。比如某用户...

指针OR数组?用他们来表达字符串又有何不同?

cocowy的编程之旅 在学习C语言的过程中我们经常可以看到或者听到这样一句话:数组其实等价于指针,例如: 在这里可以轻松的看出输出后他们的值相等,其实在计算机内存里面,p为本地变量,有着他自己的作用域。而指针变量q保存着这个数组的首地址,通过*号指向这个地址保存的变量值。 然而我们再看一个例子: 这个时候计算机报错,这是为什么呢? 其实原因很简单,指针说指向的这个字符串的地址是位于计算机代码段地...

猜你喜欢

广度搜索

广度搜索的基本使用方法 广度搜索不同于深度搜索,是一种一步一步进行的过程,每一个点只记录一遍。需要用到队列记录每一步可以走到的位置,找到目标位置输出步数即可。 用到的知识:结构体、队列 如图 首先我们需要定义一个结构体来存储每个遍历到的点和步数 广搜不会用到递归,所以可以直接在主函数里写,这里需要定义一个结构体队列 初始化队列并将起始点入列 遍历 完整代码...

NIO Socket 编程实现tcp通信入门(二)

1、NIO简介 NIO面向通道和缓冲区进行工作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。可以双向传输数据,是同步非阻塞式IO。NIO还引入了选择器机制,从而实现了一个选择器监听多个底层通道,减少了线程并发数。用NIO实现socket的Tcp通信需要掌握下面三个知识点: Buffer 缓冲区 Channel 通道 Selector 选择器   2、java.nio.Buff...

[字节码系列]ObjectWeb ASM构建Method Monitor

      在前面的篇章中,我们看到Java Instrutment的强大能力,本篇,我们将介绍如何使用ObjectWeb ASM的字节码增强能力构建Method Monitor       1.什么是ObjectWeb ASM      ObjectWeb ...

Core Location 电子围栏:入门

原文:Geofencing with Core Location: Getting Started 作者:Andy Pereira 译者:kmyhy 更新说明:Andy Pereira 将本教程升级至 Xcode 9.3 和 Swift 4.1。 Geofencing 会在设备进入/离开指定的电子围栏时通知应用程序。它可以让你写出一些很酷的应用程序,当你从家里出来时触发通知,或者在附近出现最爱的商...

Android 圆角边框RoundRect原理

绘制圆角矩形的方法 该方法来自Canvas类,rect代表矩形,rx和ry分别代表形成圆角所需要的椭圆的x和y轴半径,那么rx和ry究竟如何形成圆角呢? 形成圆角的原理 矩形的四个圆角是分别生成的,以左上角的圆角为例: 首先通过rect绘制出矩形,然后以矩形的左上角定点为起点,分别向x和y轴平移rx和ry, 得到的点为中心,以rx和ry为x和y轴的半径绘制椭圆,椭圆的坐上半部分圆弧就是圆角了。如下...