diff options
-rw-r--r-- | gtk/src/callbacks.c | 184 | ||||
-rw-r--r-- | gtk/src/ghb.ui | 311 | ||||
-rw-r--r-- | gtk/src/hb-backend.c | 411 | ||||
-rw-r--r-- | gtk/src/hb-backend.h | 25 | ||||
-rw-r--r-- | gtk/src/internal_defaults.xml | 16 | ||||
-rw-r--r-- | gtk/src/presets.c | 30 | ||||
-rw-r--r-- | gtk/src/values.c | 9 | ||||
-rw-r--r-- | libhb/bd.c | 4 | ||||
-rw-r--r-- | libhb/common.c | 742 | ||||
-rw-r--r-- | libhb/common.h | 101 | ||||
-rw-r--r-- | libhb/decavcodec.c | 2 | ||||
-rw-r--r-- | libhb/decmetadata.c | 114 | ||||
-rw-r--r-- | libhb/decmpeg2.c | 8 | ||||
-rw-r--r-- | libhb/decsrtsub.c | 5 | ||||
-rw-r--r-- | libhb/dvd.c | 4 | ||||
-rw-r--r-- | libhb/dvdnav.c | 4 | ||||
-rw-r--r-- | libhb/hb.c | 326 | ||||
-rw-r--r-- | libhb/hb.h | 18 | ||||
-rw-r--r-- | libhb/internal.h | 4 | ||||
-rw-r--r-- | libhb/muxcommon.c | 9 | ||||
-rw-r--r-- | libhb/muxmkv.c | 72 | ||||
-rw-r--r-- | libhb/muxmp4.c | 73 | ||||
-rw-r--r-- | libhb/reader.c | 20 | ||||
-rw-r--r-- | libhb/rendersub.c | 6 | ||||
-rw-r--r-- | libhb/scan.c | 104 | ||||
-rw-r--r-- | libhb/stream.c | 100 | ||||
-rw-r--r-- | libhb/sync.c | 7 | ||||
-rw-r--r-- | libhb/work.c | 113 | ||||
-rw-r--r-- | macosx/ChapterTitles.m | 17 | ||||
-rw-r--r-- | macosx/Controller.m | 62 | ||||
-rw-r--r-- | macosx/HBPreviewController.m | 4 | ||||
-rw-r--r-- | test/test.c | 78 |
32 files changed, 1960 insertions, 1023 deletions
diff --git a/gtk/src/callbacks.c b/gtk/src/callbacks.c index 0ff45d1c1..29c767c17 100644 --- a/gtk/src/callbacks.c +++ b/gtk/src/callbacks.c @@ -1328,9 +1328,8 @@ update_title_duration(signal_user_data_t *ud) } else if (ghb_settings_combo_int(ud->settings, "PtoPType") == 2) { - ghb_title_info_t tinfo; - - if (ghb_get_title_info (&tinfo, ti)) + hb_title_t * title = ghb_get_title_info (ti); + if (title != NULL) { gint64 frames; gint duration; @@ -1338,7 +1337,7 @@ update_title_duration(signal_user_data_t *ud) start = ghb_settings_get_int(ud->settings, "start_point"); end = ghb_settings_get_int(ud->settings, "end_point"); frames = end - start + 1; - duration = frames * tinfo.rate_base / tinfo.rate; + duration = frames * title->rate_base / title->rate; hh = duration / (60*60); mm = (duration / 60) % 60; ss = duration % 60; @@ -1354,19 +1353,19 @@ update_title_duration(signal_user_data_t *ud) } static void -show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo) +show_title_info(signal_user_data_t *ud, hb_title_t *title) { GtkWidget *widget; gchar *text; - ghb_settings_set_string(ud->settings, "source", tinfo->path); - if (tinfo->type == HB_STREAM_TYPE || tinfo->type == HB_FF_STREAM_TYPE) + ghb_settings_set_string(ud->settings, "source", title->path); + if (title->type == HB_STREAM_TYPE || title->type == HB_FF_STREAM_TYPE) { GtkWidget *widget = GHB_WIDGET (ud->builder, "source_title"); - if (tinfo->name != NULL && tinfo->name[0] != 0) + if (title->name != NULL && title->name[0] != 0) { - gtk_label_set_text (GTK_LABEL(widget), tinfo->name); - ghb_settings_set_string(ud->settings, "volume_label", tinfo->name); + gtk_label_set_text (GTK_LABEL(widget), title->name); + ghb_settings_set_string(ud->settings, "volume_label", title->name); set_destination(ud); } else @@ -1380,31 +1379,35 @@ show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo) ud->scale_busy = TRUE; update_title_duration(ud); widget = GHB_WIDGET (ud->builder, "source_codec"); - if ( tinfo->video_codec_name ) - gtk_label_set_text (GTK_LABEL(widget), tinfo->video_codec_name); + if ( title->video_codec_name ) + gtk_label_set_text (GTK_LABEL(widget), title->video_codec_name); else gtk_label_set_text (GTK_LABEL(widget), "Unknown"); widget = GHB_WIDGET (ud->builder, "source_dimensions"); - text = g_strdup_printf ("%d x %d", tinfo->width, tinfo->height); + text = g_strdup_printf ("%d x %d", title->width, title->height); gtk_label_set_text (GTK_LABEL(widget), text); - ghb_settings_set_int(ud->settings, "source_width", tinfo->width); - ghb_settings_set_int(ud->settings, "source_height", tinfo->height); + ghb_settings_set_int(ud->settings, "source_width", title->width); + ghb_settings_set_int(ud->settings, "source_height", title->height); g_free(text); widget = GHB_WIDGET (ud->builder, "source_aspect"); - text = get_aspect_string(tinfo->aspect_n, tinfo->aspect_d); + gint aspect_n, aspect_d; + hb_reduce(&aspect_n, &aspect_d, + title->width * title->pixel_aspect_width, + title->height * title->pixel_aspect_height); + text = get_aspect_string(aspect_n, aspect_d); gtk_label_set_text (GTK_LABEL(widget), text); g_free(text); widget = GHB_WIDGET (ud->builder, "source_frame_rate"); - text = (gchar*)get_rate_string(tinfo->rate_base, tinfo->rate); + text = (gchar*)get_rate_string(title->rate_base, title->rate); gtk_label_set_text (GTK_LABEL(widget), text); g_free(text); //widget = GHB_WIDGET (ud->builder, "source_interlaced"); - //gtk_label_set_text (GTK_LABEL(widget), tinfo->interlaced ? "Yes" : "No"); + //gtk_label_set_text (GTK_LABEL(widget), title->interlaced ? "Yes" : "No"); ghb_ui_update(ud, "scale_width", - ghb_int64_value(tinfo->width - tinfo->crop[2] - tinfo->crop[3])); + ghb_int64_value(title->width - title->crop[2] - title->crop[3])); // If anamorphic or keep_aspect, the hight will be automatically calculated gboolean keep_aspect; gint pic_par; @@ -1413,28 +1416,28 @@ show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo) if (!(keep_aspect || pic_par) || pic_par == 3) { ghb_ui_update(ud, "scale_height", - ghb_int64_value(tinfo->height - tinfo->crop[0] - tinfo->crop[1])); + ghb_int64_value(title->height - title->crop[0] - title->crop[1])); } // Set the limits of cropping. hb_set_anamorphic_size crashes if // you pass it a cropped width or height == 0. gint bound; - bound = tinfo->height / 2 - 8; + bound = title->height / 2 - 8; widget = GHB_WIDGET (ud->builder, "PictureTopCrop"); gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound); widget = GHB_WIDGET (ud->builder, "PictureBottomCrop"); gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound); - bound = tinfo->width / 2 - 8; + bound = title->width / 2 - 8; widget = GHB_WIDGET (ud->builder, "PictureLeftCrop"); gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound); widget = GHB_WIDGET (ud->builder, "PictureRightCrop"); gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound); if (ghb_settings_get_boolean(ud->settings, "PictureAutoCrop")) { - ghb_ui_update(ud, "PictureTopCrop", ghb_int64_value(tinfo->crop[0])); - ghb_ui_update(ud, "PictureBottomCrop", ghb_int64_value(tinfo->crop[1])); - ghb_ui_update(ud, "PictureLeftCrop", ghb_int64_value(tinfo->crop[2])); - ghb_ui_update(ud, "PictureRightCrop", ghb_int64_value(tinfo->crop[3])); + ghb_ui_update(ud, "PictureTopCrop", ghb_int64_value(title->crop[0])); + ghb_ui_update(ud, "PictureBottomCrop", ghb_int64_value(title->crop[1])); + ghb_ui_update(ud, "PictureLeftCrop", ghb_int64_value(title->crop[2])); + ghb_ui_update(ud, "PictureRightCrop", ghb_int64_value(title->crop[3])); } ud->scale_busy = FALSE; ghb_set_scale (ud, GHB_PIC_KEEP_PAR|GHB_PIC_USE_MAX); @@ -1443,25 +1446,26 @@ show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo) crop[1] = ghb_settings_get_int(ud->settings, "PictureBottomCrop"); crop[2] = ghb_settings_get_int(ud->settings, "PictureLeftCrop"); crop[3] = ghb_settings_get_int(ud->settings, "PictureRightCrop"); - width = tinfo->width - crop[2] - crop[3]; - height = tinfo->height - crop[0] - crop[1]; + width = title->width - crop[2] - crop[3]; + height = title->height - crop[0] - crop[1]; widget = GHB_WIDGET (ud->builder, "crop_dimensions"); text = g_strdup_printf ("%d x %d", width, height); gtk_label_set_text (GTK_LABEL(widget), text); g_free(text); - gint duration = tinfo->duration / 90000; + gint duration = title->duration / 90000; + gint num_chapters = hb_list_count(title->list_chapter); if (ghb_settings_combo_int(ud->settings, "PtoPType") == 0) { widget = GHB_WIDGET (ud->builder, "start_point"); - gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo->num_chapters); + gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, num_chapters); gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), 1); widget = GHB_WIDGET (ud->builder, "end_point"); - gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo->num_chapters); - gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), tinfo->num_chapters); + gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, num_chapters); + gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), num_chapters); } else if (ghb_settings_combo_int(ud->settings, "PtoPType") == 1) { @@ -1476,7 +1480,7 @@ show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo) } else if (ghb_settings_combo_int(ud->settings, "PtoPType") == 2) { - gdouble max_frames = (gdouble)duration * tinfo->rate / tinfo->rate_base; + gdouble max_frames = (gdouble)duration * title->rate / title->rate_base; widget = GHB_WIDGET (ud->builder, "start_point"); gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, max_frames); gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), 1); @@ -1488,29 +1492,57 @@ show_title_info(signal_user_data_t *ud, ghb_title_info_t *tinfo) widget = GHB_WIDGET (ud->builder, "angle"); gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), 1); - gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo->angle_count); - ghb_settings_set_int(ud->settings, "angle_count", tinfo->angle_count); + gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, title->angle_count); + ghb_settings_set_int(ud->settings, "angle_count", title->angle_count); ud->dont_clear_presets = FALSE; + // Set default metadata name + ghb_ui_update(ud, "MetaName", ghb_string_value(title->name)); + if (title->metadata) + { + if (title->metadata->name) + { + ghb_ui_update(ud, "MetaName", + ghb_string_value(title->metadata->name)); + } + ghb_ui_update(ud, "MetaArtist", + ghb_string_value(title->metadata->artist)); + ghb_ui_update(ud, "MetaReleaseDate", + ghb_string_value(title->metadata->release_date)); + ghb_ui_update(ud, "MetaComment", + ghb_string_value(title->metadata->comment)); + if (!title->metadata->name && title->metadata->album) + { + ghb_ui_update(ud, "MetaName", + ghb_string_value(title->metadata->album)); + } + ghb_ui_update(ud, "MetaAlbumArtist", + ghb_string_value(title->metadata->album_artist)); + ghb_ui_update(ud, "MetaGenre", + ghb_string_value(title->metadata->genre)); + ghb_ui_update(ud, "MetaDescription", + ghb_string_value(title->metadata->description)); + ghb_ui_update(ud, "MetaLongDescription", + ghb_string_value(title->metadata->long_description)); + } } void set_title_settings(GValue *settings, gint titleindex) { - ghb_title_info_t tinfo; - ghb_settings_set_int(settings, "title", titleindex); ghb_settings_set_int(settings, "title_no", titleindex); - if (ghb_get_title_info (&tinfo, titleindex)) + hb_title_t * title = ghb_get_title_info(titleindex); + if (title != NULL) { - ghb_settings_set_int(settings, "source_width", tinfo.width); - ghb_settings_set_int(settings, "source_height", tinfo.height); - ghb_settings_set_string(settings, "source", tinfo.path); - if (tinfo.type == HB_STREAM_TYPE || tinfo.type == HB_FF_STREAM_TYPE) + ghb_settings_set_int(settings, "source_width", title->width); + ghb_settings_set_int(settings, "source_height", title->height); + ghb_settings_set_string(settings, "source", title->path); + if (title->type == HB_STREAM_TYPE || title->type == HB_FF_STREAM_TYPE) { - if (tinfo.name != NULL && tinfo.name[0] != 0) + if (title->name != NULL && title->name[0] != 0) { - ghb_settings_set_string(settings, "volume_label", tinfo.name); + ghb_settings_set_string(settings, "volume_label", title->name); } else { @@ -1519,7 +1551,7 @@ set_title_settings(GValue *settings, gint titleindex) } } ghb_settings_set_int(settings, "scale_width", - tinfo.width - tinfo.crop[2] - tinfo.crop[3]); + title->width - title->crop[2] - title->crop[3]); // If anamorphic or keep_aspect, the hight will // be automatically calculated @@ -1530,11 +1562,11 @@ set_title_settings(GValue *settings, gint titleindex) if (!(keep_aspect || pic_par) || pic_par == 3) { ghb_settings_set_int(settings, "scale_height", - tinfo.width - tinfo.crop[0] - tinfo.crop[1]); + title->width - title->crop[0] - title->crop[1]); } ghb_set_scale_settings(settings, GHB_PIC_KEEP_PAR|GHB_PIC_USE_MAX); - ghb_settings_set_int(settings, "angle_count", tinfo.angle_count); + ghb_settings_set_int(settings, "angle_count", title->angle_count); } update_chapter_list_settings(settings); ghb_set_pref_audio_settings(titleindex, settings); @@ -1559,14 +1591,13 @@ ghb_add_all_titles(signal_user_data_t *ud) for (ii = 0; ii < count; ii++) { - ghb_title_info_t tinfo; - GValue *settings = ghb_value_dup(ud->settings); ghb_settings_set_boolean(settings, "use_source_name", TRUE); - if (ghb_get_title_info (&tinfo, ii)) + hb_title_t * title = ghb_get_title_info(ii); + if (title != NULL) { - if (tinfo.type == HB_DVD_TYPE || - tinfo.type == HB_BD_TYPE) + if (title->type == HB_DVD_TYPE || + title->type == HB_BD_TYPE) { ghb_settings_set_boolean(settings, "title_no_in_destination", TRUE); @@ -1582,7 +1613,6 @@ static gboolean update_preview = FALSE; G_MODULE_EXPORT void title_changed_cb(GtkWidget *widget, signal_user_data_t *ud) { - ghb_title_info_t tinfo; gint titleindex; g_debug("title_changed_cb ()"); @@ -1593,9 +1623,10 @@ title_changed_cb(GtkWidget *widget, signal_user_data_t *ud) ghb_update_ui_combo_box (ud, "AudioTrack", titleindex, FALSE); ghb_update_ui_combo_box (ud, "SubtitleTrack", titleindex, FALSE); - if (ghb_get_title_info (&tinfo, titleindex)) + hb_title_t * title = ghb_get_title_info(titleindex); + if (title != NULL) { - show_title_info(ud, &tinfo); + show_title_info(ud, title); } ghb_check_dependency(ud, widget, NULL); update_chapter_list_settings(ud->settings); @@ -1640,26 +1671,28 @@ G_MODULE_EXPORT void ptop_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud) { gint ti; - ghb_title_info_t tinfo; + hb_title_t * title; ghb_widget_to_setting(ud->settings, widget); ghb_check_dependency(ud, widget, NULL); ghb_live_reset(ud); ti = ghb_settings_combo_int(ud->settings, "title"); - if (!ghb_get_title_info (&tinfo, ti)) + title = ghb_get_title_info(ti); + if (title == NULL) return; - gint duration = tinfo.duration / 90000; + gint num_chapters = hb_list_count(title->list_chapter); + gint duration = title->duration / 90000; if (ghb_settings_combo_int(ud->settings, "PtoPType") == 0) { widget = GHB_WIDGET (ud->builder, "start_point"); - gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo.num_chapters); + gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, num_chapters); gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), 1); widget = GHB_WIDGET (ud->builder, "end_point"); - gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, tinfo.num_chapters); - gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), tinfo.num_chapters); + gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, num_chapters); + gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), num_chapters); } else if (ghb_settings_combo_int(ud->settings, "PtoPType") == 1) { @@ -1673,7 +1706,7 @@ ptop_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud) } else if (ghb_settings_combo_int(ud->settings, "PtoPType") == 2) { - gdouble max_frames = (gdouble)duration * tinfo.rate / tinfo.rate_base; + gdouble max_frames = (gdouble)duration * title->rate / title->rate_base; widget = GHB_WIDGET (ud->builder, "start_point"); gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 1, max_frames); gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), 1); @@ -1715,6 +1748,20 @@ setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud) ghb_live_reset(ud); } +G_MODULE_EXPORT gboolean +meta_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, + signal_user_data_t *ud) +{ + ghb_widget_to_setting(ud->settings, widget); + return FALSE; +} + +G_MODULE_EXPORT void +meta_setting_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud) +{ + ghb_widget_to_setting(ud->settings, widget); +} + G_MODULE_EXPORT void chapter_markers_changed_cb(GtkWidget *widget, signal_user_data_t *ud) { @@ -1926,7 +1973,6 @@ G_MODULE_EXPORT void crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud) { gint titleindex, crop[4]; - ghb_title_info_t tinfo; g_debug("crop_changed_cb ()"); ghb_widget_to_setting(ud->settings, widget); @@ -1940,13 +1986,14 @@ crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud) crop[2] = ghb_settings_get_int(ud->settings, "PictureLeftCrop"); crop[3] = ghb_settings_get_int(ud->settings, "PictureRightCrop"); titleindex = ghb_settings_combo_int(ud->settings, "title"); - if (ghb_get_title_info (&tinfo, titleindex)) + hb_title_t * title = ghb_get_title_info(titleindex); + if (title != NULL) { gint width, height; gchar *text; - width = tinfo.width - crop[2] - crop[3]; - height = tinfo.height - crop[0] - crop[1]; + width = title->width - crop[2] - crop[3]; + height = title->height - crop[0] - crop[1]; widget = GHB_WIDGET (ud->builder, "crop_dimensions"); text = g_strdup_printf ("%d x %d", width, height); gtk_label_set_text (GTK_LABEL(widget), text); @@ -2787,15 +2834,14 @@ ghb_backend_events(signal_user_data_t *ud) ghb_refresh_preset(ud); } - ghb_title_info_t tinfo; - ghb_update_ui_combo_box(ud, "title", 0, FALSE); titleindex = ghb_longest_title(); ghb_ui_update(ud, "title", ghb_int64_value(titleindex)); label = GTK_LABEL(GHB_WIDGET (ud->builder, "source_title")); // Are there really any titles. - if (!ghb_get_title_info(&tinfo, titleindex)) + hb_title_t * title = ghb_get_title_info(titleindex); + if (title == NULL) { gtk_label_set_text(label, "None"); } diff --git a/gtk/src/ghb.ui b/gtk/src/ghb.ui index bf24d17d1..b5ca17ca2 100644 --- a/gtk/src/ghb.ui +++ b/gtk/src/ghb.ui @@ -4231,6 +4231,317 @@ no-fast-pskip=0:no-dct-decimate=0:cabac=1</property> <property name="tab_fill">False</property> </packing> </child> + <child> + <object class="GtkAlignment" id="alignment76"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="top_padding">48</property> + <property name="right_padding">24</property> + <property name="left_padding">24</property> + <property name="yscale">0</property> + <child> + <object class="GtkTable" id="tags_table"> + <property name="n_rows">8</property> + <property name="n_columns">2</property> + <property name="visible">True</property> + <property name="column_spacing">5</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="GtkLabel" id="tag_title_label"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Title:</property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="x_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="MetaName"> + <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="max_length">80</property> + <property name="activates_default">True</property> + <property name="width_chars">50</property> + <property name="truncate_multiline">True</property> + <signal name="changed" handler="meta_setting_widget_changed_cb"/> + </object> + <packing> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="tag_actors_label"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Actors:</property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="x_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="MetaArtist"> + <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="max_length">80</property> + <property name="activates_default">True</property> + <property name="width_chars">50</property> + <property name="truncate_multiline">True</property> + <signal name="changed" handler="meta_setting_widget_changed_cb"/> + </object> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="tag_director_label"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Director:</property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="x_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="MetaAlbumArtist"> + <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="max_length">80</property> + <property name="activates_default">True</property> + <property name="width_chars">50</property> + <property name="truncate_multiline">True</property> + <signal name="changed" handler="meta_setting_widget_changed_cb"/> + </object> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="tag_release_date_label"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Release Date:</property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="x_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="MetaReleaseDate"> + <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="max_length">80</property> + <property name="activates_default">True</property> + <property name="width_chars">50</property> + <property name="truncate_multiline">True</property> + <signal name="changed" handler="meta_setting_widget_changed_cb"/> + </object> + <packing> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="tag_comment_label"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Comment:</property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="x_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="MetaComment"> + <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="max_length">80</property> + <property name="activates_default">True</property> + <property name="width_chars">50</property> + <property name="truncate_multiline">True</property> + <signal name="changed" handler="meta_setting_widget_changed_cb"/> + </object> + <packing> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="tag_genre_label"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Genre:</property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="top_attach">5</property> + <property name="bottom_attach">6</property> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="x_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="MetaGenre"> + <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="max_length">80</property> + <property name="activates_default">True</property> + <property name="width_chars">50</property> + <property name="truncate_multiline">True</property> + <signal name="changed" handler="meta_setting_widget_changed_cb"/> + </object> + <packing> + <property name="top_attach">5</property> + <property name="bottom_attach">6</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="tag_description_label"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Description:</property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="x_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="MetaDescription"> + <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="max_length">80</property> + <property name="activates_default">True</property> + <property name="width_chars">50</property> + <property name="truncate_multiline">True</property> + <signal name="changed" handler="meta_setting_widget_changed_cb"/> + </object> + <packing> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="tag_long_description_label"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Plot:</property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="top_attach">7</property> + <property name="bottom_attach">8</property> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="x_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="MetaLongDescriptionScroll"> + <property name="height_request">80</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">etched-in</property> + <child> + <object class="GtkTextView" id="MetaLongDescription"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="wrap_mode">GTK_WRAP_CHAR</property> + <property name="accepts_tab">False</property> + <signal handler="meta_focus_out_cb" name="focus_out_event"/> + </object> + </child> + </object> + <packing> + <property name="top_attach">7</property> + <property name="bottom_attach">8</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + </object> + <packing> + </packing> + </child> + </object> + </child> + <child type="tab"> + <object class="GtkLabel" id="metadata_label"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Tags</property> + </object> + <packing> + <property name="position">6</property> + <property name="tab_fill">False</property> + </packing> + </child> </object> </child> diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c index f2638bf73..cda5882e8 100644 --- a/gtk/src/hb-backend.c +++ b/gtk/src/hb-backend.c @@ -1404,18 +1404,11 @@ ghb_subtitle_track_source(GValue *settings, gint track) if (titleindex < 0) return VOBSUB; - hb_list_t * list; hb_title_t * title; hb_subtitle_t * sub; if (h_scan == NULL) return VOBSUB; - list = hb_get_titles( h_scan ); - if( !hb_list_count( list ) ) - { - /* No valid title, stop right there */ - return VOBSUB; - } - title = hb_list_item( list, titleindex ); + title = ghb_get_title_info( titleindex ); if (title == NULL) return VOBSUB; // Bad titleindex sub = hb_list_item( title->list_subtitle, track); if (sub != NULL) @@ -1445,17 +1438,10 @@ ghb_subtitle_track_source_name(GValue *settings, gint track) if (titleindex < 0) goto done; - hb_list_t * list; hb_title_t * title; hb_subtitle_t * sub; - if (h_scan == NULL) - goto done; - list = hb_get_titles( h_scan ); - if( !hb_list_count( list ) ) - goto done; - - title = hb_list_item( list, titleindex ); + title = ghb_get_title_info( titleindex ); if (title == NULL) goto done; @@ -1482,20 +1468,10 @@ ghb_subtitle_track_lang(GValue *settings, gint track) if (track < 0) goto fail; - hb_list_t * list; hb_title_t * title; hb_subtitle_t * sub; - if (h_scan == NULL) - goto fail; - - list = hb_get_titles( h_scan ); - if( !hb_list_count( list ) ) - { - /* No valid title, stop right there */ - goto fail; - } - title = hb_list_item( list, titleindex ); + title = ghb_get_title_info( titleindex ); if (title == NULL) // Bad titleindex goto fail; sub = hb_list_item( title->list_subtitle, track); @@ -1509,17 +1485,9 @@ fail: gint ghb_get_title_number(gint titleindex) { - hb_list_t * list; hb_title_t * title; - if (h_scan == NULL) return 1; - list = hb_get_titles( h_scan ); - if( !hb_list_count( list ) ) - { - /* No valid title, stop right there */ - return 1; - } - title = hb_list_item( list, titleindex ); + title = ghb_get_title_info( titleindex ); if (title == NULL) return 1; // Bad titleindex return title->index; } @@ -2104,7 +2072,6 @@ audio_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex) { GtkTreeIter iter; GtkListStore *store; - hb_list_t * list = NULL; hb_title_t * title = NULL; hb_audio_config_t * audio; gint ii; @@ -2114,14 +2081,10 @@ audio_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex) g_debug("audio_track_opts_set ()\n"); store = get_combo_box_store(builder, name); gtk_list_store_clear(store); - if (h_scan != NULL) + title = ghb_get_title_info(titleindex); + if (title != NULL) { - list = hb_get_titles( h_scan ); - title = (hb_title_t*)hb_list_item( list, titleindex ); - if (title != NULL) - { - count = hb_list_count( title->list_audio ); - } + count = hb_list_count( title->list_audio ); } if (count > 100) count = 100; if (audio_track_opts.map) @@ -2188,16 +2151,13 @@ audio_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex) const gchar* ghb_audio_track_description(gint track, int titleindex) { - hb_list_t * list = NULL; hb_title_t * title = NULL; hb_audio_config_t * audio; gchar * desc = "Unknown"; g_debug("ghb_audio_track_description ()\n"); - if (h_scan == NULL) return desc; - list = hb_get_titles( h_scan ); - title = (hb_title_t*)hb_list_item( list, titleindex ); + title = ghb_get_title_info( titleindex ); if (title == NULL) return desc; if (track >= hb_list_count( title->list_audio )) return desc; @@ -2211,7 +2171,6 @@ subtitle_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex) { GtkTreeIter iter; GtkListStore *store; - hb_list_t * list = NULL; hb_title_t * title = NULL; hb_subtitle_t * subtitle; gint ii, count = 0; @@ -2220,14 +2179,10 @@ subtitle_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex) g_debug("subtitle_track_opts_set ()\n"); store = get_combo_box_store(builder, name); gtk_list_store_clear(store); - if (h_scan != NULL) + title = ghb_get_title_info(titleindex); + if (title != NULL) { - list = hb_get_titles( h_scan ); - title = (hb_title_t*)hb_list_item( list, titleindex ); - if (title != NULL) - { - count = hb_list_count( title->list_subtitle ); - } + count = hb_list_count( title->list_subtitle ); } if (count > 100) count = 100; if (subtitle_opts.map) g_free(subtitle_opts.map); @@ -2313,44 +2268,39 @@ subtitle_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex) gint ghb_longest_title() { - hb_list_t * list; + hb_title_set_t * title_set; hb_title_t * title; gint ii; gint count = 0; - gint titleindex = 0; gint feature; g_debug("ghb_longest_title ()\n"); if (h_scan == NULL) return 0; - list = hb_get_titles( h_scan ); - count = hb_list_count( list ); + title_set = hb_get_title_set( h_scan ); + count = hb_list_count( title_set->list_title ); if (count < 1) return 0; - title = (hb_title_t*)hb_list_item(list, 0); - feature = title->job->feature; + title = (hb_title_t*)hb_list_item(title_set->list_title, 0); + feature = title_set->feature; for (ii = 0; ii < count; ii++) { - title = (hb_title_t*)hb_list_item(list, ii); + title = (hb_title_t*)hb_list_item(title_set->list_title, ii); if (title->index == feature) { return ii; } } - return titleindex; + return 0; } const gchar* ghb_get_source_audio_lang(gint titleindex, gint track) { - hb_list_t * list; hb_title_t * title; hb_audio_config_t * audio; const gchar *lang = "und"; g_debug("ghb_lookup_1st_audio_lang ()\n"); - if (h_scan == NULL) - return lang; - list = hb_get_titles( h_scan ); - title = (hb_title_t*)hb_list_item( list, titleindex ); + title = ghb_get_title_info( titleindex ); if (title == NULL) return lang; if (hb_list_count( title->list_audio ) <= track) @@ -2390,7 +2340,6 @@ ghb_find_audio_track( gint fallback_acodec, GHashTable *track_indices) { - hb_list_t * list; hb_title_t * title; hb_audio_config_t * audio; gint ii; @@ -2405,9 +2354,7 @@ ghb_find_audio_track( gint channels; g_debug("find_audio_track ()\n"); - if (h_scan == NULL) return -1; - list = hb_get_titles( h_scan ); - title = (hb_title_t*)hb_list_item( list, titleindex ); + title = ghb_get_title_info( titleindex ); if (title != NULL) { count = hb_list_count( title->list_audio ); @@ -2617,15 +2564,12 @@ ghb_find_pref_subtitle_track(const gchar *lang) gint ghb_find_cc_track(gint titleindex) { - hb_list_t * list; hb_title_t * title; hb_subtitle_t * subtitle; gint count, ii; g_debug("ghb_find_cc_track ()\n"); - if (h_scan == NULL) return -2; - list = hb_get_titles( h_scan ); - title = (hb_title_t*)hb_list_item( list, titleindex ); + title = ghb_get_title_info( titleindex ); if (title != NULL) { count = hb_list_count( title->list_subtitle ); @@ -2649,57 +2593,55 @@ ghb_find_subtitle_track( gint source, GHashTable * track_indices) { - hb_list_t * list; hb_title_t * title; hb_subtitle_t * subtitle; gint count, ii; gboolean *used; - + g_debug("find_subtitle_track ()\n"); if (strcmp(lang, "auto") == 0) return -1; - if (h_scan == NULL) return -1; - list = hb_get_titles( h_scan ); - title = (hb_title_t*)hb_list_item( list, titleindex ); - if (title != NULL) + + title = ghb_get_title_info( titleindex ); + if (title == NULL) + return -2; + + count = hb_list_count( title->list_subtitle ); + used = g_hash_table_lookup(track_indices, lang); + if (used == NULL) { - count = hb_list_count( title->list_subtitle ); - used = g_hash_table_lookup(track_indices, lang); - if (used == NULL) + used = g_malloc0(count * sizeof(gboolean)); + g_hash_table_insert(track_indices, g_strdup(lang), used); + } + // Try to find an item that matches the preferred language and source + for (ii = 0; ii < count; ii++) + { + if (used[ii]) + continue; + + subtitle = (hb_subtitle_t*)hb_list_item( title->list_subtitle, ii ); + if (source == subtitle->source && + ((strcmp(lang, subtitle->iso639_2) == 0) || + (strcmp(lang, "und") == 0))) { - used = g_malloc0(count * sizeof(gboolean)); - g_hash_table_insert(track_indices, g_strdup(lang), used); + used[ii] = TRUE; + return ii; } - // Try to find an item that matches the preferred language and source - for (ii = 0; ii < count; ii++) - { - if (used[ii]) - continue; + } + // Try to find an item that matches the preferred language + for (ii = 0; ii < count; ii++) + { + if (used[ii]) + continue; - subtitle = (hb_subtitle_t*)hb_list_item( title->list_subtitle, ii ); - if (source == subtitle->source && - ((strcmp(lang, subtitle->iso639_2) == 0) || - (strcmp(lang, "und") == 0))) - { - used[ii] = TRUE; - return ii; - } - } - // Try to find an item that matches the preferred language - for (ii = 0; ii < count; ii++) + subtitle = (hb_subtitle_t*)hb_list_item( title->list_subtitle, ii ); + if (((!force || (force && ghb_canForceSub(subtitle->source))) && + (!burn || (burn && ghb_canBurnSub(subtitle->source)))) && + ((strcmp(lang, subtitle->iso639_2) == 0) || + (strcmp(lang, "und") == 0))) { - if (used[ii]) - continue; - - subtitle = (hb_subtitle_t*)hb_list_item( title->list_subtitle, ii ); - if (((!force || (force && ghb_canForceSub(subtitle->source))) && - (!burn || (burn && ghb_canBurnSub(subtitle->source)))) && - ((strcmp(lang, subtitle->iso639_2) == 0) || - (strcmp(lang, "und") == 0))) - { - used[ii] = TRUE; - return ii; - } + used[ii] = TRUE; + return ii; } } return -2; @@ -3081,16 +3023,13 @@ ghb_build_advanced_opts_string(GValue *settings) void ghb_part_duration(gint tt, gint sc, gint ec, gint *hh, gint *mm, gint *ss) { - hb_list_t * list; hb_title_t * title; - hb_chapter_t * chapter; + hb_chapter_t * chapter; gint count, c; gint64 duration; *hh = *mm = *ss = 0; - if (h_scan == NULL) return; - list = hb_get_titles( h_scan ); - title = (hb_title_t*)hb_list_item( list, tt ); + title = ghb_get_title_info( tt ); if (title == NULL) return; *hh = title->hours; @@ -3119,16 +3058,13 @@ ghb_part_duration(gint tt, gint sc, gint ec, gint *hh, gint *mm, gint *ss) void ghb_get_chapter_duration(gint ti, gint ii, gint *hh, gint *mm, gint *ss) { - hb_list_t * list; hb_title_t * title; - hb_chapter_t * chapter; + hb_chapter_t * chapter; gint count; g_debug("ghb_get_chapter_duration (title = %d)\n", ti); *hh = *mm = *ss = 0; - if (h_scan == NULL) return; - list = hb_get_titles( h_scan ); - title = (hb_title_t*)hb_list_item( list, ti ); + title = ghb_get_title_info( ti ); if (title == NULL) return; count = hb_list_count( title->list_chapter ); if (ii >= count) return; @@ -3142,18 +3078,15 @@ ghb_get_chapter_duration(gint ti, gint ii, gint *hh, gint *mm, gint *ss) GValue* ghb_get_chapters(gint titleindex) { - hb_list_t * list; hb_title_t * title; - hb_chapter_t * chapter; + hb_chapter_t * chapter; gint count, ii; GValue *chapters = NULL; g_debug("ghb_get_chapters (title = %d)\n", titleindex); chapters = ghb_array_value_new(0); - if (h_scan == NULL) return chapters; - list = hb_get_titles( h_scan ); - title = (hb_title_t*)hb_list_item( list, titleindex ); + title = ghb_get_title_info( titleindex ); if (title == NULL) return chapters; count = hb_list_count( title->list_chapter ); for (ii = 0; ii < count; ii++) @@ -3601,49 +3534,15 @@ ghb_track_status() } } -gboolean -ghb_get_title_info(ghb_title_info_t *tinfo, gint titleindex) +hb_title_t * +ghb_get_title_info(gint titleindex) { hb_list_t * list; - hb_title_t * title; - - if (h_scan == NULL) return FALSE; - list = hb_get_titles( h_scan ); - if( !hb_list_count( list ) ) - { - /* No valid title, stop right there */ - return FALSE; - } - title = hb_list_item( list, titleindex ); - if (title == NULL) return FALSE; // Bad titleindex - tinfo->index = titleindex; - tinfo->video_codec_name = title->video_codec_name; - tinfo->width = title->width; - tinfo->height = title->height; - memcpy(tinfo->crop, title->crop, 4 * sizeof(int)); - // Don't allow crop to 0 - if (title->crop[0] + title->crop[1] >= title->height) - title->crop[0] = title->crop[1] = 0; - if (title->crop[2] + title->crop[3] >= title->width) - title->crop[2] = title->crop[3] = 0; - tinfo->num_chapters = hb_list_count(title->list_chapter); - tinfo->rate_base = title->rate_base; - tinfo->rate = title->rate; - tinfo->interlaced = title->detected_interlacing; - hb_reduce(&(tinfo->aspect_n), &(tinfo->aspect_d), - title->width * title->pixel_aspect_width, - title->height * title->pixel_aspect_height); - tinfo->hours = title->hours; - tinfo->minutes = title->minutes; - tinfo->seconds = title->seconds; - tinfo->duration = title->duration; - - tinfo->angle_count = title->angle_count; - tinfo->path = title->path; - tinfo->name = title->name; - tinfo->type = title->type; - return TRUE; + if (h_scan == NULL) return NULL; + list = hb_get_titles( h_scan ); + if (list == NULL) return NULL; + return hb_list_item( list, titleindex ); } hb_audio_config_t* @@ -3740,13 +3639,13 @@ ghb_limit_rational( gint *num, gint *den, gint limit ) void ghb_set_scale_settings(GValue *settings, gint mode) { - hb_list_t * list; hb_title_t * title; hb_job_t * job; gboolean keep_aspect; gint pic_par; gboolean autocrop, autoscale, noscale; - gint crop[4], width, height, par_width, par_height; + gint crop[4] = {0,}; + gint width, height, par_width, par_height; gint crop_width, crop_height; gint aspect_n, aspect_d; gboolean keep_width = (mode & GHB_PIC_KEEP_WIDTH); @@ -3769,19 +3668,13 @@ ghb_set_scale_settings(GValue *settings, gint mode) ghb_settings_set_boolean(settings, "PictureKeepRatio", TRUE); } - if (h_scan == NULL) return; - list = hb_get_titles( h_scan ); - if( !hb_list_count( list ) ) - { - /* No valid title, stop right there */ - return; - } gint titleindex; titleindex = ghb_settings_combo_int(settings, "title"); - title = hb_list_item( list, titleindex ); + title = ghb_get_title_info (titleindex); if (title == NULL) return; - job = title->job; + + job = hb_job_init( title ); if (job == NULL) return; // First configure widgets @@ -3801,14 +3694,12 @@ ghb_set_scale_settings(GValue *settings, gint mode) keep_height = FALSE; } - ghb_title_info_t tinfo; - ghb_get_title_info (&tinfo, titleindex); if (autocrop) { - crop[0] = tinfo.crop[0]; - crop[1] = tinfo.crop[1]; - crop[2] = tinfo.crop[2]; - crop[3] = tinfo.crop[3]; + crop[0] = title->crop[0]; + crop[1] = title->crop[1]; + crop[2] = title->crop[2]; + crop[3] = title->crop[3]; ghb_settings_set_int(settings, "PictureTopCrop", crop[0]); ghb_settings_set_int(settings, "PictureBottomCrop", crop[1]); ghb_settings_set_int(settings, "PictureLeftCrop", crop[2]); @@ -3826,8 +3717,8 @@ ghb_set_scale_settings(GValue *settings, gint mode) gint need1, need2; // Adjust the cropping to accomplish the desired width and height - crop_width = tinfo.width - crop[2] - crop[3]; - crop_height = tinfo.height - crop[0] - crop[1]; + crop_width = width - crop[2] - crop[3]; + crop_height = height - crop[0] - crop[1]; width = MOD_DOWN(crop_width, mod); height = MOD_DOWN(crop_height, mod); @@ -3999,6 +3890,7 @@ ghb_set_scale_settings(GValue *settings, gint mode) ghb_settings_set_int(settings, "PicturePARHeight", par_height); ghb_settings_set_int(settings, "PictureDisplayWidth", disp_width); ghb_settings_set_int(settings, "PictureDisplayHeight", height); + hb_job_close( &job ); } void @@ -4290,25 +4182,20 @@ ghb_validate_video(GValue *settings) gboolean ghb_validate_subtitles(GValue *settings) { - hb_list_t * list; hb_title_t * title; gchar *message; - if (h_scan == NULL) return FALSE; - list = hb_get_titles( h_scan ); - if( !hb_list_count( list ) ) + gint titleindex; + + titleindex = ghb_settings_combo_int(settings, "title"); + title = ghb_get_title_info(titleindex); + if (title == NULL) { /* No valid title, stop right there */ g_message("No title found.\n"); return FALSE; } - gint titleindex; - - titleindex = ghb_settings_combo_int(settings, "title"); - title = hb_list_item( list, titleindex ); - if (title == NULL) return FALSE; - const GValue *slist, *subtitle; gint count, ii, source; gboolean burned, one_burned = FALSE; @@ -4368,25 +4255,20 @@ ghb_validate_subtitles(GValue *settings) gboolean ghb_validate_audio(GValue *settings) { - hb_list_t * list; hb_title_t * title; gchar *message; GValue *value; - if (h_scan == NULL) return FALSE; - list = hb_get_titles( h_scan ); - if( !hb_list_count( list ) ) + gint titleindex; + + titleindex = ghb_settings_combo_int(settings, "title"); + title = ghb_get_title_info( titleindex ); + if (title == NULL) { /* No valid title, stop right there */ g_message("No title found.\n"); return FALSE; } - - gint titleindex; - - titleindex = ghb_settings_combo_int(settings, "title"); - title = hb_list_item( list, titleindex ); - if (title == NULL) return FALSE; gint mux = ghb_settings_combo_int(settings, "FileFormat"); const GValue *audio_list; @@ -4602,7 +4484,7 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex) if (title == NULL) return; /* Set job settings */ - job = title->job; + job = hb_job_init( title ); if (job == NULL) return; job->angle = ghb_settings_get_int(js, "angle"); @@ -4686,9 +4568,8 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex) { name = g_strdup_printf ("Chapter %2d", chap+1); } - chapter_s = hb_list_item( job->title->list_chapter, chap); - strncpy(chapter_s->title, name, 1023); - chapter_s->title[1023] = '\0'; + chapter_s = hb_list_item( job->list_chapter, chap); + hb_chapter_set_title(chapter_s, name); g_free(name); } } @@ -4945,7 +4826,8 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex) } dest_str = ghb_settings_get_string(js, "destination"); - job->file = dest_str; + hb_job_set_file( job, dest_str); + g_free(dest_str); const GValue *subtitle_list; gint subtitle; @@ -5066,6 +4948,57 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex) advanced_opts = NULL; } + char * meta; + + meta = ghb_settings_get_string(js, "MetaName"); + if (meta && *meta) + { + hb_metadata_set_name(job->metadata, meta); + } + free(meta); + meta = ghb_settings_get_string(js, "MetaArtist"); + if (meta && *meta) + { + hb_metadata_set_artist(job->metadata, meta); + } + free(meta); + meta = ghb_settings_get_string(js, "MetaAlbumArtist"); + if (meta && *meta) + { + hb_metadata_set_album_artist(job->metadata, meta); + } + free(meta); + meta = ghb_settings_get_string(js, "MetaReleaseDate"); + if (meta && *meta) + { + hb_metadata_set_release_date(job->metadata, meta); + } + free(meta); + meta = ghb_settings_get_string(js, "MetaComment"); + if (meta && *meta) + { + hb_metadata_set_comment(job->metadata, meta); + } + free(meta); + meta = ghb_settings_get_string(js, "MetaGenre"); + if (meta && *meta) + { + hb_metadata_set_genre(job->metadata, meta); + } + free(meta); + meta = ghb_settings_get_string(js, "MetaDescription"); + if (meta && *meta) + { + hb_metadata_set_description(job->metadata, meta); + } + free(meta); + meta = ghb_settings_get_string(js, "MetaLongDescription"); + if (meta && *meta) + { + hb_metadata_set_long_description(job->metadata, meta); + } + free(meta); + if (job->indepth_scan == 1) { // Subtitle scan. Look for subtitle matching audio language @@ -5076,7 +5009,7 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex) */ job->pass = -1; job->indepth_scan = 1; - job->advanced_opts = NULL; + hb_job_set_advanced_opts(job, NULL); /* * Add the pre-scan job @@ -5095,7 +5028,7 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex) */ job->pass = 1; job->indepth_scan = 0; - job->advanced_opts = advanced_opts; + hb_job_set_advanced_opts(job, advanced_opts); /* * If turbo options have been selected then set job->fastfirstpass @@ -5109,10 +5042,9 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex) { job->fastfirstpass = 0; } + job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24); hb_add( h, job ); - //if (job->advanced_opts != NULL) - // g_free(job->advanced_opts); job->pass = 2; /* @@ -5124,25 +5056,18 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex) job->indepth_scan = 0; job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24); hb_add( h, job ); - //if (job->advanced_opts != NULL) - // g_free(job->advanced_opts); } else { - job->advanced_opts = advanced_opts; + hb_job_set_advanced_opts(job, advanced_opts); job->indepth_scan = 0; job->pass = 0; job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24); hb_add( h, job ); - //if (job->advanced_opts != NULL) - // g_free(job->advanced_opts); } + g_free(advanced_opts); - // Reset the job so it can be use again to add other jobs - // for the same title. - hb_reset_job(job); - - if (dest_str) g_free(dest_str); + hb_job_close(&job); } void @@ -5327,19 +5252,16 @@ ghb_get_preview_image( { GValue *settings; hb_title_t *title; - hb_list_t *list; + hb_job_t *job; settings = ud->settings; - list = hb_get_titles( h_scan ); - if( !hb_list_count( list ) ) - { - /* No valid title, stop right there */ - return NULL; - } - title = hb_list_item( list, titleindex ); - if (title == NULL) return NULL; - if (title->job == NULL) return NULL; - set_preview_job_settings(title->job, settings); + title = ghb_get_title_info( titleindex ); + if( title == NULL ) return NULL; + + job = hb_job_init( title ); + if (job == NULL) return NULL; + + set_preview_job_settings(job, settings); // hb_get_preview doesn't compensate for anamorphic, so lets // calculate scale factors @@ -5347,13 +5269,13 @@ ghb_get_preview_image( gint pic_par = ghb_settings_combo_int(settings, "PicturePAR"); if (pic_par) { - hb_set_anamorphic_size( title->job, &width, &height, + hb_set_anamorphic_size( job, &width, &height, &par_width, &par_height ); } // Make sure we have a big enough buffer to receive the image from libhb - gint dstWidth = title->job->width; - gint dstHeight= title->job->height; + gint dstWidth = job->width; + gint dstHeight= job->height; static guint8 *buffer = NULL; static gint bufferSize = 0; @@ -5365,7 +5287,8 @@ ghb_get_preview_image( bufferSize = newSize; buffer = (guint8*) g_realloc( buffer, bufferSize ); } - hb_get_preview( h_scan, title, index, buffer ); + hb_get_preview( h_scan, job, index, buffer ); + hb_job_close( &job ); // Create an GdkPixbuf and copy the libhb image into it, converting it from // libhb's format something suitable. diff --git a/gtk/src/hb-backend.h b/gtk/src/hb-backend.h index e1ff28a75..ded2fd8c0 100644 --- a/gtk/src/hb-backend.h +++ b/gtk/src/hb-backend.h @@ -62,29 +62,6 @@ typedef struct #define GHB_PIC_KEEP_PAR 0x20 #define GHB_PIC_USE_MAX 0x40 -typedef struct -{ - gchar *path; - gchar *name; - gint index; - gint type; - char *video_codec_name; - gint width; - gint height; - gint crop[4]; - gint num_chapters; - gint rate; - gint rate_base; - gint interlaced; - gint aspect_n; - gint aspect_d; - gint hours; - gint minutes; - gint seconds; - gint64 duration; - gint angle_count; -} ghb_title_info_t; - #define GHB_AUDIO_SAMPLERATE 1 #define GHB_AUDIO_BITRATE 2 #define GHB_FRAMERATE 3 @@ -123,7 +100,7 @@ void ghb_track_status(void); void ghb_backend_scan(const gchar *path, gint titleindex, gint preview_count, guint64 min_duration); void ghb_backend_scan_stop(); void ghb_backend_queue_scan(const gchar *path, gint titleindex); -gboolean ghb_get_title_info(ghb_title_info_t *tinfo, gint titleindex); +hb_title_t* ghb_get_title_info(gint titleindex); void ghb_par_init(signal_user_data_t *ud); void ghb_set_scale(signal_user_data_t *ud, gint mode); void ghb_set_scale_settings(GValue *settings, gint mode); diff --git a/gtk/src/internal_defaults.xml b/gtk/src/internal_defaults.xml index 68667222a..e5d98cebe 100644 --- a/gtk/src/internal_defaults.xml +++ b/gtk/src/internal_defaults.xml @@ -24,6 +24,22 @@ <integer>100</integer> <key>folder</key> <string></string> + <key>MetaName</key> + <string></string> + <key>MetaArtist</key> + <string></string> + <key>MetaAlbumArtist</key> + <string></string> + <key>MetaReleaseDate</key> + <string></string> + <key>MetaComment</key> + <string></string> + <key>MetaGenre</key> + <string></string> + <key>MetaDescription</key> + <string></string> + <key>MetaLongDescription</key> + <string></string> <key>preset</key> <array> <string>Normal</string> diff --git a/gtk/src/presets.c b/gtk/src/presets.c index eeacbde04..1905e5597 100644 --- a/gtk/src/presets.c +++ b/gtk/src/presets.c @@ -4195,12 +4195,12 @@ presets_row_expanded_cb( } static void -preset_update_title_deps(signal_user_data_t *ud, ghb_title_info_t *tinfo) +preset_update_title_deps(signal_user_data_t *ud, hb_title_t *title) { GtkWidget *widget; ghb_ui_update(ud, "scale_width", - ghb_int64_value(tinfo->width - tinfo->crop[2] - tinfo->crop[3])); + ghb_int64_value(title->width - title->crop[2] - title->crop[3])); // If anamorphic or keep_aspect, the hight will be automatically calculated gboolean keep_aspect; gint pic_par; @@ -4209,35 +4209,34 @@ preset_update_title_deps(signal_user_data_t *ud, ghb_title_info_t *tinfo) if (!(keep_aspect || pic_par) || pic_par == 3) { ghb_ui_update(ud, "scale_height", - ghb_int64_value(tinfo->height - tinfo->crop[0] - tinfo->crop[1])); + ghb_int64_value(title->height - title->crop[0] - title->crop[1])); } // Set the limits of cropping. hb_set_anamorphic_size crashes if // you pass it a cropped width or height == 0. gint bound; - bound = tinfo->height / 2 - 2; + bound = title->height / 2 - 2; widget = GHB_WIDGET (ud->builder, "PictureTopCrop"); gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound); widget = GHB_WIDGET (ud->builder, "PictureBottomCrop"); gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound); - bound = tinfo->width / 2 - 2; + bound = title->width / 2 - 2; widget = GHB_WIDGET (ud->builder, "PictureLeftCrop"); gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound); widget = GHB_WIDGET (ud->builder, "PictureRightCrop"); gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound); if (ghb_settings_get_boolean(ud->settings, "PictureAutoCrop")) { - ghb_ui_update(ud, "PictureTopCrop", ghb_int64_value(tinfo->crop[0])); - ghb_ui_update(ud, "PictureBottomCrop", ghb_int64_value(tinfo->crop[1])); - ghb_ui_update(ud, "PictureLeftCrop", ghb_int64_value(tinfo->crop[2])); - ghb_ui_update(ud, "PictureRightCrop", ghb_int64_value(tinfo->crop[3])); + ghb_ui_update(ud, "PictureTopCrop", ghb_int64_value(title->crop[0])); + ghb_ui_update(ud, "PictureBottomCrop", ghb_int64_value(title->crop[1])); + ghb_ui_update(ud, "PictureLeftCrop", ghb_int64_value(title->crop[2])); + ghb_ui_update(ud, "PictureRightCrop", ghb_int64_value(title->crop[3])); } } void ghb_refresh_preset(signal_user_data_t *ud) { - ghb_title_info_t tinfo; GValue *preset; gint *indices, len; @@ -4266,9 +4265,10 @@ ghb_refresh_preset(signal_user_data_t *ud) ghb_set_pref_audio_from_settings(ud, ud->settings); ghb_set_pref_subtitle(titleindex, ud); ghb_settings_set_boolean(ud->settings, "preset_modified", FALSE); - if (ghb_get_title_info (&tinfo, titleindex)) + hb_title_t * title = ghb_get_title_info(titleindex); + if (title != NULL) { - preset_update_title_deps(ud, &tinfo); + preset_update_title_deps(ud, title); } ud->scale_busy = FALSE; ghb_set_scale (ud, GHB_PIC_KEEP_PAR|GHB_PIC_USE_MAX); @@ -4306,7 +4306,6 @@ presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_ { GtkTreeModel *store; GtkTreeIter iter; - ghb_title_info_t tinfo; GtkWidget *widget; g_debug("presets_list_selection_changed_cb ()"); @@ -4343,9 +4342,10 @@ presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_ ghb_set_pref_audio_from_settings(ud, ud->settings); ghb_set_pref_subtitle(titleindex, ud); ghb_settings_set_boolean(ud->settings, "preset_modified", FALSE); - if (ghb_get_title_info (&tinfo, titleindex)) + hb_title_t * title = ghb_get_title_info(titleindex); + if (title != NULL) { - preset_update_title_deps(ud, &tinfo); + preset_update_title_deps(ud, title); } ud->scale_busy = FALSE; ghb_set_scale (ud, GHB_PIC_KEEP_PAR|GHB_PIC_USE_MAX); diff --git a/gtk/src/values.c b/gtk/src/values.c index dd23d0e48..f755363e5 100644 --- a/gtk/src/values.c +++ b/gtk/src/values.c @@ -322,7 +322,14 @@ ghb_string_value(const gchar *str) static GValue gval = {0,}; if (!G_IS_VALUE(&gval)) g_value_init(&gval, G_TYPE_STRING); - g_value_set_string(&gval, str); + if (str == NULL) + { + g_value_set_string(&gval, ""); + } + else + { + g_value_set_string(&gval, str); + } return &gval; } diff --git a/libhb/bd.c b/libhb/bd.c index 208782674..268cdaab0 100644 --- a/libhb/bd.c +++ b/libhb/bd.c @@ -491,10 +491,12 @@ hb_title_t * hb_bd_title_scan( hb_bd_t * d, int tt, uint64_t min_duration ) /* Chapters */ for ( ii = 0; ii < ti->chapter_count; ii++ ) { + char chapter_title[80]; chapter = calloc( sizeof( hb_chapter_t ), 1 ); chapter->index = ii + 1; - sprintf( chapter->title, "Chapter %d", chapter->index ); + sprintf( chapter_title, "Chapter %d", chapter->index ); + hb_chapter_set_title( chapter, chapter_title ); chapter->duration = ti->chapters[ii].duration; chapter->block_start = ti->chapters[ii].offset; diff --git a/libhb/common.c b/libhb/common.c index 821f17e76..80b526c2a 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -306,13 +306,13 @@ const char* hb_mixdown_get_short_name_from_mixdown(int amixdown) return ""; } -void hb_autopassthru_apply_settings( hb_job_t * job, hb_title_t * title ) +void hb_autopassthru_apply_settings( hb_job_t * job ) { int i, j, already_printed; hb_audio_t * audio; - for( i = 0, already_printed = 0; i < hb_list_count( title->list_audio ); ) + for( i = 0, already_printed = 0; i < hb_list_count( job->list_audio ); ) { - audio = hb_list_item( title->list_audio, i ); + audio = hb_list_item( job->list_audio, i ); if( audio->config.out.codec == HB_ACODEC_AUTO_PASS ) { if( !already_printed ) @@ -327,8 +327,8 @@ void hb_autopassthru_apply_settings( hb_job_t * job, hb_title_t * title ) { hb_log( "Auto Passthru: passthru not possible and no valid fallback specified, dropping track %d", audio->config.out.track ); - hb_list_rem( title->list_audio, audio ); - free( audio ); + hb_list_rem( job->list_audio, audio ); + hb_audio_close( &audio ); continue; } audio->config.out.samplerate = audio->config.in.samplerate; @@ -1157,7 +1157,7 @@ hb_list_t * hb_list_init() ********************************************************************** * Returns the number of items currently in the list *********************************************************************/ -int hb_list_count( hb_list_t * l ) +int hb_list_count( const hb_list_t * l ) { return l->items_count; } @@ -1252,7 +1252,7 @@ void hb_list_rem( hb_list_t * l, void * p ) * Returns item at position i, or NULL if there are not that many * items in the list *********************************************************************/ -void * hb_list_item( hb_list_t * l, int i ) +void * hb_list_item( const hb_list_t * l, int i ) { if( i < 0 || i >= l->items_count ) { @@ -1575,6 +1575,19 @@ void hb_register_error_handler( hb_error_handler_t * handler ) error_handler = handler; } +static void hb_update_str( char **dst, const char *src ) +{ + if ( dst ) + { + free( *dst ); + *dst = NULL; + if ( src ) + { + *dst = strdup( src ); + } + } +} + /********************************************************************** * hb_title_init ********************************************************************** @@ -1592,6 +1605,7 @@ hb_title_t * hb_title_init( char * path, int index ) t->list_chapter = hb_list_init(); t->list_subtitle = hb_list_init(); t->list_attachment = hb_list_init(); + t->metadata = hb_metadata_init(); strcat( t->path, path ); // default to decoding mpeg2 t->video_id = 0xE0; @@ -1616,65 +1630,252 @@ void hb_title_close( hb_title_t ** _t ) hb_subtitle_t * subtitle; hb_attachment_t * attachment; - while( ( audio = hb_list_item( t->list_audio, 0 ) ) ) - { - hb_list_rem( t->list_audio, audio ); - free( audio ); - } - hb_list_close( &t->list_audio ); - while( ( chapter = hb_list_item( t->list_chapter, 0 ) ) ) { hb_list_rem( t->list_chapter, chapter ); - free( chapter ); + hb_chapter_close( &chapter ); } hb_list_close( &t->list_chapter ); + while( ( audio = hb_list_item( t->list_audio, 0 ) ) ) + { + hb_list_rem( t->list_audio, audio ); + hb_audio_close( &audio ); + } + hb_list_close( &t->list_audio ); + while( ( subtitle = hb_list_item( t->list_subtitle, 0 ) ) ) { hb_list_rem( t->list_subtitle, subtitle ); - if ( subtitle->extradata ) - { - free( subtitle->extradata ); - subtitle->extradata = NULL; - } - free( subtitle ); + hb_subtitle_close( &subtitle ); } hb_list_close( &t->list_subtitle ); while( ( attachment = hb_list_item( t->list_attachment, 0 ) ) ) { hb_list_rem( t->list_attachment, attachment ); - if ( attachment->name ) + hb_attachment_close( &attachment ); + } + hb_list_close( &t->list_attachment ); + + hb_metadata_close( &t->metadata ); + + free( t->video_codec_name ); + free(t->container_name); + +#if defined(HB_TITLE_JOBS) + hb_job_close( &t->job ); +#endif + + free( t ); + *_t = NULL; +} + +/* + * Create a pristine job structure from a title + * title_index is 1 based + */ +hb_job_t * hb_job_init_by_index( hb_handle_t * h, int title_index ) +{ + hb_title_set_t *title_set = hb_get_title_set( h ); + hb_title_t * title = hb_list_item( title_set->list_title, + title_index - 1 ); + return hb_job_init( title ); +} + +hb_job_t * hb_job_init( hb_title_t * title ) +{ + hb_job_t * job; + + if ( title == NULL ) + return NULL; + + job = calloc( sizeof( hb_job_t ), 1 ); + + job->title = title; + + /* Set defaults settings */ + job->chapter_start = 1; + job->chapter_end = hb_list_count( title->list_chapter ); + job->list_chapter = hb_chapter_list_copy( title->list_chapter ); + + /* Autocrop by default. Gnark gnark */ + memcpy( job->crop, title->crop, 4 * sizeof( int ) ); + + /* Preserve a source's pixel aspect, if it's available. */ + if( title->pixel_aspect_width && title->pixel_aspect_height ) + { + job->anamorphic.par_width = title->pixel_aspect_width; + job->anamorphic.par_height = title->pixel_aspect_height; + } + + if( title->aspect != 0 && title->aspect != 1. && + !job->anamorphic.par_width && !job->anamorphic.par_height) + { + hb_reduce( &job->anamorphic.par_width, &job->anamorphic.par_height, + (int)(title->aspect * title->height + 0.5), title->width ); + } + + job->width = title->width - job->crop[2] - job->crop[3]; + hb_fix_aspect( job, HB_KEEP_WIDTH ); + if( job->height > title->height - job->crop[0] - job->crop[1] ) + { + job->height = title->height - job->crop[0] - job->crop[1]; + hb_fix_aspect( job, HB_KEEP_HEIGHT ); + } + + job->keep_ratio = 1; + + job->vcodec = HB_VCODEC_FFMPEG_MPEG4; + job->vquality = -1.0; + job->vbitrate = 1000; + job->pass = 0; + job->vrate = title->rate; + job->vrate_base = title->rate_base; + + job->mux = HB_MUX_MP4; + + job->list_audio = hb_list_init(); + job->list_subtitle = hb_list_init(); + job->list_filter = hb_list_init(); + + job->list_attachment = hb_attachment_list_copy( title->list_attachment ); + job->metadata = hb_metadata_copy( title->metadata ); + + return job; +} + +/** + * Clean up the job structure so that is is ready for setting up a new job. + * Should be called by front-ends after hb_add(). + */ +/********************************************************************** + * hb_job_reset + ********************************************************************** + * + *********************************************************************/ +void hb_job_reset( hb_job_t * job ) +{ + if ( job ) + { + hb_audio_t *audio; + hb_subtitle_t *subtitle; + hb_filter_object_t *filter; + hb_title_t * title = job->title; + + // clean up audio list + while( ( audio = hb_list_item( job->list_audio, 0 ) ) ) + { + hb_list_rem( job->list_audio, audio ); + hb_audio_close( &audio ); + } + + // clean up subtitle list + while( ( subtitle = hb_list_item( job->list_subtitle, 0 ) ) ) { - free( attachment->name ); - attachment->name = NULL; + hb_list_rem( job->list_subtitle, subtitle ); + hb_subtitle_close( &subtitle ); } - if ( attachment->data ) + + // clean up filter list + while( ( filter = hb_list_item( job->list_filter, 0 ) ) ) { - free( attachment->data ); - attachment->data = NULL; + hb_list_rem( job->list_filter, filter ); + hb_filter_close( &filter ); } - free( attachment ); + + hb_metadata_close( &job->metadata ); + job->metadata = hb_metadata_copy( title->metadata ); } - hb_list_close( &t->list_attachment ); +} - if( t->metadata ) +/********************************************************************** + * hb_job_close + ********************************************************************** + * + *********************************************************************/ +void hb_job_close( hb_job_t ** _j ) +{ + if (_j) { - if( t->metadata->coverart ) + hb_job_t * job = *_j; + + if (job) { - free( t->metadata->coverart ); + hb_chapter_t *chapter; + hb_audio_t *audio; + hb_subtitle_t *subtitle; + hb_filter_object_t *filter; + hb_attachment_t *attachment; + + free(job->file); + free(job->advanced_opts); + + // clean up chapter list + while( ( chapter = hb_list_item( job->list_chapter, 0 ) ) ) + { + hb_list_rem( job->list_chapter, chapter ); + hb_chapter_close( &chapter ); + } + hb_list_close( &job->list_chapter ); + + // clean up audio list + while( ( audio = hb_list_item( job->list_audio, 0 ) ) ) + { + hb_list_rem( job->list_audio, audio ); + hb_audio_close( &audio ); + } + hb_list_close( &job->list_audio ); + + // clean up subtitle list + while( ( subtitle = hb_list_item( job->list_subtitle, 0 ) ) ) + { + hb_list_rem( job->list_subtitle, subtitle ); + hb_subtitle_close( &subtitle ); + } + hb_list_close( &job->list_subtitle ); + + // clean up filter list + while( ( filter = hb_list_item( job->list_filter, 0 ) ) ) + { + hb_list_rem( job->list_filter, filter ); + hb_filter_close( &filter ); + } + hb_list_close( &job->list_filter ); + + // clean up attachment list + while( ( attachment = hb_list_item( job->list_attachment, 0 ) ) ) + { + hb_list_rem( job->list_attachment, attachment ); + hb_attachment_close( &attachment ); + } + hb_list_close( &job->list_attachment ); + + // clean up metadata + if ( job->metadata ) + { + hb_metadata_close( &job->metadata ); + } + free( job ); } - free( t->metadata ); + _j = NULL; } +} - if ( t->video_codec_name ) +void hb_job_set_file( hb_job_t *job, const char *file ) +{ + if ( job ) { - free( t->video_codec_name ); + hb_update_str( &job->file, file ); } +} - free( t ); - *_t = NULL; +void hb_job_set_advanced_opts( hb_job_t *job, const char *advanced_opts ) +{ + if ( job ) + { + hb_update_str( &job->advanced_opts, advanced_opts ); + } } hb_filter_object_t * hb_filter_copy( hb_filter_object_t * filter ) @@ -1689,6 +1890,30 @@ hb_filter_object_t * hb_filter_copy( hb_filter_object_t * filter ) return filter_copy; } +/********************************************************************** + * hb_filter_list_copy + ********************************************************************** + * + *********************************************************************/ +hb_list_t *hb_filter_list_copy(const hb_list_t *src) +{ + hb_list_t *list = hb_list_init(); + hb_filter_object_t *filter = NULL; + int i; + + if( src ) + { + for( i = 0; i < hb_list_count(src); i++ ) + { + if( ( filter = hb_list_item( src, i ) ) ) + { + hb_list_add( list, hb_filter_copy(filter) ); + } + } + } + return list; +} + /** * Gets a filter object with the given type * @param filter_id The type of filter to get. @@ -1759,6 +1984,93 @@ void hb_filter_close( hb_filter_object_t ** _f ) } /********************************************************************** + * hb_chapter_copy + ********************************************************************** + * + *********************************************************************/ +hb_chapter_t *hb_chapter_copy(const hb_chapter_t *src) +{ + hb_chapter_t *chap = NULL; + + if ( src ) + { + chap = calloc( 1, sizeof(*chap) ); + memcpy( chap, src, sizeof(*chap) ); + if ( src->title ) + { + chap->title = strdup( src->title ); + } + } + return chap; +} + +/********************************************************************** + * hb_chapter_list_copy + ********************************************************************** + * + *********************************************************************/ +hb_list_t *hb_chapter_list_copy(const hb_list_t *src) +{ + hb_list_t *list = hb_list_init(); + hb_chapter_t *chapter = NULL; + int i; + + if( src ) + { + for( i = 0; i < hb_list_count(src); i++ ) + { + if( ( chapter = hb_list_item( src, i ) ) ) + { + hb_list_add( list, hb_chapter_copy(chapter) ); + } + } + } + return list; +} + +/********************************************************************** + * hb_chapter_close + ********************************************************************** + * + *********************************************************************/ +void hb_chapter_close(hb_chapter_t **chap) +{ + if ( chap && *chap ) + { + free((*chap)->title); + free(*chap); + *chap = NULL; + } +} + +/********************************************************************** + * hb_chapter_set_title + ********************************************************************** + * + *********************************************************************/ +void hb_chapter_set_title( hb_chapter_t *chapter, const char *title ) +{ + if ( chapter ) + { + hb_update_str( &chapter->title, title ); + } +} + +/********************************************************************** + * hb_chapter_set_title_by_index + ********************************************************************** + * Applies information from the given job to the official job instance. + * @param job Handle to hb_job_t. + * @param chapter The chapter to apply the name to (1-based). + * @param titel to apply. + *********************************************************************/ +void hb_chapter_set_title_by_index( hb_job_t * job, int chapter_index, const char * title ) +{ + hb_chapter_t * chapter = hb_list_item( job->list_chapter, chapter_index - 1 ); + hb_chapter_set_title( chapter, title ); +} + +/********************************************************************** * hb_audio_copy ********************************************************************** * @@ -1771,11 +2083,54 @@ hb_audio_t *hb_audio_copy(const hb_audio_t *src) { audio = calloc(1, sizeof(*audio)); memcpy(audio, src, sizeof(*audio)); + if ( src->config.out.name ) + { + audio->config.out.name = strdup(src->config.out.name); + } } return audio; } /********************************************************************** + * hb_audio_list_copy + ********************************************************************** + * + *********************************************************************/ +hb_list_t *hb_audio_list_copy(const hb_list_t *src) +{ + hb_list_t *list = hb_list_init(); + hb_audio_t *audio = NULL; + int i; + + if( src ) + { + for( i = 0; i < hb_list_count(src); i++ ) + { + if( ( audio = hb_list_item( src, i ) ) ) + { + hb_list_add( list, hb_audio_copy(audio) ); + } + } + } + return list; +} + +/********************************************************************** + * hb_audio_close + ********************************************************************** + * + *********************************************************************/ +void hb_audio_close( hb_audio_t **audio ) +{ + if ( audio && *audio ) + { + free((*audio)->config.out.name); + free(*audio); + *audio = NULL; + } +} + +/********************************************************************** * hb_audio_new ********************************************************************** * @@ -1878,7 +2233,7 @@ int hb_audio_add(const hb_job_t * job, const hb_audio_config_t * audiocfg) } if (audiocfg->out.name && *audiocfg->out.name) { - audio->config.out.name = audiocfg->out.name; + audio->config.out.name = strdup(audiocfg->out.name); } hb_list_add(job->list_audio, audio); @@ -1918,6 +2273,45 @@ hb_subtitle_t *hb_subtitle_copy(const hb_subtitle_t *src) } /********************************************************************** + * hb_subtitle_list_copy + ********************************************************************** + * + *********************************************************************/ +hb_list_t *hb_subtitle_list_copy(const hb_list_t *src) +{ + hb_list_t *list = hb_list_init(); + hb_subtitle_t *subtitle = NULL; + int i; + + if( src ) + { + for( i = 0; i < hb_list_count(src); i++ ) + { + if( ( subtitle = hb_list_item( src, i ) ) ) + { + hb_list_add( list, hb_subtitle_copy(subtitle) ); + } + } + } + return list; +} + +/********************************************************************** + * hb_subtitle_close + ********************************************************************** + * + *********************************************************************/ +void hb_subtitle_close( hb_subtitle_t **sub ) +{ + if ( sub && *sub ) + { + free ((*sub)->extradata); + free(*sub); + *sub = NULL; + } +} + +/********************************************************************** * hb_subtitle_add ********************************************************************** * @@ -2026,6 +2420,238 @@ int hb_subtitle_can_pass( int source, int mux ) } } +/********************************************************************** + * hb_metadata_init + ********************************************************************** + * + *********************************************************************/ +hb_metadata_t *hb_metadata_init() +{ + hb_metadata_t *metadata = calloc( 1, sizeof(*metadata) ); + return metadata; +} + +/********************************************************************** + * hb_metadata_copy + ********************************************************************** + * + *********************************************************************/ +hb_metadata_t *hb_metadata_copy( const hb_metadata_t *src ) +{ + hb_metadata_t *metadata = NULL; + + if ( src ) + { + metadata = calloc( 1, sizeof(*metadata) ); + if ( src->name ) + { + metadata->name = strdup(src->name); + } + if ( src->artist ) + { + metadata->artist = strdup(src->artist); + } + if ( src->album_artist ) + { + metadata->album_artist = strdup(src->album_artist); + } + if ( src->composer ) + { + metadata->composer = strdup(src->composer); + } + if ( src->release_date ) + { + metadata->release_date = strdup(src->release_date); + } + if ( src->comment ) + { + metadata->comment = strdup(src->comment); + } + if ( src->album ) + { + metadata->album = strdup(src->album); + } + if ( src->genre ) + { + metadata->genre = strdup(src->genre); + } + if ( src->description ) + { + metadata->description = strdup(src->description); + } + if ( src->long_description ) + { + metadata->long_description = strdup(src->long_description); + } + if ( src->list_coverart ) + { + int ii; + for ( ii = 0; ii < hb_list_count( src->list_coverart ); ii++ ) + { + hb_coverart_t *art = hb_list_item( src->list_coverart, ii ); + hb_metadata_add_coverart( + metadata, art->data, art->size, art->type ); + } + } + } + return metadata; +} + +/********************************************************************** + * hb_metadata_close + ********************************************************************** + * + *********************************************************************/ +void hb_metadata_close( hb_metadata_t **_m ) +{ + if ( _m && *_m ) + { + hb_metadata_t *m = *_m; + hb_coverart_t *art; + + free( m->name ); + free( m->artist ); + free( m->composer ); + free( m->release_date ); + free( m->comment ); + free( m->album ); + free( m->album_artist ); + free( m->genre ); + free( m->description ); + free( m->long_description ); + + if ( m->list_coverart ) + { + while( ( art = hb_list_item( m->list_coverart, 0 ) ) ) + { + hb_list_rem( m->list_coverart, art ); + free( art->data ); + free( art ); + } + hb_list_close( &m->list_coverart ); + } + + free( m ); + *_m = NULL; + } +} + +/********************************************************************** + * hb_metadata_set_* + ********************************************************************** + * + *********************************************************************/ +void hb_metadata_set_name( hb_metadata_t *metadata, const char *name ) +{ + if ( metadata ) + { + hb_update_str( &metadata->name, name ); + } +} + +void hb_metadata_set_artist( hb_metadata_t *metadata, const char *artist ) +{ + if ( metadata ) + { + hb_update_str( &metadata->artist, artist ); + } +} + +void hb_metadata_set_composer( hb_metadata_t *metadata, const char *composer ) +{ + if ( metadata ) + { + hb_update_str( &metadata->composer, composer ); + } +} + +void hb_metadata_set_release_date( hb_metadata_t *metadata, const char *release_date ) +{ + if ( metadata ) + { + hb_update_str( &metadata->release_date, release_date ); + } +} + +void hb_metadata_set_comment( hb_metadata_t *metadata, const char *comment ) +{ + if ( metadata ) + { + hb_update_str( &metadata->comment, comment ); + } +} + +void hb_metadata_set_genre( hb_metadata_t *metadata, const char *genre ) +{ + if ( metadata ) + { + hb_update_str( &metadata->genre, genre ); + } +} + +void hb_metadata_set_album( hb_metadata_t *metadata, const char *album ) +{ + if ( metadata ) + { + hb_update_str( &metadata->album, album ); + } +} + +void hb_metadata_set_album_artist( hb_metadata_t *metadata, const char *album_artist ) +{ + if ( metadata ) + { + hb_update_str( &metadata->album_artist, album_artist ); + } +} + +void hb_metadata_set_description( hb_metadata_t *metadata, const char *description ) +{ + if ( metadata ) + { + hb_update_str( &metadata->description, description ); + } +} + +void hb_metadata_set_long_description( hb_metadata_t *metadata, const char *long_description ) +{ + if ( metadata ) + { + hb_update_str( &metadata->long_description, long_description ); + } +} + +void hb_metadata_add_coverart( hb_metadata_t *metadata, const uint8_t *data, int size, int type ) +{ + if ( metadata ) + { + if ( metadata->list_coverart == NULL ) + { + metadata->list_coverart = hb_list_init(); + } + hb_coverart_t *art = calloc( 1, sizeof(hb_coverart_t) ); + art->data = malloc( size ); + memcpy( art->data, data, size ); + art->size = size; + art->type = type; + hb_list_add( metadata->list_coverart, art ); + } +} + +void hb_metadata_rem_coverart( hb_metadata_t *metadata, int idx ) +{ + if ( metadata ) + { + hb_coverart_t *art = hb_list_item( metadata->list_coverart, idx ); + if ( art ) + { + hb_list_rem( metadata->list_coverart, art ); + free( art->data ); + free( art ); + } + } +} + char * hb_strdup_printf( const char * fmt, ... ) { int len; @@ -2119,6 +2745,46 @@ hb_attachment_t *hb_attachment_copy(const hb_attachment_t *src) } /********************************************************************** + * hb_attachment_list_copy + ********************************************************************** + * + *********************************************************************/ +hb_list_t *hb_attachment_list_copy(const hb_list_t *src) +{ + hb_list_t *list = hb_list_init(); + hb_attachment_t *attachment = NULL; + int i; + + if( src ) + { + for( i = 0; i < hb_list_count(src); i++ ) + { + if( ( attachment = hb_list_item( src, i ) ) ) + { + hb_list_add( list, hb_attachment_copy(attachment) ); + } + } + } + return list; +} + +/********************************************************************** + * hb_attachment_close + ********************************************************************** + * + *********************************************************************/ +void hb_attachment_close( hb_attachment_t **attachment ) +{ + if ( attachment && *attachment ) + { + free((*attachment)->data); + free((*attachment)->name); + free(*attachment); + *attachment = NULL; + } +} + +/********************************************************************** * hb_yuv2rgb ********************************************************************** * Converts a YCrCb pixel to an RGB pixel. diff --git a/libhb/common.h b/libhb/common.h index f7cc6dfef..41711e954 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -73,6 +73,7 @@ typedef struct hb_rate_s hb_rate_t; typedef struct hb_mixdown_s hb_mixdown_t; typedef struct hb_encoder_s hb_encoder_t; typedef struct hb_job_s hb_job_t; +typedef struct hb_title_set_s hb_title_set_t; typedef struct hb_title_s hb_title_t; typedef struct hb_chapter_s hb_chapter_t; typedef struct hb_audio_s hb_audio_t; @@ -81,6 +82,7 @@ typedef struct hb_subtitle_s hb_subtitle_t; typedef struct hb_subtitle_config_s hb_subtitle_config_t; typedef struct hb_attachment_s hb_attachment_t; typedef struct hb_metadata_s hb_metadata_t; +typedef struct hb_coverart_s hb_coverart_t; typedef struct hb_state_s hb_state_t; typedef union hb_esconfig_u hb_esconfig_t; typedef struct hb_work_private_s hb_work_private_t; @@ -102,11 +104,11 @@ typedef struct hb_lock_s hb_lock_t; #include "libavutil/audioconvert.h" hb_list_t * hb_list_init(); -int hb_list_count( hb_list_t * ); +int hb_list_count( const hb_list_t * ); void hb_list_add( hb_list_t *, void * ); void hb_list_insert( hb_list_t * l, int pos, void * p ); void hb_list_rem( hb_list_t *, void * ); -void * hb_list_item( hb_list_t *, int ); +void * hb_list_item( const hb_list_t *, int ); void hb_list_close( hb_list_t ** ); void hb_reduce( int *x, int *y, int num, int den ); @@ -117,12 +119,19 @@ void hb_limit_rational64( int64_t *x, int64_t *y, int64_t num, int64_t den, int6 #define HB_KEEP_HEIGHT 1 void hb_fix_aspect( hb_job_t * job, int keep ); +void hb_job_set_advanced_opts( hb_job_t *job, const char *advanced_opts ); +void hb_job_set_file( hb_job_t *job, const char *file ); + hb_audio_t *hb_audio_copy(const hb_audio_t *src); +hb_list_t *hb_audio_list_copy(const hb_list_t *src); +void hb_audio_close(hb_audio_t **audio); void hb_audio_config_init(hb_audio_config_t * audiocfg); int hb_audio_add(const hb_job_t * job, const hb_audio_config_t * audiocfg); hb_audio_config_t * hb_list_audio_config_item(hb_list_t * list, int i); hb_subtitle_t *hb_subtitle_copy(const hb_subtitle_t *src); +hb_list_t *hb_subtitle_list_copy(const hb_list_t *src); +void hb_subtitle_close( hb_subtitle_t **sub ); int hb_subtitle_add(const hb_job_t * job, const hb_subtitle_config_t * subtitlecfg, int track); int hb_srt_add(const hb_job_t * job, const hb_subtitle_config_t * subtitlecfg, const char *lang); @@ -131,6 +140,29 @@ int hb_subtitle_can_burn( int source ); int hb_subtitle_can_pass( int source, int mux ); hb_attachment_t *hb_attachment_copy(const hb_attachment_t *src); +hb_list_t *hb_attachment_list_copy(const hb_list_t *src); +void hb_attachment_close(hb_attachment_t **attachment); + +hb_metadata_t * hb_metadata_init(); +hb_metadata_t * hb_metadata_copy(const hb_metadata_t *src); +void hb_metadata_close(hb_metadata_t **metadata); +void hb_metadata_set_name( hb_metadata_t *metadata, const char *name ); +void hb_metadata_set_artist( hb_metadata_t *metadata, const char *artist ); +void hb_metadata_set_composer( hb_metadata_t *metadata, const char *composer ); +void hb_metadata_set_release_date( hb_metadata_t *metadata, const char *release_date ); +void hb_metadata_set_comment( hb_metadata_t *metadata, const char *comment ); +void hb_metadata_set_genre( hb_metadata_t *metadata, const char *genre ); +void hb_metadata_set_album( hb_metadata_t *metadata, const char *album ); +void hb_metadata_set_album_artist( hb_metadata_t *metadata, const char *album_artist ); +void hb_metadata_set_description( hb_metadata_t *metadata, const char *description ); +void hb_metadata_set_long_description( hb_metadata_t *metadata, const char *long_description ); +void hb_metadata_add_coverart( hb_metadata_t *metadata, const uint8_t *data, int size, int type ); +void hb_metadata_rem_coverart( hb_metadata_t *metadata, int ii ); + +hb_chapter_t *hb_chapter_copy(const hb_chapter_t *src); +hb_list_t *hb_chapter_list_copy(const hb_list_t *src); +void hb_chapter_close(hb_chapter_t **chapter); +void hb_chapter_set_title(hb_chapter_t *chapter, const char *title); struct hb_rate_s { @@ -205,7 +237,9 @@ int hb_mixdown_get_low_freq_channel_count(int amixdown); int hb_mixdown_get_mixdown_from_short_name(const char *short_name); const char* hb_mixdown_get_short_name_from_mixdown(int amixdown); -void hb_autopassthru_apply_settings( hb_job_t * job, hb_title_t * title ); +int hb_mixdown_get_mixdown_from_short_name( const char * short_name ); +const char * hb_mixdown_get_short_name_from_mixdown( int amixdown ); +void hb_autopassthru_apply_settings( hb_job_t * job ); void hb_autopassthru_print_settings( hb_job_t * job ); int hb_autopassthru_get_encoder( int in_codec, int copy_mask, int fallback, int muxer ); int hb_get_best_mixdown(uint32_t codec, uint64_t layout, int mixdown); @@ -222,6 +256,12 @@ void hb_get_audio_compression_limits(uint32_t codec, float *low, float *high, fl float hb_get_best_audio_compression( uint32_t codec, float compression); float hb_get_default_audio_compression( uint32_t codec ); +struct hb_title_set_s +{ + hb_list_t * list_title; + int feature; // Detected DVD feature title +}; + /****************************************************************************** * hb_job_t: settings to be filled by the UI *****************************************************************************/ @@ -333,6 +373,8 @@ struct hb_job_s #define HB_COLR_MAT_SMPTE240M 7 // 0, 3-5, 8-65535: reserved + hb_list_t * list_chapter; + /* List of audio settings. */ hb_list_t * list_audio; int acodec_copy_mask; // Auto Passthru allowed codecs @@ -341,6 +383,10 @@ struct hb_job_s /* Subtitles */ hb_list_t * list_subtitle; + hb_list_t * list_attachment; + + hb_metadata_t * metadata; + /* Muxer settings mux: output file format file: file path */ @@ -349,7 +395,7 @@ struct hb_job_s #define HB_MUX_MKV 0x200000 int mux; - const char * file; + char * file; /* Allow MP4 files > 4 gigs */ int largeFileSize; @@ -534,7 +580,7 @@ struct hb_chapter_s uint64_t duration; /* Optional chapter title */ - char title[1024]; + char *title; }; /* @@ -615,23 +661,38 @@ struct hb_subtitle_s */ struct hb_attachment_s { - enum attachtype { FONT_TTF_ATTACH } type; + enum attachtype { FONT_TTF_ATTACH, HB_ART_ATTACH } type; char * name; char * data; int size; }; +struct hb_coverart_s +{ + uint8_t *data; + uint32_t size; + enum arttype { + HB_ART_UNDEFINED, + HB_ART_BMP, + HB_ART_GIF, + HB_ART_PNG, + HB_ART_JPEG + } type; +}; + struct hb_metadata_s { - char name[255]; - char artist[255]; - char composer[255]; - char release_date[255]; - char comment[1024]; - char album[255]; - char genre[255]; - uint32_t coverart_size; - uint8_t *coverart; + char *name; + char *artist; // Actors + char *composer; + char *release_date; + char *comment; + char *album; // DVD + char *album_artist; // Director + char *genre; + char *description; + char *long_description; + hb_list_t * list_coverart; }; struct hb_title_s @@ -682,7 +743,7 @@ struct hb_title_s int video_codec_param; /* codec specific config */ char *video_codec_name; int video_bitrate; - const char *container_name; + char *container_name; int data_rate; hb_metadata_t *metadata; @@ -692,12 +753,15 @@ struct hb_title_s hb_list_t * list_subtitle; hb_list_t * list_attachment; - /* Job template for this title */ +#define HB_TITLE_JOBS +#if defined(HB_TITLE_JOBS) hb_job_t * job; +#endif uint32_t flags; // set if video stream doesn't have IDR frames #define HBTF_NO_IDR (1 << 0) +#define HBTF_SCAN_COMPLETE (1 << 0) }; @@ -941,7 +1005,8 @@ enum hb_filter_object_t * hb_filter_init( int filter_id ); hb_filter_object_t * hb_filter_copy( hb_filter_object_t * filter ); -void hb_filter_close( hb_filter_object_t ** ); +hb_list_t *hb_filter_list_copy(const hb_list_t *src); +void hb_filter_close( hb_filter_object_t ** ); typedef void hb_error_handler_t( const char *errmsg ); diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c index 4fd22c833..dd3c8879d 100644 --- a/libhb/decavcodec.c +++ b/libhb/decavcodec.c @@ -565,7 +565,7 @@ static void log_chapter( hb_work_private_t *pv, int chap_num, int64_t pts ) if ( !pv->job ) return; - c = hb_list_item( pv->job->title->list_chapter, chap_num - 1 ); + c = hb_list_item( pv->job->list_chapter, chap_num - 1 ); if ( c && c->title ) { hb_log( "%s: \"%s\" (%d) at frame %u time %"PRId64, diff --git a/libhb/decmetadata.c b/libhb/decmetadata.c index e3829de09..513e64fbe 100644 --- a/libhb/decmetadata.c +++ b/libhb/decmetadata.c @@ -11,9 +11,10 @@ #include "common.h" -static void decmp4metadata( hb_title_t *title ) +static int decmp4metadata( hb_title_t *title ) { MP4FileHandle input_file; + int result = 0; hb_deep_log( 2, "Got an MP4 input, read the metadata"); input_file = MP4Read( title->path, 0 ); @@ -31,35 +32,93 @@ static void decmp4metadata( hb_title_t *title ) if( tags->name ) { hb_deep_log( 2, "Metadata Name in input file is '%s'", tags->name ); - strncpy( title->metadata->name, tags->name, sizeof(title->metadata->name) ); + hb_metadata_set_name(title->metadata, tags->name); + result = 1; } if( tags->artist ) - strncpy( title->metadata->artist, tags->artist, sizeof(title->metadata->artist) ); + { + hb_metadata_set_artist(title->metadata, tags->artist); + result = 1; + } if( tags->composer ) - strncpy( title->metadata->composer, tags->composer, sizeof(title->metadata->composer) ); + { + hb_metadata_set_composer(title->metadata, tags->composer); + result = 1; + } if( tags->comments ) - strncpy( title->metadata->comment, tags->comments, sizeof(title->metadata->comment) ); + { + hb_metadata_set_comment(title->metadata, tags->comments); + result = 1; + } if( tags->releaseDate ) - strncpy( title->metadata->release_date, tags->releaseDate, sizeof(title->metadata->release_date) ); + { + hb_metadata_set_release_date(title->metadata, tags->releaseDate); + result = 1; + } if( tags->album ) - strncpy( title->metadata->album, tags->album, sizeof(title->metadata->album) ); + { + hb_metadata_set_album(title->metadata, tags->album); + result = 1; + } + + if( tags->albumArtist ) + { + hb_metadata_set_album_artist(title->metadata, tags->albumArtist); + result = 1; + } if( tags->genre ) - strncpy( title->metadata->genre, tags->genre, sizeof(title->metadata->genre) ); + { + hb_metadata_set_genre(title->metadata, tags->genre); + result = 1; + } + + if( tags->description ) + { + hb_metadata_set_description(title->metadata, tags->description); + result = 1; + } + + if( tags->longDescription ) + { + hb_metadata_set_long_description(title->metadata, tags->longDescription); + result = 1; + } - if( tags->artworkCount > 0 ) { - const MP4TagArtwork* art = tags->artwork + 0; // first element - title->metadata->coverart = (uint8_t*)malloc( art->size ); - title->metadata->coverart_size = art->size; - memcpy( title->metadata->coverart, art->data, art->size ); + int ii; + for ( ii = 0; ii < tags->artworkCount; ii++ ) + { + const MP4TagArtwork* art = tags->artwork + ii; + int type; + switch ( art->type ) + { + case MP4_ART_BMP: + type = HB_ART_BMP; + break; + case MP4_ART_GIF: + type = HB_ART_GIF; + break; + case MP4_ART_JPEG: + type = HB_ART_JPEG; + break; + case MP4_ART_PNG: + type = HB_ART_PNG; + break; + default: + type = HB_ART_UNDEFINED; + break; + } + hb_metadata_add_coverart( + title->metadata, art->data, art->size, type); hb_deep_log( 2, "Got some cover art of type %d, size %d", art->type, - title->metadata->coverart_size ); + art->size ); + result = 1; } /* store,free tags */ @@ -91,11 +150,13 @@ static void decmp4metadata( hb_title_t *title ) if( chapter_list[i-1].title ) { - strcpy( chapter->title, chapter_list[i-1].title ); + hb_chapter_set_title( chapter, chapter_list[i-1].title ); } else { - sprintf( chapter->title, "Chapter %d", chapter->index ); + char chapter_title[80]; + sprintf( chapter_title, "Chapter %d", chapter->index ); + hb_chapter_set_title( chapter, chapter_title ); } hb_deep_log( 2, "Added chapter %i, name='%s', dur=%"PRId64", (%02i:%02i:%02i)", @@ -109,6 +170,7 @@ static void decmp4metadata( hb_title_t *title ) MP4Close( input_file ); } + return result; } /* @@ -116,24 +178,16 @@ static void decmp4metadata( hb_title_t *title ) * * Look at the title and extract whatever metadata we can from that title. */ -void decmetadata( hb_title_t *title ) +int decmetadata( hb_title_t *title ) { if( !title ) { - return; + return 0; } - if( title->metadata ) - { - free( title->metadata ); - title->metadata = NULL; - } - - title->metadata = calloc( sizeof(hb_metadata_t), 1); - if( !title->metadata ) { - return; + return 0; } /* @@ -141,9 +195,7 @@ void decmetadata( hb_title_t *title ) */ if( title->container_name && strcmp(title->container_name, "mov,mp4,m4a,3gp,3g2,mj2") == 0 ) { - decmp4metadata( title ); - } else { - free( title->metadata ); - title->metadata = NULL; + return decmp4metadata( title ); } + return 0; } diff --git a/libhb/decmpeg2.c b/libhb/decmpeg2.c index 311fc93c8..991feb8e9 100644 --- a/libhb/decmpeg2.c +++ b/libhb/decmpeg2.c @@ -498,11 +498,11 @@ static int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es, m->look_for_iframe = 0; const char *chap_name = ""; if ( m->job && new_chap > 0 && - hb_list_item( m->job->title->list_chapter, + hb_list_item( m->job->list_chapter, new_chap - 1 ) ) { hb_chapter_t * c = hb_list_item( - m->job->title->list_chapter, + m->job->list_chapter, new_chap - 1 ); chap_name = c->title; } @@ -514,10 +514,10 @@ static int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es, { // this is the first frame returned by the decoder m->first_pts = buf->s.start; - if ( m->job && hb_list_item( m->job->title->list_chapter, + if ( m->job && hb_list_item( m->job->list_chapter, m->job->chapter_start - 1 ) ) { - hb_chapter_t * c = hb_list_item( m->job->title->list_chapter, + hb_chapter_t * c = hb_list_item( m->job->list_chapter, m->job->chapter_start - 1 ); hb_log( "mpeg2: \"%s\" (%d) at frame %u time %"PRId64, c->title, m->job->chapter_start, m->nframes, buf->s.start ); diff --git a/libhb/decsrtsub.c b/libhb/decsrtsub.c index 55004c05f..6d1754068 100644 --- a/libhb/decsrtsub.c +++ b/libhb/decsrtsub.c @@ -464,7 +464,6 @@ static int decsrtInit( hb_work_object_t * w, hb_job_t * job ) hb_buffer_t *buffer; int i; hb_chapter_t * chapter; - hb_title_t *title = job->title; pv = calloc( 1, sizeof( hb_work_private_t ) ); if( pv ) @@ -489,7 +488,7 @@ static int decsrtInit( hb_work_object_t * w, hb_job_t * job ) pv->start_time = 0; for( i = 1; i < job->chapter_start; ++i ) { - chapter = hb_list_item( title->list_chapter, i - 1 ); + chapter = hb_list_item( job->list_chapter, i - 1 ); if( chapter ) { pv->start_time += chapter->duration; @@ -501,7 +500,7 @@ static int decsrtInit( hb_work_object_t * w, hb_job_t * job ) pv->stop_time = pv->start_time; for( i = job->chapter_start; i <= job->chapter_end; ++i ) { - chapter = hb_list_item( title->list_chapter, i - 1 ); + chapter = hb_list_item( job->list_chapter, i - 1 ); if( chapter ) { pv->stop_time += chapter->duration; diff --git a/libhb/dvd.c b/libhb/dvd.c index 1a273f977..f342b5474 100644 --- a/libhb/dvd.c +++ b/libhb/dvd.c @@ -561,11 +561,13 @@ static hb_title_t * hb_dvdread_title_scan( hb_dvd_t * e, int t, uint64_t min_dur for( i = 0; i < vts->vts_ptt_srpt->title[title->ttn-1].nr_of_ptts; i++ ) { + char chapter_title[80]; chapter = calloc( sizeof( hb_chapter_t ), 1 ); /* remember the on-disc chapter number */ chapter->index = i + 1; - sprintf( chapter->title, "Chapter %d", chapter->index ); + sprintf( chapter_title, "Chapter %d", chapter->index ); + hb_chapter_set_title( chapter, chapter_title ); pgc_id = vts->vts_ptt_srpt->title[title->ttn-1].ptt[i].pgcn; pgn = vts->vts_ptt_srpt->title[title->ttn-1].ptt[i].pgn; diff --git a/libhb/dvdnav.c b/libhb/dvdnav.c index 638b6e5af..c1f152efd 100644 --- a/libhb/dvdnav.c +++ b/libhb/dvdnav.c @@ -740,12 +740,14 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t, uint64_t min_dura for (i = pgn; i <= pgc->nr_of_programs; i++) { + char chapter_title[80]; chapter = calloc( sizeof( hb_chapter_t ), 1 ); chapter->pgcn = pgcn; chapter->pgn = i; chapter->index = c + 1; - sprintf( chapter->title, "Chapter %d", chapter->index ); + sprintf( chapter_title, "Chapter %d", chapter->index ); + hb_chapter_set_title( chapter, chapter_title ); hb_list_add( title->list_chapter, chapter ); c++; diff --git a/libhb/hb.c b/libhb/hb.c index 52ddc206b..8a1ec3b1e 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -36,7 +36,7 @@ struct hb_handle_s int pid; /* DVD/file scan thread */ - hb_list_t * list_title; + hb_title_set_t title_set; hb_thread_t * scan_thread; /* The thread which processes the jobs. Others threads are launched @@ -71,7 +71,6 @@ int hb_instance_counter = 0; int hb_process_initialized = 0; static void thread_func( void * ); -hb_title_t * hb_get_title_by_index( hb_handle_t *, int ); static int ff_lockmgr_cb(void **mutex, enum AVLockOp op) { @@ -432,7 +431,7 @@ hb_handle_t * hb_init( int verbose, int update_check ) */ hb_buffer_pool_init(); - h->list_title = hb_list_init(); + h->title_set.list_title = hb_list_init(); h->jobs = hb_list_init(); h->state_lock = hb_lock_init(); @@ -531,7 +530,7 @@ hb_handle_t * hb_init_dl( int verbose, int update_check ) } } - h->list_title = hb_list_init(); + h->title_set.list_title = hb_list_init(); h->jobs = hb_list_init(); h->current_job = NULL; @@ -631,7 +630,7 @@ void hb_remove_previews( hb_handle_t * h ) dir = opendir( dirname ); if (dir == NULL) return; - count = hb_list_count( h->list_title ); + count = hb_list_count( h->title_set.list_title ); while( ( entry = readdir( dir ) ) ) { if( entry->d_name[0] == '.' ) @@ -640,7 +639,7 @@ void hb_remove_previews( hb_handle_t * h ) } for( i = 0; i < count; i++ ) { - title = hb_list_item( h->list_title, i ); + title = hb_list_item( h->title_set.list_title, i ); len = snprintf( filename, 1024, "%d_%d", h->id, title->index ); if (strncmp(entry->d_name, filename, len) == 0) { @@ -670,15 +669,15 @@ void hb_scan( hb_handle_t * h, const char * path, int title_index, /* Clean up from previous scan */ hb_remove_previews( h ); - while( ( title = hb_list_item( h->list_title, 0 ) ) ) + while( ( title = hb_list_item( h->title_set.list_title, 0 ) ) ) { - hb_list_rem( h->list_title, title ); + hb_list_rem( h->title_set.list_title, title ); hb_title_close( &title ); } hb_log( "hb_scan: path=%s, title_index=%d", path, title_index ); h->scan_thread = hb_scan_init( h, &h->scan_die, path, title_index, - h->list_title, preview_count, + &h->title_set, preview_count, store_previews, min_duration ); } @@ -689,25 +688,12 @@ void hb_scan( hb_handle_t * h, const char * path, int title_index, */ hb_list_t * hb_get_titles( hb_handle_t * h ) { - return h->list_title; + return h->title_set.list_title; } -/** - * Create preview image of desired title a index of picture. - * @param h Handle to hb_handle_t. - * @param title_index Index of the title to get the preview for (1-based). - * @param picture Index in title. - * @param buffer Handle to buffer were image will be drawn. - */ -void hb_get_preview_by_index( hb_handle_t * h, int title_index, int picture, uint8_t * buffer ) +hb_title_set_t * hb_get_title_set( hb_handle_t * h ) { - hb_title_t * title; - - title = hb_get_title_by_index( h, title_index ); - if ( title != NULL ) - { - hb_get_preview( h, title, picture, buffer ); - } + return &h->title_set; } int hb_save_preview( hb_handle_t * h, int title, int preview, hb_buffer_t *buf ) @@ -747,12 +733,16 @@ hb_buffer_t * hb_read_preview( hb_handle_t * h, int title_idx, int preview ) { FILE * file; char filename[1024]; + hb_title_set_t *title_set; + hb_title_t * title = NULL; + title_set = hb_get_title_set(h); + int ii; - for (ii = 0; ii < hb_list_count(h->list_title); ii++) + for (ii = 0; ii < hb_list_count(title_set->list_title); ii++) { - title = hb_list_item( h->list_title, ii); + title = hb_list_item( title_set->list_title, ii); if (title != NULL && title->index == title_idx) { break; @@ -804,10 +794,10 @@ hb_buffer_t * hb_read_preview( hb_handle_t * h, int title_idx, int preview ) * @param picture Index in title. * @param buffer Handle to buffer were image will be drawn. */ -void hb_get_preview( hb_handle_t * h, hb_title_t * title, int picture, +void hb_get_preview( hb_handle_t * h, hb_job_t * job, int picture, uint8_t * buffer ) { - hb_job_t * job = title->job; + hb_title_t * title = job->title; char filename[1024]; hb_buffer_t * in_buf, * deint_buf = NULL, * preview_buf; uint8_t * pen; @@ -991,26 +981,6 @@ int hb_detect_comb( hb_buffer_t * buf, int color_equal, int color_diff, int thre /** * Calculates job width and height for anamorphic content, * - * @param h Instance handle - * @param title_index Index of the title/job to inspect (1-based). - * @param output_width Pointer to returned storage width - * @param output_height Pointer to returned storage height - * @param output_par_width Pointer to returned pixel width - * @param output_par_height Pointer to returned pixel height - */ -void hb_set_anamorphic_size_by_index( hb_handle_t * h, int title_index, - int *output_width, int *output_height, - int *output_par_width, int *output_par_height ) -{ - hb_title_t * title; - title = hb_get_title_by_index( h, title_index ); - - hb_set_anamorphic_size( title->job, output_width, output_height, output_par_width, output_par_height ); -} - -/** - * Calculates job width and height for anamorphic content, - * * @param job Handle to hb_job_t * @param output_width Pointer to returned storage width * @param output_height Pointer to returned storage height @@ -1423,53 +1393,6 @@ hb_job_t * hb_current_job( hb_handle_t * h ) } /** - * Applies information from the given job to the official job instance. - * @param h Handle to hb_handle_t. - * @param title_index Index of the title to apply the chapter name to (1-based). - * @param chapter The chapter to apply the name to (1-based). - * @param job Job information to apply. - */ -void hb_set_chapter_name( hb_handle_t * h, int title_index, int chapter_index, const char * chapter_name ) -{ - hb_title_t * title; - title = hb_get_title_by_index( h, title_index ); - - hb_chapter_t * chapter = hb_list_item( title->list_chapter, chapter_index - 1 ); - - strncpy(chapter->title, chapter_name, 1023); - chapter->title[1023] = '\0'; -} - -/** - * Applies information from the given job to the official job instance. - * Currently only applies information needed for anamorphic size calculation and previews. - * @param h Handle to hb_handle_t. - * @param title_index Index of the title to apply the job information to (1-based). - * @param job Job information to apply. - */ -void hb_set_job( hb_handle_t * h, int title_index, hb_job_t * job ) -{ - int i; - - hb_title_t * title; - title = hb_get_title_by_index( h, title_index ); - - hb_job_t * job_target = title->job; - - job_target->deinterlace = job->deinterlace; - job_target->width = job->width; - job_target->height = job->height; - job_target->maxWidth = job->maxWidth; - job_target->maxHeight = job->maxHeight; - for (i = 0; i < 4; i++) - { - job_target->crop[i] = job->crop[i]; - } - - job_target->anamorphic = job->anamorphic; -} - -/** * Adds a job to the job list. * @param h Handle to hb_handle_t. * @param job Handle to hb_job_t. @@ -1477,85 +1400,21 @@ void hb_set_job( hb_handle_t * h, int title_index, hb_job_t * job ) void hb_add( hb_handle_t * h, hb_job_t * job ) { hb_job_t * job_copy; - hb_title_t * title, * title_copy; - hb_chapter_t * chapter, * chapter_copy; hb_audio_t * audio; hb_subtitle_t * subtitle; - hb_attachment_t * attachment; int i; char audio_lang[4]; - /* Copy the title */ - title = job->title; - title_copy = malloc( sizeof( hb_title_t ) ); - memcpy( title_copy, title, sizeof( hb_title_t ) ); - - title_copy->list_chapter = hb_list_init(); - for( i = 0; i < hb_list_count( title->list_chapter ); i++ ) - { - chapter = hb_list_item( title->list_chapter, i ); - chapter_copy = malloc( sizeof( hb_chapter_t ) ); - memcpy( chapter_copy, chapter, sizeof( hb_chapter_t ) ); - hb_list_add( title_copy->list_chapter, chapter_copy ); - } - - /* - * Copy the metadata - */ - if( title->metadata ) - { - title_copy->metadata = malloc( sizeof( hb_metadata_t ) ); - - if( title_copy->metadata ) - { - memcpy( title_copy->metadata, title->metadata, sizeof( hb_metadata_t ) ); - - /* - * Need to copy the artwork seperatly (TODO). - */ - if( title->metadata->coverart ) - { - title_copy->metadata->coverart = malloc( title->metadata->coverart_size ); - if( title_copy->metadata->coverart ) - { - memcpy( title_copy->metadata->coverart, title->metadata->coverart, - title->metadata->coverart_size ); - } else { - title_copy->metadata->coverart_size = 0; - } - } - } - } - - /* Copy the audio track(s) we want */ - title_copy->list_audio = hb_list_init(); - for( i = 0; i < hb_list_count(job->list_audio); i++ ) - { - if( ( audio = hb_list_item( job->list_audio, i ) ) ) - { - hb_list_add( title_copy->list_audio, hb_audio_copy(audio) ); - } - } - - /* Initialize subtitle list - filled out further below */ - title_copy->list_subtitle = hb_list_init(); - - /* Copy all the attachments */ - title_copy->list_attachment = hb_list_init(); - for( i = 0; i < hb_list_count(title->list_attachment); i++ ) - { - if( ( attachment = hb_list_item( title->list_attachment, i ) ) ) - { - hb_list_add( title_copy->list_attachment, hb_attachment_copy(attachment) ); - } - } - title_copy->video_codec_name = strdup( title->video_codec_name ); + /* Copy the job */ + job_copy = calloc( sizeof( hb_job_t ), 1 ); + memcpy( job_copy, job, sizeof( hb_job_t ) ); - /* If we're doing Foreign Audio Search, copy all subtitles matching the first - * audio track language we find in the audio list. + /* If we're doing Foreign Audio Search, copy all subtitles matching the + * first audio track language we find in the audio list. * - * Otherwise, copy all subtitles found in the input job (which can be manually - * selected by the user, or added after the Foreign Audio Search pass). */ + * Otherwise, copy all subtitles found in the input job (which can be + * manually selected by the user, or added after the Foreign Audio + * Search pass). */ memset( audio_lang, 0, sizeof( audio_lang ) ); if( job->indepth_scan ) @@ -1571,9 +1430,16 @@ void hb_add( hb_handle_t * h, hb_job_t * job ) break; } } - for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + + /* + * If doing a subtitle scan then add all the matching subtitles for this + * language. + */ + job_copy->list_subtitle = hb_list_init(); + + for( i = 0; i < hb_list_count( job->title->list_subtitle ); i++ ) { - subtitle = hb_list_item( title->list_subtitle, i ); + subtitle = hb_list_item( job->title->list_subtitle, i ); if( strcmp( subtitle->iso639_2, audio_lang ) == 0 && hb_subtitle_can_force( subtitle->source ) ) { @@ -1582,54 +1448,31 @@ void hb_add( hb_handle_t * h, hb_job_t * job ) * * We will update the subtitle list on the next pass later, after * the subtitle scan pass has completed. */ - hb_list_add( title_copy->list_subtitle, hb_subtitle_copy( subtitle ) ); + hb_list_add( job_copy->list_subtitle, + hb_subtitle_copy( subtitle ) ); } } } else { /* Copy all subtitles from the input job to title_copy/job_copy. */ - for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) - { - if( ( subtitle = hb_list_item( job->list_subtitle, i ) ) ) - { - hb_list_add( title_copy->list_subtitle, hb_subtitle_copy( subtitle ) ); - } - } + job_copy->list_subtitle = hb_subtitle_list_copy( job->list_subtitle ); } - /* Copy the job */ - job_copy = calloc( sizeof( hb_job_t ), 1 ); - memcpy( job_copy, job, sizeof( hb_job_t ) ); - title_copy->job = job_copy; - job_copy->title = title_copy; - job_copy->list_audio = title_copy->list_audio; - job_copy->list_subtitle = title_copy->list_subtitle; // sharing list between title and job - job_copy->file = strdup( job->file ); + job_copy->list_chapter = hb_chapter_list_copy( job->list_chapter ); + job_copy->list_audio = hb_audio_list_copy( job->list_audio ); + job_copy->list_attachment = hb_attachment_list_copy( job->list_attachment ); + job_copy->metadata = hb_metadata_copy( job->metadata ); + + if ( job->file ) + job_copy->file = strdup( job->file ); + if ( job->advanced_opts ) + job_copy->advanced_opts = strdup( job->advanced_opts ); job_copy->h = h; job_copy->pause = h->pause_lock; /* Copy the job filter list */ - if( job->list_filter ) - { - int i; - int filter_count = hb_list_count( job->list_filter ); - job_copy->list_filter = hb_list_init(); - for( i = 0; i < filter_count; i++ ) - { - /* - * Copy the filters, since the MacGui reuses the global filter objects - * meaning that queued up jobs overwrite the previous filter settings. - * In reality, settings is probably the only field that needs duplicating - * since it's the only value that is ever changed. But name is duplicated - * as well for completeness. Not copying private_data since it gets - * created for each job in renderInit. - */ - hb_filter_object_t * filter = hb_list_item( job->list_filter, i ); - hb_filter_object_t * filter_copy = hb_filter_copy( filter ); - hb_list_add( job_copy->list_filter, filter_copy ); - } - } + job_copy->list_filter = hb_filter_list_copy( job->list_filter ); /* Add the job to the list */ hb_list_add( h->jobs, job_copy ); @@ -1638,37 +1481,6 @@ void hb_add( hb_handle_t * h, hb_job_t * job ) } /** - * Clean up the job structure so that is is ready for setting up a new job. - * Should be called by front-ends after hb_add(). - */ -void hb_reset_job( hb_job_t * job ) -{ - hb_audio_t *audio; - hb_subtitle_t *subtitle; - hb_filter_object_t *filter; - - // clean up audio list - while( ( audio = hb_list_item( job->list_audio, 0 ) ) ) - { - hb_list_rem( job->list_audio, audio ); - free( audio ); - } - // clean up subtitle list - while( ( subtitle = hb_list_item( job->list_subtitle, 0 ) ) ) - { - hb_list_rem( job->list_subtitle, subtitle ); - free( subtitle ); - } - // clean up filter list - while( ( filter = hb_list_item( job->list_filter, 0 ) ) ) - { - hb_list_rem( job->list_filter, filter ); - free( filter->settings ); - free( filter ); - } -} - -/** * Removes a job from the job list. * @param h Handle to hb_handle_t. * @param job Handle to hb_job_t. @@ -1831,17 +1643,12 @@ void hb_close( hb_handle_t ** _h ) hb_thread_close( &h->main_thread ); - while( ( title = hb_list_item( h->list_title, 0 ) ) ) + while( ( title = hb_list_item( h->title_set.list_title, 0 ) ) ) { - hb_list_rem( h->list_title, title ); - if( title->job ) - { - hb_reset_job( title->job ); - } - free( title->job ); + hb_list_rem( h->title_set.list_title, title ); hb_title_close( &title ); } - hb_list_close( &h->list_title ); + hb_list_close( &h->title_set.list_title ); hb_list_close( &h->jobs ); hb_lock_close( &h->state_lock ); @@ -1925,9 +1732,9 @@ static void thread_func( void * _h ) hb_title_t * title; hb_remove_previews( h ); - while( ( title = hb_list_item( h->list_title, 0 ) ) ) + while( ( title = hb_list_item( h->title_set.list_title, 0 ) ) ) { - hb_list_rem( h->list_title, title ); + hb_list_rem( h->title_set.list_title, title ); hb_title_close( &title ); } @@ -1936,7 +1743,7 @@ static void thread_func( void * _h ) else { hb_log( "libhb: scan thread found %d valid title(s)", - hb_list_count( h->list_title ) ); + hb_list_count( h->title_set.list_title ) ); } hb_lock( h->state_lock ); h->state.state = HB_STATE_SCANDONE; //originally state.state @@ -2024,29 +1831,6 @@ int hb_get_instance_id( hb_handle_t * h ) } /** - * Returns the title with the given title index. - * @param h Handle to hb_handle_t - * @param title_index the index of the title to get - * @returns The requested title - */ -hb_title_t * hb_get_title_by_index( hb_handle_t * h, int title_index ) -{ - hb_title_t * title; - int i; - int count = hb_list_count( h->list_title ); - for (i = 0; i < count; i++) - { - title = hb_list_item( h->list_title, i ); - if (title->index == title_index) - { - return title; - } - } - - return NULL; -} - -/** * Sets the current state. * @param h Handle to hb_handle_t * @param s Handle to new hb_state_t diff --git a/libhb/hb.h b/libhb/hb.h index da2311834..825032cfb 100644 --- a/libhb/hb.h +++ b/libhb/hb.h @@ -54,21 +54,23 @@ uint64_t hb_first_duration( hb_handle_t * ); Returns the list of valid titles detected by the latest scan. */ hb_list_t * hb_get_titles( hb_handle_t * ); +/* hb_get_title_set() + Returns the title set which contains a list of valid titles detected + by the latest scan and title set data. */ +hb_title_set_t * hb_get_title_set( hb_handle_t * ); + /* hb_detect_comb() Analyze a frame for interlacing artifacts, returns true if they're found. Taken from Thomas Oestreich's 32detect filter in the Transcode project. */ int hb_detect_comb( hb_buffer_t * buf, int color_equal, int color_diff, int threshold, int prog_equal, int prog_diff, int prog_threshold ); +// JJJ: title->job? int hb_save_preview( hb_handle_t * h, int title, int preview, hb_buffer_t *buf ); hb_buffer_t * hb_read_preview( hb_handle_t * h, int title_idx, int preview ); -void hb_get_preview_by_index( hb_handle_t *, int, int, uint8_t * ); -void hb_get_preview( hb_handle_t *, hb_title_t *, int, +void hb_get_preview( hb_handle_t *, hb_job_t *, int, uint8_t * ); void hb_set_size( hb_job_t *, double ratio, int pixels ); -void hb_set_anamorphic_size_by_index( hb_handle_t *, int, - int *output_width, int *output_height, - int *output_par_width, int *output_par_height ); void hb_set_anamorphic_size( hb_job_t *, int *output_width, int *output_height, int *output_par_width, int *output_par_height ); @@ -83,7 +85,11 @@ void hb_set_chapter_name( hb_handle_t *, int, int, const char * ); void hb_set_job( hb_handle_t *, int, hb_job_t * ); void hb_add( hb_handle_t *, hb_job_t * ); void hb_rem( hb_handle_t *, hb_job_t * ); -void hb_reset_job( hb_job_t * job ); + +hb_job_t * hb_job_init_by_index( hb_handle_t *h, int title_index ); +hb_job_t * hb_job_init( hb_title_t * title ); +void hb_job_reset( hb_job_t * job ); +void hb_job_close( hb_job_t ** job ); void hb_start( hb_handle_t * ); void hb_pause( hb_handle_t * ); diff --git a/libhb/internal.h b/libhb/internal.h index caa2e7189..1c02ffe85 100644 --- a/libhb/internal.h +++ b/libhb/internal.h @@ -228,7 +228,7 @@ static inline hb_buffer_t * hb_video_buffer_init( int width, int height ) hb_thread_t * hb_update_init( int * build, char * version ); hb_thread_t * hb_scan_init( hb_handle_t *, volatile int * die, const char * path, int title_index, - hb_list_t * list_title, int preview_count, + hb_title_set_t * title_set, int preview_count, int store_previews, uint64_t min_duration ); hb_thread_t * hb_work_init( hb_list_t * jobs, volatile int * die, int * error, hb_job_t ** job ); @@ -266,7 +266,7 @@ extern const hb_muxer_t hb_demux[]; /*********************************************************************** * decmetadata.c **********************************************************************/ -extern void decmetadata( hb_title_t *title ); +extern int decmetadata( hb_title_t *title ); /*********************************************************************** * batch.c diff --git a/libhb/muxcommon.c b/libhb/muxcommon.c index 6587a4dac..d5d9c7a92 100644 --- a/libhb/muxcommon.c +++ b/libhb/muxcommon.c @@ -441,7 +441,6 @@ static void mux_loop( void * _w ) hb_work_object_t * hb_muxer_init( hb_job_t * job ) { - hb_title_t * title = job->title; int i; hb_mux_t * mux = calloc( sizeof( hb_mux_t ), 1 ); hb_work_object_t * w; @@ -490,9 +489,9 @@ hb_work_object_t * hb_muxer_init( hb_job_t * job ) add_mux_track( mux, job->mux_data, 1 ); muxer->done = &muxer->private_data->mux->done; - for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = 0; i < hb_list_count( job->list_audio ); i++ ) { - hb_audio_t *audio = hb_list_item( title->list_audio, i ); + hb_audio_t *audio = hb_list_item( job->list_audio, i ); w = hb_get_work( WORK_MUX ); w->private_data = calloc( sizeof( hb_work_private_t ), 1 ); @@ -507,9 +506,9 @@ hb_work_object_t * hb_muxer_init( hb_job_t * job ) w->thread = hb_thread_init( w->name, mux_loop, w, HB_NORMAL_PRIORITY ); } - for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) { - hb_subtitle_t *subtitle = hb_list_item( title->list_subtitle, i ); + hb_subtitle_t *subtitle = hb_list_item( job->list_subtitle, i ); if (subtitle->config.dest != PASSTHRUSUB) continue; diff --git a/libhb/muxmkv.c b/libhb/muxmkv.c index addd800de..2b629bc49 100644 --- a/libhb/muxmkv.c +++ b/libhb/muxmkv.c @@ -59,7 +59,6 @@ static uint8_t * create_flac_header( uint8_t *data, int size ) static int MKVInit( hb_mux_object_t * m ) { hb_job_t * job = m->job; - hb_title_t * title = job->title; hb_audio_t * audio; hb_mux_data_t * mux_data; @@ -197,9 +196,9 @@ static int MKVInit( hb_mux_object_t * m ) mux_data->track = mk_createTrack(m->file, track); /* add the audio tracks */ - for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = 0; i < hb_list_count( job->list_audio ); i++ ) { - audio = hb_list_item( title->list_audio, i ); + audio = hb_list_item( job->list_audio, i ); mux_data = calloc(1, sizeof( hb_mux_data_t ) ); audio->priv.mux_data = mux_data; @@ -328,14 +327,14 @@ static int MKVInit( hb_mux_object_t * m ) "custom colors: OFF, tridx: 0000, " "colors: 000000, 000000, 000000, 000000\n"; - for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) { hb_subtitle_t * subtitle; uint32_t rgb[16]; char subidx[2048]; int len; - subtitle = hb_list_item( title->list_subtitle, i ); + subtitle = hb_list_item( job->list_subtitle, i ); if (subtitle->config.dest != PASSTHRUSUB) continue; @@ -400,7 +399,7 @@ static int MKVInit( hb_mux_object_t * m ) if (need_fonts) { - hb_list_t * list_attachment = job->title->list_attachment; + hb_list_t * list_attachment = job->list_attachment; int i; for ( i = 0; i < hb_list_count(list_attachment); i++ ) { @@ -437,7 +436,6 @@ static int MKVMux( hb_mux_object_t * m, hb_mux_data_t * mux_data, { ogg_packet *op = NULL; hb_job_t * job = m->job; - hb_title_t * title = job->title; uint64_t timecode = 0; hb_chapter_t *chapter_data; char tmp_buffer[1024]; @@ -457,7 +455,7 @@ static int MKVMux( hb_mux_object_t * m, hb_mux_data_t * mux_data, { mux_data->current_chapter = buf->s.new_chap - 2; } - chapter_data = hb_list_item( title->list_chapter, + chapter_data = hb_list_item( job->list_chapter, mux_data->current_chapter++ ); tmp_buffer[0] = '\0'; @@ -556,7 +554,6 @@ static int MKVEnd( hb_mux_object_t * m ) { hb_job_t *job = m->job; hb_mux_data_t *mux_data = job->mux_data; - hb_title_t *title = job->title; hb_chapter_t *chapter_data; char tmp_buffer[1024]; char *string = tmp_buffer; @@ -569,7 +566,7 @@ static int MKVEnd( hb_mux_object_t * m ) return 0; } - chapter_data = hb_list_item( title->list_chapter, mux_data->current_chapter++ ); + chapter_data = hb_list_item( job->list_chapter, mux_data->current_chapter++ ); if(job->chapter_markers) { @@ -588,29 +585,62 @@ static int MKVEnd( hb_mux_object_t * m ) mk_createChapterSimple(m->file, mux_data->prev_chapter_tc, mux_data->prev_chapter_tc, string); } - if( title->metadata ) + if( job->metadata ) { - hb_metadata_t *md = title->metadata; + hb_metadata_t *md = job->metadata; hb_deep_log( 2, "Writing Metadata to output file..."); - mk_createTagSimple( m->file, MK_TAG_TITLE, md->name ); - mk_createTagSimple( m->file, "ARTIST", md->artist ); - mk_createTagSimple( m->file, "COMPOSER", md->composer ); - mk_createTagSimple( m->file, MK_TAG_SYNOPSIS, md->comment ); - mk_createTagSimple( m->file, "DATE_RELEASED", md->release_date ); - // mk_createTagSimple( m->file, "", md->album ); - mk_createTagSimple( m->file, MK_TAG_GENRE, md->genre ); + if ( md->name ) + { + mk_createTagSimple( m->file, MK_TAG_TITLE, md->name ); + } + if ( md->artist ) + { + mk_createTagSimple( m->file, "ARTIST", md->artist ); + } + if ( md->album_artist ) + { + mk_createTagSimple( m->file, "DIRECTOR", md->album_artist ); + } + if ( md->composer ) + { + mk_createTagSimple( m->file, "COMPOSER", md->composer ); + } + if ( md->release_date ) + { + mk_createTagSimple( m->file, "DATE_RELEASED", md->release_date ); + } + if ( md->comment ) + { + mk_createTagSimple( m->file, "SUMMARY", md->comment ); + } + if ( !md->name && md->album ) + { + mk_createTagSimple( m->file, MK_TAG_TITLE, md->album ); + } + if ( md->genre ) + { + mk_createTagSimple( m->file, MK_TAG_GENRE, md->genre ); + } + if ( md->description ) + { + mk_createTagSimple( m->file, "DESCRIPTION", md->description ); + } + if ( md->long_description ) + { + mk_createTagSimple( m->file, "SYNOPSIS", md->long_description ); + } } // Update and track private data that can change during // encode. int i; - for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = 0; i < hb_list_count( job->list_audio ); i++ ) { mk_Track * track; hb_audio_t * audio; - audio = hb_list_item( title->list_audio, i ); + audio = hb_list_item( job->list_audio, i ); track = audio->priv.mux_data->track; switch (audio->config.out.codec & HB_ACODEC_MASK) diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c index d21e4b767..f1380dc18 100644 --- a/libhb/muxmp4.c +++ b/libhb/muxmp4.c @@ -262,9 +262,9 @@ static int MP4Init( hb_mux_object_t * m ) } /* add the audio tracks */ - for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = 0; i < hb_list_count( job->list_audio ); i++ ) { - audio = hb_list_item( title->list_audio, i ); + audio = hb_list_item( job->list_audio, i ); mux_data = calloc(1, sizeof( hb_mux_data_t ) ); audio->priv.mux_data = mux_data; @@ -464,7 +464,7 @@ static int MP4Init( hb_mux_object_t * m ) /* Set the language for this track */ MP4SetTrackLanguage(m->file, mux_data->track, audio->config.lang.iso639_2); - if( hb_list_count( title->list_audio ) > 1 ) + if( hb_list_count( job->list_audio ) > 1 ) { /* Set the audio track alternate group */ MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 1); @@ -944,7 +944,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, duration = m->sum_dur - m->chapter_duration + offset; if ( duration >= (90000*3)/2 ) { - chapter = hb_list_item( m->job->title->list_chapter, + chapter = hb_list_item( m->job->list_chapter, buf->s.new_chap - 2 ); MP4AddChapter( m->file, @@ -1248,7 +1248,6 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, static int MP4End( hb_mux_object_t * m ) { hb_job_t * job = m->job; - hb_title_t * title = job->title; // Flush the delayed frame if ( m->delay_buf ) @@ -1264,7 +1263,7 @@ static int MP4End( hb_mux_object_t * m ) if ( duration >= (90000*3)/2 ) { - chapter = hb_list_item( m->job->title->list_chapter, + chapter = hb_list_item( m->job->list_chapter, m->current_chapter - 1 ); MP4AddChapter( m->file, @@ -1293,9 +1292,9 @@ static int MP4End( hb_mux_object_t * m ) /* * Write the MP4 iTunes metadata if we have any metadata */ - if( title->metadata ) + if( job->metadata ) { - hb_metadata_t *md = title->metadata; + hb_metadata_t *md = job->metadata; const MP4Tags* tags; hb_deep_log( 2, "Writing Metadata to output file..."); @@ -1306,28 +1305,60 @@ static int MP4End( hb_mux_object_t * m ) MP4TagsFetch( tags, m->file ); /* populate */ - if( strlen( md->name )) + if( md->name ) MP4TagsSetName( tags, md->name ); - if( strlen( md->artist )) + if( md->artist ) MP4TagsSetArtist( tags, md->artist ); - if( strlen( md->composer )) + if( md->composer ) MP4TagsSetComposer( tags, md->composer ); - if( strlen( md->comment )) + if( md->comment ) MP4TagsSetComments( tags, md->comment ); - if( strlen( md->release_date )) + if( md->release_date ) MP4TagsSetReleaseDate( tags, md->release_date ); - if( strlen( md->album )) + if( md->album ) MP4TagsSetAlbum( tags, md->album ); - if( strlen( md->genre )) + if( md->album_artist ) + MP4TagsSetAlbumArtist( tags, md->album_artist ); + if( md->genre ) MP4TagsSetGenre( tags, md->genre ); + if( md->description ) + MP4TagsSetDescription( tags, md->description ); + if( md->long_description ) + MP4TagsSetLongDescription( tags, md->long_description ); - if( md->coverart ) + if( md->list_coverart ) { - MP4TagArtwork art; - art.data = md->coverart; - art.size = md->coverart_size; - art.type = MP4_ART_UNDEFINED; // delegate typing to libmp4v2 - MP4TagsAddArtwork( tags, &art ); + hb_coverart_t * coverart; + int ii; + + for ( ii = 0; ii < hb_list_count( md->list_coverart ); ii++ ) + { + coverart = hb_list_item( md->list_coverart, ii ); + MP4TagArtwork art; + int type; + switch ( coverart->type ) + { + case HB_ART_BMP: + type = MP4_ART_BMP; + break; + case HB_ART_GIF: + type = MP4_ART_GIF; + break; + case HB_ART_JPEG: + type = MP4_ART_JPEG; + break; + case HB_ART_PNG: + type = MP4_ART_PNG; + break; + default: + type = MP4_ART_UNDEFINED; + break; + } + art.data = coverart->data; + art.size = coverart->size; + art.type = type; + MP4TagsAddArtwork( tags, &art ); + } } /* push data to MP4 file */ diff --git a/libhb/reader.c b/libhb/reader.c index 8148e6590..d5c937422 100644 --- a/libhb/reader.c +++ b/libhb/reader.c @@ -386,12 +386,12 @@ void ReadLoop( void * _w ) * a media chapter that got merged, we'll stop ripping too early. */ int start = r->job->chapter_start; - hb_chapter_t *chap = hb_list_item( r->title->list_chapter, chapter_end - 1 ); + hb_chapter_t *chap = hb_list_item( r->job->list_chapter, chapter_end - 1 ); chapter_end = chap->index; if (start > 1) { - chap = hb_list_item( r->title->list_chapter, start - 1 ); + chap = hb_list_item( r->job->list_chapter, start - 1 ); start = chap->index; } /* end chapter mapping XXX */ @@ -453,12 +453,12 @@ void ReadLoop( void * _w ) * end chapter so that we end at the right time. */ int start = r->job->chapter_start; - hb_chapter_t *chap = hb_list_item( r->title->list_chapter, chapter_end - 1 ); + hb_chapter_t *chap = hb_list_item( r->job->list_chapter, chapter_end - 1 ); chapter_end = chap->index; if (start > 1) { - chap = hb_list_item( r->title->list_chapter, start - 1 ); + chap = hb_list_item( r->job->list_chapter, start - 1 ); start = chap->index; } @@ -670,14 +670,14 @@ void ReadLoop( void * _w ) push_buf( r, r->job->fifo_mpeg2, hb_buffer_init(0) ); hb_audio_t *audio; - for( n = 0; (audio = hb_list_item( r->job->title->list_audio, n)); ++n ) + for( n = 0; (audio = hb_list_item( r->job->list_audio, n)); ++n ) { if ( audio->priv.fifo_in ) push_buf( r, audio->priv.fifo_in, hb_buffer_init(0) ); } hb_subtitle_t *subtitle; - for( n = 0; (subtitle = hb_list_item( r->job->title->list_subtitle, n)); ++n ) + for( n = 0; (subtitle = hb_list_item( r->job->list_subtitle, n)); ++n ) { if ( subtitle->fifo_in && subtitle->source == VOBSUB) push_buf( r, subtitle->fifo_in, hb_buffer_init(0) ); @@ -780,11 +780,11 @@ static hb_fifo_t ** GetFifoForId( hb_work_private_t * r, int id ) } } - count = hb_list_count( title->list_subtitle ); + count = hb_list_count( job->list_subtitle ); count = count > 99 ? 99 : count; for( i = n = 0; i < count; i++ ) { - subtitle = hb_list_item( title->list_subtitle, i ); + subtitle = hb_list_item( job->list_subtitle, i ); if (id == subtitle->id) { /* pass the subtitles to be processed */ @@ -798,9 +798,9 @@ static hb_fifo_t ** GetFifoForId( hb_work_private_t * r, int id ) if( !job->indepth_scan ) { - for( i = n = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = n = 0; i < hb_list_count( job->list_audio ); i++ ) { - audio = hb_list_item( title->list_audio, i ); + audio = hb_list_item( job->list_audio, i ); if( id == audio->id ) { r->fifos[n++] = audio->priv.fifo_in; diff --git a/libhb/rendersub.c b/libhb/rendersub.c index 568b7d1b0..c9e9f02cf 100644 --- a/libhb/rendersub.c +++ b/libhb/rendersub.c @@ -441,7 +441,7 @@ static int ssa_init( hb_filter_object_t * filter, ass_set_message_cb( pv->ssa, ssa_log, NULL ); // Load embedded fonts - hb_list_t * list_attachment = init->job->title->list_attachment; + hb_list_t * list_attachment = init->job->list_attachment; int i; for ( i = 0; i < hb_list_count(list_attachment); i++ ) { @@ -678,9 +678,9 @@ static int hb_rendersub_init( hb_filter_object_t * filter, } // Find the subtitle we need - for( ii = 0; ii < hb_list_count(init->job->title->list_subtitle); ii++ ) + for( ii = 0; ii < hb_list_count(init->job->list_subtitle); ii++ ) { - subtitle = hb_list_item( init->job->title->list_subtitle, ii ); + subtitle = hb_list_item( init->job->list_subtitle, ii ); if( subtitle && subtitle->config.dest == RENDERSUB ) { // Found it diff --git a/libhb/scan.c b/libhb/scan.c index 10ed35391..0163af406 100644 --- a/libhb/scan.c +++ b/libhb/scan.c @@ -18,7 +18,7 @@ typedef struct char * path; int title_index; - hb_list_t * list_title; + hb_title_set_t * title_set; hb_bd_t * bd; hb_dvd_t * dvd; @@ -51,7 +51,7 @@ static const char *aspect_to_string( double aspect ) hb_thread_t * hb_scan_init( hb_handle_t * handle, volatile int * die, const char * path, int title_index, - hb_list_t * list_title, int preview_count, + hb_title_set_t * title_set, int preview_count, int store_previews, uint64_t min_duration ) { hb_scan_t * data = calloc( sizeof( hb_scan_t ), 1 ); @@ -60,7 +60,7 @@ hb_thread_t * hb_scan_init( hb_handle_t * handle, volatile int * die, data->die = die; data->path = strdup( path ); data->title_index = title_index; - data->list_title = list_title; + data->title_set = title_set; data->preview_count = preview_count; data->store_previews = store_previews; @@ -88,7 +88,8 @@ static void ScanFunc( void * _data ) if( data->title_index ) { /* Scan this title only */ - hb_list_add( data->list_title, hb_bd_title_scan( data->bd, + hb_list_add( data->title_set->list_title, + hb_bd_title_scan( data->bd, data->title_index, 0 ) ); } else @@ -96,10 +97,12 @@ static void ScanFunc( void * _data ) /* Scan all titles */ for( i = 0; i < hb_bd_title_count( data->bd ); i++ ) { - hb_list_add( data->list_title, hb_bd_title_scan( data->bd, + hb_list_add( data->title_set->list_title, + hb_bd_title_scan( data->bd, i + 1, data->min_title_duration ) ); } - feature = hb_bd_main_feature( data->bd, data->list_title ); + feature = hb_bd_main_feature( data->bd, + data->title_set->list_title ); } } else if( ( data->dvd = hb_dvd_init( data->path ) ) ) @@ -109,7 +112,8 @@ static void ScanFunc( void * _data ) if( data->title_index ) { /* Scan this title only */ - hb_list_add( data->list_title, hb_dvd_title_scan( data->dvd, + hb_list_add( data->title_set->list_title, + hb_dvd_title_scan( data->dvd, data->title_index, 0 ) ); } else @@ -117,10 +121,12 @@ static void ScanFunc( void * _data ) /* Scan all titles */ for( i = 0; i < hb_dvd_title_count( data->dvd ); i++ ) { - hb_list_add( data->list_title, hb_dvd_title_scan( data->dvd, + hb_list_add( data->title_set->list_title, + hb_dvd_title_scan( data->dvd, i + 1, data->min_title_duration ) ); } - feature = hb_dvd_main_feature( data->dvd, data->list_title ); + feature = hb_dvd_main_feature( data->dvd, + data->title_set->list_title ); } } else if ( ( data->batch = hb_batch_init( data->path ) ) ) @@ -131,7 +137,7 @@ static void ScanFunc( void * _data ) title = hb_batch_title_scan( data->batch, data->title_index ); if ( title ) { - hb_list_add( data->list_title, title ); + hb_list_add( data->title_set->list_title, title ); } } else @@ -144,7 +150,7 @@ static void ScanFunc( void * _data ) title = hb_batch_title_scan( data->batch, i + 1 ); if ( title != NULL ) { - hb_list_add( data->list_title, title ); + hb_list_add( data->title_set->list_title, title ); } } } @@ -156,7 +162,7 @@ static void ScanFunc( void * _data ) { title = hb_stream_title_scan( data->stream, title ); if ( title ) - hb_list_add( data->list_title, title ); + hb_list_add( data->title_set->list_title, title ); } else { @@ -166,7 +172,7 @@ static void ScanFunc( void * _data ) } } - for( i = 0; i < hb_list_count( data->list_title ); ) + for( i = 0; i < hb_list_count( data->title_set->list_title ); ) { int j; hb_state_t state; @@ -176,7 +182,7 @@ static void ScanFunc( void * _data ) { goto finish; } - title = hb_list_item( data->list_title, i ); + title = hb_list_item( data->title_set->list_title, i ); #define p state.param.scanning /* Update the UI */ @@ -185,7 +191,7 @@ static void ScanFunc( void * _data ) p.title_count = data->dvd ? hb_dvd_title_count( data->dvd ) : data->bd ? hb_bd_title_count( data->bd ) : data->batch ? hb_batch_title_count( data->batch ) : - hb_list_count(data->list_title); + hb_list_count(data->title_set->list_title); hb_set_state( data->h, &state ); #undef p @@ -194,7 +200,7 @@ static void ScanFunc( void * _data ) if( !DecodePreviews( data, title ) ) { /* TODO: free things */ - hb_list_rem( data->list_title, title ); + hb_list_rem( data->title_set->list_title, title ); for( j = 0; j < hb_list_count( title->list_audio ); j++) { audio = hb_list_item( title->list_audio, j ); @@ -247,64 +253,16 @@ static void ScanFunc( void * _data ) i++; } - /* Init jobs templates */ - for( i = 0; i < hb_list_count( data->list_title ); i++ ) - { - hb_job_t * job; - - title = hb_list_item( data->list_title, i ); - job = calloc( sizeof( hb_job_t ), 1 ); - title->job = job; - - job->title = title; - job->feature = feature; + data->title_set->feature = feature; - /* Set defaults settings */ - job->chapter_start = 1; - job->chapter_end = hb_list_count( title->list_chapter ); - - /* Autocrop by default. Gnark gnark */ - memcpy( job->crop, title->crop, 4 * sizeof( int ) ); - - /* Preserve a source's pixel aspect, if it's available. */ - if( title->pixel_aspect_width && title->pixel_aspect_height ) - { - job->anamorphic.par_width = title->pixel_aspect_width; - job->anamorphic.par_height = title->pixel_aspect_height; - } - - if( title->aspect != 0 && title->aspect != 1. && - !job->anamorphic.par_width && !job->anamorphic.par_height) - { - hb_reduce( &job->anamorphic.par_width, &job->anamorphic.par_height, - (int)(title->aspect * title->height + 0.5), title->width ); - } - - job->width = title->width - job->crop[2] - job->crop[3]; - hb_fix_aspect( job, HB_KEEP_WIDTH ); - if( job->height > title->height - job->crop[0] - job->crop[1] ) - { - job->height = title->height - job->crop[0] - job->crop[1]; - hb_fix_aspect( job, HB_KEEP_HEIGHT ); - } - - hb_log( "scan: title (%d) job->width:%d, job->height:%d", - i, job->width, job->height ); - - job->keep_ratio = 1; - - job->vcodec = HB_VCODEC_FFMPEG_MPEG4; - job->vquality = -1.0; - job->vbitrate = 1000; - job->pass = 0; - job->vrate = title->rate; - job->vrate_base = title->rate_base; - - job->list_audio = hb_list_init(); - job->list_subtitle = hb_list_init(); - job->list_filter = hb_list_init(); - - job->mux = HB_MUX_MP4; + /* Mark title scan complete and init jobs */ + for( i = 0; i < hb_list_count( data->title_set->list_title ); i++ ) + { + title = hb_list_item( data->title_set->list_title, i ); + title->flags |= HBTF_SCAN_COMPLETE; +#if defined(HB_TITLE_JOBS) + title->job = hb_job_init( title ); +#endif } finish: diff --git a/libhb/stream.c b/libhb/stream.c index ede9f33d3..503e296dc 100644 --- a/libhb/stream.c +++ b/libhb/stream.c @@ -960,11 +960,10 @@ hb_stream_t * hb_bd_stream_open( hb_title_t *title ) update_ts_streams( d, pid, 0, stream_type, S, NULL ); } - // When scanning, title->job == NULL. We don't need to wait for - // a PCR when scanning. In fact, it trips us up on the first - // preview of every title since we would have to read quite a - // lot of data before finding the PCR. - if ( title->job ) + // We don't need to wait for a PCR when scanning. In fact, it + // trips us up on the first preview of every title since we would + // have to read quite a lot of data before finding the PCR. + if ( !(title->flags & HBTF_SCAN_COMPLETE) ) { /* BD has PCRs, but the BD index always points to a packet * after a PCR packet, so we will not see the initial PCR @@ -2774,7 +2773,6 @@ int decode_program_map(hb_stream_t* stream) stream->pmt_info.PCR_PID = bits_get(&bb, 13); bits_get(&bb, 4); int program_info_length = bits_get(&bb, 12); - int i; for (i = 0; i < program_info_length - 2; ) { @@ -5371,6 +5369,7 @@ static void add_ffmpeg_subtitle( hb_title_t *title, hb_stream_t *stream, int id static char *get_ffmpeg_metadata_value( AVDictionary *m, char *key ) { AVDictionaryEntry *tag = NULL; + while ( (tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX)) ) { if ( !strcmp( key, tag->key ) ) @@ -5425,6 +5424,64 @@ static void add_ffmpeg_attachment( hb_title_t *title, hb_stream_t *stream, int i hb_list_add(title->list_attachment, attachment); } +static int ffmpeg_decmetadata( AVDictionary *m, hb_title_t *title ) +{ + int result = 0; + AVDictionaryEntry *tag = NULL; + while ( (tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX)) ) + { + if ( !strcasecmp( "TITLE", tag->key ) ) + { + hb_metadata_set_name(title->metadata, tag->value); + result = 1; + } + else if ( !strcasecmp( "ARTIST", tag->key ) ) + { + hb_metadata_set_artist(title->metadata, tag->value); + result = 1; + } + else if ( !strcasecmp( "DIRECTOR", tag->key ) || + !strcasecmp( "album_artist", tag->key ) ) + { + hb_metadata_set_album_artist(title->metadata, tag->value); + result = 1; + } + else if ( !strcasecmp( "COMPOSER", tag->key ) ) + { + hb_metadata_set_composer(title->metadata, tag->value); + result = 1; + } + else if ( !strcasecmp( "DATE_RELEASED", tag->key ) || + !strcasecmp( "date", tag->key ) ) + { + hb_metadata_set_release_date(title->metadata, tag->value); + result = 1; + } + else if ( !strcasecmp( "SUMMARY", tag->key ) || + !strcasecmp( "comment", tag->key ) ) + { + hb_metadata_set_comment(title->metadata, tag->value); + result = 1; + } + else if ( !strcasecmp( "GENRE", tag->key ) ) + { + hb_metadata_set_genre(title->metadata, tag->value); + result = 1; + } + else if ( !strcasecmp( "DESCRIPTION", tag->key ) ) + { + hb_metadata_set_description(title->metadata, tag->value); + result = 1; + } + else if ( !strcasecmp( "SYNOPSIS", tag->key ) ) + { + hb_metadata_set_long_description(title->metadata, tag->value); + result = 1; + } + } + return result; +} + static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream, hb_title_t *title ) { AVFormatContext *ic = stream->ffmpeg_ic; @@ -5520,16 +5577,20 @@ static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream, hb_title_t *title ) chapter->seconds = ( seconds % 60 ); tag = av_dict_get( m->metadata, "title", NULL, 0 ); - /* Ignore generic chapter names set by MakeMKV ("Chapter 00" etc.). + /* Ignore generic chapter names set by MakeMKV + * ("Chapter 00" etc.). * Our default chapter names are better. */ if( tag && tag->value && - ( strncmp( "Chapter ", tag->value, 8 ) || strlen( tag->value ) > 11 ) ) + ( strncmp( "Chapter ", tag->value, 8 ) || + strlen( tag->value ) > 11 ) ) { - strcpy( chapter->title, tag->value ); + hb_chapter_set_title( chapter, tag->value ); } else { - sprintf( chapter->title, "Chapter %d", chapter->index ); + char chapter_title[80]; + sprintf( chapter_title, "Chapter %d", chapter->index ); + hb_chapter_set_title( chapter, chapter_title ); } hb_deep_log( 2, "Added chapter %i, name='%s', dur=%"PRIu64", (%02i:%02i:%02i)", @@ -5543,7 +5604,11 @@ static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream, hb_title_t *title ) /* * Fill the metadata. */ - decmetadata( title ); + // JJJ: is this necessary? can we just get this metadata from libav api's? + if (!decmetadata( title )) + { + ffmpeg_decmetadata( ic->metadata, title ); + } if( hb_list_count( title->list_chapter ) == 0 ) { @@ -5787,16 +5852,25 @@ hb_buffer_t * hb_ffmpeg_read( hb_stream_t *stream ) static int ffmpeg_seek( hb_stream_t *stream, float frac ) { AVFormatContext *ic = stream->ffmpeg_ic; + int res; if ( frac > 0. ) { int64_t pos = (double)stream->ffmpeg_ic->duration * (double)frac + ffmpeg_initial_timestamp( stream ); - avformat_seek_file( ic, -1, 0, pos, pos, AVSEEK_FLAG_BACKWARD); + res = avformat_seek_file( ic, -1, 0, pos, pos, AVSEEK_FLAG_BACKWARD); + if (res < 0) + { + hb_error("avformat_seek_file failed"); + } } else { int64_t pos = ffmpeg_initial_timestamp( stream ); - avformat_seek_file( ic, -1, 0, pos, pos, AVSEEK_FLAG_BACKWARD); + res = avformat_seek_file( ic, -1, 0, pos, pos, AVSEEK_FLAG_BACKWARD); + if (res < 0) + { + hb_error("avformat_seek_file failed"); + } } stream->need_keyframe = 1; return 1; diff --git a/libhb/sync.c b/libhb/sync.c index c3e4c37a1..f416d1664 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -167,7 +167,7 @@ hb_work_object_t * hb_sync_init( hb_job_t * job ) duration = 0; for( i = job->chapter_start; i <= job->chapter_end; i++ ) { - chapter = hb_list_item( title->list_chapter, i - 1 ); + chapter = hb_list_item( job->list_chapter, i - 1 ); duration += chapter->duration; } } @@ -179,7 +179,7 @@ hb_work_object_t * hb_sync_init( hb_job_t * job ) /* Initialize libsamplerate for every audio track we have */ if ( ! job->indepth_scan ) { - for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = 0; i < hb_list_count( job->list_audio ); i++ ) { InitAudio( job, pv->common, i ); } @@ -892,7 +892,6 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ) { hb_work_object_t * w; hb_work_private_t * pv; - hb_title_t * title = job->title; hb_sync_audio_t * sync; pv = calloc( 1, sizeof( hb_work_private_t ) ); @@ -905,7 +904,7 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ) w = hb_get_work( WORK_SYNC_AUDIO ); w->private_data = pv; - w->audio = hb_list_item( title->list_audio, i ); + w->audio = hb_list_item( job->list_audio, i ); w->fifo_in = w->audio->priv.fifo_raw; if ( w->audio->config.out.codec & HB_ACODEC_PASS_FLAG ) diff --git a/libhb/work.c b/libhb/work.c index 277ebf033..030920c59 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -389,9 +389,9 @@ void hb_display_job_info( hb_job_t * job ) job->select_subtitle_config.default_track ? ", Default" : "" ); } - for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) { - subtitle = hb_list_item( title->list_subtitle, i ); + subtitle = hb_list_item( job->list_subtitle, i ); if( subtitle ) { @@ -425,9 +425,9 @@ void hb_display_job_info( hb_job_t * job ) if( !job->indepth_scan ) { - for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = 0; i < hb_list_count( job->list_audio ); i++ ) { - audio = hb_list_item( title->list_audio, i ); + audio = hb_list_item( job->list_audio, i ); hb_log( " * audio track %d", audio->config.out.track ); @@ -529,6 +529,7 @@ static void do_job( hb_job_t * job ) hb_work_object_t * w; hb_work_object_t * sync; hb_work_object_t * muxer; + hb_work_object_t *reader = hb_get_work(WORK_READER); hb_interjob_t * interjob; hb_audio_t * audio; @@ -563,21 +564,25 @@ static void do_job( hb_job_t * job ) { interjob->select_subtitle->config.force = 0; } - for( i = 0; i < hb_list_count(title->list_subtitle); ) + for( i = 0; i < hb_list_count( job->list_subtitle ); ) { - if( ( subtitle = hb_list_item( title->list_subtitle, i ) ) ) + subtitle = hb_list_item( job->list_subtitle, i ); + if( subtitle ) { - /* Remove the scanned subtitle from the list if it would result in: + /* Remove the scanned subtitle from the list if + * it would result in: * - an emty track (forced and no forced hits) * - an identical, duplicate subtitle track: * -> both (or neither) are forced * -> subtitle is not forced but all its hits are forced */ if( ( interjob->select_subtitle->id == subtitle->id ) && - ( ( subtitle->config.force && interjob->select_subtitle->forced_hits == 0 ) || + ( ( subtitle->config.force && + interjob->select_subtitle->forced_hits == 0 ) || ( subtitle->config.force == interjob->select_subtitle->config.force ) || - ( subtitle->config.force == 0 && interjob->select_subtitle->hits == interjob->select_subtitle->forced_hits ) ) ) + ( !subtitle->config.force && + interjob->select_subtitle->hits == interjob->select_subtitle->forced_hits ) ) ) { - hb_list_rem( title->list_subtitle, subtitle ); + hb_list_rem( job->list_subtitle, subtitle ); free( subtitle ); continue; } @@ -602,13 +607,13 @@ static void do_job( hb_job_t * job ) if (job->pass == 0 || job->pass == 2) { // final pass, interjob->select_subtitle is no longer needed - hb_list_insert(title->list_subtitle, 0, interjob->select_subtitle); + hb_list_insert(job->list_subtitle, 0, interjob->select_subtitle); interjob->select_subtitle = NULL; } else { // this is not the final pass, so we need to copy it instead - hb_list_insert(title->list_subtitle, 0, hb_subtitle_copy(interjob->select_subtitle)); + hb_list_insert(job->list_subtitle, 0, hb_subtitle_copy(interjob->select_subtitle)); } } @@ -616,10 +621,9 @@ static void do_job( hb_job_t * job ) { // Sanitize subtitles uint8_t one_burned = 0; - for( i = 0; i < hb_list_count( title->list_subtitle ); ) + for( i = 0; i < hb_list_count( job->list_subtitle ); ) { - subtitle = hb_list_item( title->list_subtitle, i ); - + subtitle = hb_list_item( job->list_subtitle, i ); if ( subtitle->config.dest == RENDERSUB ) { if ( one_burned ) @@ -627,7 +631,7 @@ static void do_job( hb_job_t * job ) if ( !hb_subtitle_can_pass(subtitle->source, job->mux) ) { hb_log( "More than one subtitle burn-in requested, dropping track %d.", i ); - hb_list_rem( title->list_subtitle, subtitle ); + hb_list_rem( job->list_subtitle, subtitle ); free( subtitle ); continue; } @@ -661,7 +665,7 @@ static void do_job( hb_job_t * job ) else { hb_log( "Subtitle pass-thru requested and input track is not compatible with container. One track already burned, dropping track %d.", i ); - hb_list_rem( title->list_subtitle, subtitle ); + hb_list_rem( job->list_subtitle, subtitle ); free( subtitle ); continue; } @@ -697,9 +701,9 @@ static void do_job( hb_job_t * job ) init.height = title->height; init.par_width = job->anamorphic.par_width; init.par_height = job->anamorphic.par_height; - memcpy(init.crop, title->crop, sizeof(int[4])); - init.vrate_base = title->rate_base; - init.vrate = title->rate; + memcpy(init.crop, job->crop, sizeof(int[4])); + init.vrate_base = job->vrate_base; + init.vrate = job->vrate; init.pfr_vrate_base = job->pfr_vrate_base; init.pfr_vrate = job->pfr_vrate; init.cfr = 0; @@ -720,7 +724,7 @@ static void do_job( hb_job_t * job ) job->height = init.height; job->anamorphic.par_width = init.par_width; job->anamorphic.par_height = init.par_height; - memcpy(title->crop, init.crop, sizeof(int[4])); + memcpy(job->crop, init.crop, sizeof(int[4])); job->vrate_base = init.vrate_base; job->vrate = init.vrate; job->pfr_vrate_base = init.pfr_vrate_base; @@ -761,18 +765,18 @@ static void do_job( hb_job_t * job ) if (!job->indepth_scan) { // apply Auto Passthru settings - hb_autopassthru_apply_settings(job, title); + hb_autopassthru_apply_settings(job); // sanitize audio settings - for (i = 0; i < hb_list_count(title->list_audio);) + for (i = 0; i < hb_list_count(job->list_audio);) { - audio = hb_list_item(title->list_audio, i); + audio = hb_list_item(job->list_audio, i); if (audio->config.out.codec == HB_ACODEC_AUTO_PASS) { // Auto Passthru should have been handled above // remove track to avoid a crash hb_log("Auto Passthru error, dropping track %d", audio->config.out.track); - hb_list_rem(title->list_audio, audio); + hb_list_rem(job->list_audio, audio); free(audio); continue; } @@ -782,7 +786,7 @@ static void do_job( hb_job_t * job ) { hb_log("Passthru requested and input codec is not the same as output codec for track %d, dropping track", audio->config.out.track); - hb_list_rem(title->list_audio, audio); + hb_list_rem(job->list_audio, audio); free(audio); continue; } @@ -796,9 +800,9 @@ static void do_job( hb_job_t * job ) int best_bitrate = 0; int best_samplerate = 0; - for (i = 0; i < hb_list_count(title->list_audio); i++) + for (i = 0; i < hb_list_count(job->list_audio); i++) { - audio = hb_list_item(title->list_audio, i); + audio = hb_list_item(job->list_audio, i); /* set up the audio work structures */ audio->priv.fifo_raw = hb_fifo_init(FIFO_SMALL, FIFO_SMALL_WAKE); @@ -999,9 +1003,9 @@ static void do_job( hb_job_t * job ) w->fifo_in = job->fifo_mpeg2; w->fifo_out = job->fifo_raw; - for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) { - subtitle = hb_list_item( title->list_subtitle, i ); + subtitle = hb_list_item( job->list_subtitle, i ); if( subtitle ) { @@ -1081,9 +1085,9 @@ static void do_job( hb_job_t * job ) hb_list_add( job->list_work, w ); - for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = 0; i < hb_list_count( job->list_audio ); i++ ) { - audio = hb_list_item( title->list_audio, i ); + audio = hb_list_item( job->list_audio, i ); /* * Audio Decoder Thread @@ -1140,7 +1144,6 @@ static void do_job( hb_job_t * job ) hb_display_job_info( job ); /* Init read & write threads */ - hb_work_object_t *reader = hb_get_work(WORK_READER); if ( reader->init( reader, job ) ) { hb_error( "Failure to initialise thread '%s'", reader->name ); @@ -1330,9 +1333,9 @@ cleanup: hb_fifo_close( &job->fifo_sync ); hb_fifo_close( &job->fifo_mpeg4 ); - for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) { - subtitle = hb_list_item( title->list_subtitle, i ); + subtitle = hb_list_item( job->list_subtitle, i ); if( subtitle ) { hb_fifo_close( &subtitle->fifo_in ); @@ -1341,9 +1344,9 @@ cleanup: hb_fifo_close( &subtitle->fifo_out ); } } - for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = 0; i < hb_list_count( job->list_audio ); i++ ) { - audio = hb_list_item( title->list_audio, i ); + audio = hb_list_item( job->list_audio, i ); if( audio->priv.fifo_in != NULL ) hb_fifo_close( &audio->priv.fifo_in ); if( audio->priv.fifo_raw != NULL ) @@ -1354,13 +1357,22 @@ cleanup: hb_fifo_close( &audio->priv.fifo_out ); } + if( job->list_filter ) + { + for( i = 0; i < hb_list_count( job->list_filter ); i++ ) + { + hb_filter_object_t * filter = hb_list_item( job->list_filter, i ); + hb_fifo_close( &filter->fifo_out ); + } + } + if( job->indepth_scan ) { /* Before closing the title print out our subtitle stats if we need to * find the highest and lowest. */ - for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) { - subtitle = hb_list_item( title->list_subtitle, i ); + subtitle = hb_list_item( job->list_subtitle, i ); hb_log( "Subtitle track %d (id 0x%x) '%s': %d hits (%d forced)", subtitle->track, subtitle->id, subtitle->lang, @@ -1415,34 +1427,23 @@ cleanup: hb_log( "No candidate detected during subtitle scan" ); } - for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) { - subtitle = hb_list_item( title->list_subtitle, i ); + subtitle = hb_list_item( job->list_subtitle, i ); if( subtitle->id == subtitle_hit ) { subtitle->config = job->select_subtitle_config; - hb_list_rem( title->list_subtitle, subtitle ); + // Remove from list since we are taking ownership + // of the subtitle. + hb_list_rem( job->list_subtitle, subtitle ); interjob->select_subtitle = subtitle; break; } } } - if( job->list_filter ) - { - for( i = 0; i < hb_list_count( job->list_filter ); i++ ) - { - hb_filter_object_t * filter = hb_list_item( job->list_filter, i ); - hb_fifo_close( &filter->fifo_out ); - hb_filter_close( &filter ); - } - hb_list_close( &job->list_filter ); - } - hb_buffer_pool_free(); - - hb_title_close( &job->title ); - free( job ); + hb_job_close( &job ); } static inline void copy_chapter( hb_buffer_t * dst, hb_buffer_t * src ) diff --git a/macosx/ChapterTitles.m b/macosx/ChapterTitles.m index 893c2dc22..2fcd77272 100644 --- a/macosx/ChapterTitles.m +++ b/macosx/ChapterTitles.m @@ -29,18 +29,18 @@ if (!title) return; - int count = hb_list_count( title->list_chapter ); + hb_job_t * job = title->job; + int count = hb_list_count( job->list_chapter ); for( i = 0; i < count; i++ ) { - hb_chapter_t *chapter = hb_list_item( title->list_chapter, i ); + hb_chapter_t *chapter = hb_list_item( job->list_chapter, i ); - if( chapter != NULL && chapter->title[0] == '\0' ) + if( chapter != NULL && chapter->title == NULL ) { chapterString = [NSString stringWithFormat:@"Chapter %2d",(i+1)]; - strncpy( chapter->title, [chapterString UTF8String], 1023); - chapter->title[1023] = '\0'; + hb_chapter_set_title( chapter, [chapterString UTF8String]); } } @@ -67,12 +67,11 @@ { if( fTitle ) { - hb_chapter_t *chapter = hb_list_item( fTitle->list_chapter, rowIndex ); + hb_chapter_t *chapter = hb_list_item( fTitle->job->list_chapter, rowIndex ); if( chapter != NULL ) { - strncpy( chapter->title, [anObject UTF8String], 1023); - chapter->title[1023] = '\0'; + hb_chapter_set_title( chapter, [anObject UTF8String]); } } } @@ -92,7 +91,7 @@ { if( fTitle ) { - hb_chapter_t *chapter = hb_list_item( fTitle->list_chapter, rowIndex ); + hb_chapter_t *chapter = hb_list_item( fTitle->job->list_chapter, rowIndex ); if( chapter != NULL ) { diff --git a/macosx/Controller.m b/macosx/Controller.m index c3edceb1a..dea32a40c 100644 --- a/macosx/Controller.m +++ b/macosx/Controller.m @@ -1982,13 +1982,13 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It - (IBAction) showNewScan:(id)sender { - hb_list_t * list; + hb_title_set_t * title_set; hb_title_t * title = NULL; int feature_title=0; // Used to store the main feature title - list = hb_get_titles( fHandle ); + title_set = hb_get_title_set( fHandle ); - if( !hb_list_count( list ) ) + if( !hb_list_count( title_set->list_title ) ) { /* We display a message if a valid dvd source was not chosen */ [fSrcDVD2Field setStringValue: @"No Valid Source Found"]; @@ -2036,9 +2036,9 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [[fWindow toolbar] validateVisibleItems]; [fSrcTitlePopUp removeAllItems]; - for( int i = 0; i < hb_list_count( list ); i++ ) + for( int i = 0; i < hb_list_count( title_set->list_title ); i++ ) { - title = (hb_title_t *) hb_list_item( list, i ); + title = (hb_title_t *) hb_list_item( title_set->list_title, i ); currentSource = [NSString stringWithUTF8String: title->name]; /*Set DVD Name at top of window with the browsedSourceDisplayName grokked right before -performScan */ @@ -2081,7 +2081,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It } /* See if this is the main feature according to libhb */ - if (title->index == title->job->feature) + if (title->index == title_set->feature) { feature_title = i; } @@ -2503,10 +2503,10 @@ fWorkingCount = 0; */ int i; NSMutableArray *ChapterNamesArray = [[NSMutableArray alloc] init]; - int chaptercount = hb_list_count( fTitle->list_chapter ); + int chaptercount = hb_list_count( fTitle->job->list_chapter ); for( i = 0; i < chaptercount; i++ ) { - hb_chapter_t *chapter = (hb_chapter_t *) hb_list_item( fTitle->list_chapter, i ); + hb_chapter_t *chapter = (hb_chapter_t *) hb_list_item( fTitle->job->list_chapter, i ); if( chapter != NULL ) { [ChapterNamesArray addObject:[NSString stringWithUTF8String:chapter->title]]; @@ -2844,7 +2844,7 @@ fWorkingCount = 0; NSMutableDictionary * queueToApply = [QueueFileArray objectAtIndex:currentQueueEncodeIndex]; [self writeToActivityLog: "Preset: %s", [[queueToApply objectForKey:@"PresetName"] UTF8String]]; [self writeToActivityLog: "processNewQueueEncode number of passes expected is: %d", ([[queueToApply objectForKey:@"VideoTwoPass"] intValue] + 1)]; - job->file = [[queueToApply objectForKey:@"DestinationPath"] UTF8String]; + hb_job_set_file(job, [[queueToApply objectForKey:@"DestinationPath"] UTF8String]); [self prepareJob]; /* @@ -2852,16 +2852,14 @@ fWorkingCount = 0; */ if( job->indepth_scan == 1 ) { - char *x264opts_tmp; + NSString *advanced_opts_tmp = [NSString stringWithUTF8String: job->advanced_opts]; /* * When subtitle scan is enabled do a fast pre-scan job * which will determine which subtitles to enable, if any. */ job->pass = -1; - x264opts_tmp = job->advanced_opts; - - job->advanced_opts = NULL; + hb_job_set_advanced_opts(job, NULL); job->indepth_scan = 1; @@ -2870,7 +2868,7 @@ fWorkingCount = 0; * Add the pre-scan job */ hb_add( fQueueEncodeLibhb, job ); - job->advanced_opts = x264opts_tmp; + hb_job_set_advanced_opts(job, [advanced_opts_tmp UTF8String] ); } @@ -2900,8 +2898,10 @@ fWorkingCount = 0; [queueToApply setObject:[NSNumber numberWithInt:1] forKey:@"Status"]; [self saveQueueFileItem]; - /* we need to clean up the various lists after the job(s) have been set */ - hb_reset_job( job ); + /* libhb makes a copy of the job. So we need to free any resource + * that were allocated in construction of the job. This empties + * the audio, subtitle, and filter lists */ + hb_job_reset(job); /* We should be all setup so let 'er rip */ [self doRip]; @@ -3231,13 +3231,11 @@ fWorkingCount = 0; /* Lets use this as per Nyx, Thanks Nyx! */ /* For previews we ignore the turbo option for the first pass of two since we only use 1 pass */ job->fastfirstpass = 0; - job->advanced_opts = strdup( [[fAdvancedOptions optionsString] UTF8String] ); - - + hb_job_set_advanced_opts(job, [[fAdvancedOptions optionsString] UTF8String] ); } else if( job->vcodec & HB_VCODEC_FFMPEG_MASK ) { - job->advanced_opts = strdup( [[fAdvancedOptions optionsStringLavc] UTF8String] ); + hb_job_set_advanced_opts(job, [[fAdvancedOptions optionsStringLavc] UTF8String] ); } /* Video settings */ @@ -3689,11 +3687,10 @@ bool one_burned = FALSE; id tempObject; while (tempObject = [enumerator nextObject]) { - hb_chapter_t *chapter = (hb_chapter_t *) hb_list_item( title->list_chapter, i ); + hb_chapter_t *chapter = (hb_chapter_t *) hb_list_item( job->list_chapter, i ); if( chapter != NULL ) { - strncpy( chapter->title, [tempObject UTF8String], 1023); - chapter->title[1023] = '\0'; + hb_chapter_set_title( chapter, [tempObject UTF8String] ); } i++; } @@ -3726,13 +3723,13 @@ bool one_burned = FALSE; { job->fastfirstpass = 0; } - job->advanced_opts = strdup( [[queueToApply objectForKey:@"x264Option"] UTF8String] ); + hb_job_set_advanced_opts( job, [[queueToApply objectForKey:@"x264Option"] UTF8String] ); } else if( job->vcodec & HB_VCODEC_FFMPEG_MASK ) { if ([queueToApply objectForKey:@"lavcOption"]) { - job->advanced_opts = strdup( [[queueToApply objectForKey:@"lavcOption"] UTF8String] ); + hb_job_set_advanced_opts( job, [[queueToApply objectForKey:@"lavcOption"] UTF8String] ); } } @@ -4579,7 +4576,6 @@ bool one_burned = FALSE; } /* Start Get and set the initial pic size for display */ - hb_job_t * job = title->job; fTitle = title; /* Set Auto Crop to on upon selecting a new title */ @@ -4587,12 +4583,12 @@ bool one_burned = FALSE; /* We get the originial output picture width and height and put them in variables for use with some presets later on */ - PicOrigOutputWidth = job->width; - PicOrigOutputHeight = job->height; - AutoCropTop = job->crop[0]; - AutoCropBottom = job->crop[1]; - AutoCropLeft = job->crop[2]; - AutoCropRight = job->crop[3]; + PicOrigOutputWidth = title->width; + PicOrigOutputHeight = title->height; + AutoCropTop = title->crop[0]; + AutoCropBottom = title->crop[1]; + AutoCropLeft = title->crop[2]; + AutoCropRight = title->crop[3]; /* Reset the new title in fPictureController && fPreviewController*/ [fPictureController SetTitle:title]; @@ -4614,8 +4610,6 @@ bool one_burned = FALSE; userInfo: [NSDictionary dictionaryWithObjectsAndKeys: [NSData dataWithBytesNoCopy: &fTitle length: sizeof(fTitle) freeWhenDone: NO], keyTitleTag, nil]]]; - - [fVidRatePopUp selectItemAtIndex: 0]; /* we run the picture size values through calculatePictureSizing to get all picture setting information*/ diff --git a/macosx/HBPreviewController.m b/macosx/HBPreviewController.m index 7b59f712b..d7a07dc8a 100644 --- a/macosx/HBPreviewController.m +++ b/macosx/HBPreviewController.m @@ -698,7 +698,7 @@ buffer = (uint8_t *) realloc( buffer, bufferSize ); } - hb_get_preview( handle, title, pictureIndex, buffer ); + hb_get_preview( handle, title->job, pictureIndex, buffer ); // Create an NSBitmapImageRep and copy the libhb image into it, converting it from // libhb's format to one suitable for NSImage. Along the way, we'll strip off the @@ -907,7 +907,7 @@ hb_add( fPreviewLibhb, job ); /* we need to clean up the various lists after the job(s) have been set */ - hb_reset_job( job ); + hb_job_reset( job ); [fEncodingControlBox setHidden: NO]; [fPictureControlBox setHidden: YES]; diff --git a/test/test.c b/test/test.c index bf0c086b4..472fabd54 100644 --- a/test/test.c +++ b/test/test.c @@ -385,14 +385,14 @@ static void ShowCommands() fprintf( stdout, " [r]esume Resume encoding\n" ); } -static void PrintTitleInfo( hb_title_t * title ) +static void PrintTitleInfo( hb_title_t * title, int feature ) { hb_chapter_t * chapter; hb_subtitle_t * subtitle; int i; fprintf( stderr, "+ title %d:\n", title->index ); - if ( title->index == title->job->feature ) + if ( title->index == feature ) { fprintf( stderr, " + Main Feature\n" ); } @@ -472,6 +472,18 @@ static void PrintTitleInfo( hb_title_t * title ) } +static void PrintTitleSetInfo( hb_title_set_t * title_set ) +{ + int i; + hb_title_t * title; + + for( i = 0; i < hb_list_count( title_set->list_title ); i++ ) + { + title = hb_list_item( title_set->list_title, i ); + PrintTitleInfo( title, title_set->feature ); + } +} + static int test_sub_list( char ** list, int pos ) { int i; @@ -582,7 +594,7 @@ static int HandleEvents( hb_handle_t * h ) case HB_STATE_SCANDONE: { - hb_list_t * list; + hb_title_set_t * title_set; hb_title_t * title; hb_job_t * job; int i; @@ -599,9 +611,9 @@ static int HandleEvents( hb_handle_t * h ) double gain = 0; /* Audio argument string parsing variables */ - list = hb_get_titles( h ); + title_set = hb_get_title_set( h ); - if( !hb_list_count( list ) ) + if( !title_set || !hb_list_count( title_set->list_title ) ) { /* No valid title, stop right there */ fprintf( stderr, "No title found.\n" ); @@ -618,9 +630,9 @@ static int HandleEvents( hb_handle_t * h ) fprintf( stderr, "Searching for main feature title...\n" ); - for( i = 0; i < hb_list_count( list ); i++ ) + for( i = 0; i < hb_list_count( title_set->list_title ); i++ ) { - title = hb_list_item( list, i ); + title = hb_list_item( title_set->list_title, i ); title_time = (title->hours*60*60 ) + (title->minutes *60) + (title->seconds); fprintf( stderr, " + Title (%d) index %d has length %dsec\n", i, title->index, title_time ); @@ -630,7 +642,7 @@ static int HandleEvents( hb_handle_t * h ) main_feature_pos = i; main_feature_idx = title->index; } - if( title->job->feature == title->index ) + if( title_set->feature == title->index ) { main_feature_time = title_time; main_feature_pos = i; @@ -648,28 +660,24 @@ static int HandleEvents( hb_handle_t * h ) fprintf( stderr, "Found main feature title, setting title to %d\n", main_feature_idx); - title = hb_list_item( list, main_feature_pos); + title = hb_list_item( title_set->list_title, main_feature_pos); } else { - title = hb_list_item( list, 0 ); + title = hb_list_item( title_set->list_title, 0 ); } if( !titleindex || titlescan ) { /* Scan-only mode, print infos and exit */ - int i; - for( i = 0; i < hb_list_count( list ); i++ ) - { - title = hb_list_item( list, i ); - PrintTitleInfo( title ); - } + PrintTitleSetInfo( title_set ); die = 1; break; } + PrintTitleInfo( title, title_set->feature ); + /* Set job settings */ - job = title->job; + job = hb_job_init( title ); - PrintTitleInfo( title ); if( chapter_start && chapter_end && !stop_at_pts && !start_at_preview && !stop_at_frame && !start_at_pts && !start_at_frame ) { @@ -1312,16 +1320,14 @@ static int HandleEvents( hb_handle_t * h ) { hb_chapter_t * chapter_s; - chapter_s = hb_list_item( job->title->list_chapter, chapter - 1); - strncpy(chapter_s->title, cell->cell_text, 1023); - chapter_s->title[1023] = '\0'; + chapter_s = hb_list_item( job->list_chapter, chapter - 1); + hb_chapter_set_title(chapter_s, cell->cell_text); } } hb_dispose_cell( cell ); } - hb_close_csv_file( file ); } } @@ -1705,8 +1711,8 @@ static int HandleEvents( hb_handle_t * h ) } } - if( hb_list_count( audios ) == 0 && - hb_list_count( job->title->list_audio ) > 0 ) + if( hb_list_count(audios) == 0 && + hb_list_count(title->list_audio) > 0 ) { /* Create a new audio track with default settings */ audio = calloc( 1, sizeof( *audio ) ); @@ -2434,22 +2440,13 @@ static int HandleEvents( hb_handle_t * h ) job->ipod_atom = 1; } - job->file = strdup( output ); + hb_job_set_file( job, output ); if( color_matrix_code ) { job->color_matrix_code = color_matrix_code; } - if( advanced_opts != NULL && *advanced_opts != '\0' ) - { - job->advanced_opts = advanced_opts; - } - else /*avoids a bus error crash when options aren't specified*/ - { - job->advanced_opts = NULL; - } - job->x264_profile = x264_profile; job->x264_preset = x264_preset; job->x264_tune = x264_tune; @@ -2491,17 +2488,13 @@ static int HandleEvents( hb_handle_t * h ) if( subtitle_scan ) { - char *advanced_opts_tmp; - /* * When subtitle scan is enabled do a fast pre-scan job * which will determine which subtitles to enable, if any. */ job->pass = -1; - advanced_opts_tmp = job->advanced_opts; - - job->advanced_opts = NULL; + hb_job_set_advanced_opts(job, NULL); job->indepth_scan = subtitle_scan; fprintf( stderr, "Subtitle Scan Enabled - enabling " @@ -2511,10 +2504,10 @@ static int HandleEvents( hb_handle_t * h ) * Add the pre-scan job */ hb_add( h, job ); - - job->advanced_opts = advanced_opts_tmp; } + hb_job_set_advanced_opts(job, advanced_opts); + if( twoPass ) { /* @@ -2558,9 +2551,10 @@ static int HandleEvents( hb_handle_t * h ) job->indepth_scan = 0; job->pass = 0; + hb_add( h, job ); } - hb_reset_job( job ); + hb_job_close( &job ); hb_start( h ); break; } |