diff --git a/gstafcsrc/gstafcsrc.cpp b/gstafcsrc/gstafcsrc.cpp index a58e23f6f..4361ebb8f 100644 --- a/gstafcsrc/gstafcsrc.cpp +++ b/gstafcsrc/gstafcsrc.cpp @@ -135,18 +135,37 @@ static void gst_afc_src_init(GstAfcSrc* element, GstAfcSrcClass* gclass) { element->location_ = NULL; element->uuid_ = NULL; element->path_ = NULL; + element->connected_ = false; element->afc_ = NULL; element->afc_port_ = 0; element->device_ = NULL; element->file_handle_ = 0; element->lockdown_ = NULL; + element->buffer_ = NULL; + element->buffer_is_valid_ = false; + element->buffer_length_ = 0; + element->buffer_offset_ = 0; } static void gst_afc_src_finalize(GObject* object) { - GstAfcSrc* src = GST_AFCSRC(object); - free(src->location_); - free(src->uuid_); - free(src->path_); + GstAfcSrc* self = GST_AFCSRC(object); + free(self->location_); + free(self->uuid_); + free(self->path_); + free(self->buffer_); + + if (self->file_handle_) + afc_file_close(self->afc_, self->file_handle_); + + if (self->afc_) + afc_client_free(self->afc_); + + if (self->lockdown_) + lockdownd_client_free(self->lockdown_); + + if (self->device_) + idevice_free(self->device_); + G_OBJECT_CLASS(parent_class)->finalize(object); } @@ -184,6 +203,10 @@ static void gst_afc_src_get_property( static gboolean gst_afc_src_start(GstBaseSrc* src) { GstAfcSrc* self = GST_AFCSRC(src); + // Don't connect again + if (self->connected_) + return true; + // Check that a URI has been passed if (!self->location_ || self->location_[0] == '\0') { GST_ELEMENT_ERROR(src, RESOURCE, NOT_FOUND, ("No URI specified"), (NULL)); @@ -235,25 +258,12 @@ static gboolean gst_afc_src_start(GstBaseSrc* src) { return false; } + self->connected_ = true; + return true; } static gboolean gst_afc_src_stop(GstBaseSrc* src) { - GstAfcSrc* self = GST_AFCSRC(src); - - if (self->file_handle_) { - afc_file_close(self->afc_, self->file_handle_); - } - - if (self->afc_) { - afc_client_free(self->afc_); - } - if (self->lockdown_) { - lockdownd_client_free(self->lockdown_); - } - if (self->device_) { - idevice_free(self->device_); - } return true; } @@ -267,12 +277,26 @@ static GstFlowReturn gst_afc_src_create(GstBaseSrc* src, guint64 offset, guint l return GST_FLOW_ERROR; } - uint32_t bytes_read = 0; - if (length > 0) { + // Is this section within our cache? + if (!self->buffer_is_valid_ || offset < self->buffer_offset_ || + offset + length > self->buffer_offset_ + self->buffer_length_) { + // No - read from the device to fill our internal cache. + // Always read twice the requested size so the next read(s) hit the cache too. + if (self->buffer_length_ != length * 2) { + self->buffer_ = (char*)realloc(self->buffer_, length * 2); + self->buffer_is_valid_ = true; + self->buffer_length_ = length * 2; + } + self->buffer_offset_ = offset; + + uint32_t bytes_read = 0; afc_file_seek(self->afc_, self->file_handle_, offset, SEEK_SET); - afc_file_read(self->afc_, self->file_handle_, (char*)(GST_BUFFER_DATA(buf)), length, &bytes_read); + afc_file_read(self->afc_, self->file_handle_, self->buffer_, length * 2, &bytes_read); } + // Copy from our internal buffer to the output buffer + memcpy(GST_BUFFER_DATA(buf), self->buffer_ + offset - self->buffer_offset_, length); + *buffer = buf; return GST_FLOW_OK; } diff --git a/gstafcsrc/gstafcsrc.h b/gstafcsrc/gstafcsrc.h index 34d577259..046649a61 100644 --- a/gstafcsrc/gstafcsrc.h +++ b/gstafcsrc/gstafcsrc.h @@ -49,6 +49,7 @@ struct _GstAfcSrc { char* uuid_; char* path_; + bool connected_; idevice_t device_; lockdownd_client_t lockdown_; afc_client_t afc_; @@ -56,6 +57,11 @@ struct _GstAfcSrc { uint16_t afc_port_; uint64_t file_handle_; + + bool buffer_is_valid_; + guint64 buffer_offset_; + guint buffer_length_; + char* buffer_; }; struct _GstAfcSrcClass {