diff -r d2d226b5a4bd -r 987fafbda04d maemo-ui-old/src/mmyth_tvplayer.c --- a/maemo-ui-old/src/mmyth_tvplayer.c Fri Feb 01 14:30:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,712 +0,0 @@ -/** - * GMyth Library - * - * @file gmyth/mmyth_tvplayer.c - * - * @brief

This component provides playback of the remote A/V using - * GStreamer. - * - * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. - * @author Hallyson Luiz de Morais Melo - * - *//* - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "mmyth_tvplayer.h" - -#include - -#include - -#define MYTHTV_VERSION_DEFAULT 30 - -typedef struct _GstPlayerWindowStateChange { - GstElement *play; - GstState old_state, - new_state; - MMythTVPlayer *tvplayer; -} GstPlayerWindowStateChange; - -typedef struct _GstPlayerWindowTagFound { - GstElement *play; - GstTagList *taglist; - MMythTVPlayer *tvplayer; -} GstPlayerWindowTagFound; - -/* - * static gboolean idle_state (gpointer data); - */ -static gboolean bus_call(GstBus * bus, GstMessage * msg, gpointer data); - -static void mmyth_tvplayer_class_init(MMythTVPlayerClass * klass); -static void mmyth_tvplayer_init(MMythTVPlayer * object); - -static void mmyth_tvplayer_dispose(GObject * object); -static void mmyth_tvplayer_finalize(GObject * object); - -G_DEFINE_TYPE(MMythTVPlayer, mmyth_tvplayer, G_TYPE_OBJECT) - - static gboolean mmyth_tvplayer_create_pipeline(MMythTVPlayer * - tvplayer); - static void new_pad_cb(GstElement * element, GstPad * pad, - gpointer data); - - static gboolean expose_cb(GtkWidget * widget, - GdkEventExpose * event, gpointer user_data); - - static void - mmyth_tvplayer_class_init(MMythTVPlayerClass * klass) -{ - GObjectClass *gobject_class; - - gobject_class = (GObjectClass *) klass; - - gobject_class->dispose = mmyth_tvplayer_dispose; - gobject_class->finalize = mmyth_tvplayer_finalize; -} - -static void -new_pad_cb(GstElement * element, GstPad * pad, gpointer data) -{ - MMythTVPlayer *tvplayer = MMYTH_TVPLAYER(data); - GstPadLinkReturn ret; - char *s; - - s = gst_caps_to_string(pad->caps); - - if (s[0] == 'a') { - ret = - gst_pad_link(pad, - gst_element_get_pad(tvplayer->audioqueue1, - "sink")); - } else { - ret = - gst_pad_link(pad, - gst_element_get_pad(tvplayer->videoqueue1, - "sink")); - } - - g_free(s); -} - -static gboolean -expose_cb(GtkWidget * widget, GdkEventExpose * event, gpointer user_data) -{ - MMythTVPlayer *tvplayer = MMYTH_TVPLAYER(user_data); - - if (tvplayer && tvplayer->videow) { - gst_x_overlay_set_xwindow_id(GST_X_OVERLAY - (tvplayer->gst_videosink), - GDK_WINDOW_XWINDOW(widget->window)); - return TRUE; - } - - g_warning("MMythTVPlayer expose called before setting video window\n"); - - return FALSE; -} - -static void -mmyth_tvplayer_init(MMythTVPlayer * tvplayer) -{ - tvplayer->gst_pipeline = NULL; - tvplayer->gst_source = NULL; - tvplayer->gst_videodec = NULL; - tvplayer->gst_videosink = NULL; - tvplayer->gst_videocolortrs = NULL; - tvplayer->videoqueue1 = NULL; - tvplayer->videoqueue2 = NULL; - tvplayer->audioqueue1 = NULL; - tvplayer->audioqueue2 = NULL; - - /* - * GTKWidget for rendering the video - */ - tvplayer->videow = NULL; - tvplayer->expose_handler = 0; - - tvplayer->backend_hostname = NULL; - tvplayer->backend_port = 0; - tvplayer->local_hostname = NULL; - - tvplayer->recorder = NULL; - tvplayer->tvchain = NULL; - tvplayer->proginfo = NULL; -} - -static void -mmyth_tvplayer_dispose(GObject * object) -{ - - G_OBJECT_CLASS(mmyth_tvplayer_parent_class)->dispose(object); -} - -static void -mmyth_tvplayer_finalize(GObject * object) -{ - g_signal_handlers_destroy(object); - - MMythTVPlayer *tvplayer = MMYTH_TVPLAYER(object); - - g_debug("[%s] Finalizing tvplayer", __FUNCTION__); - - if (tvplayer->videow != NULL) { - if (g_signal_handler_is_connected(tvplayer->videow, - tvplayer->expose_handler)) { - g_signal_handler_disconnect(tvplayer->videow, - tvplayer->expose_handler); - } - g_object_unref(tvplayer->videow); - } - - if (tvplayer->recorder != NULL) - g_object_unref(tvplayer->recorder); - if (tvplayer->tvchain != NULL) - g_object_unref(tvplayer->tvchain); - if (tvplayer->proginfo != NULL) - g_object_unref(tvplayer->proginfo); - - // Release Gstreamer elements - if (tvplayer->gst_pipeline != NULL) - g_object_unref(tvplayer->gst_pipeline); - if (tvplayer->gst_source != NULL) - g_object_unref(tvplayer->gst_source); - if (tvplayer->gst_videodec != NULL) - g_object_unref(tvplayer->gst_videodec); - if (tvplayer->gst_videocolortrs != NULL) - g_object_unref(tvplayer->gst_videocolortrs); - if (tvplayer->gst_videosink != NULL) - g_object_unref(tvplayer->gst_videosink); - if (tvplayer->videoqueue1 != NULL) - g_object_unref(tvplayer->videoqueue1); - if (tvplayer->videoqueue2 != NULL) - g_object_unref(tvplayer->videoqueue2); - if (tvplayer->audioqueue1 != NULL) - g_object_unref(tvplayer->audioqueue1); - if (tvplayer->audioqueue2 != NULL) - g_object_unref(tvplayer->audioqueue2); - - G_OBJECT_CLASS(mmyth_tvplayer_parent_class)->finalize(object); -} - -/** Creates a new instance of MMythTVPlayer. - * - * @return a new instance of MMythTVPlayer. - */ -MMythTVPlayer * -mmyth_tvplayer_new() -{ - MMythTVPlayer *tvplayer = - MMYTH_TVPLAYER(g_object_new(MMYTH_TVPLAYER_TYPE, NULL)); - - return tvplayer; -} - -/** Initializes the tv player. - * - * @param tvplayer the object instance. - * @return gboolean TRUE if the pipeline was created - * successfully, FALSE otherwise. - */ -gboolean -mmyth_tvplayer_initialize(MMythTVPlayer * tvplayer, - GMythBackendInfo * backend_info) -{ - tvplayer->backend_info = backend_info; - - if (!mmyth_tvplayer_create_pipeline(tvplayer)) { - g_warning - ("[%s] Error while creating pipeline. TV Player not initialized", - __FUNCTION__); - return FALSE; - } else { - g_debug("[%s] GStreamer pipeline created", __FUNCTION__); - } - - return TRUE; -} - -/** Creates the GStreamer pipeline used by the player. - * - * @param tvplayer the object instance. - * @return gboolean TRUE if the pipeline was created - * successfully, FALSE otherwise. - */ -static gboolean -mmyth_tvplayer_create_pipeline(MMythTVPlayer * tvplayer) -{ - GstElement *pipeline; - GstElement *source, - *parser; - GstElement *videodec, - *videosink; - GstElement *videocolortrs; -#ifndef MAEMO_PLATFORM - GstElement *audiodec, - *audioconv, - *audioqueue2; -#endif - GstElement *audiosink; - GstElement *videoqueue1, - *videoqueue2, - *audioqueue1; - - g_debug("MMythTVPlayer: Setting the Gstreamer pipeline\n"); - - pipeline = gst_pipeline_new("video-player"); - source = gst_element_factory_make("mythtvsrc", "myth-source"); - parser = gst_element_factory_make("nuvdemux", "nuv-demux"); - - /* - * Gstreamer Video elements - */ - videoqueue1 = gst_element_factory_make("queue", "video-queue1"); - videodec = gst_element_factory_make("ffdec_mpeg4", "video-decoder"); - videoqueue2 = gst_element_factory_make("queue", "video-queue2"); - videocolortrs = - gst_element_factory_make("ffmpegcolorspace", - "image-color-transforms"); - -#ifdef MAEMO_PLATFORM - videosink = gst_element_factory_make("sdlvideosink", "image-output"); -#else - videosink = gst_element_factory_make("xvimagesink", "image-output"); -#endif - - /* - * Gstreamer Audio elements - */ - audioqueue1 = gst_element_factory_make("queue", "audio-queue1"); -#ifdef MAEMO_PLATFORM - audiosink = gst_element_factory_make("dspmp3sink", "audio-output"); -#else - audioqueue2 = gst_element_factory_make("queue", "audio-queue2"); - audiodec = gst_element_factory_make("mad", "audio-decoder"); - audioconv = - gst_element_factory_make("audioconvert", "audio-converter"); - audiosink = gst_element_factory_make("alsasink", "audio-output"); -#endif - - if (!(pipeline && source && parser && videodec && videosink) || - !(videoqueue1 && videoqueue2 && audioqueue1 && audiosink)) { - /* - * FIXME: hanlde the error correctly - */ - /* - * video_alignment is not being created (below) and is causing - * problems to the ui - */ - - tvplayer->gst_pipeline = NULL; - tvplayer->gst_videodec = NULL; - tvplayer->gst_videosink = NULL; - tvplayer->gst_videocolortrs = NULL; - - g_warning("GstElement creation error!\n"); - return FALSE; - } -#ifndef MAEMO_PLATFORM - if (!(audiodec && audioconv)) { - g_warning("GstElement for audio stream creation error!"); - return FALSE; - } -#endif - - tvplayer->gst_pipeline = pipeline; - tvplayer->gst_source = source; - tvplayer->gst_videodec = videodec; - tvplayer->gst_videosink = videosink; - tvplayer->gst_videocolortrs = videocolortrs; - g_object_ref(tvplayer->gst_pipeline); - g_object_ref(tvplayer->gst_source); - g_object_ref(tvplayer->gst_videodec); - g_object_ref(tvplayer->gst_videosink); - g_object_ref(tvplayer->gst_videocolortrs); - - tvplayer->videoqueue1 = videoqueue1; - tvplayer->videoqueue2 = videoqueue2; - tvplayer->audioqueue1 = audioqueue1; - g_object_ref(tvplayer->videoqueue1); - g_object_ref(tvplayer->videoqueue2); - g_object_ref(tvplayer->audioqueue1); - -#ifndef MAEMO_PLATFORM - tvplayer->audioqueue2 = audioqueue2; - g_object_ref(tvplayer->audioqueue2); -#endif - - // g_object_set (G_OBJECT (videosink), "sync", TRUE, NULL); - g_object_set(G_OBJECT(audiosink), "sync", FALSE, NULL); - - gst_bus_add_watch(gst_pipeline_get_bus - (GST_PIPELINE(tvplayer->gst_pipeline)), bus_call, - tvplayer); - - gst_bin_add_many(GST_BIN(pipeline), source, parser, videoqueue1, - videodec, videoqueue2, videocolortrs, videosink, - NULL); - -#ifndef MAEMO_PLATFORM - gst_bin_add_many(GST_BIN(pipeline), audioqueue1, audiodec, audioconv, - audioqueue2, audiosink, NULL); -#else - gst_bin_add_many(GST_BIN(pipeline), audioqueue1, audiosink, NULL); -#endif - - { - // GstCaps *rtpcaps = gst_caps_new_simple ("application/x-rtp", - // NULL); - // gst_element_link_filtered(source, parser, rtpcaps); - } - - gst_element_link(source, parser); - gst_element_link_many(videoqueue1, videodec, videoqueue2, - videocolortrs, videosink, NULL); - -#ifndef MAEMO_PLATFORM - gst_element_link_many(videosink, audioqueue1, audiodec, audioconv, - audioqueue2, audiosink, NULL); -#else - gst_element_link_many(videosink, audioqueue1, audiosink, NULL); -#endif - - g_signal_connect(parser, "pad-added", G_CALLBACK(new_pad_cb), - tvplayer); - - return TRUE; -} - -/** Configures the backend and the tv player - * for playing the recorded content A/V. - * - * FIXME: Change filename to program info or other structure about the recorded - * - * @param tvplayer the object instance. - * @param filename the file uri of the recorded content to be played. - * @return TRUE if successfull, FALSE if any error happens. - */ -gboolean -mmyth_tvplayer_record_setup(MMythTVPlayer * tvplayer, - const gchar * filename) -{ - // FIXME: we should receive the uri instead of filename - const gchar *hostname = - gmyth_backend_info_get_hostname(tvplayer->backend_info); - const gint port = - gmyth_backend_info_get_port(tvplayer->backend_info); - - GString *fullpath = g_string_new("myth://"); - g_string_append_printf(fullpath, "%s:%d/%s", hostname, port, filename); - - tvplayer->is_livetv = FALSE; - - g_debug("[%s] Setting record uri to gstreamer pipeline to %s", - __FUNCTION__, fullpath->str); - - g_object_set(G_OBJECT(tvplayer->gst_source), "location", - fullpath->str, NULL); - - return TRUE; -} - -/** Configures the backend and the tv player - * for playing the live tv. - * - * @param tvplayer the object instance. - * @return TRUE if successfull, FALSE if any error happens. - */ -gboolean -mmyth_tvplayer_livetv_setup(MMythTVPlayer * tvplayer) -{ - gboolean res = TRUE; - - tvplayer->livetv = gmyth_livetv_new(); - - if (!gmyth_livetv_setup(tvplayer->livetv, tvplayer->backend_info)) - goto error; - - return res; - - error: - res = FALSE; - if (tvplayer->livetv != NULL) { - g_object_unref(tvplayer->livetv); - } - - if (tvplayer->local_hostname != NULL) { - g_string_free(tvplayer->local_hostname, TRUE); - } - - if (tvplayer->recorder != NULL) { - g_object_unref(tvplayer->recorder); - tvplayer->recorder = NULL; - } - - if (tvplayer->tvchain != NULL) { - g_object_unref(tvplayer->tvchain); - tvplayer->tvchain = NULL; - } - - if (tvplayer->proginfo != NULL) { - g_object_unref(tvplayer->proginfo); - tvplayer->proginfo = NULL; - } - - return res; - -} - -/** Sets the GTK video widget for the tv player. - * - * @param tvplayer the object instance. - * @param videow the GTK video window. - * @return TRUE if successfull, FALSE if any error happens. - */ -gboolean -mmyth_tvplayer_set_widget(MMythTVPlayer * tvplayer, GtkWidget * videow) -{ - tvplayer->videow = videow; - g_object_ref(videow); - - g_debug("[%s] Setting widget for tv player render", __FUNCTION__); - - tvplayer->expose_handler = - g_signal_connect(tvplayer->videow, "expose-event", - G_CALLBACK(expose_cb), tvplayer); - - // g_signal_connect(miptv_ui->videow, "size_request", - // G_CALLBACK(cb_preferred_video_size), miptv_ui); - - return TRUE; -} - -static gboolean -bus_call(GstBus * bus, GstMessage * msg, gpointer data) -{ - // MMythTVPlayer *tvplayer = MMYTH_TVPLAYER ( data ); - // GMainLoop *loop = tvplayer->loop; - - switch (GST_MESSAGE_TYPE(msg)) { - case GST_MESSAGE_EOS: - printf("End of stream\n"); - // g_idle_add ((GSourceFunc) idle_eos, data); - gst_element_set_state(GST_ELEMENT(GST_MESSAGE_SRC(msg)), - GST_STATE_NULL); - gst_element_set_locked_state(GST_ELEMENT(GST_MESSAGE_SRC(msg)), - TRUE); - break; - case GST_MESSAGE_ERROR: - { - gchar *debug; - GError *err; - - gst_message_parse_error(msg, &err, &debug); - g_free(debug); - - printf("Error: %s\n", err->message); - g_error_free(err); - - // g_main_loop_quit (loop); - } - break; - default: - printf(gst_message_type_get_name(GST_MESSAGE_TYPE(msg))); - printf("\n"); - break; - } - - return TRUE; -} - - -#if 0 -static gboolean -idle_state(gpointer data) -{ - GstPlayerWindowStateChange *st = data; - - if (st->old_state == GST_STATE_PLAYING) { - if (st->miptv_ui->idle_id != 0) { - g_source_remove(st->miptv_ui->idle_id); - st->miptv_ui->idle_id = 0; - } - } else if (st->new_state == GST_STATE_PLAYING) { - if (st->miptv_ui->idle_id != 0) - g_source_remove(st->miptv_ui->idle_id); - - st->miptv_ui->idle_id = g_idle_add(cb_iterate, st->miptv_ui); - } - - /* - * new movie loaded? - */ - if (st->old_state == GST_STATE_READY - && st->new_state > GST_STATE_READY) { - - /* - * gboolean have_video = FALSE; - */ - - gtk_widget_show(st->miptv_ui->videow); - - gtk_window_resize(GTK_WINDOW(st->miptv_ui->main_window), 1, 1); - - } - - /* - * discarded movie? - */ - if (st->old_state > GST_STATE_READY - && st->new_state == GST_STATE_READY) { - - if (st->miptv_ui->tagcache) { - gst_tag_list_free(st->miptv_ui->tagcache); - st->miptv_ui->tagcache = NULL; - } - } - - gst_object_unref(GST_OBJECT(st->play)); - // g_object_unref (G_OBJECT (st->win)); - g_free(st); - - /* - * once - */ - return FALSE; -} - -#endif - -/** Stops playing the current A/V. - * - * FIXME: How to proceed differently between livetv - * and recorded content? - * - * @param tvplayer the object instance. - * @return void - */ -void -mmyth_tvplayer_stop_playing(MMythTVPlayer * tvplayer) -{ - g_debug("[%s] Setting gstreamer pipeline state to NULL", __FUNCTION__); - - gst_element_set_state(tvplayer->gst_pipeline, GST_STATE_NULL); - - if (tvplayer->is_livetv) { - if (!gmyth_recorder_stop_livetv(tvplayer->recorder)) { - g_warning("[%s] Error while stoping remote encoder", - __FUNCTION__); - } - } -} - -/** Queries if the tvplayer is active playing A/V content. - * - * @param tvplayer the object instance. - * @return TRUE if the tvplayer is active, FALSE otherwise. - */ -gboolean -mmyth_tvplayer_is_playing(MMythTVPlayer * tvplayer) -{ - return (GST_STATE(tvplayer->gst_pipeline) == GST_STATE_PLAYING); -} - -/** Static function that sets the tvplayer state to PLAYING. - * - * @param tvplayer the object instance. - * @return TRUE if the tvplayer is active, FALSE otherwise. - */ -static gboolean -idle_play(gpointer data) -{ - MMythTVPlayer *tvplayer = MMYTH_TVPLAYER(data); - - g_debug("MMythTVPlayer: Setting pipeline state to PLAYING\n"); - - gst_element_set_state(tvplayer->gst_pipeline, GST_STATE_PLAYING); - - return FALSE; -} - -/** Start playing A/V with the tvplayer attributes. - * - * @param tvplayer the object instance. - */ -void -mmyth_tvplayer_start_playing(MMythTVPlayer * tvplayer) -{ - - // FIXME: Move this to livetv_setup?? - if (tvplayer->is_livetv) { - -#if 0 - if (!tvplayer || !(tvplayer->proginfo) - || !(tvplayer->local_hostname) - || !(tvplayer->gst_source)) { - g_warning("GMythtvPlayer not ready to start playing\n"); - } - - if (!(tvplayer->proginfo->pathname)) { - g_warning - ("[%s] Playback url is null, could not play the myth content", - __FUNCTION__); - return; - } - - g_debug("MMythTVPlayer: Start playing %s", - tvplayer->proginfo->pathname->str); -#endif - g_object_set(G_OBJECT(tvplayer->gst_source), "mythtv-live", - TRUE, NULL); -#if 0 - if (tvplayer->tvchain != NULL) { - GString *str_chainid = - gmyth_tvchain_get_id(tvplayer->tvchain); - g_print("[%s]\tCHAIN ID: %s\n", __FUNCTION__, - str_chainid->str); - - g_object_set(G_OBJECT(tvplayer->gst_source), - "mythtv-live-chainid", g_strdup(str_chainid->str), - NULL); - if (str_chainid != NULL) - g_string_free(str_chainid, FALSE); - } - - if (tvplayer->recorder != NULL) - g_object_set(G_OBJECT(tvplayer->gst_source), "mythtv-live-id", - tvplayer->recorder->recorder_num, NULL); - g_debug("[%s] Setting location to %s", __FUNCTION__, - tvplayer->proginfo->pathname->str); - - /* - * Sets the gstreamer properties acording to the service access - * address - */ - g_object_set(G_OBJECT(tvplayer->gst_source), "location", - tvplayer->proginfo->pathname->str, NULL); -#endif - } - - g_object_set(G_OBJECT(tvplayer->gst_source), "mythtv-version", - MYTHTV_VERSION_DEFAULT, NULL); - - g_object_set(G_OBJECT(tvplayer->gst_source), "mythtv-debug", - TRUE, NULL); - - g_idle_add(idle_play, tvplayer); - -}