Qt + FFmpeg实现播放器(FFmpeg可以解码的格式基本都可以播放)。

2023-05-16

一、开发环境的准备

Linux下移植ffmpeg开源库。

二、代码实现播放功能

1、打开音视频流并获取音视频流信息;
2、查找视频流位置以及查找并打开视频解码器;
3、视频解码的同时处理图片像素数据;
4、最后要释放申请的内存空间。
*

.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QDesktopWidget>
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = NULL);
    ~Widget();

private slots:
    void on_pushButton_clicked();
    void slotOpenFile();
    void on_Close_clicked();
    void on_Close_2_clicked();

private:
    Ui::Widget *ui;
    QString currentFileName;
};

#endif // WIDGET_H

.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QTime>
#include <QFileDialog>
#include <QScreen>
// 调用FFmpeg的头文件
extern "C"{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
}

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle("hello");//设置窗口的标题
    QObject::connect(ui->open,SIGNAL(clicked()),this,SLOT(slotOpenFile()));
}

Widget::~Widget()
{
    delete ui;
}

// 延时函数
void delay(int msec)
{
    QTime dieTime = QTime::currentTime().addMSecs(msec);
    while( QTime::currentTime() < dieTime )
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}

void Widget::slotOpenFile()//打开文件键
{
    currentFileName = QFileDialog::getOpenFileName(this, tr("open-file"), tr(""),
                    tr("Video files(*.rmvb *.rm *.avi *.wmv *.mkv *.asf *.3gp *.mov *.mp4 *.ogv* )"));
    if( !currentFileName.isEmpty() )
    {
        on_pushButton_clicked();
    }
}


void Widget::on_pushButton_clicked()
{
    AVFormatContext *pFormatCtx; // 存储音视频封装格式中包含的信息
    int videoIndex = -1; // 视频帧索引,初始化为-1
    AVCodecContext *pCodecCtx; // 视频流编码结构
    AVCodec *pCodec; // 视频解码器
    AVFrame *pFrame, *pFrameRGB;
    unsigned char *out_buffer;
    AVPacket *packet;
    int ret, got_picture;
    struct SwsContext *img_convert_ctx; // 主要用于视频图像的转换

    char file_path[1280] = {0};
    strcpy(file_path,currentFileName.toUtf8().data());

    // 注册FFMpeg的库
    av_register_all();

    /*** (一)打开音视频流并获取音视频流信息 ***/
    // 初始化AVFormatContext
    pFormatCtx = avformat_alloc_context();
    // 打开音视频流
    /*avformat_open_input函数*/
   //打开一个文件并解析。可解析的内容包括:视频流、音频流、视频流参数、音频流参数、视频帧索引。
   //参数一:AVFormatContext **ps, 格式化的上下文(由avformat_alloc_context分配)的指针。
   //参数二:要打开的流的url,地址最终会存入到AVFormatContext结构体当中。
   //参数三:指定输入的封装格式。一般传NULL,由FFmpeg自行探测。
   //参数四:包含AVFormatContext和demuxer私有选项的字典。返回时,此参数将被销毁并替换为包含找不到的选项
    if (avformat_open_input(&pFormatCtx, file_path, NULL, NULL) != 0)
    {
        printf("Couldn't open input stream.\n");
        return;
    }
    // 获取音视频流数据信息
    if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
    {
        printf("Couldn't find stream information.\n");
        return;
    }

    /*** (二)查找视频流位置以及查找并打开视频解码器 ***/
    // 查找视频流的起始索引位置(nb_streams表示视音频流的个数)
    for (int i = 0; i < (int)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 ;
    }
    // 查找视频解码器
    pCodecCtx = pFormatCtx->streams[videoIndex]->codec; // 获取视频流编码结构
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    if (pCodec == NULL)
    {
        printf("Codec not found.\n");
        return ;
    }
    // 打开解码器
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
    {
        printf("Could not open codec.\n");
        return ;
    }

    // 打印视频信息
    printf("--------------- File Information ----------------\n");
    av_dump_format(pFormatCtx, 0, file_path, 0); // 此函数打印输入或输出的详细信息
    printf("-------------------------------------------------\n");

    /*** (三)视频解码的同时处理图片像素数据 ***/
    // 创建帧结构,此函数仅分配基本结构空间,图像数据空 间需通过av_malloc分配
    pFrame = av_frame_alloc();
    pFrameRGB = av_frame_alloc();
    // 创建动态内存,创建存储图像数据的空间(av_image_get_buffer_size获取一帧图像需要的大小)
    out_buffer = (unsigned char *)av_malloc((size_t)av_image_get_buffer_size(AV_PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height, 1));
    // 存储一帧像素数据缓冲区
    av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, out_buffer,
        AV_PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height, 1);
    packet = (AVPacket *)av_malloc(sizeof(AVPacket));

    // 初始化img_convert_ctx结构
    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);
    // av_read_frame读取一帧未解码的数据
    while (av_read_frame(pFormatCtx, packet) >= 0)
    {
        // 如果是视频数据
        if (packet->stream_index == videoIndex)
        {
            // 解码一帧视频数据
            ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
            if (ret < 0)
            {
                printf("Decode Error.\n");
                return ;
            }
            if (got_picture)
            {
                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)); // 在label上播放视频图片
                delay(40);
            }
        }
        av_free_packet(packet);
    }

    /*** (四)最后要释放申请的内存空间 ***/
    sws_freeContext(img_convert_ctx); // 释放一个SwsContext
    av_frame_free(&pFrameRGB);
    av_frame_free(&pFrame);
    avcodec_close(pCodecCtx);
    avformat_close_input(&pFormatCtx);
}


void Widget::on_Close_clicked()//退出键
{
    close();
}

void Widget::on_Close_2_clicked()//全屏键
{
    static bool max = false;
    static QRect location = this->geometry();
    if (max) {
        this->setGeometry(location);
    } else {
        location = this->geometry();
        this->setGeometry(qApp->desktop()->availableGeometry());
    }

    this->setProperty("canMove", max);
    max = !max;
}

三、参考源码

Qt + FFmpeg简单实现视频播放
Qt + FFmpeg实时视频播放

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt + FFmpeg实现播放器(FFmpeg可以解码的格式基本都可以播放)。 的相关文章

  • @ApiModel 和 @ApiModelProperty

    64 ApiModel 使用场景 xff1a 在实体类上边使用 xff0c 标记类时swagger的解析类 1 什么是Swagger OpenAPI规范 xff08 OpenAPI Specification 简称OAS xff09 是Li
  • MySQL_基本的SELECT语句

    目录 SQL概念 xff1a SQL分类 xff1a SQL语言的规则与规范 xff1a SELECT的基本语句 我是ZGB xff0c Java领域新星创作者 xff0c 阿里云专家博主 xff0c 华为云 云享专家博主 xff0c 热衷
  • springcloud之gateway服务网关

    目录 微服务中网关的作用 gateway 与 zuul springcloud gateway 简介 相关概念 工作流程 特征 快速上手 Maven 依赖 application properties 配置文件 启动类 eureka cli
  • 4438无线网络组网代码解析

    device bind process 是怎么实现绑定的 xff1f enum NOSTATE UBIND 等待接收 握手一次1 WAIT FOR TOUCH WAIT FOR CONFIRM 点击按键后 回复一次2 BIND SUCCES
  • python—函数

    函数 定义和注意事项 将可能需要反复执行的代码封装为函数 xff0c 并在需要该功能的地方进行调用 xff0c 不仅可以实现代码复用 xff0c 更重要的是可以保证代码的一致性 xff0c 只需要修改该函数代码则所有调用均受到影响 设计函数
  • ROS安装gazebo教程及报错解决,并基于gazebo仿真环境实现机器人在复杂路径下自动导航(更新中)

    安装教程 xff1a 教程 70分钟入门gazebo 报错一 xff1a E Could not get lock var lib dpkg lock frontend open 11 Resource temporarily unavai
  • UCOSIII-消息队列

    目录 1 简介 1 1消息队列 xff08 异步通信方式 xff09 1 2消息池 2 结构体 2 1消息元素os msg 2 2消息池元素osmsgpool 全局变量 2 3消息队列结构体OS Q 2 4消息列表结构体OS MSG Q 3
  • 利用Nodemcu+Arduino nano+TB6612+点灯科技APP制作简易麦克纳姆轮Wi-Fi遥控小车

    摘要 麦克纳姆轮小车由于车轮本身的特殊结构 xff0c 可以实现全向行驶 xff0c 可玩性非常强 麦克纳姆轮原理在这里不做展开 xff0c 麦克纳姆小车主要是通过控制四个轮胎的转与不转以及转动的方向来实现多方向的运动 xff0c 其中一种
  • Collecting package metadata (current_repodata.json): fail亲测成功

    在Ubantu中创建anaconda虚拟环境时报错 xff1a Collecting package metadata current repodata json failed ProxyError Conda cannot proceed
  • Vue----模板渲染语法中使用JavaScript表达式

    文章目录 3 5 模板渲染语法中使用JavaScript表达式 3 5 模板渲染语法中使用JavaScript表达式 在vue提供的模板渲染语法中 xff0c 除了支持绑定简单的数据值外 xff0c 还支持JavaScript表达式运算 用
  • 树莓派下载Ubuntu20.04.3版本 +通过设置找到wifi标志+开启vnc远程桌面+灰屏解决方法

    貌似从19版本开始就下完之后右上角没有出现wifi标志 xff0c 在csdn上也十分难找到方法 xff0c 对于网线直连的 csdn上是有十分多的方法的 xff0c 大家可以去找找看 但是对于一开始就连wifi的方法似乎特别少 xff0c
  • 字符数组和字符串数组中的‘\0‘尾零存在的问题

    一 在字符和字符串中是否必须存在 答 xff1a 在字符数组中非必要存在 xff0c 但是在字符串数组中定义的时候必须存在 字符数组 1 并不要求它的最后一个字符为 39 0 39 xff0c 甚至可以不包括 39 0 39 xff0c 像
  • FreeRTOS学习笔记一

    FreeRTOS 任务不允许以任何方式从实现函数中返回 它们绝不能有一条 return 语句 void ATaskFunction void pvParameters int iVariableExample 61 0 for 传入NULL
  • css实现loading效果

    主要利用css3特性 xff0c 以及伪元素的使用实现此功能 lt html lang 61 34 en 34 gt lt head gt lt meta charset 61 34 UTF 8 34 gt lt meta http equ
  • ros学习记录:Gazebo加载速度慢,长时间停在“Preparing your world”

    前言 ros学习记录笔记 xff0c 一个小白的自留地 xff0c 欢迎大佬批评指正 一 问题描述 Gazebo加载速度慢 xff0c 长时间停在 Preparing your world 二 解决办法 1 下载模型到根文件下的 gazeb
  • ROS坐标系统,常见的坐标系和其含义

    摘自 xff1a ros基础必看之各个frame的理解 黑猫爱小鹿的博客 CSDN博客 文章目录 常见的坐标系坐标系的约定坐标系变换的计算Map之间的切换添加 ros中常见的坐标系 转载链接 1 1 现在小车进行移动 1 2 如图 1 2
  • 运行roscore报错解决(重装ROS)

    前言 一个小白的自留地 xff0c 欢迎大佬批评指正 运行roscore出现如下错误 WARNING unable to configure logging No log files will be generated Checking l
  • keil5出现‘Target not created‘

    keil5出现 Target not created 新建工程中写了main函数进行编译时出现错误的问题 xff1a Using Compiler 39 V5 06 update 5 build 528 39 folder 39 D Kei
  • 2 常见模块库(2)

    2 5 复用器与分路器模块 Mux是一种用于将多个信号组合成一个信号的模块 Mux模块的名称来源于多路复用器 xff08 Multiplexer xff09 使用Mux可以将多个输入信号组合成一个向量或矩阵 xff0c 以便在模型中传递和处
  • 8 DWA(一)

    8 DWA DMA简介 DMA xff08 Direct Memory Access xff09 直接存储器存取 xff08 可以直接访问32内部存储器 xff0c 包括内存SRAM xff0c Flash xff09 DMA可以提供外设和

随机推荐

  • 9 串口通信(一)

    9 串口通信 通信接口 通信的目的 xff1a 将一个设备的数据传送到另一个设备 xff0c 扩展硬件系统 通信协议 xff1a 制定通信的规则 xff0c 通信双方按照协议规则进行数据收发 名称引脚双工时钟电平设备USARTTX RX全双
  • 9 串口通信(二)

    函数介绍 xff1a span class token comment init三剑客 span span class token keyword void span span class token function USART DeIn
  • 3 连续模块(二)

    3 5 零极点增益模块 在控制系统设计和分析中 xff0c 常用的函数包括 传递函数 xff08 tf xff09 零极点 xff08 zpk xff09 和状态空间 xff08 ss xff09 函数 传递函数 xff08 tf xff0
  • Android packageManagerService如何添加安装权限白名单

    https blog csdn net myvest article details 54344076
  • 4 非线性模块库(二)

    4 4 量化模块及归零模块 1 xff09 Quantizer 在Simulink中 xff0c Quantizer xff08 量化器 xff09 模块是一种数学运算模块 xff0c 用于将连续信号离散化为多级离散值 xff0c 具有模拟
  • TRIZ创新方法——技术系统进化趋势

    技术系统进化趋势 技术系统及进化趋势S曲线法则技术系统的S曲线产品的进化曲线 八大技术系统进化法则 xff08 1 xff09 完备性法则 xff08 2 xff09 能量传递法则 xff08 3 xff09 协调性进化法则 xff08 4
  • 英特尔 NUC X15 笔记本 评测 英特尔上架新款 NUC X15 笔记本参数配置

    配置方面 xff0c 这款笔记本搭载了 i7 12700H 处理器 xff0c 14 核 20 线程 xff0c 睿频可达 4 7GHz 显卡为英特尔锐炫 A730M xff0c 搭载 24 个 Xe 内核 xff0c 拥有 12GB 19
  • vs2019未能正确加载解决方案的项目

    网上朋友们说是路径出了问题 xff0c 需要修改 vcxproj文件的内容 xff0c 我试了一下没成功 最后发现 xff0c 所以打不开 xff0c 是因为我下载了别人的项目 xff0c 用解压软件解压后直接打开了 sln 当我把解压后的
  • 自我提升解决bug的能力(一)

    我和大家分享一个我的自我提升解决bug的能力 满满的干货 一名优秀的程序员会具备较强解决bug的能力 如果你觉得自己不够优秀 xff0c 解决bug能力不足 xff0c 学习处于被动的状态 那我要大声的告诉你请不要迷茫 xff0c 陷入低沉
  • 论文笔记:VIBE: Video Inference for Human Body Pose and Shape Estimation

    要解决的问题 有3D关键点标注的数据集太少 xff0c 所以我们想生成这样的数据集 所以我们提出了一个 利用视频进行动作估计的新方法 xff0c 解决了数据集缺乏和预测准确率不佳的问题 主要创新点 利用 对抗式生成网络 来区分 真实人类动作
  • 2022年春招实习十四面(嵌入式面经)(已完结)

    文章目录 前言CVTE xff08 嵌入式软件 xff09 CVTE一面 xff08 嵌入式软件开发 xff09 时长 xff1a 50分钟CVTE二面 xff08 55分钟 xff09 阿里菜鸟网络 xff08 嵌入式软件 xff09 阿
  • 二分算法简单介绍

    二分算法 xff0c 顾名思义 就是把一组有序数据的搜索区域缩小一半 下面给大家举例说明一下 如何确定被缩小的搜索区间 原理分析 拿一个有序的整形数组来举例 int a 10 61 1 2 3 4 5 6 7 8 9 10 xff0c 在初
  • 论文投稿指南——中文核心期刊

    gt gt gt 深度学习Tricks xff0c 第一时间送达 lt lt lt 目录 xff08 一 xff09 国内三大核心 1 中文社会科学引文索引 xff08 CSSCI 南大核心 xff09 2 中国科学引文数据库 xff08
  • linux opendir(打开目录函数) readdir(读取目录函数) closedir(关闭目录函数)

    Linux下opendir readdir 和closedir 这三个函数主要用来遍历目录 在使用这三个函数前必须先包括以下两个头文件 xff1a include lt sys types h gt include lt dirent h
  • Cmakelists.txt 的基本框架

    执行 cmake 表示在当前目录下执行 cmake cmake 表示在前一级目录下执行 cmake make 在当前目录下执行 make 语法 1 设置 cmake 版本需求 cmake minimum required VERSION 2
  • UartAssist - 串口调试助手。

    由于项目需要用到串口 xff0c 所以我就找到一个简单易上手的串口调试助手 串口调试助手 1 助手界面 xff1a 2 设置串口 xff0c 点击 打开 3 设置发送区和接收区参数 4 输入发送内容 xff0c 点击 发送 即可
  • 网络摄像机rtsp地址详解。

    RTSP xff08 Real Time Streaming Protocol xff09 xff0c RFC2326 xff0c 实时流传输协议 xff0c 是TCP IP协议体系中的一个应用层协议 xff0c 由哥伦比亚大学 网景和Re
  • Qt 登陆界面实现

    简单的QT用户登录界面 一 项目描述 在登录界面输入用户名和密码正确之后才进入欢迎界面 用户名 xff1a xiaoxian 密码 xff1a 1240 二 效果图 三 源代码 loginform span class token punc
  • FFMPEG保存视频流数据至本地(rtsp转mp4)

    将rtsp流中的h264视频流在没解码之前获取下来 xff0c 并保存到本地文件mp4中的h264流中 xff0c h264 gt mp4 网络摄像机rtsp地址详解 流程图 xff1a 源码 xff1a span class token
  • Qt + FFmpeg实现播放器(FFmpeg可以解码的格式基本都可以播放)。

    一 开发环境的准备 Linux下移植ffmpeg开源库 二 代码实现播放功能 1 打开音视频流并获取音视频流信息 xff1b 2 查找视频流位置以及查找并打开视频解码器 xff1b 3 视频解码的同时处理图片像素数据 xff1b 4 最后要