OSDN Git Service

add support for Nero vobsubs in mp4
authorjstebbins <jstebbins@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Mon, 24 May 2010 21:53:48 +0000 (21:53 +0000)
committerjstebbins <jstebbins@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Mon, 24 May 2010 21:53:48 +0000 (21:53 +0000)
Note that these do not work with any apple products that I know of.  Perian
might be able to do something with them.  MPlayer and VLC both grok nero
vobsubs.

libhb, cli, and lingui updated.

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

contrib/mp4v2/A00-nero-vobsub.patch [new file with mode: 0644]
gtk/src/hb-backend.c
gtk/src/subtitlehandler.c
libhb/muxmp4.c
test/test.c

diff --git a/contrib/mp4v2/A00-nero-vobsub.patch b/contrib/mp4v2/A00-nero-vobsub.patch
new file mode 100644 (file)
index 0000000..beb8be6
--- /dev/null
@@ -0,0 +1,142 @@
+diff -Naur mp4v2-trunk-r355/include/mp4v2/general.h mp4v2-trunk-r355/include/mp4v2/general.h
+--- mp4v2-trunk-r355/include/mp4v2/general.h   2009-05-23 06:09:58.000000000 -0700
++++ mp4v2-trunk-r355/include/mp4v2/general.h   2010-05-23 14:22:21.949288657 -0700
+@@ -75,6 +75,7 @@
+ #define MP4_CNTL_TRACK_TYPE     "cntl"  /**< Constant: control track. */
+ #define MP4_TEXT_TRACK_TYPE     "text"  /**< Constant: text track. */
+ #define MP4_SUBTITLE_TRACK_TYPE "sbtl"  /**< Constant: subtitle track. */
++#define MP4_SUBPIC_TRACK_TYPE   "subp"  /**< Constant: subtitle track. */
+ /*
+  * This second set of track types should be created
+  * via MP4AddSystemsTrack(type)
+diff -Naur mp4v2-trunk-r355/include/mp4v2/track.h mp4v2-trunk-r355/include/mp4v2/track.h
+--- mp4v2-trunk-r355/include/mp4v2/track.h     2009-05-23 06:21:49.000000000 -0700
++++ mp4v2-trunk-r355/include/mp4v2/track.h     2010-05-23 15:43:47.249286008 -0700
+@@ -310,6 +310,13 @@
+     uint16_t      height );
+ MP4V2_EXPORT
++MP4TrackId MP4AddSubpicTrack(
++    MP4FileHandle hFile,
++    uint32_t      timescale,
++    uint16_t      width,
++    uint16_t      height );
++
++MP4V2_EXPORT
+ MP4TrackId MP4AddPixelAspectRatio(
+     MP4FileHandle hFile,
+     MP4TrackId    refTrackId,
+diff -Naur mp4v2-trunk-r355/src/descriptors.h mp4v2-trunk-r355/src/descriptors.h
+--- mp4v2-trunk-r355/src/descriptors.h 2009-05-20 19:52:32.000000000 -0700
++++ mp4v2-trunk-r355/src/descriptors.h 2010-05-23 16:29:34.800935677 -0700
+@@ -119,6 +119,7 @@
+ // ES objectTypeId
+ const uint8_t MP4SystemsV1ObjectType            = 0x01;
+ const uint8_t MP4SystemsV2ObjectType            = 0x02;
++const uint8_t MP4SubpicObjectType               = 0xe0;
+ // ES streamType
+ const uint8_t MP4ObjectDescriptionStreamType    = 0x01;
+@@ -131,6 +132,7 @@
+ const uint8_t MP4OCIStreamType                  = 0x08;
+ const uint8_t MP4MPEGJStreamType                = 0x09;
+ const uint8_t MP4UserPrivateStreamType          = 0x20;
++const uint8_t MP4NeroSubpicStreamType           = 0x38;
+ ///////////////////////////////////////////////////////////////////////////////
+diff -Naur mp4v2-trunk-r355/src/mp4.cpp mp4v2-trunk-r355/src/mp4.cpp
+--- mp4v2-trunk-r355/src/mp4.cpp       2009-05-23 06:29:37.000000000 -0700
++++ mp4v2-trunk-r355/src/mp4.cpp       2010-05-23 15:45:28.852222074 -0700
+@@ -1174,6 +1174,23 @@
+         return MP4_INVALID_TRACK_ID;
+     }
++    MP4TrackId MP4AddSubpicTrack(MP4FileHandle hFile,
++                                   uint32_t timescale,
++                                   uint16_t width,
++                                   uint16_t height)
++    {
++        if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
++            try {
++                return ((MP4File*)hFile)->AddSubpicTrack(timescale, width, height);
++            }
++            catch (MP4Error* e) {
++                PRINT_ERROR(e);
++                delete e;
++            }
++        }
++        return MP4_INVALID_TRACK_ID;
++    }
++
+     MP4TrackId MP4AddChapterTextTrack(
+         MP4FileHandle hFile, MP4TrackId refTrackId, uint32_t timescale)
+     {
+diff -Naur mp4v2-trunk-r355/src/mp4file.cpp mp4v2-trunk-r355/src/mp4file.cpp
+--- mp4v2-trunk-r355/src/mp4file.cpp   2009-05-26 19:34:56.000000000 -0700
++++ mp4v2-trunk-r355/src/mp4file.cpp   2010-05-23 16:32:52.654220633 -0700
+@@ -2095,6 +2095,50 @@
+     return trackId;
+ }
++MP4TrackId MP4File::AddSubpicTrack(uint32_t timescale,
++                                     uint16_t width,
++                                     uint16_t height)
++{
++    MP4TrackId trackId =
++        AddTrack(MP4_SUBPIC_TRACK_TYPE, timescale);
++
++    InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "nmhd", 0);
++
++    (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "mp4s");
++
++    SetTrackFloatProperty(trackId, "tkhd.width", width);
++    SetTrackFloatProperty(trackId, "tkhd.height", height);
++    SetTrackIntegerProperty(trackId, "tkhd.layer", 0);
++
++    // stsd is a unique beast in that it has a count of the number
++    // of child atoms that needs to be incremented after we add the mp4s atom
++    MP4Integer32Property* pStsdCountProperty;
++    FindIntegerProperty(
++        MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
++        (MP4Property**)&pStsdCountProperty);
++    pStsdCountProperty->IncrementValue();
++
++    SetTrackIntegerProperty(trackId,
++                            "mdia.minf.stbl.stsd.mp4s.esds.ESID",
++#if 0
++                            // note - for a file, these values need to
++                            // be 0 - wmay - 04/16/2003
++                            trackId
++#else
++                            0
++#endif
++                           );
++
++    SetTrackIntegerProperty(trackId,
++                            "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.objectTypeId",
++                            MP4SubpicObjectType);
++
++    SetTrackIntegerProperty(trackId,
++                            "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.streamType",
++                            MP4NeroSubpicStreamType);
++    return trackId;
++}
++
+ MP4TrackId MP4File::AddChapterTextTrack(MP4TrackId refTrackId, uint32_t timescale)
+ {
+     // validate reference track id
+diff -Naur mp4v2-trunk-r355/src/mp4file.h mp4v2-trunk-r355/src/mp4file.h
+--- mp4v2-trunk-r355/src/mp4file.h     2009-05-23 06:29:37.000000000 -0700
++++ mp4v2-trunk-r355/src/mp4file.h     2010-05-23 15:44:57.568026299 -0700
+@@ -388,6 +388,10 @@
+                                 uint16_t width,
+                                 uint16_t height);
++    MP4TrackId AddSubpicTrack(uint32_t timescale,
++                                uint16_t width,
++                                uint16_t height);
++
+     MP4TrackId AddPixelAspectRatio(MP4TrackId trackId, uint32_t hSpacing, uint32_t vSpacing);
+     MP4TrackId AddColr(MP4TrackId trackId, uint16_t pri, uint16_t tran, uint16_t mat);
index 94fa5b0..e7265ef 100644 (file)
@@ -3893,23 +3893,6 @@ ghb_validate_subtitles(signal_user_data_t *ud)
                {
                        one_burned = TRUE;
                }
-               if (!burned && mux == HB_MUX_MP4 && source == VOBSUB)
-               {
-                       // MP4 can only handle burned vobsubs.  make sure there isn't
-                       // already something burned in the list
-                       message = g_strdup_printf(
-                       "Your chosen container does not support soft bitmap subtitles.\n\n"
-                               "You should change your subtitle selections.\n"
-                               "If you continue, some subtitles will be lost.");
-                       if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, 
-                               "Cancel", "Continue"))
-                       {
-                               g_free(message);
-                               return FALSE;
-                       }
-                       g_free(message);
-                       break;
-               }
                if (source == SRTSUB)
                {
                        gchar *filename;
@@ -4621,15 +4604,10 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
                subtitle = ghb_settings_get_int(ssettings, "SubtitleTrack");
                if (subtitle == -1)
                {
-                       if (!burned && job->mux == HB_MUX_MKV)
+                       if (!burned)
                        {
                                job->select_subtitle_config.dest = PASSTHRUSUB;
                        }
-                       else if (!burned && job->mux == HB_MUX_MP4)
-                       {
-                               // Skip any non-burned vobsubs when output is mp4
-                               continue;
-                       }
                        else if (burned)
                        {
                                // Only allow one subtitle to be burned into the video
@@ -4652,17 +4630,10 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
                        if (subt != NULL)
                        {
                                sub_config = subt->config;
-                               if (!burned && job->mux == HB_MUX_MKV && 
-                                       subt->format == PICTURESUB)
+                               if (!burned && subt->format == PICTURESUB)
                                {
                                        sub_config.dest = PASSTHRUSUB;
                                }
-                               else if (!burned && job->mux == HB_MUX_MP4 && 
-                                       subt->format == PICTURESUB)
-                               {
-                                       // Skip any non-burned vobsubs when output is mp4
-                                       continue;
-                               }
                                else if ( burned && subt->format == PICTURESUB )
                                {
                                        // Only allow one subtitle to be burned into the video
index b74eb27..1c5b42c 100644 (file)
@@ -41,15 +41,6 @@ free_subtitle_key(gpointer data)
 static gboolean
 mustBurn(signal_user_data_t *ud, GValue *settings)
 {
-       if (ghb_settings_combo_int(ud->settings, "FileFormat") == HB_MUX_MP4)
-       {
-               // MP4 can only handle burned vobsubs.  make sure there isn't
-               // already something burned in the list
-               if (ghb_settings_get_int(settings, "SubtitleSource") == VOBSUB)
-               {
-                       return TRUE;
-               }
-       }
        return FALSE;
 }
 
index 01ba940..3c878fd 100644 (file)
@@ -520,6 +520,46 @@ static int MP4Init( hb_mux_object_t * m )
                 MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE));
             }
         }
+        else if( subtitle && subtitle->format == PICTURESUB && 
+            subtitle->config.dest == PASSTHRUSUB )
+        {
+            mux_data = calloc(1, sizeof( hb_mux_data_t ) );
+            subtitle->mux_data = mux_data;
+            mux_data->subtitle = 1;
+            mux_data->sub_format = subtitle->format;
+
+            mux_data->track = MP4AddSubpicTrack( m->file, 90000, title->width, title->height );
+
+            MP4SetTrackLanguage(m->file, mux_data->track, subtitle->iso639_2);
+
+            /* Tune track chunk duration */
+            MP4TuneTrackDurationPerChunk( m, mux_data->track );
+            uint8_t palette[16][4];
+            int ii;
+            for ( ii = 0; ii < 16; ii++ )
+            {
+                palette[ii][0] = 0;
+                palette[ii][1] = (subtitle->palette[ii] >> 16) & 0xff;
+                palette[ii][2] = (subtitle->palette[ii] >> 8) & 0xff;
+                palette[ii][3] = (subtitle->palette[ii]) & 0xff;
+            }
+            if (!(MP4SetTrackESConfiguration( m->file, mux_data->track,
+                    (uint8_t*)palette, 16 * 4 )))
+            {
+                hb_error("muxmp4.c: MP4SetTrackESConfiguration failed!");
+                *job->die = 1;
+                return 0;
+            }
+            if ( !subtitle_default || subtitle->config.default_track ) {
+                /* Enable the default subtitle track */
+                MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE));
+                subtitle_default = 1;
+            }
+            else
+            {
+                MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_DISABLED | TRACK_IN_MOVIE));
+            }
+        }
     }
 
     if (job->chapter_markers)
@@ -1048,6 +1088,39 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
 
             mux_data->sum_dur += (buf->stop - buf->start);
         }
+        else if( mux_data->sub_format == PICTURESUB )
+        {
+            /* Write an empty sample */
+            if ( mux_data->sum_dur < buf->start )
+            {
+                uint8_t empty[2] = {0,0};
+                if( !MP4WriteSample( m->file,
+                                    mux_data->track,
+                                    empty,
+                                    2,
+                                    buf->start - mux_data->sum_dur,
+                                    0,
+                                    1 ))
+                {
+                    hb_error("Failed to write to output file, disk full?");
+                    *job->die = 1;
+                } 
+                mux_data->sum_dur += buf->start - mux_data->sum_dur;
+            }
+            if( !MP4WriteSample( m->file,
+                                 mux_data->track,
+                                 buf->data,
+                                 buf->size,
+                                 buf->stop - buf->start,
+                                 0,
+                                 1 ))
+            {
+                hb_error("Failed to write to output file, disk full?");
+                *job->die = 1;
+            }
+
+            mux_data->sum_dur += (buf->stop - buf->start);
+        }
     }
     else
     {
index 30c9bfa..dc37402 100644 (file)
@@ -1792,18 +1792,10 @@ static int HandleEvents( hb_handle_t * h )
 
                         force = test_sub_list(subforce, token, pos);
 
-                        if ( !burn && mux == HB_MUX_MKV && 
-                             subtitle->format == PICTURESUB)
+                        if ( !burn && subtitle->format == PICTURESUB)
                         {
                             sub_config.dest = PASSTHRUSUB;
                         }
-                        else if (!burn && mux == HB_MUX_MP4 &&
-                             subtitle->format == PICTURESUB)
-                        {
-                            // Skip any non-burned vobsubs when output is mp4
-                            fprintf( stderr, "Warning: Skipping subtitle track %d, can't pass-through VOBSUBs in an MP4 container,\nadd '--subtitle-burn %d' to the command line\n", track+1, track+1 );
-                            continue;
-                        }
                         else if ( burn && subtitle->format == PICTURESUB )
                         {
                             // Only allow one subtitle to be burned into video