summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjstebbins <[email protected]>2009-11-25 21:14:44 +0000
committerjstebbins <[email protected]>2009-11-25 21:14:44 +0000
commit009238a822971a933d0b7642fd04c15bf8e404a2 (patch)
tree0979d88ba5116f4ad7e41f55bc7f93a1a82040b9
parent08483929dd5352012eb8b1f1143f138e3d5f19f0 (diff)
batch file scanning and scan cancel
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://svn.handbrake.fr/HandBrake/trunk@2980 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r--gtk/src/callbacks.c92
-rw-r--r--gtk/src/ghb.ui32
-rw-r--r--gtk/src/hb-backend.c75
-rw-r--r--gtk/src/hb-backend.h6
-rw-r--r--gtk/src/marshalers.h4
-rw-r--r--gtk/src/presets.c2
-rw-r--r--libhb/batch.c128
-rw-r--r--libhb/common.c46
-rw-r--r--libhb/common.h5
-rw-r--r--libhb/decmetadata.c2
-rw-r--r--libhb/dvd.c2
-rw-r--r--libhb/dvdnav.c1
-rw-r--r--libhb/hb.c42
-rw-r--r--libhb/hb.h1
-rw-r--r--libhb/internal.h17
-rw-r--r--libhb/ports.h6
-rw-r--r--libhb/reader.c18
-rw-r--r--libhb/scan.c69
-rw-r--r--libhb/stream.c2
-rw-r--r--libhb/work.c2
-rw-r--r--macosx/Controller.h3
-rw-r--r--macosx/Controller.m81
-rw-r--r--test/test.c13
23 files changed, 567 insertions, 82 deletions
diff --git a/gtk/src/callbacks.c b/gtk/src/callbacks.c
index 532ac697c..fb319b297 100644
--- a/gtk/src/callbacks.c
+++ b/gtk/src/callbacks.c
@@ -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);
}
}
diff --git a/gtk/src/ghb.ui b/gtk/src/ghb.ui
index e599233ec..f01283308 100644
--- a/gtk/src/ghb.ui
+++ b/gtk/src/ghb.ui
@@ -671,7 +671,7 @@
<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>
@@ -726,12 +726,12 @@
</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>
@@ -756,13 +756,30 @@
<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>
@@ -918,7 +935,7 @@
</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>
diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c
index 14db5b085..d0609836b 100644
--- a/gtk/src/hb-backend.c
+++ b/gtk/src/hb-backend.c
@@ -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;
}
diff --git a/gtk/src/hb-backend.h b/gtk/src/hb-backend.h
index ac5ea70c5..1ccb53eac 100644
--- a/gtk/src/hb-backend.h
+++ b/gtk/src/hb-backend.h
@@ -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);
diff --git a/gtk/src/marshalers.h b/gtk/src/marshalers.h
index 1034f926d..a5ae52491 100644
--- a/gtk/src/marshalers.h
+++ b/gtk/src/marshalers.h
@@ -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,
diff --git a/gtk/src/presets.c b/gtk/src/presets.c
index bac7bb895..687daba8f 100644
--- a/gtk/src/presets.c
+++ b/gtk/src/presets.c
@@ -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
index 000000000..f627df555
--- /dev/null
+++ b/libhb/batch.c
@@ -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;
+}
+
diff --git a/libhb/common.c b/libhb/common.c
index 357625528..ce983987f 100644
--- a/libhb/common.c
+++ b/libhb/common.c
@@ -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;
+ }
+}
+
diff --git a/libhb/common.h b/libhb/common.h
index b6c5e5714..a85beda01 100644
--- a/libhb/common.h
+++ b/libhb/common.h
@@ -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
diff --git a/libhb/decmetadata.c b/libhb/decmetadata.c
index e377f8c25..bd848a95a 100644
--- a/libhb/decmetadata.c
+++ b/libhb/decmetadata.c
@@ -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 )
{
diff --git a/libhb/dvd.c b/libhb/dvd.c
index fa5373e79..fbac84de4 100644
--- a/libhb/dvd.c
+++ b/libhb/dvd.c
@@ -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 ) ) )
{
diff --git a/libhb/dvdnav.c b/libhb/dvdnav.c
index 2f1ac93cc..84895caca 100644
--- a/libhb/dvdnav.c
+++ b/libhb/dvdnav.c
@@ -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 ) );
diff --git a/libhb/hb.c b/libhb/hb.c
index 34fe53b72..1b899e39c 100644
--- a/libhb/hb.c
+++ b/libhb/hb.c
@@ -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 );
diff --git a/libhb/hb.h b/libhb/hb.h
index 234d4b502..04d87b2be 100644
--- a/libhb/hb.h
+++ b/libhb/hb.h
@@ -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. */
diff --git a/libhb/internal.h b/libhb/internal.h
index 9a03074bf..88c8ef983 100644
--- a/libhb/internal.h
+++ b/libhb/internal.h
@@ -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;
diff --git a/libhb/ports.h b/libhb/ports.h
index 0f3697f0d..47be2d76e 100644
--- a/libhb/ports.h
+++ b/libhb/ports.h
@@ -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
***********************************************************************/
diff --git a/libhb/reader.c b/libhb/reader.c
index 1dda826d0..94ee77efb 100644
--- a/libhb/reader.c
+++ b/libhb/reader.c
@@ -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)
diff --git a/libhb/scan.c b/libhb/scan.c
index 74cc52adb..ea15fc512 100644
--- a/libhb/scan.c
+++ b/libhb/scan.c
@@ -12,17 +12,19 @@
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
diff --git a/libhb/stream.c b/libhb/stream.c
index ff593b2c7..da2e5791d 100644
--- a/libhb/stream.c
+++ b/libhb/stream.c
@@ -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
diff --git a/libhb/work.c b/libhb/work.c
index 2209b15f2..6bd9700f7 100644
--- a/libhb/work.c
+++ b/libhb/work.c
@@ -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 );
diff --git a/macosx/Controller.h b/macosx/Controller.h
index 07a027231..a9bce271f 100644
--- a/macosx/Controller.h
+++ b/macosx/Controller.h
@@ -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;
diff --git a/macosx/Controller.m b/macosx/Controller.m
index 7960b2d52..bc9f4acad 100644
--- a/macosx/Controller.m
+++ b/macosx/Controller.m
@@ -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 ) )
{
diff --git a/test/test.c b/test/test.c
index ad21868f4..3d5e960a9 100644
--- a/test/test.c
+++ b/test/test.c
@@ -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",