static GstFlowReturn gst_multi_file_sink_write_buffer (GstMultiFileSink * multifilesink, GstBuffer * buffer) { GstMapInfo map; gboolean ret; gboolean first_file = TRUE; gst_buffer_map (buffer, &map, GST_MAP_READ); switch (multifilesink->next_file) { case GST_MULTI_FILE_SINK_NEXT_BUFFER: if (multifilesink->files != NULL) first_file = FALSE; if (!gst_multi_file_sink_open_next_file (multifilesink)) goto stdio_write_error; if (first_file == FALSE) gst_multi_file_sink_write_stream_headers (multifilesink); GST_DEBUG_OBJECT (multifilesink, "Writing buffer data (%" G_GSIZE_FORMAT " bytes) to new file", map.size); ret = fwrite (map.data, map.size, 1, multifilesink->file); if (ret != 1) goto stdio_write_error; gst_multi_file_sink_close_file (multifilesink, buffer); break; case GST_MULTI_FILE_SINK_NEXT_DISCONT: if (GST_BUFFER_IS_DISCONT (buffer)) { if (multifilesink->file) gst_multi_file_sink_close_file (multifilesink, buffer); } if (multifilesink->file == NULL) { if (!gst_multi_file_sink_open_next_file (multifilesink)) goto stdio_write_error; } ret = fwrite (map.data, map.size, 1, multifilesink->file); if (ret != 1) goto stdio_write_error; break; case GST_MULTI_FILE_SINK_NEXT_KEY_FRAME: if (multifilesink->next_segment == GST_CLOCK_TIME_NONE) { if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) { multifilesink->next_segment = GST_BUFFER_TIMESTAMP (buffer) + 10 * GST_SECOND; } } if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) && GST_BUFFER_TIMESTAMP (buffer) >= multifilesink->next_segment && !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) { if (multifilesink->file) { first_file = FALSE; gst_multi_file_sink_close_file (multifilesink, buffer); } multifilesink->next_segment += 10 * GST_SECOND; } if (multifilesink->file == NULL) { if (!gst_multi_file_sink_open_next_file (multifilesink)) goto stdio_write_error; if (!first_file) gst_multi_file_sink_write_stream_headers (multifilesink); } ret = fwrite (map.data, map.size, 1, multifilesink->file); if (ret != 1) goto stdio_write_error; break; case GST_MULTI_FILE_SINK_NEXT_KEY_UNIT_EVENT: if (multifilesink->file == NULL) { if (!gst_multi_file_sink_open_next_file (multifilesink)) goto stdio_write_error; /* we don't need to write stream headers here, they will be inserted in * the stream by upstream elements if key unit events have * all_headers=true set */ } ret = fwrite (map.data, map.size, 1, multifilesink->file); if (ret != 1) goto stdio_write_error; break; case GST_MULTI_FILE_SINK_NEXT_MAX_SIZE:{ guint64 new_size; new_size = multifilesink->cur_file_size + map.size; if (new_size > multifilesink->max_file_size) { GST_INFO_OBJECT (multifilesink, "current size: %" G_GUINT64_FORMAT ", new_size: %" G_GUINT64_FORMAT ", max. size %" G_GUINT64_FORMAT, multifilesink->cur_file_size, new_size, multifilesink->max_file_size); if (multifilesink->file != NULL) { first_file = FALSE; gst_multi_file_sink_close_file (multifilesink, buffer); } } if (multifilesink->file == NULL) { if (!gst_multi_file_sink_open_next_file (multifilesink)) goto stdio_write_error; if (!first_file) gst_multi_file_sink_write_stream_headers (multifilesink); } ret = fwrite (map.data, map.size, 1, multifilesink->file); if (ret != 1) goto stdio_write_error; multifilesink->cur_file_size += map.size; break; } case GST_MULTI_FILE_SINK_NEXT_MAX_DURATION:{ GstClockTime new_duration = 0; if (GST_BUFFER_PTS_IS_VALID (buffer) && GST_CLOCK_TIME_IS_VALID (multifilesink->file_pts)) { /* The new duration will extend to this new buffer pts ... */ new_duration = GST_BUFFER_PTS (buffer) - multifilesink->file_pts; /* ... and duration (if it has one) */ if (GST_BUFFER_DURATION_IS_VALID (buffer)) new_duration += GST_BUFFER_DURATION (buffer); } if (new_duration > multifilesink->max_file_duration) { GST_INFO_OBJECT (multifilesink, "new_duration: %" G_GUINT64_FORMAT ", max. duration %" G_GUINT64_FORMAT, new_duration, multifilesink->max_file_duration); if (multifilesink->file != NULL) { first_file = FALSE; gst_multi_file_sink_close_file (multifilesink, buffer); } } if (multifilesink->file == NULL) { if (!gst_multi_file_sink_open_next_file (multifilesink)) goto stdio_write_error; multifilesink->file_pts = GST_BUFFER_PTS (buffer); if (!first_file) gst_multi_file_sink_write_stream_headers (multifilesink); } ret = fwrite (map.data, map.size, 1, multifilesink->file); if (ret != 1) goto stdio_write_error; break; } default: g_assert_not_reached (); } gst_buffer_unmap (buffer, &map); return GST_FLOW_OK; /* ERRORS */ stdio_write_error: switch (errno) { case ENOSPC: GST_ELEMENT_ERROR (multifilesink, RESOURCE, NO_SPACE_LEFT, ("Error while writing to file."), ("%s", g_strerror (errno))); break; default: GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE, ("Error while writing to file."), ("%s", g_strerror (errno))); } gst_buffer_unmap (buffer, &map); return GST_FLOW_ERROR; }
static gboolean gst_multi_file_sink_event (GstBaseSink * sink, GstEvent * event) { GstMultiFileSink *multifilesink; gchar *filename; multifilesink = GST_MULTI_FILE_SINK (sink); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CUSTOM_DOWNSTREAM: { GstClockTime timestamp, duration; GstClockTime running_time, stream_time; guint64 offset, offset_end; gboolean all_headers; guint count; if (multifilesink->next_file != GST_MULTI_FILE_SINK_NEXT_KEY_UNIT_EVENT || !gst_video_event_is_force_key_unit (event)) goto out; gst_video_event_parse_downstream_force_key_unit (event, ×tamp, &stream_time, &running_time, &all_headers, &count); if (multifilesink->force_key_unit_count != -1 && multifilesink->force_key_unit_count == count) goto out; multifilesink->force_key_unit_count = count; if (multifilesink->file) { duration = GST_CLOCK_TIME_NONE; offset = offset_end = -1; filename = g_strdup_printf (multifilesink->filename, multifilesink->index); gst_multi_file_sink_close_file (multifilesink, NULL); gst_multi_file_sink_post_message_full (multifilesink, timestamp, duration, offset, offset_end, running_time, stream_time, filename); g_free (filename); } if (multifilesink->file == NULL) { if (!gst_multi_file_sink_open_next_file (multifilesink)) goto stdio_write_error; } break; } case GST_EVENT_EOS: if (multifilesink->aggregate_gops) { GstBuffer *buf = gst_buffer_new (); /* push key unit buffer to force writing out the pending GOP data */ GST_INFO_OBJECT (sink, "EOS, write pending GOP data"); GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT); gst_multi_file_sink_render (sink, buf); gst_buffer_unref (buf); } if (multifilesink->file) { gchar *filename; filename = g_strdup_printf (multifilesink->filename, multifilesink->index); gst_multi_file_sink_close_file (multifilesink, NULL); gst_multi_file_sink_post_message_from_time (multifilesink, GST_BASE_SINK (multifilesink)->segment.position, -1, filename); g_free (filename); } break; default: break; } out: return GST_BASE_SINK_CLASS (parent_class)->event (sink, event); /* ERRORS */ stdio_write_error: { GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE, ("Error while writing to file."), (NULL)); gst_event_unref (event); return FALSE; } }
static GstFlowReturn gst_multi_file_sink_render (GstBaseSink * sink, GstBuffer * buffer) { GstMultiFileSink *multifilesink; guint size; guint8 *data; gchar *filename; gboolean ret; GError *error = NULL; size = GST_BUFFER_SIZE (buffer); data = GST_BUFFER_DATA (buffer); multifilesink = GST_MULTI_FILE_SINK (sink); switch (multifilesink->next_file) { case GST_MULTI_FILE_SINK_NEXT_BUFFER: gst_multi_file_sink_ensure_max_files (multifilesink); filename = g_strdup_printf (multifilesink->filename, multifilesink->index); ret = g_file_set_contents (filename, (char *) data, size, &error); if (!ret) goto write_error; multifilesink->files = g_slist_append (multifilesink->files, filename); multifilesink->n_files += 1; gst_multi_file_sink_post_message (multifilesink, buffer, filename); multifilesink->index++; break; case GST_MULTI_FILE_SINK_NEXT_DISCONT: if (GST_BUFFER_IS_DISCONT (buffer)) { if (multifilesink->file) gst_multi_file_sink_close_file (multifilesink, buffer); } if (multifilesink->file == NULL) { if (!gst_multi_file_sink_open_next_file (multifilesink)) goto stdio_write_error; } ret = fwrite (GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), 1, multifilesink->file); if (ret != 1) goto stdio_write_error; break; case GST_MULTI_FILE_SINK_NEXT_KEY_FRAME: if (multifilesink->next_segment == GST_CLOCK_TIME_NONE) { if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) { multifilesink->next_segment = GST_BUFFER_TIMESTAMP (buffer) + 10 * GST_SECOND; } } if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) && GST_BUFFER_TIMESTAMP (buffer) >= multifilesink->next_segment && !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) { if (multifilesink->file) gst_multi_file_sink_close_file (multifilesink, buffer); multifilesink->next_segment += 10 * GST_SECOND; } if (multifilesink->file == NULL) { int i; if (!gst_multi_file_sink_open_next_file (multifilesink)) goto stdio_write_error; if (multifilesink->streamheaders) { for (i = 0; i < multifilesink->n_streamheaders; i++) { ret = fwrite (GST_BUFFER_DATA (multifilesink->streamheaders[i]), GST_BUFFER_SIZE (multifilesink->streamheaders[i]), 1, multifilesink->file); if (ret != 1) goto stdio_write_error; } } } ret = fwrite (GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), 1, multifilesink->file); if (ret != 1) goto stdio_write_error; break; default: g_assert_not_reached (); } return GST_FLOW_OK; /* ERRORS */ write_error: { switch (error->code) { case G_FILE_ERROR_NOSPC:{ GST_ELEMENT_ERROR (multifilesink, RESOURCE, NO_SPACE_LEFT, (NULL), (NULL)); break; } default:{ GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE, ("Error while writing to file \"%s\".", filename), ("%s", g_strerror (errno))); } } g_error_free (error); g_free (filename); return GST_FLOW_ERROR; } stdio_write_error: GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE, ("Error while writing to file."), (NULL)); return GST_FLOW_ERROR; }