rendered paste body/* Time-stamp: <2008-01-07 07:07:33 Sonic1>|| Copyright (C) 2002-2003 Ryan Houdek <Sonicadvance1 at users.sourceforge.net>| Part of the gtkpod project.|| URL: http://gtkpod.sourceforge.net/|| This program is free software; you can redistribute it and/or modify| it under the terms of the GNU 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 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|| iTunes and iPod are trademarks of Apple|| This product is not supported/written/published by Apple!*/#ifdef HAVE_CONFIG_H# include <config.h>#endif#ifdef HAVE_GSTREAMER#include <math.h>#include <gst/gst.h>#include <gst/interfaces/xoverlay.h>#include <gdk/gdkx.h> #include "info.h"#include "misc.h"#include "misc_track.h"#include "mp3file.h"#include "prefs.h"#include "tools.h"#include "string.h" GMainLoop *loop; GstElement *pipeline, *audio, *audiomixer, *video, *volume; GstElement *src, *dec, *conv, *sink, *videosink, *videoconv; GstPad *audiopad, *videopad; GstBus *bus;GtkWidget *drawing_area;GtkWidget *vol_scale;static gboolean prevbut = FALSE;static gboolean stopall = FALSE;static GThread *thread = NULL;static GtkWidget *play_button;static GtkWidget *song_scale;static GtkWidget *song_label;static GList *l;gboolean hasvideo = FALSE;static int my_bus_callback (GstBus *bus, GstMessage *msg, gpointer data){ switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_EOS: gtk_range_set_range(GTK_RANGE (song_scale), 0, 1); gtk_range_set_value (GTK_RANGE (song_scale), 0); gtk_label_set_text(GTK_LABEL (song_label),""); g_main_loop_quit (data); break; case GST_MESSAGE_ERROR: { gchar *debug; GError *err; gst_message_parse_error (msg, &err, &debug); g_free (debug); g_print ("Error: %s\n", err->message); g_error_free (err); g_main_loop_quit (data); break; } default: break; } return TRUE;}int init_audio(int argc, char *argv[]){ gst_init (&argc, &argv); play_button = gtkpod_xml_get_widget (main_window_xml, "Play_button"); song_scale = gtkpod_xml_get_widget (main_window_xml, "song_scale"); song_label = gtkpod_xml_get_widget (main_window_xml, "song_label"); drawing_area = gtkpod_xml_get_widget (main_window_xml, "video_widget"); vol_scale = gtkpod_xml_get_widget (main_window_xml, "vol_scale"); gtk_widget_realize(gtkpod_xml_get_widget (main_window_xml, "video_widget")); return 0;}static gboolean set_scale_range (GstElement *pipeline){ GstFormat fmt = GST_FORMAT_TIME; gint64 len; if (loop == NULL || GST_OBJECT_IS_DISPOSING(pipeline)) return FALSE; if (loop != NULL || g_main_loop_is_running (loop)) { if(gst_element_query_duration (pipeline, &fmt, &len)) { gtk_range_set_range (GTK_RANGE (song_scale), 0, (((GstClockTime)(len)) / GST_SECOND)); return FALSE; } } else return FALSE; return TRUE;}static gboolean set_scale_position (GstElement *pipeline){ GstFormat fmt = GST_FORMAT_TIME; gint64 pos; gint64 len; if(loop == NULL || thread == NULL || !g_main_loop_is_running(loop)) return FALSE; if (loop != NULL || g_main_loop_is_running(loop)) { if (gst_element_query_position (pipeline, &fmt, &pos)) { gint seconds = ((GstClockTime) pos) / GST_SECOND; gint length; gchar *label; gst_element_query_duration (pipeline, &fmt, &len); length = ((GstClockTime) len) / GST_SECOND; label = g_strdup_printf (_("%s (%d:%02d of %d:%02d)"), (gchar *) g_object_get_data (G_OBJECT (song_label), "tr_title"), seconds / 60, seconds % 60, length / 60, length % 60); gtk_range_set_value (GTK_RANGE (song_scale), seconds); gtk_label_set_text (GTK_LABEL (song_label), label); g_free (label); return TRUE; } } return FALSE;}#ifndef M_LN10#define M_LN10 (log(10.0))#endifstatic void volume_changed_callback (GtkWidget *widget, GstElement* volume){ gdouble value; gdouble level; value = gtk_range_get_value (GTK_RANGE (widget)); level = exp (value / 20.0 * M_LN10); g_object_set (volume, "volume", level, NULL);}static voidcb_newpad (GstElement *decodebin, GstPad *pad, gboolean last, gpointer data){ GstCaps *caps; GstStructure *str; GstPad *audiopad, *videopad; /* check media type */ caps = gst_pad_get_caps (pad); str = gst_caps_get_structure (caps, 0); printf("string = %s\n",gst_structure_get_name (str)); const gchar *name = gst_structure_get_name (str); if (g_strrstr (name, "audio")) { /* only link once */ audiopad = gst_element_get_pad (audio, "sink"); if (GST_PAD_IS_LINKED (audiopad)) { g_object_unref (audiopad); return; } /* link'n'play */ gst_pad_link (pad, audiopad); // Link audiopad to pad or other way around, dunno //gst_element_link (volume, dec); //Doesn't seem to work... //volume_changed_callback (vol_scale, volume); //Change volume to default } if (g_strrstr (name, "video")) { // only link once videopad = gst_element_get_pad (video, "sink"); if (GST_PAD_IS_LINKED (videopad)) { g_object_unref (videopad); return; } // link'n'play gst_pad_link (pad, videopad); set_video_mode (TRUE); } gst_caps_unref (caps);}static void *playsong_real (void *ptr){ gchar *str; l = ptr; while (l) { Track *tr = l->data; g_return_val_if_fail(tr, (void*)-1);//printf("%d\n",a++); str = get_file_name_from_source(tr, SOURCE_PREFER_LOCAL);//printf("%d\n",a++); if (str) { gtk_label_set_text(GTK_LABEL (song_label), tr->title); // set label to title g_object_set_data (G_OBJECT (song_label), "tr_title", tr->title); // set label to title...again?wtf? gtk_widget_set_sensitive (vol_scale, TRUE); //set volume scale sensitivity to true /* init GStreamer */ loop = g_main_loop_new (NULL, FALSE); // make new loop /* setup */ pipeline = gst_pipeline_new ("pipeline"); //Create our pipeline volume = gst_element_factory_make ("volume", "volume"); // Create volume element bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); // get pipeline's bus gst_bus_add_watch (bus, my_bus_callback, loop); //Add a watch to the bus gst_object_unref (bus); //unref the bus src = gst_element_factory_make ("filesrc", "source"); //create the file source g_object_set (G_OBJECT (src), "location", str, NULL); //set location to the file location dec = gst_element_factory_make ("decodebin", "decoder"); //create our decodebin g_signal_connect (dec, "new-decoded-pad", G_CALLBACK (cb_newpad), NULL); //signal to the new-decoded-pad(same as new-pad) gst_bin_add_many (GST_BIN (pipeline), src, dec, NULL); //add src and dec to pipeline gst_element_link (src, dec); //link src and dec together /* create audio output */ audio = gst_bin_new ("audiobin"); //create our audio bin conv = gst_element_factory_make ("audioconvert", "aconv"); //Create audioconvert element audiopad = gst_element_get_pad (conv, "sink"); //get the audioconvert pad sink = gst_element_factory_make ("alsasink", "sink"); //create our alsasink gst_bin_add_many (GST_BIN (audio), conv, sink, volume, NULL); //add volume, conv, and sink to audio gst_element_link (conv, sink); // link sink and conv gst_element_add_pad (audio, gst_ghost_pad_new ("sink", audiopad)); // add pad to audio...? gst_object_unref (audiopad); //unref audiopad gst_bin_add (GST_BIN (pipeline), audio); //add audio to pipeline /*create video output*/ video = gst_bin_new ("videobin"); //create videobin videoconv = gst_element_factory_make ("ffmpegcolorspace", "vconv"); //make ffmpegcolorspace videopad = gst_element_get_pad (videoconv, "sink"); //get videoconv pad videosink = gst_element_factory_make ("xvimagesink", "sink"); //create video sink g_object_set (G_OBJECT (videosink), "force-aspect-ratio", TRUE, NULL); //force aspect ratio gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (videosink), gdk_x11_drawable_get_xid (drawing_area->window)); //set the overlay to our drawing area gst_bin_add_many (GST_BIN (video),videoconv, videosink, NULL); //add videoconv and videosink to video gst_element_link (videoconv, videosink); //link videoconv and videosink gst_element_add_pad (video, gst_ghost_pad_new ("sink", videopad)); //add pad to video...? gst_object_unref (videopad); //unref videopad //gst_bin_add(GST_BIN (pipeline), video); //If file doesn't contain video, it crashes the program, so commented out /* Volume Control */ //volume_changed_callback (vol_scale, volume); g_signal_connect (vol_scale, "value-changed", G_CALLBACK (volume_changed_callback), volume); //connect volume-changed signal // gst_bin_add_many (GST_BIN (pipeline), src, dec, volume, audio, NULL); /* run */ gst_element_set_state (pipeline, GST_STATE_PLAYING);// set state g_timeout_add (250, (GSourceFunc) set_scale_range, GST_PIPELINE (pipeline)); g_timeout_add (1000, (GSourceFunc) set_scale_position, GST_PIPELINE (pipeline)); //g_timeout_add (500, (GSourceFunc) checkinfo, gst_pipeline_get_bus (GST_PIPELINE (pipeline))); g_main_loop_run (loop); /* cleanup */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); #ifndef NEW_PIPE_PER_FILE /*if (GST_STATE_CHANGE_ASYNC == sret) { if (gst_element_get_state (GST_ELEMENT (pipeline), &state, NULL, GST_CLOCK_TIME_NONE) == GST_STATE_CHANGE_FAILURE) { g_print ("State change failed. Aborting"); break; } }*/ #endif if(pipeline != NULL) gst_object_unref (GST_OBJECT (pipeline)); g_main_loop_unref (loop); //START OLD! D:< } if (stopall) break; if (!prevbut) l = g_list_next(l); else prevbut = FALSE; } thread = NULL; stopall = FALSE; g_thread_exit (0); return (void*)-1;}void seek_to_time (gint64 time_seconds){ if(loop == NULL || pipeline == NULL || thread == NULL || !g_main_loop_is_running(loop)) return; if (!gst_element_seek (pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,GST_SEEK_TYPE_SET, time_seconds*1000000000, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) g_print ("Seek failed!\n");}void pause_song(){ if(loop == NULL || pipeline == NULL || thread == NULL || !g_main_loop_is_running(loop)) { play_song (tm_get_selected_tracks()); } GstState state, pending; gst_element_get_state(pipeline, &state, &pending, GST_CLOCK_TIME_NONE); if(state == GST_STATE_PLAYING) { gst_element_set_state (pipeline, GST_STATE_PAUSED); gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (play_button), GTK_STOCK_MEDIA_PLAY); } else if(state == GST_STATE_PAUSED) { gst_element_set_state (pipeline, GST_STATE_PLAYING); gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (play_button), GTK_STOCK_MEDIA_PAUSE); }}static void waitforpipeline(int state){ if(pipeline == NULL || thread == NULL) return; GstState istate, ipending; gst_element_get_state(pipeline, &istate, &ipending, GST_CLOCK_TIME_NONE); if(istate == GST_STATE_VOID_PENDING) return; gst_element_set_state (pipeline, state); do { gst_element_get_state(pipeline, &istate, &ipending, GST_CLOCK_TIME_NONE); if(istate == GST_STATE_VOID_PENDING) return; } while(istate != state); return;}static void stop_song (){ if(loop != NULL && g_main_loop_is_running(loop)) g_main_loop_quit(loop); gtk_range_set_range(GTK_RANGE (song_scale), 0, 1); gtk_range_set_value (GTK_RANGE (song_scale), 0); gtk_label_set_text(GTK_LABEL (song_label), "");}void stop_all_songs (){ stopall = TRUE; //stop_song (); waitforpipeline (1); thread = NULL; set_video_mode (FALSE); gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (play_button), GTK_STOCK_MEDIA_PLAY); stopall = FALSE; gtk_widget_set_sensitive (gtkpod_xml_get_widget (main_window_xml, "song_scale"), FALSE);}void previous_song(){ prevbut = TRUE; l = g_list_previous (l); stop_song(); waitforpipeline (1);}void next_song(){ stop_song(); waitforpipeline (1);}int play_song(GList *songs){ stop_all_songs(); GError *err1 = NULL ; printf("fault\n"); if (!g_thread_supported ()) { printf("fault2\n"); g_thread_init (NULL); gdk_threads_init (); } printf("fault3\n"); thread = g_thread_create ((GThreadFunc)playsong_real, (void *)songs, TRUE, &err1);printf("fault4\n"); if (!thread) { printf ("GStreamer thread creation failed: %s\n", err1->message); g_error_free (err1); } printf("fault5\n"); gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (play_button), GTK_STOCK_MEDIA_PAUSE); printf("fault6\n"); return 0;}#endif