diff options
-rw-r--r-- | gtk/src/callbacks.c | 26 | ||||
-rw-r--r-- | gtk/src/callbacks.h | 1 | ||||
-rw-r--r-- | gtk/src/ghb.m4 | 302 | ||||
-rw-r--r-- | gtk/src/hb-backend.c | 120 | ||||
-rw-r--r-- | gtk/src/hb-backend.h | 18 | ||||
-rw-r--r-- | gtk/src/queuehandler.c | 447 | ||||
-rw-r--r-- | gtk/src/queuehandler.h | 3 | ||||
-rw-r--r-- | libhb/common.h | 27 | ||||
-rw-r--r-- | libhb/hb.c | 60 | ||||
-rw-r--r-- | libhb/hb_json.c | 7 | ||||
-rw-r--r-- | libhb/muxcommon.c | 3 | ||||
-rw-r--r-- | libhb/scan.c | 3 | ||||
-rw-r--r-- | libhb/sync.c | 18 | ||||
-rw-r--r-- | libhb/work.c | 39 |
14 files changed, 886 insertions, 188 deletions
diff --git a/gtk/src/callbacks.c b/gtk/src/callbacks.c index 6e0373bfd..7c661c415 100644 --- a/gtk/src/callbacks.c +++ b/gtk/src/callbacks.c @@ -1382,7 +1382,7 @@ source_dialog_extra_widgets( gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0); } -static void break_duration(gint64 duration, gint *hh, gint *mm, gint *ss) +void ghb_break_duration(gint64 duration, gint *hh, gint *mm, gint *ss) { *hh = duration / (60*60); *mm = (duration / 60) % 60; @@ -1415,7 +1415,7 @@ update_title_duration(signal_user_data_t *ud) start = ghb_dict_get_int(ud->settings, "start_point"); end = ghb_dict_get_int(ud->settings, "end_point"); duration = end - start; - break_duration(duration, &hh, &mm, &ss); + ghb_break_duration(duration, &hh, &mm, &ss); } else if (ghb_settings_combo_int(ud->settings, "PtoPType") == 2) { @@ -1428,7 +1428,7 @@ update_title_duration(signal_user_data_t *ud) end = ghb_dict_get_int(ud->settings, "end_point"); frames = end - start + 1; duration = frames * title->vrate.den / title->vrate.num; - break_duration(duration, &hh, &mm, &ss); + ghb_break_duration(duration, &hh, &mm, &ss); } else { @@ -3767,6 +3767,8 @@ submit_job(signal_user_data_t *ud, GhbValue *queueDict) GhbValue *job_dict = ghb_dict_get(queueDict, "Job"); int unique_id = ghb_add_job(ghb_queue_handle(), job_dict); ghb_dict_set_int(uiDict, "job_unique_id", unique_id); + time_t now = time(NULL); + ghb_dict_set_int(uiDict, "job_start_time", now); ghb_start_queue(); // Show queue progress bar @@ -3899,7 +3901,7 @@ ghb_start_next_job(signal_user_data_t *ud) ghb_dict_set_bool(ud->globals, "SkipDiskFreeCheck", FALSE); } -gchar* +static gchar* working_status_string(signal_user_data_t *ud, ghb_instance_status_t *status) { gchar *task_str, *job_str, *status_str; @@ -3967,7 +3969,7 @@ working_status_string(signal_user_data_t *ud, ghb_instance_status_t *status) return status_str; } -gchar* +static gchar* searching_status_string(signal_user_data_t *ud, ghb_instance_status_t *status) { gchar *task_str, *job_str, *status_str; @@ -4142,8 +4144,8 @@ ghb_backend_events(signal_user_data_t *ud) // This needs to be in scanning and working since scanning // happens fast enough that it can be missed gtk_label_set_text(work_status, _("Scanning ...")); - gtk_progress_bar_set_fraction(progress, 0); - ghb_queue_progress_set_fraction(ud, index, 0); + gtk_progress_bar_set_fraction(progress, status.queue.progress); + ghb_queue_progress_set_fraction(ud, index, status.queue.progress); } else if (status.queue.state & GHB_STATE_SCANDONE) { @@ -4152,6 +4154,7 @@ ghb_backend_events(signal_user_data_t *ud) else if (status.queue.state & GHB_STATE_PAUSED) { gtk_label_set_text (work_status, _("Paused")); + ghb_queue_update_live_stats(ud, index, &status.queue); } else if (status.queue.state & GHB_STATE_SEARCHING) { @@ -4170,6 +4173,7 @@ ghb_backend_events(signal_user_data_t *ud) status_str = working_status_string(ud, &status.queue); gtk_label_set_text (work_status, status_str); gtk_progress_bar_set_fraction (progress, status.queue.progress); + ghb_queue_update_live_stats(ud, index, &status.queue); ghb_queue_progress_set_fraction(ud, index, status.queue.progress); g_free(status_str); } @@ -4196,8 +4200,12 @@ ghb_backend_events(signal_user_data_t *ud) { GhbValue *uiDict = ghb_dict_get(queueDict, "uiSettings"); ghb_dict_set_int(uiDict, "job_status", qstatus); + time_t now = time(NULL); + ghb_dict_set_int(uiDict, "job_finish_time", now); + ghb_dict_set_int(uiDict, "job_pause_time_ms", status.queue.paused); } ghb_queue_update_status_icon(ud, index); + ghb_queue_update_live_stats(ud, index, &status.queue); gtk_progress_bar_set_fraction(progress, 1.0); ghb_queue_progress_set_fraction(ud, index, 1.0); @@ -4607,10 +4615,10 @@ chapter_refresh_list_row_ui( g_debug("Updating chapter row ui"); chapter = ghb_dict_get_string(ghb_array_get(chapter_list, index), "Name"); duration = ghb_get_chapter_duration(title, index) / 90000; - break_duration(duration, &hh, &mm, &ss); + ghb_break_duration(duration, &hh, &mm, &ss); s_duration = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss); start = ghb_get_chapter_start(title, index) / 90000; - break_duration(start, &hh, &mm, &ss); + ghb_break_duration(start, &hh, &mm, &ss); s_start = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss); gtk_list_store_set(GTK_LIST_STORE(tm), ti, 0, index+1, diff --git a/gtk/src/callbacks.h b/gtk/src/callbacks.h index 09d67ad04..6e025f0a6 100644 --- a/gtk/src/callbacks.h +++ b/gtk/src/callbacks.h @@ -90,6 +90,7 @@ void ghb_scale_configure(signal_user_data_t *ud, char *name, double val, void ghb_update_summary_info(signal_user_data_t *ud); void ghb_set_title_settings(signal_user_data_t *ud, GhbValue *settings); void ghb_browse_uri(signal_user_data_t *ud, const gchar *uri); +void ghb_break_duration(gint64 duration, gint *hh, gint *mm, gint *ss); #endif // _CALLBACKS_H_ diff --git a/gtk/src/ghb.m4 b/gtk/src/ghb.m4 index 0e2c21ecb..f3a4e6e4e 100644 --- a/gtk/src/ghb.m4 +++ b/gtk/src/ghb.m4 @@ -115,21 +115,21 @@ conjunction with the "Forced" option.</property> <attribute name="action">app.queue-reset-all</attribute> </item> <item> - <attribute name="label" translatable="yes">Delete Completed Jobs</attribute> + <attribute name="label" translatable="yes">Clear Completed Jobs</attribute> <attribute name="action">app.queue-delete-complete</attribute> </item> <item> - <attribute name="label" translatable="yes">Delete All Jobs</attribute> + <attribute name="label" translatable="yes">Clear All Jobs</attribute> <attribute name="action">app.queue-delete-all</attribute> </item> <item> - <attribute name="label" translatable="yes">Export Queue</attribute> - <attribute name="action">app.queue-export</attribute> - </item> - <item> <attribute name="label" translatable="yes">Import Queue</attribute> <attribute name="action">app.queue-import</attribute> </item> + <item> + <attribute name="label" translatable="yes">Export Queue</attribute> + <attribute name="action">app.queue-export</attribute> + </item> </section> </menu> @@ -345,6 +345,7 @@ conjunction with the "Forced" option.</property> <property name="hexpand">False</property> <property name="can_focus">False</property> <property name="halign">start</property> + <property name="valign">baseline</property> <property name="use_markup">True</property> <property name="margin-start">12</property> <property name="label" translatable="yes"><span size="x-large">Queue</span></property> @@ -359,6 +360,7 @@ conjunction with the "Forced" option.</property> <property name="hexpand">False</property> <property name="can_focus">False</property> <property name="halign">start</property> + <property name="valign">baseline</property> <property name="use_markup">True</property> <property name="margin-start">12</property> <property name="label" translatable="yes">0 jobs pending</property> @@ -514,6 +516,8 @@ conjunction with the "Forced" option.</property> <property name="activate_on_single_click">False</property> <signal name="row-selected" handler="queue_list_selection_changed_cb" swapped="no"/> <signal name="key-press-event" handler="queue_key_press_cb" swapped="no"/> + <signal name="drag-motion" handler="queue_drag_motion_cb" swapped="no"/> + <signal name="drag-data-received" handler="queue_drop_cb" swapped="no"/> </object> </child> </object> @@ -570,6 +574,7 @@ conjunction with the "Forced" option.</property> <property name="orientation">vertical</property> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="margin-top">4</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <child> <object class="GtkStackSwitcher" id="QueueStackSwitcher"> @@ -1007,6 +1012,291 @@ Resets the queue job to pending and ready to run again.</property> <property name="can_focus">False</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="spacing">3</property> + <child> + <object class="GtkScrolledWindow" id="queue_stats_scroll"> + <property name="visible">True</property> + <property name="can-focus">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="shadow-type">GTK_SHADOW_NONE</property> + <property name="vexpand">True</property> + <property name="hscrollbar-policy">GTK_POLICY_NEVER</property> + <property name="valign">GTK_ALIGN_FILL</property> + <property name="margin-bottom">12</property> + <child> + <object class="GtkGrid" id="queue_stats_grid"> + <property name="visible">True</property> + <property name="vexpand">True</property> + <property name="hexpand">False</property> + <property name="can_focus">False</property> + <property name="column-spacing">12</property> + <property name="row-spacing">12</property> + <child> + <object class="GtkLabel" id="queue_stats_pass_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="halign">start</property> + <property name="use_markup">True</property> + <property name="label" translatable="yes">Pass:</property> + </object> + <packing> + <property name="top_attach">0</property> + <property name="left_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_pass"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="halign">start</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="hexpand">False</property> + <property name="label" translatable="yes"></property> + <property name="width-chars">50</property> + </object> + <packing> + <property name="top_attach">0</property> + <property name="left_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_start_time_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="halign">start</property> + <property name="use_markup">True</property> + <property name="label" translatable="yes">Start Time:</property> + </object> + <packing> + <property name="top_attach">1</property> + <property name="left_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_start_time"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="halign">start</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="hexpand">False</property> + <property name="label" translatable="yes"></property> + <property name="width-chars">50</property> + </object> + <packing> + <property name="top_attach">1</property> + <property name="left_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_finish_time_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="halign">start</property> + <property name="use_markup">True</property> + <property name="label" translatable="yes">End Time:</property> + </object> + <packing> + <property name="top_attach">2</property> + <property name="left_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_finish_time"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="halign">start</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="hexpand">False</property> + <property name="label" translatable="yes"></property> + <property name="width-chars">50</property> + <property name="lines">2</property> + <property name="wrap_mode">word-char</property> + <property name="ellipsize">middle</property> + <property name="selectable">True</property> + </object> + <packing> + <property name="top_attach">2</property> + <property name="left_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_paused_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="halign">start</property> + <property name="use_markup">True</property> + <property name="label" translatable="yes">Paused Duration:</property> + </object> + <packing> + <property name="top_attach">3</property> + <property name="left_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_paused"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="halign">start</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="hexpand">False</property> + <property name="label" translatable="yes"></property> + <property name="width-chars">50</property> + <property name="lines">2</property> + <property name="wrap_mode">word-char</property> + <property name="ellipsize">middle</property> + <property name="selectable">True</property> + </object> + <packing> + <property name="top_attach">3</property> + <property name="left_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_encode_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="halign">start</property> + <property name="use_markup">True</property> + <property name="label" translatable="yes">Encode Time:</property> + </object> + <packing> + <property name="top_attach">4</property> + <property name="left_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_encode"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="halign">start</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="hexpand">False</property> + <property name="label" translatable="yes"></property> + <property name="width-chars">50</property> + </object> + <packing> + <property name="top_attach">4</property> + <property name="left_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_file_size_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="halign">start</property> + <property name="use_markup">True</property> + <property name="label" translatable="yes">File Size:</property> + </object> + <packing> + <property name="top_attach">5</property> + <property name="left_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_file_size"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="halign">start</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="hexpand">False</property> + <property name="label" translatable="yes"></property> + <property name="width-chars">50</property> + </object> + <packing> + <property name="top_attach">5</property> + <property name="left_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_result_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="halign">start</property> + <property name="use_markup">True</property> + <property name="label" translatable="yes">Status:</property> + </object> + <packing> + <property name="top_attach">6</property> + <property name="left_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_result"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="halign">start</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="hexpand">False</property> + <property name="label" translatable="yes"></property> + <property name="width-chars">50</property> + </object> + <packing> + <property name="top_attach">6</property> + <property name="left_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> </object> <packing> <property name="position">1</property> diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c index 139713e52..c79b821b7 100644 --- a/gtk/src/hb-backend.c +++ b/gtk/src/hb-backend.c @@ -3453,6 +3453,8 @@ ghb_get_status(ghb_status_t *status) static void update_status(hb_state_t *state, ghb_instance_status_t *status) { + status->unique_id = state->sequence_id; + #define p state->param.scanning if (state->state & HB_STATE_SCANNING) { @@ -3465,6 +3467,7 @@ update_status(hb_state_t *state, ghb_instance_status_t *status) } else { + // If last state seen was scanning, signal that scan id complete if (status->state & GHB_STATE_SCANNING) { status->state |= GHB_STATE_SCANDONE; @@ -3473,83 +3476,72 @@ update_status(hb_state_t *state, ghb_instance_status_t *status) } #undef p #define p state->param.working - if (state->state & HB_STATE_WORKING) - { - if (status->state & GHB_STATE_SCANNING) + if (state->state & (HB_STATE_WORKING | HB_STATE_WORKDONE | + HB_STATE_SEARCHING)) + { + status->pass = p.pass; + status->pass_count = p.pass_count; + status->pass_id = p.pass_id; + status->progress = p.progress; + status->rate_cur = p.rate_cur; + status->rate_avg = p.rate_avg; + status->eta_seconds = p.eta_seconds; + status->hours = p.hours; + status->minutes = p.minutes; + status->seconds = p.seconds; + status->paused = p.paused; + + if (state->state & HB_STATE_WORKING) { - status->state &= ~GHB_STATE_SCANNING; - status->state |= GHB_STATE_SCANDONE; + status->state |= GHB_STATE_WORKING; + status->state &= ~GHB_STATE_PAUSED; + status->state &= ~GHB_STATE_SEARCHING; } - status->state |= GHB_STATE_WORKING; - status->state &= ~GHB_STATE_PAUSED; - status->state &= ~GHB_STATE_SEARCHING; - status->pass = p.pass; - status->pass_count = p.pass_count; - status->pass_id = p.pass_id; - status->progress = p.progress; - status->rate_cur = p.rate_cur; - status->rate_avg = p.rate_avg; - status->hours = p.hours; - status->minutes = p.minutes; - status->seconds = p.seconds; - status->unique_id = p.sequence_id; - } - else - { - status->state &= ~GHB_STATE_WORKING; - } - if (state->state & HB_STATE_SEARCHING) - { - status->state |= GHB_STATE_SEARCHING; - status->state &= ~GHB_STATE_WORKING; - status->state &= ~GHB_STATE_PAUSED; - status->pass = p.pass; - status->pass_count = p.pass_count; - status->pass_id = p.pass_id; - status->progress = p.progress; - status->rate_cur = p.rate_cur; - status->rate_avg = p.rate_avg; - status->hours = p.hours; - status->minutes = p.minutes; - status->seconds = p.seconds; - status->unique_id = p.sequence_id; - } - else - { - status->state &= ~GHB_STATE_SEARCHING; - } -#undef p -#define p state->param.working - if (state->state & HB_STATE_WORKDONE) - { - status->state |= GHB_STATE_WORKDONE; - status->state &= ~GHB_STATE_MUXING; - status->state &= ~GHB_STATE_PAUSED; - status->state &= ~GHB_STATE_WORKING; - status->state &= ~GHB_STATE_SEARCHING; - status->unique_id = p.sequence_id; - switch (p.error) + else { - case HB_ERROR_NONE: - status->error = GHB_ERROR_NONE; - break; - case HB_ERROR_CANCELED: - status->error = GHB_ERROR_CANCELED; - break; - default: - status->error = GHB_ERROR_FAIL; - break; + status->state &= ~GHB_STATE_WORKING; + } + if (state->state & HB_STATE_SEARCHING) + { + status->state |= GHB_STATE_SEARCHING; + status->state &= ~GHB_STATE_WORKING; + status->state &= ~GHB_STATE_PAUSED; + } + else + { + status->state &= ~GHB_STATE_SEARCHING; + } + if (state->state & HB_STATE_WORKDONE) + { + status->state |= GHB_STATE_WORKDONE; + status->state &= ~GHB_STATE_MUXING; + status->state &= ~GHB_STATE_PAUSED; + status->state &= ~GHB_STATE_WORKING; + status->state &= ~GHB_STATE_SEARCHING; + switch (p.error) + { + case HB_ERROR_NONE: + status->error = GHB_ERROR_NONE; + break; + case HB_ERROR_CANCELED: + status->error = GHB_ERROR_CANCELED; + break; + default: + status->error = GHB_ERROR_FAIL; + break; + } } } -#undef p if (state->state & HB_STATE_PAUSED) { + status->paused = p.paused; status->state |= GHB_STATE_PAUSED; } else { status->state &= ~GHB_STATE_PAUSED; } +#undef p if (state->state & HB_STATE_MUXING) { status->state |= GHB_STATE_MUXING; diff --git a/gtk/src/hb-backend.h b/gtk/src/hb-backend.h index 592a759b6..4bcd41a59 100644 --- a/gtk/src/hb-backend.h +++ b/gtk/src/hb-backend.h @@ -47,17 +47,19 @@ typedef struct gint preview_cur; // WORKING - gint unique_id; - gint pass_id; - gint pass; - gint pass_count; + gint unique_id; + gint pass_id; + gint pass; + gint pass_count; gdouble progress; gdouble rate_cur; gdouble rate_avg; - gint hours; - gint minutes; - gint seconds; - gint error; + gint64 eta_seconds; + gint hours; + gint minutes; + gint seconds; + gint64 paused; + gint error; } ghb_instance_status_t; typedef struct diff --git a/gtk/src/queuehandler.c b/gtk/src/queuehandler.c index fba04a258..496bcfd92 100644 --- a/gtk/src/queuehandler.c +++ b/gtk/src/queuehandler.c @@ -36,6 +36,7 @@ #include "subtitlehandler.h" #include "ghb-dvd.h" #include "plist.h" +#include "queuehandler.h" void ghb_queue_buttons_grey(signal_user_data_t *ud); G_MODULE_EXPORT void @@ -70,6 +71,12 @@ static GtkWidget *find_widget(GtkWidget *widget, gchar *name) return result; } +void +ghb_queue_drag_n_drop_init(signal_user_data_t * ud) +{ + +} + static void queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) { @@ -116,7 +123,7 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) str = g_string_new(""); if (preset_modified) { - g_string_append_printf(str, _("Modified, %s"), name); + g_string_append_printf(str, _("%s (Modified)"), name); } else { @@ -156,22 +163,22 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) sep = "\n"; if (markers) { - g_string_append_printf(str, "%s%s", sep, "Chapter Markers"); + g_string_append_printf(str, "%s%s", sep, _("Chapter Markers")); sep = ", "; } if (av_align) { - g_string_append_printf(str, "%s%s", sep, "Align A/V"); + g_string_append_printf(str, "%s%s", sep, _("Align A/V")); sep = ", "; } if (http) { - g_string_append_printf(str, "%s%s", sep, "Web Optimized"); + g_string_append_printf(str, "%s%s", sep, _("Web Optimized")); sep = ", "; } if (ipod) { - g_string_append_printf(str, "%s%s", sep, "iPod 5G"); + g_string_append_printf(str, "%s%s", sep, _("iPod 5G")); sep = ", "; } @@ -203,10 +210,10 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) display_height); display_width = ghb_dict_get_int(uiDict, "PictureDisplayWidth"); - text = g_strdup_printf("%d:%d:%d:%d Crop\n" - "%dx%d storage, %dx%d display\n" - "%d:%d Pixel Aspect Ratio\n" - "%s Display Aspect Ratio", + text = g_strdup_printf(_("%d:%d:%d:%d Crop\n" + "%dx%d storage, %dx%d display\n" + "%d:%d Pixel Aspect Ratio\n" + "%s Display Aspect Ratio"), crop[0], crop[1], crop[2], crop[3], width, height, (int)display_width, display_height, par_width, par_height, display_aspect); @@ -234,19 +241,19 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) int br = ghb_dict_get_int(uiDict, "VideoAvgBitrate"); if (!two_pass) { - g_string_append_printf(str, "%s, Bitrate %dkbps", + g_string_append_printf(str, _("%s, Bitrate %dkbps"), video_encoder->name, br); } else { - g_string_append_printf(str, "%s, Bitrate %dkbps (2 Pass)", + g_string_append_printf(str, _("%s, Bitrate %dkbps (2 Pass)"), video_encoder->name, br); } } else { gdouble quality = ghb_dict_get_double(uiDict, "VideoQualitySlider"); - g_string_append_printf(str, "%s, Constant Quality %.4g(%s)", + g_string_append_printf(str, _("%s, Constant Quality %.4g(%s)"), video_encoder->name, quality, hb_video_quality_get_name(video_encoder->codec)); } @@ -279,22 +286,22 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) sep = "\n"; if (enc_preset != NULL) { - g_string_append_printf(str, "%sPreset %s", sep, enc_preset); + g_string_append_printf(str, _("%sPreset %s"), sep, enc_preset); sep = ", "; } if (enc_tune != NULL) { - g_string_append_printf(str, "%sTune %s", sep, enc_tune); + g_string_append_printf(str, _("%sTune %s"), sep, enc_tune); sep = ", "; } if (enc_profile != NULL) { - g_string_append_printf(str, "%sProfile %s", sep, enc_profile); + g_string_append_printf(str, _("%sProfile %s"), sep, enc_profile); sep = ", "; } if (enc_level != NULL) { - g_string_append_printf(str, "%sLevel %s", sep, enc_level); + g_string_append_printf(str, _("%sLevel %s"), sep, enc_level); sep = ", "; } @@ -311,16 +318,16 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) rate_str = g_strdup_printf("%.6g", (gdouble)vrate.num / vrate.den); if (ghb_dict_get_bool(uiDict, "VideoFramerateCFR")) { - g_string_append_printf(str, "\nConstant Framerate %s fps", rate_str); + g_string_append_printf(str, _("\nConstant Framerate %s fps"), rate_str); } else if (ghb_dict_get_bool(uiDict, "VideoFrameratePFR")) { - g_string_append_printf(str, "\nPeak Framerate %s fps (may be lower)", + g_string_append_printf(str, _("\nPeak Framerate %s fps (may be lower)"), rate_str); } else if (ghb_dict_get_bool(uiDict, "VideoFramerateVFR")) { - g_string_append_printf(str, "\nVariable Framerate %s fps", rate_str); + g_string_append_printf(str, _("\nVariable Framerate %s fps"), rate_str); } g_free(rate_str); @@ -483,18 +490,18 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) burn = ghb_dict_get_bool(searchDict, "Burn"); def = ghb_dict_get_bool(searchDict, "Default"); - g_string_append_printf(str, "Foreign Audio Scan"); + g_string_append_printf(str, _("Foreign Audio Scan")); if (force) { - g_string_append_printf(str, ", Forced Only"); + g_string_append_printf(str, _(", Forced Only")); } if (burn) { - g_string_append_printf(str, ", Burned"); + g_string_append_printf(str, _(", Burned")); } else if (def) { - g_string_append_printf(str, ", Default"); + g_string_append_printf(str, _(", Default")); } sep = "\n"; } @@ -516,15 +523,15 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) g_string_append_printf(str, "%s%s", sep, desc); if (force) { - g_string_append_printf(str, ", Forced Only"); + g_string_append_printf(str, _(", Forced Only")); } if (burn) { - g_string_append_printf(str, ", Burned"); + g_string_append_printf(str, _(", Burned")); } else if (def) { - g_string_append_printf(str, ", Default"); + g_string_append_printf(str, _(", Default")); } sep = "\n"; } @@ -535,6 +542,160 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) g_free(text); } +void +queue_update_stats(GhbValue * queueDict, signal_user_data_t *ud) +{ + GhbValue * uiDict; + + uiDict = ghb_dict_get(queueDict, "uiSettings"); + if (uiDict == NULL) // should never happen + { + return; + } + + const char * result = ""; + int status = ghb_dict_get_int(uiDict, "job_status"); + + switch (status) + { + case GHB_QUEUE_RUNNING: + // This job is running. + // ghb_queue_update_live_stats() will update stats + return; + + case GHB_QUEUE_DONE: + result = _("Completed"); + break; + + case GHB_QUEUE_CANCELED: + result = _("Canceled"); + break; + + case GHB_QUEUE_FAIL: + result = _("Failed"); + break; + + case GHB_QUEUE_PENDING: + default: + // Should never happen + result = _("Unknown"); + break; + } + + GtkLabel * label; + struct tm * tm; + char date[40] = ""; + char * str; + time_t start, finish, paused, duration; + + start = ghb_dict_get_int(uiDict, "job_start_time"); + finish = ghb_dict_get_int(uiDict, "job_finish_time"); + paused = ghb_dict_get_int(uiDict, "job_pause_time_ms") / 1000; + + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_pass_label")); + gtk_widget_set_visible(GTK_WIDGET(label), FALSE); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_pass")); + gtk_widget_set_visible(GTK_WIDGET(label), FALSE); + + tm = localtime( &start ); + strftime(date, 40, "%c", tm); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_start_time")); + gtk_label_set_text(label, date); + + tm = localtime( &finish ); + strftime(date, 40, "%c", tm); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_finish_time")); + gtk_label_set_text(label, date); + + int dd = 0, hh, mm, ss; + ghb_break_duration(paused, &hh, &mm, &ss); + if (hh >= 24) + { + dd = hh / 24; + hh = hh - dd * 24; + } + switch (dd) + { + case 0: + str = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss); + break; + case 1: + str = g_strdup_printf(_("%d Day %02d:%02d:%02d"), dd, hh, mm, ss); + break; + default: + str = g_strdup_printf(_("%d Days %02d:%02d:%02d"), dd, hh, mm, ss); + break; + } + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_paused")); + gtk_label_set_text(label, str); + g_free(str); + + duration = finish - start; + if (duration < 0) + { + duration = 0; + } + dd = 0; + ghb_break_duration(duration, &hh, &mm, &ss); + if (hh >= 24) + { + dd = hh / 24; + hh = hh - dd * 24; + } + switch (dd) + { + case 0: + str = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss); + break; + case 1: + str = g_strdup_printf(_("%d Day %02d:%02d:%02d"), dd, hh, mm, ss); + break; + default: + str = g_strdup_printf(_("%d Days %02d:%02d:%02d"), dd, hh, mm, ss); + break; + } + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_encode")); + gtk_label_set_text(label, str); + g_free(str); + + const char * path; + struct stat stbuf; + + path = ghb_dict_get_string(uiDict, "destination"); + if (g_stat(path, &stbuf) == 0) + { + const char * units = _("B"); + double size = stbuf.st_size; + if (size > 1024) + { + units = _("KB"); + size /= 1024.0; + } + if (size > 1024) + { + units = _("MB"); + size /= 1024.0; + } + if (size > 1024) + { + units = _("GB"); + size /= 1024.0; + } + str = g_strdup_printf("%.2f %s", size, units); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_file_size")); + gtk_label_set_text(label, str); + g_free(str); + } + else + { + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_file_size")); + gtk_label_set_text(label, _("Error")); + } + + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_result")); + gtk_label_set_text(label, result); +} + #define ACTIVITY_MAX_READ_SZ (1024*1024) static void read_log(signal_user_data_t * ud, const char * log_path) { @@ -592,11 +753,12 @@ void ghb_queue_select_log(signal_user_data_t * ud) GtkTextBuffer * current; gint index; GhbValue * queueDict, *uiDict; - GtkWidget * queue_log_tab; + GtkWidget * queue_log_tab, * queue_stats_tab; - queue_log_tab = GHB_WIDGET(ud->builder, "queue_log_tab"); - lb = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "queue_list")); - row = gtk_list_box_get_selected_row(lb); + queue_log_tab = GHB_WIDGET(ud->builder, "queue_log_tab"); + queue_stats_tab = GHB_WIDGET(ud->builder, "queue_stats_tab"); + lb = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "queue_list")); + row = gtk_list_box_get_selected_row(lb); if (row != NULL) { // There is a queue list row selected @@ -619,6 +781,7 @@ void ghb_queue_select_log(signal_user_data_t * ud) // Selected encode is running, enable display of log and // show the live buffer gtk_widget_set_visible(queue_log_tab, TRUE); + gtk_widget_set_visible(queue_stats_tab, TRUE); if (ud->queue_activity_buffer != current) { gtk_text_view_set_buffer(tv, ud->queue_activity_buffer); @@ -639,6 +802,7 @@ void ghb_queue_select_log(signal_user_data_t * ud) { // enable display of log and read log into display buffer gtk_widget_set_visible(queue_log_tab, TRUE); + gtk_widget_set_visible(queue_stats_tab, TRUE); ghb_ui_update(ud, "queue_activity_location", ghb_string_value(log_path)); read_log(ud, log_path); @@ -648,6 +812,7 @@ void ghb_queue_select_log(signal_user_data_t * ud) // No log file, encode is pending // disable display of log gtk_widget_set_visible(queue_log_tab, FALSE); + gtk_widget_set_visible(queue_stats_tab, FALSE); } } } @@ -655,6 +820,7 @@ void ghb_queue_select_log(signal_user_data_t * ud) { // No row selected, disable display of log gtk_widget_set_visible(queue_log_tab, FALSE); + gtk_widget_set_visible(queue_stats_tab, FALSE); } } @@ -692,6 +858,7 @@ queue_list_selection_changed_cb(GtkListBox *box, GtkListBoxRow *row, queueDict = ghb_array_get(ud->queue, index); } queue_update_summary(queueDict, ud); + queue_update_stats(queueDict, ud); ghb_queue_select_log(ud); ghb_queue_buttons_grey(ud); } @@ -867,6 +1034,224 @@ ghb_queue_progress_set_fraction(signal_user_data_t *ud, int index, gdouble frac) } void +ghb_queue_update_live_stats(signal_user_data_t * ud, int index, ghb_instance_status_t * status) +{ + int count = ghb_array_len(ud->queue); + if (index < 0 || index >= count) + { + // invalid index + return; + } + + GtkListBox * lb; + GtkListBoxRow * row; + + lb = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "queue_list")); + row = gtk_list_box_get_selected_row(lb); + if (row == NULL || index != gtk_list_box_row_get_index(row)) + { + return; + } + + GhbValue * queueDict, * uiDict; + queueDict = ghb_array_get(ud->queue, index); + if (queueDict == NULL) // should never happen + { + return; + } + uiDict = ghb_dict_get(queueDict, "uiSettings"); + if (uiDict == NULL) // should never happen + { + return; + } + + GtkLabel * label; + struct tm * tm; + char date[40] = ""; + char * str; + const char * pass = ""; + const char * result = ""; + time_t start, finish, paused, duration; + + start = ghb_dict_get_int(uiDict, "job_start_time"); + finish = time(NULL); + if (status->state & GHB_STATE_WORKING) + { + finish += status->eta_seconds; + } + paused = status->paused / 1000; + if ((status->state & GHB_STATE_WORKING) && status->pass_count > 1) + { + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_pass_label")); + gtk_widget_set_visible(GTK_WIDGET(label), TRUE); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_pass")); + gtk_widget_set_visible(GTK_WIDGET(label), TRUE); + switch (status->pass_id) + { + case HB_PASS_SUBTITLE: + pass = _("Foreign Audio Search"); + break; + + case HB_PASS_ENCODE_1ST: + pass = _("Encode First"); + break; + + case HB_PASS_ENCODE_2ND: + pass = _("Encode Second"); + break; + + default: + // Should never happen + pass = _("Error"); + break; + } + } + else + { + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_pass_label")); + gtk_widget_set_visible(GTK_WIDGET(label), FALSE); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_pass")); + gtk_widget_set_visible(GTK_WIDGET(label), FALSE); + } + + if (status->state & GHB_STATE_SCANNING) + { + result = _("Scanning Title"); + } + else if (status->state & GHB_STATE_SCANNING) + { + result = _("Encoding Paused"); + } + else if (status->state & GHB_STATE_WORKING) + { + result = _("Encoding In Progress"); + } + else if (status->state & GHB_STATE_WORKDONE) + { + switch (status->error) + { + case GHB_ERROR_NONE: + result = _("Completed"); + break; + + case GHB_ERROR_CANCELED: + result = _("Canceled"); + break; + + case GHB_ERROR_FAIL: + result = _("Failed"); + break; + + default: + // Should never happen + result = _("Unknown"); + break; + } + } + + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_pass")); + gtk_label_set_text(label, pass); + + tm = localtime( &start ); + strftime(date, 40, "%c", tm); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_start_time")); + gtk_label_set_text(label, date); + + tm = localtime( &finish ); + strftime(date, 40, "%c", tm); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_finish_time")); + gtk_label_set_text(label, date); + + int dd = 0, hh, mm, ss; + ghb_break_duration(paused, &hh, &mm, &ss); + if (hh >= 24) + { + dd = hh / 24; + hh = hh - dd * 24; + } + switch (dd) + { + case 0: + str = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss); + break; + case 1: + str = g_strdup_printf(_("%d Day %02d:%02d:%02d"), dd, hh, mm, ss); + break; + default: + str = g_strdup_printf(_("%d Days %02d:%02d:%02d"), dd, hh, mm, ss); + break; + } + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_paused")); + gtk_label_set_text(label, str); + g_free(str); + + duration = finish - start; + if (duration < 0) + { + duration = 0; + } + dd = 0; + ghb_break_duration(duration, &hh, &mm, &ss); + if (hh >= 24) + { + dd = hh / 24; + hh = hh - dd * 24; + } + switch (dd) + { + case 0: + str = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss); + break; + case 1: + str = g_strdup_printf(_("%d Day %02d:%02d:%02d"), dd, hh, mm, ss); + break; + default: + str = g_strdup_printf(_("%d Days %02d:%02d:%02d"), dd, hh, mm, ss); + break; + } + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_encode")); + gtk_label_set_text(label, str); + g_free(str); + + const char * path; + struct stat stbuf; + + path = ghb_dict_get_string(uiDict, "destination"); + if (g_stat(path, &stbuf) == 0) + { + const char * units = _("B"); + double size = stbuf.st_size; + if (size > 1024) + { + units = _("KB"); + size /= 1024.0; + } + if (size > 1024) + { + units = _("MB"); + size /= 1024.0; + } + if (size > 1024) + { + units = _("GB"); + size /= 1024.0; + } + str = g_strdup_printf("%.2f %s", size, units); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_file_size")); + gtk_label_set_text(label, str); + g_free(str); + } + else + { + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_file_size")); + gtk_label_set_text(label, _("Error")); + } + + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_result")); + gtk_label_set_text(label, result); +} + +void ghb_queue_update_status_icon(signal_user_data_t *ud, int index) { int count = ghb_array_len(ud->queue); @@ -2376,7 +2761,7 @@ queue_drag_motion_cb( } G_MODULE_EXPORT void -queue_drag_cb( +queue_drop_cb( GtkListBox * lb, GdkDragContext * ctx, gint x, diff --git a/gtk/src/queuehandler.h b/gtk/src/queuehandler.h index 55a6a6e88..0814209f0 100644 --- a/gtk/src/queuehandler.h +++ b/gtk/src/queuehandler.h @@ -27,6 +27,7 @@ #include <gtk/gtk.h> #include "settings.h" +#include "hb-backend.h" void ghb_queue_buttons_grey(signal_user_data_t *ud); gboolean ghb_reload_queue(signal_user_data_t *ud); @@ -41,5 +42,7 @@ void ghb_queue_progress_set_fraction(signal_user_data_t *ud, int index, void ghb_queue_update_status(signal_user_data_t *ud, int index, int status); void ghb_queue_update_status_icon(signal_user_data_t *ud, int index); void ghb_queue_select_log(signal_user_data_t * ud); +void ghb_queue_update_live_stats(signal_user_data_t * ud, int index, + ghb_instance_status_t * status); #endif // _QUEUEHANDLER_H_ diff --git a/libhb/common.h b/libhb/common.h index 8c112e7ad..a5127bc66 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -722,7 +722,6 @@ struct hb_job_s volatile int * die; volatile int done; - uint64_t st_pause_date; uint64_t st_paused; hb_fifo_t * fifo_mpeg2; /* MPEG-2 video ES */ @@ -1127,9 +1126,10 @@ struct hb_state_s #define HB_STATE_WORKDONE 32 #define HB_STATE_MUXING 64 #define HB_STATE_SEARCHING 128 - int state; + int state; + int sequence_id; - union + struct { struct { @@ -1148,16 +1148,17 @@ struct hb_state_s #define HB_PASS_ENCODE 0 #define HB_PASS_ENCODE_1ST 1 // Some code depends on these values being #define HB_PASS_ENCODE_2ND 2 // 1 and 2. Do not change. - int pass_id; - int pass; - int pass_count; - float progress; - float rate_cur; - float rate_avg; - int hours; - int minutes; - int seconds; - int sequence_id; + int pass_id; + int pass; + int pass_count; + float progress; + float rate_cur; + float rate_avg; + int64_t eta_seconds; + int hours; + int minutes; + int seconds; + uint64_t paused; hb_error_code error; } working; diff --git a/libhb/hb.c b/libhb/hb.c index 720a7585d..4edf4835e 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -54,6 +54,8 @@ struct hb_handle_s int paused; hb_lock_t * pause_lock; + int64_t pause_date; + int64_t pause_duration; volatile int scan_die; @@ -211,6 +213,7 @@ hb_handle_t * hb_init( int verbose ) h->state.state = HB_STATE_IDLE; h->pause_lock = hb_lock_init(); + h->pause_date = -1; h->interjob = calloc( sizeof( hb_interjob_t ), 1 ); @@ -1506,25 +1509,28 @@ void hb_rem( hb_handle_t * h, hb_job_t * job ) void hb_start( hb_handle_t * h ) { hb_lock( h->state_lock ); - h->state.state = HB_STATE_WORKING; + h->state.state = HB_STATE_WORKING; + h->state.sequence_id = 0; #define p h->state.param.working - p.pass = -1; - p.pass_count = -1; - p.progress = 0.0; - p.rate_cur = 0.0; - p.rate_avg = 0.0; - p.hours = -1; - p.minutes = -1; - p.seconds = -1; - p.sequence_id = 0; + p.pass = -1; + p.pass_count = -1; + p.progress = 0.0; + p.rate_cur = 0.0; + p.rate_avg = 0.0; + p.eta_seconds = 0; + p.hours = -1; + p.minutes = -1; + p.seconds = -1; + p.paused = 0; #undef p hb_unlock( h->state_lock ); - h->paused = 0; - - h->work_die = 0; - h->work_error = HB_ERROR_NONE; - h->work_thread = hb_work_init( h->jobs, &h->work_die, &h->work_error, &h->current_job ); + h->paused = 0; + h->pause_date = -1; + h->pause_duration = 0; + h->work_die = 0; + h->work_error = HB_ERROR_NONE; + h->work_thread = hb_work_init( h->jobs, &h->work_die, &h->work_error, &h->current_job ); } /** @@ -1538,7 +1544,7 @@ void hb_pause( hb_handle_t * h ) hb_lock( h->pause_lock ); h->paused = 1; - hb_current_job( h )->st_pause_date = hb_get_date(); + h->pause_date = hb_get_date(); hb_lock( h->state_lock ); h->state.state = HB_STATE_PAUSED; @@ -1554,12 +1560,17 @@ void hb_resume( hb_handle_t * h ) { if( h->paused ) { -#define job hb_current_job( h ) - if( job->st_pause_date != -1 ) + if (h->pause_date != -1) { - job->st_paused += hb_get_date() - job->st_pause_date; + // Calculate paused time for current job sequence + h->pause_duration += hb_get_date() - h->pause_date; + + // Calculate paused time for current job pass + // Required to calculate accurate ETA for pass + h->current_job->st_paused += hb_get_date() - h->pause_date; + h->pause_date = -1; + h->state.param.working.paused = h->pause_duration; } -#undef job hb_unlock( h->pause_lock ); h->paused = 0; @@ -1830,6 +1841,11 @@ static void thread_func( void * _h ) hb_unlock( h->state_lock ); } + if (h->paused) + { + h->state.param.working.paused = h->pause_duration + + hb_get_date() - h->pause_date; + } hb_snooze( 50 ); } @@ -1905,9 +1921,7 @@ void hb_set_state( hb_handle_t * h, hb_state_t * s ) { // Set which job is being worked on if (h->current_job) - h->state.param.working.sequence_id = h->current_job->sequence_id; - else - h->state.param.working.sequence_id = 0; + h->state.sequence_id = h->current_job->sequence_id; } hb_unlock( h->state_lock ); hb_unlock( h->pause_lock ); diff --git a/libhb/hb_json.c b/libhb/hb_json.c index d3d190df4..70fbe4284 100644 --- a/libhb/hb_json.c +++ b/libhb/hb_json.c @@ -63,9 +63,10 @@ hb_dict_t* hb_state_to_dict( hb_state_t * state) case HB_STATE_SCANNING: case HB_STATE_SCANDONE: dict = json_pack_ex(&error, 0, - "{s:o, s{s:o, s:o, s:o, s:o, s:o}}", + "{s:o, s{s:o, s:o, s:o, s:o, s:o, s:o}}", "State", hb_value_string(state_s), "Scanning", + "SequenceID", hb_value_int(state->sequence_id), "Progress", hb_value_double(state->param.scanning.progress), "Preview", hb_value_int(state->param.scanning.preview_cur), "PreviewCount", hb_value_int(state->param.scanning.preview_count), @@ -88,14 +89,14 @@ hb_dict_t* hb_state_to_dict( hb_state_t * state) "Hours", hb_value_int(state->param.working.hours), "Minutes", hb_value_int(state->param.working.minutes), "Seconds", hb_value_int(state->param.working.seconds), - "SequenceID", hb_value_int(state->param.working.sequence_id)); + "SequenceID", hb_value_int(state->sequence_id)); break; case HB_STATE_WORKDONE: dict = json_pack_ex(&error, 0, "{s:o, s{s:o, s:o}}", "State", hb_value_string(state_s), "WorkDone", - "SequenceID", hb_value_int(state->param.working.sequence_id), + "SequenceID", hb_value_int(state->sequence_id), "Error", hb_value_int(state->param.working.error)); break; case HB_STATE_MUXING: diff --git a/libhb/muxcommon.c b/libhb/muxcommon.c index 93b144a23..de62c1241 100644 --- a/libhb/muxcommon.c +++ b/libhb/muxcommon.c @@ -505,9 +505,10 @@ static void muxClose( hb_work_object_t * muxer ) { /* Update the UI */ hb_state_t state; + hb_get_state2(job->h, &state); state.state = HB_STATE_MUXING; state.param.muxing.progress = 0; - hb_set_state( job->h, &state ); + hb_set_state(job->h, &state); } if( mux->m ) diff --git a/libhb/scan.c b/libhb/scan.c index 640ffdddb..53e3921ea 100644 --- a/libhb/scan.c +++ b/libhb/scan.c @@ -75,6 +75,7 @@ hb_thread_t * hb_scan_init( hb_handle_t * handle, volatile int * die, // Initialize scan state hb_state_t state; + hb_get_state2(handle, &state); #define p state.param.scanning state.state = HB_STATE_SCANNING; p.title_cur = 1; @@ -1434,6 +1435,7 @@ static void UpdateState1(hb_scan_t *scan, int title) { hb_state_t state; + hb_get_state2(scan->h, &state); #define p state.param.scanning /* Update the UI */ state.state = HB_STATE_SCANNING; @@ -1454,6 +1456,7 @@ static void UpdateState2(hb_scan_t *scan, int title) { hb_state_t state; + hb_get_state2(scan->h, &state); #define p state.param.scanning /* Update the UI */ state.state = HB_STATE_SCANNING; diff --git a/libhb/sync.c b/libhb/sync.c index 4969b2268..201bca65b 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -3233,8 +3233,6 @@ static void UpdateState( sync_common_t * common, int frame_count ) if (frame_count == 0) { common->st_first = hb_get_date(); - job->st_pause_date = -1; - job->st_paused = 0; } if (hb_get_date() > common->st_dates[3] + 1000) @@ -3264,9 +3262,10 @@ static void UpdateState( sync_common_t * common, int frame_count ) p.rate_avg = 1000.0 * common->st_counts[3] / (common->st_dates[3] - common->st_first - job->st_paused); eta = (common->est_frame_count - common->st_counts[3]) / p.rate_avg; - p.hours = eta / 3600; - p.minutes = (eta % 3600) / 60; - p.seconds = eta % 60; + p.eta_seconds = eta; + p.hours = eta / 3600; + p.minutes = (eta % 3600) / 60; + p.seconds = eta % 60; } else { @@ -3300,8 +3299,6 @@ static void UpdateSearchState( sync_common_t * common, int64_t start, if (frame_count == 0) { common->st_first = now; - job->st_pause_date = -1; - job->st_paused = 0; } hb_get_state2(job->h, &state); @@ -3332,9 +3329,10 @@ static void UpdateSearchState( sync_common_t * common, int64_t start, avg = 1000.0 * start / (now - common->st_first); eta = (common->pts_to_start - start) / avg; } - p.hours = eta / 3600; - p.minutes = (eta % 3600) / 60; - p.seconds = eta % 60; + p.eta_seconds = eta; + p.hours = eta / 3600; + p.minutes = (eta % 3600) / 60; + p.seconds = eta % 60; } else { diff --git a/libhb/work.c b/libhb/work.c index a20f33dbd..56e7270bb 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -57,43 +57,40 @@ hb_thread_t * hb_work_init( hb_list_t * jobs, volatile int * die, hb_error_code return hb_thread_init( "work", work_func, work, HB_LOW_PRIORITY ); } -static void InitWorkState(hb_handle_t *h, int pass_id, int pass, int pass_count) +static void InitWorkState(hb_job_t * job, int pass, int pass_count) { hb_state_t state; - state.state = HB_STATE_WORKING; + memset(&state, 0, sizeof(state)); + state.state = HB_STATE_WORKING; + state.sequence_id = job->sequence_id; #define p state.param.working - p.pass_id = pass_id; - p.pass = pass; - p.pass_count = pass_count; - p.progress = 0.0; - p.rate_cur = 0.0; - p.rate_avg = 0.0; - p.hours = -1; - p.minutes = -1; - p.seconds = -1; + p.pass_id = job->pass_id; + p.pass = pass; + p.pass_count = pass_count; + p.progress = 0.0; + p.rate_cur = 0.0; + p.rate_avg = 0.0; + p.eta_seconds = 0; + p.hours = -1; + p.minutes = -1; + p.seconds = -1; #undef p - hb_set_state( h, &state ); - + hb_set_state( job->h, &state ); } static void SetWorkStateInfo(hb_job_t *job) { hb_state_t state; - if (job == NULL) { return; } hb_get_state2(job->h, &state); - - state.param.working.error = *job->done_error; - state.param.working.sequence_id = job->sequence_id; - + state.param.working.error = *job->done_error; hb_set_state( job->h, &state ); - } /** @@ -122,6 +119,8 @@ static void work_func( void * _work ) { hb_deep_log(1, "json job:\n%s", job->json); + // Initialize state sequence_id + InitWorkState(job, 0, 0); // Perform title scan for json job hb_json_job_scan(job->h, job->json); @@ -151,7 +150,7 @@ static void work_func( void * _work ) job->die = work->die; job->done_error = work->error; *(work->current_job) = job; - InitWorkState(job->h, job->pass_id, pass + 1, pass_count); + InitWorkState(job, pass + 1, pass_count); do_job( job ); } SetWorkStateInfo(job); |