1// Copyright (C) 2021 The Qt Company
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qgstsubtitlesink_p.h"
5#include "qgst_debug_p.h"
6
7#include <QtCore/qdebug.h>
8
9QT_BEGIN_NAMESPACE
10
11namespace {
12GstBaseSinkClass *gst_sink_parent_class;
13thread_local QAbstractSubtitleObserver *gst_current_observer;
14
15class QGstSubtitleSinkClass
16{
17public:
18 GstBaseSinkClass parent_class;
19};
20
21} // namespace
22
23#define ST_SINK(s) QGstSubtitleSink *sink(reinterpret_cast<QGstSubtitleSink *>(s))
24
25QGstElement QGstSubtitleSink::createSink(QAbstractSubtitleObserver *observer)
26{
27 gst_current_observer = observer;
28
29 QGstSubtitleSink *gstSink = reinterpret_cast<QGstSubtitleSink *>(
30 g_object_new(object_type: QGstSubtitleSink::get_type(), first_property_name: nullptr));
31
32 return QGstElement{
33 qGstCheckedCast<GstElement>(arg: gstSink),
34 QGstElement::NeedsRef,
35 };
36}
37
38GType QGstSubtitleSink::get_type()
39{
40 // clang-format off
41 static constexpr GTypeInfo info =
42 {
43 .class_size: sizeof(QGstSubtitleSinkClass), // class_size
44 .base_init: base_init, // base_init
45 .base_finalize: nullptr, // base_finalize
46 .class_init: class_init, // class_init
47 .class_finalize: nullptr, // class_finalize
48 .class_data: nullptr, // class_data
49 .instance_size: sizeof(QGstSubtitleSink), // instance_size
50 .n_preallocs: 0, // n_preallocs
51 .instance_init: instance_init, // instance_init
52 .value_table: nullptr // value_table
53 };
54 // clang-format on
55
56 static const GType type = []() {
57 const auto result = g_type_register_static(
58 GST_TYPE_BASE_SINK, type_name: "QGstSubtitleSink", info: &info, flags: GTypeFlags(0));
59 return result;
60 }();
61
62 return type;
63}
64
65void QGstSubtitleSink::class_init(gpointer g_class, gpointer class_data)
66{
67 Q_UNUSED(class_data);
68
69 gst_sink_parent_class = reinterpret_cast<GstBaseSinkClass *>(g_type_class_peek_parent(g_class));
70
71 GstBaseSinkClass *base_sink_class = reinterpret_cast<GstBaseSinkClass *>(g_class);
72 base_sink_class->render = QGstSubtitleSink::render;
73 base_sink_class->get_caps = QGstSubtitleSink::get_caps;
74 base_sink_class->set_caps = QGstSubtitleSink::set_caps;
75 base_sink_class->propose_allocation = QGstSubtitleSink::propose_allocation;
76 base_sink_class->wait_event = QGstSubtitleSink::wait_event;
77
78 GstElementClass *element_class = reinterpret_cast<GstElementClass *>(g_class);
79 element_class->change_state = QGstSubtitleSink::change_state;
80 gst_element_class_set_metadata(klass: element_class,
81 longname: "Qt built-in subtitle sink",
82 classification: "Sink/Subtitle",
83 description: "Qt default built-in subtitle sink",
84 author: "The Qt Company");
85
86 GObjectClass *object_class = reinterpret_cast<GObjectClass *>(g_class);
87 object_class->finalize = QGstSubtitleSink::finalize;
88}
89
90void QGstSubtitleSink::base_init(gpointer g_class)
91{
92 static GstStaticPadTemplate sink_pad_template =
93 GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS("ANY"));
94
95 gst_element_class_add_pad_template(
96 GST_ELEMENT_CLASS(g_class), templ: gst_static_pad_template_get(pad_template: &sink_pad_template));
97}
98
99void QGstSubtitleSink::instance_init(GTypeInstance *instance, gpointer /*g_class*/)
100{
101 ST_SINK(instance);
102
103 Q_ASSERT(gst_current_observer);
104 sink->observer = gst_current_observer;
105 gst_current_observer = nullptr;
106}
107
108void QGstSubtitleSink::finalize(GObject *object)
109{
110 // Chain up
111 G_OBJECT_CLASS(gst_sink_parent_class)->finalize(object);
112}
113
114GstStateChangeReturn QGstSubtitleSink::change_state(GstElement *element, GstStateChange transition)
115{
116 return GST_ELEMENT_CLASS(gst_sink_parent_class)->change_state(element, transition);
117}
118
119GstCaps *QGstSubtitleSink::get_caps(GstBaseSink *base, GstCaps *filter)
120{
121 return gst_sink_parent_class->get_caps(base, filter);
122}
123
124gboolean QGstSubtitleSink::set_caps(GstBaseSink *base, GstCaps *caps)
125{
126 qDebug() << "set_caps:" << caps;
127 return gst_sink_parent_class->set_caps(base, caps);
128}
129
130gboolean QGstSubtitleSink::propose_allocation(GstBaseSink *base, GstQuery *query)
131{
132 return gst_sink_parent_class->propose_allocation(base, query);
133}
134
135GstFlowReturn QGstSubtitleSink::wait_event(GstBaseSink *base, GstEvent *event)
136{
137 GstFlowReturn retval = gst_sink_parent_class->wait_event(base, event);
138 ST_SINK(base);
139 if (event->type == GST_EVENT_GAP) {
140 // qDebug() << "gap, clearing subtitle";
141 sink->observer->updateSubtitle(QString());
142 }
143 return retval;
144}
145
146GstFlowReturn QGstSubtitleSink::render(GstBaseSink *base, GstBuffer *buffer)
147{
148 ST_SINK(base);
149 GstMemory *mem = gst_buffer_get_memory(buffer, idx: 0);
150 GstMapInfo info;
151 QString subtitle;
152 if (gst_memory_map(mem, info: &info, flags: GST_MAP_READ))
153 subtitle = QString::fromUtf8(utf8: reinterpret_cast<const char *>(info.data));
154 gst_memory_unmap(mem, info: &info);
155// qDebug() << "render" << buffer << subtitle;
156 sink->observer->updateSubtitle(subtitle);
157 return GST_FLOW_OK;
158}
159
160QT_END_NAMESPACE
161

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtmultimedia/src/plugins/multimedia/gstreamer/common/qgstsubtitlesink.cpp