当前位置: 首页 > article >正文

Qt调用ffmpeg库录屏并进行UDP组播推流

基于以下参考链接,采用其界面和程序框架,实现实时推送UDP组播视频流,替换原拉流功能
https://blog.csdn.net/u012532263/article/details/102736700

源码在windows(qt-opensource-windows-x86-5.12.9.exe)、ubuntu20.04.6(x64)(qt-opensource-linux-x64-5.12.12.run)、以及针对arm64的ubuntu20.04.6(x64)交叉编译环境下编译成功(QT5.12.8, 5.15.13), 可执行程序在windows,ubuntu(x64)、arm64上均可运行。

工程代码见:
https://download.csdn.net/download/daqinzl/90316849

主要代码
videoplayer.cpp

#include "videoplayer.h"
#include <QDebug>
extern "C"
{
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
    #include "libavutil/pixfmt.h"
    #include "libswscale/swscale.h"
    #include "libavdevice/avdevice.h"
}

#include <stdio.h>
#include<iostream>
using namespace std;
VideoPlayer::VideoPlayer()
{

}

VideoPlayer::~VideoPlayer()
{

}

void VideoPlayer::startPlay()
{
    ///调用 QThread 的start函数 将会自动执行下面的run函数 run函数是一个新的线程
    this->start();

}

void VideoPlayer::run()
{

    AVFormatContext* m_fmt_ctx = NULL;
    AVInputFormat* m_input_fmt = NULL;
    int video_stream = -1;
    avdevice_register_all();
    avcodec_register_all();
    //const char* deviceName =  "desktop";
    //const char* inputformat = "gdigrab";

    const char* deviceName =  ":0.0+0,00";
    const char* inputformat = "x11grab";

    int FPS = 23;  //15
    m_fmt_ctx = avformat_alloc_context();
    m_input_fmt = av_find_input_format(inputformat);
    AVDictionary* deoptions = NULL;
    av_dict_set_int(&deoptions, "framerate", FPS, AV_DICT_MATCH_CASE);
    av_dict_set_int(&deoptions, "rtbufsize", 3041280 * 100 * 5, 0);

    av_dict_set(&deoptions,"video_size","1920*1080",0); //

    //如果不设置的话,在输入源是直播流的时候,会花屏。单位bytes
    //av_dict_set(&deoptions, "buffer_size", "10485760", 0);
    //av_dict_set(&deoptions, "reuse", "1", 0);

    int ret = avformat_open_input(&m_fmt_ctx, deviceName, m_input_fmt, &deoptions);
    if (ret != 0) {
        qDebug() << "1. " << ret << "\n"; return;
    }
    av_dict_free(&deoptions);
    ret = avformat_find_stream_info(m_fmt_ctx, NULL);
    if (ret < 0) {
        qDebug() << "2. " << ret << "\n"; return;
    }
    av_dump_format(m_fmt_ctx, 0, deviceName, 0);
    video_stream = av_find_best_stream(m_fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    if (video_stream < 0) {
        qDebug() << "3. " << -1 << "\n"; return;
    }

    AVCodecContext * _codec_ctx = m_fmt_ctx->streams[video_stream]->codec;
    AVCodec* _codec = avcodec_find_decoder(_codec_ctx->codec_id);
    if (_codec == NULL) {
        qDebug() << "4. " << -1 << "\n"; return;
    }
    ret = avcodec_open2(_codec_ctx, _codec, NULL);
    if (ret != 0) {
        qDebug() << "5. " << -1 << "\n"; return;
    }
    int width = m_fmt_ctx->streams[video_stream]->codec->width;
    int height = m_fmt_ctx->streams[video_stream]->codec->height;
    int fps = m_fmt_ctx->streams[video_stream]->codec->framerate.num > 0 ? m_fmt_ctx->streams[video_stream]->codec->framerate.num : 25;
    AVPixelFormat videoType = m_fmt_ctx->streams[video_stream]->codec->pix_fmt;
    std::cout << "avstream timebase : " << m_fmt_ctx->streams[video_stream]->time_base.num << " / " << m_fmt_ctx->streams[video_stream]->time_base.den << endl;
        AVDictionary* enoptions = 0;
    //av_dict_set(&enoptions, "preset", "superfast", 0);
    //av_dict_set(&enoptions, "tune", "zerolatency", 0);
    av_dict_set(&enoptions, "preset", "ultrafast", 0);
    av_dict_set(&enoptions, "tune", "zerolatency", 0);

    //TODO
    //av_dict_set(&enoptions, "pkt_size", "1316", 0);    //Maximum UDP packet size
    av_dict_set(&dic, "fifo_size", "18800", 0);
    av_dict_set(&enoptions, "buffer_size", "0", 1);
    av_dict_set(&dic, "bitrate", "11000000", 0);
    av_dict_set(&dic, "buffer_size", "1000000", 0);//1316
    //av_dict_set(&enoptions, "reuse", "1", 0);

    AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264);
    if (!codec)
    {
        std::cout << "avcodec_find_encoder failed!" << endl;
        qDebug() << "6. " << "NULL" << "\n"; return;
    }
    AVCodecContext* vc = avcodec_alloc_context3(codec);
    if (!vc)
    {
        std::cout << "avcodec_alloc_context3 failed!" << endl;
        qDebug() << "7. " << "NULL" << "\n"; return;
    }
    std::cout << "avcodec_alloc_context3 success!" << endl;
    vc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    vc->codec_id = AV_CODEC_ID_H264;
    vc->codec_type = AVMEDIA_TYPE_VIDEO;
    vc->pix_fmt = AV_PIX_FMT_YUV420P;
    vc->width = width;
    vc->height = height;
    vc->time_base.num = 1;
    vc->time_base.den = FPS;
    vc->framerate = { FPS,1 };
    vc->bit_rate = 10241000;
    vc->gop_size = 120;
    vc->qmin = 10;
    vc->qmax = 51;
    vc->max_b_frames = 0;
    vc->profile = FF_PROFILE_H264_MAIN;
    ret = avcodec_open2(vc, codec, &enoptions);
    if (ret != 0)
    {
        qDebug() << "8. " << ret << "\n"; return;
    }
    std::cout << "avcodec_open2 success!" << endl;
    av_dict_free(&enoptions);
    SwsContext *vsc = nullptr;
    vsc = sws_getCachedContext(vsc,
        width, height, (AVPixelFormat)videoType, //源宽、高、像素格式
        width, height, AV_PIX_FMT_YUV420P,//目标宽、高、像素格式
        SWS_BICUBIC, // 尺寸变化使用算法
        0, 0, 0
    );
    if (!vsc)
    {
        cout << "sws_getCachedContext failed!";
        qDebug() << "9. " << "false" << "\n"; return;
    }
    AVFrame* yuv = av_frame_alloc();
    yuv->format = AV_PIX_FMT_YUV420P;
    yuv->width = width;
    yuv->height = height;
    yuv->pts = 0;
    ret = av_frame_get_buffer(yuv, 32);
    if (ret != 0)
    {
        qDebug() << "10. " << ret << "\n"; return;
    }
    //const char* rtmpurl = "rtmp://192.168.0.105:1935/live/desktop";
    //const char* rtmpurl = "rtmp://172.17.53.33:1935/live/desktop";
    const char* rtmpurl = "udp://224.1.1.1:5001";
    AVFormatContext * ic = NULL;
    //ret = avformat_alloc_output_context2(&ic, 0, "flv", rtmpurl);
    ret = avformat_alloc_output_context2(&ic, NULL, "mpegts", rtmpurl);//UDP
    if (ret < 0)
    {
        qDebug() << "11. " << ret << "\n"; return;
    }
    AVStream* st = avformat_new_stream(ic, NULL);
    if (!st)
    {
        qDebug() << "12. " << -1 << "\n"; return;
    }
    st->codecpar->codec_tag = 0;
    avcodec_parameters_from_context(st->codecpar, vc);
    av_dump_format(ic, 0, rtmpurl, 1);
    ret = avio_open(&ic->pb, rtmpurl, AVIO_FLAG_WRITE);
    if (ret != 0)
    {
        qDebug() << "13. " << ret << "\n"; return;
    }
    ret = avformat_write_header(ic, NULL);
    if (ret != 0)
    {
        qDebug() << "14. " << ret << "\n"; return;
    }
    AVPacket* packet = av_packet_alloc();
    AVPacket* Encodepacket = av_packet_alloc();
    int frameIndex = 0;
    int EncodeIndex = 0;
    AVFrame* rgb = av_frame_alloc();
    AVBitStreamFilterContext* h264bsfc = av_bitstream_filter_init("h264_mp4toannexb");
    long long startpts = m_fmt_ctx->start_time;
    long long lastpts = 0;
    long long duration = av_rescale_q(1, { 1,FPS }, { 1,AV_TIME_BASE });
    int got_picture = 0;
    while (frameIndex < 2000000)
    {
        ret = av_read_frame(m_fmt_ctx, packet);
        if (ret < 0) {
            break;
        }
        if (packet->stream_index == video_stream)
        {
            ret = avcodec_decode_video2(_codec_ctx, rgb, &got_picture, packet);
            if (ret < 0) {
                printf("Decode Error.\n");
                qDebug() << "15. " << ret << "\n"; return;
            }
            if (got_picture) {
                int h = sws_scale(vsc, rgb->data, rgb->linesize, 0, height, //源数据
                yuv->data, yuv->linesize);
                int guesspts = frameIndex * duration;
                yuv->pts = guesspts;
                frameIndex++;
                ret = avcodec_encode_video2(vc, Encodepacket, yuv, &got_picture);
                if (ret < 0) {
                    printf("Failed to encode!\n");
                    break;
                }
                if (got_picture == 1) {
                    Encodepacket->pts = av_rescale_q(EncodeIndex, vc->time_base, st->time_base);
                    Encodepacket->dts = Encodepacket->pts;
                    std::cout << "frameindex : " << EncodeIndex << " pts : " << Encodepacket->pts << " dts: " << Encodepacket->dts << " encodeSize:" << Encodepacket->size << " curtime - lasttime " << Encodepacket->pts - lastpts << endl;
                        lastpts = Encodepacket->pts;
                    ret = av_interleaved_write_frame(ic, Encodepacket);
                    EncodeIndex++;
                    av_packet_unref(Encodepacket);
                }
            }
        }
        av_packet_unref(packet);
    }
    ret = avcodec_send_frame(vc, NULL);
    while (ret >= 0) {
        ret = avcodec_receive_packet(vc, Encodepacket);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            break;
        }
        if (ret < 0) {
            break;
        }
        ret = av_interleaved_write_frame(ic, Encodepacket);
        EncodeIndex++;
    }
    av_write_trailer(ic);
    av_packet_free(&packet);
    av_packet_free(&Encodepacket);
    av_frame_free(&rgb);
    av_frame_free(&yuv);
    av_bitstream_filter_close(h264bsfc);
    h264bsfc = NULL;
    if (vsc){
        sws_freeContext(vsc);
        vsc = NULL;
    }
    if (_codec_ctx){
        avcodec_close(_codec_ctx);
    }
    _codec_ctx = NULL;
    _codec = NULL;
    if (vc){
        avcodec_free_context(&vc);
    }
    if (m_fmt_ctx){
        avformat_close_input(&m_fmt_ctx);
    }
    if (ic && !(ic->flags & AVFMT_NOFILE)){
        avio_closep(&ic->pb);
    }
    if (ic) {
        avformat_free_context(ic);
        ic = NULL;
    }
    m_input_fmt = NULL;

}
 

相关文章:

Qt调用ffmpeg库录屏并进行UDP组播推流

基于以下参考链接&#xff0c;采用其界面和程序框架&#xff0c;实现实时推送UDP组播视频流&#xff0c;替换原拉流功能 https://blog.csdn.net/u012532263/article/details/102736700 源码在windows&#xff08;qt-opensource-windows-x86-5.12.9.exe&#xff09;、ubuntu20.…...

HarmonyOS:创建应用静态快捷方式

一、前言 静态快捷方式是一种在系统中创建的可以快速访问应用程序或特定功能的链接。它通常可以在长按应用图标&#xff0c;以图标和相应的文字出现在应用图标的上方&#xff0c;用户可以迅速启动对应应用程序的组件。使用快捷方式&#xff0c;可以提高效率&#xff0c;节省了查…...

mysql 学习6 DQL语句,对数据库中的表进行 查询 操作

前期准备数据 重新create 一张表 create table emp(id int comment 编号,workno varchar(10) comment 工号,name varchar(10) comment 姓名,gender char comment 性别,ager tinyint unsigned comment 年龄,idcard char(18) comment 身份证号,workaddress varchar(10) c…...

【ES实战】治理项之索引模板相关治理

索引模板治理 文章目录 索引模板治理问题现象分析思路操作步骤问题程序化方案索引与索引模板增加分片数校验管理 彩蛋如何查询Flink on Yarn 模式下的Task Manager日志相关配置查询已停止的Flink任务查询未停止的Flink任务 问题现象 在集群索引新建时&#xff0c;索引的分片比…...

springboot3 集成 knife4j(接口文档)

提示&#xff1a;文章是集成 knife4j&#xff0c;而非 swagger2 或者 swagger3&#xff0c;效果如图 文章目录 前言一、添加依赖二、如何集成1.配置文件2.注解部分1.Tag2.Operation3.Parameter4.Schema 3.使用 总结 前言 提示&#xff1a;&#xff1a;大家在开发阶段&#xff…...

51单片机开发:独立键盘实验

实验目的&#xff1a;按下键盘1时&#xff0c;点亮LED灯1。 键盘原理图如下图所示&#xff0c;可见&#xff0c;由于接GND&#xff0c;当键盘按下时&#xff0c;P3相应的端口为低电平。 键盘按下时会出现抖动&#xff0c;时间通常为5-10ms&#xff0c;代码中通过延时函数delay…...

Flutter_学习记录_Tab的简单Demo~真的很简单

1. Tab的简单使用了解 要实现tab(选项卡或者标签视图)需要用到三个组件&#xff1a; TabBarTabBarViewTabController 这一块&#xff0c;我也不知道怎么整理了&#xff0c;直接提供代码吧&#xff1a; import package:flutter/material.dart;void main() {runApp(MyApp());…...

GESP2024年3月认证C++六级( 第三部分编程题(1)游戏)

参考程序&#xff1a; #include <cstdio> using namespace std; const int N 2e5 5; const int mod 1e9 7; int n, a, b, c; int f[N << 1]; int ans; int main() {scanf("%d%d%d%d", &n, &a, &b, &c);f[N n] 1;for (int i n; i…...

数据结构测试题2

一、单选题&#xff08;每题 2 分&#xff0c;共20分&#xff09; 1. 栈和队列的共同特点是( A )。 A.只允许在端点处插入和删除元素 B.都是先进后出 C.都是先进先出 D.没有共同点 2. 用链接方式存储的队列&#xff0c;在进行插入运算时( C ) A. 仅修改头指针 B. 头…...

Linux 系统服务开机自启动指导手册

一、引言 在 Linux 系统中&#xff0c;设置服务开机自启动是常见的系统配置任务。本文档详细介绍了多种实现服务开机自启动的方法&#xff0c;包括 systemctl 方式、通用脚本方式、crontab 方案等&#xff0c;并提供了生产环境下的方案建议和开机启动脚本示例。 二、systemct…...

项目概述与规划 (I)

项目概述与规划 (I) JavaScript的学习已经接近尾声了&#xff0c;最后我们将通过一个项目来讲我们在JavaScript中学习到的所有都在这个项目中展现出来&#xff0c;这个项目的DEMO来自于Udemy中的课程&#xff0c;作者是Jonas Schmedtmann&#xff1b; 项目规划 项目步骤 用户…...

【WebRTC - STUN/TURN服务 - COTURN配置】

在WebRTC中&#xff0c;对于通信的两端不在同一个局域网的情况下&#xff0c;通信两端往往无法P2P直接连接&#xff0c;需要一个TURN中继服务&#xff0c;而中继服务可以选用 COTURN 构建。 注&#xff1a;COTURN 是一个开源的 TURN&#xff08;Traversal Using Relays around…...

【HuggingFace项目】:Open-R1 - DeepSeek-R1 大模型开源复现计划

项目链接&#xff1a;https://github.com/huggingface/open-r1 概述 Open-R1 是由 HuggingFace 发布的一个完全开放的项目&#xff0c;旨在通过三个主要步骤复现 DeepSeek-R1 的完整训练流程。这个项目的目标是让更多人能够理解和使用 DeepSeek-R1 的技术方案&#xff0c;从而…...

On to OpenGL and 3D computer graphics

2. On to OpenGL and 3D computer graphics 声明&#xff1a;该代码来自&#xff1a;Computer Graphics Through OpenGL From Theory to Experiments&#xff0c;仅用作学习参考 2.1 First Program Square.cpp完整代码 /// // square.cpp // // OpenGL program to draw a squ…...

计算机毕设【开题报告】怎么写?

本文将围绕如何编写计算机专业的开题报告展开&#xff0c;结合具体的步骤、方法技巧&#xff0c;并提供一个基于SpringBoot系统的完整示例&#xff0c;帮助大家顺利完成开题报告。 一、开题报告的核心结构 开题报告通常包括以下几个部分&#xff1a; 选题背景及意义 说明项目研…...

【数据分享】2014-2025年我国水系数据(免费获取/全国/分省)

水系数据是我们在各项研究中经常使用的数据&#xff01;水系数据虽然很常用&#xff0c;但是却基本没有能下载最近年份水系数据的网站&#xff0c;所以很多人不知道如何获得水系数据。 本次我们给大家分享的是2014-2025年的全国范围的水系数据&#xff0c;包括水系线数据和水系…...

学习数据结构(2)算法复杂度+顺序表

1.空间复杂度 &#xff08;1&#xff09;概念 空间复杂度也是一个数学表达式&#xff0c;表示一个算法在运行过程中根据算法的需要额外临时开辟的空间。 空间复杂度不是指程序占用了多少bytes的空间&#xff0c;因为常规情况每个对象大小差异不会很大&#xff0c;所以空间复杂…...

MyBatis和JPA区别详解

文章目录 MyBatis和JPA区别详解一、引言二、设计理念与使用方式1、MyBatis&#xff1a;半自动化的ORM框架1.1、代码示例 2、JPA&#xff1a;全自动的ORM框架2.1、代码示例 三、性能优化与适用场景1、MyBatis&#xff1a;灵活的SQL控制1.1、适用场景 2、JPA&#xff1a;开发效率…...

DeepSeek明确学术研究方向效果如何?

明确学术研究方向 在学术写作中&#xff0c;选择一个出色的研究主题至关重要&#xff0c;因为它直接关系到论文是否能登上高级别的学术期刊。不少学者在这个过程中走入了误区&#xff0c;他们往往将大把的时间花在写作本身&#xff0c;而忽略了对选题的深入思考&#xff0c;这…...

牛客周赛round78 B,C

B.一起做很甜的梦 题意&#xff1a;就是输出n个数&#xff08;1-n&#xff09;&#xff0c;使输出的序列中任意选连续的小序列&#xff08;小序列长度>2&&<n-1&#xff09;不符合排列&#xff08;例如如果所选长度为2&#xff0c;在所有长度为2 的小序列里不能出…...

基于语义-拓扑-度量表征引导的大语言模型推理的空中视觉语言导航

1. 摘要翻译及主要贡献点 摘要&#xff1a; 空中视觉语言导航&#xff08;VLN&#xff09;是一项新兴任务&#xff0c;它使无人机能够通过自然语言指令和视觉线索在户外环境中导航。由于户外空中场景中复杂的空间关系&#xff0c;这项任务仍然具有挑战性。本文提出了一种端到…...

如何在Spring Boot项目中高效集成Spring Security

1 Spring Security 介绍 Spring Security 是一个功能强大且高度可定制的安全框架,专为保护基于Java的应用程序而设计。它不仅提供了认证(Authentication)和授权(Authorization)的功能,还支持防止各种常见的安全攻击模式。本文将详细介绍Spring Security的主要特点、功能…...

React 前端框架实战教程

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 引言 React 是由 Facebook 开发的前端 JavaScript 库&#xff0c;旨在构建高效、灵活的用户界面&#xff0c;尤其适用于单页应用…...

c语言中的数组(上)

数组的概念 数组是⼀组相同类型元素的集合&#xff1b; 数组中存放的是1个或者多个数据&#xff0c;但是数组元素个数不能为0。 数组中存放的多个数据&#xff0c;类型是相同的。 数组分为⼀维数组和多维数组&#xff0c;多维数组⼀般⽐较多⻅的是⼆维数组。 数组创建 在C语言…...

Spring Boot 中的事件发布与监听:深入理解 ApplicationEventPublisher(附Demo)

目录 前言1. 基本知识2. Demo3. 实战代码 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 基本的Java知识推荐阅读&#xff1a; java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&am…...

java.math 包 中的 BigDecimal 类(详细案例拆解)

前言&#xff1a; 小编打算近期更俩三期类的专栏&#xff0c;一些常用的专集类&#xff0c;给大家分好类别总结和详细的代码举例解释。 今天是第五个 java.lang.Math 包中的 BigDecimal 类 我们一直都是以这样的形式&#xff0c;让新手小白轻松理解复杂晦涩的概念&#xff0c…...

【记录】日常|从零散记录到博客之星Top300的成长之路

文章目录 shandianchengzi 2024 年度盘点概述写作风格简介2024年的创作内容总结 shandianchengzi 2024 年度盘点 概述 2024年及2025年至今我创作了786即84篇文章&#xff0c;加上这篇就是85篇。 很荣幸这次居然能够入选博客之星Top300&#xff0c;这个排名在我之前的所有年份…...

定时器按键tim_key模版

低优先级放在高优先级内势必是程序卡死 把高优先级放到低优先级内&#xff0c;会使程序卡死 可修改 Debuger调试方法 Pwm rcc #include "my_main.h" uint8_t led_sta0x10; char text[30]; void LED_Disp(uint8_t dsLED) {HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPI…...

Swing使用MVC模型架构

什么是MVC模式? MVC是一组英文的缩写,其全名是Model-View-Controller,也就是“模型-视图-控制器”这三个部分组成。这三个部分任意一个部分发生变化都会引起另外两个发生变化。三者之间的关系示意图如下所示: MVC分为三个部分,所以在MVC模型中将按照此三部分分成三…...

ui-automator定位官网文档下载及使用

一、ui-automator定位官网文档简介及下载 AndroidUiAutomator&#xff1a;移动端特有的定位方式&#xff0c;uiautomator是java实现的&#xff0c;定位类型必须写成java类型 官方地址&#xff1a;https://developer.android.com/training/testing/ui-automator.html#ui-autom…...