summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjstebbins <[email protected]>2010-05-24 21:53:48 +0000
committerjstebbins <[email protected]>2010-05-24 21:53:48 +0000
commitddb445bf2829b7e6311a24453adc4a39b0215fb5 (patch)
treefb6b6b292b4707adfd6b5025fa9c0172e73097b8
parent139cac98014fc013254bf6183513a50cd99fb874 (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.patch142
-rw-r--r--gtk/src/hb-backend.c33
-rw-r--r--gtk/src/subtitlehandler.c9
-rw-r--r--libhb/muxmp4.c73
-rw-r--r--test/test.c10
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