]> granicus.if.org Git - handbrake/commitdiff
Improve management of titles and jobs
authorjstebbins <jstebbins.hb@gmail.com>
Mon, 12 Nov 2012 08:22:07 +0000 (08:22 +0000)
committerjstebbins <jstebbins.hb@gmail.com>
Mon, 12 Nov 2012 08:22:07 +0000 (08:22 +0000)
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

32 files changed:
gtk/src/callbacks.c
gtk/src/ghb.ui
gtk/src/hb-backend.c
gtk/src/hb-backend.h
gtk/src/internal_defaults.xml
gtk/src/presets.c
gtk/src/values.c
libhb/bd.c
libhb/common.c
libhb/common.h
libhb/decavcodec.c
libhb/decmetadata.c
libhb/decmpeg2.c
libhb/decsrtsub.c
libhb/dvd.c
libhb/dvdnav.c
libhb/hb.c
libhb/hb.h
libhb/internal.h
libhb/muxcommon.c
libhb/muxmkv.c
libhb/muxmp4.c
libhb/reader.c
libhb/rendersub.c
libhb/scan.c
libhb/stream.c
libhb/sync.c
libhb/work.c
macosx/ChapterTitles.m
macosx/Controller.m
macosx/HBPreviewController.m
test/test.c

index 0ff45d1c1649577fff175047ea0076be84095828..29c767c17a9912dffd82979a424f05afbbffb77b 100644 (file)
@@ -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");
                }
index bf24d17d1b5667f7faf37290a44ab61204787acf..b5ca17ca2e2e85cfc5871285616e86a316f9b5b7 100644 (file)
@@ -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>
 
index f2638bf73c70f6cdd4823c3991f3ed59abb1e53f..cda5882e85ad027b6684b445ddda5b49550bb4d1 100644 (file)
@@ -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.
index e1ff28a75348f6c0e3dee699071a4dbc2385b2bd..ded2fd8c0ecd731c32afedc2ebda3891473012dc 100644 (file)
@@ -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);
index 68667222a38278a251d199396a7e074efc9468a0..e5d98cebe11b4f95fbf7788ff6ed13f9e14bc9c3 100644 (file)
                <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>
index eeacbde044408a894593225c12fdefbc08fb8e34..1905e5597e5656fdb4e92e319d0056951f277216 100644 (file)
@@ -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);
index dd23d0e48e776f7a0f141b085fbe7e362573fc0f..f755363e5cf3c80d20fcd0f8ad1c16521c273ff5 100644 (file)
@@ -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;
 }
 
index 208782674af1b46eeacdec8711e331fa1b8d1d2c..268cdaab04c4040819a6315700971e1b82f0527d 100644 (file)
@@ -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;
index 821f17e76cb90df1452d3dbf7d98c40df94af95d..80b526c2a36ed4d7d54910a0aa3e04915e2c5ebe 100644 (file)
@@ -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.
@@ -1758,6 +1983,93 @@ void hb_filter_close( hb_filter_object_t ** _f )
     *_f = NULL;
 }
 
+/**********************************************************************
+ * 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,10 +2083,53 @@ 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);
@@ -1917,6 +2272,45 @@ hb_subtitle_t *hb_subtitle_copy(const hb_subtitle_t *src)
     return subtitle;
 }
 
+/**********************************************************************
+ * 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;
@@ -2118,6 +2744,46 @@ hb_attachment_t *hb_attachment_copy(const hb_attachment_t *src)
     return attachment;
 }
 
+/**********************************************************************
+ * 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
  **********************************************************************
index f7cc6dfefae9faf524a0d13547aec3e6797492b4..41711e9548be87a4c822c7ac96749d38b07aed1f 100644 (file)
@@ -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 );
 
index 4fd22c833fa16576e6cbe26386d8a9604fd20d63..dd3c8879db0f97be92609d3d16fb9b5c13fa6a4a 100644 (file)
@@ -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,
index e3829de093aede15085ce1235062a49423baf22f..513e64fbe5dc5f1f960a2338820007ae42aa6031 100644 (file)
 
 #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;
 }
index 311fc93c883ed0f9fac99573de02f8c3eca548f7..991feb8e9a6b7b0ebc4676e585368f6715f586ed 100644 (file)
@@ -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 );
index 55004c05f9d846a0bd09b553a6913f53e2229c15..6d1754068dcfad3433f34ba0f6b07679eeb24500 100644 (file)
@@ -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;
index 1a273f977185af6308bc912748caacf935da2c39..f342b54748f4e7bdb3082a93131f356af66d8dd6 100644 (file)
@@ -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;
index 638b6e5af82833de8d93b5cd4eb8adf8bb561048..c1f152efd58a45b887bcd186357970d71e4d7f10 100644 (file)
@@ -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++;
index 52ddc206b94e0b520db1815438d46709bd4b1038..8a1ec3b1e4b30abea756e684c069e4bd69c55446 100644 (file)
@@ -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;
@@ -988,26 +978,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,
  *
@@ -1422,53 +1392,6 @@ hb_job_t * hb_current_job( hb_handle_t * h )
     return( h->current_job );
 }
 
-/**
- * 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.
@@ -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 );
@@ -1637,37 +1480,6 @@ void hb_add( hb_handle_t * h, hb_job_t * job )
     h->job_count_permanent++;
 }
 
-/**
- * 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.
@@ -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
@@ -2023,29 +1830,6 @@ int hb_get_instance_id( hb_handle_t * h )
     return h->id;
 }
 
-/**
- * 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
index da23118341949941a392f668e1239fdae7049328..825032cfbad24348dfeda08ff9c26cc126affcd2 100644 (file)
@@ -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 * );
index caa2e71896900a1115fa4ce10de20a1b143a8bde..1c02ffe85c4bd945925f7e6824fad973ffa72684 100644 (file)
@@ -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
index 6587a4dacac5706fb6974d626c653bb168e2ab1a..d5d9c7a9204d28ff4b9d00c81ec1d8cf445bd2be 100644 (file)
@@ -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;
index addd800def5eddd212b9463fbd136b0296a3b01d..2b629bc49342cfc78404266cdc8f802b6651f871 100644 (file)
@@ -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)
index d21e4b7678c650302238068a40cf1c9d74436ac4..f1380dc1824168a3955d64c159c9997332d37529 100644 (file)
@@ -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 */
index 8148e6590be1dc26786faf6b40593dabcc08ed52..d5c937422925cec3a008c24514d7f82e623e2f9f 100644 (file)
@@ -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;
index 568b7d1b004e31b143382a0876c982ead95ca778..c9e9f02cf5825c9d5e97602678d335c2c1995125 100644 (file)
@@ -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
index 10ed353918f1e2aa6728d34013653e3ffa5721d0..0163af4061a30483e119eaf3278c883d3c51ef45 100644 (file)
@@ -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:
index ede9f33d346213462d65228d20d03b484d5978fa..503e296dc31eee7313e849a1185d2f6118548b05 100644 (file)
@@ -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;
index c3e4c37a187f5ee717495579e9d98ae3ca959f83..f416d1664a454b8261bebf7d92a965a7116c8496 100644 (file)
@@ -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 )
index 277ebf0336c66d29561ff50350136271eec52385..030920c59ad5a7afbecebc630f24d7803ff5f234 100644 (file)
@@ -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 )
index 893c2dc22321d1cf89b7d8ba3bca3ca42d85e361..2fcd77272ad220c08f1fe07917a380777fa50a2b 100644 (file)
     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]);
         }
     }
     
     {
         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 )
             {
index c3edceb1a488ecb6fbdf84834272b7efdf4fec35..dea32a40c1899c22affd1b744ce5527fe25d0dda 100644 (file)
@@ -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*/
index 7b59f712bf3f9fe756d08bfec5ffa649ba4504ac..d7a07dc8a9d9ef7ab933d0543e0c52965b21741f 100644 (file)
         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
     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];
index bf0c086b4b6758fdf65b103db63b88c44695797b..472fabd54b863dbc53a6595c4bafacba75aee174 100644 (file)
@@ -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;
         }