summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRodeo <[email protected]>2012-05-10 22:30:18 +0000
committerRodeo <[email protected]>2012-05-10 22:30:18 +0000
commitea44e3d23deb066758e8caff32d99346e7a9e9b9 (patch)
treed4336ad7c1be23dec5b20ffb1cc856c4f1f55ae9
parent4fb04896b1fb8ddebdf2440ce361732151e6dfd6 (diff)
libhb: PGS subtitle improvements.
Some devices (such as the WD TV Live) expect PGS subtitle "frames" to come as a single packet, whereas on Blu-ray, each frame "segment" comes in its own packet. When doing PGS passthrough, merge packets so that 1 subtitle == 1 packet. This matches what MakeMKV amd mkvmerge do. Also, when doing forced-only extraction, don't include more 'empty' PGS subtitles than necessary. In muxmkv, cleanup negative subtitle durations (doesn't appear to fix anything, but it doesn't make anything worse either). git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@4658 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r--libhb/decpgssub.c109
-rw-r--r--libhb/muxmkv.c10
2 files changed, 98 insertions, 21 deletions
diff --git a/libhb/decpgssub.c b/libhb/decpgssub.c
index 77b90ad03..aecf51df3 100644
--- a/libhb/decpgssub.c
+++ b/libhb/decpgssub.c
@@ -18,6 +18,10 @@ struct hb_work_private_s
// while parsing an input packet.
hb_buffer_t * list_buffer;
hb_buffer_t * last_buffer;
+ // for PGS subs, we need to pass 'empty' subtitles through (they clear the
+ // display) - when doing forced-only extraction, only pass empty subtitles
+ // through if we've seen a forced sub and haven't seen any empty sub since
+ uint8_t seen_forced_sub;
};
static int decsubInit( hb_work_object_t * w, hb_job_t * job )
@@ -30,6 +34,7 @@ static int decsubInit( hb_work_object_t * w, hb_job_t * job )
pv = calloc( 1, sizeof( hb_work_private_t ) );
w->private_data = pv;
+ pv->seen_forced_sub = 0;
pv->context = context;
pv->job = job;
@@ -111,23 +116,52 @@ static int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
avp.size = 0;
}
- if (has_subtitle && subtitle.num_rects > 0)
+ /* Subtitles are "usable" if:
+ * 1. Libav returned a subtitle (has_subtitle) AND
+ * 2. we are not doing Foreign Audio Search (!pv->job->indepth_scan)
+ * For forced-only extraction, usable subtitles also need to:
+ * a. be forced (subtitle.forced) OR
+ * b. clear a forced sub (pv->seen_forced_sub && !subtitle.num_rects) */
+ uint8_t useable_sub;
+
+ if (has_subtitle)
{
- w->subtitle->hits++;
- if (subtitle.forced)
- w->subtitle->forced_hits++;
+ // subtitle statistics
+ if (subtitle.num_rects != 0)
+ {
+ w->subtitle->hits++;
+ if (subtitle.forced)
+ {
+ w->subtitle->forced_hits++;
+ }
+ }
+ // is it usable?
+ if (pv->job->indepth_scan)
+ {
+ useable_sub = 0;
+ }
+ else if (w->subtitle->config.force)
+ {
+ useable_sub = subtitle.forced || (pv->seen_forced_sub && !subtitle.num_rects);
+ // note if we find forced or empty subtitles
+ if (subtitle.forced)
+ {
+ pv->seen_forced_sub = 1;
+ }
+ else if (!subtitle.num_rects)
+ {
+ pv->seen_forced_sub = 0;
+ }
+ }
+ else
+ {
+ useable_sub = 1;
+ }
+ }
+ else
+ {
+ useable_sub = 0;
}
-
- // The sub is "usable" if:
- // 1. libav returned a sub AND
- // 2. we are not scanning for foreign audio subs AND
- // 3. we want all subs (e.g. not forced) OR
- // 4. the sub is forced and we only want forced OR
- // 5. subtitle clears the previous sub (these are never forced)
- // subtitle.num_rects == 0
- uint8_t useable_sub = has_subtitle && !pv->job->indepth_scan &&
- ( !subtitle.num_rects || !w->subtitle->config.force ||
- ( w->subtitle->config.force && subtitle.forced ) );
if (useable_sub)
{
@@ -137,8 +171,49 @@ static int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
if ( w->subtitle->config.dest == PASSTHRUSUB &&
hb_subtitle_can_pass( PGSSUB, pv->job->mux ) )
{
- out = pv->list_pass_buffer;
- pv->list_pass_buffer = NULL;
+ /* PGS subtitles are spread across multiple packets (1 per segment).
+ * In the MKV container, all segments are found in the same packet
+ * (this is expected by some devices, such as the WD TV Live).
+ * So if there are multiple packets, merge them. */
+ if (pv->list_pass_buffer->next == NULL)
+ {
+ // packets already merged (e.g. MKV sources)
+ out = pv->list_pass_buffer;
+ pv->list_pass_buffer = NULL;
+ }
+ else
+ {
+ int size = 0;
+ uint8_t * data;
+ hb_buffer_t * b;
+
+ b = pv->list_pass_buffer;
+ while (b != NULL)
+ {
+ size += b->size;
+ b = b->next;
+ }
+
+ out = hb_buffer_init( size );
+ data = out->data;
+ b = pv->list_pass_buffer;
+ while (b != NULL)
+ {
+ memcpy( data, b->data, b->size );
+ data += b->size;
+ b = b->next;
+ }
+ hb_buffer_close( &pv->list_pass_buffer );
+
+ out->s = in->s;
+ out->sequence = in->sequence;
+ }
+ if (pts >= 0)
+ {
+ // this should (eventually) always be the case
+ out->s.start = pts;
+ }
+ out->s.stop = 0;
}
else
{
diff --git a/libhb/muxmkv.c b/libhb/muxmkv.c
index 227159579..b1927ff80 100644
--- a/libhb/muxmkv.c
+++ b/libhb/muxmkv.c
@@ -473,17 +473,19 @@ static int MKVMux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
return 0;
}
}
- else if ( mux_data->subtitle )
+ else if (mux_data->subtitle)
{
- uint64_t duration;
- timecode = buf->s.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;
}
-
+ uint64_t duration;
+ timecode = buf->s.start * TIMECODE_SCALE;
duration = buf->s.stop * TIMECODE_SCALE - timecode;
+ // PGS subtitles have negative durations (buf->s.start - 0)
+ if (duration < 0)
+ duration = 0;
mk_addFrameData(m->file, mux_data->track, buf->data, buf->size);
mk_setFrameFlags(m->file, mux_data->track, timecode, 1, duration);
mk_flushFrame(m->file, mux_data->track);