dec_sub: allow postprocessing between decoders

Until now, timing and charset recoding postprocessing was applied on
packets as they were output by the demuxer, and then passed to the
decoders. Make it so that postprocessing can happen after some decoders
in special situations.
This commit is contained in:
wm4 2013-06-24 01:04:17 +02:00
parent 74c56309a3
commit 0b2e073853
1 changed files with 41 additions and 14 deletions

View File

@ -240,16 +240,22 @@ static struct demux_packet *recode_packet(struct demux_packet *in,
return pkt; return pkt;
} }
void sub_decode(struct dec_sub *sub, struct demux_packet *packet) static void decode_chain_recode(struct dec_sub *sub, struct sd **sd, int num_sd,
struct demux_packet *packet)
{ {
if (sub->num_sd > 0) { if (num_sd > 0) {
struct demux_packet *recoded = NULL; struct demux_packet *recoded = NULL;
if (sub->charset) if (sub->charset)
recoded = recode_packet(packet, sub->charset); recoded = recode_packet(packet, sub->charset);
decode_chain(sub->sd, sub->num_sd, recoded ? recoded : packet); decode_chain(sd, num_sd, recoded ? recoded : packet);
} }
} }
void sub_decode(struct dec_sub *sub, struct demux_packet *packet)
{
decode_chain_recode(sub, sub->sd, sub->num_sd, packet);
}
static const char *guess_sub_cp(struct packet_list *subs, const char *usercp) static const char *guess_sub_cp(struct packet_list *subs, const char *usercp)
{ {
if (!mp_charset_requires_guess(usercp)) if (!mp_charset_requires_guess(usercp))
@ -318,7 +324,7 @@ static void fix_overlaps_and_gaps(struct packet_list *subs)
} }
} }
static void add_sub_list(struct dec_sub *sub, struct packet_list *subs) static void add_sub_list(struct dec_sub *sub, int at, struct packet_list *subs)
{ {
struct sd *sd = sub_get_last_sd(sub); struct sd *sd = sub_get_last_sd(sub);
assert(sd); assert(sd);
@ -326,7 +332,7 @@ static void add_sub_list(struct dec_sub *sub, struct packet_list *subs)
sd->no_remove_duplicates = true; sd->no_remove_duplicates = true;
for (int n = 0; n < subs->num_packets; n++) for (int n = 0; n < subs->num_packets; n++)
sub_decode(sub, subs->packets[n]); decode_chain_recode(sub, sub->sd + at, sub->num_sd - at, subs->packets[n]);
// Hack for broken FFmpeg packet format: make sd_ass keep the subtitle // Hack for broken FFmpeg packet format: make sd_ass keep the subtitle
// events on reset(), even if broken FFmpeg ASS packets were received // events on reset(), even if broken FFmpeg ASS packets were received
@ -338,31 +344,52 @@ static void add_sub_list(struct dec_sub *sub, struct packet_list *subs)
sd->no_remove_duplicates = false; sd->no_remove_duplicates = false;
} }
static void add_packet(struct packet_list *subs, struct demux_packet *pkt)
{
pkt = demux_copy_packet(pkt);
talloc_steal(subs, pkt);
MP_TARRAY_APPEND(subs, subs->packets, subs->num_packets, pkt);
}
// Read all packets from the demuxer and decode/add them. Returns false if // Read all packets from the demuxer and decode/add them. Returns false if
// there are circumstances which makes this not possible. // there are circumstances which makes this not possible.
bool sub_read_all_packets(struct dec_sub *sub, struct sh_sub *sh) bool sub_read_all_packets(struct dec_sub *sub, struct sh_sub *sh)
{ {
struct MPOpts *opts = sub->opts; struct MPOpts *opts = sub->opts;
if (!sub_accept_packets_in_advance(sub) || sh->track) if (!sub_accept_packets_in_advance(sub) || sh->track || sub->num_sd < 1)
return false; return false;
const char *codec = sh->gsh->codec ? sh->gsh->codec : "";
struct packet_list *subs = talloc_zero(NULL, struct packet_list); struct packet_list *subs = talloc_zero(NULL, struct packet_list);
// In some cases, we want to put the packets through a decoder first.
// Preprocess until sub->sd[preprocess].
int preprocess = 0;
// movtext is currently the only subtitle format that has text output,
// but binary input. Do charset conversion after converting to text.
if (sub->sd[0]->driver == &sd_movtext)
preprocess = 1;
for (;;) { for (;;) {
ds_get_next_pts(sh->ds); ds_get_next_pts(sh->ds);
struct demux_packet *pkt = ds_get_packet_sub(sh->ds); struct demux_packet *pkt = ds_get_packet_sub(sh->ds);
if (!pkt) if (!pkt)
break; break;
pkt = demux_copy_packet(pkt); if (preprocess) {
talloc_steal(subs, pkt); decode_chain(sub->sd, preprocess, pkt);
MP_TARRAY_APPEND(subs, subs->packets, subs->num_packets, pkt); while (1) {
pkt = get_decoded_packet(sub->sd[preprocess - 1]);
if (!pkt)
break;
add_packet(subs, pkt);
}
} else {
add_packet(subs, pkt);
}
} }
// Can't run auto-detection on movtext packets: it's the only codec that if (opts->sub_cp && !sh->is_utf8)
// even though it decodes to text has binary input data.
if (opts->sub_cp && !sh->is_utf8 && strcmp(codec, "movtext") != 0)
sub->charset = guess_sub_cp(subs, opts->sub_cp); sub->charset = guess_sub_cp(subs, opts->sub_cp);
if (sub->charset) if (sub->charset)
@ -378,7 +405,7 @@ bool sub_read_all_packets(struct dec_sub *sub, struct sh_sub *sh)
if (!opts->suboverlap_enabled) if (!opts->suboverlap_enabled)
fix_overlaps_and_gaps(subs); fix_overlaps_and_gaps(subs);
add_sub_list(sub, subs); add_sub_list(sub, preprocess, subs);
talloc_free(subs); talloc_free(subs);
return true; return true;