diff options
-rw-r--r-- | gtk/src/Makefile.am | 1 | ||||
-rw-r--r-- | gtk/src/audiohandler.c | 6 | ||||
-rw-r--r-- | gtk/src/callbacks.c | 176 | ||||
-rw-r--r-- | gtk/src/ghb.ui | 162 | ||||
-rw-r--r-- | gtk/src/hb-backend.c | 224 | ||||
-rw-r--r-- | gtk/src/hb-backend.h | 18 | ||||
-rw-r--r-- | gtk/src/internal_defaults.xml | 4 | ||||
-rw-r--r-- | gtk/src/main.c | 8 | ||||
-rw-r--r-- | gtk/src/preview.c | 697 | ||||
-rw-r--r-- | gtk/src/preview.h | 26 | ||||
-rw-r--r-- | gtk/src/resource_data.h | 245 | ||||
-rw-r--r-- | gtk/src/resources.plist | 166 | ||||
-rw-r--r-- | gtk/src/settings.h | 3 |
13 files changed, 1549 insertions, 187 deletions
diff --git a/gtk/src/Makefile.am b/gtk/src/Makefile.am index 4cae9d35f..b784a99ac 100644 --- a/gtk/src/Makefile.am +++ b/gtk/src/Makefile.am @@ -99,6 +99,7 @@ ghb_SOURCES = \ resources.h \ presets.c \ presets.h \ + preview.c \ icons.c \ icons.h \ icon_tools.c \ diff --git a/gtk/src/audiohandler.c b/gtk/src/audiohandler.c index eaf7f93e7..53c96919b 100644 --- a/gtk/src/audiohandler.c +++ b/gtk/src/audiohandler.c @@ -17,6 +17,7 @@ #include "hb-backend.h" #include "values.h" #include "callbacks.h" +#include "preview.h" #include "audiohandler.h" void @@ -332,6 +333,7 @@ audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud) } g_free(container); } + ghb_live_reset(ud); } void @@ -353,6 +355,7 @@ audio_track_changed_cb(GtkWidget *widget, signal_user_data_t *ud) track = ghb_settings_combo_option(asettings, "AudioTrack"); ghb_settings_set_string(asettings, "AudioTrackDescription", track); } + ghb_live_reset(ud); } void @@ -369,6 +372,7 @@ audio_mix_changed_cb(GtkWidget *widget, signal_user_data_t *ud) ghb_widget_to_setting(asettings, widget); audio_list_refresh_selected(ud); } + ghb_live_reset(ud); } void @@ -384,6 +388,7 @@ audio_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud) ghb_widget_to_setting(asettings, widget); audio_list_refresh_selected(ud); } + ghb_live_reset(ud); } // subtitles differ from other settings in that @@ -397,6 +402,7 @@ subtitle_changed_cb(GtkWidget *widget, signal_user_data_t *ud) g_debug("subtitle_changed_cb () %s", name); ghb_widget_to_setting(ud->settings, widget); ghb_check_dependency(ud, widget); + ghb_live_reset(ud); } void diff --git a/gtk/src/callbacks.c b/gtk/src/callbacks.c index e13b97de5..0b8ee4c90 100644 --- a/gtk/src/callbacks.c +++ b/gtk/src/callbacks.c @@ -35,6 +35,7 @@ #include "resources.h" #include "settings.h" #include "presets.h" +#include "preview.h" #include "values.h" #include "plist.h" #include "appcast.h" @@ -880,6 +881,7 @@ container_changed_cb(GtkWidget *widget, signal_user_data_t *ud) ghb_check_dependency(ud, widget); update_acodec_combo(ud); ghb_clear_presets_selection(ud); + ghb_live_reset(ud); audio_list = ghb_settings_get_value(ud->settings, "audio_list"); if (ghb_ac3_in_audio_list (audio_list)) @@ -1009,55 +1011,8 @@ show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo) gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo->num_chapters); } -static gint preview_button_width; -static gint preview_button_height; static gboolean update_preview = FALSE; -static void -set_preview_image(signal_user_data_t *ud) -{ - GtkWidget *widget; - gint preview_width, preview_height, target_height, width, height; - - g_debug("set_preview_button_image ()"); - gint titleindex; - - titleindex = ghb_settings_combo_int(ud->settings, "title"); - if (titleindex < 0) return; - widget = GHB_WIDGET (ud->builder, "preview_frame"); - gint frame = ghb_widget_int(widget) - 1; - GdkPixbuf *preview = ghb_get_preview_image (titleindex, frame, ud->settings, TRUE); - if (preview == NULL) return; - widget = GHB_WIDGET (ud->builder, "preview_image"); - gtk_image_set_from_pixbuf(GTK_IMAGE(widget), preview); - - preview_width = gdk_pixbuf_get_width(preview); - preview_height = gdk_pixbuf_get_height(preview); - gchar *text = g_strdup_printf("%d x %d", preview_width, preview_height); - widget = GHB_WIDGET (ud->builder, "preview_dims"); - gtk_label_set_text(GTK_LABEL(widget), text); - g_free(text); - - g_debug("preview %d x %d", preview_width, preview_height); - target_height = MIN(preview_button_height - 12, 128); - height = target_height; - width = preview_width * height / preview_height; - - if ((height >= 16) && (width >= 16)) - { - GdkPixbuf *scaled_preview; - scaled_preview = gdk_pixbuf_scale_simple (preview, width, height, GDK_INTERP_NEAREST); - if (scaled_preview != NULL) - { - g_object_unref (preview); - - widget = GHB_WIDGET (ud->builder, "preview_button_image"); - gtk_image_set_from_pixbuf(GTK_IMAGE(widget), scaled_preview); - g_object_unref (scaled_preview); - } - } -} - void title_changed_cb(GtkWidget *widget, signal_user_data_t *ud) { @@ -1092,7 +1047,7 @@ title_changed_cb(GtkWidget *widget, signal_user_data_t *ud) // control range here. ghb_ui_update(ud, "preview_frame", ghb_int64_value(1)); - set_preview_image (ud); + ghb_set_preview_image (ud); } void @@ -1101,6 +1056,7 @@ setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud) ghb_widget_to_setting(ud->settings, widget); ghb_check_dependency(ud, widget); ghb_clear_presets_selection(ud); + ghb_live_reset(ud); } static void @@ -1162,6 +1118,7 @@ http_opt_changed_cb(GtkWidget *widget, signal_user_data_t *ud) ghb_widget_to_setting(ud->settings, widget); ghb_check_dependency(ud, widget); ghb_clear_presets_selection(ud); + ghb_live_reset(ud); // AC3 is not allowed when Web optimized ghb_grey_combo_options (ud->builder); } @@ -1176,6 +1133,7 @@ vcodec_changed_cb(GtkWidget *widget, signal_user_data_t *ud) ghb_widget_to_setting(ud->settings, widget); ghb_check_dependency(ud, widget); ghb_clear_presets_selection(ud); + ghb_live_reset(ud); ghb_vquality_range(ud, &vqmin, &vqmax, &step, &page, &digits); GtkWidget *qp = GHB_WIDGET(ud->builder, "VideoQualitySlider"); gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax); @@ -1196,6 +1154,7 @@ target_size_changed_cb(GtkWidget *widget, signal_user_data_t *ud) ghb_widget_to_setting(ud->settings, widget); ghb_check_dependency(ud, widget); ghb_clear_presets_selection(ud); + ghb_live_reset(ud); if (ghb_settings_get_boolean(ud->settings, "vquality_type_target")) { gint titleindex; @@ -1258,6 +1217,7 @@ scale_width_changed_cb(GtkWidget *widget, signal_user_data_t *ud) text = g_strdup_printf ("%d x %d", width, height); gtk_label_set_text (GTK_LABEL(widget), text); g_free(text); + ghb_live_reset(ud); } void @@ -1275,6 +1235,7 @@ scale_height_changed_cb(GtkWidget *widget, signal_user_data_t *ud) text = g_strdup_printf ("%d x %d", width, height); gtk_label_set_text (GTK_LABEL(widget), text); g_free(text); + ghb_live_reset(ud); } void @@ -1311,6 +1272,7 @@ crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud) gtk_label_set_text (GTK_LABEL(widget), text); g_free(text); update_preview = TRUE; + ghb_live_reset(ud); } void @@ -1320,6 +1282,7 @@ scale_changed_cb(GtkWidget *widget, signal_user_data_t *ud) ghb_widget_to_setting(ud->settings, widget); ghb_check_dependency(ud, widget); ghb_clear_presets_selection(ud); + ghb_live_reset(ud); ghb_set_scale (ud, GHB_SCALE_KEEP_NONE); update_preview = TRUE; @@ -1467,6 +1430,7 @@ prune_logs(signal_user_data_t *ud) g_dir_close(gdir); } g_free(dest_dir); + ghb_preview_cleanup(ud); } static void @@ -1612,7 +1576,7 @@ find_queue_job(GValue *queue, gint unique_id, GValue **job) } gchar* -working_status_string(signal_user_data_t *ud, ghb_status_t *status) +working_status_string(signal_user_data_t *ud, ghb_instance_status_t *status) { gchar *task_str, *job_str, *status_str; gint qcount; @@ -1680,26 +1644,26 @@ ghb_backend_events(signal_user_data_t *ud) progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar")); // First handle the status of title scans // Then handle the status of the queue - if (status.state & GHB_STATE_SCANNING) + if (status.scan.state & GHB_STATE_SCANNING) { - if (status.title_cur == 0) + if (status.scan.title_cur == 0) { status_str = g_strdup ("Scanning..."); } else { status_str = g_strdup_printf ("Scanning title %d of %d...", - status.title_cur, status.title_count ); + status.scan.title_cur, status.scan.title_count ); } gtk_progress_bar_set_text (progress, status_str); g_free(status_str); - if (status.title_count > 0) + if (status.scan.title_count > 0) { gtk_progress_bar_set_fraction (progress, - (gdouble)status.title_cur / status.title_count); + (gdouble)status.scan.title_cur / status.scan.title_count); } } - else if (status.state & GHB_STATE_SCANDONE) + else if (status.scan.state & GHB_STATE_SCANDONE) { status_str = g_strdup_printf ("Scan done"); gtk_progress_bar_set_text (progress, status_str); @@ -1720,7 +1684,7 @@ ghb_backend_events(signal_user_data_t *ud) gtk_progress_bar_set_fraction (progress, 0); gtk_progress_bar_set_text (progress, "No Source"); } - ghb_clear_state(GHB_STATE_SCANDONE); + ghb_clear_scan_state(GHB_STATE_SCANDONE); ghb_queue_buttons_grey(ud, work_started); if (ghb_queue_edit_settings) { @@ -1736,43 +1700,43 @@ ghb_backend_events(signal_user_data_t *ud) ghb_queue_edit_settings = NULL; } } - else if (status.queue_state & GHB_STATE_SCANNING) + else if (status.queue.state & GHB_STATE_SCANNING) { status_str = g_strdup_printf ("Scanning ..."); gtk_progress_bar_set_text (progress, status_str); g_free(status_str); gtk_progress_bar_set_fraction (progress, 0); } - else if (status.queue_state & GHB_STATE_SCANDONE) + else if (status.queue.state & GHB_STATE_SCANDONE) { ghb_clear_queue_state(GHB_STATE_SCANDONE); submit_job(ud->current_job); } - else if (status.queue_state & GHB_STATE_PAUSED) + else if (status.queue.state & GHB_STATE_PAUSED) { status_str = g_strdup_printf ("Paused"); gtk_progress_bar_set_text (progress, status_str); g_free(status_str); } - else if (status.queue_state & GHB_STATE_WORKING) + else if (status.queue.state & GHB_STATE_WORKING) { - status_str = working_status_string(ud, &status); + status_str = working_status_string(ud, &status.queue); gtk_progress_bar_set_text (progress, status_str); - gtk_progress_bar_set_fraction (progress, status.progress); + gtk_progress_bar_set_fraction (progress, status.queue.progress); g_free(status_str); } - else if (status.queue_state & GHB_STATE_WORKDONE) + else if (status.queue.state & GHB_STATE_WORKDONE) { gint qstatus; work_started = FALSE; ghb_queue_buttons_grey(ud, FALSE); - index = find_queue_job(ud->queue, status.unique_id, &js); + index = find_queue_job(ud->queue, status.queue.unique_id, &js); treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list")); store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview)); if (ud->cancel_encode) - status.error = GHB_ERROR_CANCELED; - switch( status.error ) + status.queue.error = GHB_ERROR_CANCELED; + switch( status.queue.error ) { case GHB_ERROR_NONE: gtk_progress_bar_set_text( progress, "Rip done!" ); @@ -1829,11 +1793,11 @@ ghb_backend_events(signal_user_data_t *ud) g_io_channel_unref(ud->job_activity_log); ud->job_activity_log = NULL; } - else if (status.queue_state & GHB_STATE_MUXING) + else if (status.queue.state & GHB_STATE_MUXING) { gtk_progress_bar_set_text(progress, "Muxing: this may take awhile..."); } - if (status.queue_state & GHB_STATE_SCANNING) + if (status.queue.state & GHB_STATE_SCANNING) { // This needs to be in scanning and working since scanning // happens fast enough that it can be missed @@ -1843,7 +1807,7 @@ ghb_backend_events(signal_user_data_t *ud) ghb_queue_buttons_grey(ud, TRUE); } } - if (status.queue_state & GHB_STATE_WORKING) + if (status.queue.state & GHB_STATE_WORKING) { // This needs to be in scanning and working since scanning // happens fast enough that it can be missed @@ -1852,8 +1816,8 @@ ghb_backend_events(signal_user_data_t *ud) work_started = TRUE; ghb_queue_buttons_grey(ud, TRUE); } - index = find_queue_job(ud->queue, status.unique_id, &js); - if (status.unique_id != 0 && index >= 0) + index = find_queue_job(ud->queue, status.queue.unique_id, &js); + if (status.queue.unique_id != 0 && index >= 0) { gchar working_icon[] = "hb-working0"; working_icon[10] = '0' + working; @@ -1871,11 +1835,36 @@ ghb_backend_events(signal_user_data_t *ud) GtkLabel *label; gchar *status_str; - status_str = working_status_string(ud, &status); + status_str = working_status_string(ud, &status.queue); label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_status")); gtk_label_set_text (label, status_str); g_free(status_str); } + if (status.scan.state & GHB_STATE_WORKING) + { + GtkProgressBar *live_progress; + live_progress = GTK_PROGRESS_BAR( + GHB_WIDGET(ud->builder, "live_encode_progress")); + status_str = working_status_string(ud, &status.scan); + gtk_progress_bar_set_text (live_progress, status_str); + gtk_progress_bar_set_fraction (live_progress, status.scan.progress); + g_free(status_str); + } + if (status.scan.state & GHB_STATE_WORKDONE) + { + switch( status.scan.error ) + { + case GHB_ERROR_NONE: + { + ghb_live_encode_done(ud, TRUE); + } break; + default: + { + ghb_live_encode_done(ud, FALSE); + } break; + } + ghb_clear_scan_state(GHB_STATE_WORKDONE); + } } gboolean @@ -1883,6 +1872,7 @@ ghb_timer_cb(gpointer data) { signal_user_data_t *ud = (signal_user_data_t*)data; + ghb_live_preview_progress(ud); ghb_backend_events(ud); if (update_default_destination) { @@ -1902,7 +1892,7 @@ ghb_timer_cb(gpointer data) } if (update_preview) { - set_preview_image (ud); + ghb_set_preview_image (ud); update_preview = FALSE; } return TRUE; @@ -2255,42 +2245,6 @@ chapter_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_ } void -preview_button_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud) -{ - gint titleindex; - - titleindex = ghb_settings_combo_int(ud->settings, "title"); - if (titleindex < 0) return; - g_debug("titleindex %d", titleindex); - - GtkWidget *widget = GHB_WIDGET (ud->builder, "preview_window"); - gtk_widget_show (widget); -} - -void -preview_frame_value_changed_cb(GtkWidget *widget, signal_user_data_t *ud) -{ - set_preview_image(ud); -} - -void -preview_button_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud) -{ - g_debug("-------------------------------allocate %d x %d", allocation->width, allocation->height); - if (preview_button_width == allocation->width && - preview_button_height == allocation->height) - { - // Nothing to do. Bug out. - g_debug("nothing to do"); - return; - } - g_debug("-------------------------------prev allocate %d x %d", preview_button_width, preview_button_height); - preview_button_width = allocation->width; - preview_button_height = allocation->height; - set_preview_image(ud); -} - -void debug_log_handler(const gchar *domain, GLogLevelFlags flags, const gchar *msg, gpointer data) { signal_user_data_t *ud = (signal_user_data_t*)data; @@ -2512,9 +2466,10 @@ void drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud) { gchar *device; - gint state = ghb_get_state(); + gint state = ghb_get_scan_state(); static gboolean first_time = TRUE; + if (state != GHB_STATE_IDLE) return; if (ud->current_dvd_device == NULL) return; // A drive change event happens when the program initially starts // and I don't want to automatically scan at that time. @@ -2523,7 +2478,6 @@ drive_changed_cb(GVolumeMonitor *gvm, GDrive *gd, signal_user_data_t *ud) first_time = FALSE; return; } - if (state != GHB_STATE_IDLE) return; device = g_drive_get_identifier(gd, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE); // DVD insertion detected. Scan it. diff --git a/gtk/src/ghb.ui b/gtk/src/ghb.ui index d278f77d8..3e3e75fcc 100644 --- a/gtk/src/ghb.ui +++ b/gtk/src/ghb.ui @@ -161,6 +161,13 @@ <property name="page_size">0</property> <property name="value">0</property> </object> + <object class="GtkAdjustment" id="preview_progress_adj"> + <property name="upper">100</property> + <property name="lower">0</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + <property name="value">0</property> + </object> <object class="GtkUIManager" id="uimanager1"> <child> <object class="GtkActionGroup" id="actiongroup1"> @@ -545,6 +552,7 @@ </child> <child> <object class="GtkComboBox" id="title"> + <property name="height_request">16</property> <property name="width_request">150</property> <property name="visible">True</property> <property name="has_frame">False</property> @@ -3168,6 +3176,7 @@ no-fast-pskip=0:no-dct-decimate=0:cabac=1</property> </child> <child> <object class="GtkProgressBar" id="progressbar"> + <property name="height_request">16</property> <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="text" translatable="yes"/> @@ -4044,9 +4053,76 @@ location as the movie.</property> <property name="left_padding">12</property> <property name="right_padding">4</property> <child> - <object class="GtkImage" id="preview_image"> + <object class="GtkTable" id="table1"> <property name="visible">True</property> - <property name="icon_name">hb-icon</property> + <property name="n_rows">3</property> + <property name="n_columns">3</property> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <object class="GtkLabel" id="label45"> + <property name="visible">True</property> + </object> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label44"> + <property name="visible">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label43"> + <property name="visible">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label42"> + <property name="visible">True</property> + </object> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> + <child> + <object class="GtkDrawingArea" id="preview_image"> + <property name="visible">True</property> + <property name="app_paintable">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> </object> </child> </object> @@ -4061,6 +4137,86 @@ location as the movie.</property> </object> </child> <child> + <object class="GtkHBox" id="hbox7"> + <property name="visible">True</property> + <child> + <object class="GtkButton" id="live_preview_play"> + <property name="height_request">30</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="relief">none</property> + <signal handler="live_preview_start_cb" name="clicked"/> + <child> + <object class="GtkImage" id="live_preview_play_image"> + <property name="visible">True</property> + <property name="stock">gtk-media-play</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHScale" id="live_preview_progress"> + <property name="visible">False</property> + <property name="can_focus">True</property> + <property name="adjustment">preview_progress_adj</property> + <property name="draw_value">False</property> + <property name="value_pos">right</property> + <signal handler="live_preview_seek_cb" name="value_changed"/> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="live_progress_box"> + <property name="visible">True</property> + <child> + <object class="GtkLabel" id="label1"> + <property name="height_request">1</property> + <property name="visible">True</property> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkProgressBar" id="live_encode_progress"> + <property name="height_request">16</property> + <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="text" translatable="yes"></property> + </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label2"> + <property name="height_request">1</property> + <property name="visible">True</property> + </object> + <packing> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + <child> <object class="GtkHBox" id="hbox8"> <property name="visible">True</property> <child> @@ -4529,7 +4685,7 @@ the other to maintain the video's original aspect ratio.</property> </object> <packing> <property name="expand">False</property> - <property name="position">1</property> + <property name="position">2</property> </packing> </child> </object> diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c index 3bc95e3ba..5c8741411 100644 --- a/gtk/src/hb-backend.c +++ b/gtk/src/hb-backend.c @@ -840,6 +840,15 @@ static hb_handle_t * h_queue = NULL; extern void hb_get_tempory_directory(hb_handle_t *h, char path[512]); +gchar* +ghb_get_tmp_dir() +{ + char dir[512]; + + hb_get_tempory_directory(h_scan, dir); + return g_strdup(dir); +} + void ghb_hb_cleanup(gboolean partial) { @@ -1990,11 +1999,11 @@ void ghb_backend_scan(const gchar *path, gint titleindex) { hb_scan( h_scan, path, titleindex ); - hb_status.state |= GHB_STATE_SCANNING; + hb_status.scan.state |= GHB_STATE_SCANNING; // initialize count and cur to something that won't cause FPE // when computing progress - hb_status.title_count = 1; - hb_status.title_cur = 0; + hb_status.scan.title_count = 1; + hb_status.scan.title_cur = 0; } void @@ -2002,43 +2011,43 @@ ghb_backend_queue_scan(const gchar *path, gint titlenum) { g_debug("ghb_backend_queue_scan()"); hb_scan( h_queue, path, titlenum ); - hb_status.queue_state |= GHB_STATE_SCANNING; + hb_status.queue.state |= GHB_STATE_SCANNING; } gint -ghb_get_state() +ghb_get_scan_state() { - return hb_status.state; + return hb_status.scan.state; } gint ghb_get_queue_state() { - return hb_status.queue_state; + return hb_status.queue.state; } void -ghb_clear_state(gint state) +ghb_clear_scan_state(gint state) { - hb_status.state &= ~state; + hb_status.scan.state &= ~state; } void ghb_clear_queue_state(gint state) { - hb_status.queue_state &= ~state; + hb_status.queue.state &= ~state; } void -ghb_set_state(gint state) +ghb_set_scan_state(gint state) { - hb_status.state |= state; + hb_status.scan.state |= state; } void ghb_set_queue_state(gint state) { - hb_status.queue_state |= state; + hb_status.queue.state |= state; } void @@ -2050,66 +2059,125 @@ ghb_get_status(ghb_status_t *status) void ghb_track_status() { - hb_state_t s; + hb_state_t s_scan; hb_state_t s_queue; if (h_scan == NULL) return; - hb_get_state( h_scan, &s ); - switch( s.state ) + hb_get_state( h_scan, &s_scan ); + switch( s_scan.state ) { -#define p s.param.scanning +#define p s_scan.param.scanning case HB_STATE_SCANNING: { - hb_status.state |= GHB_STATE_SCANNING; - hb_status.title_count = p.title_count; - hb_status.title_cur = p.title_cur; + hb_status.scan.state |= GHB_STATE_SCANNING; + hb_status.scan.title_count = p.title_count; + hb_status.scan.title_cur = p.title_cur; } break; #undef p case HB_STATE_SCANDONE: { - hb_status.state &= ~GHB_STATE_SCANNING; - hb_status.state |= GHB_STATE_SCANDONE; + hb_status.scan.state &= ~GHB_STATE_SCANNING; + hb_status.scan.state |= GHB_STATE_SCANDONE; + } break; + +#define p s_scan.param.working + case HB_STATE_WORKING: + hb_status.scan.state |= GHB_STATE_WORKING; + hb_status.scan.state &= ~GHB_STATE_PAUSED; + hb_status.scan.job_cur = p.job_cur; + hb_status.scan.job_count = p.job_count; + hb_status.scan.progress = p.progress; + hb_status.scan.rate_cur = p.rate_cur; + hb_status.scan.rate_avg = p.rate_avg; + hb_status.scan.hours = p.hours; + hb_status.scan.minutes = p.minutes; + hb_status.scan.seconds = p.seconds; + hb_status.scan.unique_id = p.sequence_id & 0xFFFFFF; + break; +#undef p + + case HB_STATE_PAUSED: + hb_status.scan.state |= GHB_STATE_PAUSED; + break; + + case HB_STATE_MUXING: + { + hb_status.scan.state |= GHB_STATE_MUXING; } break; +#define p s_scan.param.workdone + case HB_STATE_WORKDONE: + { + hb_job_t *job; + + hb_status.scan.state |= GHB_STATE_WORKDONE; + hb_status.scan.state &= ~GHB_STATE_MUXING; + hb_status.scan.state &= ~GHB_STATE_PAUSED; + hb_status.scan.state &= ~GHB_STATE_WORKING; + switch (p.error) + { + case HB_ERROR_NONE: + hb_status.scan.error = GHB_ERROR_NONE; + break; + case HB_ERROR_CANCELED: + hb_status.scan.error = GHB_ERROR_CANCELED; + break; + default: + hb_status.scan.error = GHB_ERROR_FAIL; + break; + } + // Delete all remaining jobs of this encode. + // An encode can be composed of multiple associated jobs. + // When a job is stopped, libhb removes it from the job list, + // but does not remove other jobs that may be associated with it. + // Associated jobs are taged in the sequence id. + while ((job = hb_job(h_scan, 0)) != NULL) + hb_rem( h_scan, job ); + } break; +#undef p } hb_get_state( h_queue, &s_queue ); switch( s_queue.state ) { +#define p s_queue.param.scanning case HB_STATE_SCANNING: { - hb_status.queue_state |= GHB_STATE_SCANNING; + hb_status.queue.state |= GHB_STATE_SCANNING; + hb_status.queue.title_count = p.title_count; + hb_status.queue.title_cur = p.title_cur; } break; +#undef p case HB_STATE_SCANDONE: { - hb_status.queue_state &= ~GHB_STATE_SCANNING; - hb_status.queue_state |= GHB_STATE_SCANDONE; + hb_status.queue.state &= ~GHB_STATE_SCANNING; + hb_status.queue.state |= GHB_STATE_SCANDONE; } break; #define p s_queue.param.working case HB_STATE_WORKING: - hb_status.queue_state |= GHB_STATE_WORKING; - hb_status.queue_state &= ~GHB_STATE_PAUSED; - hb_status.job_cur = p.job_cur; - hb_status.job_count = p.job_count; - hb_status.progress = p.progress; - hb_status.rate_cur = p.rate_cur; - hb_status.rate_avg = p.rate_avg; - hb_status.hours = p.hours; - hb_status.minutes = p.minutes; - hb_status.seconds = p.seconds; - hb_status.unique_id = p.sequence_id & 0xFFFFFF; + hb_status.queue.state |= GHB_STATE_WORKING; + hb_status.queue.state &= ~GHB_STATE_PAUSED; + hb_status.queue.job_cur = p.job_cur; + hb_status.queue.job_count = p.job_count; + hb_status.queue.progress = p.progress; + hb_status.queue.rate_cur = p.rate_cur; + hb_status.queue.rate_avg = p.rate_avg; + hb_status.queue.hours = p.hours; + hb_status.queue.minutes = p.minutes; + hb_status.queue.seconds = p.seconds; + hb_status.queue.unique_id = p.sequence_id & 0xFFFFFF; break; #undef p case HB_STATE_PAUSED: - hb_status.queue_state |= GHB_STATE_PAUSED; + hb_status.queue.state |= GHB_STATE_PAUSED; break; case HB_STATE_MUXING: { - hb_status.queue_state |= GHB_STATE_MUXING; + hb_status.queue.state |= GHB_STATE_MUXING; } break; #define p s_queue.param.workdone @@ -2117,20 +2185,22 @@ ghb_track_status() { hb_job_t *job; - hb_status.queue_state |= GHB_STATE_WORKDONE; - hb_status.queue_state &= ~GHB_STATE_MUXING; - hb_status.queue_state &= ~GHB_STATE_PAUSED; - hb_status.queue_state &= ~GHB_STATE_WORKING; + hb_status.queue.state |= GHB_STATE_WORKDONE; + hb_status.queue.state &= ~GHB_STATE_MUXING; + hb_status.queue.state &= ~GHB_STATE_PAUSED; + hb_status.queue.state &= ~GHB_STATE_WORKING; switch (p.error) { case HB_ERROR_NONE: - hb_status.error = GHB_ERROR_NONE; + hb_status.queue.error = GHB_ERROR_NONE; + break; case HB_ERROR_CANCELED: - hb_status.error = GHB_ERROR_CANCELED; + hb_status.queue.error = GHB_ERROR_CANCELED; + break; default: - hb_status.error = GHB_ERROR_FAIL; + hb_status.queue.error = GHB_ERROR_FAIL; + break; } - hb_status.error = p.error; // Delete all remaining jobs of this encode. // An encode can be composed of multiple associated jobs. // When a job is stopped, libhb removes it from the job list, @@ -2320,8 +2390,8 @@ ghb_set_scale(signal_user_data_t *ud, gint mode) { width = crop_width; height = crop_height; - max_width = 0; //crop_width; - max_height = 0; //crop_height; + max_width = 0; + max_height = 0; } else { @@ -2864,8 +2934,8 @@ ghb_validate_vquality(GValue *settings) return TRUE; } -void -ghb_add_job(GValue *js, gint unique_id) +static void +add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex) { hb_list_t * list; hb_title_t * title; @@ -2880,19 +2950,15 @@ ghb_add_job(GValue *js, gint unique_id) gchar *denoise_str = NULL; gchar *dest_str = NULL; - g_debug("ghb_add_job()\n"); - if (h_queue == NULL) return; - list = hb_get_titles( h_queue ); + g_debug("add_job()\n"); + if (h == NULL) return; + list = hb_get_titles( h ); if( !hb_list_count( list ) ) { /* No valid title, stop right there */ return; } - // Since I'm doing a scan of the single title I want just prior - // to adding the job, there is only the one title to choose from. - //gint titleindex = ghb_settings_get_int(js, "title"); - gint titleindex = 0; title = hb_list_item( list, titleindex ); if (title == NULL) return; @@ -2900,6 +2966,12 @@ ghb_add_job(GValue *js, gint unique_id) job = title->job; if (job == NULL) return; + job->start_at_preview = ghb_settings_get_int(js, "start_frame") + 1; + if (job->start_at_preview) + { + job->pts_to_stop = ghb_settings_get_int(js, "live_duration") * 90000LL; + } + tweaks = ghb_settings_get_boolean(js, "allow_tweaks"); job->mux = ghb_settings_combo_int(js, "FileFormat"); if (job->mux == HB_MUX_MP4) @@ -3138,6 +3210,7 @@ ghb_add_job(GValue *js, gint unique_id) } else { +printf("switching to faac\n"); audio.out.codec = HB_ACODEC_FAAC; } } @@ -3269,7 +3342,7 @@ ghb_add_job(GValue *js, gint unique_id) * Add the pre-scan job */ job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24); - hb_add( h_queue, job ); + hb_add( h, job ); //if (job->x264opts != NULL) // g_free(job->x264opts); @@ -3322,7 +3395,7 @@ ghb_add_job(GValue *js, gint unique_id) job->x264opts = x264opts; } job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24); - hb_add( h_queue, job ); + hb_add( h, job ); //if (job->x264opts != NULL) // g_free(job->x264opts); @@ -3337,7 +3410,7 @@ ghb_add_job(GValue *js, gint unique_id) job->indepth_scan = 0; job->x264opts = x264opts2; job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24); - hb_add( h_queue, job ); + hb_add( h, job ); //if (job->x264opts != NULL) // g_free(job->x264opts); } @@ -3346,7 +3419,7 @@ ghb_add_job(GValue *js, gint unique_id) job->indepth_scan = 0; job->pass = 0; job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24); - hb_add( h_queue, job ); + hb_add( h, job ); //if (job->x264opts != NULL) // g_free(job->x264opts); } @@ -3359,6 +3432,23 @@ ghb_add_job(GValue *js, gint unique_id) } void +ghb_add_job(GValue *js, gint unique_id) +{ + // Since I'm doing a scan of the single title I want just prior + // to adding the job, there is only the one title to choose from. + add_job(h_queue, js, unique_id, 0); +} + +void +ghb_add_live_job(GValue *js, gint unique_id) +{ + // Since I'm doing a scan of the single title I want just prior + // to adding the job, there is only the one title to choose from. + gint titleindex = ghb_settings_combo_int(js, "title"); + add_job(h_scan, js, unique_id, titleindex); +} + +void ghb_remove_job(gint unique_id) { hb_job_t * job; @@ -3388,6 +3478,18 @@ ghb_stop_queue() } void +ghb_start_live_encode() +{ + hb_start( h_scan ); +} + +void +ghb_stop_live_encode() +{ + hb_stop( h_scan ); +} + +void ghb_pause_queue() { hb_state_t s; diff --git a/gtk/src/hb-backend.h b/gtk/src/hb-backend.h index 48e85a966..16165d61b 100644 --- a/gtk/src/hb-backend.h +++ b/gtk/src/hb-backend.h @@ -26,10 +26,9 @@ enum GHB_ERROR_FAIL, }; -typedef struct ghb_status_s +typedef struct { gint state; - gint queue_state; // SCANNING gint title_count; @@ -46,6 +45,12 @@ typedef struct ghb_status_s gint minutes; gint seconds; gint error; +} ghb_instance_status_t; + +typedef struct +{ + ghb_instance_status_t scan; + ghb_instance_status_t queue; } ghb_status_t; #define GHB_SCALE_KEEP_NONE 0 @@ -96,11 +101,15 @@ void ghb_start_queue(void); void ghb_stop_queue(void); void ghb_pause_queue(void); -gint ghb_get_state(void); -void ghb_clear_state(gint state); +void ghb_add_live_job(GValue *js, gint unique_id); +void ghb_start_live_encode(); +void ghb_stop_live_encode(); + +void ghb_clear_scan_state(gint state); void ghb_clear_queue_state(gint state); void ghb_set_state(gint state); +gint ghb_get_scan_state(); gint ghb_get_queue_state(); void ghb_get_status(ghb_status_t *status); void ghb_track_status(void); @@ -137,5 +146,6 @@ gboolean ghb_validate_filter_string(const gchar *str, gint max_fields); void ghb_hb_cleanup(gboolean partial); gint ghb_lookup_combo_int(const gchar *name, const GValue *acodec); const gchar* ghb_lookup_combo_option(const gchar *name, const GValue *acodec); +gchar* ghb_get_tmp_dir(); #endif // _HBBACKEND_H_ diff --git a/gtk/src/internal_defaults.xml b/gtk/src/internal_defaults.xml index 143223cfd..be0d9e519 100644 --- a/gtk/src/internal_defaults.xml +++ b/gtk/src/internal_defaults.xml @@ -12,6 +12,8 @@ <integer>100</integer> <key>folder</key> <string></string> + <key>live_duration</key> + <integer>15</integer> <key>preset</key> <array> <string>Normal</string> @@ -30,6 +32,8 @@ <integer>0</integer> <key>start_chapter</key> <integer>1</integer> + <key>start_frame</key> + <integer>-1</integer> <key>title</key> <string>none</string> <key>volume_label</key> diff --git a/gtk/src/main.c b/gtk/src/main.c index 08d7ff1a3..061364b02 100644 --- a/gtk/src/main.c +++ b/gtk/src/main.c @@ -33,6 +33,7 @@ #include <config.h> #include <gtk/gtk.h> +#include <gst/gst.h> #include <glib/gstdio.h> #include <gio/gio.h> #include "hbversion.h" @@ -47,6 +48,7 @@ #include "settings.h" #include "resources.h" #include "presets.h" +#include "preview.h" /* @@ -491,6 +493,7 @@ main (int argc, char *argv[]) GValue *preset; GError *error = NULL; GOptionContext *context; + GtkWidget *widget; mm_flags = mm_support(); #ifdef ENABLE_NLS @@ -499,9 +502,12 @@ main (int argc, char *argv[]) textdomain (GETTEXT_PACKAGE); #endif + if (!g_thread_supported()) + g_thread_init(NULL); context = g_option_context_new ("- Rip and encode DVD or MPEG file"); g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); g_option_context_add_group (context, gtk_get_option_group (TRUE)); + g_option_context_add_group (context, gst_init_get_option_group ()); g_option_context_parse (context, &argc, &argv, &error); g_option_context_free(context); @@ -523,6 +529,7 @@ main (int argc, char *argv[]) watch_volumes (ud); ud->builder = create_builder_or_die (BUILDER_NAME); // Redirect stderr to the activity window + ghb_preview_init(ud); IoRedirect(ud); ghb_log("Handbrake Version: %s (%d)", HB_VERSION, HB_BUILD); ghb_init_dep_map(); @@ -567,7 +574,6 @@ main (int argc, char *argv[]) ghb_hbfd(ud, TRUE); } gboolean tweaks = ghb_settings_get_boolean(ud->settings, "allow_tweaks"); - GtkWidget *widget; widget = GHB_WIDGET(ud->builder, "PictureDeinterlace"); tweaks ? gtk_widget_hide(widget) : gtk_widget_show(widget); widget = GHB_WIDGET(ud->builder, "tweak_PictureDeinterlace"); diff --git a/gtk/src/preview.c b/gtk/src/preview.c new file mode 100644 index 000000000..a4dfcdd5a --- /dev/null +++ b/gtk/src/preview.c @@ -0,0 +1,697 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * preview.c + * Copyright (C) John Stebbins 2008 <stebbins@stebbins> + * + * preview.c is free software. + * + * You may redistribute it and/or modify it under the terms of the + * GNU General Public License, as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include <unistd.h> +#include <glib.h> +#include <glib/gstdio.h> +#include <glib-object.h> +#include <gtk/gtk.h> +#include <gdk/gdkx.h> +#include <gst/gst.h> +#include <gst/interfaces/xoverlay.h> +#include <gst/video/video.h> +#include <gst/pbutils/missing-plugins.h> +#include "settings.h" +#include "callbacks.h" +#include "hb-backend.h" +#include "preview.h" +#include "values.h" +#include "hb.h" + +#define PREVIEW_STATE_IMAGE 0 +#define PREVIEW_STATE_LIVE 1 + +struct preview_s +{ + GstElement *play; + gint64 len; + gint64 pos; + gboolean seek_lock; + gboolean progress_lock; + gint width; + gint height; + GtkWidget *view; + gulong xid; + GdkPixbuf *pix; + gint button_width; + gint button_height; + gint frame; + gint state; + gboolean pause; + gboolean encoded[10]; + gint encode_frame; + gchar *current; +}; + +static gboolean live_preview_cb(GstBus *bus, GstMessage *msg, gpointer data); +static GstBusSyncReply create_window(GstBus *bus, GstMessage *msg, + gpointer data); +gboolean preview_expose_cb(GtkWidget *widget, GdkEventExpose *event, + signal_user_data_t *ud); + +void +ghb_preview_init(signal_user_data_t *ud) +{ + GstBus *bus; + GstElement *xover; + + ud->preview = g_malloc0(sizeof(preview_t)); + ud->preview->view = GHB_WIDGET(ud->builder, "preview_image"); + gtk_widget_realize(ud->preview->view); + g_signal_connect(G_OBJECT(ud->preview->view), "expose_event", + G_CALLBACK(preview_expose_cb), ud); + ud->preview->xid = GDK_DRAWABLE_XID(ud->preview->view->window); + + ud->preview->play = gst_element_factory_make("playbin", "play"); + ud->preview->pause = TRUE; + //xover = gst_element_factory_make("xvimagesink", "xover"); + xover = gst_element_factory_make("gconfvideosink", "xover"); + g_object_set(G_OBJECT(ud->preview->play), "video-sink", xover, NULL); + //g_object_set(G_OBJECT(xover), "force-aspect-ratio", TRUE, NULL); + + bus = gst_pipeline_get_bus(GST_PIPELINE(ud->preview->play)); + gst_bus_add_watch(bus, live_preview_cb, ud); + gst_bus_set_sync_handler(bus, create_window, ud->preview); + gst_object_unref(bus); +} + +void +ghb_preview_cleanup(signal_user_data_t *ud) +{ + if (ud->preview->current) + { + ud->preview->current = NULL; + g_free(ud->preview->current); + } +} + +static GstBusSyncReply +create_window(GstBus *bus, GstMessage *msg, gpointer data) +{ + preview_t *preview = (preview_t*)data; + + switch (GST_MESSAGE_TYPE(msg)) + { + case GST_MESSAGE_ELEMENT: + { + if (!gst_structure_has_name(msg->structure, "prepare-xwindow-id")) + return GST_BUS_PASS; + gst_x_overlay_set_xwindow_id( + GST_X_OVERLAY(GST_MESSAGE_SRC(msg)), preview->xid); + gst_message_unref(msg); + return GST_BUS_DROP; + } break; + + default: + { + } break; + } + return GST_BUS_PASS; +} + +static GList * +get_stream_info_objects_for_type (GstElement *play, const gchar *typestr) +{ + GValueArray *info_arr = NULL; + GList *ret = NULL; + guint ii; + + if (play == NULL) + return NULL; + + g_object_get(play, "stream-info-value-array", &info_arr, NULL); + if (info_arr == NULL) + return NULL; + + for (ii = 0; ii < info_arr->n_values; ++ii) + { + GObject *info_obj; + GValue *val; + + val = g_value_array_get_nth(info_arr, ii); + info_obj = g_value_get_object(val); + if (info_obj) + { + GParamSpec *pspec; + GEnumValue *value; + gint type = -1; + + g_object_get(info_obj, "type", &type, NULL); + pspec = g_object_class_find_property( + G_OBJECT_GET_CLASS (info_obj), "type"); + value = g_enum_get_value( + G_PARAM_SPEC_ENUM (pspec)->enum_class, type); + if (value) + { + if (g_ascii_strcasecmp (value->value_nick, typestr) == 0 || + g_ascii_strcasecmp (value->value_name, typestr) == 0) + { + ret = g_list_prepend (ret, g_object_ref (info_obj)); + } + } + } + } + g_value_array_free (info_arr); + return g_list_reverse (ret); +} + +static void +caps_set(GstCaps *caps, preview_t *preview) +{ + GstStructure *ss; + + ss = gst_caps_get_structure(caps, 0); + if (ss) + { + gint fps_n, fps_d, width, height; + guint num, den, par_n, par_d; + guint disp_par_n, disp_par_d; + const GValue *par; + GValue disp_par = {0,}; + GstElement *xover; + GObjectClass *klass; + GParamSpec *pspec; + + gst_structure_get_fraction(ss, "framerate", &fps_n, &fps_d); + gst_structure_get_int(ss, "width", &width); + gst_structure_get_int(ss, "height", &height); + par = gst_structure_get_value(ss, "pixel-aspect-ratio"); + par_n = gst_value_get_fraction_numerator(par); + par_d = gst_value_get_fraction_denominator(par); + + g_value_init(&disp_par, GST_TYPE_FRACTION); + gst_value_set_fraction(&disp_par, 1, 1); + g_object_get(preview->play, "video-sink", &xover, NULL); + klass = G_OBJECT_GET_CLASS(xover); + pspec = g_object_class_find_property(klass, "pixel-aspect_ratio"); + if (pspec) + { + GValue par_prop = {0,}; + + g_value_init(&par_prop, pspec->value_type); + g_object_get_property(G_OBJECT(xover), "pixel-aspect-ratio", + &par_prop); + if (!g_value_transform(&par_prop, &disp_par)) + { + g_warning("transform failed"); + gst_value_set_fraction(&disp_par, 1, 1); + } + g_value_unset(&par_prop); + } + disp_par_n = gst_value_get_fraction_numerator(&disp_par); + disp_par_d = gst_value_get_fraction_denominator(&disp_par); + g_value_unset(&disp_par); + gst_video_calculate_display_ratio( + &num, &den, width, height, par_n, par_d, disp_par_n, disp_par_d); + + width = gst_util_uint64_scale_int(height, num, den); + if (width != preview->width || height != preview->height) + { + gtk_widget_set_size_request(preview->view, width, height); + preview->width = width; + preview->height = height; + } + } +} + +static void +update_stream_info(preview_t *preview) +{ + GList *vstreams, *ll; + GstPad *vpad = NULL; + + vstreams = get_stream_info_objects_for_type(preview->play, "video"); + if (vstreams) + { + for (ll = vstreams; vpad == NULL && ll != NULL; ll = ll->next) + { + g_object_get(ll->data, "object", &vpad, NULL); + } + } + if (vpad) + { + GstCaps *caps; + + caps = gst_pad_get_negotiated_caps(vpad); + if (caps) + { + caps_set(caps, preview); + gst_caps_unref(caps); + } + //g_signal_connect(vpad, "notify::caps", G_CALLBACK(caps_set_cb), preview); + gst_object_unref(vpad); + } + g_list_foreach(vstreams, (GFunc)g_object_unref, NULL); + g_list_free(vstreams); +} + +static gboolean +live_preview_cb(GstBus *bus, GstMessage *msg, gpointer data) +{ + signal_user_data_t *ud = (signal_user_data_t*)data; + + switch (GST_MESSAGE_TYPE(msg)) + { + case GST_MESSAGE_ERROR: + { + GError *err; + gchar *debug; + + gst_message_parse_error(msg, &err, &debug); + g_warning("Gstreamer Error: %s", err->message); + g_error_free(err); + g_free(debug); + } break; + + case GST_MESSAGE_ELEMENT: + { + if (gst_is_missing_plugin_message(msg)) + { + gst_element_set_state(ud->preview->play, GST_STATE_PAUSED); + gchar *message, *desc; + desc = gst_missing_plugin_message_get_description(msg); + message = g_strdup_printf( + "Missing GStreamer plugin\n" + "Audio or Video may not play as expected\n\n%s", + desc); + ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Ok", NULL); + g_free(message); + gst_element_set_state(ud->preview->play, GST_STATE_PLAYING); + } + } break; + + case GST_MESSAGE_STATE_CHANGED: + { + GstState state, pending; + gst_element_get_state(ud->preview->play, &state, &pending, 0); + if (state == GST_STATE_PAUSED || state == GST_STATE_PLAYING) + { + update_stream_info(ud->preview); + } + } break; + + case GST_MESSAGE_EOS: + { + // Done + GtkImage *img; + + img = GTK_IMAGE(GHB_WIDGET(ud->builder, "live_preview_play_image")); + gtk_image_set_from_stock(img, "gtk-media-play", GTK_ICON_SIZE_BUTTON); + gst_element_set_state(ud->preview->play, GST_STATE_PAUSED); + ud->preview->pause = TRUE; + gst_element_seek(ud->preview->play, 1.0, + GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, + GST_SEEK_TYPE_SET, 0, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); + } break; + + default: + { + // Ignore + } + } + return TRUE; +} + +void +live_preview_start(signal_user_data_t *ud) +{ + GtkImage *img; + gchar *uri; + + img = GTK_IMAGE(GHB_WIDGET(ud->builder, "live_preview_play_image")); + if (!ud->preview->encoded[ud->preview->frame]) + { + gtk_image_set_from_stock(img, "gtk-media-play", GTK_ICON_SIZE_BUTTON); + gst_element_set_state(ud->preview->play, GST_STATE_NULL); + ud->preview->pause = TRUE; + return; + } + + uri = g_strdup_printf("file://%s", ud->preview->current); + gtk_image_set_from_stock(img, "gtk-media-pause", GTK_ICON_SIZE_BUTTON); + ud->preview->state = PREVIEW_STATE_LIVE; + g_object_set(G_OBJECT(ud->preview->play), "uri", uri, NULL); + gst_element_set_state(ud->preview->play, GST_STATE_PLAYING); + ud->preview->pause = FALSE; + g_free(uri); +} + +void +live_preview_pause(signal_user_data_t *ud) +{ + GtkImage *img; + + img = GTK_IMAGE(GHB_WIDGET(ud->builder, "live_preview_play_image")); + gtk_image_set_from_stock(img, "gtk-media-play", GTK_ICON_SIZE_BUTTON); + gst_element_set_state(ud->preview->play, GST_STATE_PAUSED); + ud->preview->pause = TRUE; +} + +void +live_preview_stop(signal_user_data_t *ud) +{ + GtkImage *img; + GtkRange *progress; + + img = GTK_IMAGE(GHB_WIDGET(ud->builder, "live_preview_play_image")); + gtk_image_set_from_stock(img, "gtk-media-play", GTK_ICON_SIZE_BUTTON); + gst_element_set_state(ud->preview->play, GST_STATE_NULL); + ud->preview->pause = TRUE; + ud->preview->state = PREVIEW_STATE_IMAGE; + + progress = GTK_RANGE(GHB_WIDGET(ud->builder, "live_preview_progress")); + gtk_range_set_value(progress, 0); +} + +void +ghb_live_reset(signal_user_data_t *ud) +{ + gboolean encoded; + + if (!ud->preview->pause) + live_preview_stop(ud); + if (ud->preview->current) + { + g_free(ud->preview->current); + ud->preview->current = NULL; + } + encoded = ud->preview->encoded[ud->preview->frame]; + memset(ud->preview->encoded, 0, sizeof(gboolean) * 10); + if (encoded) + ghb_set_preview_image(ud); +} + +extern void hb_get_tempory_directory(hb_handle_t *h, char path[512]); + +void +live_preview_start_cb(GtkWidget *xwidget, signal_user_data_t *ud) +{ + gchar *tmp_dir; + gchar *name; + gint frame = ud->preview->frame; + + tmp_dir = ghb_get_tmp_dir(); + name = g_strdup_printf("%s/live%02d", tmp_dir, ud->preview->frame); + if (ud->preview->current) + g_free(ud->preview->current); + ud->preview->current = name; + + if (ud->preview->encoded[frame] && + g_file_test(name, G_FILE_TEST_IS_REGULAR)) + { + if (ud->preview->pause) + live_preview_start(ud); + else + live_preview_pause(ud); + } + else + { + GValue *js; + + ud->preview->encode_frame = frame; + js = ghb_value_dup(ud->settings); + ghb_settings_set_string(js, "destination", name); + ghb_settings_set_int(js, "start_frame", ud->preview->frame); + ghb_settings_set_int(js, "live_duration", 15); + ghb_add_live_job(js, 0); + ghb_start_live_encode(); + ghb_value_free(js); + } +} + +void +ghb_live_encode_done(signal_user_data_t *ud, gboolean success) +{ + GtkWidget *widget; + GtkWidget *prog; + + prog = GHB_WIDGET(ud->builder, "live_encode_progress"); + if (success && + ud->preview->encode_frame == ud->preview->frame) + { + gtk_progress_bar_set_text(GTK_PROGRESS_BAR(prog), "Done"); + gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(prog), 1); + ud->preview->encoded[ud->preview->encode_frame] = TRUE; + live_preview_start(ud); + widget = GHB_WIDGET(ud->builder, "live_progress_box"); + gtk_widget_hide (widget); + widget = GHB_WIDGET(ud->builder, "live_preview_progress"); + gtk_widget_show (widget); + } + else + { + gtk_progress_bar_set_text(GTK_PROGRESS_BAR(prog), ""); + gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(prog), 0); + ud->preview->encoded[ud->preview->encode_frame] = FALSE; + } +} + +static gboolean +unlock_progress_cb(signal_user_data_t *ud) +{ + ud->preview->progress_lock = FALSE; + // This function is initiated by g_idle_add. Must return false + // so that it is not called again + return FALSE; +} + +void +ghb_live_preview_progress(signal_user_data_t *ud) +{ + GstFormat fmt = GST_FORMAT_TIME; + gint64 len = -1, pos = -1; + + if (ud->preview->state != PREVIEW_STATE_LIVE || ud->preview->seek_lock) + return; + + ud->preview->progress_lock = TRUE; + if (gst_element_query_duration(ud->preview->play, &fmt, &len)) + { + if (len != -1 && fmt == GST_FORMAT_TIME) + { + ud->preview->len = len / GST_MSECOND; + } + } + if (gst_element_query_position(ud->preview->play, &fmt, &pos)) + { + if (pos != -1 && fmt == GST_FORMAT_TIME) + { + ud->preview->pos = pos / GST_MSECOND; + } + } + if (ud->preview->len > 0) + { + GtkRange *progress; + gdouble percent; + + percent = (gdouble)ud->preview->pos * 100 / ud->preview->len; + progress = GTK_RANGE(GHB_WIDGET(ud->builder, "live_preview_progress")); + gtk_range_set_value(progress, percent); + } + g_idle_add((GSourceFunc)unlock_progress_cb, ud); +} + +static gboolean +unlock_seek_cb(signal_user_data_t *ud) +{ + ud->preview->seek_lock = FALSE; + // This function is initiated by g_idle_add. Must return false + // so that it is not called again + return FALSE; +} + +void +live_preview_seek_cb(GtkWidget *widget, signal_user_data_t *ud) +{ + gdouble dval; + gint64 pos; + + if (ud->preview->progress_lock) + return; + + ud->preview->seek_lock = TRUE; + dval = gtk_range_get_value(GTK_RANGE(widget)); + pos = ((ud->preview->len * dval) / 100) * GST_MSECOND; + gst_element_seek(ud->preview->play, 1.0, + GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, + GST_SEEK_TYPE_SET, pos, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); + g_idle_add((GSourceFunc)unlock_seek_cb, ud); +} + +void +ghb_set_preview_image(signal_user_data_t *ud) +{ + GtkWidget *widget; + gint preview_width, preview_height, target_height, width, height; + + g_debug("set_preview_button_image ()"); + gint titleindex; + + live_preview_stop(ud); + + titleindex = ghb_settings_combo_int(ud->settings, "title"); + if (titleindex < 0) return; + widget = GHB_WIDGET (ud->builder, "preview_frame"); + ud->preview->frame = ghb_widget_int(widget) - 1; + if (ud->preview->encoded[ud->preview->frame]) + { + widget = GHB_WIDGET(ud->builder, "live_progress_box"); + gtk_widget_hide (widget); + widget = GHB_WIDGET(ud->builder, "live_preview_progress"); + gtk_widget_show (widget); + } + else + { + widget = GHB_WIDGET(ud->builder, "live_preview_progress"); + gtk_widget_hide (widget); + widget = GHB_WIDGET(ud->builder, "live_progress_box"); + gtk_widget_show (widget); + widget = GHB_WIDGET(ud->builder, "live_encode_progress"); + gtk_progress_bar_set_text(GTK_PROGRESS_BAR(widget), ""); + gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(widget), 0); + } + if (ud->preview->pix != NULL) + g_object_unref(ud->preview->pix); + ud->preview->pix = ghb_get_preview_image(titleindex, ud->preview->frame, + ud->settings, TRUE); + if (ud->preview->pix == NULL) return; + preview_width = gdk_pixbuf_get_width(ud->preview->pix); + preview_height = gdk_pixbuf_get_height(ud->preview->pix); + widget = GHB_WIDGET (ud->builder, "preview_image"); + if (preview_width != ud->preview->width || + preview_height != ud->preview->height) + { + gtk_widget_set_size_request(widget, preview_width, preview_height); + ud->preview->width = preview_width; + ud->preview->height = preview_height; + } + gdk_draw_pixbuf( + widget->window, NULL, ud->preview->pix, 0, 0, 0, 0, + -1, -1, GDK_RGB_DITHER_NONE, 0, 0); + + gchar *text = g_strdup_printf("%d x %d", preview_width, preview_height); + widget = GHB_WIDGET (ud->builder, "preview_dims"); + gtk_label_set_text(GTK_LABEL(widget), text); + g_free(text); + + g_debug("preview %d x %d", preview_width, preview_height); + target_height = MIN(ud->preview->button_height - 12, 128); + height = target_height; + width = preview_width * height / preview_height; + + if ((height >= 16) && (width >= 16)) + { + GdkPixbuf *scaled_preview; + scaled_preview = gdk_pixbuf_scale_simple (ud->preview->pix, width, + height, GDK_INTERP_NEAREST); + if (scaled_preview != NULL) + { + widget = GHB_WIDGET (ud->builder, "preview_button_image"); + gtk_image_set_from_pixbuf(GTK_IMAGE(widget), scaled_preview); + g_object_unref (scaled_preview); + } + } +} + +static gboolean +delayed_expose_cb(signal_user_data_t *ud) +{ + GstElement *vsink; + GstXOverlay *xover; + + g_object_get(ud->preview->play, "video-sink", &vsink, NULL); + if (GST_IS_BIN(vsink)) + xover = GST_X_OVERLAY(gst_bin_get_by_interface( + GST_BIN(vsink), GST_TYPE_X_OVERLAY)); + else + xover = GST_X_OVERLAY(vsink); + gst_x_overlay_expose(xover); + // This function is initiated by g_idle_add. Must return false + // so that it is not called again + return FALSE; +} + +gboolean +preview_expose_cb( + GtkWidget *widget, + GdkEventExpose *event, + signal_user_data_t *ud) +{ + if (ud->preview->state == PREVIEW_STATE_LIVE) + { + if (GST_STATE(ud->preview->play) >= GST_STATE_PAUSED) + { + GstElement *vsink; + GstXOverlay *xover; + + g_object_get(ud->preview->play, "video-sink", &vsink, NULL); + if (GST_IS_BIN(vsink)) + xover = GST_X_OVERLAY(gst_bin_get_by_interface( + GST_BIN(vsink), GST_TYPE_X_OVERLAY)); + else + xover = GST_X_OVERLAY(vsink); + gst_x_overlay_expose(xover); + // For some reason, the exposed region doesn't always get + // cleaned up here. But a delayed gst_x_overlay_expose() + // takes care of it. + g_idle_add((GSourceFunc)delayed_expose_cb, ud); + return FALSE; + } + return TRUE; + } + + gdk_draw_pixbuf( + widget->window, NULL, ud->preview->pix, 0, 0, 0, 0, + -1, -1, GDK_RGB_DITHER_NONE, 0, 0); + return TRUE; +} + +void +preview_button_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud) +{ + g_debug("allocate %d x %d", allocation->width, allocation->height); + if (ud->preview->button_width == allocation->width && + ud->preview->button_height == allocation->height) + { + // Nothing to do. Bug out. + g_debug("nothing to do"); + return; + } + g_debug("prev allocate %d x %d", ud->preview->button_width, + ud->preview->button_height); + ud->preview->button_width = allocation->width; + ud->preview->button_height = allocation->height; + ghb_set_preview_image(ud); +} + +void +preview_button_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud) +{ + gint titleindex; + + titleindex = ghb_settings_combo_int(ud->settings, "title"); + if (titleindex < 0) return; + g_debug("titleindex %d", titleindex); + + GtkWidget *widget = GHB_WIDGET (ud->builder, "preview_window"); + gtk_widget_show (widget); +} + +void +preview_frame_value_changed_cb(GtkWidget *widget, signal_user_data_t *ud) +{ + ghb_set_preview_image(ud); +} + diff --git a/gtk/src/preview.h b/gtk/src/preview.h new file mode 100644 index 000000000..2b026fed0 --- /dev/null +++ b/gtk/src/preview.h @@ -0,0 +1,26 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA + */ +#if !defined(_GHB_PREVIEW_H_) +#define _GHB_PREVIEW_H_ + +void ghb_preview_init(signal_user_data_t *ud); +void ghb_set_preview_image(signal_user_data_t *ud); +void ghb_live_preview_progress(signal_user_data_t *ud); +void ghb_live_encode_done(signal_user_data_t *ud, gboolean success); +void ghb_preview_cleanup(signal_user_data_t *ud); +void ghb_live_reset(signal_user_data_t *ud); + +#endif // _GHB_PREVIEW_H_ diff --git a/gtk/src/resource_data.h b/gtk/src/resource_data.h index f4470984f..a6fe4794e 100644 --- a/gtk/src/resource_data.h +++ b/gtk/src/resource_data.h @@ -206,6 +206,15 @@ " <property name="page_size">0</property>\n" " <property name="value">0</property>\n" " </object>\n" +" <object class="GtkAdjustment" id="preview_progress_" +"adj">\n" +" <property name="upper">100</property>\n" +" <property name="lower">0</property>\n" +" <property name="step_increment">1</property>\n" +" <property name="page_increment">10</property>" +"\n" +" <property name="value">0</property>\n" +" </object>\n" " <object class="GtkUIManager" id="uimanager1"&g" "t;\n" " <child>\n" @@ -811,6 +820,8 @@ " <child>\n" " <object class="GtkComboBox&qu" "ot; id="title">\n" +" <property name="height_request">" +";16</property>\n" " <property name="width_reque" "st">150</property>\n" " <property name="visible&quo" @@ -5212,6 +5223,8 @@ " <child>\n" " <object class="GtkProgressBar" id="prog" "ressbar">\n" +" <property name="height_request">16</" +"property>\n" " <property name="visible">True</prope" "rty>\n" " <property name="events">GDK_POINTER_MOT" @@ -6633,12 +6646,109 @@ " <property name="right_padding">4</pr" "operty>\n" " <child>\n" -" <object class="GtkImage" id="previe" -"w_image">\n" +" <object class="GtkTable" id="table1" +"">\n" " <property name="visible">True</p" "roperty>\n" -" <property name="icon_name">hb-icon&" +" <property name="n_rows">3</prope" +"rty>\n" +" <property name="n_columns">3</pr" +"operty>\n" +" <child>\n" +" <placeholder/>\n" +" </child>\n" +" <child>\n" +" <placeholder/>\n" +" </child>\n" +" <child>\n" +" <placeholder/>\n" +" </child>\n" +" <child>\n" +" <placeholder/>\n" +" </child>\n" +" <child>\n" +" <object class="GtkLabel" id="la" +"bel45">\n" +" <property name="visible">True&l" +"t;/property>\n" +" </object>\n" +" <packing>\n" +" <property name="left_attach">2&" "lt;/property>\n" +" <property name="right_attach">3" +"</property>\n" +" <property name="top_attach">1&l" +"t;/property>\n" +" <property name="bottom_attach">" +"2</property>\n" +" </packing>\n" +" </child>\n" +" <child>\n" +" <object class="GtkLabel" id="la" +"bel44">\n" +" <property name="visible">True&l" +"t;/property>\n" +" </object>\n" +" <packing>\n" +" <property name="left_attach">1&" +"lt;/property>\n" +" <property name="right_attach">2" +"</property>\n" +" <property name="top_attach">2&l" +"t;/property>\n" +" <property name="bottom_attach">" +"3</property>\n" +" </packing>\n" +" </child>\n" +" <child>\n" +" <object class="GtkLabel" id="la" +"bel43">\n" +" <property name="visible">True&l" +"t;/property>\n" +" </object>\n" +" <packing>\n" +" <property name="left_attach">1&" +"lt;/property>\n" +" <property name="right_attach">2" +"</property>\n" +" </packing>\n" +" </child>\n" +" <child>\n" +" <object class="GtkLabel" id="la" +"bel42">\n" +" <property name="visible">True&l" +"t;/property>\n" +" </object>\n" +" <packing>\n" +" <property name="top_attach">1&l" +"t;/property>\n" +" <property name="bottom_attach">" +"2</property>\n" +" </packing>\n" +" </child>\n" +" <child>\n" +" <object class="GtkDrawingArea" id=&q" +"uot;preview_image">\n" +" <property name="visible">True&l" +"t;/property>\n" +" <property name="app_paintable">" +"True</property>\n" +" </object>\n" +" <packing>\n" +" <property name="left_attach">1&" +"lt;/property>\n" +" <property name="right_attach">2" +"</property>\n" +" <property name="top_attach">1&l" +"t;/property>\n" +" <property name="bottom_attach">" +"2</property>\n" +" <property name="x_options"><" +"/property>\n" +" <property name="y_options"><" +"/property>\n" +" </packing>\n" +" </child>\n" " </object>\n" " </child>\n" " </object>\n" @@ -6658,6 +6768,129 @@ " </object>\n" " </child>\n" " <child>\n" +" <object class="GtkHBox" id="hbox7">" +"\n" +" <property name="visible">True</property&" +"gt;\n" +" <child>\n" +" <object class="GtkButton" id="live_prev" +"iew_play">\n" +" <property name="height_request">30</" +"property>\n" +" <property name="visible">True</prope" +"rty>\n" +" <property name="can_focus">True</pro" +"perty>\n" +" <property name="receives_default">True&" +"lt;/property>\n" +" <property name="relief">none</proper" +"ty>\n" +" <signal handler="live_preview_start_cb" na" +"me="clicked"/>\n" +" <child>\n" +" <object class="GtkImage" id="live_p" +"review_play_image">\n" +" <property name="visible">True</p" +"roperty>\n" +" <property name="stock">gtk-media-pl" +"ay</property>\n" +" </object>\n" +" </child>\n" +" </object>\n" +" <packing>\n" +" <property name="expand">False</prope" +"rty>\n" +" <property name="position">0</propert" +"y>\n" +" </packing>\n" +" </child>\n" +" <child>\n" +" <object class="GtkHScale" id="live_prev" +"iew_progress">\n" +" <property name="visible">False</prop" +"erty>\n" +" <property name="can_focus">True</pro" +"perty>\n" +" <property name="adjustment">preview_pro" +"gress_adj</property>\n" +" <property name="draw_value">False</p" +"roperty>\n" +" <property name="value_pos">right</pr" +"operty>\n" +" <signal handler="live_preview_seek_cb" nam" +"e="value_changed"/>\n" +" </object>\n" +" <packing>\n" +" <property name="position">1</propert" +"y>\n" +" </packing>\n" +" </child>\n" +" <child>\n" +" <object class="GtkVBox" id="live_progre" +"ss_box">\n" +" <property name="visible">True</prope" +"rty>\n" +" <child>\n" +" <object class="GtkLabel" id="label1" +"">\n" +" <property name="height_request">1&l" +"t;/property>\n" +" <property name="visible">True</p" +"roperty>\n" +" </object>\n" +" <packing>\n" +" <property name="position">0</pro" +"perty>\n" +" </packing>\n" +" </child>\n" +" <child>\n" +" <object class="GtkProgressBar" id="" +"live_encode_progress">\n" +" <property name="height_request">16&" +"lt;/property>\n" +" <property name="visible">True</p" +"roperty>\n" +" <property name="events">GDK_POINTER" +"_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | G" +"DK_BUTTON_RELEASE_MASK</property>\n" +" <property name="text" translatable=&qu" +"ot;yes"></property>\n" +" </object>\n" +" <packing>\n" +" <property name="expand">False</propert" +"y>\n" +" <property name="position">1</pro" +"perty>\n" +" </packing>\n" +" </child>\n" +" <child>\n" +" <object class="GtkLabel" id="label2" +"">\n" +" <property name="height_request">1&l" +"t;/property>\n" +" <property name="visible">True</p" +"roperty>\n" +" </object>\n" +" <packing>\n" +" <property name="position">2</pro" +"perty>\n" +" </packing>\n" +" </child>\n" +" </object>\n" +" <packing>\n" +" <property name="position">2</propert" +"y>\n" +" </packing>\n" +" </child>\n" +" </object>\n" +" <packing>\n" +" <property name="expand">False</property&" +"gt;\n" +" <property name="position">1</property>" +";\n" +" </packing>\n" +" </child>\n" +" <child>\n" " <object class="GtkHBox" id="hbox8">" "\n" " <property name="visible">True</property&" @@ -7413,7 +7646,7 @@ " <packing>\n" " <property name="expand">False</property&" "gt;\n" -" <property name="position">1</property>" +" <property name="position">2</property>" ";\n" " </packing>\n" " </child>\n" @@ -10347,6 +10580,8 @@ " <integer>100</integer>\n" " <key>folder</key>\n" " <string></string>\n" +" <key>live_duration</key>\n" +" <integer>15</integer>\n" " <key>preset</key>\n" " <array>\n" " <string>Normal</string>\n" @@ -10365,6 +10600,8 @@ " <integer>0</integer>\n" " <key>start_chapter</key>\n" " <integer>1</integer>\n" +" <key>start_frame</key>\n" +" <integer>-1</integer>\n" " <key>title</key>\n" " <string>none</string>\n" " <key>tweak_PictureDecomb</key>\n" diff --git a/gtk/src/resources.plist b/gtk/src/resources.plist index 5ce2d716f..f01338942 100644 --- a/gtk/src/resources.plist +++ b/gtk/src/resources.plist @@ -166,6 +166,13 @@ <property name="page_size">0</property> <property name="value">0</property> </object> + <object class="GtkAdjustment" id="preview_progress_adj"> + <property name="upper">100</property> + <property name="lower">0</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + <property name="value">0</property> + </object> <object class="GtkUIManager" id="uimanager1"> <child> <object class="GtkActionGroup" id="actiongroup1"> @@ -550,6 +557,7 @@ </child> <child> <object class="GtkComboBox" id="title"> + <property name="height_request">16</property> <property name="width_request">150</property> <property name="visible">True</property> <property name="has_frame">False</property> @@ -3173,6 +3181,7 @@ no-fast-pskip=0:no-dct-decimate=0:cabac=1</property> </child> <child> <object class="GtkProgressBar" id="progressbar"> + <property name="height_request">16</property> <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="text" translatable="yes"/> @@ -4049,9 +4058,76 @@ location as the movie.</property> <property name="left_padding">12</property> <property name="right_padding">4</property> <child> - <object class="GtkImage" id="preview_image"> + <object class="GtkTable" id="table1"> <property name="visible">True</property> - <property name="icon_name">hb-icon</property> + <property name="n_rows">3</property> + <property name="n_columns">3</property> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <object class="GtkLabel" id="label45"> + <property name="visible">True</property> + </object> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label44"> + <property name="visible">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label43"> + <property name="visible">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label42"> + <property name="visible">True</property> + </object> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> + <child> + <object class="GtkDrawingArea" id="preview_image"> + <property name="visible">True</property> + <property name="app_paintable">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> </object> </child> </object> @@ -4066,6 +4142,86 @@ location as the movie.</property> </object> </child> <child> + <object class="GtkHBox" id="hbox7"> + <property name="visible">True</property> + <child> + <object class="GtkButton" id="live_preview_play"> + <property name="height_request">30</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="relief">none</property> + <signal handler="live_preview_start_cb" name="clicked"/> + <child> + <object class="GtkImage" id="live_preview_play_image"> + <property name="visible">True</property> + <property name="stock">gtk-media-play</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHScale" id="live_preview_progress"> + <property name="visible">False</property> + <property name="can_focus">True</property> + <property name="adjustment">preview_progress_adj</property> + <property name="draw_value">False</property> + <property name="value_pos">right</property> + <signal handler="live_preview_seek_cb" name="value_changed"/> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="live_progress_box"> + <property name="visible">True</property> + <child> + <object class="GtkLabel" id="label1"> + <property name="height_request">1</property> + <property name="visible">True</property> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkProgressBar" id="live_encode_progress"> + <property name="height_request">16</property> + <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="text" translatable="yes"></property> + </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label2"> + <property name="height_request">1</property> + <property name="visible">True</property> + </object> + <packing> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + <child> <object class="GtkHBox" id="hbox8"> <property name="visible">True</property> <child> @@ -4534,7 +4690,7 @@ the other to maintain the video's original aspect ratio.</property> </object> <packing> <property name="expand">False</property> - <property name="position">1</property> + <property name="position">2</property> </packing> </child> </object> @@ -5044,6 +5200,8 @@ R2RrUAAABBgBAQACAAAAQAAAABAAAAAQ////AP///wD///8A////AP///wD///8A////AP///wD///8A <integer>100</integer> <key>folder</key> <string></string> + <key>live_duration</key> + <integer>15</integer> <key>preset</key> <array> <string>Normal</string> @@ -5062,6 +5220,8 @@ R2RrUAAABBgBAQACAAAAQAAAABAAAAAQ////AP///wD///8A////AP///wD///8A////AP///wD///8A <integer>0</integer> <key>start_chapter</key> <integer>1</integer> + <key>start_frame</key> + <integer>-1</integer> <key>title</key> <string>none</string> <key>tweak_PictureDecomb</key> diff --git a/gtk/src/settings.h b/gtk/src/settings.h index bc4adc65c..4d6eb22df 100644 --- a/gtk/src/settings.h +++ b/gtk/src/settings.h @@ -36,6 +36,8 @@ enum GHB_STATE_MUXING = 0x40, }; +typedef struct preview_s preview_t; + typedef struct { gchar *current_dvd_device; @@ -48,6 +50,7 @@ typedef struct GValue *current_job; GIOChannel *activity_log; GIOChannel *job_activity_log; + preview_t *preview; gchar *appcast; gint appcast_len; } signal_user_data_t; |