OSDN Git Service

mkv soft subtitle support
authorjstebbins <jstebbins@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Tue, 19 May 2009 22:27:11 +0000 (22:27 +0000)
committerjstebbins <jstebbins@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Tue, 19 May 2009 22:27:11 +0000 (22:27 +0000)
- new libmkv 0.6.4 with subtitle track support
- muxmkv supports vobsub and closed caption subtitles
- added subtitle format, source, and dest initialization to dvdnav
- moved subtitle_force flag into hb_subtitle_t struct as it needs to
  be settable per subtitle
- gtk ui added subtitle tab which allows selection of multiple subtitles
- reorgainize subtitle sync code to prevent dropping of subtitles when
  multiple subtitles are enabled

git-svn-id: svn://localhost/HandBrake/trunk@2428 b64f7644-9d1e-0410-96f1-a4d463321fa5

23 files changed:
contrib/libmkv/module.defs
gtk/src/Makefile.am
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/main.c
gtk/src/presets.c
gtk/src/queuehandler.c
gtk/src/settings.c
gtk/src/settings.h
libhb/common.h
libhb/decvobsub.c
libhb/dvdnav.c
libhb/encvobsub.c
libhb/fifo.c
libhb/muxmkv.c
libhb/reader.c
libhb/sync.c
libhb/work.c
macosx/Controller.mm
test/test.c

index 102aea0..3805d25 100644 (file)
@@ -1,5 +1,4 @@
 $(eval $(call import.MODULE.defs,LIBMKV,libmkv))
 $(eval $(call import.CONTRIB.defs,LIBMKV))
 
-LIBMKV.FETCH.url = http://download.m0k.org/handbrake/contrib/libmkv-0.6.3.1.tar.gz
-LIBMKV.EXTRACT.tarbase = libmkv
+LIBMKV.FETCH.url = http://download.m0k.org/handbrake/contrib/libmkv-0.6.4.tar.bz2
index 71b3ac3..b435cd1 100644 (file)
@@ -68,6 +68,8 @@ ghb_SOURCES = \
        queuehandler.h \
        audiohandler.c \
        audiohandler.h \
+       subtitlehandler.c \
+       subtitlehandler.h \
        x264handler.c \
        x264handler.h \
        main.c \
index f2d9642..e2140d7 100644 (file)
@@ -44,6 +44,7 @@
 #include "callbacks.h"
 #include "queuehandler.h"
 #include "audiohandler.h"
+#include "subtitlehandler.h"
 #include "resources.h"
 #include "settings.h"
 #include "presets.h"
@@ -1118,6 +1119,7 @@ container_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
                }
                g_free(container);
        }
+       ghb_subtitle_adjust_burn(ud);
 }
 
 static gchar*
@@ -1254,10 +1256,10 @@ title_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
        ghb_check_dependency(ud, widget);
 
        titleindex = ghb_settings_combo_int(ud->settings, "title");
-       ghb_update_ui_combo_box (ud->builder, "AudioTrack", titleindex, FALSE);
-       ghb_update_ui_combo_box (ud->builder, "Subtitles", titleindex, FALSE);
+       ghb_update_ui_combo_box (ud, "AudioTrack", titleindex, FALSE);
+       ghb_update_ui_combo_box (ud, "SubtitleTrack", titleindex, FALSE);
 
-       ghb_update_from_preset(ud, "Subtitles");
+       ghb_set_pref_subtitle(titleindex, ud);
        if (ghb_get_title_info (&tinfo, titleindex))
        {
                show_title_info(ud, &tinfo);
@@ -2019,7 +2021,7 @@ ghb_backend_events(signal_user_data_t *ud)
 
                ghb_title_info_t tinfo;
                        
-               ghb_update_ui_combo_box(ud->builder, "title", 0, FALSE);
+               ghb_update_ui_combo_box(ud, "title", 0, FALSE);
                titleindex = ghb_longest_title();
                ghb_ui_update(ud, "title", ghb_int64_value(titleindex));
 
index 8d52e29..57a941f 100644 (file)
                               </object>
                             </child>
                             <child type="label">
-                              <object class="GtkLabel" id="label74">
+                              <object class="GtkLabel" id="label87">
                                 <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">&lt;b&gt;Preferred Audio Language&lt;/b&gt;</property>
                             </child>
                           </object>
                         </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">3</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+                <child type="tab">
+                  <object class="GtkLabel" id="label48">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Audio</property>
+                  </object>
+                  <packing>
+                    <property name="position">2</property>
+                    <property name="tab_fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkVBox" id="subtitle_tab">
+                    <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>
+                    <child>
+                      <object class="GtkFrame" id="frame20">
+                        <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_xalign">0</property>
+                        <property name="shadow_type">none</property>
                         <child>
-                          <object class="GtkFrame" id="frame19">
+                          <object class="GtkAlignment" id="alignment23">
                             <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_xalign">0</property>
-                            <property name="shadow_type">none</property>
+                            <property name="top_padding">6</property>
+                            <property name="bottom_padding">2</property>
+                            <property name="left_padding">12</property>
+                            <property name="right_padding">2</property>
                             <child>
-                              <object class="GtkAlignment" id="alignment58">
+                              <object class="GtkVBox" id="vbox12">
                                 <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">6</property>
-                                <property name="bottom_padding">2</property>
-                                <property name="left_padding">12</property>
-                                <property name="right_padding">2</property>
+                                <property name="spacing">2</property>
                                 <child>
-                                  <object class="GtkHBox" id="hbox65">
+                                  <object class="GtkHBox" id="hbox45">
                                     <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="spacing">5</property>
-
                                     <child>
-                                      <object class="GtkComboBox" id="Subtitles">
-                                        <property name="width_request">150</property>
+                                      <object class="GtkButton" id="subtitle_add">
                                         <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="receives_default">True</property>
                                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                        <signal handler="subtitle_changed_cb" name="changed"/>
+                                        <property name="tooltip-text" translatable="yes">Add new audio settings to the list</property>
+                                        <property name="relief">GTK_RELIEF_NONE</property>
+                                        <signal handler="subtitle_add_clicked_cb" name="clicked"/>
+                                        <child>
+                                          <object class="GtkImage" id="image9">
+                                            <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="stock">gtk-add</property>
+                                          </object>
+                                        </child>
                                       </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                      </packing>
                                     </child>
                                     <child>
-                                      <object class="GtkCheckButton" id="SubtitlesForced">
+                                      <object class="GtkButton" id="subtitle_remove">
                                         <property name="visible">True</property>
                                         <property name="can_focus">True</property>
-                                        <property name="has_tooltip">True</property>
-                                        <property name="tooltip-text" translatable="yes">These are subtitles that a regular DVD player would automatically show.</property>
-                                        <property name="label" translatable="yes">Allow only forced subtitles</property>
-                                        <property name="draw_indicator">True</property>
-                                        <signal handler="setting_widget_changed_cb" name="toggled"/>
+                                        <property name="receives_default">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="tooltip-text" translatable="yes">Remove the selected audio settings</property>
+                                        <property name="relief">GTK_RELIEF_NONE</property>
+                                        <signal handler="subtitle_remove_clicked_cb" name="clicked"/>
+                                        <child>
+                                          <object class="GtkImage" id="image2">
+                                            <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="stock">gtk-remove</property>
+                                          </object>
+                                        </child>
                                       </object>
                                       <packing>
+                                        <property name="expand">False</property>
                                         <property name="position">1</property>
                                       </packing>
                                     </child>
+                                    <child>
+                                      <object class="GtkAlignment" id="alignment44">
+                                        <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="xalign">1</property>
+                                        <property name="xscale">0</property>
+                                        <property name="yscale">0</property>
+                                        <child>
+                                          <object class="GtkHBox" id="hbox21">
+                                            <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="spacing">5</property>
+                                            <child>
+                                              <object class="GtkLabel" id="label24">
+                                                <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">Subtitle:</property>
+                                              </object>
+                                            </child>
+                                            <child>
+                                              <object class="GtkComboBox" id="SubtitleTrack">
+                                                <property name="width_request">150</property>
+                                                <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>
+                                                <signal handler="subtitle_track_changed_cb" name="changed"/>
+                                              </object>
+                                              <packing>
+                                                <property name="position">1</property>
+                                                <property name="expand">False</property>
+                                              </packing>
+                                            </child>
+                                          </object>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="position">2</property>
+                                      </packing>
+                                    </child>
                                   </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkTreeView" id="subtitle_list">
+                                    <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="headers_clickable">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">1</property>
+                                  </packing>
                                 </child>
-                              </object>
-                            </child>
-                            <child type="label">
-                              <object class="GtkLabel" id="label75">
-                                <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">&lt;b&gt;Subtitles&lt;/b&gt;</property>
-                                <property name="use_markup">True</property>
                               </object>
                             </child>
                           </object>
-                          <packing>
-                            <property name="position">1</property>
-                          </packing>
                         </child>
                       </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="position">3</property>
-                      </packing>
                     </child>
                   </object>
                 </child>
                 <child type="tab">
-                  <object class="GtkLabel" id="label48">
+                  <object class="GtkLabel" id="label9">
                     <property name="visible">True</property>
-                    <property name="label" translatable="yes">Audio/Subtitles</property>
+                    <property name="label" translatable="yes">Subtitles</property>
                   </object>
                   <packing>
-                    <property name="position">2</property>
+                    <property name="position">3</property>
                     <property name="tab_fill">False</property>
                   </packing>
                 </child>
@@ -3053,7 +3137,7 @@ no-dct-decimate=0:cabac=1</property>
                     <property name="label" translatable="yes">H.264</property>
                   </object>
                   <packing>
-                    <property name="position">3</property>
+                    <property name="position">4</property>
                     <property name="tab_fill">False</property>
                   </packing>
                 </child>
@@ -3118,7 +3202,7 @@ no-dct-decimate=0:cabac=1</property>
                     <property name="label" translatable="yes">Chapters</property>
                   </object>
                   <packing>
-                    <property name="position">4</property>
+                    <property name="position">5</property>
                     <property name="tab_fill">False</property>
                   </packing>
                 </child>
@@ -4597,7 +4681,7 @@ the required multiple.</property>
                       </object>
                     </child>
                     <child type="label">
-                      <object class="GtkLabel" id="label29">
+                      <object class="GtkLabel" id="label25">
                         <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">&lt;b&gt;Storage&lt;/b&gt;</property>
@@ -4862,7 +4946,7 @@ the required multiple.</property>
                               </packing>
                             </child>
                             <child>
-                              <object class="GtkAlignment" id="alignment2">
+                              <object class="GtkAlignment" id="alignment27">
                                 <property name="visible">True</property>
                                 <property name="xalign">0</property>
                                 <property name="xscale">0</property>
@@ -4875,7 +4959,7 @@ the required multiple.</property>
                                 <property name="column_spacing">5</property>
 
                                 <child>
-                                  <object class="GtkLabel" id="label56">
+                                  <object class="GtkLabel" id="label41">
                                     <property name="visible">True</property>
                                     <property name="xalign">0</property>
                                     <property name="label" translatable="yes">Deblock:</property>
@@ -4974,7 +5058,7 @@ the required multiple.</property>
                                 <property name="column_spacing">5</property>
 
                                 <child>
-                                  <object class="GtkLabel" id="label56">
+                                  <object class="GtkLabel" id="label86">
                                     <property name="visible">True</property>
                                     <property name="xalign">0</property>
                                     <property name="label" translatable="yes">Detelecine:</property>
@@ -5627,7 +5711,7 @@ libxvidcore authors:
                     <property name="visible_window">False</property>
                     <property name="above_child">True</property>
                     <child>
-                      <object class="GtkImage" id="image3">
+                      <object class="GtkImage" id="image10">
                         <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="icon_name">hb-icon</property>
@@ -5685,7 +5769,7 @@ libxvidcore authors:
                     <property name="label_xalign">0</property>
                     <property name="shadow_type">etched-out</property>
                     <child>
-                      <object class="GtkAlignment" id="alignment2">
+                      <object class="GtkAlignment" id="alignment28">
                         <property name="visible">True</property>
                         <property name="left_padding">12</property>
                         <child>
@@ -5793,7 +5877,7 @@ libxvidcore authors:
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkAlignment" id="alignment1">
+                  <object class="GtkAlignment" id="alignment24">
                     <property name="visible">True</property>
                     <property name="xalign">0</property>
                     <property name="xscale">0</property>
index 0b7633d..bb30d2c 100644 (file)
@@ -30,6 +30,7 @@
 #include "hb-backend.h"
 #include "settings.h"
 #include "callbacks.h"
+#include "subtitlehandler.h"
 #include "preview.h"
 #include "values.h"
 #include "lang.h"
@@ -48,20 +49,24 @@ typedef struct
        options_map_t *map;
 } combo_opts_t;
 
-static const gchar *index_str[] =
-{
-       "0",
-       "1",
-       "2",
-       "3",
-       "4",
-       "5",
-       "6",
-       "7",
-       "8",
-       "9",
-       "10",
-};
+static gchar **index_str = NULL;
+static gint index_str_size = 0;
+
+static void 
+index_str_init(gint max_index)
+{
+       int ii;
+
+       if (max_index+1 > index_str_size)
+       {
+               index_str = realloc(index_str, (max_index+1) * sizeof(char*));
+               for (ii = index_str_size; ii <= max_index; ii++)
+               {
+                       index_str[ii] = g_strdup_printf("%d", ii);
+               }
+               index_str_size = max_index + 1;
+       }
+}
 
 static options_map_t d_par_opts[] =
 {
@@ -330,7 +335,7 @@ combo_name_map_t combo_name_map[] =
        {"x264_subme", &subme_opts},
        {"x264_analyse", &analyse_opts},
        {"x264_trellis", &trellis_opts},
-       {"Subtitles", &subtitle_opts},
+       {"SubtitleTrack", &subtitle_opts},
        {"title", &title_opts},
        {"AudioTrack", &audio_track_opts},
        {NULL, NULL}
@@ -629,6 +634,26 @@ ghb_vquality_range(
        }
 }
 
+static const gchar*
+lookup_generic_string(combo_opts_t *opts, const GValue *gval)
+{
+       gint ii;
+       gchar *str;
+       const gchar *result = "";
+
+       str = ghb_value_string(gval);
+       for (ii = 0; ii < opts->count; ii++)
+       {
+               if (strcmp(opts->map[ii].shortOpt, str) == 0)
+               {
+                       result = opts->map[ii].svalue;
+                       break;
+               }
+       }
+       g_free(str);
+       return result;
+}
+
 static gint
 lookup_generic_int(combo_opts_t *opts, const GValue *gval)
 {
@@ -964,6 +989,92 @@ ghb_hb_cleanup(gboolean partial)
 }
 
 gint
+ghb_subtitle_track_source(signal_user_data_t *ud, gint track)
+{
+       gint titleindex;
+
+       if (track == -2)
+               return CC608SUB;
+       if (track < 0)
+               return VOBSUB;
+       titleindex = ghb_settings_combo_int(ud->settings, "title");
+       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 );
+       if (title == NULL) return VOBSUB;       // Bad titleindex
+       sub = hb_list_item( title->list_subtitle, track);
+       if (sub != NULL)
+               return sub->source;
+       else
+               return VOBSUB;
+}
+
+const char*
+ghb_subtitle_track_source_name(signal_user_data_t *ud, gint track)
+{
+       gint titleindex;
+       const gchar * name = "Unknown";
+
+       if (track == -2)
+               return CC608SUB;
+       if (track < 0)
+               return VOBSUB;
+       if (track < 0)
+               goto done;
+
+       titleindex = ghb_settings_combo_int(ud->settings, "title");
+       if (titleindex < 0)
+               goto done;
+
+       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 ) )
+               goto done;
+
+       title = hb_list_item( list, titleindex );
+       if (title == NULL)
+               goto done;
+
+       sub = hb_list_item( title->list_subtitle, track);
+       if (sub != NULL)
+       {
+               switch (sub->source)
+               {
+                       case VOBSUB:
+                               name = "Bitmap";
+                               break;
+                       case CC708SUB:
+                       case CC608SUB:
+                       case SRTSUB:
+                               name = "Text";
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+done:
+       return name;
+}
+
+
+gint
 ghb_get_title_number(gint titleindex)
 {
        hb_list_t  * list;
@@ -1544,6 +1655,7 @@ audio_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
                audio_track_opts.map[0].svalue = "none";
                return;
        }
+       index_str_init(count-1);
        for (ii = 0; ii < count; ii++)
        {
         audio = (hb_audio_config_t *) hb_list_audio_config_item( title->list_audio, ii );
@@ -1562,20 +1674,18 @@ audio_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
        }
 }
 
-
 void
-subtitle_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
+subtitle_opts_set(signal_user_data_t *ud, 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;
-       gint count = 0;
+       hb_subtitle_t * subtitle;
+       gint ii, count = 0;
        
        g_debug("subtitle_opts_set () %s\n", name);
-       store = get_combo_box_store(builder, name);
+       store = get_combo_box_store(ud->builder, name);
        gtk_list_store_clear(store);
        if (h_scan != NULL)
        {
@@ -1590,74 +1700,77 @@ subtitle_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
        if (subtitle_opts.map) g_free(subtitle_opts.map);
        if (count > 0)
        {
-               subtitle_opts.count = count+2;
-               subtitle_opts.map = g_malloc((count+2)*sizeof(options_map_t));
+               subtitle_opts.count = count+1;
+               subtitle_opts.map = g_malloc((count+1)*sizeof(options_map_t));
        }
        else
        {
                subtitle_opts.count = LANG_TABLE_SIZE+2;
                subtitle_opts.map = g_malloc((LANG_TABLE_SIZE+2)*sizeof(options_map_t));
        }
-       // Add options for "none" and "autoselect"
-       gtk_list_store_append(store, &iter);
-       gtk_list_store_set(store, &iter, 
-                                          0, "None", 
-                                          1, TRUE, 
-                                          2, "none", 
-                                          3, -2.0, 
-                                          4, "none", 
-                                          -1);
-       subtitle_opts.map[0].option = "None";
-       subtitle_opts.map[0].shortOpt = "none";
-       subtitle_opts.map[0].ivalue = -2;
-       subtitle_opts.map[0].svalue = "none";
        gtk_list_store_append(store, &iter);
        gtk_list_store_set(store, &iter, 
                                           0, "Autoselect", 
                                           1, TRUE, 
-                                          2, "auto", 
+                                          2, "-1", 
                                           3, -1.0, 
                                           4, "auto", 
                                           -1);
-       subtitle_opts.map[1].option = "Same as audio";
-       subtitle_opts.map[1].shortOpt = "auto";
-       subtitle_opts.map[1].ivalue = -1;
-       subtitle_opts.map[1].svalue = "auto";
+       subtitle_opts.map[0].option = "Same as audio";
+       subtitle_opts.map[0].shortOpt = "-1";
+       subtitle_opts.map[0].ivalue = -1;
+       subtitle_opts.map[0].svalue = "auto";
        if (count > 0)
        {
+               index_str_init(count-1);
                for (ii = 0; ii < count; ii++)
                {
                        subtitle = (hb_subtitle_t *)hb_list_item(title->list_subtitle, ii);
+                       // Skip subtitles that must be burned if there is already
+                       // a burned subtitle in the list
+                       subtitle_opts.map[ii+1].option = subtitle->lang;
+                       subtitle_opts.map[ii+1].shortOpt = index_str[ii];
+                       subtitle_opts.map[ii+1].ivalue = ii;
+                       subtitle_opts.map[ii+1].svalue = subtitle->iso639_2;
                        gtk_list_store_append(store, &iter);
                        gtk_list_store_set(store, &iter, 
                                                0, subtitle->lang, 
                                                1, TRUE, 
-                                               2, subtitle->iso639_2
+                                               2, index_str[ii]
                                                3, (gdouble)ii, 
                                                4, subtitle->iso639_2, 
                                                -1);
-                       subtitle_opts.map[ii+2].option = subtitle->lang;
-                       subtitle_opts.map[ii+2].shortOpt = subtitle->iso639_2;
-                       subtitle_opts.map[ii+2].ivalue = ii;
-                       subtitle_opts.map[ii+2].svalue = subtitle->iso639_2;
                }
        }
        else
        {
+               gtk_list_store_append(store, &iter);
+               gtk_list_store_set(store, &iter, 
+                                          0, "Closed Captions", 
+                                          1, TRUE, 
+                                          2, "-2", 
+                                          3, -2.0, 
+                                          4, "und", 
+                                          -1);
+               subtitle_opts.map[1].option = "Closed Captions";
+               subtitle_opts.map[1].shortOpt = "-2";
+               subtitle_opts.map[1].ivalue = -2;
+               subtitle_opts.map[1].svalue = "und";
+               index_str_init(LANG_TABLE_SIZE-1);
                for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
                {
-                       gtk_list_store_append(store, &iter);
-                       gtk_list_store_set(store, &iter, 
-                               0, ghb_language_table[ii].eng_name, 
-                               1, TRUE, 
-                               2, ghb_language_table[ii].iso639_2, 
-                               3, (gdouble)ii, 
-                               4, ghb_language_table[ii].iso639_2, 
-                               -1);
                        subtitle_opts.map[ii+2].option = ghb_language_table[ii].eng_name;
-                       subtitle_opts.map[ii+2].shortOpt = ghb_language_table[ii].iso639_2;
+                       subtitle_opts.map[ii+2].shortOpt = index_str[ii];
                        subtitle_opts.map[ii+2].ivalue = ii;
                        subtitle_opts.map[ii+2].svalue = ghb_language_table[ii].iso639_2;
+                       gtk_list_store_append(store, &iter);
+                       gtk_list_store_set(store, &iter, 
+                                       0, ghb_language_table[ii].eng_name, 
+                                       1, TRUE, 
+                                       2, index_str[ii],
+                                       3, (gdouble)ii, 
+                                       4, ghb_language_table[ii].iso639_2, 
+                                       -1);
                }
        }
 }
@@ -1846,6 +1959,96 @@ ghb_find_audio_track(
        return track;
 }
 
+gint
+ghb_find_subtitle_track(
+       gint titleindex, 
+       const gchar *lang, 
+       GHashTable *track_indices)
+{
+       hb_list_t  * list;
+       hb_title_t * title;
+       hb_subtitle_t * subtitle;
+       gint ii;
+       gint count = 0;
+       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)
+       {
+               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
+               for (ii = 0; ii < count; ii++)
+               {
+                       if (used[ii])
+                               continue;
+
+                       subtitle = (hb_subtitle_t*)hb_list_item( title->list_subtitle, ii );
+                       if ((strcmp(lang, subtitle->iso639_2) == 0) ||
+                               (strcmp(lang, "und") == 0))
+                       {
+                               used[ii] = TRUE;
+                               return ii;
+                       }
+               }
+               return -1;
+       }
+       else
+       {
+               count = subtitle_opts.count;
+               for (ii = 0; ii < count; ii++)
+               {
+                       if (strcmp(lang, subtitle_opts.map[ii].svalue) == 0)
+                       {
+                               return subtitle_opts.map[ii].ivalue;
+                       }
+               }
+               return -1;
+       }
+}
+
+gint
+ghb_pick_subtitle_track(signal_user_data_t *ud)
+{
+       gint ii, count, track, candidate, first;
+       GValue *settings, *subtitle_list;
+
+       first = candidate = ghb_settings_combo_int(ud->settings, "SubtitleTrack");
+       subtitle_list = ghb_settings_get_value(ud->settings, "subtitle_list");
+       count = ghb_array_len(subtitle_list);
+       for (ii = 0; ii < count; ii++)
+       {
+               settings = ghb_array_get_nth(subtitle_list, ii);
+               track = ghb_settings_combo_int(settings, "SubtitleTrack");
+               if (candidate == track)
+               {
+                       // Already in use, pick another
+                       candidate++;
+                       if (candidate >= subtitle_opts.count)
+                       {
+                               candidate = 0;
+                       }
+                       if (candidate == first)
+                       {
+                               candidate = -1;
+                               break;
+                       }
+                       ii = -1;
+               }
+       }
+       return candidate;
+}
+
 static void
 generic_opts_set(GtkBuilder *builder, const gchar *name, combo_opts_t *opts)
 {
@@ -1888,6 +2091,8 @@ find_combo_table(const gchar *name)
 gint
 ghb_lookup_combo_int(const gchar *name, const GValue *gval)
 {
+       if (gval == NULL)
+               return 0;
        if (strcmp(name, "AudioBitrate") == 0)
                return lookup_audio_bitrate_int(gval);
        else if (strcmp(name, "AudioSamplerate") == 0)
@@ -1909,6 +2114,8 @@ ghb_lookup_combo_int(const gchar *name, const GValue *gval)
 gdouble
 ghb_lookup_combo_double(const gchar *name, const GValue *gval)
 {
+       if (gval == NULL)
+               return 0;
        if (strcmp(name, "AudioBitrate") == 0)
                return lookup_audio_bitrate_int(gval);
        else if (strcmp(name, "AudioSamplerate") == 0)
@@ -1930,6 +2137,8 @@ ghb_lookup_combo_double(const gchar *name, const GValue *gval)
 const gchar*
 ghb_lookup_combo_option(const gchar *name, const GValue *gval)
 {
+       if (gval == NULL)
+               return NULL;
        if (strcmp(name, "AudioBitrate") == 0)
                return lookup_audio_bitrate_option(gval);
        else if (strcmp(name, "AudioSamplerate") == 0)
@@ -1945,11 +2154,38 @@ ghb_lookup_combo_option(const gchar *name, const GValue *gval)
                return lookup_generic_option(find_combo_table(name), gval);
        }
        g_warning("ghb_lookup_combo_int() couldn't find %s", name);
-       return 0;
+       return NULL;
+}
+
+const gchar*
+ghb_lookup_combo_string(const gchar *name, const GValue *gval)
+{
+       if (gval == NULL)
+               return NULL;
+       if (strcmp(name, "AudioBitrate") == 0)
+               return lookup_audio_bitrate_option(gval);
+       else if (strcmp(name, "AudioSamplerate") == 0)
+               return lookup_audio_rate_option(gval);
+       else if (strcmp(name, "VideoFramerate") == 0)
+               return lookup_video_rate_option(gval);
+       else if (strcmp(name, "AudioMixdown") == 0)
+               return lookup_mix_option(gval);
+       else if (strcmp(name, "SourceAudioLang") == 0)
+               return lookup_audio_lang_option(gval);
+       else
+       {
+               return lookup_generic_string(find_combo_table(name), gval);
+       }
+       g_warning("ghb_lookup_combo_int() couldn't find %s", name);
+       return NULL;
 }
 
 void
-ghb_update_ui_combo_box(GtkBuilder *builder, const gchar *name, gint user_data, gboolean all)
+ghb_update_ui_combo_box(
+       signal_user_data_t *ud, 
+       const gchar *name, 
+       gint user_data, 
+       gboolean all)
 {
        GtkComboBox *combo = NULL;
        gint signal_id;
@@ -1961,7 +2197,7 @@ ghb_update_ui_combo_box(GtkBuilder *builder, const gchar *name, gint user_data,
                // Clearing a combo box causes a rash of "changed" events, even when
                // the active item is -1 (inactive).  To control things, I'm disabling
                // the event till things are settled down.
-               combo = GTK_COMBO_BOX(GHB_WIDGET(builder, name));
+               combo = GTK_COMBO_BOX(GHB_WIDGET(ud->builder, name));
                signal_id = g_signal_lookup("changed", GTK_TYPE_COMBO_BOX);
                if (signal_id > 0)
                {
@@ -1977,52 +2213,52 @@ ghb_update_ui_combo_box(GtkBuilder *builder, const gchar *name, gint user_data,
        }       
        if (all)
        {
-               audio_bitrate_opts_set(builder, "AudioBitrate");
-               audio_samplerate_opts_set(builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count);
-               video_rate_opts_set(builder, "VideoFramerate", hb_video_rates, hb_video_rates_count);
-               mix_opts_set(builder, "AudioMixdown");
-               language_opts_set(builder, "SourceAudioLang");
-               subtitle_opts_set(builder, "Subtitles", user_data);
-               title_opts_set(builder, "title");
-               audio_track_opts_set(builder, "AudioTrack", user_data);
-               generic_opts_set(builder, "VideoQualityGranularity", &vqual_granularity_opts);
-               generic_opts_set(builder, "PicturePAR", &par_opts);
-               generic_opts_set(builder, "PictureModulus", &alignment_opts);
-               generic_opts_set(builder, "LoggingLevel", &logging_opts);
-               generic_opts_set(builder, "FileFormat", &container_opts);
-               generic_opts_set(builder, "PictureDeinterlace", &deint_opts);
-               generic_opts_set(builder, "PictureDetelecine", &detel_opts);
-               generic_opts_set(builder, "PictureDecomb", &decomb_opts);
-               generic_opts_set(builder, "PictureDenoise", &denoise_opts);
-               generic_opts_set(builder, "VideoEncoder", &vcodec_opts);
-               generic_opts_set(builder, "AudioEncoder", &acodec_opts);
-               generic_opts_set(builder, "x264_direct", &direct_opts);
-               generic_opts_set(builder, "x264_b_adapt", &badapt_opts);
-               generic_opts_set(builder, "x264_me", &me_opts);
-               generic_opts_set(builder, "x264_subme", &subme_opts);
-               generic_opts_set(builder, "x264_analyse", &analyse_opts);
-               generic_opts_set(builder, "x264_trellis", &trellis_opts);
+               audio_bitrate_opts_set(ud->builder, "AudioBitrate");
+               audio_samplerate_opts_set(ud->builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count);
+               video_rate_opts_set(ud->builder, "VideoFramerate", hb_video_rates, hb_video_rates_count);
+               mix_opts_set(ud->builder, "AudioMixdown");
+               language_opts_set(ud->builder, "SourceAudioLang");
+               subtitle_opts_set(ud, "SubtitleTrack", user_data);
+               title_opts_set(ud->builder, "title");
+               audio_track_opts_set(ud->builder, "AudioTrack", user_data);
+               generic_opts_set(ud->builder, "VideoQualityGranularity", &vqual_granularity_opts);
+               generic_opts_set(ud->builder, "PicturePAR", &par_opts);
+               generic_opts_set(ud->builder, "PictureModulus", &alignment_opts);
+               generic_opts_set(ud->builder, "LoggingLevel", &logging_opts);
+               generic_opts_set(ud->builder, "FileFormat", &container_opts);
+               generic_opts_set(ud->builder, "PictureDeinterlace", &deint_opts);
+               generic_opts_set(ud->builder, "PictureDetelecine", &detel_opts);
+               generic_opts_set(ud->builder, "PictureDecomb", &decomb_opts);
+               generic_opts_set(ud->builder, "PictureDenoise", &denoise_opts);
+               generic_opts_set(ud->builder, "VideoEncoder", &vcodec_opts);
+               generic_opts_set(ud->builder, "AudioEncoder", &acodec_opts);
+               generic_opts_set(ud->builder, "x264_direct", &direct_opts);
+               generic_opts_set(ud->builder, "x264_b_adapt", &badapt_opts);
+               generic_opts_set(ud->builder, "x264_me", &me_opts);
+               generic_opts_set(ud->builder, "x264_subme", &subme_opts);
+               generic_opts_set(ud->builder, "x264_analyse", &analyse_opts);
+               generic_opts_set(ud->builder, "x264_trellis", &trellis_opts);
        }
        else
        {
                if (strcmp(name, "AudioBitrate") == 0)
-                       audio_bitrate_opts_set(builder, "AudioBitrate");
+                       audio_bitrate_opts_set(ud->builder, "AudioBitrate");
                else if (strcmp(name, "AudioSamplerate") == 0)
-                       audio_samplerate_opts_set(builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count);
+                       audio_samplerate_opts_set(ud->builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count);
                else if (strcmp(name, "VideoFramerate") == 0)
-                       video_rate_opts_set(builder, "VideoFramerate", hb_video_rates, hb_video_rates_count);
+                       video_rate_opts_set(ud->builder, "VideoFramerate", hb_video_rates, hb_video_rates_count);
                else if (strcmp(name, "AudioMixdown") == 0)
-                       mix_opts_set(builder, "AudioMixdown");
+                       mix_opts_set(ud->builder, "AudioMixdown");
                else if (strcmp(name, "SourceAudioLang") == 0)
-                       language_opts_set(builder, "SourceAudioLang");
-               else if (strcmp(name, "Subtitles") == 0)
-                       subtitle_opts_set(builder, "Subtitles", user_data);
+                       language_opts_set(ud->builder, "SourceAudioLang");
+               else if (strcmp(name, "SubtitleTrack") == 0)
+                       subtitle_opts_set(ud, "SubtitleTrack", user_data);
                else if (strcmp(name, "title") == 0)
-                       title_opts_set(builder, "title");
+                       title_opts_set(ud->builder, "title");
                else if (strcmp(name, "AudioTrack") == 0)
-                       audio_track_opts_set(builder, "AudioTrack", user_data);
+                       audio_track_opts_set(ud->builder, "AudioTrack", user_data);
                else
-                       generic_opts_set(builder, name, find_combo_table(name));
+                       generic_opts_set(ud->builder, name, find_combo_table(name));
        }
        if (handler_id > 0)
        {
@@ -2040,7 +2276,7 @@ init_ui_combo_boxes(GtkBuilder *builder)
        init_combo_box(builder, "VideoFramerate");
        init_combo_box(builder, "AudioMixdown");
        init_combo_box(builder, "SourceAudioLang");
-       init_combo_box(builder, "Subtitles");
+       init_combo_box(builder, "SubtitleTrack");
        init_combo_box(builder, "title");
        init_combo_box(builder, "AudioTrack");
        for (ii = 0; combo_name_map[ii].name != NULL; ii++)
@@ -2248,12 +2484,12 @@ ghb_set_default_bitrate_opts(GtkBuilder *builder, gint last_rate)
 static ghb_status_t hb_status;
 
 void
-ghb_combo_init(GtkBuilder *builder)
+ghb_combo_init(signal_user_data_t *ud)
 {
        // Set up the list model for the combos
-       init_ui_combo_boxes(builder);
+       init_ui_combo_boxes(ud->builder);
        // Populate all the combos
-       ghb_update_ui_combo_box(builder, NULL, 0, TRUE);
+       ghb_update_ui_combo_box(ud, NULL, 0, TRUE);
 }
 
 void
@@ -3699,24 +3935,42 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
        {
                job->x264opts =  NULL;
        }
+
+       const GValue *subtitle_list;
        gint subtitle;
-       subtitle = ghb_settings_get_int(js, "subtitle_index");
-       if (subtitle == -1)
-       {
-               job->indepth_scan = 1;
-       }
-       else if (subtitle >= 0)
+       
+       subtitle_list = ghb_settings_get_value(js, "subtitle_list");
+       count = ghb_array_len(subtitle_list);
+       for (ii = 0; ii < count; ii++)
        {
-       hb_subtitle_t * subt;
+               GValue *ssettings;
+               gboolean burned;
 
-               subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, subtitle);
-               if (subt != NULL)
+               ssettings = ghb_array_get_nth(subtitle_list, ii);
+
+               subtitle = ghb_settings_get_int(ssettings, "SubtitleTrack");
+               burned = ghb_settings_get_boolean(ssettings, "SubtitleBurned");
+               if (subtitle == -1)
+               {
+                       job->indepth_scan = 1;
+               }
+               else if (subtitle >= 0)
                {
-                       hb_list_add(job->list_subtitle, subt);
+               hb_subtitle_t * subt;
+
+                       subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, subtitle);
+                       if (subt != NULL)
+                       {
+                               if (!burned && job->mux == HB_MUX_MKV && 
+                                       subt->format == PICTURESUB)
+                               {
+                                       subt->dest = PASSTHRUSUB;
+                               }
+                               subt->force = ghb_settings_get_boolean(ssettings, "SubtitleForced");
+                               hb_list_add(job->list_subtitle, subt);
+                       }
                }
        }
-       gboolean forced_subtitles = ghb_settings_get_boolean(js, "SubtitlesForced");
-       job->subtitle_force = forced_subtitles;
 
        if (job->indepth_scan == 1)
        {
index d946b92..4517f44 100644 (file)
@@ -98,7 +98,7 @@ void ghb_vquality_range(
        gint *digits,
        gboolean *inverted);
 //const gchar* ghb_get_rate_string(gint rate, gint type);
-void ghb_combo_init(GtkBuilder *builder);
+void ghb_combo_init(signal_user_data_t *ud);
 void ghb_backend_init(gint debug);
 void ghb_backend_close(void);
 void ghb_add_job(GValue *js, gint unique_id);
@@ -136,10 +136,12 @@ void ghb_set_passthru_bitrate_opts(GtkBuilder *builder, gint bitrate);
 void ghb_set_default_bitrate_opts(GtkBuilder *builder, gint last_rate);
 void ghb_grey_combo_options(GtkBuilder *builder);
 void ghb_update_ui_combo_box(
-       GtkBuilder *builder, const gchar *name, gint user_data, gboolean all);
+       signal_user_data_t *ud, const gchar *name, gint user_data, gboolean all);
 gint ghb_find_audio_track(
-       gint titleindex, const gchar *lang, 
-       gint acodec, GHashTable *track_indices);
+       gint titleindex, const gchar *lang, gint acodec, GHashTable *track_indices);
+gint ghb_find_subtitle_track(
+       gint titleindex, const gchar *lang, GHashTable *track_indices);
+gint ghb_pick_subtitle_track(signal_user_data_t *ud);
 gint ghb_longest_title(void);
 gchar* ghb_build_x264opts_string(GValue *settings);
 GdkPixbuf* ghb_get_preview_image(
@@ -148,6 +150,8 @@ GdkPixbuf* ghb_get_preview_image(
 gint ghb_calculate_target_bitrate(GValue *settings, gint titleindex);
 gchar* ghb_dvd_volname(const gchar *device);
 gint ghb_get_title_number(gint titleindex);
+gint ghb_subtitle_track_source(signal_user_data_t *ud, gint track);
+const char* ghb_subtitle_track_source_name(signal_user_data_t *ud, gint track);
 
 gboolean ghb_validate_vquality(GValue *settings);
 gboolean ghb_validate_audio(signal_user_data_t *ud);
@@ -155,9 +159,10 @@ gboolean ghb_validate_video(signal_user_data_t *ud);
 gboolean ghb_validate_filters(signal_user_data_t *ud);
 gboolean ghb_validate_filter_string(const gchar *str, gint max_fields);
 void ghb_hb_cleanup(gboolean partial);
-gint ghb_lookup_combo_int(const gchar *name, const GValue *acodec);
-gdouble ghb_lookup_combo_double(const gchar *name, const GValue *acodec);
-const gchar* ghb_lookup_combo_option(const gchar *name, const GValue *acodec);
+gint ghb_lookup_combo_int(const gchar *name, const GValue *gval);
+gdouble ghb_lookup_combo_double(const gchar *name, const GValue *gval);
+const gchar* ghb_lookup_combo_option(const gchar *name, const GValue *gval);
+const gchar* ghb_lookup_combo_string(const gchar *name, const GValue *gval);
 gchar* ghb_get_tmp_dir();
 
 #endif // _HBBACKEND_H_
index eb858d0..be58588 100644 (file)
@@ -89,6 +89,9 @@
                <key>audio_list</key>
                <array>
                </array>
+               <key>subtitle_list</key>
+               <array>
+               </array>
                <key>vquality_type_bitrate</key>
                <false />
                <key>vquality_type_constant</key>
                <integer>0</integer>
                <key>PictureWidth</key>
                <integer>0</integer>
-               <key>SubtitlesForced</key>
-               <true />
                <key>VideoFramerate</key>
                <string>source</string>
                <key>VideoGrayScale</key>
                <integer>1</integer>
                <key>SourceAudioLang</key>
                <string>und</string>
-               <key>Subtitles</key>
-               <string>none</string>
+               <key>SubtitleList</key>
+               <array>
+                       <dict>
+                               <key>SubtitleLanguage</key>
+                               <string>und</string>
+                               <key>SubtitleForced</key>
+                               <false />
+                               <key>SubtitleBurned</key>
+                               <true />
+                       </dict>
+               </array>
                <key>VideoTurboTwoPass</key>
                <false />
                <key>UsesPictureFilters</key>
index 505142b..d7a15c1 100644 (file)
@@ -376,6 +376,67 @@ bind_audio_tree_model (signal_user_data_t *ud)
        g_debug("Done\n");
 }
 
+extern G_MODULE_EXPORT void subtitle_list_selection_changed_cb(void);
+extern G_MODULE_EXPORT void subtitle_forced_toggled_cb(void);
+extern G_MODULE_EXPORT void subtitle_burned_toggled_cb(void);
+
+// Create and bind the tree model to the tree view for the subtitle track list
+// Also, connect up the signal that lets us know the selection has changed
+static void
+bind_subtitle_tree_model (signal_user_data_t *ud)
+{
+       GtkCellRenderer *cell;
+       GtkTreeViewColumn *column;
+       GtkListStore *treestore;
+       GtkTreeView  *treeview;
+       GtkTreeSelection *selection;
+       GtkWidget *widget;
+
+       g_debug("bind_subtitle_tree_model ()\n");
+       treeview = GTK_TREE_VIEW(GHB_WIDGET (ud->builder, "subtitle_list"));
+       selection = gtk_tree_view_get_selection (treeview);
+       // 5 columns in model.  4 are visible, the other 1 is for storing
+       // values that I need
+       treestore = gtk_list_store_new(5, 
+                                                                       G_TYPE_STRING,
+                                                                       G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+                                                                       G_TYPE_STRING, G_TYPE_STRING);
+       gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(treestore));
+
+       cell = gtk_cell_renderer_text_new();
+       column = gtk_tree_view_column_new_with_attributes(
+                                                                       _("Track"), cell, "text", 0, NULL);
+       gtk_tree_view_append_column(treeview, GTK_TREE_VIEW_COLUMN(column));
+
+       cell = gtk_cell_renderer_toggle_new();
+       column = gtk_tree_view_column_new_with_attributes(
+                                                                       _("Forced Only"), cell, "active", 1, NULL);
+       gtk_tree_view_column_set_max_width (column, 50);
+       gtk_tree_view_append_column(treeview, GTK_TREE_VIEW_COLUMN(column));
+       g_signal_connect(cell, "toggled", subtitle_forced_toggled_cb, ud);
+
+       cell = gtk_cell_renderer_toggle_new();
+       gtk_cell_renderer_toggle_set_radio(GTK_CELL_RENDERER_TOGGLE(cell), TRUE);
+       column = gtk_tree_view_column_new_with_attributes(
+                                                                       _("Burned In"), cell, "active", 2, NULL);
+       gtk_tree_view_column_set_max_width (column, 50);
+       gtk_tree_view_append_column(treeview, GTK_TREE_VIEW_COLUMN(column));
+       g_signal_connect(cell, "toggled", subtitle_burned_toggled_cb, ud);
+
+       cell = gtk_cell_renderer_text_new();
+       column = gtk_tree_view_column_new_with_attributes(
+                                                                       _("Type"), cell, "text", 3, NULL);
+       gtk_tree_view_append_column(treeview, GTK_TREE_VIEW_COLUMN(column));
+
+
+       g_signal_connect(selection, "changed", subtitle_list_selection_changed_cb, ud);
+       // Need to disable remove and update buttons since there are initially
+       // no selections
+       widget = GHB_WIDGET (ud->builder, "subtitle_remove");
+       gtk_widget_set_sensitive(widget, FALSE);
+       g_debug("Done\n");
+}
+
 extern G_MODULE_EXPORT void presets_list_selection_changed_cb(void);
 extern G_MODULE_EXPORT void presets_drag_cb(void);
 extern G_MODULE_EXPORT void presets_drag_motion_cb(void);
@@ -642,12 +703,13 @@ main (int argc, char *argv[])
        buffer = gtk_text_view_get_buffer (textview);
        g_signal_connect(buffer, "changed", (GCallback)x264_entry_changed_cb, ud);
 
-       ghb_combo_init(ud->builder);
+       ghb_combo_init(ud);
 
        g_debug("ud %p\n", ud);
        g_debug("ud->builder %p\n", ud->builder);
 
        bind_audio_tree_model(ud);
+       bind_subtitle_tree_model(ud);
        bind_presets_tree_model(ud);
        bind_queue_tree_model(ud);
        bind_chapter_tree_model(ud);
index 25a5e96..35f7b9c 100644 (file)
@@ -20,6 +20,7 @@
 #include "settings.h"
 #include "callbacks.h"
 #include "audiohandler.h"
+#include "subtitlehandler.h"
 #include "hb-backend.h"
 #include "plist.h"
 #include "resources.h"
@@ -2057,15 +2058,25 @@ export_value_xlat(GValue *dict)
        gval = export_value_xlat2(denoise_xlat, lin_val, G_TYPE_INT);
        if (gval)
                ghb_dict_insert(dict, g_strdup(key), gval);
-       key = "Subtitles";
-       lin_val = ghb_dict_lookup(dict, key);
-       gval = export_subtitle_xlat2(lin_val);
-       if (gval)
-               ghb_dict_insert(dict, g_strdup(key), gval);
+
+       GValue *slist;
+       GValue *sdict;
+       gint count, ii;
+
+       slist = ghb_dict_lookup(dict, "SubtitleList");
+       count = ghb_array_len(slist);
+       for (ii = 0; ii < count; ii++)
+       {
+               sdict = ghb_array_get_nth(slist, ii);
+               key = "SubtitleLanguage";
+               lin_val = ghb_dict_lookup(sdict, key);
+               gval = export_subtitle_xlat2(lin_val);
+               if (gval)
+                       ghb_dict_insert(sdict, g_strdup(key), gval);
+       }
 
        GValue *alist;
        GValue *adict;
-       gint count, ii;
 
        alist = ghb_dict_lookup(dict, "AudioList");
        count = ghb_array_len(alist);
@@ -2132,13 +2143,34 @@ import_value_xlat2(
                                return gval;
                        }
                }
-               //g_warning("Can't map value: (%s)", str);
                g_free(str);
        }
        else
        {
-               g_warning("Bad key: (%s)", key);
-               return NULL;
+               gint ii;
+               gchar *str;
+               GValue *sval;
+
+               str = ghb_value_string(mac_val);
+               for (ii = 0; value_map[ii].mac_val; ii++)
+               {
+                       if (strcmp(str, value_map[ii].mac_val) == 0)
+                       {
+                               sval = ghb_string_value_new(value_map[ii].lin_val);
+                               g_free(str);
+                               gval = ghb_value_new(G_VALUE_TYPE(mac_val));
+                               if (!g_value_transform(sval, gval))
+                               {
+                                       g_warning("can't transform");
+                                       ghb_value_free(gval);
+                                       ghb_value_free(sval);
+                                       return NULL;
+                               }
+                               ghb_value_free(sval);
+                               return gval;
+                       }
+               }
+               g_free(str);
        }
        return NULL;
 }
@@ -2185,19 +2217,82 @@ import_value_xlat(GValue *dict)
        gval = import_value_xlat2(defaults, denoise_xlat, key, mac_val);
        if (gval)
                ghb_dict_insert(dict, g_strdup(key), gval);
-       key = "Subtitles";
-       mac_val = ghb_dict_lookup(dict, key);
-       gval = import_subtitle_xlat2(mac_val);
-       if (gval)
-               ghb_dict_insert(dict, g_strdup(key), gval);
+
+       GValue *sdeflist;
+       GValue *sdefaults;
+       GValue *slist;
+       GValue *sdict;
+       gint count, ii;
+
+       sdeflist = ghb_dict_lookup(defaults, "SubtitleList");
+       if (sdeflist)
+       {
+               slist = ghb_dict_lookup(dict, "SubtitleList");
+               if (slist)
+               {
+                       sdefaults = ghb_array_get_nth(sdeflist, 0);
+                       count = ghb_array_len(slist);
+                       for (ii = 0; ii < count; ii++)
+                       {
+                               sdict = ghb_array_get_nth(slist, ii);
+                               key = "SubtitleLanguage";
+                               mac_val = ghb_dict_lookup(sdict, key);
+                               gval = import_subtitle_xlat2(mac_val);
+                               if (gval)
+                                       ghb_dict_insert(sdict, g_strdup(key), gval);
+                       }
+               
+               }
+               else
+               {
+                       key = "Subtitles";
+                       mac_val = ghb_dict_lookup(dict, key);
+                       if (mac_val)
+                       {
+                               gchar *lang;
+       
+                               gval = import_subtitle_xlat2(mac_val);
+                               lang = ghb_value_string(gval);
+                               if (lang && strcmp(lang, "none") != 0 && !slist)
+                               {
+                                       slist = ghb_array_value_new(8);
+                                       sdict = ghb_dict_value_new();
+                                       ghb_dict_insert(dict, g_strdup("SubtitleList"), slist);
+                                       ghb_array_append(slist, sdict);
+                                       ghb_dict_insert(sdict, g_strdup("SubtitleLanguage"), gval);
+                                       gval = ghb_dict_lookup(dict, "SubtitlesForced");
+                                       if (gval != NULL)
+                                       {
+                                               ghb_dict_insert(sdict, g_strdup("SubtitleForced"), 
+                                                                               ghb_value_dup(gval));
+                                       }
+                                       else
+                                       {
+                                               ghb_dict_insert(sdict, g_strdup("SubtitleForced"), 
+                                                                               ghb_boolean_value_new(FALSE));
+                                       }
+                                       ghb_dict_insert(sdict, g_strdup("SubtitleBurned"),
+                                                                       ghb_boolean_value_new(TRUE));
+                               }
+                               else
+                               {
+                                       ghb_value_free(gval);
+                               }
+                               if (lang)
+                                       g_free(lang);
+                       }
+               }
+       }
+       ghb_dict_remove(dict, "Subtitles");
+       ghb_dict_remove(dict, "SubtitlesForced");
+
 
        GValue *alist;
        GValue *adict;
        GValue *adefaults;
        GValue *adeflist;
-       gint count, ii;
 
-       adeflist = ghb_dict_lookup(dict, "AudioList");
+       adeflist = ghb_dict_lookup(defaults, "AudioList");
        if (adeflist)
        {
                adefaults = ghb_array_get_nth(adeflist, 0);
@@ -2847,6 +2942,16 @@ update_audio_presets(signal_user_data_t *ud)
        ghb_settings_set_value(ud->settings, "AudioList", audio_list);
 }
 
+static void
+update_subtitle_presets(signal_user_data_t *ud)
+{
+       g_debug("update_subtitle_presets");
+       const GValue *subtitle_list;
+
+       subtitle_list = ghb_settings_get_value(ud->settings, "subtitle_list");
+       ghb_settings_set_value(ud->settings, "SubtitleList", subtitle_list);
+}
+
 void
 enforce_preset_type(signal_user_data_t *ud, const GValue *path)
 {
@@ -2940,6 +3045,7 @@ presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
                {
                        // Construct the audio settings presets from the current audio list
                        update_audio_presets(ud);
+                       update_subtitle_presets(ud);
                        settings_save(ud, dest);
                }
                ghb_value_free(dest);
@@ -3435,6 +3541,7 @@ presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_
                        gint titleindex;
                        titleindex = ghb_settings_combo_int(ud->settings, "title");
                        ghb_set_pref_audio(titleindex, ud);
+                       ghb_set_pref_subtitle(titleindex, ud);
                        ghb_settings_set_boolean(ud->settings, "preset_modified", FALSE);
                        if (ghb_get_title_info (&tinfo, titleindex))
                        {
index 8ff5441..1ac36ca 100644 (file)
@@ -646,7 +646,6 @@ queue_add(signal_user_data_t *ud)
        GValue *settings;
        gint titleindex;
        gint titlenum;
-       gint sub;
        
        g_debug("queue_add ()");
        if (!validate_settings(ud))
@@ -663,9 +662,6 @@ queue_add(signal_user_data_t *ud)
                ud->queue = ghb_array_value_new(32);
        // Make a copy of current settings to be used for the new job
        settings = ghb_value_dup(ud->settings);
-       sub = ghb_settings_combo_int(settings, "Subtitles");
-       ghb_settings_set_int(settings, "subtitle_index", sub);
-       
        ghb_settings_set_int(settings, "job_status", GHB_QUEUE_PENDING);
        ghb_settings_set_int(settings, "job_unique_id", 0);
        titleindex = ghb_settings_combo_int(settings, "title");
index c665770..41dd26b 100644 (file)
@@ -170,6 +170,12 @@ ghb_settings_combo_option(const GValue *settings, const gchar *key)
        return ghb_lookup_combo_option(key, ghb_settings_get_value(settings, key));
 }
 
+const gchar*
+ghb_settings_combo_string(const GValue *settings, const gchar *key)
+{
+       return ghb_lookup_combo_string(key, ghb_settings_get_value(settings, key));
+}
+
 // Map widget names to setting keys
 // Widgets that map to settings have names
 // of this format: s_<setting key>
index 8c2cac8..072baf0 100644 (file)
@@ -86,6 +86,7 @@ gchar* ghb_settings_get_string(const GValue *settings, const gchar *key);
 gint ghb_settings_combo_int(const GValue *settings, const gchar *key);
 gdouble ghb_settings_combo_double(const GValue *settings, const gchar *key);
 const gchar* ghb_settings_combo_option(const GValue *settings, const gchar *key);
+const gchar* ghb_settings_combo_string(const GValue *settings, const gchar *key);
 
 GValue* ghb_widget_value(GtkWidget *widget);
 gchar* ghb_widget_string(GtkWidget *widget);
index 5163189..224b40c 100644 (file)
@@ -238,7 +238,6 @@ struct hb_job_s
 
     int indepth_scan;
     hb_subtitle_t ** select_subtitle;
-    int subtitle_force;
     char * native_language;
 
     int             angle;              // dvd angle to encode
@@ -445,6 +444,7 @@ struct hb_subtitle_s
     enum subtype { PICTURESUB, TEXTSUB } format;
     enum subsource { VOBSUB, SRTSUB, CC608SUB, CC708SUB } source;
     enum subdest { RENDERSUB, PASSTHRUSUB } dest;
+    int  force;
     char lang[1024];
     char iso639_2[4];
     uint8_t type; /* Closed Caption, Childrens, Directors etc */
@@ -639,6 +639,9 @@ struct hb_work_object_s
     /* Pointer hb_audio_t so we have access to the info in the audio worker threads. */
     hb_audio_t        * audio;
 
+    /* Pointer hb_subtitle_t so we have access to the info in the subtitle worker threads. */
+    hb_subtitle_t     * subtitle;
+
     hb_work_private_t * private_data;
 
     hb_thread_t       * thread;
index fd1f891..e5633d5 100644 (file)
@@ -8,27 +8,27 @@
 
 struct hb_work_private_s
 {
-    hb_job_t * job;
-
-    uint8_t    buf[0xFFFF];
-    int        size_sub;
-    int        size_got;
-    int        size_rle;
-    int64_t    pts;
-    int64_t    pts_start;
-    int64_t    pts_stop;
-    int        pts_forced;
-    int        x;
-    int        y;
-    int        width;
-    int        height;
-    int        stream_id;
-
-    int        offsets[2];
-    uint8_t    lum[4];
-    uint8_t    chromaU[4];
-    uint8_t    chromaV[4];
-    uint8_t    alpha[4];
+    hb_job_t    * job;
+
+    hb_buffer_t * buf;
+    int           size_sub;
+    int           size_got;
+    int           size_rle;
+    int64_t       pts;
+    int64_t       pts_start;
+    int64_t       pts_stop;
+    int           pts_forced;
+    int           x;
+    int           y;
+    int           width;
+    int           height;
+    int           stream_id;
+
+    int           offsets[2];
+    uint8_t       lum[4];
+    uint8_t       chromaU[4];
+    uint8_t       chromaV[4];
+    uint8_t       alpha[4];
 };
 
 static hb_buffer_t * Decode( hb_work_object_t * );
@@ -76,7 +76,10 @@ int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
             pv->size_sub = size_sub;
             pv->size_rle = size_rle;
 
-            memcpy( pv->buf, in->data, in->size );
+            pv->buf      = hb_buffer_init( 0xFFFF );
+            memcpy( pv->buf->data, in->data, in->size );
+            pv->buf->id = in->id;
+            pv->buf->sequence = in->sequence;
             pv->size_got = in->size;
             pv->pts      = in->start;
         }
@@ -86,7 +89,9 @@ int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
         /* We are waiting for the end of the current subtitle */
         if( in->size <= pv->size_sub - pv->size_got )
         {
-            memcpy( pv->buf + pv->size_got, in->data, in->size );
+            memcpy( pv->buf->data + pv->size_got, in->data, in->size );
+            pv->buf->id = in->id;
+            pv->buf->sequence = in->sequence;
             pv->size_got += in->size;
             if( in->start >= 0 )
             {
@@ -99,11 +104,14 @@ int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
 
     if( pv->size_sub && pv->size_sub == pv->size_got )
     {
+        pv->buf->size = pv->size_sub;
+
         /* We got a complete subtitle, decode it */
         *buf_out = Decode( w );
 
         if( buf_out && *buf_out )
         {
+            (*buf_out)->id = in->id;
             (*buf_out)->sequence = in->sequence;
         }
 
@@ -145,6 +153,7 @@ static void ParseControls( hb_work_object_t * w )
     hb_job_t * job = pv->job;
     hb_title_t * title = job->title;
     hb_subtitle_t * subtitle;
+    uint8_t * buf = pv->buf->data;
 
     int i, n;
     int command;
@@ -161,12 +170,12 @@ static void ParseControls( hb_work_object_t * w )
 
     for( i = pv->size_rle; ; )
     {
-        date = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
-        next = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
+        date = ( buf[i] << 8 ) | buf[i+1]; i += 2;
+        next = ( buf[i] << 8 ) | buf[i+1]; i += 2;
 
         for( ;; )
         {
-            command = pv->buf[i++];
+            command = buf[i++];
 
             /*
              * There are eight commands available for
@@ -224,10 +233,10 @@ static void ParseControls( hb_work_object_t * w )
                     int colors[4];
                     int j;
 
-                    colors[0] = (pv->buf[i+0]>>4)&0x0f;
-                    colors[1] = (pv->buf[i+0])&0x0f;
-                    colors[2] = (pv->buf[i+1]>>4)&0x0f;
-                    colors[3] = (pv->buf[i+1])&0x0f;
+                    colors[0] = (buf[i+0]>>4)&0x0f;
+                    colors[1] = (buf[i+0])&0x0f;
+                    colors[2] = (buf[i+1]>>4)&0x0f;
+                    colors[3] = (buf[i+1])&0x0f;
 
                     for( j = 0; j < 4; j++ )
                     {
@@ -267,10 +276,10 @@ static void ParseControls( hb_work_object_t * w )
                      */
                     uint8_t    alpha[4];
 
-                    alpha[3] = (pv->buf[i+0]>>4)&0x0f;
-                    alpha[2] = (pv->buf[i+0])&0x0f;
-                    alpha[1] = (pv->buf[i+1]>>4)&0x0f;
-                    alpha[0] = (pv->buf[i+1])&0x0f;
+                    alpha[3] = (buf[i+0]>>4)&0x0f;
+                    alpha[2] = (buf[i+0])&0x0f;
+                    alpha[1] = (buf[i+1]>>4)&0x0f;
+                    alpha[0] = (buf[i+1])&0x0f;
 
 
                     int lastAlpha = pv->alpha[3] + pv->alpha[2] + pv->alpha[1] + pv->alpha[0];
@@ -296,17 +305,17 @@ static void ParseControls( hb_work_object_t * w )
                 }
                 case 0x05: // 0x05 - SET_DAREA - defines the display area
                 {
-                    pv->x     = (pv->buf[i+0]<<4) | ((pv->buf[i+1]>>4)&0x0f);
-                    pv->width = (((pv->buf[i+1]&0x0f)<<8)| pv->buf[i+2]) - pv->x + 1;
-                    pv->y     = (pv->buf[i+3]<<4)| ((pv->buf[i+4]>>4)&0x0f);
-                    pv->height = (((pv->buf[i+4]&0x0f)<<8)| pv->buf[i+5]) - pv->y + 1;
+                    pv->x     = (buf[i+0]<<4) | ((buf[i+1]>>4)&0x0f);
+                    pv->width = (((buf[i+1]&0x0f)<<8)| buf[i+2]) - pv->x + 1;
+                    pv->y     = (buf[i+3]<<4)| ((buf[i+4]>>4)&0x0f);
+                    pv->height = (((buf[i+4]&0x0f)<<8)| buf[i+5]) - pv->y + 1;
                     i += 6;
                     break;
                 }
                 case 0x06: // 0x06 - SET_DSPXA - defines the pixel data addresses
                 {
-                    pv->offsets[0] = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
-                    pv->offsets[1] = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
+                    pv->offsets[0] = ( buf[i] << 8 ) | buf[i+1]; i += 2;
+                    pv->offsets[1] = ( buf[i] << 8 ) | buf[i+1]; i += 2;
                     break;
                 }
             }
@@ -475,7 +484,7 @@ static hb_buffer_t * Decode( hb_work_object_t * w )
     /* Get infos about the subtitle */
     ParseControls( w );
 
-    if( job->indepth_scan || ( job->subtitle_force && pv->pts_forced == 0 ) )
+    if( job->indepth_scan || ( w->subtitle->force && pv->pts_forced == 0 ) )
     {
         /*
          * Don't encode subtitles when doing a scan.
@@ -486,11 +495,18 @@ static hb_buffer_t * Decode( hb_work_object_t * w )
         return NULL;
     }
 
+    if (w->subtitle->dest == PASSTHRUSUB)
+    {
+        pv->buf->start  = pv->pts_start;
+        pv->buf->stop   = pv->pts_stop;
+        return pv->buf;
+    }
+
     /* Do the actual decoding now */
     buf_raw = malloc( ( pv->width * pv->height ) * 4 );
 
 #define GET_NEXT_NIBBLE code = ( code << 4 ) | ( ( ( *offset & 1 ) ? \
-( pv->buf[((*offset)>>1)] & 0xF ) : ( pv->buf[((*offset)>>1)] >> 4 ) ) ); \
+( pv->buf->data[((*offset)>>1)] & 0xF ) : ( pv->buf->data[((*offset)>>1)] >> 4 ) ) ); \
 (*offset)++
 
     offsets[0] = pv->offsets[0] * 2;
@@ -547,6 +563,8 @@ static hb_buffer_t * Decode( hb_work_object_t * w )
         }
     }
 
+    hb_buffer_close( &pv->buf );
+
     /* Crop subtitle (remove transparent borders) */
     buf = CropSubtitle( w, buf_raw );
 
index 5fde4cb..515de1e 100644 (file)
@@ -619,11 +619,15 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t )
         lang = lang_for_code( ifo->vtsi_mat->vts_subp_attr[i].lang_code );
 
         subtitle = calloc( sizeof( hb_subtitle_t ), 1 );
+        subtitle->track = i+1;
         subtitle->id = ( ( 0x20 + position ) << 8 ) | 0xbd;
         snprintf( subtitle->lang, sizeof( subtitle->lang ), "%s",
              strlen(lang->native_name) ? lang->native_name : lang->eng_name);
         snprintf( subtitle->iso639_2, sizeof( subtitle->iso639_2 ), "%s",
                   lang->iso639_2);
+        subtitle->format = PICTURESUB;
+        subtitle->source = VOBSUB;
+        subtitle->dest   = RENDERSUB;  // By default render (burn-in) the VOBSUB.
 
         subtitle->type = lang_extension;
 
index ee49d7a..20a9879 100644 (file)
@@ -26,9 +26,15 @@ int encsubInit( hb_work_object_t * w, hb_job_t * job )
 int encsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
                 hb_buffer_t ** buf_out )
 {
-    hb_work_private_t * pv = w->private_data;
     hb_buffer_t * in = *buf_in;
 
+    if (w->subtitle->source != VOBSUB)
+    {
+        // Invalid source, send EOF, this shouldn't ever happen
+        hb_log("encvobsub: invalid subtitle source");
+        hb_buffer_close( buf_in );
+        *buf_out = hb_buffer_init(0);
+    }
     if ( in->size <= 0 )
     {
         /* EOF on input stream - send it downstream & say that we're done */
@@ -38,10 +44,14 @@ int encsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
     }
 
     /*
-     * Don't do anything at present, just pass the buffer on.
+     * Not much to do, just pass the buffer on.
+     * Some day, we may re-encode bd subtitles here ;)
      */
-    *buf_out = in;
-    *buf_in = NULL;
+    if (buf_out)
+    {
+        *buf_out = in;
+        *buf_in = NULL;
+    }
 
     return HB_WORK_OK; 
 }
index c756f56..7337874 100644 (file)
@@ -191,6 +191,7 @@ void hb_buffer_close( hb_buffer_t ** _b )
     if( buffer_pool && b->data && !hb_fifo_is_full( buffer_pool ) )
     {
         hb_fifo_push_head( buffer_pool, b );
+        *_b = NULL;
         return;
     }
     /* either the pool is full or this size doesn't use a pool - free the buf */
index c3d6279..04f9ae5 100644 (file)
@@ -34,6 +34,27 @@ struct hb_mux_data_s
     int       sub_format;
 };
 
+static int yuv2rgb(int yuv)
+{
+    double y, Cr, Cb;
+    int r, g, b;
+
+    y =  (yuv >> 16) & 0xff;
+    Cr = (yuv >>  8) & 0xff;
+    Cb = (yuv)       & 0xff;
+
+    r = 1.164 * (y - 16)                      + 2.018 * (Cb - 128);
+    g = 1.164 * (y - 16) - 0.813 * (Cr - 128) - 0.391 * (Cb - 128);
+    b = 1.164 * (y - 16) + 1.596 * (Cr - 128);
+    r = (r < 0) ? 0 : r;
+    g = (g < 0) ? 0 : g;
+    b = (b < 0) ? 0 : b;
+    r = (r > 255) ? 255 : r;
+    g = (g > 255) ? 255 : g;
+    b = (b > 255) ? 255 : b;
+    return (r << 16) | (g << 8) | b;
+}
+
 /**********************************************************************
  * MKVInit
  **********************************************************************
@@ -48,7 +69,7 @@ static int MKVInit( hb_mux_object_t * m )
 
     uint8_t         *avcC = NULL;
     uint8_t         default_track_flag = 1;
-    int             avcC_len, i;
+    int             avcC_len, i, j;
     ogg_packet      *ogg_headers[3];
     mk_TrackConfig *track;
 
@@ -261,7 +282,7 @@ static int MKVInit( hb_mux_object_t * m )
     for( i = 0; i < hb_list_count( title->list_subtitle ); i++ )
     {
         hb_subtitle_t * subtitle;
-        uint32_t      * palette;
+        uint32_t        rgb[16];
         char            subidx[2048];
         int             len;
 
@@ -270,28 +291,39 @@ static int MKVInit( hb_mux_object_t * m )
             continue;
 
         memset(track, 0, sizeof(mk_TrackConfig));
+        switch (subtitle->format)
+        {
+            case PICTURESUB:
+                track->codecID = MK_SUBTITLE_VOBSUB;
+                for (j = 0; j < 16; j++)
+                    rgb[j] = yuv2rgb(title->palette[j]);
+                len = snprintf(subidx, 2048, subidx_fmt, 
+                        title->width, title->height,
+                        0, 0, "OFF",
+                        rgb[0], rgb[1], rgb[2], rgb[3],
+                        rgb[4], rgb[5], rgb[6], rgb[7],
+                        rgb[8], rgb[9], rgb[10], rgb[11],
+                        rgb[12], rgb[13], rgb[14], rgb[15]);
+                track->codecPrivate = subidx;
+                track->codecPrivateSize = len + 1;
+                break;
+            case TEXTSUB:
+                track->codecID = MK_SUBTITLE_UTF8;
+                break;
+            default:
+                continue;
+        }
 
         mux_data = calloc(1, sizeof( hb_mux_data_t ) );
         subtitle->mux_data = mux_data;
         mux_data->subtitle = 1;
         mux_data->sub_format = subtitle->format;
         
-        palette = title->palette;
-        len = snprintf(subidx, 2048, subidx_fmt, title->width, title->height,
-                 0, 0, "OFF",
-                 palette[0], palette[1], palette[2], palette[3],
-                 palette[4], palette[5], palette[6], palette[7],
-                 palette[8], palette[9], palette[10], palette[11],
-                 palette[12], palette[13], palette[14], palette[15]);
-        track->codecPrivate = subidx;
-        track->codecPrivateSize = len + 1;
-        track->codecID = MK_SUBTITLE_VOBSUB;
         track->flagEnabled = 1;
         track->trackType = MK_TRACK_SUBTITLE;
         track->language = subtitle->iso639_2;
 
         mux_data->track = mk_createTrack(m->file, track);
-
     }
 
     if( mk_writeHeader( m->file, "HandBrake " HB_PROJECT_VERSION) < 0 )
@@ -362,19 +394,33 @@ static int MKVMux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
                 *job->die = 1;
             }
             mk_addFrameData(m->file, mux_data->track, op->packet, op->bytes);
-            mk_setFrameFlags(m->file, mux_data->track, timecode, 1);
+            mk_setFrameFlags(m->file, mux_data->track, timecode, 1, 0);
             return 0;
         }
     }
     else if ( mux_data->subtitle )
     {
         timecode = buf->start * TIMECODE_SCALE;
+        if( mk_startFrame(m->file, mux_data->track) < 0)
+        {
+            hb_error( "Failed to write frame to output file, Disk Full?" );
+            *job->die = 1;
+        }
         if( mux_data->sub_format == TEXTSUB )
         {
-            hb_log("MuxMKV: Text Sub:%lld: %s", buf->start, buf->data);
-            // TODO: add CC data to track
-            return 0;
+            uint64_t   duration;
+
+            duration = buf->stop * TIMECODE_SCALE - timecode;
+            mk_addFrameData(m->file, mux_data->track, buf->data, buf->size);
+            mk_setFrameFlags(m->file, mux_data->track, timecode, 1, duration);
         }
+        else
+        {
+            mk_addFrameData(m->file, mux_data->track, buf->data, buf->size);
+            mk_setFrameFlags(m->file, mux_data->track, timecode, 1, 0);
+        }
+        mk_flushFrame(m->file, mux_data->track);
+        return 0;
     }
     else
     {
@@ -391,7 +437,7 @@ static int MKVMux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
                 *job->die = 1;
             }
             mk_addFrameData(m->file, mux_data->track, op->packet, op->bytes);
-            mk_setFrameFlags(m->file, mux_data->track, timecode, 1);
+            mk_setFrameFlags(m->file, mux_data->track, timecode, 1, 0);
             return 0;
         }
     }
@@ -403,7 +449,10 @@ static int MKVMux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
     }
     mk_addFrameData(m->file, mux_data->track, buf->data, buf->size);
     mk_setFrameFlags(m->file, mux_data->track, timecode,
-                     ((job->vcodec == HB_VCODEC_X264 && mux_data == job->mux_data) ? (buf->frametype == HB_FRAME_IDR) : ((buf->frametype & HB_FRAME_KEY) != 0)) );
+                     ((job->vcodec == HB_VCODEC_X264 && 
+                       mux_data == job->mux_data) ? 
+                            (buf->frametype == HB_FRAME_IDR) : 
+                            ((buf->frametype & HB_FRAME_KEY) != 0)), 0 );
     return 0;
 }
 
index dd47815..c865ea8 100644 (file)
@@ -527,7 +527,7 @@ static hb_fifo_t ** GetFifoForId( hb_job_t * job, int id )
         subtitle =  hb_list_item( title->list_subtitle, i );
         if (id == subtitle->id) {
             subtitle->hits++;
-            if( !job->indepth_scan || job->subtitle_force )
+            if( !job->indepth_scan || subtitle->force )
             {
                 /*
                  * Pass the subtitles to be processed if we are not scanning, or if
index 1001ed5..d769079 100644 (file)
@@ -485,7 +485,9 @@ static void SyncVideo( hb_work_object_t * w )
                        when the second one starts */
                     sub2 = hb_fifo_see2( subtitle->fifo_raw );
                     if( sub2 && sub->stop > sub2->start )
+                    {
                         sub->stop = sub2->start;
+                    }
                     
                     // hb_log("0x%x: video seq: %lld  subtitle sequence: %lld",
                     //       sub, cur->sequence, sub->sequence);
@@ -508,120 +510,160 @@ static void SyncVideo( hb_work_object_t * w )
                          * and we'll deal with it in the next block of
                          * code.
                          */
-                        break;
-                    }
-                    
-                    /*
-                     * The subtitle is older than this picture, trash it
-                     */
-                    sub = hb_fifo_get( subtitle->fifo_raw );
-                    hb_buffer_close( &sub );
-                }
-                
-                if( sub && sub->size == 0 )
-                {
-                    /* 
-                     * Continue immediately on subtitle EOF
-                     */
-                    break;
-                }
 
-                /*
-                 * There is a valid subtitle, is it time to display it?
-                 */
-                if( sub )
-                {
-                    if( sub->stop > sub->start)
-                    {
                         /*
-                         * Normal subtitle which ends after it starts, check to
-                         * see that the current video is between the start and end.
+                         * There is a valid subtitle, is it time to display it?
                          */
-                        if( cur->start > sub->start &&
-                            cur->start < sub->stop )
+                        if( sub->stop > sub->start)
                         {
                             /*
-                             * We should be playing this, so leave the
-                             * subtitle in place.
-                             *
-                             * fall through to display
+                             * Normal subtitle which ends after it starts, 
+                             * check to see that the current video is between 
+                             * the start and end.
                              */
-                            if( ( sub->stop - sub->start ) < ( 3 * 90000 ) )
+                            if( cur->start > sub->start &&
+                                cur->start < sub->stop )
                             {
                                 /*
-                                 * Subtitle is on for less than three seconds, extend
-                                 * the time that it is displayed to make it easier
-                                 * to read. Make it 3 seconds or until the next
-                                 * subtitle is displayed.
-                                 *
-                                 * This is in response to Indochine which only
-                                 * displays subs for 1 second - too fast to read.
-                                 */
-                                sub->stop = sub->start + ( 3 * 90000 );
+                                * We should be playing this, so leave the
+                                * subtitle in place.
+                                *
+                                * fall through to display
+                                */
+                                if( ( sub->stop - sub->start ) < ( 3 * 90000 ) )
+                                {
+                                    /*
+                                     * Subtitle is on for less than three 
+                                     * seconds, extend the time that it is 
+                                     * displayed to make it easier to read. 
+                                     * Make it 3 seconds or until the next
+                                     * subtitle is displayed.
+                                     *
+                                     * This is in response to Indochine which 
+                                     * only displays subs for 1 second - 
+                                     * too fast to read.
+                                     */
+                                    sub->stop = sub->start + ( 3 * 90000 );
                                 
-                                sub2 = hb_fifo_see2( subtitle->fifo_raw );
+                                    sub2 = hb_fifo_see2( subtitle->fifo_raw );
                                 
-                                if( sub2 && sub->stop > sub2->start )
-                                {
-                                    sub->stop = sub2->start;
+                                    if( sub2 && sub->stop > sub2->start )
+                                    {
+                                        sub->stop = sub2->start;
+                                    }
                                 }
                             }
+                            else
+                            {
+                                /*
+                                 * Defer until the play point is within 
+                                 * the subtitle
+                                 */
+                                sub = NULL;
+                            }
                         }
                         else
                         {
                             /*
-                             * Defer until the play point is within the subtitle
+                             * The end of the subtitle is less than the start, 
+                             * this is a sign of a PTS discontinuity.
                              */
-                            sub = NULL;
+                            if( sub->start > cur->start )
+                            {
+                                /*
+                                 * we haven't reached the start time yet, or
+                                 * we have jumped backwards after having
+                                 * already started this subtitle.
+                                 */
+                                if( cur->start < sub->stop )
+                                {
+                                    /*
+                                     * We have jumped backwards and so should
+                                     * continue displaying this subtitle.
+                                     *
+                                     * fall through to display.
+                                     */
+                                }
+                                else
+                                {
+                                    /*
+                                     * Defer until the play point is 
+                                     * within the subtitle
+                                     */
+                                    sub = NULL;
+                                }
+                            } else {
+                                /*
+                                * Play this subtitle as the start is 
+                                * greater than our video point.
+                                *
+                                * fall through to display/
+                                */
+                            }
                         }
+                       break;
                     }
                     else
                     {
+                    
                         /*
-                         * The end of the subtitle is less than the start, this is a
-                         * sign of a PTS discontinuity.
+                         * The subtitle is older than this picture, trash it
                          */
-                        if( sub->start > cur->start )
+                        sub = hb_fifo_get( subtitle->fifo_raw );
+                        hb_buffer_close( &sub );
+                    }
+                }
+                
+                /* If we have a subtitle for this picture, copy it */
+                /* FIXME: we should avoid this memcpy */
+                if( sub )
+                {
+                    if( sub->size > 0 )
+                    {
+                        if( subtitle->dest == RENDERSUB )
                         {
-                            /*
-                             * we haven't reached the start time yet, or
-                             * we have jumped backwards after having
-                             * already started this subtitle.
-                             */
-                            if( cur->start < sub->stop )
-                            {
-                                /*
-                                 * We have jumped backwards and so should
-                                 * continue displaying this subtitle.
-                                 *
-                                 * fall through to display.
-                                 */
-                            }
-                            else
+                            if ( cur->sub == NULL )
                             {
                                 /*
-                                 * Defer until the play point is within the subtitle
+                                 * Tack onto the video buffer for rendering
                                  */
-                                sub = NULL;
+                                cur->sub         = hb_buffer_init( sub->size );
+                                cur->sub->x      = sub->x;
+                                cur->sub->y      = sub->y;
+                                cur->sub->width  = sub->width;
+                                cur->sub->height = sub->height;
+                                memcpy( cur->sub->data, sub->data, sub->size ); 
                             }
                         } else {
                             /*
-                             * Play this subtitle as the start is greater than our
-                             * video point.
-                             *
-                             * fall through to display/
+                             * Pass-Through, pop it off of the raw queue, 
+                             * rewrite times and make it available to be 
+                             * reencoded.
                              */
+                            uint64_t sub_duration;
+                            sub = hb_fifo_get( subtitle->fifo_raw );
+                            sub_duration = sub->stop - sub->start;
+                            sub->start = cur->start;
+                            buf_tmp = hb_fifo_see( job->fifo_raw );
+                            int64_t duration = buf_tmp->start - cur->start;
+                            sub->stop = sub->start + duration;
+                            hb_fifo_push( subtitle->fifo_sync, sub );
+                        }
+                    } else {
+                        /*
+                        * EOF - consume for rendered, else pass through
+                        */
+                        if( subtitle->dest == RENDERSUB )
+                        {
+                            sub = hb_fifo_get( subtitle->fifo_raw );
+                            hb_buffer_close( &sub );
+                        } else {
+                            sub = hb_fifo_get( subtitle->fifo_raw );
+                            hb_fifo_push( subtitle->fifo_out, sub );
                         }
                     }
                 }
             }
-            if( sub )
-            {
-                /*
-                 * Got a sub to display...
-                 */
-                break;
-            }
         } // end subtitles
 
         /*
@@ -639,6 +681,7 @@ static void SyncVideo( hb_work_object_t * w )
          */
         buf_tmp = cur;
         pv->cur = cur = hb_fifo_get( job->fifo_raw );
+        cur->sub = NULL;
         pv->next_pts = cur->start;
         int64_t duration = cur->start - buf_tmp->start;
         if ( duration <= 0 )
@@ -659,51 +702,6 @@ static void SyncVideo( hb_work_object_t * w )
             pv->chap_mark = 0;
         }
 
-        /* If we have a subtitle for this picture, copy it */
-        /* FIXME: we should avoid this memcpy */
-        if( sub && subtitle && 
-            subtitle->format == PICTURESUB )
-        {
-            if( sub->size > 0 )
-            {
-                if( subtitle->dest == RENDERSUB )
-                {
-                    /*
-                     * Tack onto the video buffer for rendering
-                     */
-                    buf_tmp->sub         = hb_buffer_init( sub->size );
-                    buf_tmp->sub->x      = sub->x;
-                    buf_tmp->sub->y      = sub->y;
-                    buf_tmp->sub->width  = sub->width;
-                    buf_tmp->sub->height = sub->height;
-                    memcpy( buf_tmp->sub->data, sub->data, sub->size ); 
-                } else {
-                    /*
-                     * Pass-Through, pop it off of the raw queue, rewrite times and
-                     * make it available to be reencoded.
-                     */
-                    uint64_t sub_duration;
-                    sub = hb_fifo_get( subtitle->fifo_raw );
-                    sub_duration = sub->stop - sub->start;
-                    sub->start = buf_tmp->start;
-                    sub->stop = sub->start + duration;
-                    hb_fifo_push( subtitle->fifo_sync, sub );
-                }
-            } else {
-                /*
-                 * EOF - consume for rendered, else pass through
-                 */
-                if( subtitle->dest == RENDERSUB )
-                {
-                    sub = hb_fifo_get( subtitle->fifo_raw );
-                    hb_buffer_close( &sub );
-                } else {
-                    sub = hb_fifo_get( subtitle->fifo_raw );
-                    hb_fifo_push( subtitle->fifo_out, sub );
-                }
-            }
-        }
-
         /* Push the frame to the renderer */
         hb_fifo_push( job->fifo_sync, buf_tmp );
 
index 7b270ca..59dea5d 100644 (file)
@@ -501,16 +501,16 @@ static void do_job( hb_job_t * job, int cpu_count )
              *
              * select_subtitle implies that we did a scan.
              */
-            if( !job->indepth_scan && job->subtitle_force &&
+            if( !job->indepth_scan && subtitle->force &&
                 job->select_subtitle )
             {
                 if( subtitle->forced_hits == 0 )
                 {
-                    job->subtitle_force = 0;
+                    subtitle->force = 0;
                 }
             }
 
-            if( (!job->indepth_scan || job->subtitle_force) && 
+            if( (!job->indepth_scan || subtitle->force) && 
                 subtitle->source == VOBSUB ) {
                 /*
                  * Don't add threads for subtitles when we are scanning, unless
@@ -519,6 +519,7 @@ static void do_job( hb_job_t * job, int cpu_count )
                 w = hb_get_work( WORK_DECVOBSUB );
                 w->fifo_in  = subtitle->fifo_in;
                 w->fifo_out = subtitle->fifo_raw;
+                w->subtitle = subtitle;
                 hb_list_add( job->list_work, w );
             }
 
@@ -541,6 +542,7 @@ static void do_job( hb_job_t * job, int cpu_count )
                 w = hb_get_work( WORK_ENCVOBSUB );
                 w->fifo_in  = subtitle->fifo_sync;
                 w->fifo_out = subtitle->fifo_out;
+                w->subtitle = subtitle;
                 hb_list_add( job->list_work, w );
             }
         }
index 8543164..250c8fe 100644 (file)
@@ -2615,10 +2615,6 @@ fWorkingCount = 0;
     job->file = [[queueToApply objectForKey:@"DestinationPath"] UTF8String];
     //[self writeToActivityLog: "processNewQueueEncode sending to prepareJob"];
     [self prepareJob];
-    if( [[queueToApply objectForKey:@"SubtitlesForced"] intValue] == 1 )
-        job->subtitle_force = 1;
-    else
-        job->subtitle_force = 0;
     
     /*
      * If scanning we need to do some extra setup of the job.
@@ -3217,6 +3213,10 @@ fWorkingCount = 0;
         job->indepth_scan = 0;
         hb_subtitle_t *subtitle = (hb_subtitle_t *) hb_list_item( title->list_subtitle, 
                                                                   [[queueToApply objectForKey:@"JobSubtitlesIndex"] intValue] - 2 );
+        if( [[queueToApply objectForKey:@"SubtitlesForced"] intValue] == 1 )
+            subtitle->force = 1;
+        else
+            subtitle->force = 0;
         hb_list_add( job->list_subtitle, subtitle );
         break;
     }
index 3fecfb1..44e44d1 100644 (file)
@@ -1655,6 +1655,9 @@ static int HandleEvents( hb_handle_t * h )
                  */
                 subtitle = hb_list_item( title->list_subtitle, sub-1 );
                 if( subtitle ) {
+                    if( subtitle_force ) {
+                        subtitle->force = subtitle_force;
+                    }
                     hb_list_add( job->list_subtitle, subtitle );
                 } else {
                     fprintf( stderr, "Could not find subtitle track %d, skipped\n", sub );
@@ -1709,11 +1712,6 @@ static int HandleEvents( hb_handle_t * h )
             if (maxHeight)
                 job->maxHeight = maxHeight;
 
-            if( subtitle_force )
-            {
-                job->subtitle_force = subtitle_force;
-            }
-
             if( start_at_preview )
             {
                 job->start_at_preview = start_at_preview - 1;