OSDN Git Service

batch file scanning and scan cancel
authorjstebbins <jstebbins@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Wed, 25 Nov 2009 21:14:44 +0000 (21:14 +0000)
committerjstebbins <jstebbins@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Wed, 25 Nov 2009 21:14:44 +0000 (21:14 +0000)
When a directory is specified as the source, first we attempt to open as a dvd,
then if that fails, we attempt to open each file in the directory as a stream
source.  Since opening a large directory of files can take a really long time,
you can also now cancel a scan.

git-svn-id: svn://localhost/HandBrake/trunk@2980 b64f7644-9d1e-0410-96f1-a4d463321fa5

23 files changed:
gtk/src/callbacks.c
gtk/src/ghb.ui
gtk/src/hb-backend.c
gtk/src/hb-backend.h
gtk/src/marshalers.h
gtk/src/presets.c
libhb/batch.c [new file with mode: 0644]
libhb/common.c
libhb/common.h
libhb/decmetadata.c
libhb/dvd.c
libhb/dvdnav.c
libhb/hb.c
libhb/hb.h
libhb/internal.h
libhb/ports.h
libhb/reader.c
libhb/scan.c
libhb/stream.c
libhb/work.c
macosx/Controller.h
macosx/Controller.m
test/test.c

index 532ac69..fb319b2 100644 (file)
@@ -900,7 +900,11 @@ start_scan(
                return;
 
        widget = GHB_WIDGET(ud->builder, "sourcetoolbutton");
-       gtk_widget_set_sensitive(widget, FALSE);
+       gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(widget), "hb-stop");
+       gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), "Stop Scan");
+       gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), "Stop Scan");
+       //gtk_widget_set_sensitive(widget, FALSE);
+
        action = GHB_ACTION(ud->builder, "source_action");
        gtk_action_set_sensitive(action, FALSE);
        action = GHB_ACTION(ud->builder, "source_single_action");
@@ -936,14 +940,14 @@ ghb_do_scan(
        if (filename != NULL)
        {
                last_scan_file = g_strdup(filename);
-               ghb_settings_set_string(ud->settings, "source", filename);
+               ghb_settings_set_string(ud->settings, "scan_source", filename);
                if (update_source_label(ud, filename, TRUE))
                {
                        gchar *path;
                        gint preview_count;
 
                        show_scan_progress(ud);
-                       path = ghb_settings_get_string( ud->settings, "source");
+                       path = ghb_settings_get_string( ud->settings, "scan_source");
                        prune_logs(ud);
 
                        preview_count = ghb_settings_get_int(ud->settings, "preview_count");
@@ -964,7 +968,7 @@ update_source_name(gpointer data)
        GtkWidget *dialog;
        gchar *sourcename;
 
-       sourcename = ghb_settings_get_string(ud->settings, "source");
+       sourcename = ghb_settings_get_string(ud->settings, "scan_source");
        dialog = GHB_WIDGET(ud->builder, "source_dialog");
        gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), sourcename);
        g_free(sourcename);
@@ -981,7 +985,7 @@ do_source_dialog(GtkButton *button, gboolean single, signal_user_data_t *ud)
        gboolean checkbutton_active;
 
        g_debug("source_browse_clicked_cb ()");
-       sourcename = ghb_settings_get_string(ud->settings, "source");
+       sourcename = ghb_settings_get_string(ud->settings, "scan_source");
        checkbutton_active = FALSE;
        if (g_file_test(sourcename, G_FILE_TEST_IS_DIR))
        {
@@ -1038,7 +1042,16 @@ do_source_dialog(GtkButton *button, gboolean single, signal_user_data_t *ud)
 G_MODULE_EXPORT void
 source_button_clicked_cb(GtkButton *button, signal_user_data_t *ud)
 {
-       do_source_dialog(button, FALSE, ud);
+       ghb_status_t status;
+       ghb_get_status(&status);
+       if (status.scan.state & GHB_STATE_SCANNING)
+       {
+               ghb_backend_scan_stop();
+       }
+       else
+       {
+               do_source_dialog(button, FALSE, ud);
+       }
 }
 
 G_MODULE_EXPORT void
@@ -1053,7 +1066,7 @@ dvd_source_activate_cb(GtkAction *action, signal_user_data_t *ud)
        const gchar *filename;
        gchar *sourcename;
 
-       sourcename = ghb_settings_get_string(ud->settings, "source");
+       sourcename = ghb_settings_get_string(ud->settings, "scan_source");
        filename = gtk_action_get_name(action);
        ghb_do_scan(ud, filename, 0, TRUE);
        if (strcmp(sourcename, filename) != 0)
@@ -1309,25 +1322,51 @@ get_rate_string(gint rate_base, gint rate)
        rate_s = g_strdup_printf("%.6g", rate_f);
        return rate_s;
 }
+
+static void
+update_title_duration(signal_user_data_t *ud)
+{
+       gint ti;
+       gint hh, mm, ss, start, end;
+       gchar *text;
+       GtkWidget *widget;
+
+       ti = ghb_settings_combo_int(ud->settings, "title");
+       widget = GHB_WIDGET (ud->builder, "title_duration");
+
+       start = ghb_settings_get_int(ud->settings, "start_chapter");
+       end = ghb_settings_get_int(ud->settings, "end_chapter");
+       ghb_part_duration(ti, start, end, &hh, &mm, &ss);
+       text = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss);
+       gtk_label_set_text (GTK_LABEL(widget), text);
+       g_free(text);
+}
+
 static void
 show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo)
 {
        GtkWidget *widget;
        gchar *text;
 
-       ud->dont_clear_presets = TRUE;
-       widget = GHB_WIDGET (ud->builder, "title_duration");
-       if (tinfo->duration != 0)
+       ghb_settings_set_string(ud->settings, "source", tinfo->path);
+       if (tinfo->type == HB_STREAM_TYPE)
        {
-               text = g_strdup_printf ("%02d:%02d:%02d", tinfo->hours, 
-                               tinfo->minutes, tinfo->seconds);
-       }
-       else
-       {
-               text = g_strdup_printf ("Unknown");
+               GtkWidget *widget = GHB_WIDGET (ud->builder, "source_title");
+               if (tinfo->name != NULL && tinfo->name[0] != 0)
+               {
+                       gtk_label_set_text (GTK_LABEL(widget), tinfo->name);
+                       ghb_settings_set_string(ud->settings, "volume_label", tinfo->name);
+                       set_destination(ud);
+               }
+               else
+               {
+                       gchar *label = "No Title Found";
+                       gtk_label_set_text (GTK_LABEL(widget), label);
+                       ghb_settings_set_string(ud->settings, "volume_label", label);
+               }
        }
-       gtk_label_set_text (GTK_LABEL(widget), text);
-       g_free(text);
+       ud->dont_clear_presets = TRUE;
+       update_title_duration(ud);
        widget = GHB_WIDGET (ud->builder, "source_dimensions");
        text = g_strdup_printf ("%d x %d", tinfo->width, tinfo->height);
        gtk_label_set_text (GTK_LABEL(widget), text);
@@ -1572,6 +1611,7 @@ start_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
        {
                gtk_widget_show(widget);
        }
+       update_title_duration(ud);
 }
 
 G_MODULE_EXPORT void
@@ -1602,6 +1642,7 @@ end_chapter_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
        {
                gtk_widget_show(widget);
        }
+       update_title_duration(ud);
 }
 
 G_MODULE_EXPORT void
@@ -2410,13 +2451,16 @@ ghb_backend_events(signal_user_data_t *ud)
                GtkAction *action;
 
                widget = GHB_WIDGET(ud->builder, "sourcetoolbutton");
-               gtk_widget_set_sensitive(widget, TRUE);
+               gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(widget), "hb-source");
+               gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), "Source");
+               gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), "Choose Video Source");
+
                action = GHB_ACTION(ud->builder, "source_action");
                gtk_action_set_sensitive(action, TRUE);
                action = GHB_ACTION(ud->builder, "source_single_action");
                gtk_action_set_sensitive(action, TRUE);
 
-               source = ghb_settings_get_string(ud->settings, "source");
+               source = ghb_settings_get_string(ud->settings, "scan_source");
                update_source_label(ud, source, FALSE);
 
                scan_prog = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "scan_prog"));
@@ -3546,7 +3590,7 @@ handle_media_change(const gchar *device, gboolean insert, signal_user_data_t *ud
                                update_source_label(ud, device, TRUE);
                                gint preview_count;
                                preview_count = ghb_settings_get_int(ud->settings, "preview_count");
-                               ghb_settings_set_string(ud->settings, "source", device);
+                               ghb_settings_set_string(ud->settings, "scan_source", device);
                                start_scan(ud, device, 0, preview_count);
                        }
                }
@@ -3563,7 +3607,7 @@ handle_media_change(const gchar *device, gboolean insert, signal_user_data_t *ud
                        {
                                ghb_hb_cleanup(TRUE);
                                prune_logs(ud);
-                               ghb_settings_set_string(ud->settings, "source", "/dev/null");
+                               ghb_settings_set_string(ud->settings, "scan_source", "/dev/null");
                                start_scan(ud, "/dev/null", 0, 1);
                        }
                }
@@ -3650,7 +3694,7 @@ drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
                        update_source_label(ud, device, TRUE);
                        gint preview_count;
                        preview_count = ghb_settings_get_int(ud->settings, "preview_count");
-                       ghb_settings_set_string(ud->settings, "source", device);
+                       ghb_settings_set_string(ud->settings, "scan_source", device);
                        start_scan(ud, device, 0, preview_count);
                }
        }
@@ -3658,7 +3702,7 @@ drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud)
        {
                ghb_hb_cleanup(TRUE);
                prune_logs(ud);
-               ghb_settings_set_string(ud->settings, "source", "/dev/null");
+               ghb_settings_set_string(ud->settings, "scan_source", "/dev/null");
                start_scan(ud, "/dev/null", 0, 1);
        }
 }
index e599233..f012833 100644 (file)
                     <child>
                       <object class="GtkVBox" id="vbox16">
                         <property name="visible">True</property>
-                        <property name="spacing">6</property>
+                        <property name="spacing">2</property>
                         <child>
                           <object class="GtkHBox" id="hbox54">
                             <property name="visible">True</property>
                           </packing>
                         </child>
                         <child>
-                          <object class="GtkAlignment" id="alignment65">
+                          <object class="GtkAlignment" id="alignment72">
                             <property name="visible">True</property>
+                            <property name="top_padding">6</property>
                             <property name="left_padding">6</property>
-                            <property name="bottom_padding">6</property>
                             <child>
-                              <object class="GtkHBox" id="hbox5">
+                              <object class="GtkHBox" id="hbox8">
                                 <property name="visible">True</property>
                                 <property name="spacing">4</property>
                                 <child>
                                     <property name="position">1</property>
                                   </packing>
                                 </child>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkAlignment" id="alignment65">
+                            <property name="visible">True</property>
+                            <property name="left_padding">6</property>
+                            <property name="bottom_padding">6</property>
+                            <child>
+                              <object class="GtkHBox" id="hbox5">
+                                <property name="visible">True</property>
+                                <property name="spacing">4</property>
                                 <child>
                                   <object class="GtkAlignment" id="chapter_box">
                                     <property name="visible">True</property>
                                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                                     <property name="xalign">0</property>
                                     <property name="xscale">0</property>
-                                    <property name="left_padding">8</property>
+                                    <property name="left_padding">0</property>
                                     <child>
                                       <object class="GtkHBox" id="hbox4">
                                         <property name="visible">True</property>
                           </object>
                           <packing>
                             <property name="expand">False</property>
-                            <property name="position">1</property>
+                            <property name="position">2</property>
                           </packing>
                         </child>
                       </object>
@@ -6558,6 +6575,7 @@ libx264 authors:
   <object class="GtkFileChooserDialog" id="source_dialog">
     <property name="border_width">5</property>
     <property name="modal">True</property>
+    <property name="action">GTK_FILE_CHOOSER_ACTION_OPEN</property>
     <property name="type_hint">dialog</property>
     <property name="skip_taskbar_hint">True</property>
     <property name="skip_pager_hint">True</property>
@@ -6610,7 +6628,7 @@ libx264 authors:
             </child>
             <child>
               <object class="GtkCheckButton" id="source_folder_flag">
-                <property name="label" translatable="yes">Open VIDEO_TS folder</property>
+                <property name="label" translatable="yes">Open folder (DVD or batch)</property>
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="receives_default">False</property>
index 14db5b0..d060983 100644 (file)
@@ -1759,14 +1759,32 @@ title_opts_set(GtkBuilder *builder, const gchar *name)
        for (ii = 0; ii < count; ii++)
        {
                title = (hb_title_t*)hb_list_item(list, ii);
-               if (title->duration != 0)
+               if (title->type == HB_STREAM_TYPE)
                {
-                       titles[ii]  = g_strdup_printf ("%d - %02dh%02dm%02ds",
-                               title->index, title->hours, title->minutes, title->seconds);
+                       if (title->duration != 0)
+                       {
+                               titles[ii]  = g_strdup_printf ("%d - %02dh%02dm%02ds - %s",
+                                       title->index, title->hours, title->minutes, title->seconds, 
+                                       title->name);
+                       }
+                       else
+                       {
+                               titles[ii]  = g_strdup_printf ("%d - %s", 
+                                                                               title->index, title->name);
+                       }
                }
                else
                {
-                       titles[ii]  = g_strdup_printf ("%d - Unknown Length", title->index);
+                       if (title->duration != 0)
+                       {
+                               titles[ii]  = g_strdup_printf ("%d - %02dh%02dm%02ds",
+                                       title->index, title->hours, title->minutes, title->seconds);
+                       }
+                       else
+                       {
+                               titles[ii]  = g_strdup_printf ("%d - Unknown Length", 
+                                                                               title->index);
+                       }
                }
                gtk_list_store_append(store, &iter);
                gtk_list_store_set(store, &iter, 
@@ -2639,6 +2657,44 @@ ghb_build_x264opts_string(GValue *settings)
 }
 
 void
+ghb_part_duration(gint tt, gint sc, gint ec, gint *hh, gint *mm, gint *ss)
+{
+       hb_list_t  * list;
+       hb_title_t * title;
+    hb_chapter_t * chapter;
+       gint count, c;
+       gint64 duration;
+       
+       *hh = *mm = *ss = 0;
+       if (h_scan == NULL) return;
+       list = hb_get_titles( h_scan );
+    title = (hb_title_t*)hb_list_item( list, tt );
+       if (title == NULL) return;
+
+       *hh = title->hours;
+       *mm = title->minutes;
+       *ss = title->seconds;
+
+       count = hb_list_count(title->list_chapter);
+       if (sc > count) sc = count;
+       if (ec > count) ec = count;
+
+       if (sc == 1 && ec == count)
+               return;
+
+       duration = 0;
+       for (c = sc; c <= ec; c++)
+       {
+               chapter = hb_list_item(title->list_chapter, c-1);
+               duration += chapter->duration;
+       }
+
+       *hh =   duration / 90000 / 3600;
+       *mm = ((duration / 90000) % 3600) / 60;
+       *ss =  (duration / 90000) % 60;
+}
+
+void
 ghb_get_chapter_duration(gint ti, gint ii, gint *hh, gint *mm, gint *ss)
 {
        hb_list_t  * list;
@@ -2853,6 +2909,11 @@ ghb_backend_close()
        hb_close(&h_scan);
 }
 
+void ghb_backend_scan_stop()
+{
+    hb_scan_stop( h_scan );
+}
+
 void
 ghb_backend_scan(const gchar *path, gint titleindex, gint preview_count)
 {
@@ -3085,8 +3146,9 @@ ghb_get_title_info(ghb_title_info_t *tinfo, gint titleindex)
                return FALSE;
        }
 
-    title = hb_list_item( list, titleindex );
+       title = hb_list_item( list, titleindex );
        if (title == NULL) return FALSE;        // Bad titleindex
+       tinfo->index = titleindex;
        tinfo->width = title->width;
        tinfo->height = title->height;
        memcpy(tinfo->crop, title->crop, 4 * sizeof(int));
@@ -3107,6 +3169,9 @@ ghb_get_title_info(ghb_title_info_t *tinfo, gint titleindex)
        tinfo->duration = title->duration;
 
        tinfo->angle_count = title->angle_count;
+       tinfo->path = title->path;
+       tinfo->name = title->name;
+       tinfo->type = title->type;
        return TRUE;
 }
 
index ac5ea70..1ccb53e 100644 (file)
@@ -62,6 +62,10 @@ typedef struct
 
 typedef struct
 {
+       gchar *path;
+       gchar *name;
+       gint index;
+       gint type;
        gint width;
        gint height;
        gint crop[4];
@@ -120,12 +124,14 @@ gint ghb_get_queue_state();
 void ghb_get_status(ghb_status_t *status);
 void ghb_track_status(void);
 void ghb_backend_scan(const gchar *path, gint titleindex, gint preview_count);
+void ghb_backend_scan_stop();
 void ghb_backend_queue_scan(const gchar *path, gint titleindex);
 gboolean ghb_get_title_info(ghb_title_info_t *tinfo, gint titleindex);
 void ghb_par_init(signal_user_data_t *ud);
 void ghb_set_scale(signal_user_data_t *ud, gint mode);
 GValue* ghb_get_chapters(gint titleindex);
 void ghb_get_chapter_duration(gint ti, gint ii, gint *hh, gint *mm, gint *ss);
+void ghb_part_duration(gint tt, gint sc, gint ec, gint *hh, gint *mm, gint *ss);
 gint ghb_get_best_mix(gint titleindex, gint track, gint acodec, gint mix);
 gboolean ghb_ac3_in_audio_list(const GValue *audio_list);
 gboolean ghb_audio_is_passthru(gint acodec);
index 1034f92..a5ae524 100644 (file)
@@ -6,7 +6,7 @@
 
 G_BEGIN_DECLS
 
-/* VOID:STRING,STRING (marshalers.list:1) */
+/* VOID:STRING,STRING (/home/jstebbins/Source/HandBrake.batch/build.dbg/../gtk/src/marshalers.list:1) */
 extern void ghb_marshal_VOID__STRING_STRING (GClosure     *closure,
                                              GValue       *return_value,
                                              guint         n_param_values,
@@ -14,7 +14,7 @@ extern void ghb_marshal_VOID__STRING_STRING (GClosure     *closure,
                                              gpointer      invocation_hint,
                                              gpointer      marshal_data);
 
-/* BOOLEAN:BOXED (marshalers.list:2) */
+/* BOOLEAN:BOXED (/home/jstebbins/Source/HandBrake.batch/build.dbg/../gtk/src/marshalers.list:2) */
 extern void ghb_marshal_BOOLEAN__BOXED (GClosure     *closure,
                                         GValue       *return_value,
                                         guint         n_param_values,
index bac7bb8..687daba 100644 (file)
@@ -1241,7 +1241,7 @@ ghb_prefs_to_ui(signal_user_data_t *ud)
                ghb_ui_update(ud, "hbfd", ghb_int64_value(0));
        }
        gval = ghb_settings_get_value(ud->settings, "default_source");
-       ghb_settings_set_value (ud->settings, "source", gval);
+       ghb_settings_set_value (ud->settings, "scan_source", gval);
 
        str = ghb_settings_get_string(ud->settings, "destination_dir");
        ghb_ui_update(ud, "dest_dir", ghb_string_value(str));
diff --git a/libhb/batch.c b/libhb/batch.c
new file mode 100644 (file)
index 0000000..f627df5
--- /dev/null
@@ -0,0 +1,128 @@
+/* $Id: dvd.c,v 1.12 2005/11/25 15:05:25 titer Exp $
+
+   This file is part of the HandBrake source code.
+   Homepage: <http://handbrake.fr/>.
+   It may be used under the terms of the GNU General Public License. */
+
+#include "hb.h"
+#include "lang.h"
+
+struct hb_batch_s
+{
+    char      * path;
+    hb_list_t * list_file;
+};
+
+/***********************************************************************
+ * hb_batch_init
+ ***********************************************************************
+ *
+ **********************************************************************/
+hb_batch_t * hb_batch_init( char * path )
+{
+    hb_batch_t    * d;
+    struct stat     sb;
+    DIR           * dir;
+    struct dirent * entry;
+    char          * filename;
+
+    if ( stat( path, &sb ) )
+        return NULL;
+
+    if ( !S_ISDIR( sb.st_mode ) )
+        return NULL;
+
+    dir = opendir( path );
+    if ( dir == NULL )
+        return NULL;
+
+    d = calloc( sizeof( hb_batch_t ), 1 );
+    d->list_file = hb_list_init();
+
+    while ( (entry = readdir( dir ) ) )
+    {
+        filename = hb_strdup_printf( "%s" DIR_SEP_STR "%s", path, entry->d_name );
+        if ( stat( filename, &sb ) )
+        {
+            free( filename );
+            continue;
+        }
+
+        if ( !S_ISREG( sb.st_mode ) )
+        {
+            free( filename );
+            continue;
+        }
+
+        hb_list_add( d->list_file, filename );
+    }
+
+    if ( hb_list_count( d->list_file ) == 0 )
+    {
+        hb_list_close( &d->list_file );
+        free( d );
+        return NULL;
+    }
+
+    d->path = strdup( path );
+
+    return d;
+}
+
+/***********************************************************************
+ * hb_batch_title_count
+ **********************************************************************/
+int hb_batch_title_count( hb_batch_t * d )
+{
+    return hb_list_count( d->list_file );
+}
+
+/***********************************************************************
+ * hb_batch_title_scan
+ **********************************************************************/
+hb_title_t * hb_batch_title_scan( hb_batch_t * d, int t )
+{
+
+    hb_title_t   * title;
+    char         * filename;
+    hb_stream_t  * stream;
+
+    if ( t < 1 )
+        return NULL;
+
+    filename = hb_list_item( d->list_file, t-1 );
+    if ( filename == NULL )
+        return NULL;
+
+    stream = hb_stream_open( filename, 0 );
+    if ( stream == NULL )
+        return NULL;
+
+    title = hb_stream_title_scan( stream );
+    title->index = t;
+    hb_stream_close( &stream );
+
+    return title;
+}
+
+/***********************************************************************
+ * hb_batch_close
+ ***********************************************************************
+ * Closes and frees everything
+ **********************************************************************/
+void hb_batch_close( hb_batch_t ** _d )
+{
+    hb_batch_t * d = *_d;
+    char       * filename;
+
+    while ( ( filename = hb_list_item( d->list_file, 0 ) ) )
+    {
+        hb_list_rem( d->list_file, filename );
+        free( filename );
+    }
+    hb_list_close( &d->list_file );
+    free( d->path );
+    free( d );
+    *_d = NULL;
+}
+
index 3576255..ce98398 100644 (file)
@@ -714,7 +714,7 @@ void hb_register_error_handler( hb_error_handler_t * handler )
  **********************************************************************
  *
  *********************************************************************/
-hb_title_t * hb_title_init( char * dvd, int index )
+hb_title_t * hb_title_init( char * path, int index )
 {
     hb_title_t * t;
 
@@ -724,7 +724,7 @@ hb_title_t * hb_title_init( char * dvd, int index )
     t->list_audio    = hb_list_init();
     t->list_chapter  = hb_list_init();
     t->list_subtitle = hb_list_init();
-    strcat( t->dvd, dvd );
+    strcat( t->path, path );
     // default to decoding mpeg2
     t->video_id      = 0xE0;
     t->video_codec   = WORK_DECMPEG2;
@@ -973,3 +973,45 @@ int hb_srt_add( const hb_job_t * job,
     }
     return retval;
 }
+
+char * hb_strdup_printf( char * fmt, ... )
+{
+    int       len;
+    va_list   ap;
+    int       size = 256;
+    char    * str;
+    char    * tmp;
+
+    str = malloc( size );
+    if ( str == NULL )
+        return NULL;
+
+    while (1) 
+    {
+        /* Try to print in the allocated space. */
+        va_start( ap, fmt );
+        len = vsnprintf( str, size, fmt, ap );
+        va_end( ap );
+
+        /* If that worked, return the string. */
+        if ( len > -1 && len < size )
+        {
+            return str;
+        }
+
+        /* Else try again with more space. */
+        if ( len > -1 )     /* glibc 2.1 */
+            size = len + 1; /* precisely what is needed */
+        else                /* glibc 2.0 */
+            size *= 2;      /* twice the old size */
+        tmp = realloc( str, size );
+        if ( tmp == NULL )
+        {
+            free( str );
+            return NULL;
+        }
+        else
+            str = tmp;
+    }
+}
+
index b6c5e57..a85beda 100644 (file)
@@ -501,7 +501,8 @@ struct hb_metadata_s
 
 struct hb_title_s
 {
-    char        dvd[1024];
+    enum { HB_DVD_TYPE, HB_STREAM_TYPE } type;
+    char        path[1024];
     char        name[1024];
     int         index;
     int         vts;
@@ -735,4 +736,6 @@ typedef void hb_error_handler_t( const char *errmsg );
 
 extern void hb_register_error_handler( hb_error_handler_t * handler );
 
+char * hb_strdup_printf( char * fmt, ... );
+
 #endif
index e377f8c..bd848a9 100644 (file)
@@ -13,7 +13,7 @@ static void decmp4metadata( hb_title_t *title )
     MP4FileHandle input_file;
     hb_deep_log( 2, "Got an MP4 input, read the metadata");
 
-    input_file = MP4Read( title->dvd, 0 );
+    input_file = MP4Read( title->path, 0 );
 
     if( input_file != MP4_INVALID_FILE_HANDLE )
     { 
index fa5373e..fbac84d 100644 (file)
@@ -158,6 +158,8 @@ static hb_title_t * hb_dvdread_title_scan( hb_dvd_t * e, int t )
     hb_log( "scan: scanning title %d", t );
 
     title = hb_title_init( d->path, t );
+    title->type = HB_DVD_TYPE;
+
     if( DVDUDFVolumeInfo( d->reader, title->name, sizeof( title->name ),
                           unused, sizeof( unused ) ) )
     {
index 2f1ac93..84895ca 100644 (file)
@@ -307,6 +307,7 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
     hb_log( "scan: scanning title %d", t );
 
     title = hb_title_init( d->path, t );
+    title->type = HB_DVD_TYPE;
     if (dvdnav_get_title_string(d->dvdnav, &name) == DVDNAV_STATUS_OK)
     {
         strncpy( title->name, name, sizeof( title->name ) );
index 34fe53b..1b899e3 100644 (file)
@@ -38,6 +38,7 @@ struct hb_handle_s
     /* For MacGui active queue
        increments each time the scan thread completes*/
     int            scanCount;
+    volatile int   scan_die;
     
     /* Stash of persistent data between jobs, for stuff
        like correcting frame count and framerate estimates
@@ -379,6 +380,8 @@ void hb_scan( hb_handle_t * h, const char * path, int title_index,
 {
     hb_title_t * title;
 
+    h->scan_die = 0;
+
     /* Clean up from previous scan */
     hb_remove_previews( h );
     while( ( title = hb_list_item( h->list_title, 0 ) ) )
@@ -388,8 +391,9 @@ void hb_scan( hb_handle_t * h, const char * path, int title_index,
     }
 
     hb_log( "hb_scan: path=%s, title_index=%d", path, title_index );
-    h->scan_thread = hb_scan_init( h, path, title_index, h->list_title,
-                                   preview_count, store_previews );
+    h->scan_thread = hb_scan_init( h, &h->scan_die, path, title_index, 
+                                   h->list_title, preview_count, 
+                                   store_previews );
 }
 
 /**
@@ -1238,6 +1242,20 @@ void hb_stop( hb_handle_t * h )
 }
 
 /**
+ * Stops the conversion process.
+ * @param h Handle to hb_handle_t.
+ */
+void hb_scan_stop( hb_handle_t * h )
+{
+    h->scan_die = 1;
+
+    h->job_count = hb_count(h);
+    h->job_count_permanent = 0;
+
+    hb_resume( h );
+}
+
+/**
  * Returns the state of the conversion process.
  * @param h Handle to hb_handle_t.
  * @param s Handle to hb_state_t which to copy the state data.
@@ -1340,8 +1358,24 @@ static void thread_func( void * _h )
         {
             hb_thread_close( &h->scan_thread );
 
-            hb_log( "libhb: scan thread found %d valid title(s)",
-                    hb_list_count( h->list_title ) );
+            if ( h->scan_die )
+            {
+                hb_title_t * title;
+
+                hb_remove_previews( h );
+                while( ( title = hb_list_item( h->list_title, 0 ) ) )
+                {
+                    hb_list_rem( h->list_title, title );
+                    hb_title_close( &title );
+                }
+
+                hb_log( "hb_scan: canceled" );
+            }
+            else
+            {
+                hb_log( "libhb: scan thread found %d valid title(s)",
+                        hb_list_count( h->list_title ) );
+            }
             hb_lock( h->state_lock );
             h->state.state = HB_STATE_SCANDONE; //originally state.state
                        hb_unlock( h->state_lock );
index 234d4b5..04d87b2 100644 (file)
@@ -42,6 +42,7 @@ void          hb_dvd_set_dvdnav( int enable );
 void          hb_scan( hb_handle_t *, const char * path,
                        int title_index, int preview_count,
                        int store_previews );
+void          hb_scan_stop( hb_handle_t * );
 
 /* hb_get_titles()
    Returns the list of valid titles detected by the latest scan. */
index 9a03074..88c8ef9 100644 (file)
@@ -131,9 +131,10 @@ static inline void hb_buffer_swap_copy( hb_buffer_t *src, hb_buffer_t *dst )
  * Threads: update.c, scan.c, work.c, reader.c, muxcommon.c
  **********************************************************************/
 hb_thread_t * hb_update_init( int * build, char * version );
-hb_thread_t * hb_scan_init( hb_handle_t *, const char * path,
-                            int title_index, hb_list_t * list_title,
-                            int preview_count, int store_previews );
+hb_thread_t * hb_scan_init( hb_handle_t *, volatile int * die, 
+                            const char * path, int title_index, 
+                            hb_list_t * list_title, int preview_count, 
+                            int store_previews );
 hb_thread_t * hb_work_init( hb_list_t * jobs, int cpu_count,
                             volatile int * die, int * error, hb_job_t ** job );
 hb_thread_t  * hb_reader_init( hb_job_t * );
@@ -166,6 +167,16 @@ extern const hb_muxer_t hb_demux[];
 extern void decmetadata( hb_title_t *title );
 
 /***********************************************************************
+ * batch.c
+ **********************************************************************/
+typedef struct hb_batch_s hb_batch_t;
+
+hb_batch_t  * hb_batch_init( char * path );
+void          hb_batch_close( hb_batch_t ** _d );
+int           hb_batch_title_count( hb_batch_t * d );
+hb_title_t  * hb_batch_title_scan( hb_batch_t * d, int t );
+
+/***********************************************************************
  * dvd.c
  **********************************************************************/
 typedef union  hb_dvd_s hb_dvd_t;
index 0f3697f..47be2d7 100644 (file)
@@ -7,6 +7,12 @@
 #ifndef HB_PORTS_H
 #define HB_PORTS_H
 
+#if defined(_WIN32)
+#define DIR_SEP_STR "\\"
+#else
+#define DIR_SEP_STR "/"
+#endif
+
 /************************************************************************
  * Utils
  ***********************************************************************/
index 1dda826..94ee77e 100644 (file)
@@ -194,12 +194,20 @@ static void ReaderFunc( void * _r )
     int            chapter = -1;
     int            chapter_end = r->job->chapter_end;
 
-    if( !( r->dvd = hb_dvd_init( r->title->dvd ) ) )
+    if ( r->title->type == HB_DVD_TYPE )
     {
-        if ( !( r->stream = hb_stream_open( r->title->dvd, r->title ) ) )
-        {
-          return;
-        }
+        if ( !( r->dvd = hb_dvd_init( r->title->path ) ) )
+            return;
+    }
+    else if ( r->title->type == HB_STREAM_TYPE )
+    {
+        if ( !( r->stream = hb_stream_open( r->title->path, r->title ) ) )
+            return;
+    }
+    else
+    {
+        // Unknown type, should never happen
+        return;
     }
 
     if (r->dvd)
index 74cc52a..ea15fc5 100644 (file)
 
 typedef struct
 {
-    hb_handle_t * h;
+    hb_handle_t  * h;
+    volatile int * die;
 
-    char        * path;
-    int           title_index;
-    hb_list_t   * list_title;
+    char         * path;
+    int            title_index;
+    hb_list_t    * list_title;
 
-    hb_dvd_t    * dvd;
-       hb_stream_t * stream;
+    hb_dvd_t     * dvd;
+    hb_stream_t  * stream;
+    hb_batch_t   * batch;
        
-    int           preview_count;
-    int           store_previews;
+    int            preview_count;
+    int            store_previews;
 
 } hb_scan_t;
 
@@ -43,13 +45,15 @@ static const char *aspect_to_string( double aspect )
     return arstr;
 }
 
-hb_thread_t * hb_scan_init( hb_handle_t * handle, const char * path,
-                            int title_index, hb_list_t * list_title,
-                            int preview_count, int store_previews )
+hb_thread_t * hb_scan_init( hb_handle_t * handle, volatile int * die,
+                            const char * path, int title_index, 
+                            hb_list_t * list_title, int preview_count, 
+                            int store_previews )
 {
     hb_scan_t * data = calloc( sizeof( hb_scan_t ), 1 );
 
     data->h            = handle;
+    data->die          = die;
     data->path         = strdup( path );
     data->title_index  = title_index;
     data->list_title   = list_title;
@@ -91,6 +95,20 @@ static void ScanFunc( void * _data )
             }
         }
     }
+    else if ( ( data->batch = hb_batch_init( data->path ) ) )
+    {
+        /* Scan all titles */
+        for( i = 0; i < hb_batch_title_count( data->batch ); i++ )
+        {
+            hb_title_t * title;
+
+            title = hb_batch_title_scan( data->batch, i + 1 );
+            if ( title != NULL )
+            {
+                hb_list_add( data->list_title, title );
+            }
+        }
+    }
     else if ( (data->stream = hb_stream_open( data->path, 0 ) ) != NULL )
     {
         hb_list_add( data->list_title, hb_stream_title_scan( data->stream ) );
@@ -107,6 +125,10 @@ static void ScanFunc( void * _data )
         hb_state_t state;
         hb_audio_t * audio;
 
+        if ( *data->die )
+        {
+                       goto finish;
+        }
         title = hb_list_item( data->list_title, i );
 
 #define p state.param.scanning
@@ -202,6 +224,8 @@ static void ScanFunc( void * _data )
         job->mux = HB_MUX_MP4;
     }
 
+finish:
+
     if( data->dvd )
     {
         hb_dvd_close( &data->dvd );
@@ -210,6 +234,10 @@ static void ScanFunc( void * _data )
        {
                hb_stream_close(&data->stream);
        }
+    if( data->batch )
+    {
+        hb_batch_close( &data->batch );
+    }
     free( data->path );
     free( data );
     _data = NULL;
@@ -379,9 +407,13 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
 
     if (data->dvd)
     {
-      hb_dvd_start( data->dvd, title, 1 );
-      title->angle_count = hb_dvd_angle_count( data->dvd );
-      hb_log( "scan: title angle(s) %d", title->angle_count );
+        hb_dvd_start( data->dvd, title, 1 );
+        title->angle_count = hb_dvd_angle_count( data->dvd );
+        hb_log( "scan: title angle(s) %d", title->angle_count );
+    }
+    else if (data->batch)
+    {
+        data->stream = hb_stream_open( title->path, title );
     }
 
     for( i = 0; i < data->preview_count; i++ )
@@ -390,6 +422,10 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title )
         FILE * file_preview;
         char   filename[1024];
 
+        if ( *data->die )
+        {
+            return 0;
+        }
         if (data->dvd)
         {
           if( !hb_dvd_seek( data->dvd, (float) ( i + 1 ) / ( data->preview_count + 1.0 ) ) )
@@ -663,6 +699,11 @@ skip_preview:
             hb_buffer_close( &vid_buf );
     }
 
+    if ( data->batch && data->stream )
+    {
+        hb_stream_close( &data->stream );
+    }
+
     if ( npreviews )
     {
         // use the most common frame info for our final title dimensions
index ff593b2..da2e579 100644 (file)
@@ -652,6 +652,7 @@ hb_title_t * hb_stream_title_scan(hb_stream_t *stream)
 
     // 'Barebones Title'
     hb_title_t *aTitle = hb_title_init( stream->path, 0 );
+    aTitle->type = HB_STREAM_TYPE;
     aTitle->index = 1;
 
        // Copy part of the stream path to the title name
@@ -2702,6 +2703,7 @@ static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream )
 
     // 'Barebones Title'
     hb_title_t *title = hb_title_init( stream->path, 0 );
+    title->type = HB_STREAM_TYPE;
     title->index = 1;
 
        // Copy part of the stream path to the title name
index 2209b15..6bd9700 100644 (file)
@@ -125,7 +125,7 @@ void hb_display_job_info( hb_job_t * job )
     hb_log("job configuration:");
     hb_log( " * source");
     
-    hb_log( "   + %s", title->dvd );
+    hb_log( "   + %s", title->path );
 
     hb_log( "   + title %d, chapter(s) %d to %d", title->index,
             job->chapter_start, job->chapter_end );
index 07a0272..a9bce27 100644 (file)
@@ -279,6 +279,9 @@ BOOL                        fIsDragging;
 - (void) performScan:(NSString *) scanPath scanTitleNum: (int) scanTitleNum;
 - (IBAction) showNewScan: (id) sender;
 
+
+- (IBAction) cancelScanning:(id)sender;
+
 - (void)     updateUI: (NSTimer *) timer;
 - (void)     enableUI: (bool) enable;
 
index 7960b2d..bc9f4ac 100644 (file)
@@ -1100,9 +1100,33 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
         hb_state_t s;
         
         hb_get_state( fHandle, &s );
-        if (s.state == HB_STATE_SCANNING && ([ident isEqualToString: StartEncodingIdentifier] || [ident isEqualToString: AddToQueueIdentifier]))
-            return NO;
-        
+        if (s.state == HB_STATE_SCANNING)
+        {
+            
+            if ([ident isEqualToString: ChooseSourceIdentifier])
+            {
+                [toolbarItem setImage: [NSImage imageNamed: @"Stop"]];
+                [toolbarItem setLabel: @"Cancel Scan"];
+                [toolbarItem setPaletteLabel: @"Cancel Scanning"];
+                [toolbarItem setToolTip: @"Cancel Scanning Source"];
+                return YES;
+            }
+            
+            if ([ident isEqualToString: StartEncodingIdentifier] || [ident isEqualToString: AddToQueueIdentifier])
+                return NO;
+        }
+        else
+        {
+            if ([ident isEqualToString: ChooseSourceIdentifier])
+            {
+                [toolbarItem setImage: [NSImage imageNamed: @"Source"]];
+                [toolbarItem setLabel: @"Source"];
+                [toolbarItem setPaletteLabel: @"Source"];
+                [toolbarItem setToolTip: @"Choose Video Source"];
+                return YES;
+            }
+        }
+
         hb_get_state2( fQueueEncodeLibhb, &s );
         
         if (s.state == HB_STATE_WORKING || s.state == HB_STATE_MUXING)
@@ -1307,6 +1331,16 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
 /*Opens the source browse window, called from Open Source widgets */
 - (IBAction) browseSources: (id) sender
 {
+    
+    hb_state_t s;
+    hb_get_state( fHandle, &s );
+    if (s.state == HB_STATE_SCANNING)
+    {
+        [self cancelScanning:nil];
+        return;
+    }
+    
+    
     NSOpenPanel * panel;
        
     panel = [NSOpenPanel openPanel];
@@ -1368,7 +1402,7 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
             if ([[scanPath lastPathComponent] isEqualToString: @"VIDEO_TS"])
             {
                 /* If VIDEO_TS Folder is chosen, choose its parent folder for the source display name
-                 we have to use the title->dvd value so we get the proper name of the volume if a physical dvd is the source*/
+                 we have to use the title->path value so we get the proper name of the volume if a physical dvd is the source*/
                 displayTitlescanSourceName = [[scanPath stringByDeletingLastPathComponent] lastPathComponent];
             }
             else
@@ -1699,6 +1733,11 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
     }
 }
 
+- (IBAction) cancelScanning:(id)sender
+{
+    hb_scan_stop(fHandle);
+}
+
 - (IBAction) showNewScan:(id)sender
 {
     hb_list_t  * list;
@@ -1765,13 +1804,21 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
                 }
                 
                 [fSrcTitlePopUp addItemWithTitle: [NSString
-                                                   stringWithFormat: @"%d - %02dh%02dm%02ds",
-                                                   title->index, title->hours, title->minutes,
+                                                   stringWithFormat: @"%s %d - %02dh%02dm%02ds",
+                                                   title->name,title->index, title->hours, title->minutes,
                                                    title->seconds]];
             }
             
-            // Select the longuest title
-            [fSrcTitlePopUp selectItemAtIndex: indxpri];
+            /* if we are a stream, select the first title */
+            if (title->type == HB_STREAM_TYPE)
+            {
+                [fSrcTitlePopUp selectItemAtIndex: 0];
+            }
+            else
+            {
+                /* if not then select the longest title (dvd) */
+                [fSrcTitlePopUp selectItemAtIndex: indxpri];
+            }
             [self titlePopUpChanged:nil];
             
             SuccessfulScan = YES;
@@ -2075,7 +2122,7 @@ fWorkingCount = 0;
     [queueFileJob setObject:[NSNumber numberWithInt:2] forKey:@"Status"];
     /* Source and Destination Information */
     
-    [queueFileJob setObject:[NSString stringWithUTF8String: title->dvd] forKey:@"SourcePath"];
+    [queueFileJob setObject:[NSString stringWithUTF8String: title->path] forKey:@"SourcePath"];
     [queueFileJob setObject:[fSrcDVD2Field stringValue] forKey:@"SourceName"];
     [queueFileJob setObject:[NSNumber numberWithInt:title->index] forKey:@"TitleNumber"];
     [queueFileJob setObject:[NSNumber numberWithInt:[fSrcAnglePopUp indexOfSelectedItem] + 1] forKey:@"TitleAngle"];
@@ -4136,6 +4183,22 @@ bool one_burned = FALSE;
     hb_title_t * title = (hb_title_t*)
         hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
 
+    /* If we are a stream type, grok the output file name from title->name upon title change */
+    if (title->type == HB_STREAM_TYPE)
+    {
+        /* we set the default name according to the new title->name */
+        [fDstFile2Field setStringValue: [NSString stringWithFormat:
+                                         @"%@/%@.%@", [[fDstFile2Field stringValue] stringByDeletingLastPathComponent],
+                                         [NSString stringWithUTF8String: title->name],
+                                         [[fDstFile2Field stringValue] pathExtension]]];
+        /* If we have more than one title and are stream then we have a batch, change the source to read out the parent folder also */
+        if ( hb_list_count( list ) > 1 )
+        {                                  
+            [fSrcDVD2Field setStringValue:[NSString stringWithFormat:@"%@/%@", browsedSourceDisplayName,[NSString stringWithUTF8String: title->name]]];
+        }
+    }
+    
+    
     /* If Auto Naming is on. We create an output filename of dvd name - title number */
     if( [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultAutoNaming"] > 0 && ( hb_list_count( list ) > 1 ) )
        {
index ad21868..3d5e960 100644 (file)
@@ -378,9 +378,16 @@ static void PrintTitleInfo( hb_title_t * title )
     int i;
 
     fprintf( stderr, "+ title %d:\n", title->index );
-    fprintf( stderr, "  + vts %d, ttn %d, cells %d->%d (%d blocks)\n",
-             title->vts, title->ttn, title->cell_start, title->cell_end,
-             title->block_count );
+    if ( title->type == HB_STREAM_TYPE )
+    {
+        fprintf( stderr, "  + stream: %s\n", title->path );
+    }
+    else if ( title->type == HB_DVD_TYPE )
+    {
+        fprintf( stderr, "  + vts %d, ttn %d, cells %d->%d (%d blocks)\n",
+                title->vts, title->ttn, title->cell_start, title->cell_end,
+                title->block_count );
+    }
     if (dvdnav)
         fprintf( stderr, "  + angle(s) %d\n", title->angle_count );
     fprintf( stderr, "  + duration: %02d:%02d:%02d\n",