static void
_add_track_element (GESFormatter * self, GESClip * clip,
    GESTrackElement * trackelement, const gchar * track_id,
    GstStructure * children_properties, GstStructure * properties)
{
  GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
  GESTrack *track = g_hash_table_lookup (priv->tracks, track_id);

  if (track == NULL) {
    GST_WARNING_OBJECT (self, "No track with id %s, can not add trackelement",
        track_id);
    gst_object_unref (trackelement);
    return;
  }

  GST_DEBUG_OBJECT (self, "Adding track_element: %" GST_PTR_FORMAT
      " To : %" GST_PTR_FORMAT, trackelement, clip);

  ges_container_add (GES_CONTAINER (clip), GES_TIMELINE_ELEMENT (trackelement));
  gst_structure_foreach (children_properties,
      (GstStructureForeachFunc) _set_child_property, trackelement);

  if (properties)
    gst_structure_foreach (properties,
        (GstStructureForeachFunc) set_property_foreach, trackelement);
}
void
ges_base_xml_formatter_set_timeline_properties (GESBaseXmlFormatter * self,
    GESTimeline * timeline, const gchar * properties, const gchar * metadatas)
{
  GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
  gboolean auto_transition = FALSE;

  if (properties) {
    GstStructure *props = gst_structure_from_string (properties, NULL);

    if (props) {
      if (gst_structure_get_boolean (props, "auto-transition",
              &auto_transition))
        gst_structure_remove_field (props, "auto-transition");

      gst_structure_foreach (props,
          (GstStructureForeachFunc) set_property_foreach, timeline);
      gst_structure_free (props);
    }
  }

  if (metadatas) {
    ges_meta_container_add_metas_from_string (GES_META_CONTAINER (timeline),
        metadatas);
  };

  priv->timeline_auto_transition = auto_transition;
}
void
ges_base_xml_formatter_add_source (GESBaseXmlFormatter * self,
    const gchar * track_id, GstStructure * children_properties)
{
  GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
  GESTrackElement *element = NULL;

  if (track_id[0] != '-' && priv->current_clip)
    element = _get_element_by_track_id (priv, track_id, priv->current_clip);

  else if (track_id[0] != '-' && priv->current_pending_clip) {
    PendingChildProperties *pchildprops;

    pchildprops = g_slice_new0 (PendingChildProperties);
    pchildprops->track_id = g_strdup (track_id);
    pchildprops->structure = children_properties ?
        gst_structure_copy (children_properties) : NULL;
    priv->current_pending_clip->children_props =
        g_list_append (priv->current_pending_clip->children_props, pchildprops);
    return;
  } else {
    element = priv->current_track_element;
  }

  if (element == NULL) {
    GST_WARNING
        ("No current track element to which we can append children properties");
    return;
  }

  gst_structure_foreach (children_properties,
      (GstStructureForeachFunc) _set_child_property, element);
}
static void
_finalize (GObject * object)
{
  GESBaseXmlFormatterPrivate *priv = _GET_PRIV (object);

  if (priv->parsecontext != NULL)
    g_markup_parse_context_free (priv->parsecontext);

  G_OBJECT_CLASS (parent_class)->finalize (object);
}
void
ges_base_xml_formatter_add_layer (GESBaseXmlFormatter * self,
    GType extractable_type, guint priority, GstStructure * properties,
    const gchar * metadatas, GError ** error)
{
  LayerEntry *entry;
  GESAsset *asset;
  GESLayer *layer;
  gboolean auto_transition = FALSE;
  GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);

  if (priv->check_only)
    return;

  if (extractable_type == G_TYPE_NONE)
    layer = ges_layer_new ();
  else {
    asset = ges_asset_request (extractable_type, NULL, error);
    if (asset == NULL) {
      if (error && *error == NULL) {
        g_set_error (error, G_MARKUP_ERROR,
            G_MARKUP_ERROR_INVALID_CONTENT,
            "Layer type %s could not be created'",
            g_type_name (extractable_type));
        return;
      }
    }
    layer = GES_LAYER (ges_asset_extract (asset, error));
  }

  ges_layer_set_priority (layer, priority);
  ges_timeline_add_layer (GES_FORMATTER (self)->timeline, layer);
  if (properties) {
    if (gst_structure_get_boolean (properties, "auto-transition",
            &auto_transition))
      gst_structure_remove_field (properties, "auto-transition");

    gst_structure_foreach (properties,
        (GstStructureForeachFunc) set_property_foreach, layer);
  }

  if (metadatas)
    ges_meta_container_add_metas_from_string (GES_META_CONTAINER (layer),
        metadatas);

  entry = g_slice_new0 (LayerEntry);
  entry->layer = gst_object_ref (layer);
  entry->auto_trans = auto_transition;

  g_hash_table_insert (priv->layers, GINT_TO_POINTER (priority), entry);
}
void
ges_base_xml_formatter_add_control_binding (GESBaseXmlFormatter * self,
    const gchar * binding_type, const gchar * source_type,
    const gchar * property_name, gint mode, const gchar * track_id,
    GSList * timed_values)
{
  GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
  GESTrackElement *element = NULL;

  if (track_id[0] != '-' && priv->current_clip)
    element = _get_element_by_track_id (priv, track_id, priv->current_clip);

  else if (track_id[0] != '-' && priv->current_pending_clip) {
    PendingBinding *pbinding;

    pbinding = g_slice_new0 (PendingBinding);
    pbinding->source = gst_interpolation_control_source_new ();
    g_object_set (pbinding->source, "mode", mode, NULL);
    gst_timed_value_control_source_set_from_list (GST_TIMED_VALUE_CONTROL_SOURCE
        (pbinding->source), timed_values);
    pbinding->propname = g_strdup (property_name);
    pbinding->binding_type = g_strdup (binding_type);
    pbinding->track_id = g_strdup (track_id);
    priv->current_pending_clip->pending_bindings =
        g_list_append (priv->current_pending_clip->pending_bindings, pbinding);
    return;
  }

  else {
    element = priv->current_track_element;
  }

  if (element == NULL) {
    GST_WARNING ("No current track element to which we can append a binding");
    return;
  }

  if (!g_strcmp0 (source_type, "interpolation")) {
    GstControlSource *source;

    source = gst_interpolation_control_source_new ();
    ges_track_element_set_control_source (element, source,
        property_name, binding_type);

    g_object_set (source, "mode", mode, NULL);

    gst_timed_value_control_source_set_from_list (GST_TIMED_VALUE_CONTROL_SOURCE
        (source), timed_values);
  } else
    GST_WARNING ("This interpolation type is not supported\n");
}
static void
_dispose (GObject * object)
{
  GESBaseXmlFormatterPrivate *priv = _GET_PRIV (object);

  g_clear_pointer (&priv->assetid_pendingclips,
      (GDestroyNotify) g_hash_table_unref);
  g_clear_pointer (&priv->containers, (GDestroyNotify) g_hash_table_unref);
  g_clear_pointer (&priv->clipid_pendings, (GDestroyNotify) g_hash_table_unref);
  g_clear_pointer (&priv->tracks, (GDestroyNotify) g_hash_table_unref);
  g_clear_pointer (&priv->layers, (GDestroyNotify) g_hash_table_unref);

  G_OBJECT_CLASS (parent_class)->dispose (object);
}
Exemplo n.º 8
0
static void
ges_container_init (GESContainer * self)
{
    self->priv = _GET_PRIV (self);

    /* FIXME, check why default was GST_SECOND? (before the existend of
     * ges-container)
     *
     * _DURATION (self) = GST_SECOND; */
    self->height = 1;             /* FIXME Why 1 and not 0? */
    self->children = NULL;

    self->priv->mappings = g_hash_table_new_full (g_direct_hash, g_direct_equal,
                           NULL, (GDestroyNotify) _free_mapping);
}
static gboolean
_can_load_uri (GESFormatter * dummy_formatter, const gchar * uri,
    GError ** error)
{
  GMarkupParseContext *ctx;
  GESBaseXmlFormatter *self = GES_BASE_XML_FORMATTER (dummy_formatter);

  /* we create a temporary object so we can use it as a context */
  _GET_PRIV (self)->check_only = TRUE;


  ctx = create_parser_context (self, uri, error);
  if (!ctx)
    return FALSE;

  g_markup_parse_context_free (ctx);
  return TRUE;
}
void
ges_base_xml_formatter_add_group (GESBaseXmlFormatter * self,
    const gchar * id, const gchar * properties)
{
  PendingGroup *pgroup;
  GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);

  if (priv->check_only)
    return;

  pgroup = g_slice_new0 (PendingGroup);
  pgroup->group = ges_group_new ();

  g_hash_table_insert (priv->containers, g_strdup (id),
      gst_object_ref (pgroup->group));
  priv->groups = g_list_prepend (priv->groups, pgroup);

  return;
}
void
ges_base_xml_formatter_last_group_add_child (GESBaseXmlFormatter * self,
    const gchar * child_id, const gchar * name)
{
  PendingGroup *pgroup;
  GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);

  if (priv->check_only)
    return;

  g_return_if_fail (priv->groups);

  pgroup = priv->groups->data;

  pgroup->pending_children =
      g_list_prepend (pgroup->pending_children, g_strdup (child_id));

  GST_DEBUG_OBJECT (self, "Adding %s to %s", child_id,
      GES_TIMELINE_ELEMENT_NAME (((PendingGroup *) priv->groups->data)->group));
}
static gboolean
_load_from_uri (GESFormatter * self, GESTimeline * timeline, const gchar * uri,
    GError ** error)
{
  GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);

  ges_timeline_set_auto_transition (timeline, FALSE);

  priv->parsecontext =
      create_parser_context (GES_BASE_XML_FORMATTER (self), uri, error);

  if (!priv->parsecontext)
    return FALSE;

  if (g_hash_table_size (priv->assetid_pendingclips) == 0 &&
      priv->pending_assets == NULL)
    g_idle_add ((GSourceFunc) _loading_done_cb, g_object_ref (self));

  return TRUE;
}
void
ges_base_xml_formatter_add_track (GESBaseXmlFormatter * self,
    GESTrackType track_type, GstCaps * caps, const gchar * id,
    GstStructure * properties, const gchar * metadatas, GError ** error)
{
  GESTrack *track;
  GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);

  if (priv->check_only) {
    if (caps)
      gst_caps_unref (caps);

    return;
  }

  track = ges_track_new (track_type, caps);
  ges_timeline_add_track (GES_FORMATTER (self)->timeline, track);

  if (properties) {
    gchar *restriction;
    GstCaps *caps;

    gst_structure_get (properties, "restriction-caps", G_TYPE_STRING,
        &restriction, NULL);
    gst_structure_remove_fields (properties, "restriction-caps", "caps",
        "message-forward", NULL);
    if (g_strcmp0 (restriction, "NULL")) {
      caps = gst_caps_from_string (restriction);
      ges_track_set_restriction_caps (track, caps);
    }
    gst_structure_foreach (properties,
        (GstStructureForeachFunc) set_property_foreach, track);
  }

  g_hash_table_insert (priv->tracks, g_strdup (id), gst_object_ref (track));
  if (metadatas)
    ges_meta_container_add_metas_from_string (GES_META_CONTAINER (track),
        metadatas);
}
void
ges_base_xml_formatter_add_asset (GESBaseXmlFormatter * self,
    const gchar * id, GType extractable_type, GstStructure * properties,
    const gchar * metadatas, GError ** error)
{
  PendingAsset *passet;
  GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);

  if (priv->check_only)
    return;

  passet = g_slice_new0 (PendingAsset);
  passet->metadatas = g_strdup (metadatas);
  passet->formatter = gst_object_ref (self);
  if (properties)
    passet->properties = gst_structure_copy (properties);

  ges_asset_request_async (extractable_type, id, NULL,
      (GAsyncReadyCallback) new_asset_cb, passet);
  ges_project_add_loading_asset (GES_FORMATTER (self)->project,
      extractable_type, id);
  priv->pending_assets = g_list_prepend (priv->pending_assets, passet);
}
void
ges_base_xml_formatter_add_track_element (GESBaseXmlFormatter * self,
    GType track_element_type, const gchar * asset_id, const gchar * track_id,
    const gchar * timeline_obj_id, GstStructure * children_properties,
    GstStructure * properties, const gchar * metadatas, GError ** error)
{
  GESTrackElement *trackelement;

  GError *err = NULL;
  GESAsset *asset = NULL;
  GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);

  if (priv->check_only)
    return;

  if (g_type_is_a (track_element_type, GES_TYPE_TRACK_ELEMENT) == FALSE) {
    GST_DEBUG_OBJECT (self, "%s is not a TrackElement, can not create it",
        g_type_name (track_element_type));
    goto out;
  }

  if (g_type_is_a (track_element_type, GES_TYPE_BASE_EFFECT) == FALSE) {
    GST_FIXME_OBJECT (self, "%s currently not supported",
        g_type_name (track_element_type));
    goto out;
  }

  asset = ges_asset_request (track_element_type, asset_id, &err);
  if (asset == NULL) {
    GST_DEBUG_OBJECT (self, "Can not create trackelement %s", asset_id);
    GST_FIXME_OBJECT (self, "Check if missing plugins etc %s",
        err ? err->message : "");

    goto out;
  }

  trackelement = GES_TRACK_ELEMENT (ges_asset_extract (asset, NULL));
  if (trackelement) {
    GESClip *clip;
    if (metadatas)
      ges_meta_container_add_metas_from_string (GES_META_CONTAINER
          (trackelement), metadatas);

    clip = g_hash_table_lookup (priv->containers, timeline_obj_id);
    if (clip) {
      _add_track_element (GES_FORMATTER (self), clip, trackelement, track_id,
          children_properties, properties);
    } else {
      PendingEffects *peffect;
      PendingClip *pend = g_hash_table_lookup (priv->clipid_pendings,
          timeline_obj_id);
      if (pend == NULL) {
        GST_WARNING_OBJECT (self, "No Clip with id: %s can not "
            "add TrackElement", timeline_obj_id);
        goto out;
      }

      peffect = g_slice_new0 (PendingEffects);

      peffect->trackelement = trackelement;
      peffect->track_id = g_strdup (track_id);
      peffect->properties = properties ? gst_structure_copy (properties) : NULL;
      peffect->children_properties = children_properties ?
          gst_structure_copy (children_properties) : NULL;

      pend->effects = g_list_append (pend->effects, peffect);
    }
    priv->current_track_element = trackelement;
  }

  ges_project_add_asset (GES_FORMATTER (self)->project, asset);

out:
  if (asset)
    gst_object_unref (asset);
  if (err)
    g_error_free (err);

  return;
}
void
ges_base_xml_formatter_add_encoding_profile (GESBaseXmlFormatter * self,
    const gchar * type, const gchar * parent, const gchar * name,
    const gchar * description, GstCaps * format, const gchar * preset,
    const gchar * preset_name, guint id, guint presence, GstCaps * restriction,
    guint pass, gboolean variableframerate, GstStructure * properties,
    GError ** error)
{
  const GList *tmp;
  GstEncodingProfile *profile;
  GstEncodingContainerProfile *parent_profile = NULL;
  GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);

  if (priv->check_only)
    goto done;

  if (parent == NULL) {
    profile =
        _create_profile (self, type, parent, name, description, format, preset,
        preset_name, id, presence, restriction, pass, variableframerate);
    ges_project_add_encoding_profile (GES_FORMATTER (self)->project, profile);
    gst_object_unref (profile);

    goto done;
  }

  for (tmp = ges_project_list_encoding_profiles (GES_FORMATTER (self)->project);
      tmp; tmp = tmp->next) {
    GstEncodingProfile *tmpprofile = GST_ENCODING_PROFILE (tmp->data);

    if (g_strcmp0 (gst_encoding_profile_get_name (tmpprofile),
            gst_encoding_profile_get_name (tmpprofile)) == 0) {

      if (!GST_IS_ENCODING_CONTAINER_PROFILE (tmpprofile)) {
        g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
            "Profile '%s' parent %s is not a container...'", name, parent);
        goto done;
      }

      parent_profile = GST_ENCODING_CONTAINER_PROFILE (tmpprofile);
      break;
    }
  }

  if (parent_profile == NULL) {
    g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
        "Profile '%s' parent %s does not exist'", name, parent);
    goto done;
  }

  profile =
      _create_profile (self, type, parent, name, description, format, preset,
      preset_name, id, presence, restriction, pass, variableframerate);

  if (profile == NULL)
    goto done;

  gst_encoding_container_profile_add_profile (parent_profile, profile);

done:
  if (format)
    gst_caps_unref (format);
  if (restriction)
    gst_caps_unref (restriction);
}
void
ges_base_xml_formatter_add_clip (GESBaseXmlFormatter * self,
    const gchar * id, const char *asset_id, GType type, GstClockTime start,
    GstClockTime inpoint, GstClockTime duration,
    guint layer_prio, GESTrackType track_types, GstStructure * properties,
    const gchar * metadatas, GError ** error)
{
  GESAsset *asset;
  GESClip *nclip;
  LayerEntry *entry;
  GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);

  if (priv->check_only)
    return;

  entry = g_hash_table_lookup (priv->layers, GINT_TO_POINTER (layer_prio));
  if (entry == NULL) {
    g_set_error (error, GES_ERROR, GES_ERROR_FORMATTER_MALFORMED_INPUT_FILE,
        "We got a Clip in a layer"
        " that does not exist, something is wrong either in the project file or"
        " in %s", g_type_name (G_OBJECT_TYPE (self)));
    return;
  }

  /* We do not want the properties that are passed to layer-add_asset to be reset */
  if (properties)
    gst_structure_remove_fields (properties, "supported-formats",
        "inpoint", "start", "duration", NULL);

  asset = ges_asset_request (type, asset_id, NULL);
  if (asset == NULL) {
    gchar *real_id;
    PendingClip *pclip;
    GList *pendings;

    real_id = ges_extractable_type_check_id (type, asset_id, error);
    if (real_id == NULL) {
      if (*error == NULL)
        g_set_error (error, G_MARKUP_ERROR,
            G_MARKUP_ERROR_INVALID_CONTENT,
            "Object type '%s' with Asset id: %s not be created'",
            g_type_name (type), asset_id);

      return;
    }

    pendings = g_hash_table_lookup (priv->assetid_pendingclips, asset_id);

    pclip = g_slice_new0 (PendingClip);
    GST_DEBUG_OBJECT (self, "Adding pending %p for %s, currently: %i",
        pclip, asset_id, g_list_length (pendings));

    pclip->id = g_strdup (id);
    pclip->track_types = track_types;
    pclip->duration = duration;
    pclip->inpoint = inpoint;
    pclip->start = start;
    pclip->layer = gst_object_ref (entry->layer);

    pclip->properties = properties ? gst_structure_copy (properties) : NULL;
    pclip->metadatas = g_strdup (metadatas);

    /* Add the new pending object to the hashtable */
    g_hash_table_insert (priv->assetid_pendingclips, real_id,
        g_list_append (pendings, pclip));
    g_hash_table_insert (priv->clipid_pendings, g_strdup (id), pclip);

    priv->current_clip = NULL;
    priv->current_pending_clip = pclip;

    return;
  }

  nclip = _add_object_to_layer (priv, id, entry->layer,
      asset, start, inpoint, duration, track_types, metadatas, properties);

  if (!nclip)
    return;

  priv->current_clip = nclip;
}
static void
new_asset_cb (GESAsset * source, GAsyncResult * res, PendingAsset * passet)
{
  GError *error = NULL;
  gchar *possible_id = NULL;
  GList *tmp, *pendings = NULL;
  GESFormatter *self = passet->formatter;
  const gchar *id = ges_asset_get_id (source);
  GESBaseXmlFormatterPrivate *priv = _GET_PRIV (self);
  GESAsset *asset = ges_asset_request_finish (res, &error);

  if (error) {
    GST_LOG_OBJECT (self, "Error %s creating asset id: %s", error->message, id);

    /* We set the metas on the Asset to give hints to the user */
    if (passet->metadatas)
      ges_meta_container_add_metas_from_string (GES_META_CONTAINER (source),
          passet->metadatas);
    if (passet->properties)
      gst_structure_foreach (passet->properties,
          (GstStructureForeachFunc) set_property_foreach, source);

    possible_id = ges_project_try_updating_id (GES_FORMATTER (self)->project,
        source, error);

    if (possible_id == NULL) {
      GST_WARNING_OBJECT (self, "Abandoning creation of asset %s with ID %s"
          "- Error: %s", g_type_name (G_OBJECT_TYPE (source)), id,
          error->message);

      pendings = g_hash_table_lookup (priv->assetid_pendingclips, id);
      for (tmp = pendings; tmp; tmp = tmp->next)
        _free_pending_clip (priv, (PendingClip *) tmp->data);

      _free_pending_asset (priv, passet);
      goto done;
    }

    /* We got a possible ID replacement for that asset, create it, and
     * make sure the assetid_pendingclips will use it */
    ges_asset_request_async (ges_asset_get_extractable_type (source),
        possible_id, NULL, (GAsyncReadyCallback) new_asset_cb, passet);
    ges_project_add_loading_asset (GES_FORMATTER (self)->project,
        ges_asset_get_extractable_type (source), possible_id);

    pendings = g_hash_table_lookup (priv->assetid_pendingclips, id);
    if (pendings) {
      g_hash_table_remove (priv->assetid_pendingclips, id);
      g_hash_table_insert (priv->assetid_pendingclips,
          g_strdup (possible_id), pendings);

      /* pendings should no be freed */
      pendings = NULL;
    }
    goto done;
  }

  /* now that we have the GESAsset, we create the GESClips */
  pendings = g_hash_table_lookup (priv->assetid_pendingclips, id);
  GST_DEBUG_OBJECT (self, "Asset created with ID %s, now creating pending "
      " Clips, nb pendings: %i", id, g_list_length (pendings));
  for (tmp = pendings; tmp; tmp = tmp->next) {
    GList *tmpeffect;
    GESClip *clip;
    PendingClip *pend = (PendingClip *) tmp->data;

    clip =
        _add_object_to_layer (priv, pend->id, pend->layer, asset,
        pend->start, pend->inpoint, pend->duration, pend->track_types,
        pend->metadatas, pend->properties);

    if (clip == NULL)
      continue;

    _add_children_properties (priv, pend->children_props, clip);
    _add_pending_bindings (priv, pend->pending_bindings, clip);

    GST_DEBUG_OBJECT (self, "Adding %i effect to new object",
        g_list_length (pend->effects));
    for (tmpeffect = pend->effects; tmpeffect; tmpeffect = tmpeffect->next) {
      PendingEffects *peffect = (PendingEffects *) tmpeffect->data;

      /* We keep a ref as _free_pending_effect unrefs it */
      _add_track_element (self, clip, gst_object_ref (peffect->trackelement),
          peffect->track_id, peffect->children_properties, peffect->properties);
    }
    _free_pending_clip (priv, pend);
  }

  /* And now add to the project */
  ges_project_add_asset (self->project, asset);
  gst_object_unref (self);

  _free_pending_asset (priv, passet);

done:
  if (asset)
    gst_object_unref (asset);
  if (possible_id)
    g_free (possible_id);

  if (pendings) {
    g_hash_table_remove (priv->assetid_pendingclips, id);
    g_list_free (pendings);
  }

  if (g_hash_table_size (priv->assetid_pendingclips) == 0 &&
      priv->pending_assets == NULL)
    _loading_done (self);
}