summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gtk/src/callbacks.c26
-rw-r--r--gtk/src/callbacks.h1
-rw-r--r--gtk/src/ghb.m4302
-rw-r--r--gtk/src/hb-backend.c120
-rw-r--r--gtk/src/hb-backend.h18
-rw-r--r--gtk/src/queuehandler.c447
-rw-r--r--gtk/src/queuehandler.h3
-rw-r--r--libhb/common.h27
-rw-r--r--libhb/hb.c60
-rw-r--r--libhb/hb_json.c7
-rw-r--r--libhb/muxcommon.c3
-rw-r--r--libhb/scan.c3
-rw-r--r--libhb/sync.c18
-rw-r--r--libhb/work.c39
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">&lt;span size="x-large"&gt;Queue&lt;/span&gt;</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);