gstreamer+qt5实现简易视频播放器

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、安装环境
    • 1.QT5
    • 2.gstreamer
  • 二、代码
    • 1.Windows实现
  • 三、测试效果
  • 总结


前言

最近在研究mpp,通过gstreamer实现了硬解码,但是我在想我可能需要一个播放器,我之前学过qt5所以就选择了qt5来结合gstreamer开发一个简单的播放器。今天的环境基于Windows,后续会把Linux的也补上的。

注意:基于QT5,我觉得因为全平台特性,可能QT5比MFC还是有优势,代码只需要小改就可以轻松移植。


一、安装环境

本身不需要特殊配置就支持N卡硬解码,A卡和I卡可能要借助VAAP,我手上没有设备,暂未研究。所以显卡驱动和芯片组驱动就不说了肯定都是要装的。

1.QT5

这个不介绍了,网上找找就好了。

2.gstreamer

Windows11安装并使用Gstreamer-1.0

二、代码

代码很简单,没有特别做UI,只实现了视频硬解码、播放和音频播放功能

1.Windows实现

代码只能跑在Windows上因为播放组件是需要区分WIndows和Linux甚至MacOS的。

Gstreamer_Player.pro

QT       += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++17# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \mainwindow.cppHEADERS += \mainwindow.hFORMS += \mainwindow.ui# 添加GStreamer和Glib库
unix {PKGCONFIG += gstreamer-1.0 gstreamer-video-1.0 glib-2.0 gstvideo-1.0
}# 如果你使用的是Windows,请添加以下内容,并调整路径
win32 {INCLUDEPATH += E:/gstreamer/1.0/msvc_x86_64/include/gstreamer-1.0INCLUDEPATH += E:/gstreamer/1.0/msvc_x86_64/include/glib-2.0INCLUDEPATH += E:/gstreamer/1.0/msvc_x86_64/lib/glib-2.0/includeLIBS += -LE:/gstreamer/1.0/msvc_x86_64/lib -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lgstvideo-1.0
}# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <gst/gst.h>
#include <gst/video/videooverlay.h>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void on_playButton_clicked();private:Ui::MainWindow *ui;GstElement *pipeline;
};#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QFileDialog>//代码只有Windows系统才执行
#ifdef Q_OS_WIN
#include <windows.h>
#include <dwmapi.h>
#endifMainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);gst_init(nullptr, nullptr);pipeline = gst_pipeline_new("pipeline");GstElement *source = gst_element_factory_make("filesrc", "source");GstElement *demuxer = gst_element_factory_make("decodebin", "demuxer");GstElement *videoconvert = gst_element_factory_make("videoconvert", "videoconvert");GstElement *videosink = gst_element_factory_make("d3dvideosink", "videosink");GstElement *audioconvert = gst_element_factory_make("audioconvert", "audioconvert");GstElement *audioresample = gst_element_factory_make("audioresample", "audioresample");GstElement *audiosink = gst_element_factory_make("autoaudiosink", "audiosink");//这一句可以合并,因为都是必须创建成功的if (!pipeline || !source || !demuxer || !videoconvert || !videosink || !audioconvert || !audioresample || !audiosink) {QMessageBox::critical(this, "Error", "Failed to create GStreamer elements.");return;}gst_bin_add_many(GST_BIN(pipeline), source, demuxer, videoconvert, videosink, audioconvert, audioresample, audiosink, nullptr);gst_element_link(source, demuxer);g_signal_connect(demuxer, "pad-added", G_CALLBACK(+[](GstElement *demuxer, GstPad *new_pad, gpointer user_data) {GstElement *pipeline = GST_ELEMENT(user_data);GstPad *videoconvert_sink_pad = gst_element_get_static_pad(gst_bin_get_by_name(GST_BIN(pipeline), "videoconvert"), "sink");GstPad *audioconvert_sink_pad = gst_element_get_static_pad(gst_bin_get_by_name(GST_BIN(pipeline), "audioconvert"), "sink");GstPadLinkReturn ret;GstCaps *new_pad_caps = gst_pad_get_current_caps(new_pad);GstStructure *new_pad_struct = gst_caps_get_structure(new_pad_caps, 0);const gchar *new_pad_type = gst_structure_get_name(new_pad_struct);if (g_str_has_prefix(new_pad_type, "video/x-raw")) {ret = gst_pad_link(new_pad, videoconvert_sink_pad);} else if (g_str_has_prefix(new_pad_type, "audio/x-raw")) {ret = gst_pad_link(new_pad, audioconvert_sink_pad);} else {ret = GST_PAD_LINK_OK;}if (GST_PAD_LINK_FAILED(ret)) {g_printerr("Type is '%s' but link failed.\n", new_pad_type);} else {g_print("Link succeeded (type '%s').\n", new_pad_type);}gst_object_unref(videoconvert_sink_pad);gst_object_unref(audioconvert_sink_pad);gst_caps_unref(new_pad_caps);}), pipeline);gst_element_link_many(videoconvert, videosink, nullptr);gst_element_link_many(audioconvert, audioresample, audiosink, nullptr);GstBus *bus = gst_element_get_bus(pipeline);gst_bus_add_signal_watch(bus);g_signal_connect(bus, "message::error", G_CALLBACK(+[](GstBus *bus, GstMessage *msg, gpointer user_data) {GError *err;gchar *debug_info;gst_message_parse_error(msg, &err, &debug_info);g_printerr("Error received from element %s: %s\n", GST_OBJECT_NAME(msg->src), err->message);g_printerr("Debugging information: %s\n", debug_info ? debug_info : "none");g_clear_error(&err);g_free(debug_info);}), nullptr);gst_object_unref(bus);WId winId = ui->videoWidget->winId();gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(videosink), winId);
}MainWindow::~MainWindow()
{gst_element_set_state(pipeline, GST_STATE_NULL);gst_object_unref(pipeline);delete ui;
}void MainWindow::on_playButton_clicked()
{QString filename = QFileDialog::getOpenFileName(this, "Open Video File", "", "Video Files (*.mp4 *.avi *.mkv)");if (filename.isEmpty())return;gst_element_set_state(pipeline, GST_STATE_READY);g_object_set(G_OBJECT(gst_bin_get_by_name(GST_BIN(pipeline), "source")), "location", filename.toStdString().c_str(), nullptr);gst_element_set_state(pipeline, GST_STATE_PLAYING);
}

main.cpp

#include "mainwindow.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}

mainwindow.ui

一个Widget命名为videoWidget,一个Pushbutton命名为playButton。布局参考下面的:

在这里插入图片描述

注意:选择MSVC 2015编译链,要不然会找不到库!

在这里插入图片描述

三、测试效果

在这里插入图片描述

除非花里胡哨的特效,一般UI在Windows上和Linux上可以复用。

在这里插入图片描述

在这里插入图片描述

实测可以正常调用N卡硬解码(需要显卡支持)。


总结

1、不算太难,复杂的应用还需要继续琢磨。
2、Windows上还是简单,我最终的目标是在开发板上实现gstreamer+qt5+硬解码播放,开发板上没有统一的接口。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/31431.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ROS实验课(三)

write in advance 此次实验课给我的生活来了沉重的一击&#xff0c;不单单是因为没有做出来&#xff0c;还因为我卡在了 插件 缺失 而无法解决。之前对待实验课&#xff0c;能在操作流程之外有暇思考具体的实现&#xff0c;此次只能记录简单的操作流程部分。 老规矩&#xff…

小米手机怎么用代理换ip:步骤详解与实用指南

在数字化时代&#xff0c;网络安全与隐私保护日益受到重视。对于小米手机用户而言&#xff0c;使用代理换IP已成为提升网络安全性、访问特定网站或绕过地域限制的有效手段。本文将详细介绍如何在小米手机上设置代理以更换IP地址&#xff0c;帮助用户更好地保护个人信息和享受更…

javascript浏览器对象模型

BOM对象&#xff1a; BOM 是浏览器对象模型的简称。JavaScript 将整个浏览器窗口按照实现的功能不同拆分成若干个对象&#xff1b; 包含&#xff1a;window 对象、history 对象、location 对象和 document 对象等 window对象&#xff1a; 常用方法&#xff1a; 1.prompt();…

文化保护与数字化时代:Facebook的文化责任

随着数字化时代的到来&#xff0c;全球各地的文化遗产和传统面临着前所未有的挑战和机遇。作为全球最大的社交网络平台之一&#xff0c;Facebook在连接亿万用户的同时&#xff0c;也肩负着重要的文化责任。本文将深入探讨Facebook在文化保护和传承方面的作用和责任&#xff0c;…

入门Rabbitmq

1、什么是消息队列 消息队列&#xff1a;应用之间传递消息的方式&#xff0c;允许应用程序异步发送和接收消息&#xff0c;不需要连接对方 消息&#xff1a;文本字符串&#xff0c;对象.... 队列&#xff1a;存储数据。先进先出 2、应用场景 ①库存系统挂掉之后 MQ会等待&…

修改vscode的主题颜色

1、首选项--主题--颜色主题 2、选择一个喜欢的颜色主题 这样就可以了。

推动产业数字化转型,六个方面引领变革

从工业经济时代走向数字经济时代&#xff0c;世界经济发生着全方位、革命性的变化&#xff0c;产业数字化便是最显著的表现之一。当前&#xff0c;产业数字化不断深入发展&#xff0c;平台经济、工业互联网、智能制造等新业态、新模式不断涌现&#xff0c;成为了数字经济的重要…

深度分析:React Native、Flutter、UniApp、Taro、Vue的差异

深度分析&#xff1a;React Native、Flutter、UniApp、Taro、Vue React Native 优势: 跨平台代码共享&#xff1a;使用JavaScript和React&#xff0c;可以为iOS和Android开发应用&#xff0c;代码复用率高。活跃社区和生态系统&#xff1a;React和React Native有庞大的社区&a…

chatgpt的原理是什么

ChatGPT 是基于 OpenAI 开发的 GPT&#xff08;Generative Pre-trained Transformer&#xff09;系列模型&#xff0c;它的原理依赖于深度学习、自然语言处理&#xff08;NLP&#xff09;以及 Transformer 架构。以下是 ChatGPT 的工作原理的详细解释&#xff1a; 1. Transform…

php上传zip压缩包到服务器并解压,解析压缩包内excel表格数据导入到数据库

需求: 1.需要管理后台将excel表格中的每条单词数据导入到数据库中. 2.每条单词数据对应的图片和音频文件需要上传到服务器中. 为了让客户上传数据方便,考虑了一下决定通过后台上传压缩包的方式实现 测试压缩包: 压缩包的目录结构 管理后台导入教材 public function upload…

深度学习算法informer(时序预测)(五)(informer整体模型)

整体架构如图 代码如下 lass Informer(nn.Module):def __init__(self, enc_in, dec_in, c_out, seq_len, label_len, out_len, factor5, d_model512, n_heads8, e_layers3, d_layers2, d_ff512, dropout0.0, attnprob, embedfixed, freqh, activationgelu, output_attention …

判断101 - 200之间有多少个素数,并输出所有素数。

题目&#xff1a;判断101 - 200之间有多少个素数&#xff0c;并输出所有素数。 解法一&#xff1a;程序分析&#xff1a;判断素数的方法&#xff1a;用一个数分别去除2到sqrt(这个数)&#xff0c;如果能被整除&#xff0c;则表明此数不是素数&#xff0c;反之是素数。 void ma…

鸿蒙开发通信与连接:【@ohos.wifi (WLAN)】

WLAN 说明&#xff1a; 本模块首批接口从API version 6开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import wifi from ohos.wifi;wifi.isWifiActive isWifiActive(): boolean 查询WLAN是否已激活。 需要权限&#xff1a; ohos.p…

stable diffusion 模型和lora融合

炜哥的AI学习笔记——SuperMerger插件学习 - 哔哩哔哩接下来学习的插件名字叫做 SuperMerger,它的作用正如其名,可以融合大模型或者 LoRA,一般来说会结合之前的插件 LoRA Block Weight 使用,在调整完成 LoRA 模型的权重后使用改插件进行重新打包。除了 LoRA ,Checkpoint 也…

PCL 拟合二维椭圆(迭代法)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 一般情况,我们会用椭圆拟合二维点,用椭球拟合三维点。在n维中,这些对象被称为超椭球体,由二次方程隐式定义 超椭球的中心是n1向量C,nn矩阵S是正定的,n1向量X是超椭球上的任意点。矩阵S可以用特征分解,S = R…

ATFX Connect四度加冕!荣膺2024最佳机构业务经纪商奖

近期&#xff0c;知名经纪商ATFX凭借在公益、科技、教育及媒体领域的一系列创新营销举措&#xff0c;掀起一波营销热潮&#xff0c;品牌联动效应显著。日前&#xff0c;ATFX又以实力而赢得一项新荣誉。全球知名媒体Holiston Media举办的2024环球金融大奖 (Global Forex Awards …

网站安全防护怎么做?

引言&#xff1a;在当今数字化的时代&#xff0c;网络安全已经成为个人、企业乃至整个社会的一项关键挑战。随着互联网的普及和信息技术的迅猛发展&#xff0c;我们的生活和工作方式日益依赖于各种互联网服务和数据交换。然而&#xff0c;这种依赖也带来了越来越多的安全威胁和…

瞭解代理伺服器主要使用的是什麼協議

代理伺服器可以使用多種協議來實現其功能。以下是幾種常見的代理協議&#xff0c;包括它們的工作原理、應用場景以及優缺點。 1. HTTP代理 最常見的代理協議之一&#xff0c;主要用於處理網頁流覽請求。 工作原理&#xff1a;HTTP代理伺服器接收客戶端的HTTP請求&#xff0c…

分层Agent

分层Teams 分层Agent创建tool研究团队工具文档编写团队工具 通用能力定义Agent团队研究团队文档编写团队 添加图层 分层Agent 在前面的示例&#xff08;Agent管理&#xff09;中&#xff0c;我们引入了单个管理节点的概念&#xff0c;用于在不同工作节点之间路由工作。 但是&a…

C++堆栈的区别?两者大小有限制吗?【面试】

C堆栈的区别&#xff1a; 内存分配方式&#xff1a; 堆&#xff1a;由程序员手动分配和释放&#xff0c;如果程序员不释放&#xff0c;程序结束时可能由操作系统(OS)回收。堆的分配方式类似于链表。栈&#xff1a;由编译器自动分配和释放&#xff0c;主要存放函数的参数值和局部…