70 if (device->isSequential())
71 qWarning() <<
"GStreamer: sequential QIODevices are not fully supported";
73 QMutexLocker lock(&m_registryMutex);
75 auto it = m_reverseLookupTable.find(device);
76 if (it != m_reverseLookupTable.end())
79 QByteArray identifier =
80 "qiodevice:/"_ba + QUuid::createUuid().toByteArray(QUuid::StringFormat::Id128);
82 m_registry.emplace(identifier, std::make_shared<Record>(identifier, device));
84 QMetaObject::Connection destroyedConnection = QObject::connect(
85 device, &QObject::destroyed,
this,
90 unregisterDevice(device);
92 Qt::DirectConnection);
95 device, &QIODevice::aboutToClose,
this,
96 [
this, device, destroyedConnection = std::move(destroyedConnection)] {
97 unregisterDevice(device);
98 disconnect(destroyedConnection);
100 Qt::DirectConnection);
102 m_reverseLookupTable.emplace(device, identifier);
247 std::unique_lock guard{ *
this };
249 return GST_FLOW_ERROR;
252 if (!gst_buffer_map(buf, &info, GST_MAP_WRITE)) {
254 GST_ELEMENT_ERROR(&baseSrc, RESOURCE, WRITE, (
nullptr), (
"Can't map buffer for writing"));
255 return GST_FLOW_ERROR;
258 int64_t totalRead = 0;
259 GstFlowReturn ret = record->runWhileLocked([&](QIODevice *device) -> GstFlowReturn {
260 if (device->pos() != qint64(offset)) {
261 bool success = device->seek(offset);
263 qWarning() <<
"seek on iodevice failed";
264 return GST_FLOW_ERROR;
268 int64_t remain = length;
271 device->read(
reinterpret_cast<
char *>(info.data + totalRead), remain);
272 if (bytesRead == -1) {
273 if (device->atEnd()) {
277 GST_ELEMENT_ERROR(&baseSrc, RESOURCE, READ, (
nullptr), GST_ERROR_SYSTEM);
278 return GST_FLOW_ERROR;
282 totalRead += bytesRead;
288 if (ret != GST_FLOW_OK) {
289 gst_buffer_unmap(buf, &info);
290 gst_buffer_resize(buf, 0, 0);
294 gst_buffer_unmap(buf, &info);
295 if (totalRead != length)
296 gst_buffer_resize(buf, 0, totalRead);
298 GST_BUFFER_OFFSET(buf) = offset;
299 GST_BUFFER_OFFSET_END(buf) = offset + totalRead;
315 Q_ASSERT(QLatin1StringView(location).startsWith(
"qiodevice:/"_L1));
318 std::lock_guard guard{ *
this };
319 GstState state = GST_STATE(
this);
321 if (state != GST_STATE_READY && state != GST_STATE_NULL) {
323 "Changing the `uri' property on qiodevicesrc when the resource is open is not "
326 g_set_error(err, GST_URI_ERROR, GST_URI_ERROR_BAD_STATE,
327 "Changing the `uri' property on qiodevicesrc when the resource is open "
328 "is not supported.");
333 auto newRecord = gQIODeviceRegistry->findRecord(QByteArrayView{ location });
336 std::lock_guard guard{ *
this };
337 record = std::move(newRecord);
340 g_object_notify(G_OBJECT(
this),
"uri");
384 GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
385 gobjectClass->set_property = [](GObject *instance, guint propId,
const GValue *value,
388 return src->setProperty(propId, value, pspec);
391 gobjectClass->get_property = [](GObject *instance, guint propId, GValue *value,
394 return src->getProperty(propId, value, pspec);
397 g_object_class_install_property(
398 gobjectClass, PROP_URI,
399 g_param_spec_string(
"uri",
"QRC Location",
"Path of the qrc to read",
nullptr,
400 GParamFlags(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS
401 | GST_PARAM_MUTABLE_READY)));
403 gobjectClass->finalize = [](GObject *instance) {
406 src->record.~SharedRecord();
407 G_OBJECT_CLASS(parent_class)->finalize(instance);
411 GstElementClass *gstelementClass = GST_ELEMENT_CLASS(klass);
412 gst_element_class_set_static_metadata(gstelementClass,
"QRC Source",
"Source/QRC",
413 "Read from arbitrary point in QRC resource",
414 "Tim Blechmann <tim.blechmann@qt.io>");
416 static GstStaticPadTemplate srctemplate =
417 GST_STATIC_PAD_TEMPLATE(
"src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY);
419 gst_element_class_add_static_pad_template(gstelementClass, &srctemplate);
422 GstBaseSrcClass *gstbasesrcClass = GST_BASE_SRC_CLASS(klass);
423 gstbasesrcClass->start = [](GstBaseSrc *basesrc) -> gboolean {
424 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(basesrc);
427 gstbasesrcClass->stop = [](GstBaseSrc *basesrc) -> gboolean {
428 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(basesrc);
432 gstbasesrcClass->is_seekable = [](GstBaseSrc *basesrc) -> gboolean {
433 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(basesrc);
434 return src->isSeekable();
436 gstbasesrcClass->get_size = [](GstBaseSrc *basesrc, guint64 *size) -> gboolean {
437 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(basesrc);
438 auto optionalSize = src->size();
441 *size = optionalSize.value();
444 gstbasesrcClass->fill = [](GstBaseSrc *basesrc, guint64 offset, guint length,
445 GstBuffer *buf) -> GstFlowReturn {
446 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(basesrc);
447 return src->fill(offset, length, buf);
453 GstURIHandlerInterface *iface = (GstURIHandlerInterface *)g_handlerInterface;
455 iface->get_type = [](GType) {
458 iface->get_protocols = [](GType) {
459 static constexpr const gchar *protocols[] = {
465 iface->get_uri = [](GstURIHandler *handler) -> gchar * {
466 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(handler);
467 std::lock_guard guard{ *src };
469 return g_strdup(src->record->id.constData());
472 iface->set_uri = [](GstURIHandler *handler,
const gchar *uri, GError **err) -> gboolean {
473 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(handler);
474 return src->setURI(uri, err);