gchar * ges_project_try_updating_id (GESProject * project, GESAsset * asset, GError * error) { gchar *new_id = NULL; g_return_val_if_fail (GES_IS_PROJECT (project), NULL); g_return_val_if_fail (GES_IS_ASSET (asset), NULL); g_return_val_if_fail (error, NULL); GST_DEBUG_OBJECT (project, "Try to proxy %s", ges_asset_get_id (asset)); if (ges_asset_request_id_update (asset, &new_id, error) == FALSE) { GST_DEBUG_OBJECT (project, "Type: %s can not be proxied for id: %s", g_type_name (G_OBJECT_TYPE (asset)), ges_asset_get_id (asset)); return NULL; } if (new_id == NULL) g_signal_emit (project, _signals[MISSING_URI_SIGNAL], 0, error, asset, &new_id); if (new_id) { if (!ges_asset_set_proxy (asset, new_id)) { g_free (new_id); new_id = NULL; } } g_hash_table_remove (project->priv->loading_assets, ges_asset_get_id (asset)); return new_id; }
static inline GESClip * _add_object_to_layer (GESBaseXmlFormatterPrivate * priv, const gchar * id, GESLayer * layer, GESAsset * asset, GstClockTime start, GstClockTime inpoint, GstClockTime duration, GESTrackType track_types, const gchar * metadatas, GstStructure * properties) { GESClip *clip = ges_layer_add_asset (layer, asset, start, inpoint, duration, track_types); if (clip == NULL) { GST_WARNING_OBJECT (clip, "Could not add object from asset: %s", ges_asset_get_id (asset)); return NULL; } if (metadatas) ges_meta_container_add_metas_from_string (GES_META_CONTAINER (clip), metadatas); if (properties) gst_structure_foreach (properties, (GstStructureForeachFunc) set_property_foreach, clip); g_hash_table_insert (priv->containers, g_strdup (id), gst_object_ref (clip)); return clip; }
static void new_asset_cb (GESAsset * source, GAsyncResult * res, GESProject * project) { GError *error = NULL; gchar *possible_id = NULL; const gchar *id = ges_asset_get_id (source); GESAsset *asset = ges_asset_request_finish (res, &error); if (error) { possible_id = ges_project_try_updating_id (project, source, error); if (possible_id == NULL) { g_hash_table_remove (project->priv->loading_assets, id); g_hash_table_add (project->priv->loaded_with_error, g_strdup (id)); g_signal_emit (project, _signals[ERROR_LOADING_ASSET], 0, error, id, ges_asset_get_extractable_type (source)); return; } ges_project_create_asset (project, possible_id, ges_asset_get_extractable_type (source)); g_free (possible_id); g_error_free (error); return; } ges_project_add_asset (project, asset); if (asset) gst_object_unref (asset); }
static void extractable_set_asset (GESExtractable * self, GESAsset * asset) { GEnumClass *enum_class; GESVideoStandardTransitionType value; GESTransitionClip *trans = GES_TRANSITION_CLIP (self); const gchar *vtype = ges_asset_get_id (asset); /* Update the transition type if we actually changed it */ if (g_strcmp0 (vtype, trans->priv->vtype_name)) { guint index; value = GES_VIDEO_STANDARD_TRANSITION_TYPE_CROSSFADE; enum_class = g_type_class_peek (GES_VIDEO_STANDARD_TRANSITION_TYPE_TYPE); /* Find the in value in use */ for (index = 0; index < enum_class->n_values; index++) { if (g_strcmp0 (enum_class->values[index].value_nick, vtype) == 0) { value = enum_class->values[index].value; break; } } ges_transition_clip_update_vtype_internal (GES_CLIP (self), value, FALSE); } }
/** * ges_project_add_asset: * @project: A #GESProject * @asset: (transfer none): A #GESAsset to add to @project * * Adds a #Asset to @project, the project will keep a reference on * @asset. * * Returns: %TRUE if the asset could be added %FALSE it was already * in the project */ gboolean ges_project_add_asset (GESProject * project, GESAsset * asset) { g_return_val_if_fail (GES_IS_PROJECT (project), FALSE); if (g_hash_table_lookup (project->priv->assets, ges_asset_get_id (asset))) return FALSE; g_hash_table_insert (project->priv->assets, g_strdup (ges_asset_get_id (asset)), gst_object_ref (asset)); g_hash_table_remove (project->priv->loading_assets, ges_asset_get_id (asset)); GST_DEBUG_OBJECT (project, "Asset added: %s", ges_asset_get_id (asset)); g_signal_emit (project, _signals[ASSET_ADDED_SIGNAL], 0, asset); return TRUE; }
static void _send_error_loading_asset (GESProject * project, GESAsset * asset, GError * error) { const gchar *id = ges_asset_get_id (asset); GST_DEBUG_OBJECT (project, "Sending error loading asset for %s", id); g_hash_table_remove (project->priv->loading_assets, id); g_hash_table_add (project->priv->loaded_with_error, g_strdup (id)); g_signal_emit (project, _signals[ERROR_LOADING_ASSET], 0, error, id, ges_asset_get_extractable_type (asset)); }
static gboolean _load_project (GESProject * project, GESTimeline * timeline, GError ** error) { GError *lerr = NULL; GESProjectPrivate *priv; GESFormatter *formatter; priv = GES_PROJECT (project)->priv; if (priv->uri == NULL) { EmitLoadedInIdle *data = g_slice_new (EmitLoadedInIdle); GST_LOG_OBJECT (project, "%s, Loading an empty timeline %s" " as no URI set yet", GST_OBJECT_NAME (timeline), ges_asset_get_id (GES_ASSET (project))); data->timeline = gst_object_ref (timeline); data->project = gst_object_ref (project); /* Make sure the signal is emitted after the functions ends */ g_idle_add ((GSourceFunc) _emit_loaded_in_idle, data); return TRUE; } if (priv->formatter_asset == NULL) priv->formatter_asset = _find_formatter_asset_for_uri (priv->uri); if (priv->formatter_asset == NULL) goto failed; formatter = GES_FORMATTER (ges_asset_extract (priv->formatter_asset, &lerr)); if (lerr) { GST_WARNING_OBJECT (project, "Could not create the formatter: %s", (*error)->message); goto failed; } ges_project_add_formatter (GES_PROJECT (project), formatter); ges_formatter_load_from_uri (formatter, timeline, priv->uri, &lerr); if (lerr) { GST_WARNING_OBJECT (project, "Could not load the timeline," " returning: %s", lerr->message); goto failed; } return TRUE; failed: if (lerr) g_propagate_error (error, lerr); return FALSE; }
/** * ges_project_remove_asset: * @project: A #GESProject * @asset: (transfer none): A #GESAsset to remove from @project * * remove a @asset to from @project. * * Returns: %TRUE if the asset could be removed %FALSE otherwise */ gboolean ges_project_remove_asset (GESProject * project, GESAsset * asset) { gboolean ret; g_return_val_if_fail (GES_IS_PROJECT (project), FALSE); ret = g_hash_table_remove (project->priv->assets, ges_asset_get_id (asset)); g_signal_emit (project, _signals[ASSET_REMOVED_SIGNAL], 0, asset); return ret; }
static void _fill_track_type (GESAsset * asset) { GESTrackType ttype; gchar *bin_desc; const gchar *id = ges_asset_get_id (asset); bin_desc = ges_effect_assect_id_get_type_and_bindesc (id, &ttype, NULL); if (bin_desc) { ges_track_element_asset_set_track_type (GES_TRACK_ELEMENT_ASSET (asset), ttype); } else { GST_WARNING_OBJECT (asset, "No track type set, you should" " specify one in [audio, video] as first component" " in the asset id"); } }
gchar * ges_project_try_updating_id (GESProject * project, GESAsset * asset, GError * error) { gchar *new_id = NULL; const gchar *id; g_return_val_if_fail (GES_IS_PROJECT (project), NULL); g_return_val_if_fail (GES_IS_ASSET (asset), NULL); g_return_val_if_fail (error, NULL); id = ges_asset_get_id (asset); GST_DEBUG_OBJECT (project, "Try to proxy %s", id); if (ges_asset_request_id_update (asset, &new_id, error) == FALSE) { GST_DEBUG_OBJECT (project, "Type: %s can not be proxied for id: %s " "and error: %s", g_type_name (G_OBJECT_TYPE (asset)), id, error->message); _send_error_loading_asset (project, asset, error); return NULL; } if (new_id == NULL) { GST_DEBUG_OBJECT (project, "Sending 'missing-uri' signal for %s", id); g_signal_emit (project, _signals[MISSING_URI_SIGNAL], 0, error, asset, &new_id); } if (new_id) { GST_DEBUG_OBJECT (project, "new id found: %s", new_id); if (!ges_asset_set_proxy (asset, new_id)) { g_free (new_id); new_id = NULL; } } else { GST_DEBUG_OBJECT (project, "No new id found for %s", id); } g_hash_table_remove (project->priv->loading_assets, id); if (new_id == NULL) _send_error_loading_asset (project, asset, error); return new_id; }
static void asset_created_cb (GObject * source, GAsyncResult * res, gpointer udata) { GList *tracks, *tmp; GESAsset *asset; GESLayer *layer; GESUriClip *tlfs; GError *error = NULL; asset = ges_asset_request_finish (res, &error); ASSERT_OBJECT_REFCOUNT (asset, "1 for us + for the cache + 1 taken " "by g_simple_async_result_complete_in_idle", 3); fail_unless (error == NULL); fail_if (asset == NULL); fail_if (g_strcmp0 (ges_asset_get_id (asset), av_uri)); layer = GES_LAYER (g_async_result_get_user_data (res)); tlfs = GES_URI_CLIP (ges_layer_add_asset (layer, asset, 0, 0, GST_CLOCK_TIME_NONE, GES_TRACK_TYPE_UNKNOWN)); fail_unless (GES_IS_URI_CLIP (tlfs)); fail_if (g_strcmp0 (ges_uri_clip_get_uri (tlfs), av_uri)); assert_equals_uint64 (_DURATION (tlfs), GST_SECOND); fail_unless (ges_clip_get_supported_formats (GES_CLIP (tlfs)) & GES_TRACK_TYPE_VIDEO); fail_unless (ges_clip_get_supported_formats (GES_CLIP (tlfs)) & GES_TRACK_TYPE_AUDIO); tracks = ges_timeline_get_tracks (ges_layer_get_timeline (layer)); for (tmp = tracks; tmp; tmp = tmp->next) { GList *trackelements = ges_track_get_elements (GES_TRACK (tmp->data)); assert_equals_int (g_list_length (trackelements), 1); fail_unless (GES_IS_VIDEO_URI_SOURCE (trackelements->data) || GES_IS_AUDIO_URI_SOURCE (trackelements->data)); g_list_free_full (trackelements, gst_object_unref); } g_list_free_full (tracks, gst_object_unref); gst_object_unref (asset); g_main_loop_quit (mainloop); }
static void new_asset_cb (GESAsset * source, GAsyncResult * res, NewAssetUData * udata) { GError *error = NULL; GESAsset *asset = ges_asset_request_finish (res, &error); GST_DEBUG_OBJECT (udata->layer, "%" GST_PTR_FORMAT " Asset loaded, " "setting its asset", udata->clip); if (error) { GESProject *project = udata->layer->timeline ? GES_PROJECT (ges_extractable_get_asset (GES_EXTRACTABLE (udata->layer->timeline))) : NULL; if (project) { gchar *possible_id; possible_id = ges_project_try_updating_id (project, source, error); if (possible_id) { ges_asset_request_async (ges_asset_get_extractable_type (source), possible_id, NULL, (GAsyncReadyCallback) new_asset_cb, udata); g_free (possible_id); return; } } GST_ERROR ("Asset could not be created for uri %s, error: %s", ges_asset_get_id (asset), error->message); } else { GESProject *project = udata->layer->timeline ? GES_PROJECT (ges_extractable_get_asset (GES_EXTRACTABLE (udata->layer->timeline))) : NULL; ges_extractable_set_asset (GES_EXTRACTABLE (udata->clip), asset); ges_project_add_asset (project, asset); ges_layer_add_clip (udata->layer, udata->clip); } gst_object_unref (asset); g_slice_free (NewAssetUData, udata); }
void ges_asset_cache_put (GESAsset * asset, GSimpleAsyncResult * res) { GType extractable_type; const gchar *asset_id; GESAssetCacheEntry *entry; /* Needing to work with the cache, taking the lock */ asset_id = ges_asset_get_id (asset); extractable_type = asset->priv->extractable_type; LOCK_CACHE; if (!(entry = _lookup_entry (extractable_type, asset_id))) { GHashTable *entries_table; entries_table = g_hash_table_lookup (type_entries_table, _extractable_type_name (extractable_type)); if (entries_table == NULL) { entries_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, _free_entries); g_hash_table_insert (type_entries_table, g_strdup (_extractable_type_name (extractable_type)), entries_table); } entry = g_slice_new0 (GESAssetCacheEntry); entry->asset = asset; if (res) entry->results = g_list_prepend (entry->results, res); g_hash_table_insert (entries_table, (gpointer) g_strdup (asset_id), (gpointer) entry); } else { if (res) { GST_DEBUG ("%s already in cache, adding result %p", asset_id, res); entry->results = g_list_prepend (entry->results, res); } } UNLOCK_CACHE; }
/** * ges_layer_add_asset: * @layer: a #GESLayer * @asset: The asset to add to * @start: The start value to set on the new #GESClip * @inpoint: The inpoint value to set on the new #GESClip * @duration: The duration value to set on the new #GESClip * @track_types: The #GESTrackType to set on the the new #GESClip * * Creates Clip from asset, adds it to layer and * returns a reference to it. * * Returns: (transfer none): Created #GESClip */ GESClip * ges_layer_add_asset (GESLayer * layer, GESAsset * asset, GstClockTime start, GstClockTime inpoint, GstClockTime duration, GESTrackType track_types) { GESClip *clip; g_return_val_if_fail (GES_IS_LAYER (layer), NULL); g_return_val_if_fail (GES_IS_ASSET (asset), NULL); g_return_val_if_fail (g_type_is_a (ges_asset_get_extractable_type (asset), GES_TYPE_CLIP), NULL); GST_DEBUG_OBJECT (layer, "Adding asset %s with: start: %" GST_TIME_FORMAT " inpoint: %" GST_TIME_FORMAT " duration: %" GST_TIME_FORMAT " track types: %d (%s)", ges_asset_get_id (asset), GST_TIME_ARGS (start), GST_TIME_ARGS (inpoint), GST_TIME_ARGS (duration), track_types, ges_track_type_name (track_types)); clip = GES_CLIP (ges_asset_extract (asset, NULL)); _set_start0 (GES_TIMELINE_ELEMENT (clip), start); _set_inpoint0 (GES_TIMELINE_ELEMENT (clip), inpoint); if (track_types != GES_TRACK_TYPE_UNKNOWN) ges_clip_set_supported_formats (clip, track_types); if (GST_CLOCK_TIME_IS_VALID (duration)) { _set_duration0 (GES_TIMELINE_ELEMENT (clip), duration); } if (!ges_layer_add_clip (layer, clip)) { gst_object_unref (clip); return NULL; } return clip; }
static gboolean extractable_set_asset (GESExtractable * self, GESAsset * asset) { gboolean res = TRUE; GESUriClip *uriclip = GES_URI_CLIP (self); GESUriClipAsset *uri_clip_asset; GESClip *clip = GES_CLIP (self); GESLayer *layer = ges_clip_get_layer (clip); GList *tmp; GESTimelineElement *audio_source = NULL, *video_source = NULL; g_return_val_if_fail (GES_IS_URI_CLIP_ASSET (asset), FALSE); uri_clip_asset = GES_URI_CLIP_ASSET (asset); if (GST_CLOCK_TIME_IS_VALID (GES_TIMELINE_ELEMENT_DURATION (clip)) == FALSE) _set_duration0 (GES_TIMELINE_ELEMENT (uriclip), ges_uri_clip_asset_get_duration (uri_clip_asset)); ges_timeline_element_set_max_duration (GES_TIMELINE_ELEMENT (uriclip), ges_uri_clip_asset_get_duration (uri_clip_asset)); ges_uri_clip_set_is_image (uriclip, ges_uri_clip_asset_is_image (uri_clip_asset)); if (ges_clip_get_supported_formats (clip) == GES_TRACK_TYPE_UNKNOWN) { ges_clip_set_supported_formats (clip, ges_clip_asset_get_supported_formats (GES_CLIP_ASSET (uri_clip_asset))); } GES_TIMELINE_ELEMENT (uriclip)->asset = asset; if (layer) { GList *children = ges_container_get_children (GES_CONTAINER (self), TRUE); for (tmp = children; tmp; tmp = tmp->next) { if (GES_IS_SOURCE (tmp->data)) { GESTrack *track = ges_track_element_get_track (tmp->data); if (track->type == GES_TRACK_TYPE_AUDIO) audio_source = gst_object_ref (tmp->data); else if (track->type == GES_TRACK_TYPE_VIDEO) video_source = gst_object_ref (tmp->data); ges_track_remove_element (track, tmp->data); ges_container_remove (GES_CONTAINER (self), tmp->data); } } g_list_free_full (children, g_object_unref); gst_object_ref (clip); ges_layer_remove_clip (layer, clip); res = ges_layer_add_clip (layer, clip); for (tmp = GES_CONTAINER_CHILDREN (self); tmp; tmp = tmp->next) { if (GES_IS_SOURCE (tmp->data)) { GESTrack *track = ges_track_element_get_track (tmp->data); if (track->type == GES_TRACK_TYPE_AUDIO && audio_source) ges_track_element_copy_properties (audio_source, tmp->data); else if (track->type == GES_TRACK_TYPE_VIDEO && video_source) ges_track_element_copy_properties (video_source, tmp->data); } } g_clear_object (&audio_source); g_clear_object (&video_source); gst_object_unref (clip); gst_object_unref (layer); } if (res) { g_free (uriclip->priv->uri); uriclip->priv->uri = g_strdup (ges_asset_get_id (asset)); } return res; }
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); }
/** * ges_project_save: * @project: A #GESProject to save * @timeline: The #GESTimeline to save, it must have been extracted from @project * @uri: The uri where to save @project and @timeline * @formatter_asset: (allow-none): The formatter asset to use or %NULL. If %NULL, * will try to save in the same format as the one from which the timeline as been loaded * or default to the formatter with highest rank * @overwrite: %TRUE to overwrite file if it exists * @error: (out) (allow-none): An error to be set in case something wrong happens or %NULL * * Save the timeline of @project to @uri. You should make sure that @timeline * is one of the timelines that have been extracted from @project * (using ges_asset_extract (@project);) * * Returns: %TRUE if the project could be save, %FALSE otherwize */ gboolean ges_project_save (GESProject * project, GESTimeline * timeline, const gchar * uri, GESAsset * formatter_asset, gboolean overwrite, GError ** error) { GESAsset *tl_asset; gboolean ret = TRUE; GESFormatter *formatter = NULL; g_return_val_if_fail (GES_IS_PROJECT (project), FALSE); g_return_val_if_fail (formatter_asset == NULL || g_type_is_a (ges_asset_get_extractable_type (formatter_asset), GES_TYPE_FORMATTER), FALSE); g_return_val_if_fail ((error == NULL || *error == NULL), FALSE); tl_asset = ges_extractable_get_asset (GES_EXTRACTABLE (timeline)); if (tl_asset == NULL && project->priv->uri == NULL) { GESAsset *asset = ges_asset_cache_lookup (GES_TYPE_PROJECT, uri); if (asset) { GST_WARNING_OBJECT (project, "Trying to save project to %s but we already" "have %" GST_PTR_FORMAT " for that uri, can not save", uri, asset); goto out; } GST_DEBUG_OBJECT (project, "Timeline %" GST_PTR_FORMAT " has no asset" " we have no uri set, so setting ourself as asset", timeline); ges_extractable_set_asset (GES_EXTRACTABLE (timeline), GES_ASSET (project)); } else if (tl_asset != GES_ASSET (project)) { GST_WARNING_OBJECT (project, "Timeline %" GST_PTR_FORMAT " not created by this project can not save", timeline); ret = FALSE; goto out; } if (formatter_asset == NULL) formatter_asset = gst_object_ref (ges_formatter_get_default ()); formatter = GES_FORMATTER (ges_asset_extract (formatter_asset, error)); if (formatter == NULL) { GST_WARNING_OBJECT (project, "Could not create the formatter %p %s: %s", formatter_asset, ges_asset_get_id (formatter_asset), (error && *error) ? (*error)->message : "Unknown Error"); ret = FALSE; goto out; } ges_project_add_formatter (project, formatter); ret = ges_formatter_save_to_uri (formatter, timeline, uri, overwrite, error); if (ret && project->priv->uri == NULL) ges_project_set_uri (project, uri); out: if (formatter_asset) gst_object_unref (formatter_asset); ges_project_remove_formatter (project, formatter); return ret; }