static const gchar * gst_file_sink_uri_get_uri (GstURIHandler * handler) { GstFileSink *sink = GST_FILE_SINK (handler); return sink->uri; }
static gboolean gst_file_sink_query (GstPad * pad, GstQuery * query) { GstFileSink *self; GstFormat format; self = GST_FILE_SINK (GST_PAD_PARENT (pad)); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_POSITION: gst_query_parse_position (query, &format, NULL); switch (format) { case GST_FORMAT_DEFAULT: case GST_FORMAT_BYTES: gst_query_set_position (query, GST_FORMAT_BYTES, self->current_pos); return TRUE; default: return FALSE; } case GST_QUERY_FORMATS: gst_query_set_formats (query, 2, GST_FORMAT_DEFAULT, GST_FORMAT_BYTES); return TRUE; case GST_QUERY_URI: gst_query_set_uri (query, self->uri); return TRUE; default: return gst_pad_query_default (pad, query); } }
static gchar * gst_file_sink_uri_get_uri (GstURIHandler * handler) { GstFileSink *sink = GST_FILE_SINK (handler); /* FIXME: make thread-safe */ return g_strdup (sink->uri); }
static gboolean gst_file_sink_query (GstBaseSink * bsink, GstQuery * query) { gboolean res; GstFileSink *self; GstFormat format; self = GST_FILE_SINK (bsink); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_POSITION: gst_query_parse_position (query, &format, NULL); switch (format) { case GST_FORMAT_DEFAULT: case GST_FORMAT_BYTES: gst_query_set_position (query, GST_FORMAT_BYTES, self->current_pos); res = TRUE; break; default: res = FALSE; break; } break; case GST_QUERY_FORMATS: gst_query_set_formats (query, 2, GST_FORMAT_DEFAULT, GST_FORMAT_BYTES); res = TRUE; break; case GST_QUERY_URI: gst_query_set_uri (query, self->uri); res = TRUE; break; case GST_QUERY_SEEKING: gst_query_parse_seeking (query, &format, NULL, NULL, NULL); if (format == GST_FORMAT_BYTES || format == GST_FORMAT_DEFAULT) { gst_query_set_seeking (query, GST_FORMAT_BYTES, self->seekable, 0, -1); } else { gst_query_set_seeking (query, format, FALSE, 0, -1); } res = TRUE; break; default: res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query); break; } return res; }
static void gst_file_sink_dispose (GObject * object) { GstFileSink *sink = GST_FILE_SINK (object); G_OBJECT_CLASS (parent_class)->dispose (object); g_free (sink->uri); sink->uri = NULL; g_free (sink->filename); sink->filename = NULL; g_free (sink->buffer); sink->buffer = NULL; sink->buffer_size = 0; }
static gboolean gst_file_sink_uri_set_uri (GstURIHandler * handler, const gchar * uri, GError ** error) { gchar *location; gboolean ret; GstFileSink *sink = GST_FILE_SINK (handler); /* allow file://localhost/foo/bar by stripping localhost but fail * for every other hostname */ if (g_str_has_prefix (uri, "file://localhost/")) { char *tmp; /* 16 == strlen ("file://localhost") */ tmp = g_strconcat ("file://", uri + 16, NULL); /* we use gst_uri_get_location() although we already have the * "location" with uri + 16 because it provides unescaping */ location = gst_uri_get_location (tmp); g_free (tmp); } else if (strcmp (uri, "file://") == 0) { /* Special case for "file://" as this is used by some applications * to test with gst_element_make_from_uri if there's an element * that supports the URI protocol. */ gst_file_sink_set_location (sink, NULL, NULL); return TRUE; } else { location = gst_uri_get_location (uri); } if (!location) { g_set_error_literal (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, "File URI without location"); return FALSE; } if (!g_path_is_absolute (location)) { g_set_error_literal (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, "File URI location must be an absolute path"); g_free (location); return FALSE; } ret = gst_file_sink_set_location (sink, location, error); g_free (location); return ret; }
static GstFlowReturn gst_file_sink_render (GstBaseSink * sink, GstBuffer * buffer) { GstFileSink *filesink; GstMapInfo info; filesink = GST_FILE_SINK (sink); gst_buffer_map (buffer, &info, GST_MAP_READ); GST_DEBUG_OBJECT (filesink, "writing %" G_GSIZE_FORMAT " bytes at %" G_GUINT64_FORMAT, info.size, filesink->current_pos); if (info.size > 0 && info.data != NULL) { if (fwrite (info.data, info.size, 1, filesink->file) != 1) goto handle_error; filesink->current_pos += info.size; } gst_buffer_unmap (buffer, &info); return GST_FLOW_OK; handle_error: { switch (errno) { case ENOSPC:{ GST_ELEMENT_ERROR (filesink, RESOURCE, NO_SPACE_LEFT, (NULL), (NULL)); break; } default:{ GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE, (_("Error while writing to file \"%s\"."), filesink->filename), ("%s", g_strerror (errno))); } } gst_buffer_unmap (buffer, &info); return GST_FLOW_ERROR; } }
static GstFlowReturn gst_file_sink_render (GstBaseSink * sink, GstBuffer * buffer) { GstFileSink *filesink; guint size; guint8 *data; filesink = GST_FILE_SINK (sink); size = GST_BUFFER_SIZE (buffer); data = GST_BUFFER_DATA (buffer); GST_DEBUG_OBJECT (filesink, "writing %u bytes at %" G_GUINT64_FORMAT, size, filesink->current_pos); if (size > 0 && data != NULL) { if (fwrite (data, size, 1, filesink->file) != 1) goto handle_error; filesink->current_pos += size; } return GST_FLOW_OK; handle_error: { switch (errno) { case ENOSPC:{ GST_ELEMENT_ERROR (filesink, RESOURCE, NO_SPACE_LEFT, (NULL), (NULL)); break; } default:{ GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE, (_("Error while writing to file \"%s\"."), filesink->filename), ("%s", g_strerror (errno))); } } return GST_FLOW_ERROR; } }
static void gst_file_sink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstFileSink *sink = GST_FILE_SINK (object); switch (prop_id) { case PROP_LOCATION: g_value_set_string (value, sink->filename); break; case PROP_BUFFER_MODE: g_value_set_enum (value, sink->buffer_mode); break; case PROP_BUFFER_SIZE: g_value_set_uint (value, sink->buffer_size); break; case PROP_APPEND: g_value_set_boolean (value, sink->append); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean gst_file_sink_stop (GstBaseSink * basesink) { gst_file_sink_close_file (GST_FILE_SINK (basesink)); return TRUE; }
static gboolean gst_file_sink_start (GstBaseSink * basesink) { return gst_file_sink_open_file (GST_FILE_SINK (basesink)); }
/* handle events (search) */ static gboolean gst_file_sink_event (GstBaseSink * sink, GstEvent * event) { GstEventType type; GstFileSink *filesink; filesink = GST_FILE_SINK (sink); type = GST_EVENT_TYPE (event); switch (type) { case GST_EVENT_SEGMENT: { const GstSegment *segment; gst_event_parse_segment (event, &segment); if (segment->format == GST_FORMAT_BYTES) { /* only try to seek and fail when we are going to a different * position */ if (filesink->current_pos != segment->start) { /* FIXME, the seek should be performed on the pos field, start/stop are * just boundaries for valid bytes offsets. We should also fill the file * with zeroes if the new position extends the current EOF (sparse streams * and segment accumulation). */ if (!gst_file_sink_do_seek (filesink, (guint64) segment->start)) goto seek_failed; } else { GST_DEBUG_OBJECT (filesink, "Ignored SEGMENT, no seek needed"); } } else { GST_DEBUG_OBJECT (filesink, "Ignored SEGMENT event of format %u (%s)", (guint) segment->format, gst_format_get_name (segment->format)); } break; } case GST_EVENT_FLUSH_STOP: if (filesink->current_pos != 0 && filesink->seekable) { gst_file_sink_do_seek (filesink, 0); if (ftruncate (fileno (filesink->file), 0)) goto flush_failed; } break; case GST_EVENT_EOS: if (fflush (filesink->file)) goto flush_failed; break; default: break; } return GST_BASE_SINK_CLASS (parent_class)->event (sink, event); /* ERRORS */ seek_failed: { GST_ELEMENT_ERROR (filesink, RESOURCE, SEEK, (_("Error while seeking in file \"%s\"."), filesink->filename), GST_ERROR_SYSTEM); gst_event_unref (event); return FALSE; } flush_failed: { GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE, (_("Error while writing to file \"%s\"."), filesink->filename), GST_ERROR_SYSTEM); gst_event_unref (event); return FALSE; } }