static void disconnect_loading_messages(TPMediaPlayer * mp) { USERDATA(mp); CM(ud); if (!ud->load_signal) return; #if (CLUTTER_GST_MAJOR_VERSION<1) GstElement * pipeline=clutter_gst_video_texture_get_playbin(CLUTTER_GST_VIDEO_TEXTURE(cm)); #else GstElement * pipeline=clutter_gst_video_texture_get_pipeline(CLUTTER_GST_VIDEO_TEXTURE(cm)); #endif if (!pipeline) return; GstBus * bus=gst_pipeline_get_bus(GST_PIPELINE(pipeline)); if (!bus) return; g_signal_handler_disconnect(bus,ud->load_signal); ud->load_signal=0; gst_object_unref(GST_OBJECT(bus)); }
static int mp_load(TPMediaPlayer * mp,const char * uri,const char * extra) { USERDATA(mp); CM(ud); clutter_media_set_uri(cm,uri); #if (CLUTTER_GST_MAJOR_VERSION<1) GstElement * pipeline=clutter_gst_video_texture_get_playbin(CLUTTER_GST_VIDEO_TEXTURE(cm)); #else GstElement * pipeline=clutter_gst_video_texture_get_pipeline(CLUTTER_GST_VIDEO_TEXTURE(cm)); #endif if (!pipeline) return 1; GstStateChangeReturn r=gst_element_set_state(pipeline,GST_STATE_PAUSED); g_debug("STATE CHANGE RETURN IS %d",r); switch(r) { case GST_STATE_CHANGE_FAILURE: { return 2; } case GST_STATE_CHANGE_SUCCESS: case GST_STATE_CHANGE_NO_PREROLL: { get_stream_information(mp); tp_media_player_loaded(mp); break; } case GST_STATE_CHANGE_ASYNC: { // The state change happens asynchronously, so we connect a signal // handler to see when it is done GstBus * bus=gst_pipeline_get_bus(GST_PIPELINE(pipeline)); if (!bus) return 3; ud->load_signal=g_signal_connect(bus,"message",G_CALLBACK(loading_messages),mp); gst_object_unref(GST_OBJECT(bus)); break; } } return 0; }
static void mex_get_stream_cb (MexProgram *program, const gchar *url, const GError *error, gpointer user_data) { MexPlayer *player = user_data; MexPlayerPrivate *priv = player->priv; MexGenericContent *generic_content; #ifdef USE_PLAYER_CLUTTER_GST ClutterGstVideoTexture *video_texture; #endif /* if idle mode has been set before the program stream was found */ if (priv->idle_mode) return; if (G_UNLIKELY (error)) { g_warning ("Could not play content: %s (%s)", error->message, url); return; } #ifdef USE_PLAYER_CLUTTER_GST /* We seek at the precise time when the file is local, but we * seek to key frame when streaming */ video_texture = CLUTTER_GST_VIDEO_TEXTURE (priv->media); if (g_str_has_prefix (url, "file://")) { clutter_gst_video_texture_set_seek_flags (video_texture, CLUTTER_GST_SEEK_FLAG_ACCURATE); } else { clutter_gst_video_texture_set_seek_flags (video_texture, CLUTTER_GST_SEEK_FLAG_NONE); } #endif clutter_media_set_uri (CLUTTER_MEDIA (priv->media), url); generic_content = MEX_GENERIC_CONTENT (priv->content); if (mex_generic_content_get_last_position_start (generic_content)) clutter_media_set_progress (CLUTTER_MEDIA (priv->media), priv->position); clutter_media_set_playing (CLUTTER_MEDIA (priv->media), TRUE); }
static void mex_get_stream_cb (MexProgram *program, const gchar *url, const GError *error, gpointer user_data) { MexPlayer *player = user_data; MexPlayerPrivate *priv = player->priv; MexGenericContent *generic_content; #ifdef USE_PLAYER_CLUTTER_GST ClutterGstVideoTexture *video_texture; #endif /* if idle mode has been set before the program stream was found */ if (priv->idle_mode) return; if (G_UNLIKELY (error)) { g_warning ("Could not play content: %s (%s)", error->message, url); return; } #ifdef USE_PLAYER_CLUTTER_GST /* We seek at the precise time when the file is local, but we * seek to key frame when streaming */ video_texture = CLUTTER_GST_VIDEO_TEXTURE (priv->media); if (g_str_has_prefix (url, "file://")) { clutter_gst_video_texture_set_seek_flags (video_texture, CLUTTER_GST_SEEK_FLAG_ACCURATE); } else { clutter_gst_video_texture_set_seek_flags (video_texture, CLUTTER_GST_SEEK_FLAG_NONE); } /* TODO when we have settings we can configure this feature */ if (g_str_has_prefix (mex_content_get_metadata (priv->content, MEX_CONTENT_METADATA_MIMETYPE), "audio/")) { GstElement *gst_element, *visual; gint gst_flags; gst_element = clutter_gst_video_texture_get_pipeline (video_texture); g_object_get (G_OBJECT (gst_element), "flags", &gst_flags, NULL); gst_flags = (GST_PLAY_FLAG_VIS | gst_flags); g_object_set (G_OBJECT (gst_element), "flags", gst_flags, NULL); visual = gst_element_factory_make ("libvisual_infinite", NULL); if (visual) g_object_set (G_OBJECT (gst_element), "vis-plugin", visual, NULL); } #endif clutter_media_set_uri (CLUTTER_MEDIA (priv->media), url); generic_content = MEX_GENERIC_CONTENT (priv->content); if (mex_generic_content_get_last_position_start (generic_content)) clutter_media_set_progress (CLUTTER_MEDIA (priv->media), priv->position); clutter_media_set_playing (CLUTTER_MEDIA (priv->media), TRUE); }
static void mex_player_init (MexPlayer *self) { MexPlayerPrivate *priv; self->priv = priv = PLAYER_PRIVATE (self); #ifdef USE_PLAYER_CLUTTER_GST priv->media = (ClutterMedia *) clutter_gst_video_texture_new (); /* We want to keep a reference to the media here to ensure consistency with * the D-BUS client interface behaviour */ g_object_ref_sink (priv->media); clutter_container_add_actor (CLUTTER_CONTAINER (self), CLUTTER_ACTOR (priv->media)); clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (priv->media), TRUE); clutter_container_child_set (CLUTTER_CONTAINER (self), CLUTTER_ACTOR (priv->media), "fit", TRUE, NULL); /* Use progressive download when possible. Don't enable that yet, the * behaviour of seeking in the non already downloaded part of the stream * is not great. Either disable seeking in that case or find out why.*/ #if 0 video_texture = CLUTTER_GST_VIDEO_TEXTURE (priv->media); clutter_gst_video_texture_set_buffering_mode (video_texture, CLUTTER_GST_BUFFERING_MODE_DOWNLOAD); #endif #else #ifdef USE_PLAYER_DBUS priv->media = (ClutterMedia *) mex_player_client_new (); #else #ifdef USE_PLAYER_SURFACE priv->media = (ClutterMedia *) mex_surface_player_new (); #else #error Unexpected player setup #endif #endif #endif g_signal_connect (priv->media, "eos", G_CALLBACK (media_eos_cb), self); g_signal_connect (priv->media, "notify::playing", G_CALLBACK (media_playing_cb), self); g_signal_connect (priv->media, "notify::progress", G_CALLBACK (media_update_progress), self); #if defined(USE_PLAYER_SURFACE) || defined (USE_PLAYER_CLUTTER_GST) { GError *error = NULL; priv->bridge = mex_media_dbus_bridge_new (priv->media); if (!mex_media_dbus_bridge_register (priv->bridge, &error)) { g_warning (G_STRLOC ": Error registering player on D-BUS"); g_clear_error (&error); } } #endif /* add info panel */ priv->info_panel = mex_info_panel_new (MEX_INFO_PANEL_MODE_FULL); mx_widget_set_disabled (MX_WIDGET (priv->info_panel), TRUE); clutter_container_add_actor (CLUTTER_CONTAINER (self), priv->info_panel); clutter_container_child_set (CLUTTER_CONTAINER (self), priv->info_panel, "y-fill", FALSE, "y-align", MX_ALIGN_END, NULL); clutter_actor_set_opacity (priv->info_panel, 0); /* add media controls */ priv->controls = mex_media_controls_new (); g_signal_connect (priv->controls, "stopped", G_CALLBACK (controls_stopped_cb), self); mex_media_controls_set_media (MEX_MEDIA_CONTROLS (priv->controls), priv->media); clutter_container_add_actor (CLUTTER_CONTAINER (self), priv->controls); clutter_container_child_set (CLUTTER_CONTAINER (self), priv->controls, "y-fill", FALSE, "y-align", MX_ALIGN_END, NULL); priv->screensaver = mex_screensaver_new (); /* start in idle mode */ mex_player_set_idle_mode (MEX_PLAYER (self), TRUE); }
int main (int argc, char *argv[]) { ClutterActor *video; /* So we can fade out at the end. */ clutter_x11_set_use_argb_visual (TRUE); if (clutter_gst_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return EXIT_FAILURE; if (argc < 2) { g_print ("Usage: %s [OPTIONS] <video file>\n", argv[0]); return EXIT_FAILURE; } if (!clutter_color_from_string (&bg_color, BG_COLOR)) { g_warning ("Invalid BG_COLOR"); exit (1); } stage = clutter_stage_new (); /* Clutter's full-screening code does not allow us to * set both that and _NET_WM_STATE_ABOVE, so do the state * management ourselves for now. */ #if 0 clutter_stage_set_fullscreen (CLUTTER_STAGE (stage), TRUE); #endif /* Clutter will set maximum size restrictions (meaning not * full screen) unless I set this. */ clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); clutter_stage_set_use_alpha (CLUTTER_STAGE (stage), TRUE); clutter_actor_set_background_color (stage, &bg_color); clutter_actor_set_layout_manager (stage, clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_FIXED, CLUTTER_BIN_ALIGNMENT_FIXED)); clutter_actor_realize (stage); set_above_and_fullscreen (); video = clutter_gst_video_texture_new (); clutter_actor_set_x_expand (video, TRUE); clutter_actor_set_y_expand (video, TRUE); clutter_actor_set_x_align (video, CLUTTER_ACTOR_ALIGN_CENTER); clutter_actor_set_y_align (video, CLUTTER_ACTOR_ALIGN_CENTER); set_idle_material (CLUTTER_GST_VIDEO_TEXTURE (video)); g_signal_connect (video, "eos", G_CALLBACK (on_video_texture_eos), NULL); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); clutter_media_set_filename (CLUTTER_MEDIA (video), argv[1]); clutter_stage_hide_cursor (CLUTTER_STAGE (stage)); clutter_actor_add_child (stage, video); g_signal_connect (stage, "key-press-event", G_CALLBACK (key_press_cb), NULL); clutter_media_set_playing (CLUTTER_MEDIA (video), TRUE); clutter_actor_show (stage); clutter_main (); return EXIT_SUCCESS; }
static void get_stream_information(TPMediaPlayer * mp) { USERDATA(mp); CM(ud); #if (CLUTTER_GST_MAJOR_VERSION < 1) GstElement * pipeline=clutter_gst_video_texture_get_playbin(CLUTTER_GST_VIDEO_TEXTURE(cm)); #else GstElement *pipeline=clutter_gst_video_texture_get_pipeline(CLUTTER_GST_VIDEO_TEXTURE(cm)); #endif if (!pipeline) return; //......................................................................... // Use stream info to get the type of each stream #if (CLUTTER_GST_MAJOR_VERSION < 1) GValueArray * info_array=NULL; g_object_get(G_OBJECT(pipeline),"stream-info-value-array",&info_array,NULL); if (info_array) { // Each entry in the array is information for a single stream guint i; for (i=0;i<info_array->n_values;++i) { GValue * info_value=g_value_array_get_nth(info_array,i); if (G_VALUE_HOLDS(info_value,G_TYPE_OBJECT)) { GObject * stream_info=g_value_get_object(info_value); if (stream_info) { gint type = -1; g_object_get(stream_info,"type",&type,NULL); switch (type) { case 1: ud->media_type|=TP_MEDIA_TYPE_AUDIO; break; case 2: ud->media_type|=TP_MEDIA_TYPE_VIDEO; break; } #if 0 // This lets you get the enum value associated with the stream type GParamSpec *pspec; GEnumValue *value; pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(stream_info),"type"); value = g_enum_get_value(G_PARAM_SPEC_ENUM(pspec)->enum_class,type); g_debug(" STREAM TYPE IS %d %s",type,value->value_nick); #endif } } } g_value_array_free(info_array); } #else gint n_audio, n_video; g_object_get(G_OBJECT(pipeline), "n-video", &n_video, NULL); g_object_get(G_OBJECT(pipeline), "n-audio", &n_audio, NULL); if(n_video) ud->media_type|=TP_MEDIA_TYPE_VIDEO; if(n_audio) ud->media_type|=TP_MEDIA_TYPE_AUDIO; #endif //......................................................................... // If there is a video stream, we get the video sink and try to find the // video size if (ud->media_type&TP_MEDIA_TYPE_VIDEO) { GstElement * video_sink=NULL; g_object_get(G_OBJECT(pipeline),"video-sink",&video_sink,NULL); if (video_sink) { GstPad * pad=gst_element_get_static_pad(video_sink,"sink"); if (pad) { // Get its video width and height gint width; gint height; if (gst_video_get_size(pad,&width,&height)) { ud->video_width=width; ud->video_height=height; } gst_object_unref(GST_OBJECT(pad)); } gst_object_unref(GST_OBJECT(video_sink)); } } #if 1 if ( ud->media_type & TP_MEDIA_TYPE_AUDIO ) { GstElement * audio_sink= gst_element_factory_make( "autoaudiosink", "TPAudioSink" ); if(!audio_sink) { g_debug("Failed to create autoaudiosink"); } else { g_object_set(G_OBJECT(pipeline),"audio-sink",audio_sink,NULL); } } #endif }
static gboolean _start_video_preview (MexContentTile *self) { MexContentTilePrivate *priv = self->priv; GstElement *pipeline; gint gst_flags; const gchar *mimetype, *uri; /* Check we're still focused */ if (!mex_actor_has_focus (CLUTTER_ACTOR (self))) return FALSE; /* Don't play if the main player is still playing.. * too many videos spoil the broth. */ if (clutter_media_get_playing (mex_player_get_clutter_media (mex_player_get_default ()))) return FALSE; mimetype = mex_content_get_metadata (priv->content, MEX_CONTENT_METADATA_MIMETYPE); if ((mimetype) && strncmp (mimetype, "video/", 6) != 0) return FALSE; if (!(uri = mex_content_get_metadata (priv->content, MEX_CONTENT_METADATA_STREAM))) return FALSE; priv->video_preview = clutter_gst_video_texture_new (); pipeline = clutter_gst_video_texture_get_pipeline (CLUTTER_GST_VIDEO_TEXTURE (priv->video_preview)); g_object_get (G_OBJECT (pipeline), "flags", &gst_flags, NULL); gst_flags = 1;//GST_PLAY_FLAG_VIDEO; g_object_set (G_OBJECT (pipeline), "flags", gst_flags, NULL); clutter_gst_video_texture_set_idle_material (CLUTTER_GST_VIDEO_TEXTURE (priv->video_preview), NULL); g_signal_connect (priv->video_preview, "eos", G_CALLBACK (_stop_video_eos), self); clutter_actor_set_opacity (priv->video_preview, 0); g_object_ref (priv->image); clutter_actor_remove_child (CLUTTER_ACTOR (self), priv->image); clutter_actor_add_child (CLUTTER_ACTOR (self), priv->video_preview); clutter_actor_animate (priv->video_preview, CLUTTER_LINEAR, 500, "opacity", 0xff, NULL); clutter_actor_set_size (priv->video_preview, (gfloat)priv->thumb_width, (gfloat)priv->thumb_height); clutter_media_set_uri (CLUTTER_MEDIA (priv->video_preview), uri); clutter_media_set_playing (CLUTTER_MEDIA (priv->video_preview), TRUE); if (priv->stop_video_preview <= 0) priv->stop_video_preview = g_timeout_add_seconds (180, (GSourceFunc)_stop_video_preview, self); return FALSE; }