20 * Boston, MA 02111-1307, USA. |
20 * Boston, MA 02111-1307, USA. |
21 */ |
21 */ |
22 |
22 |
23 /** |
23 /** |
24 * SECTION:element-fdsink |
24 * SECTION:element-fdsink |
|
25 * @short_description: write to a unix file descriptor |
25 * @see_also: #GstFdSrc |
26 * @see_also: #GstFdSrc |
26 * |
27 * |
27 * Write data to a unix file descriptor. |
28 * Write data to a unix file descriptor. |
28 * |
29 * |
29 * This element will synchronize on the clock before writing the data on the |
30 * This element will synchronize on the clock before writing the data on the |
118 GstBuffer * buffer); |
119 GstBuffer * buffer); |
119 static gboolean gst_fd_sink_start (GstBaseSink * basesink); |
120 static gboolean gst_fd_sink_start (GstBaseSink * basesink); |
120 static gboolean gst_fd_sink_stop (GstBaseSink * basesink); |
121 static gboolean gst_fd_sink_stop (GstBaseSink * basesink); |
121 static gboolean gst_fd_sink_unlock (GstBaseSink * basesink); |
122 static gboolean gst_fd_sink_unlock (GstBaseSink * basesink); |
122 static gboolean gst_fd_sink_unlock_stop (GstBaseSink * basesink); |
123 static gboolean gst_fd_sink_unlock_stop (GstBaseSink * basesink); |
123 static gboolean gst_fd_sink_event (GstBaseSink * sink, GstEvent * event); |
|
124 |
|
125 static gboolean gst_fd_sink_do_seek (GstFdSink * fdsink, guint64 new_offset); |
|
126 |
124 |
127 static void |
125 static void |
128 gst_fd_sink_base_init (gpointer g_class) |
126 gst_fd_sink_base_init (gpointer g_class) |
129 { |
127 { |
130 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); |
128 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); |
154 gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_fd_sink_render); |
152 gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_fd_sink_render); |
155 gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_fd_sink_start); |
153 gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_fd_sink_start); |
156 gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_fd_sink_stop); |
154 gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_fd_sink_stop); |
157 gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_fd_sink_unlock); |
155 gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_fd_sink_unlock); |
158 gstbasesink_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_fd_sink_unlock_stop); |
156 gstbasesink_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_fd_sink_unlock_stop); |
159 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_fd_sink_event); |
157 gstbasesink_class->event = NULL; |
160 |
158 |
161 g_object_class_install_property (gobject_class, ARG_FD, |
159 g_object_class_install_property (gobject_class, ARG_FD, |
162 g_param_spec_int ("fd", "fd", "An open file descriptor to write to", |
160 g_param_spec_int ("fd", "fd", "An open file descriptor to write to", |
163 0, G_MAXINT, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
161 0, G_MAXINT, 1, G_PARAM_READWRITE)); |
164 } |
162 } |
165 |
163 |
166 static void |
164 static void |
167 gst_fd_sink_init (GstFdSink * fdsink, GstFdSinkClass * klass) |
165 gst_fd_sink_init (GstFdSink * fdsink, GstFdSinkClass * klass) |
168 { |
166 { |
172 gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_fd_sink_query)); |
170 gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_fd_sink_query)); |
173 |
171 |
174 fdsink->fd = 1; |
172 fdsink->fd = 1; |
175 fdsink->uri = g_strdup_printf ("fd://%d", fdsink->fd); |
173 fdsink->uri = g_strdup_printf ("fd://%d", fdsink->fd); |
176 fdsink->bytes_written = 0; |
174 fdsink->bytes_written = 0; |
177 fdsink->current_pos = 0; |
|
178 |
175 |
179 GST_BASE_SINK (fdsink)->sync = TRUE; |
176 GST_BASE_SINK (fdsink)->sync = TRUE; |
180 } |
177 } |
181 |
178 |
182 static void |
179 static void |
202 case GST_QUERY_POSITION: |
199 case GST_QUERY_POSITION: |
203 gst_query_parse_position (query, &format, NULL); |
200 gst_query_parse_position (query, &format, NULL); |
204 switch (format) { |
201 switch (format) { |
205 case GST_FORMAT_DEFAULT: |
202 case GST_FORMAT_DEFAULT: |
206 case GST_FORMAT_BYTES: |
203 case GST_FORMAT_BYTES: |
207 gst_query_set_position (query, GST_FORMAT_BYTES, fdsink->current_pos); |
204 gst_query_set_position (query, GST_FORMAT_BYTES, |
|
205 fdsink->bytes_written); |
208 return TRUE; |
206 return TRUE; |
209 default: |
207 default: |
210 return FALSE; |
208 return FALSE; |
211 } |
209 } |
212 |
210 |
213 case GST_QUERY_FORMATS: |
211 case GST_QUERY_FORMATS: |
214 gst_query_set_formats (query, 2, GST_FORMAT_DEFAULT, GST_FORMAT_BYTES); |
212 gst_query_set_formats (query, 2, GST_FORMAT_DEFAULT, GST_FORMAT_BYTES); |
215 return TRUE; |
|
216 |
|
217 case GST_QUERY_URI: |
|
218 gst_query_set_uri (query, fdsink->uri); |
|
219 return TRUE; |
213 return TRUE; |
220 |
214 |
221 default: |
215 default: |
222 return gst_pad_query_default (pad, query); |
216 return gst_pad_query_default (pad, query); |
223 } |
217 } |
275 |
269 |
276 /* all is fine when we get here */ |
270 /* all is fine when we get here */ |
277 size -= written; |
271 size -= written; |
278 data += written; |
272 data += written; |
279 fdsink->bytes_written += written; |
273 fdsink->bytes_written += written; |
280 fdsink->current_pos += written; |
|
281 |
274 |
282 GST_DEBUG_OBJECT (fdsink, "wrote %d bytes, %d left", written, size); |
275 GST_DEBUG_OBJECT (fdsink, "wrote %d bytes, %d left", written, size); |
283 |
276 |
284 /* short write, select and try to write the remainder */ |
277 /* short write, select and try to write the remainder */ |
285 if (G_UNLIKELY (size > 0)) |
278 if (G_UNLIKELY (size > 0)) |
307 switch (errno) { |
300 switch (errno) { |
308 case ENOSPC: |
301 case ENOSPC: |
309 GST_ELEMENT_ERROR (fdsink, RESOURCE, NO_SPACE_LEFT, (NULL), (NULL)); |
302 GST_ELEMENT_ERROR (fdsink, RESOURCE, NO_SPACE_LEFT, (NULL), (NULL)); |
310 break; |
303 break; |
311 default:{ |
304 default:{ |
312 GST_ELEMENT_ERROR (fdsink, RESOURCE, WRITE, (NULL), |
305 GST_ELEMENT_ERROR (fdsink, RESOURCE, WRITE, |
313 ("Error while writing to file descriptor %d: %s", |
306 (_("Error while writing to file descriptor \"%d\"."), fdsink->fd), |
314 fdsink->fd, g_strerror (errno))); |
307 ("%s", g_strerror (errno))); |
315 } |
308 } |
316 } |
309 } |
317 return GST_FLOW_ERROR; |
310 return GST_FLOW_ERROR; |
318 } |
311 } |
319 } |
312 } |
341 |
334 |
342 case ESPIPE: |
335 case ESPIPE: |
343 goto not_seekable; |
336 goto not_seekable; |
344 } |
337 } |
345 } else |
338 } else |
346 GST_DEBUG_OBJECT (fdsink, "File descriptor %d is seekable", fd); |
339 GST_DEBUG_OBJECT (fdsink, "File descriptor \"%d\" is seekable", fd); |
347 |
340 |
348 return TRUE; |
341 return TRUE; |
349 |
342 |
350 invalid: |
343 invalid: |
351 { |
344 { |
352 GST_ELEMENT_ERROR (fdsink, RESOURCE, WRITE, (NULL), |
345 GST_ELEMENT_ERROR (fdsink, RESOURCE, WRITE, |
353 ("File descriptor %d is not valid: %s", fd, g_strerror (errno))); |
346 (_("File descriptor \"%d\" is not valid."), fd), |
|
347 ("%s", g_strerror (errno))); |
354 return FALSE; |
348 return FALSE; |
355 } |
349 } |
356 not_seekable: |
350 not_seekable: |
357 { |
351 { |
358 GST_DEBUG_OBJECT (fdsink, "File descriptor %d is a pipe", fd); |
352 GST_DEBUG_OBJECT (fdsink, "File descriptor \"%d\" is a pipe", fd); |
359 return TRUE; |
353 return TRUE; |
360 } |
354 } |
361 } |
355 } |
362 |
356 |
363 static gboolean |
357 static gboolean |
505 default: |
496 default: |
506 break; |
497 break; |
507 } |
498 } |
508 } |
499 } |
509 |
500 |
510 static gboolean |
|
511 gst_fd_sink_do_seek (GstFdSink * fdsink, guint64 new_offset) |
|
512 { |
|
513 off_t result; |
|
514 |
|
515 result = lseek (fdsink->fd, new_offset, SEEK_SET); |
|
516 |
|
517 if (result == -1) |
|
518 goto seek_failed; |
|
519 |
|
520 fdsink->current_pos = new_offset; |
|
521 |
|
522 GST_DEBUG_OBJECT (fdsink, "File desciptor %d to seek to position " |
|
523 "%" G_GUINT64_FORMAT, fdsink->fd, fdsink->current_pos); |
|
524 |
|
525 return TRUE; |
|
526 |
|
527 /* ERRORS */ |
|
528 seek_failed: |
|
529 { |
|
530 GST_DEBUG_OBJECT (fdsink, "File desciptor %d failed to seek to position " |
|
531 "%" G_GUINT64_FORMAT, fdsink->fd, new_offset); |
|
532 return FALSE; |
|
533 } |
|
534 } |
|
535 |
|
536 static gboolean |
|
537 gst_fd_sink_event (GstBaseSink * sink, GstEvent * event) |
|
538 { |
|
539 GstEventType type; |
|
540 GstFdSink *fdsink; |
|
541 |
|
542 fdsink = GST_FD_SINK (sink); |
|
543 |
|
544 type = GST_EVENT_TYPE (event); |
|
545 |
|
546 switch (type) { |
|
547 case GST_EVENT_NEWSEGMENT: |
|
548 { |
|
549 gint64 start, stop, pos; |
|
550 GstFormat format; |
|
551 gst_event_parse_new_segment (event, NULL, NULL, &format, &start, |
|
552 &stop, &pos); |
|
553 |
|
554 if (format == GST_FORMAT_BYTES) { |
|
555 /* only try to seek and fail when we are going to a different |
|
556 * position */ |
|
557 if (fdsink->current_pos != start) { |
|
558 /* FIXME, the seek should be performed on the pos field, start/stop are |
|
559 * just boundaries for valid bytes offsets. We should also fill the file |
|
560 * with zeroes if the new position extends the current EOF (sparse streams |
|
561 * and segment accumulation). */ |
|
562 if (!gst_fd_sink_do_seek (fdsink, (guint64) start)) |
|
563 goto seek_failed; |
|
564 } |
|
565 } else { |
|
566 GST_DEBUG_OBJECT (fdsink, |
|
567 "Ignored NEWSEGMENT event of format %u (%s)", (guint) format, |
|
568 gst_format_get_name (format)); |
|
569 } |
|
570 break; |
|
571 } |
|
572 default: |
|
573 break; |
|
574 } |
|
575 |
|
576 return TRUE; |
|
577 |
|
578 seek_failed: |
|
579 { |
|
580 GST_ELEMENT_ERROR (fdsink, RESOURCE, SEEK, (NULL), |
|
581 ("Error while seeking on file descriptor %d: %s", |
|
582 fdsink->fd, g_strerror (errno))); |
|
583 return FALSE; |
|
584 } |
|
585 |
|
586 } |
|
587 |
|
588 /*** GSTURIHANDLER INTERFACE *************************************************/ |
501 /*** GSTURIHANDLER INTERFACE *************************************************/ |
589 |
502 #ifdef __SYMBIAN32__ |
590 static GstURIType |
503 GstURIType |
|
504 #else |
|
505 static guint |
|
506 #endif |
591 gst_fd_sink_uri_get_type (void) |
507 gst_fd_sink_uri_get_type (void) |
592 { |
508 { |
593 return GST_URI_SINK; |
509 return GST_URI_SINK; |
594 } |
510 } |
595 |
|
596 static gchar ** |
511 static gchar ** |
597 gst_fd_sink_uri_get_protocols (void) |
512 gst_fd_sink_uri_get_protocols (void) |
598 { |
513 { |
599 static gchar *protocols[] = { "fd", NULL }; |
514 static gchar *protocols[] = { "fd", NULL }; |
600 |
515 |
601 return protocols; |
516 return protocols; |
602 } |
517 } |
603 |
|
604 static const gchar * |
518 static const gchar * |
605 gst_fd_sink_uri_get_uri (GstURIHandler * handler) |
519 gst_fd_sink_uri_get_uri (GstURIHandler * handler) |
606 { |
520 { |
607 GstFdSink *sink = GST_FD_SINK (handler); |
521 GstFdSink *sink = GST_FD_SINK (handler); |
608 |
522 |