Hi all,
I'm trying to rip a CD using a simple gstreamer pipeline - something that is already done in several programs, but i'd like to understand myself how it works. In the code below, I basically use the EOS event to seek to the next cd track. But the behavior I see is weird: -the first track is ripped ok -I call the start_track_rip function for track 2 -the program blocks here forever. I must be doing something really wrong but I can't see what, even by the looking at the sources of sound juicer for example. Any help is welcome, - pog Code below: ----------------- #include <glib.h> #include <gst/gst.h> #include <string.h> guint current_rip_track = 1; guint max_rip_track = 10; void start_track_rip(); static GMainLoop *loop; GstElement *pipeline; static gboolean my_bus_callback(GstBus * bus, GstMessage * message, gpointer data) { g_print("Got %s message\n", GST_MESSAGE_TYPE_NAME(message)); switch (GST_MESSAGE_TYPE(message)) { case GST_MESSAGE_ERROR:{ GError *err; gchar *debug; gst_message_parse_error(message, &err, &debug); g_print("Error: %s\n", err->message); g_error_free(err); g_free(debug); g_main_loop_quit(loop); break; } case GST_MESSAGE_EOS: if (current_rip_track < max_rip_track) { current_rip_track++; g_print("going to next track %d\n", current_rip_track); start_track_rip(); } else { g_print("no more tracks, stopping\n"); return FALSE; } break; default: /* unhandled message */ break; } return TRUE; } static gboolean cb_print_position(GstElement * pipeline) { GstState state, pending_state; static GstFormat format = GST_FORMAT_TIME; gint64 pos, len; gst_element_get_state(pipeline, &state, &pending_state, 0); if (state != GST_STATE_PLAYING && pending_state != GST_STATE_PLAYING) { return FALSE; } if (gst_element_query_position(pipeline, &format, &pos) && gst_element_query_duration(pipeline, &format, &len)) { g_print("Time: %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r", GST_TIME_ARGS(pos), GST_TIME_ARGS(len)); } /* call me again */ return TRUE; } int main() { gst_init(NULL, NULL); GstElement *source, *filter, *sink; GstBus *bus; // build pipeline pipeline = gst_pipeline_new("rip-pipeline"); source = gst_element_factory_make("cdparanoiasrc", "mycdparanoia"); filter = gst_element_factory_make("lame", "encoder"); sink = gst_element_factory_make("filesink", "myfilesink"); gst_bin_add_many(GST_BIN(pipeline), source, filter, sink, NULL); if (!gst_element_link_many(source, filter, sink, NULL)) { g_warning("Failed to link pipeline elements!"); } bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline)); gst_bus_add_watch(bus, my_bus_callback, NULL); gst_object_unref(bus); g_object_set(G_OBJECT(source), "device", "/dev/hda", NULL); start_track_rip(); g_print("starting main loop\n"); GMainLoop *loop = g_main_loop_new(NULL, FALSE); g_main_loop_run(loop); /* clean up */ gst_element_set_state(pipeline, GST_STATE_NULL); gst_object_unref(pipeline); g_main_loop_unref(loop); return (0); } void start_track_rip() { gchar buf[2048]; GstElement *sink = gst_bin_get_by_name(GST_BIN(pipeline), "myfilesink"); strcpy(buf, "/tmp/music_"); gchar buf2[10]; sprintf(buf2, "%02d", current_rip_track); strcat(buf, buf2); strcat(buf, ".mp3"); gst_element_set_state(sink, GST_STATE_NULL); g_object_set(G_OBJECT(sink), "location", buf, NULL); // seek to track GstElement *cd = gst_bin_get_by_name(GST_BIN(pipeline), "mycdparanoia"); g_object_set(G_OBJECT(cd), "track", current_rip_track, NULL); GstStateChangeReturn state_ret = gst_element_set_state(pipeline, GST_STATE_PLAYING); if (state_ret == GST_STATE_CHANGE_FAILURE) { g_print("01 state change failed\n"); } else if (state_ret == GST_STATE_CHANGE_SUCCESS) { g_print("02 state change successful\n"); } else if (state_ret == GST_STATE_CHANGE_ASYNC) { // what am I supposed to do here? g_print("seek async\n"); state_ret = gst_element_get_state(pipeline, NULL, NULL, GST_SECOND / 2); } g_timeout_add_seconds(1, (GSourceFunc) cb_print_position, pipeline); } ------------------------------------------------------------------------------ Throughout its 18-year history, RSA Conference consistently attracts the world's best and brightest in the field, creating opportunities for Conference attendees to learn about information security's most important issues through interactions with peers, luminaries and emerging and established companies. http://p.sf.net/sfu/rsaconf-dev2dev _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/gstreamer-devel |
On Fri, 2010-01-22 at 21:27 +0100, Pascal Ognibene wrote:
Hi, > I'm trying to rip a CD using a simple gstreamer pipeline (..) > In the code below, I basically use the EOS event to seek to the next > cd track. > But the behavior I see is weird: > -the first track is ripped ok > -I call the start_track_rip function for track 2 > -the program blocks here forever. > > I must be doing something really wrong but I can't see what, even by > the looking at the sources of sound juicer for example. > Any help is welcome, Not related to your problem at all, but you might want to add a queue after cdparanoiasrc to make sure encoding continues if there are problems reading the CD (dirt on the disc etc.). I haven't actually run your code, but it looks to me like you get an EOS and then change the track number via the property and that's it. However, when you get the EOS, streaming has already stopped, cdparanoiasrc is not running any longer. At that point, setting the property will not make it start up again. You have two options here: a) set pipeline state back to READY (or NULL), then change to PLAYING again. b) issue a seek in "track" format (track number might be 0-based in this case, don't remember exactly) to make it start up again. (b) might work in this particular case where you're just writing mp3 data to a file, but (a) is likely to work better in general, esp. with other encoders, if you add muxers or if you add a tag writer. So in short, try changing gst_element_set_state(sink, GST_STATE_NULL); at the beginning of start_track_rip() to gst_element_set_state(pipeline, GST_STATE_NULL); Cheers -Tim ------------------------------------------------------------------------------ Throughout its 18-year history, RSA Conference consistently attracts the world's best and brightest in the field, creating opportunities for Conference attendees to learn about information security's most important issues through interactions with peers, luminaries and emerging and established companies. http://p.sf.net/sfu/rsaconf-dev2dev _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/gstreamer-devel |
2010/1/23 Tim-Philipp Müller <[hidden email]> On Fri, 2010-01-22 at 21:27 +0100, Pascal Ognibene wrote: Thank you for your help! Actually, I stepped through the Sound Juicer code using gdb, and discovered that they destroy and recreate the pipeline for each track they rip. I've done the same, and it works fine. I'll try your solution as well to see if i can get faster seek operations between tracks. Oh, and I'm going to add a queue in the middle as per your excellent suggestion - I've been testing with a brand new CD so did not meet rip glitches yet, but this will happen for sure in "real life". Cheers, -pog ------------------------------------------------------------------------------ Throughout its 18-year history, RSA Conference consistently attracts the world's best and brightest in the field, creating opportunities for Conference attendees to learn about information security's most important issues through interactions with peers, luminaries and emerging and established companies. http://p.sf.net/sfu/rsaconf-dev2dev _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/gstreamer-devel |
Free forum by Nabble | Edit this page |