From 687b552db186af66e97c58792b2db40294e92bad Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 18 Dec 2015 01:54:14 +0100 Subject: sub: remove subtitle filter chain concept It was stupid. The only thing that still effectively used it was sd_lavc_conv - all other "filters" were the subtitle decoder/renderers for text (sd_ass) and bitmap (sd_lavc) subtitles. While having a subtitle filter chain was interesting (and actually worked in almost the same way as the audio/video ones), I didn't manage to use it in a meaningful way, and I couldn't e.g. factor secondary features like fixing subtitle timing into filters. Refactor the shit and drop unneeded things as it goes. --- sub/dec_sub.c | 225 ++++++++--------------------------------------------- sub/dec_sub.h | 2 - sub/sd.h | 37 ++------- sub/sd_ass.c | 45 +++++++---- sub/sd_lavc.c | 5 +- sub/sd_lavc_conv.c | 101 +++++++++++------------- 6 files changed, 122 insertions(+), 293 deletions(-) (limited to 'sub') diff --git a/sub/dec_sub.c b/sub/dec_sub.c index e7362e1f69..4450f577c2 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -34,19 +34,15 @@ extern const struct sd_functions sd_ass; extern const struct sd_functions sd_lavc; -extern const struct sd_functions sd_lavc_conv; static const struct sd_functions *const sd_list[] = { + &sd_lavc, #if HAVE_LIBASS &sd_ass, #endif - &sd_lavc, - &sd_lavc_conv, NULL }; -#define MAX_NUM_SD 3 - struct dec_sub { pthread_mutex_t lock; @@ -56,8 +52,7 @@ struct dec_sub { struct sh_stream *sh; - struct sd *sd[MAX_NUM_SD]; - int num_sd; + struct sd *sd; }; struct packet_list { @@ -84,6 +79,7 @@ struct dec_sub *sub_create(struct mpv_global *global) struct dec_sub *sub = talloc_zero(NULL, struct dec_sub); sub->log = mp_log_new(sub, global->log, "sub"); sub->opts = global->opts; + sub->init_sd.opts = sub->opts; mpthread_mutex_init_recursive(&sub->lock); @@ -93,12 +89,10 @@ struct dec_sub *sub_create(struct mpv_global *global) static void sub_uninit(struct dec_sub *sub) { sub_reset(sub); - for (int n = 0; n < sub->num_sd; n++) { - if (sub->sd[n]->driver->uninit) - sub->sd[n]->driver->uninit(sub->sd[n]); - talloc_free(sub->sd[n]); - } - sub->num_sd = 0; + if (sub->sd) + sub->sd->driver->uninit(sub->sd); + talloc_free(sub->sd); + sub->sd = NULL; } void sub_destroy(struct dec_sub *sub) @@ -113,16 +107,11 @@ void sub_destroy(struct dec_sub *sub) bool sub_is_initialized(struct dec_sub *sub) { pthread_mutex_lock(&sub->lock); - bool r = !!sub->num_sd; + bool r = !!sub->sd; pthread_mutex_unlock(&sub->lock); return r; } -static struct sd *sub_get_last_sd(struct dec_sub *sub) -{ - return sub->num_sd ? sub->sd[sub->num_sd - 1] : NULL; -} - void sub_set_video_res(struct dec_sub *sub, int w, int h) { pthread_mutex_lock(&sub->lock); @@ -138,14 +127,6 @@ void sub_set_video_fps(struct dec_sub *sub, double fps) pthread_mutex_unlock(&sub->lock); } -void sub_set_extradata(struct dec_sub *sub, void *data, int data_len) -{ - pthread_mutex_lock(&sub->lock); - sub->init_sd.extradata = data_len ? talloc_memdup(sub, data, data_len) : NULL; - sub->init_sd.extradata_len = data_len; - pthread_mutex_unlock(&sub->lock); -} - void sub_set_ass_renderer(struct dec_sub *sub, struct ass_library *ass_library, struct ass_renderer *ass_renderer, pthread_mutex_t *ass_lock) @@ -157,22 +138,11 @@ void sub_set_ass_renderer(struct dec_sub *sub, struct ass_library *ass_library, pthread_mutex_unlock(&sub->lock); } -static void print_chain(struct dec_sub *sub) -{ - MP_VERBOSE(sub, "Subtitle filter chain: "); - for (int n = 0; n < sub->num_sd; n++) { - struct sd *sd = sub->sd[n]; - MP_VERBOSE(sub, "%s%s (%s)", n > 0 ? " -> " : "", - sd->driver->name, sd->codec); - } - MP_VERBOSE(sub, "\n"); -} - static int sub_init_decoder(struct dec_sub *sub, struct sd *sd) { sd->driver = NULL; for (int n = 0; sd_list[n]; n++) { - if (sd_list[n]->supports_format(sd->codec)) { + if (sd->sh->codec && sd_list[n]->supports_format(sd->sh->codec)) { sd->driver = sd_list[n]; break; } @@ -190,73 +160,30 @@ static int sub_init_decoder(struct dec_sub *sub, struct sd *sd) void sub_init_from_sh(struct dec_sub *sub, struct sh_stream *sh) { - assert(!sub->num_sd); + assert(!sub->sd); assert(sh && sh->sub); pthread_mutex_lock(&sub->lock); sub->sh = sh; - if (sh->extradata && !sub->init_sd.extradata) - sub_set_extradata(sub, sh->extradata, sh->extradata_size); struct sd init_sd = sub->init_sd; - init_sd.codec = sh->codec; init_sd.sh = sh; - while (sub->num_sd < MAX_NUM_SD) { - struct sd *sd = talloc(NULL, struct sd); - *sd = init_sd; - sd->opts = sub->opts; - if (sub_init_decoder(sub, sd) < 0) { - talloc_free(sd); - break; - } - sub->sd[sub->num_sd] = sd; - sub->num_sd++; - // Try adding new converters until a decoder is reached - if (sd->driver->get_bitmaps || sd->driver->get_text) { - print_chain(sub); - pthread_mutex_unlock(&sub->lock); - return; - } - init_sd = (struct sd) { - .codec = sd->output_codec, - .converted_from = sd->codec, - .extradata = sd->output_extradata, - .extradata_len = sd->output_extradata_len, - .sh = sub->init_sd.sh, - .video_fps = sub->init_sd.video_fps, - .ass_library = sub->init_sd.ass_library, - .ass_renderer = sub->init_sd.ass_renderer, - .ass_lock = sub->init_sd.ass_lock, - }; - } + struct sd *sd = talloc(NULL, struct sd); + *sd = init_sd; - sub_uninit(sub); - MP_ERR(sub, "Could not find subtitle decoder for format '%s'.\n", - sh->codec ? sh->codec : ""); - pthread_mutex_unlock(&sub->lock); -} - -static struct demux_packet *get_decoded_packet(struct sd *sd) -{ - return sd->driver->get_converted ? sd->driver->get_converted(sd) : NULL; -} - -static void decode_chain(struct sd **sd, int num_sd, struct demux_packet *packet) -{ - if (num_sd == 0) + if (sub_init_decoder(sub, sd) < 0) { + sd->driver->uninit(sd); + talloc_free(sd); + MP_ERR(sub, "Could not find subtitle decoder for format '%s'.\n", + sh->codec ? sh->codec : ""); + pthread_mutex_unlock(&sub->lock); return; - struct sd *dec = sd[0]; - dec->driver->decode(dec, packet); - if (num_sd > 1) { - while (1) { - struct demux_packet *next = get_decoded_packet(dec); - if (!next) - break; - decode_chain(sd + 1, num_sd - 1, next); - } } + + sub->sd = sd; + pthread_mutex_unlock(&sub->lock); } static struct demux_packet *recode_packet(struct mp_log *log, @@ -283,11 +210,11 @@ static struct demux_packet *recode_packet(struct mp_log *log, static void decode_chain_recode(struct dec_sub *sub, struct demux_packet *packet) { - if (sub->num_sd > 0) { + if (sub->sd) { struct demux_packet *recoded = NULL; if (sub->sh && sub->sh->sub->charset) recoded = recode_packet(sub->log, packet, sub->sh->sub->charset); - decode_chain(sub->sd, sub->num_sd, recoded ? recoded : packet); + sub->sd->driver->decode(sub->sd, recoded ? recoded : packet); talloc_free(recoded); } } @@ -301,9 +228,6 @@ void sub_decode(struct dec_sub *sub, struct demux_packet *packet) static void add_sub_list(struct dec_sub *sub, struct packet_list *subs) { - struct sd *sd = sub_get_last_sd(sub); - assert(sd); - for (int n = 0; n < subs->num_packets; n++) decode_chain_recode(sub, subs->packets[n]); } @@ -326,8 +250,7 @@ bool sub_read_all_packets(struct dec_sub *sub, struct sh_stream *sh) pthread_mutex_lock(&sub->lock); // Converters are assumed to always accept packets in advance - struct sd *sd = sub_get_last_sd(sub); - if (!(sd && sd->driver->accept_packets_in_advance)) { + if (!(sub->sd && sub->sd->driver->accept_packets_in_advance)) { pthread_mutex_unlock(&sub->lock); return false; } @@ -353,10 +276,8 @@ bool sub_accepts_packet_in_advance(struct dec_sub *sub) { bool res = true; pthread_mutex_lock(&sub->lock); - for (int n = 0; n < sub->num_sd; n++) { - if (sub->sd[n]->driver->accepts_packet) - res &= sub->sd[n]->driver->accepts_packet(sub->sd[n]); - } + if (sub->sd && sub->sd->driver->accepts_packet) + res &= sub->sd->driver->accepts_packet(sub->sd); pthread_mutex_unlock(&sub->lock); return res; } @@ -368,22 +289,10 @@ void sub_get_bitmaps(struct dec_sub *sub, struct mp_osd_res dim, double pts, struct sub_bitmaps *res) { struct MPOpts *opts = sub->opts; - struct sd *sd = sub_get_last_sd(sub); *res = (struct sub_bitmaps) {0}; - if (sd && opts->sub_visibility) { - if (sd->driver->get_bitmaps) - sd->driver->get_bitmaps(sd, dim, pts, res); - } -} - -bool sub_has_get_text(struct dec_sub *sub) -{ - pthread_mutex_lock(&sub->lock); - struct sd *sd = sub_get_last_sd(sub); - bool r = sd && sd->driver->get_text; - pthread_mutex_unlock(&sub->lock); - return r; + if (sub->sd && opts->sub_visibility && sub->sd->driver->get_bitmaps) + sub->sd->driver->get_bitmaps(sub->sd, dim, pts, res); } // See sub_get_bitmaps() for locking requirements. @@ -393,12 +302,9 @@ char *sub_get_text(struct dec_sub *sub, double pts) { pthread_mutex_lock(&sub->lock); struct MPOpts *opts = sub->opts; - struct sd *sd = sub_get_last_sd(sub); char *text = NULL; - if (sd && opts->sub_visibility) { - if (sd->driver->get_text) - text = sd->driver->get_text(sd, pts); - } + if (sub->sd && opts->sub_visibility && sub->sd->driver->get_text) + text = sub->sd->driver->get_text(sub->sd, pts); pthread_mutex_unlock(&sub->lock); return text; } @@ -406,10 +312,8 @@ char *sub_get_text(struct dec_sub *sub, double pts) void sub_reset(struct dec_sub *sub) { pthread_mutex_lock(&sub->lock); - for (int n = 0; n < sub->num_sd; n++) { - if (sub->sd[n]->driver->reset) - sub->sd[n]->driver->reset(sub->sd[n]); - } + if (sub->sd && sub->sd->driver->reset) + sub->sd->driver->reset(sub->sd); pthread_mutex_unlock(&sub->lock); } @@ -417,69 +321,8 @@ int sub_control(struct dec_sub *sub, enum sd_ctrl cmd, void *arg) { int r = CONTROL_UNKNOWN; pthread_mutex_lock(&sub->lock); - for (int n = 0; n < sub->num_sd; n++) { - if (sub->sd[n]->driver->control) { - r = sub->sd[n]->driver->control(sub->sd[n], cmd, arg); - if (r != CONTROL_UNKNOWN) - break; - } - } + if (sub->sd && sub->sd->driver->control) + r = sub->sd->driver->control(sub->sd, cmd, arg); pthread_mutex_unlock(&sub->lock); return r; } - -#define MAX_PACKETS 10 -#define MAX_BYTES 10000 - -struct sd_conv_buffer { - struct demux_packet pkt[MAX_PACKETS]; - int num_pkt; - int read_pkt; - char buffer[MAX_BYTES]; - int cur_buffer; -}; - -void sd_conv_add_packet(struct sd *sd, void *data, int data_len, double pts, - double duration, int64_t pos) -{ - if (!sd->sd_conv_buffer) - sd->sd_conv_buffer = talloc_zero(sd, struct sd_conv_buffer); - struct sd_conv_buffer *buf = sd->sd_conv_buffer; - if (buf->num_pkt >= MAX_PACKETS || buf->cur_buffer + data_len + 1 > MAX_BYTES) - goto out_of_space; - if (buf->read_pkt == buf->num_pkt) - sd_conv_def_reset(sd); - assert(buf->read_pkt == 0); // no mixing of reading/adding allowed - struct demux_packet *pkt = &buf->pkt[buf->num_pkt++]; - *pkt = (struct demux_packet) { - .buffer = &buf->buffer[buf->cur_buffer], - .len = data_len, - .pts = pts, - .duration = duration, - .pos = pos, - }; - memcpy(pkt->buffer, data, data_len); - pkt->buffer[data_len] = 0; - buf->cur_buffer += data_len + 1; - return; - -out_of_space: - MP_ERR(sd, "Subtitle too big.\n"); -} - -struct demux_packet *sd_conv_def_get_converted(struct sd *sd) -{ - struct sd_conv_buffer *buf = sd->sd_conv_buffer; - if (buf && buf->read_pkt < buf->num_pkt) - return &buf->pkt[buf->read_pkt++]; - return NULL; -} - -void sd_conv_def_reset(struct sd *sd) -{ - struct sd_conv_buffer *buf = sd->sd_conv_buffer; - if (buf) { - buf->read_pkt = buf->num_pkt = 0; - buf->cur_buffer = 0; - } -} diff --git a/sub/dec_sub.h b/sub/dec_sub.h index 0c4d59f395..117396d9b2 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -31,7 +31,6 @@ void sub_unlock(struct dec_sub *sub); void sub_set_video_res(struct dec_sub *sub, int w, int h); void sub_set_video_fps(struct dec_sub *sub, double fps); -void sub_set_extradata(struct dec_sub *sub, void *data, int data_len); void sub_set_ass_renderer(struct dec_sub *sub, struct ass_library *ass_library, struct ass_renderer *ass_renderer, pthread_mutex_t *ass_lock); @@ -44,7 +43,6 @@ bool sub_accepts_packet_in_advance(struct dec_sub *sub); void sub_decode(struct dec_sub *sub, struct demux_packet *packet); void sub_get_bitmaps(struct dec_sub *sub, struct mp_osd_res dim, double pts, struct sub_bitmaps *res); -bool sub_has_get_text(struct dec_sub *sub); char *sub_get_text(struct dec_sub *sub, double pts); void sub_reset(struct dec_sub *sub); diff --git a/sub/sd.h b/sub/sd.h index 39b2970911..2d9207dc48 100644 --- a/sub/sd.h +++ b/sub/sd.h @@ -16,18 +16,8 @@ struct sd { const struct sd_functions *driver; void *priv; - const char *codec; - - // Extra header data passed from demuxer - char *extradata; - int extradata_len; - struct sh_stream *sh; - // Set to !=NULL if the input packets are being converted from another - // format. - const char *converted_from; - // Video resolution used for subtitle decoding. Doesn't necessarily match // the resolution of the VO, nor does it have to be the OSD resolution. int sub_video_w, sub_video_h; @@ -38,14 +28,6 @@ struct sd { struct ass_library *ass_library; struct ass_renderer *ass_renderer; pthread_mutex_t *ass_lock; - - // Set by sub converter - const char *output_codec; - char *output_extradata; - int output_extradata_len; - - // Internal buffer for sd_conv_* functions - struct sd_conv_buffer *sd_conv_buffer; }; struct sd_functions { @@ -60,21 +42,18 @@ struct sd_functions { bool (*accepts_packet)(struct sd *sd); // implicit default if NULL: true int (*control)(struct sd *sd, enum sd_ctrl cmd, void *arg); - // decoder void (*get_bitmaps)(struct sd *sd, struct mp_osd_res dim, double pts, struct sub_bitmaps *res); char *(*get_text)(struct sd *sd, double pts); - - // converter - struct demux_packet *(*get_converted)(struct sd *sd); }; -void sd_conv_add_packet(struct sd *sd, void *data, int data_len, double pts, - double duration, int64_t pos); -struct demux_packet *sd_conv_def_get_converted(struct sd *sd); -void sd_conv_def_reset(struct sd *sd); -void sd_conv_def_uninit(struct sd *sd); - -#define SD_MAX_LINE_LEN 1000 +struct lavc_conv; +bool lavc_conv_supports_format(const char *format); +struct lavc_conv *lavc_conv_create(struct mp_log *log, const char *codec_name, + char *extradata, int extradata_len); +char *lavc_conv_get_extradata(struct lavc_conv *priv); +char **lavc_conv_decode(struct lavc_conv *priv, struct demux_packet *packet); +void lavc_conv_reset(struct lavc_conv *priv); +void lavc_conv_uninit(struct lavc_conv *priv); #endif diff --git a/sub/sd_ass.c b/sub/sd_ass.c index dc045996cd..baf35b5d30 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -40,6 +40,7 @@ struct sd_ass_priv { struct ass_track *ass_track; struct ass_track *shadow_track; // for --sub-ass=no rendering bool is_converted; + struct lavc_conv *converter; bool on_top; struct sub_bitmap *parts; char last_text[500]; @@ -79,21 +80,31 @@ static void mp_ass_add_default_styles(ASS_Track *track, struct MPOpts *opts) static bool supports_format(const char *format) { - // "ssa" is used for the FFmpeg subtitle converter output - return format && (strcmp(format, "ass") == 0 || - strcmp(format, "ssa") == 0); + return (format && strcmp(format, "ass") == 0) || + lavc_conv_supports_format(format); } static int init(struct sd *sd) { struct MPOpts *opts = sd->opts; - if (!sd->ass_library || !sd->ass_renderer || !sd->ass_lock || !sd->codec) + if (!sd->ass_library || !sd->ass_renderer || !sd->ass_lock) return -1; - struct sd_ass_priv *ctx = talloc_zero(NULL, struct sd_ass_priv); + struct sd_ass_priv *ctx = talloc_zero(sd, struct sd_ass_priv); sd->priv = ctx; - ctx->is_converted = sd->converted_from != NULL; + char *extradata = sd->sh->extradata; + int extradata_size = sd->sh->extradata_size; + + if (strcmp(sd->sh->codec, "ass") != 0) { + ctx->is_converted = true; + ctx->converter = lavc_conv_create(sd->log, sd->sh->codec, extradata, + extradata_size); + if (!ctx->converter) + return -1; + extradata = lavc_conv_get_extradata(ctx->converter); + extradata_size = extradata ? strlen(extradata) : 0; + } pthread_mutex_lock(sd->ass_lock); @@ -106,10 +117,8 @@ static int init(struct sd *sd) ctx->shadow_track->PlayResY = 288; mp_ass_add_default_styles(ctx->shadow_track, opts); - if (sd->extradata) { - ass_process_codec_private(ctx->ass_track, sd->extradata, - sd->extradata_len); - } + if (extradata) + ass_process_codec_private(ctx->ass_track, extradata, extradata_size); mp_ass_add_default_styles(ctx->ass_track, opts); @@ -158,15 +167,18 @@ static void decode(struct sd *sd, struct demux_packet *packet) { struct sd_ass_priv *ctx = sd->priv; ASS_Track *track = ctx->ass_track; - if (strcmp(sd->codec, "ass") == 0) { + if (ctx->converter) { + if (check_packet_seen(sd, packet->pos)) + return; + char **r = lavc_conv_decode(ctx->converter, packet); + for (int n = 0; r && r[n]; n++) + ass_process_data(track, r[n], strlen(r[n])); + } else { // Note that for this packet format, libass has an internal mechanism // for discarding duplicate (already seen) packets. ass_process_chunk(track, packet->buffer, packet->len, lrint(packet->pts * 1000), lrint(packet->duration * 1000)); - } else { - if (!check_packet_seen(sd, packet->pos)) - ass_process_data(track, packet->buffer, packet->len); } } @@ -505,14 +517,17 @@ static void reset(struct sd *sd) struct sd_ass_priv *ctx = sd->priv; if (sd->opts->sub_clear_on_seek) ass_flush_events(ctx->ass_track); + if (ctx->converter) + lavc_conv_reset(ctx->converter); } static void uninit(struct sd *sd) { struct sd_ass_priv *ctx = sd->priv; + if (ctx->converter) + lavc_conv_uninit(ctx->converter); ass_free_track(ctx->ass_track); - talloc_free(ctx); } static int control(struct sd *sd, enum sd_ctrl cmd, void *arg) diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c index 563ac554fc..08fff28d8a 100644 --- a/sub/sd_lavc.c +++ b/sub/sd_lavc.c @@ -28,6 +28,7 @@ #include "talloc.h" #include "common/msg.h" #include "common/av_common.h" +#include "demux/stheader.h" #include "options/options.h" #include "video/mp_image.h" #include "sd.h" @@ -110,7 +111,7 @@ static void get_resolution(struct sd *sd, int wh[2]) static int init(struct sd *sd) { struct sd_lavc_priv *priv = talloc_zero(NULL, struct sd_lavc_priv); - enum AVCodecID cid = mp_codec_to_av_codec_id(sd->codec); + enum AVCodecID cid = mp_codec_to_av_codec_id(sd->sh->codec); AVCodecContext *ctx = NULL; AVCodec *sub_codec = avcodec_find_decoder(cid); if (!sub_codec) @@ -118,7 +119,7 @@ static int init(struct sd *sd) ctx = avcodec_alloc_context3(sub_codec); if (!ctx) goto error; - mp_lavc_set_extradata(ctx, sd->extradata, sd->extradata_len); + mp_lavc_set_extradata(ctx, sd->sh->extradata, sd->sh->extradata_size); if (avcodec_open2(ctx, sub_codec, NULL) < 0) goto error; priv->avctx = ctx; diff --git a/sub/sd_lavc_conv.c b/sub/sd_lavc_conv.c index ffea1860cd..21e54c04a7 100644 --- a/sub/sd_lavc_conv.c +++ b/sub/sd_lavc_conv.c @@ -32,8 +32,13 @@ #define HAVE_AV_WEBVTT (LIBAVCODEC_VERSION_MICRO >= 100) -struct sd_lavc_priv { +struct lavc_conv { + struct mp_log *log; AVCodecContext *avctx; + char *codec; + char *extradata; + AVSubtitle cur; + char **cur_list; }; static const char *get_lavc_format(const char *format) @@ -44,7 +49,7 @@ static const char *get_lavc_format(const char *format) return format; } -static bool supports_format(const char *format) +bool lavc_conv_supports_format(const char *format) { format = get_lavc_format(format); enum AVCodecID cid = mp_codec_to_av_codec_id(format); @@ -66,40 +71,43 @@ static void disable_styles(bstr header) } } -static int init(struct sd *sd) +struct lavc_conv *lavc_conv_create(struct mp_log *log, const char *codec_name, + char *extradata, int extradata_len) { - struct sd_lavc_priv *priv = talloc_zero(NULL, struct sd_lavc_priv); + struct lavc_conv *priv = talloc_zero(NULL, struct lavc_conv); + priv->log = log; + priv->cur_list = talloc_array(priv, char*, 0); + priv->codec = talloc_strdup(priv, codec_name); AVCodecContext *avctx = NULL; - const char *fmt = get_lavc_format(sd->codec); + const char *fmt = get_lavc_format(priv->codec); AVCodec *codec = avcodec_find_decoder(mp_codec_to_av_codec_id(fmt)); if (!codec) goto error; avctx = avcodec_alloc_context3(codec); if (!avctx) goto error; - avctx->extradata_size = sd->extradata_len; - avctx->extradata = sd->extradata; + avctx->extradata_size = extradata_len; + avctx->extradata = talloc_memdup(priv, extradata, extradata_len); if (avcodec_open2(avctx, codec, NULL) < 0) goto error; // Documented as "set by libavcodec", but there is no other way avctx->time_base = (AVRational) {1, 1000}; priv->avctx = avctx; - sd->priv = priv; - sd->output_codec = "ssa"; - sd->output_extradata = avctx->subtitle_header; - sd->output_extradata_len = avctx->subtitle_header_size; - if (sd->output_extradata) { - sd->output_extradata = talloc_memdup(sd, sd->output_extradata, - sd->output_extradata_len); - disable_styles((bstr){sd->output_extradata, sd->output_extradata_len}); - } - return 0; + priv->extradata = talloc_strndup(priv, avctx->subtitle_header, + avctx->subtitle_header_size); + disable_styles(bstr0(priv->extradata)); + return priv; error: - MP_FATAL(sd, "Could not open libavcodec subtitle converter\n"); + MP_FATAL(priv, "Could not open libavcodec subtitle converter\n"); av_free(avctx); talloc_free(priv); - return -1; + return NULL; +} + +char *lavc_conv_get_extradata(struct lavc_conv *priv) +{ + return priv->extradata; } #if HAVE_AV_WEBVTT @@ -217,71 +225,56 @@ static int parse_webvtt(AVPacket *in, AVPacket *pkt) #endif -static void decode(struct sd *sd, struct demux_packet *packet) +// Return a NULL-terminated list of ASS event lines. +char **lavc_conv_decode(struct lavc_conv *priv, struct demux_packet *packet) { - struct sd_lavc_priv *priv = sd->priv; AVCodecContext *avctx = priv->avctx; - AVSubtitle sub = {0}; AVPacket pkt; AVPacket parsed_pkt = {0}; int ret, got_sub; + avsubtitle_free(&priv->cur); + priv->cur_list[0] = NULL; + mp_set_av_packet(&pkt, packet, &avctx->time_base); - if (sd->codec && strcmp(sd->codec, "webvtt-webm") == 0) { + if (strcmp(priv->codec, "webvtt-webm") == 0) { if (parse_webvtt(&pkt, &parsed_pkt) < 0) { - MP_ERR(sd, "Error parsing subtitle\n"); + MP_ERR(priv, "Error parsing subtitle\n"); goto done; } pkt = parsed_pkt; } - ret = avcodec_decode_subtitle2(avctx, &sub, &got_sub, &pkt); + ret = avcodec_decode_subtitle2(avctx, &priv->cur, &got_sub, &pkt); if (ret < 0) { - MP_ERR(sd, "Error decoding subtitle\n"); + MP_ERR(priv, "Error decoding subtitle\n"); } else if (got_sub) { - for (int i = 0; i < sub.num_rects; i++) { - if (sub.rects[i]->w > 0 && sub.rects[i]->h > 0) - MP_WARN(sd, "Ignoring bitmap subtitle.\n"); - char *ass_line = sub.rects[i]->ass; + int num_cur = 0; + for (int i = 0; i < priv->cur.num_rects; i++) { + if (priv->cur.rects[i]->w > 0 && priv->cur.rects[i]->h > 0) + MP_WARN(priv, "Ignoring bitmap subtitle.\n"); + char *ass_line = priv->cur.rects[i]->ass; if (!ass_line) - break; - // This might contain embedded timestamps, using the "old" ffmpeg - // ASS packet format, in which case pts/duration might be ignored - // at a later point. - sd_conv_add_packet(sd, ass_line, strlen(ass_line), - packet->pts, packet->duration, packet->pos + i); + continue; + MP_TARRAY_APPEND(priv, priv->cur_list, num_cur, ass_line); } + MP_TARRAY_APPEND(priv, priv->cur_list, num_cur, NULL); } done: - avsubtitle_free(&sub); av_packet_unref(&parsed_pkt); + return priv->cur_list; } -static void reset(struct sd *sd) +void lavc_conv_reset(struct lavc_conv *priv) { - struct sd_lavc_priv *priv = sd->priv; - avcodec_flush_buffers(priv->avctx); - sd_conv_def_reset(sd); } -static void uninit(struct sd *sd) +void lavc_conv_uninit(struct lavc_conv *priv) { - struct sd_lavc_priv *priv = sd->priv; - avcodec_close(priv->avctx); av_free(priv->avctx); talloc_free(priv); } - -const struct sd_functions sd_lavc_conv = { - .name = "lavc_conv", - .supports_format = supports_format, - .init = init, - .decode = decode, - .get_converted = sd_conv_def_get_converted, - .reset = reset, - .uninit = uninit, -}; -- cgit v1.2.3