69 if (device->isSequential())
70 qWarning() <<
"GStreamer: sequential QIODevices are not fully supported";
72 QMutexLocker lock(&m_registryMutex);
74 auto it = m_reverseLookupTable.find(device);
75 if (it != m_reverseLookupTable.end())
78 QByteArray identifier =
79 "qiodevice:/"_ba + QUuid::createUuid().toByteArray(QUuid::StringFormat::Id128);
81 m_registry.emplace(identifier, std::make_shared<Record>(identifier, device));
83 QMetaObject::Connection destroyedConnection = QObject::connect(
84 device, &QObject::destroyed,
this,
89 unregisterDevice(device);
91 Qt::DirectConnection);
94 device, &QIODevice::aboutToClose,
this,
95 [
this, device, destroyedConnection = std::move(destroyedConnection)] {
96 unregisterDevice(device);
97 disconnect(destroyedConnection);
99 Qt::DirectConnection);
101 m_reverseLookupTable.emplace(device, identifier);
252 auto lock = lockObject();
255 return GST_FLOW_ERROR;
258 if (!gst_buffer_map(buf, &info, GST_MAP_WRITE)) {
259 GST_ELEMENT_ERROR(
this, RESOURCE, WRITE, (
nullptr), (
"Can't map buffer for writing"));
260 return GST_FLOW_ERROR;
263 int64_t totalRead = 0;
264 GstFlowReturn ret = record->runWhileLocked([&](QIODevice *device) -> GstFlowReturn {
265 if (device->pos() != qint64(offset)) {
266 bool success = device->seek(offset);
268 qWarning() <<
"seek on iodevice failed";
269 return GST_FLOW_ERROR;
273 int64_t remain = length;
276 device->read(
reinterpret_cast<
char *>(info.data + totalRead), remain);
277 if (bytesRead == -1) {
278 if (device->atEnd()) {
281 GST_ELEMENT_ERROR(
this, RESOURCE, READ, (
nullptr), GST_ERROR_SYSTEM);
282 return GST_FLOW_ERROR;
286 totalRead += bytesRead;
292 if (ret != GST_FLOW_OK) {
293 gst_buffer_unmap(buf, &info);
294 gst_buffer_resize(buf, 0, 0);
298 gst_buffer_unmap(buf, &info);
299 if (totalRead != length)
300 gst_buffer_resize(buf, 0, totalRead);
302 GST_BUFFER_OFFSET(buf) = offset;
303 GST_BUFFER_OFFSET_END(buf) = offset + totalRead;
319 Q_ASSERT(QLatin1StringView(location).startsWith(
"qiodevice:/"_L1));
322 auto lock = lockObject();
323 GstState state = GST_STATE(
this);
324 if (state != GST_STATE_READY && state != GST_STATE_NULL) {
326 "Changing the `uri' property on qiodevicesrc when the resource is open is not "
329 g_set_error(err, GST_URI_ERROR, GST_URI_ERROR_BAD_STATE,
330 "Changing the `uri' property on qiodevicesrc when the resource is open "
331 "is not supported.");
336 auto newRecord = gQIODeviceRegistry->findRecord(QByteArrayView{ location });
339 auto lock = lockObject();
340 record = std::move(newRecord);
343 g_object_notify(G_OBJECT(
this),
"uri");
387 GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
388 gobjectClass->set_property = [](GObject *instance, guint propId,
const GValue *value,
391 return src->setProperty(propId, value, pspec);
394 gobjectClass->get_property = [](GObject *instance, guint propId, GValue *value,
397 return src->getProperty(propId, value, pspec);
400 g_object_class_install_property(
401 gobjectClass, PROP_URI,
402 g_param_spec_string(
"uri",
"QRC Location",
"Path of the qrc to read",
nullptr,
403 GParamFlags(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS
404 | GST_PARAM_MUTABLE_READY)));
406 gobjectClass->finalize = [](GObject *instance) {
409 src->record.~SharedRecord();
410 G_OBJECT_CLASS(parent_class)->finalize(instance);
414 GstElementClass *gstelementClass = GST_ELEMENT_CLASS(klass);
415 gst_element_class_set_static_metadata(gstelementClass,
"QRC Source",
"Source/QRC",
416 "Read from arbitrary point in QRC resource",
417 "Tim Blechmann <tim.blechmann@qt.io>");
419 static GstStaticPadTemplate srctemplate =
420 GST_STATIC_PAD_TEMPLATE(
"src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY);
422 gst_element_class_add_static_pad_template(gstelementClass, &srctemplate);
425 GstBaseSrcClass *gstbasesrcClass = GST_BASE_SRC_CLASS(klass);
426 gstbasesrcClass->start = [](GstBaseSrc *basesrc) -> gboolean {
427 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(basesrc);
430 gstbasesrcClass->stop = [](GstBaseSrc *basesrc) -> gboolean {
431 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(basesrc);
435 gstbasesrcClass->is_seekable = [](GstBaseSrc *basesrc) -> gboolean {
436 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(basesrc);
437 return src->isSeekable();
439 gstbasesrcClass->get_size = [](GstBaseSrc *basesrc, guint64 *size) -> gboolean {
440 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(basesrc);
441 auto optionalSize = src->size();
444 *size = optionalSize.value();
447 gstbasesrcClass->fill = [](GstBaseSrc *basesrc, guint64 offset, guint length,
448 GstBuffer *buf) -> GstFlowReturn {
449 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(basesrc);
450 return src->fill(offset, length, buf);
456 GstURIHandlerInterface *iface = (GstURIHandlerInterface *)g_handlerInterface;
458 iface->get_type = [](GType) {
461 iface->get_protocols = [](GType) {
462 static constexpr const gchar *protocols[] = {
468 iface->get_uri = [](GstURIHandler *handler) -> gchar * {
469 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(handler);
470 auto lock = src->lockObject();
472 return g_strdup(src->record->id.constData());
475 iface->set_uri = [](GstURIHandler *handler,
const gchar *uri, GError **err) -> gboolean {
476 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(handler);
477 return src->setURI(uri, err);