diff options
author | jstebbins <[email protected]> | 2012-11-12 08:22:07 +0000 |
---|---|---|
committer | jstebbins <[email protected]> | 2012-11-12 08:22:07 +0000 |
commit | ab5445d6f279a3477c08f069ff3329b696cb9ac8 (patch) | |
tree | 28b1f1aa52db4f2f0d35a35950f6486955703426 | |
parent | cf1f034f914348d0f0bfcd5f8902f0a3fb519273 (diff) |
Improve management of titles and jobs
Cleans up several several unavoidable memory leaks caused by old api.
Clearly separates titles from jobs. Titles are set during scan and
never modified now.
Since titles are immutable, this lead to API some changes. For example,
We were setting chapter names in the title from the front ends. Now
these get set in the job.
These new APIs allow us to start moving away from our use of title->job.
Eventually, I would like to eliminate title->job completely, but the
mac ui is too tightly tied to using this field to allow removing it
at this time. So there is temporarily a convenience function used
only by the mac ui that allows it to continue using title->job and also
use the new APIs.
New APIs:
typedef struct hb_title_set_s hb_title_set_t;
struct hb_title_set_s
{
hb_list_t * list_title;
int feature; // Detected DVD feature title
};
hb_title_set_t * hb_get_title_set( hb_handle_t * );
This is just something I added to clean up how "feature title" info
is passed.
hb_job_t * hb_job_init( hb_title_t * title );
Initializes a new job with default settings from the title.
hb_job_t * hb_job_init_by_index( hb_handle_t *h, int title_index );
Same as hb_job_init(). For use by win Interop lib.
void hb_job_reset( hb_job_t * job );
Convenience function for the MacUi.
Clears audio, subtitle, and filter lists. The macui still uses
title->job because it is so intricately tied to it. So I created
this convenience function that it can call after adding a job.
void hb_job_close( hb_job_t ** job );
Releases the job an all resources it contains.
void hb_job_set_advanced_opts( hb_job_t *job, const char *advanced_opts );
Makes a copy of "advanced_opts" and stores in job.
Freed by hb_job_close().
void hb_job_set_file( hb_job_t *job, const char *file );
Makes a copy of "file" and stores in job.
Freed by hb_job_close().
void hb_chapter_set_title(hb_chapter_t *chapter, const char *title);
Makes a copy of "title" and stores in chapter.
Freed by hb_chapter_close().
Recommended usage (cli and lingui are updated to do this):
job = hb_job_init( title );
// set job settings ...
hb_add(h, job);
hb_job_close( &job );
I have also added new APIs for managing metadata. These are
used to add metadata to a job.
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_coverart( hb_metadata_t *metadata, const uint8_t *coverart, int size );
Example:
job = hb_job_init( &job );
// set job settings ...
hb_metadata_set_artist( job->metadata, "Danny Elfman" );
hb_add(h, job);
hb_job_close( &job );
Some APIs have changed in order to avoid using title incorrectly and
use the new hb_title_set_t.
-void hb_autopassthru_apply_settings( hb_job_t * job, hb_title_t * title );
+void hb_autopassthru_apply_settings( hb_job_t * job );
-void hb_get_preview( hb_handle_t *, hb_title_t *, int, uint8_t * );
+void hb_get_preview( hb_handle_t *, hb_job_t *, int, uint8_t * );
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 );
These APIs have been removed. Win Interop will need some changes.
I think what I've provided will be suffecient, but let me know if it's not.
-void hb_get_preview_by_index( hb_handle_t *, int, int, uint8_t * );
-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 );
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@5058 b64f7644-9d1e-0410-96f1-a4d463321fa5
-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; } |