1 /*
2     Copyright (C) 2011 Collabora Ltd. <info@collabora.co.uk>
3       @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
4 
5     This library is free software; you can redistribute it and/or modify
6     it under the terms of the GNU Lesser General Public License as published
7     by the Free Software Foundation; either version 2.1 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU Lesser General Public License for more details.
14 
15     You should have received a copy of the GNU Lesser General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "applicationsource.h"
19 #include "../elementfactory.h"
20 #include <gst/app/gstappsrc.h>
21 
22 namespace QGst {
23 namespace Utils {
24 
25 #ifndef DOXYGEN_RUN
26 
27 struct QTGSTREAMERUTILS_NO_EXPORT ApplicationSource::Priv
28 {
29 public:
30     ElementPtr m_appsrc;
31 
32     void lazyConstruct(ApplicationSource *self);
33     void setCallbacks(ApplicationSource *self);
34 
appSrcQGst::Utils::ApplicationSource::Priv35     inline GstAppSrc *appSrc()
36     {
37         return reinterpret_cast<GstAppSrc*>(static_cast<GstElement*>(m_appsrc));
38     }
39 
40 private:
41     static void need_data(GstAppSrc *src, guint length, gpointer user_data);
42     static void enough_data(GstAppSrc *src, gpointer user_data);
43     static gboolean seek_data(GstAppSrc *src, guint64 offset, gpointer user_data);
44 
need_data_noopQGst::Utils::ApplicationSource::Priv45     static void need_data_noop(GstAppSrc*, guint, gpointer) {}
enough_data_noopQGst::Utils::ApplicationSource::Priv46     static void enough_data_noop(GstAppSrc*, gpointer) {}
seek_data_noopQGst::Utils::ApplicationSource::Priv47     static gboolean seek_data_noop(GstAppSrc*, guint64, gpointer) { return FALSE; }
48 };
49 
lazyConstruct(ApplicationSource * self)50 void ApplicationSource::Priv::lazyConstruct(ApplicationSource *self)
51 {
52     if (!m_appsrc) {
53         m_appsrc = QGst::ElementFactory::make("appsrc");
54         if (!m_appsrc) {
55             qWarning() << "Failed to construct appsrc";
56         }
57         setCallbacks(self);
58     }
59 }
60 
setCallbacks(ApplicationSource * self)61 void ApplicationSource::Priv::setCallbacks(ApplicationSource *self)
62 {
63     if (m_appsrc) {
64         if (self) {
65             static GstAppSrcCallbacks callbacks = { &need_data, &enough_data, &seek_data, NULL };
66             gst_app_src_set_callbacks(appSrc(), &callbacks, self, NULL);
67         } else {
68             static GstAppSrcCallbacks callbacks = { &need_data_noop, &enough_data_noop, &seek_data_noop, NULL };
69             gst_app_src_set_callbacks(appSrc(), &callbacks, NULL, NULL);
70         }
71     }
72 }
73 
need_data(GstAppSrc * src,guint length,gpointer user_data)74 void ApplicationSource::Priv::need_data(GstAppSrc *src, guint length, gpointer user_data)
75 {
76     Q_UNUSED(src);
77     static_cast<ApplicationSource*>(user_data)->needData(length);
78 }
79 
enough_data(GstAppSrc * src,gpointer user_data)80 void ApplicationSource::Priv::enough_data(GstAppSrc *src, gpointer user_data)
81 {
82     Q_UNUSED(src);
83     static_cast<ApplicationSource*>(user_data)->enoughData();
84 }
85 
seek_data(GstAppSrc * src,guint64 offset,gpointer user_data)86 gboolean ApplicationSource::Priv::seek_data(GstAppSrc *src, guint64 offset, gpointer user_data)
87 {
88     Q_UNUSED(src);
89     return static_cast<ApplicationSource*>(user_data)->seekData(offset) ? TRUE : FALSE;
90 }
91 
92 #endif //DOXYGEN_RUN
93 
ApplicationSource()94 ApplicationSource::ApplicationSource()
95     : d(new Priv)
96 {
97 }
98 
~ApplicationSource()99 ApplicationSource::~ApplicationSource()
100 {
101     d->setCallbacks(NULL); //remove the callbacks from the source
102     delete d;
103 }
104 
element() const105 ElementPtr ApplicationSource::element() const
106 {
107     d->lazyConstruct(const_cast<ApplicationSource*>(this));
108     return d->m_appsrc;
109 }
110 
setElement(const ElementPtr & appsrc)111 void ApplicationSource::setElement(const ElementPtr & appsrc)
112 {
113     Q_ASSERT(QGlib::Type::fromInstance(appsrc).isA(GST_TYPE_APP_SRC));
114     d->setCallbacks(NULL); //remove the callbacks from the previous source
115     d->m_appsrc = appsrc;
116     d->setCallbacks(this);
117 }
118 
caps() const119 CapsPtr ApplicationSource::caps() const
120 {
121     CapsPtr c;
122     if (d->appSrc()) {
123         c = CapsPtr::wrap(gst_app_src_get_caps(d->appSrc()), false);
124     }
125     return c;
126 }
127 
setCaps(const CapsPtr & caps)128 void ApplicationSource::setCaps(const CapsPtr & caps)
129 {
130     d->lazyConstruct(this);
131     if (d->appSrc()) {
132         gst_app_src_set_caps(d->appSrc(), caps);
133     }
134 }
135 
minLatency() const136 quint64 ApplicationSource::minLatency() const
137 {
138     guint64 ret = -1;
139     if (d->appSrc()) {
140         gst_app_src_get_latency(d->appSrc(), &ret, NULL);
141     }
142     return ret;
143 }
144 
maxLatency() const145 quint64 ApplicationSource::maxLatency() const
146 {
147     guint64 ret = -1;
148     if (d->appSrc()) {
149         gst_app_src_get_latency(d->appSrc(), NULL, &ret);
150     }
151     return ret;
152 }
153 
setLatency(quint64 min,quint64 max)154 void ApplicationSource::setLatency(quint64 min, quint64 max)
155 {
156     d->lazyConstruct(this);
157     if (d->appSrc()) {
158         gst_app_src_set_latency(d->appSrc(), min, max);
159     }
160 }
161 
size() const162 qint64 ApplicationSource::size() const
163 {
164     return d->appSrc() ? gst_app_src_get_size(d->appSrc()) : -1;
165 }
166 
setSize(qint64 size)167 void ApplicationSource::setSize(qint64 size)
168 {
169     d->lazyConstruct(this);
170     if (d->appSrc()) {
171         gst_app_src_set_size(d->appSrc(), size);
172     }
173 }
174 
streamType() const175 AppStreamType ApplicationSource::streamType() const
176 {
177     return d->appSrc() ? static_cast<AppStreamType>(gst_app_src_get_stream_type(d->appSrc()))
178                        : AppStreamTypeStream;
179 }
180 
setStreamType(AppStreamType type)181 void ApplicationSource::setStreamType(AppStreamType type)
182 {
183     d->lazyConstruct(this);
184     if (d->appSrc()) {
185         gst_app_src_set_stream_type(d->appSrc(), static_cast<GstAppStreamType>(type));
186     }
187 }
188 
maxBytes() const189 quint64 ApplicationSource::maxBytes() const
190 {
191     return d->appSrc() ? gst_app_src_get_max_bytes(d->appSrc()) : 0;
192 }
193 
setMaxBytes(quint64 max)194 void ApplicationSource::setMaxBytes(quint64 max)
195 {
196     d->lazyConstruct(this);
197     if (d->appSrc()) {
198         gst_app_src_set_max_bytes(d->appSrc(), max);
199     }
200 }
201 
blockEnabled() const202 bool ApplicationSource::blockEnabled() const
203 {
204     return d->m_appsrc ? d->m_appsrc->property("block").toBool() : false;
205 }
206 
enableBlock(bool enable)207 void ApplicationSource::enableBlock(bool enable)
208 {
209     d->lazyConstruct(this);
210     if (d->m_appsrc) {
211         d->m_appsrc->setProperty("block", enable);
212     }
213 }
214 
isLive() const215 bool ApplicationSource::isLive() const
216 {
217     return d->m_appsrc ? d->m_appsrc->property("is-live").toBool() : false;
218 }
219 
setLive(bool islive)220 void ApplicationSource::setLive(bool islive)
221 {
222     d->lazyConstruct(this);
223     if (d->m_appsrc) {
224         d->m_appsrc->setProperty("is-live", islive);
225     }
226 }
227 
minPercent() const228 uint ApplicationSource::minPercent() const
229 {
230     return d->m_appsrc ? d->m_appsrc->property("min-percent").toUInt() : 0;
231 }
232 
setMinPercent(uint min)233 void ApplicationSource::setMinPercent(uint min)
234 {
235     d->lazyConstruct(this);
236     if (d->m_appsrc) {
237         d->m_appsrc->setProperty("min-percent", min);
238     }
239 }
240 
format() const241 Format ApplicationSource::format() const
242 {
243     return d->m_appsrc ? d->m_appsrc->property("format").get<Format>() : FormatBytes;
244 }
245 
setFormat(Format f)246 void ApplicationSource::setFormat(Format f)
247 {
248     d->lazyConstruct(this);
249     if (d->m_appsrc) {
250         d->m_appsrc->setProperty("format", f);
251     }
252 }
253 
pushBuffer(const BufferPtr & buffer)254 FlowReturn ApplicationSource::pushBuffer(const BufferPtr & buffer)
255 {
256     if (d->appSrc()) {
257         return static_cast<FlowReturn>(gst_app_src_push_buffer(d->appSrc(), gst_buffer_ref(buffer)));
258     } else {
259         return FlowFlushing;
260     }
261 }
262 
endOfStream()263 FlowReturn ApplicationSource::endOfStream()
264 {
265     if (d->appSrc()) {
266         return static_cast<FlowReturn>(gst_app_src_end_of_stream(d->appSrc()));
267     } else {
268         return FlowFlushing;
269     }
270 }
271 
needData(uint length)272 void ApplicationSource::needData(uint length)
273 {
274     Q_UNUSED(length);
275 }
276 
enoughData()277 void ApplicationSource::enoughData()
278 {
279 }
280 
seekData(quint64 offset)281 bool ApplicationSource::seekData(quint64 offset)
282 {
283     Q_UNUSED(offset);
284     return false;
285 }
286 
287 } //namespace Utils
288 } //namespace QGst
289