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.insert(device, identifier);
253 auto lock = lockObject();
256 return GST_FLOW_ERROR;
259 if (!gst_buffer_map(buf, &info, GST_MAP_WRITE)) {
260 GST_ELEMENT_ERROR(
this, RESOURCE, WRITE, (
nullptr), (
"Can't map buffer for writing"));
261 return GST_FLOW_ERROR;
264 int64_t totalRead = 0;
265 GstFlowReturn ret = record->runWhileLocked([&](QIODevice *device) -> GstFlowReturn {
266 if (device->pos() != qint64(offset)) {
267 bool success = device->seek(offset);
269 qWarning() <<
"seek on iodevice failed";
270 return GST_FLOW_ERROR;
274 int64_t remain = length;
277 device->read(
reinterpret_cast<
char *>(info.data + totalRead), remain);
278 if (bytesRead == -1) {
279 if (device->atEnd()) {
282 GST_ELEMENT_ERROR(
this, RESOURCE, READ, (
nullptr), GST_ERROR_SYSTEM);
283 return GST_FLOW_ERROR;
287 totalRead += bytesRead;
293 if (ret != GST_FLOW_OK) {
294 gst_buffer_unmap(buf, &info);
295 gst_buffer_resize(buf, 0, 0);
299 gst_buffer_unmap(buf, &info);
300 if (totalRead != length)
301 gst_buffer_resize(buf, 0, totalRead);
303 GST_BUFFER_OFFSET(buf) = offset;
304 GST_BUFFER_OFFSET_END(buf) = offset + totalRead;
320 Q_ASSERT(QLatin1StringView(location).startsWith(
"qiodevice:/"_L1));
323 auto lock = lockObject();
324 GstState state = GST_STATE(
this);
325 if (state != GST_STATE_READY && state != GST_STATE_NULL) {
327 "Changing the `uri' property on qiodevicesrc when the resource is open is not "
330 g_set_error(err, GST_URI_ERROR, GST_URI_ERROR_BAD_STATE,
331 "Changing the `uri' property on qiodevicesrc when the resource is open "
332 "is not supported.");
337 auto newRecord = gQIODeviceRegistry->findRecord(QByteArrayView{ location });
340 auto lock = lockObject();
341 record = std::move(newRecord);
344 g_object_notify(G_OBJECT(
this),
"uri");
388 GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
389 gobjectClass->set_property = [](GObject *instance, guint propId,
const GValue *value,
392 return src->setProperty(propId, value, pspec);
395 gobjectClass->get_property = [](GObject *instance, guint propId, GValue *value,
398 return src->getProperty(propId, value, pspec);
401 g_object_class_install_property(
402 gobjectClass, PROP_URI,
403 g_param_spec_string(
"uri",
"QRC Location",
"Path of the qrc to read",
nullptr,
404 GParamFlags(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS
405 | GST_PARAM_MUTABLE_READY)));
407 gobjectClass->finalize = [](GObject *instance) {
410 src->record.~SharedRecord();
411 G_OBJECT_CLASS(parent_class)->finalize(instance);
415 GstElementClass *gstelementClass = GST_ELEMENT_CLASS(klass);
416 gst_element_class_set_static_metadata(gstelementClass,
"QRC Source",
"Source/QRC",
417 "Read from arbitrary point in QRC resource",
418 "Tim Blechmann <tim.blechmann@qt.io>");
420 static GstStaticPadTemplate srctemplate =
421 GST_STATIC_PAD_TEMPLATE(
"src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY);
423 gst_element_class_add_static_pad_template(gstelementClass, &srctemplate);
426 GstBaseSrcClass *gstbasesrcClass = GST_BASE_SRC_CLASS(klass);
427 gstbasesrcClass->start = [](GstBaseSrc *basesrc) -> gboolean {
428 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(basesrc);
431 gstbasesrcClass->stop = [](GstBaseSrc *basesrc) -> gboolean {
432 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(basesrc);
436 gstbasesrcClass->is_seekable = [](GstBaseSrc *basesrc) -> gboolean {
437 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(basesrc);
438 return src->isSeekable();
440 gstbasesrcClass->get_size = [](GstBaseSrc *basesrc, guint64 *size) -> gboolean {
441 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(basesrc);
442 auto optionalSize = src->size();
445 *size = optionalSize.value();
448 gstbasesrcClass->fill = [](GstBaseSrc *basesrc, guint64 offset, guint length,
449 GstBuffer *buf) -> GstFlowReturn {
450 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(basesrc);
451 return src->fill(offset, length, buf);
457 GstURIHandlerInterface *iface = (GstURIHandlerInterface *)g_handlerInterface;
459 iface->get_type = [](GType) {
462 iface->get_protocols = [](GType) {
463 static constexpr const gchar *protocols[] = {
469 iface->get_uri = [](GstURIHandler *handler) -> gchar * {
470 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(handler);
471 auto lock = src->lockObject();
473 return g_strdup(src->record->id.constData());
476 iface->set_uri = [](GstURIHandler *handler,
const gchar *uri, GError **err) -> gboolean {
477 QGstQIODeviceSrc *src = asQGstQIODeviceSrc(handler);
478 return src->setURI(uri, err);