diff options
author | Rodeo <[email protected]> | 2012-05-10 22:30:18 +0000 |
---|---|---|
committer | Rodeo <[email protected]> | 2012-05-10 22:30:18 +0000 |
commit | ea44e3d23deb066758e8caff32d99346e7a9e9b9 (patch) | |
tree | d4336ad7c1be23dec5b20ffb1cc856c4f1f55ae9 | |
parent | 4fb04896b1fb8ddebdf2440ce361732151e6dfd6 (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.c | 109 | ||||
-rw-r--r-- | libhb/muxmkv.c | 10 |
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); |