static void
gst_multi_file_sink_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
  GstMultiFileSink *sink = GST_MULTI_FILE_SINK (object);

  switch (prop_id) {
    case PROP_LOCATION:
      g_value_set_string (value, sink->filename);
      break;
    case PROP_INDEX:
      g_value_set_int (value, sink->index);
      break;
    case PROP_POST_MESSAGES:
      g_value_set_boolean (value, sink->post_messages);
      break;
    case PROP_NEXT_FILE:
      g_value_set_enum (value, sink->next_file);
      break;
    case PROP_MAX_FILES:
      g_value_set_uint (value, sink->max_files);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
Esempio n. 2
0
static void
gst_multi_file_sink_finalize (GObject * object)
{
    GstMultiFileSink *sink = GST_MULTI_FILE_SINK (object);

    g_free (sink->filename);

    G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
gst_multi_file_sink_start (GstBaseSink * bsink)
{
  GstMultiFileSink *sink = GST_MULTI_FILE_SINK (bsink);

  if (sink->aggregate_gops)
    sink->gop_adapter = gst_adapter_new ();
  sink->potential_next_gop = NULL;
  sink->file_pts = GST_CLOCK_TIME_NONE;

  return TRUE;
}
Esempio n. 4
0
static gboolean
gst_multi_file_sink_stop (GstBaseSink * sink)
{
    GstMultiFileSink *multifilesink;

    multifilesink = GST_MULTI_FILE_SINK (sink);

    if (multifilesink->file != NULL) {
        fclose (multifilesink->file);
        multifilesink->file = NULL;
    }

    return TRUE;
}
Esempio n. 5
0
static gboolean
gst_multi_file_sink_stop (GstBaseSink * sink)
{
  GstMultiFileSink *multifilesink;
  int i;

  multifilesink = GST_MULTI_FILE_SINK (sink);

  if (multifilesink->file != NULL) {
    fclose (multifilesink->file);
    multifilesink->file = NULL;
  }

  if (multifilesink->streamheaders) {
    for (i = 0; i < multifilesink->n_streamheaders; i++) {
      gst_buffer_unref (multifilesink->streamheaders[i]);
    }
    g_free (multifilesink->streamheaders);
    multifilesink->streamheaders = NULL;
  }

  if (multifilesink->gop_adapter != NULL) {
    g_object_unref (multifilesink->gop_adapter);
    multifilesink->gop_adapter = NULL;
  }

  if (multifilesink->potential_next_gop != NULL) {
    g_list_free_full (multifilesink->potential_next_gop,
        (GDestroyNotify) gst_buffer_unref);
    multifilesink->potential_next_gop = NULL;
  }

  multifilesink->force_key_unit_count = -1;

  g_queue_foreach (&multifilesink->old_files, (GFunc) g_free, NULL);
  g_queue_clear (&multifilesink->old_files);

  return TRUE;
}
static gboolean
gst_multi_file_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
{
  GstMultiFileSink *multifilesink;
  GstStructure *structure;

  multifilesink = GST_MULTI_FILE_SINK (sink);

  structure = gst_caps_get_structure (caps, 0);
  if (structure) {
    const GValue *value;

    value = gst_structure_get_value (structure, "streamheader");

    if (GST_VALUE_HOLDS_ARRAY (value)) {
      int i;

      if (multifilesink->streamheaders) {
        for (i = 0; i < multifilesink->n_streamheaders; i++) {
          gst_buffer_unref (multifilesink->streamheaders[i]);
        }
        g_free (multifilesink->streamheaders);
      }

      multifilesink->n_streamheaders = gst_value_array_get_size (value);
      multifilesink->streamheaders =
          g_malloc (sizeof (GstBuffer *) * multifilesink->n_streamheaders);

      for (i = 0; i < multifilesink->n_streamheaders; i++) {
        multifilesink->streamheaders[i] =
            gst_buffer_ref (gst_value_get_buffer (gst_value_array_get_value
                (value, i)));
      }
    }
  }

  return TRUE;
}
static gboolean
gst_multi_file_sink_stop (GstBaseSink * sink)
{
  GstMultiFileSink *multifilesink;
  int i;

  multifilesink = GST_MULTI_FILE_SINK (sink);

  if (multifilesink->file != NULL) {
    fclose (multifilesink->file);
    multifilesink->file = NULL;
  }

  if (multifilesink->streamheaders) {
    for (i = 0; i < multifilesink->n_streamheaders; i++) {
      gst_buffer_unref (multifilesink->streamheaders[i]);
    }
    g_free (multifilesink->streamheaders);
    multifilesink->streamheaders = NULL;
  }

  return TRUE;
}
static void
gst_multi_file_sink_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstMultiFileSink *sink = GST_MULTI_FILE_SINK (object);

  switch (prop_id) {
    case PROP_LOCATION:
      gst_multi_file_sink_set_location (sink, g_value_get_string (value));
      break;
    case PROP_INDEX:
      sink->index = g_value_get_int (value);
      break;
    case PROP_POST_MESSAGES:
      sink->post_messages = g_value_get_boolean (value);
      break;
    case PROP_NEXT_FILE:
      sink->next_file = g_value_get_enum (value);
      break;
    case PROP_MAX_FILES:
      sink->max_files = g_value_get_uint (value);
      break;
    case PROP_MAX_FILE_SIZE:
      sink->max_file_size = g_value_get_uint64 (value);
      break;
    case PROP_MAX_FILE_DURATION:
      sink->max_file_duration = g_value_get_uint64 (value);
      break;
    case PROP_AGGREGATE_GOPS:
      sink->aggregate_gops = g_value_get_boolean (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
Esempio n. 9
0
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:
        filename = g_strdup_printf (multifilesink->filename,
                                    multifilesink->index);

        ret = g_file_set_contents (filename, (char *) data, size, &error);
        if (!ret)
            goto write_error;

        gst_multi_file_sink_post_message (multifilesink, buffer, filename);
        multifilesink->index++;

        g_free (filename);
        break;
    case GST_MULTI_FILE_SINK_NEXT_DISCONT:
        if (GST_BUFFER_IS_DISCONT (buffer)) {
            if (multifilesink->file) {
                fclose (multifilesink->file);
                multifilesink->file = NULL;

                filename = g_strdup_printf (multifilesink->filename,
                                            multifilesink->index);
                gst_multi_file_sink_post_message (multifilesink, buffer, filename);
                g_free (filename);
                multifilesink->index++;
            }
        }

        if (multifilesink->file == NULL) {
            filename = g_strdup_printf (multifilesink->filename,
                                        multifilesink->index);
            multifilesink->file = g_fopen (filename, "wb");
            g_free (filename);

            if (multifilesink->file == NULL)
                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) {
                fclose (multifilesink->file);
                multifilesink->file = NULL;

                filename = g_strdup_printf (multifilesink->filename,
                                            multifilesink->index);
                gst_multi_file_sink_post_message (multifilesink, buffer, filename);
                g_free (filename);
                multifilesink->index++;
            }

            multifilesink->next_segment += 10 * GST_SECOND;
        }

        if (multifilesink->file == NULL) {
            filename = g_strdup_printf (multifilesink->filename,
                                        multifilesink->index);
            multifilesink->file = g_fopen (filename, "wb");
            g_free (filename);

            if (multifilesink->file == NULL)
                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;
}
Esempio n. 10
0
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, &timestamp,
          &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;
  }
}
Esempio n. 11
0
static GstFlowReturn
gst_multi_file_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
{
  GstMultiFileSink *sink = GST_MULTI_FILE_SINK (bsink);
  GstFlowReturn flow = GST_FLOW_OK;
  gboolean key_unit, header;

  header = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_HEADER);
  key_unit = !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);

  if (sink->aggregate_gops) {
    GstBuffer *gop_buffer = NULL;
    guint avail;

    avail = gst_adapter_available (sink->gop_adapter);

    GST_LOG_OBJECT (sink, "aggregate GOP: received %s%s unit buffer: "
        "%" GST_PTR_FORMAT,
        (key_unit) ? "key" : "delta", (header) ? " header" : "", buffer);

    /* If it's a header buffer, it might potentially be for the next GOP */
    if (header) {
      GST_LOG_OBJECT (sink, "Accumulating buffer to potential next GOP");
      sink->potential_next_gop =
          g_list_append (sink->potential_next_gop, gst_buffer_ref (buffer));
    } else {
      if (key_unit && avail > 0) {
        GstClockTime pts, dts;
        GST_LOG_OBJECT (sink, "Grabbing pending completed GOP");
        pts = gst_adapter_prev_pts_at_offset (sink->gop_adapter, 0, NULL);
        dts = gst_adapter_prev_dts_at_offset (sink->gop_adapter, 0, NULL);
        gop_buffer = gst_adapter_take_buffer (sink->gop_adapter, avail);
        GST_BUFFER_PTS (gop_buffer) = pts;
        GST_BUFFER_DTS (gop_buffer) = dts;
      }

      /* just accumulate the buffer */
      if (sink->potential_next_gop) {
        GList *tmp;
        GST_LOG_OBJECT (sink,
            "Carrying over pending next GOP data into adapter");
        /* If we have pending data, put that first in the adapter */
        for (tmp = sink->potential_next_gop; tmp; tmp = tmp->next) {
          GstBuffer *tmpb = (GstBuffer *) tmp->data;
          gst_adapter_push (sink->gop_adapter, tmpb);
        }
        g_list_free (sink->potential_next_gop);
        sink->potential_next_gop = NULL;
      }
      GST_LOG_OBJECT (sink, "storing buffer in adapter");
      gst_adapter_push (sink->gop_adapter, gst_buffer_ref (buffer));

      if (gop_buffer != NULL) {
        GST_DEBUG_OBJECT (sink, "writing out pending GOP, %u bytes", avail);
        GST_DEBUG_OBJECT (sink,
            "gop buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
            " duration:%" GST_TIME_FORMAT,
            GST_TIME_ARGS (GST_BUFFER_PTS (gop_buffer)),
            GST_TIME_ARGS (GST_BUFFER_DTS (gop_buffer)),
            GST_TIME_ARGS (GST_BUFFER_DURATION (gop_buffer)));
        flow = gst_multi_file_sink_write_buffer (sink, gop_buffer);
        gst_buffer_unref (gop_buffer);
      }
    }
  } else {
    flow = gst_multi_file_sink_write_buffer (sink, buffer);
  }
  return flow;
}