diff options
author | jstebbins <[email protected]> | 2010-05-24 21:53:48 +0000 |
---|---|---|
committer | jstebbins <[email protected]> | 2010-05-24 21:53:48 +0000 |
commit | ddb445bf2829b7e6311a24453adc4a39b0215fb5 (patch) | |
tree | fb6b6b292b4707adfd6b5025fa9c0172e73097b8 | |
parent | 139cac98014fc013254bf6183513a50cd99fb874 (diff) |
add support for Nero vobsubs in mp4
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://svn.handbrake.fr/HandBrake/trunk@3325 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r-- | contrib/mp4v2/A00-nero-vobsub.patch | 142 | ||||
-rw-r--r-- | gtk/src/hb-backend.c | 33 | ||||
-rw-r--r-- | gtk/src/subtitlehandler.c | 9 | ||||
-rw-r--r-- | libhb/muxmp4.c | 73 | ||||
-rw-r--r-- | test/test.c | 10 |
5 files changed, 218 insertions, 49 deletions
diff --git a/contrib/mp4v2/A00-nero-vobsub.patch b/contrib/mp4v2/A00-nero-vobsub.patch new file mode 100644 index 000000000..beb8be6d8 --- /dev/null +++ b/contrib/mp4v2/A00-nero-vobsub.patch @@ -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); + diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c index 94fa5b0fa..e7265ef87 100644 --- a/gtk/src/hb-backend.c +++ b/gtk/src/hb-backend.c @@ -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 diff --git a/gtk/src/subtitlehandler.c b/gtk/src/subtitlehandler.c index b74eb27ea..1c5b42cd1 100644 --- a/gtk/src/subtitlehandler.c +++ b/gtk/src/subtitlehandler.c @@ -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; } diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c index 01ba94004..3c878fdfc 100644 --- a/libhb/muxmp4.c +++ b/libhb/muxmp4.c @@ -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 { diff --git a/test/test.c b/test/test.c index 30c9bfab2..dc37402c1 100644 --- a/test/test.c +++ b/test/test.c @@ -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 |