banshee r4898 - in trunk/banshee: . libbanshee src/Backends/Banshee.GStreamer/Banshee.GStreamer



Author: abock
Date: Sat Jan 10 05:08:47 2009
New Revision: 4898
URL: http://svn.gnome.org/viewvc/banshee?rev=4898&view=rev

Log:
2009-01-09  Aaron Bockover  <abock gnome org>

    * src/Backends/Banshee.GStreamer/Banshee.GStreamer/AudioCdRipper.cs:
    Handle the new mimetype callback and set it on the track (BGO #558526,
    BNC #464889)

    * libbanshee/banshee-ripper.c: Implemented support for the typefind
    element in the pipeline after the encoder to query a proper mime type
    for the encoded and muxed content

    * libbanshee/banshee-gst.h:
    * libbanshee/banshee-gst.c: Factored out a generic callback invoking
    version of gst_bin_iterate_recurse and gst_bin_iterate_all_by_interface
    to avoid duplicating a lot of iterator boilerplate code



Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/libbanshee/banshee-gst.c
   trunk/banshee/libbanshee/banshee-gst.h
   trunk/banshee/libbanshee/banshee-ripper.c
   trunk/banshee/src/Backends/Banshee.GStreamer/Banshee.GStreamer/AudioCdRipper.cs

Modified: trunk/banshee/libbanshee/banshee-gst.c
==============================================================================
--- trunk/banshee/libbanshee/banshee-gst.c	(original)
+++ trunk/banshee/libbanshee/banshee-gst.c	Sat Jan 10 05:08:47 2009
@@ -152,3 +152,47 @@
     
     g_free (message);
 }
+
+gboolean
+banshee_gst_bin_iterate_all_by_interface (GstBin *bin, GType type, BansheeGstBinIterateCallback callback, gpointer data)
+{
+    GstIterator *bin_iterator;
+    gpointer bin_element;
+    gboolean iterate_done = FALSE;
+    gboolean success = TRUE;
+
+    bin_iterator = type == G_TYPE_NONE 
+        ? gst_bin_iterate_recurse (bin)
+        : gst_bin_iterate_all_by_interface (bin, type);
+
+    while (!iterate_done) {
+        switch (gst_iterator_next (bin_iterator, (gpointer)&bin_element)) {
+            case GST_ITERATOR_OK:
+                if (callback != NULL && !callback (bin, type, bin_element, data)) {
+                    iterate_done = TRUE;
+                }
+            
+                gst_object_unref (bin_element);
+                break;
+            case GST_ITERATOR_RESYNC:
+                gst_iterator_resync (bin_iterator);
+                break;
+            case GST_ITERATOR_ERROR:
+                success = FALSE;
+                iterate_done = TRUE;
+                break;
+            default:
+                iterate_done = TRUE;
+                break;
+        }
+    }
+    
+    gst_iterator_free (bin_iterator);
+    return success;
+}
+
+gboolean
+banshee_gst_bin_iterate_recurse (GstBin *bin, BansheeGstBinIterateCallback callback, gpointer data)
+{
+    return banshee_gst_bin_iterate_all_by_interface (bin, G_TYPE_NONE, callback, data);
+}

Modified: trunk/banshee/libbanshee/banshee-gst.h
==============================================================================
--- trunk/banshee/libbanshee/banshee-gst.h	(original)
+++ trunk/banshee/libbanshee/banshee-gst.h	Sat Jan 10 05:08:47 2009
@@ -29,11 +29,15 @@
 #ifndef _BANSHEE_GST_H
 #define _BANSHEE_GST_H
 
-#include <glib.h>
+#include <gst/gst.h>
 
 gboolean  banshee_is_debugging ();
 guint     banshee_get_version_number ();
 
 void      banshee_log_debug (const gchar *component, const gchar *format, ...);
 
+typedef gboolean (* BansheeGstBinIterateCallback) (GstBin *bin, GType type, gpointer bin_element, gpointer data);
+gboolean  banshee_gst_bin_iterate_all_by_interface (GstBin *bin, GType type, BansheeGstBinIterateCallback callback, gpointer data);
+gboolean  banshee_gst_bin_iterate_recurse (GstBin *bin, BansheeGstBinIterateCallback callback, gpointer data);
+
 #endif /* _BANSHEE_GST_H */

Modified: trunk/banshee/libbanshee/banshee-ripper.c
==============================================================================
--- trunk/banshee/libbanshee/banshee-ripper.c	(original)
+++ trunk/banshee/libbanshee/banshee-ripper.c	Sat Jan 10 05:08:47 2009
@@ -32,6 +32,7 @@
 
 #include <string.h>
 #include <glib/gi18n.h>
+#include <glib/gstdio.h>
 
 #include "banshee-gst.h"
 #include "banshee-tagger.h"
@@ -39,6 +40,7 @@
 typedef struct BansheeRipper BansheeRipper;
 
 typedef void (* BansheeRipperFinishedCallback) (BansheeRipper *ripper);
+typedef void (* BansheeRipperMimeTypeCallback) (BansheeRipper *ripper, const gchar *mimetype);
 typedef void (* BansheeRipperProgressCallback) (BansheeRipper *ripper, gint msec, gpointer user_info);
 typedef void (* BansheeRipperErrorCallback)    (BansheeRipper *ripper, const gchar *error, const gchar *debug);
 
@@ -54,11 +56,13 @@
     GstElement *pipeline;
     GstElement *cddasrc;
     GstElement *encoder;
+    GstElement *typefind;
     GstElement *filesink;
     
     GstFormat track_format;
     
     BansheeRipperProgressCallback progress_cb;
+    BansheeRipperMimeTypeCallback mimetype_cb;
     BansheeRipperFinishedCallback finished_cb;
     BansheeRipperErrorCallback error_cb;
 };
@@ -170,6 +174,83 @@
     return TRUE;
 }
 
+static gboolean
+br_check_for_aac (GstBin *bin, GType type, gpointer bin_element, gpointer data)
+{
+    gboolean *override = (gboolean *)data;
+    *override = g_str_has_suffix (G_OBJECT_TYPE_NAME (bin_element), "AacEnc");
+    return !(*override);
+}
+
+
+static void
+br_have_type (GstElement *typefind, guint probability, GstCaps *caps, gpointer data)
+{
+    BansheeRipper *ripper = (BansheeRipper *)data;
+    const GstStructure *str;
+    const gchar *gst_mimetype;
+    const gchar *mimetype;
+    
+    str = gst_caps_get_structure (caps, 0);
+    if ((gst_mimetype = str != NULL ? gst_structure_get_name (str) : NULL) == NULL) {
+        return;
+    }
+    
+    mimetype = gst_mimetype;
+        
+    // Certain AAC plugins report the type as video/quicktime, so if
+    // we encounter this mimetype, iterate the encoder pipeline segment
+    // for an offending element and override the type
+    if (g_str_has_prefix (mimetype, "video/quicktime")) {
+        gboolean override = FALSE;
+        banshee_gst_bin_iterate_recurse (GST_BIN (ripper->encoder), br_check_for_aac, &override);
+        if (override) {
+            mimetype = "audio/mp4";
+        }
+    }
+    
+    if (banshee_is_debugging ()) {
+        g_printf ("Found Mime Type for encoded content: %s (probability = %d)\n",
+            mimetype, probability);
+    }
+    
+    if (ripper->mimetype_cb != NULL) {
+        ripper->mimetype_cb (ripper, mimetype);
+    }
+}
+
+static gboolean
+br_set_tags (GstBin *bin, GType type, gpointer bin_element, gpointer data)
+{
+    struct iterator_data_t {
+        GstTagList *tags;
+        gboolean can_tag;
+    } *iterator_data = (struct iterator_data_t *)data;
+
+    GstTagSetter *tag_setter = GST_TAG_SETTER (bin_element);
+    if (tag_setter == NULL) {
+        return TRUE;
+    }
+    
+    gst_tag_setter_add_tags (tag_setter, GST_TAG_MERGE_REPLACE_ALL,
+        GST_TAG_ENCODER, "Banshee " VERSION,
+        GST_TAG_ENCODER_VERSION, banshee_get_version_number (),
+        NULL);
+        
+    if (iterator_data->tags != NULL) {
+        gst_tag_setter_merge_tags (tag_setter, iterator_data->tags, GST_TAG_MERGE_APPEND);
+    }
+    
+    if (banshee_is_debugging ()) {
+        bt_tag_list_dump (gst_tag_setter_get_tag_list (tag_setter));
+    }
+        
+    iterator_data->can_tag = TRUE;
+    
+    return TRUE;
+}
+
+
 static GstElement *
 br_pipeline_build_encoder (const gchar *pipeline, GError **error_out)
 {
@@ -230,15 +311,26 @@
     
     g_object_set (G_OBJECT (queue), "max-size-time", 120 * GST_SECOND, NULL);
     
+    ripper->typefind = gst_element_factory_make ("typefind", "typefind");
+    if (ripper->typefind == NULL) {
+        br_raise_error (ripper, _("Could not create typefind plugin"), NULL);
+        return FALSE;
+    }
+    
+    g_signal_connect (G_OBJECT (ripper->typefind), "have-type",
+        G_CALLBACK (br_have_type), ripper);
+    
     ripper->filesink = gst_element_factory_make ("filesink", "filesink");
     if (ripper->filesink == NULL) {
         br_raise_error (ripper, _("Could not create filesink plugin"), NULL);
         return FALSE;
     }
     
-    gst_bin_add_many (GST_BIN (ripper->pipeline), ripper->cddasrc, queue, ripper->encoder, ripper->filesink, NULL);
+    gst_bin_add_many (GST_BIN (ripper->pipeline), ripper->cddasrc, queue, 
+        ripper->encoder, ripper->typefind, ripper->filesink, NULL);
         
-    if (!gst_element_link_many (ripper->cddasrc, queue, ripper->encoder, ripper->filesink, NULL)) {
+    if (!gst_element_link_many (ripper->cddasrc, queue, ripper->encoder, 
+        ripper->typefind, ripper->filesink, NULL)) {
         br_raise_error (ripper, _("Could not link pipeline elements"), NULL);
     }
     
@@ -295,7 +387,7 @@
     if (ripper->encoder_pipeline != NULL) {
         g_free (ripper->encoder_pipeline);
     }
-    
+
     g_free (ripper);
     ripper = NULL;
 }
@@ -304,10 +396,10 @@
 br_rip_track (BansheeRipper *ripper, gint track_number, gchar *output_path, 
     GstTagList *tags, gboolean *tagging_supported)
 {
-    GstIterator *bin_iterator;
-    GstElement *bin_element;
-    gboolean can_tag = FALSE;
-    gboolean iterate_done = FALSE;
+    struct {
+        GstTagList *tags;
+        gboolean can_tag;
+    } iterator_data = { tags, FALSE };
 
     g_return_val_if_fail (ripper != NULL, FALSE);
 
@@ -320,49 +412,11 @@
     g_object_set (G_OBJECT (ripper->filesink), "location", output_path, NULL);
     
     // find an element to do the tagging and set tag data
-    bin_iterator = gst_bin_iterate_all_by_interface (GST_BIN (ripper->encoder), GST_TYPE_TAG_SETTER);
-    while (!iterate_done) {
-        switch (gst_iterator_next (bin_iterator, (gpointer)&bin_element)) {
-            case GST_ITERATOR_OK: {
-                GstTagSetter *tag_setter = GST_TAG_SETTER (bin_element);
-                if (tag_setter == NULL) {
-                    break;
-                }
-                
-                gst_tag_setter_add_tags (tag_setter, GST_TAG_MERGE_REPLACE_ALL,
-                    GST_TAG_ENCODER, "Banshee " VERSION,
-                    GST_TAG_ENCODER_VERSION, banshee_get_version_number (),
-                    NULL);
-                    
-                if (tags != NULL) {
-                    gst_tag_setter_merge_tags (tag_setter, tags, GST_TAG_MERGE_APPEND);
-                }
-                
-                if (banshee_is_debugging ()) {
-                    bt_tag_list_dump (gst_tag_setter_get_tag_list (tag_setter));
-                }
-                    
-                can_tag = TRUE;    
-                gst_object_unref (bin_element);
-                break;
-            }
-            
-            case GST_ITERATOR_RESYNC: {
-                gst_iterator_resync (bin_iterator);
-                break;
-            }
-            
-            default: {
-                iterate_done = TRUE;
-                break;
-            }
-        }
-    }
-    
-    gst_iterator_free (bin_iterator);
-    
+    banshee_gst_bin_iterate_all_by_interface (GST_BIN (ripper->encoder), GST_TYPE_TAG_SETTER,
+        br_set_tags, &iterator_data);
+
     // We'll warn the user in the UI if we can't tag the encoded audio files
-    *tagging_supported = can_tag;
+    *tagging_supported = iterator_data.can_tag;
     
     // Begin the rip
     g_object_set (G_OBJECT (ripper->cddasrc), "track", track_number, NULL);
@@ -380,6 +434,13 @@
 }
 
 void
+br_set_mimetype_callback (BansheeRipper *ripper, BansheeRipperMimeTypeCallback cb)
+{
+    g_return_if_fail (ripper != NULL);
+    ripper->mimetype_cb = cb;
+}
+
+void
 br_set_finished_callback (BansheeRipper *ripper, BansheeRipperFinishedCallback cb)
 {
     g_return_if_fail (ripper != NULL);

Modified: trunk/banshee/src/Backends/Banshee.GStreamer/Banshee.GStreamer/AudioCdRipper.cs
==============================================================================
--- trunk/banshee/src/Backends/Banshee.GStreamer/Banshee.GStreamer/AudioCdRipper.cs	(original)
+++ trunk/banshee/src/Backends/Banshee.GStreamer/Banshee.GStreamer/AudioCdRipper.cs	Sat Jan 10 05:08:47 2009
@@ -50,6 +50,7 @@
         private TrackInfo current_track;
         
         private RipperProgressHandler progress_handler;
+        private RipperMimeTypeHandler mimetype_handler;
         private RipperFinishedHandler finished_handler;
         private RipperErrorHandler error_handler;
     
@@ -95,6 +96,9 @@
                 progress_handler = new RipperProgressHandler (OnNativeProgress);
                 br_set_progress_callback (handle, progress_handler);
                 
+                mimetype_handler = new RipperMimeTypeHandler (OnNativeMimeType);
+                br_set_mimetype_callback (handle, mimetype_handler);
+                
                 finished_handler = new RipperFinishedHandler (OnNativeFinished);
                 br_set_finished_callback (handle, finished_handler);
                 
@@ -173,6 +177,21 @@
             OnProgress (current_track, TimeSpan.FromMilliseconds (mseconds));
         }
         
+        private void OnNativeMimeType (IntPtr ripper, IntPtr mimetype)
+        {
+            if (mimetype != IntPtr.Zero && current_track != null) {
+                string type = GLib.Marshaller.Utf8PtrToString (mimetype);
+                if (type != null) {
+                    string [] split = type.Split (';', '.', ' ', '\t');
+                    if (split != null && split.Length > 0) {
+                        current_track.MimeType = split[0].Trim ();
+                    } else {
+                        current_track.MimeType = type.Trim ();
+                    }
+                }
+            }
+        }
+        
         private void OnNativeFinished (IntPtr ripper)
         {
             SafeUri uri = new SafeUri (output_path);
@@ -198,6 +217,7 @@
         }
         
         private delegate void RipperProgressHandler (IntPtr ripper, int mseconds);
+        private delegate void RipperMimeTypeHandler (IntPtr ripper, IntPtr mimetype);
         private delegate void RipperFinishedHandler (IntPtr ripper);
         private delegate void RipperErrorHandler (IntPtr ripper, IntPtr error, IntPtr debug);
         
@@ -215,6 +235,9 @@
         private static extern void br_set_progress_callback (HandleRef handle, RipperProgressHandler callback);
         
         [DllImport ("libbanshee")]
+        private static extern void br_set_mimetype_callback (HandleRef handle, RipperMimeTypeHandler callback);
+        
+        [DllImport ("libbanshee")]
         private static extern void br_set_finished_callback (HandleRef handle, RipperFinishedHandler callback);
         
         [DllImport ("libbanshee")]



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]