目录
1 前言
2 playbin3
3 videooverlay
4 关键代码
5 运行示例
1 前言
最近因为工作需求,要实现一个桌面流媒体播放器来支持常见的流媒体协议,经过调研发现使用gstreamer配合一些桌面级的gui应用开发工具如qt可以进行快速实现,在此进行记录。
2 playbin3
gstreamer是一个基于组件(element)的多媒体开发框架,并且已经提供了非常多的组件,比如文件源/网络源、parser、编解码器、音视频播放sink等,使用这些组件构造成一个pipeline后就可以直接使用了。除了基础组件外,gstreamer还提供了一些上层的已经封装好的容器组件(bin),比如这次我们要用到的playbin3就是一个高级的多媒体播放组件,里面对网络协议、parseer、解码器(包括硬解码)、音视频播放等进行了封装,另外playbin3对视频硬解码以及硬件渲染的支持也很好,作为使用者只需进行创建、设置一些属性、运行即可,使用起来很简单。并且playbin3除了可以播放本地文件外,对于常见的流媒体协议都进行了支持,包括rtmp、http-flv、rtsp等。
3 videooverlay
videooverlay 是gstreamer 中的一个接口,主要用于将视频渲染到外部窗口(例如gtk、qt 或sdl窗口)。它允许应用程序控制视频的显示区域,并且可以在不同的窗口系统(如 X11、Wayland、Windows 或 macOS)上工作。
下面gstreamer中用于视频播放的sink组件都支持videooverlay接口:
- xvimagesink(X11 Xv 扩展)
- glimagesink(OpenGL 渲染)
- waylandsink(Wayland 渲染)
- d3dvideosink(Windows Direct3D)
- sdlvideosink(SDL2 渲染)
借助playbin3组件和videooverlay接口,我们就可以使用gstreamer和qt快速搭建一个流媒体播放器。
4 关键代码
#include "gstreamerwidget.h"
#include "ui_gstreamerwidget.h"
#include <QVBoxLayout>
#include <QLabel>
GStreamerWidget::GStreamerWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::GStreamerWidget)
{
ui->setupUi(this);
setWindowTitle("gstreamer qt player");
setGeometry(200, 200, 1280, 800);
// layout
QVBoxLayout *layout = new QVBoxLayout(this);
QLabel *videoLable = new QLabel(this);
videoLable->setStyleSheet("background-color: black;");
layout->addWidget(videoLable);
QHBoxLayout *h_layout = new QHBoxLayout();
edit = new QLineEdit(this);
edit->setText("file:///C:/Users/15290/Desktop/video/he.mp4");
h_layout->addWidget(edit);
play_button = new QPushButton("play", this);
h_layout->addWidget(play_button);
layout->addLayout(h_layout);
// gstreamer
gst_init(NULL, NULL);
pipeline = gst_element_factory_make("playbin3", "player");
GstElement *video_sink = gst_element_factory_make("autovideosink", nullptr);
g_object_set(pipeline, "video-sink", video_sink, nullptr);
WId winId = videoLable->winId();
gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(pipeline), winId);
connect(play_button, &QPushButton::clicked, this, &GStreamerWidget::playVideo);
}
GStreamerWidget::~GStreamerWidget()
{
delete ui;
gst_element_set_state(pipeline, GST_STATE_NULL);
g_object_unref(pipeline);
}
void GStreamerWidget::playVideo()
{
if (!playing) {
g_object_set(pipeline, "uri", edit->text().toUtf8().data(), nullptr);
gst_element_set_state(pipeline, GST_STATE_PLAYING);
play_button->setText("stop");
} else {
gst_element_set_state(pipeline, GST_STATE_READY);
play_button->setText("play");
}
playing = !playing;
}