wireshark视频流播放_ffmpeg无缝推流多个视频

wireshark视频流播放_ffmpeg无缝推流多个视频使用QT+FFMPEG实现了RTSP视频流播放的基础操作,点击按钮后,将拉取指定地址的RTSP流,并在QT界面中通过Label显示

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

功能简介:

使用QT+FFMPEG实现了RTSP视频流播放的基础操作,点击按钮后,将拉取指定地址的RTSP流,并在QT界面中通过Label显示

开发环境:

  • 系统环境:Ubuntu
  • QT:5.12.12
  • FFmpeg:4.4(当前最新)

完整工程:

https://github.com/harry19902002/ffmpeg-first-demo

参考代码:

FFMPEG官方示例:FFmpeg: decode_video.c

详细介绍:

(一)添加库文件

新建一个QT工程,在pro添加lib目录和include目录的路径。

##ffmpeg
FFMPEG_LIB = /usr/local/ffmpeg/lib
FFMPEG_INCLUDE = /usr/local/ffmpeg/include

INCLUDEPATH += $$FFMPEG_INCLUDE \

LIBS += $$FFMPEG_LIB/libavcodec.so \
        $$FFMPEG_LIB/libavdevice.so \
        $$FFMPEG_LIB/libavfilter.so \
        $$FFMPEG_LIB/libavformat.so \
        $$FFMPEG_LIB/libavutil.so \
        $$FFMPEG_LIB/libswresample.so \
        $$FFMPEG_LIB/libswscale.so \

(二)界面配置

       在MainWindow.ui中,添加一个QPushButton和QLabel控件,并添加“转到槽”,添加on_pushButton_clicked()。

(三)Delay函数

#include <QTime>
//以毫秒为单位设置延时
void Delay(int msec)
{
    QTime dieTime = QTime::currentTime().addMSecs(msec);
    while(QTime::currentTime() < dieTime){
        QCoreApplication::processEvents(QEventLoop::AllEvents,100);
    }
}

(四)FFmpeg视频解码

        总体处理步骤有8步,如图所示

       wireshark视频流播放_ffmpeg无缝推流多个视频

        1.定义相关变量

    AVFormatContext *pFormatCtx = NULL;
    AVCodecContext *pCodecCtx = NULL;
    const AVCodec *pCodec = NULL;
    AVFrame *pFrame,*pFrameRGB;
    AVPacket *packet;
    struct SwsContext *img_convert_ctx;

    unsigned char *out_buffer;
    int i,videoIndex;
    int ret;
    char errors[1024] = "";

    //rtsp地址:
    char url[] = "rtsp://192.168.111.60:554/LiveMedia/ch1/Media1";

        2.初始化相关模块

    //初始化FFMPEG  调用了这个才能正常适用编码器和解码器
    pFormatCtx = avformat_alloc_context();  //init FormatContext
    //初始化FFmpeg网络模块
    avformat_network_init();    //init FFmpeg network

       3.打开视频文件并获取视频信息

    //open Media File
    ret = avformat_open_input(&pFormatCtx,url,NULL,NULL);
    if(ret != 0){
        av_strerror(ret,errors,sizeof(errors));
        cout <<"Failed to open video: ["<< ret << "]"<< errors << endl;
        exit(ret);
    }

    //Get audio information
    ret = avformat_find_stream_info(pFormatCtx,NULL);
    if(ret != 0){
        av_strerror(ret,errors,sizeof(errors));
        cout <<"Failed to get audio info: ["<< ret << "]"<< errors << endl;
        exit(ret);
    }

  4.查找视频中的流信息

    //循环查找视频中包含的流信息,直到找到视频类型的流
    //便将其记录下来 videoIndex
    //这里我们现在只处理视频流  音频流先不管他
    for (i = 0; i < pFormatCtx->nb_streams; i++) {
        if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoIndex = i;
        }
    }

    //如果videoIndex为-1 说明没有找到视频流
    if (videoIndex == -1) {
        printf("Didn't find a video stream.\n");
        return;
    }

5.配置编码上下文,AVCodecContext内容

    //配置编码上下文,AVCodecContext内容
    //1.查找解码器
    pCodec = avcodec_find_decoder(pFormatCtx->streams[videoIndex]->codecpar->codec_id);
    //2.初始化上下文
    pCodecCtx = avcodec_alloc_context3(pCodec);
    //3.配置上下文相关参数
    avcodec_parameters_to_context(pCodecCtx,pFormatCtx->streams[videoIndex]->codecpar);
    //4.打开解码器
    ret = avcodec_open2(pCodecCtx, pCodec, NULL);
    if(ret != 0){
        av_strerror(ret,errors,sizeof(errors));
        cout <<"Failed to open Codec Context: ["<< ret << "]"<< errors << endl;
        exit(ret);
    }

6.建立视频帧,并对相关参数进行配置

    //初始化视频帧
    pFrame = av_frame_alloc();
    pFrameRGB = av_frame_alloc();
    //为out_buffer申请一段存储图像的内存空间
    out_buffer = (unsigned char*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB32,pCodecCtx->width,pCodecCtx->height,1));
    //实现AVFrame中像素数据和Bitmap像素数据的关联
    av_image_fill_arrays(pFrameRGB->data,pFrameRGB->linesize, out_buffer,
                   AV_PIX_FMT_RGB32,pCodecCtx->width, pCodecCtx->height,1);
    //为AVPacket申请内存
    packet = (AVPacket *)av_malloc(sizeof(AVPacket));
    //打印媒体信息
    av_dump_format(pFormatCtx,0,url,0);
    //初始化一个SwsContext
    img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
                pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
                AV_PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);

7.通过while循环,处理每一个视频帧,并渲染到Label上

    //读取帧数据,并通过av_read_frame的返回值确认是不是还有视频帧
    while(av_read_frame(pFormatCtx,packet) >=0){
        //判断视频帧
        if(packet->stream_index == videoIndex){
            //解码视频帧
            ret = avcodec_send_packet(pCodecCtx, packet);
            ret = avcodec_receive_frame(pCodecCtx, pFrame);
            if(ret != 0){
                av_strerror(ret,errors,sizeof(errors));
                cout <<"Failed to decode video frame: ["<< ret << "]"<< errors << endl;
            }
            if (ret == 0) {
                //处理图像数据
                sws_scale(img_convert_ctx,
                                        (const unsigned char* const*) pFrame->data,
                                        pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data,
                                        pFrameRGB->linesize);
                QImage img((uchar*)pFrameRGB->data[0],pCodecCtx->width,pCodecCtx->height,QImage::Format_RGB32);
                ui->label->setPixmap(QPixmap::fromImage(img));
                //释放前需要一个延时
                Delay(1);
            }
        }
        //释放packet空间
        av_packet_unref(packet);
    }

8.结束后释放资源

    //close and release resource
    av_free(out_buffer);
    av_free(pFrameRGB);

    sws_freeContext(img_convert_ctx);
    avcodec_close(pCodecCtx);
    avcodec_free_context(&pCodecCtx);
    avformat_close_input(&pFormatCtx);
    exit(0);

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/180932.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 有源低通滤波器 vs. 有源带通滤波器 vs. LC滤波器「建议收藏」

    有源低通滤波器 vs. 有源带通滤波器 vs. LC滤波器「建议收藏」在做一个小东西,想省成本用F407内部的DAC生成Sin输出(100Hz,1kHz,10kHz,100kHz),但是407DAC能力有限,当要输出100kHz的Sin曲线的时候一个周期只能11个点左右,示波器上能看到明显的阶梯,需要一个滤波器。一直纠结有源低通,有源带通,无源LC滤波。滤波器可以通过TI的滤波器设计软件FilterPro来设计,非常简单,有一点就是运放的增益带宽积,同频率下…

    2022年5月2日
    44
  • axios的安装和使用

    axios的安装和使用文章目录一、axios介绍二、安装axios三、案例一、axios介绍什么是axios?Axios是一个基于promise的HTTP库,可以用在浏览器和node.js中。特性:1、从浏览器中创建XMLHttpRequests2、从node.js创建http请求3、支持PromiseAPI4、拦截请求和响应5、转换请求数据和响应数据6、取消请求7、自动转换JSON数据8、客户端支持防御XSRF浏览器支持:二、安装axios方法一:速.

    2025年8月18日
    3
  • polkitd进程解释

    polkitd进程解释今天想kill-9redis杀不掉然后发现这个是属于服务器方法,可以了解一下supervisor,将需要自启动的程序加入到supervisor的启动配置,只要supervisor不停止,那么监控进程就会一直运行,并且如果出现关闭情况也会被立即重启。…

    2022年6月14日
    112
  • java请求webservice_java service

    java请求webservice_java service展开全部java返回list这你应该会吧,然后转换成json格式给其它语言.json(javascriptObjectNotation的缩写)是一个基于文本的,人类可读32313133353236313431303231363533e4b893e5b19e31333361313936的,开放标准的轻量级数据交换格式。它继承了javascript中的简单数据结构和相关数组对象,称为对象。不管…

    2022年10月16日
    3
  • Redis 缓存穿透 + 缓存雪崩 + 缓存击穿的原因和解决方案「建议收藏」

    Redis 缓存穿透 + 缓存雪崩 + 缓存击穿的原因和解决方案「建议收藏」在生产环境中,会因为很多的原因造成访问请求绕过了缓存,都需要访问数据库持久层,虽然对Redsi缓存服务器不会造成影响,但是数据库的负载就会增大,使缓存的作用降低一、缓存穿透缓存穿透是指查询一个根本不存在的数据,缓存层和持久层都不会命中。在日常工作中出于容错的考虑,如果从持久层查不到数据则不写入缓存层,缓存穿透将导致不存在的数据每次请求都要到持久层去查询,失去了缓…

    2022年6月15日
    26
  • std::vector find_vectornator工具使用

    std::vector find_vectornator工具使用vector本身是没有find这一方法,其find是依靠algorithm来实现的。#include<iostream>#include<algorithm>#include<vector>intmain(){usingnamespacestd;vector<int>vec;vec.push_back(1);vec.push_back(2);vec.push_back(3);v

    2022年8月31日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号