From 009238a822971a933d0b7642fd04c15bf8e404a2 Mon Sep 17 00:00:00 2001 From: jstebbins Date: Wed, 25 Nov 2009 21:14:44 +0000 Subject: 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 --- gtk/src/callbacks.c | 92 ++++++++++++++++++++++++++---------- gtk/src/ghb.ui | 32 ++++++++++--- gtk/src/hb-backend.c | 75 ++++++++++++++++++++++++++++-- gtk/src/hb-backend.h | 6 +++ gtk/src/marshalers.h | 4 +- gtk/src/presets.c | 2 +- libhb/batch.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++ libhb/common.c | 46 +++++++++++++++++- libhb/common.h | 5 +- libhb/decmetadata.c | 2 +- libhb/dvd.c | 2 + libhb/dvdnav.c | 1 + libhb/hb.c | 42 +++++++++++++++-- libhb/hb.h | 1 + libhb/internal.h | 17 +++++-- libhb/ports.h | 6 +++ libhb/reader.c | 18 ++++++-- libhb/scan.c | 69 +++++++++++++++++++++------ libhb/stream.c | 2 + libhb/work.c | 2 +- macosx/Controller.h | 3 ++ macosx/Controller.m | 81 ++++++++++++++++++++++++++++---- test/test.c | 13 ++++-- 23 files changed, 567 insertions(+), 82 deletions(-) create mode 100644 libhb/batch.c 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 @@ True - 6 + 2 True @@ -726,12 +726,12 @@ - + True + 6 6 - 6 - + True 4 @@ -756,13 +756,30 @@ 1 + + + + + False + 1 + + + + + True + 6 + 6 + + + True + 4 True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 0 0 - 8 + 0 True @@ -918,7 +935,7 @@ False - 1 + 2 @@ -6558,6 +6575,7 @@ libx264 authors: 5 True + GTK_FILE_CHOOSER_ACTION_OPEN dialog True True @@ -6610,7 +6628,7 @@ libx264 authors: - Open VIDEO_TS folder + Open folder (DVD or batch) True True False 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, @@ -2638,6 +2656,44 @@ ghb_build_x264opts_string(GValue *settings) return result; } +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) { @@ -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: . + 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 ); } /** @@ -1237,6 +1241,20 @@ void hb_stop( hb_handle_t * h ) hb_resume( 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. @@ -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 * ); @@ -165,6 +166,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 **********************************************************************/ 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", -- cgit v1.2.3