From 1448960cd51025a5536933b41fff4b922aa9b0e9 Mon Sep 17 00:00:00 2001 From: nick black Date: Tue, 27 Jul 2021 09:49:15 -0400 Subject: [PATCH] start handling type-1 DVB subtitles #1311 --- USAGE.md | 8 +++-- doc/man/man3/notcurses_visual.3.md | 2 +- include/ncpp/Visual.hh | 4 +-- include/notcurses/notcurses.h | 9 +++--- src/lib/internal.h | 2 +- src/lib/visual.c | 16 ++++----- src/media/ffmpeg.c | 52 +++++++++++++++++++++++++++--- src/media/oiio-indep.c | 6 ---- src/player/play.cpp | 14 ++++---- 9 files changed, 77 insertions(+), 36 deletions(-) diff --git a/USAGE.md b/USAGE.md index 75a055f4f..d94a023a2 100644 --- a/USAGE.md +++ b/USAGE.md @@ -3184,9 +3184,11 @@ int ncvisual_at_yx(const struct ncvisual* n, int y, int x, uint32_t* pixel); // Set the specified pixel in the specified ncvisual. int ncvisual_set_yx(const struct ncvisual* n, int y, int x, uint32_t pixel); -// If a subtitle ought be displayed at this time, return a heap-allocated copy -// of the UTF8 text. -char* ncvisual_subtitle(const struct ncvisual* ncv); +// If a subtitle ought be displayed at this time, return a new plane (bound +// to 'parent' containing the subtitle, which might be text or graphics +// (depending on the input format). +struct ncplane* ncvisual_subtitle(struct ncplane* parent, + const struct ncvisual* ncv); ``` And finally, the `ncvisual` can be blitted to one or more `ncplane`s: diff --git a/doc/man/man3/notcurses_visual.3.md b/doc/man/man3/notcurses_visual.3.md index d1b9c3590..96aa73d0a 100644 --- a/doc/man/man3/notcurses_visual.3.md +++ b/doc/man/man3/notcurses_visual.3.md @@ -90,7 +90,7 @@ typedef int (*streamcb)(struct notcurses*, struct ncvisual*, void*); **int ncvisual_set_yx(const struct ncvisual* ***n***, int ***y***, int ***x***, uint32_t ***pixel***);** -**char* ncvisual_subtitle(const struct ncvisual* ***ncv***);** +**struct ncplane* ncvisual_subtitle(struct ncplane* ***parent***, const struct ncvisual* ***ncv***);** **int notcurses_lex_scalemode(const char* ***op***, ncscale_e* ***scaling***);** diff --git a/include/ncpp/Visual.hh b/include/ncpp/Visual.hh index 298fab650..873c9dcd1 100644 --- a/include/ncpp/Visual.hh +++ b/include/ncpp/Visual.hh @@ -76,9 +76,9 @@ namespace ncpp return error_guard (ncvisual_stream (get_notcurses (), visual, timescale, streamer, vopts, curry), -1); } - char* subtitle () const noexcept + ncplane* subtitle (Plane& p) const noexcept { - return ncvisual_subtitle (visual); + return ncvisual_subtitle (p, visual); } bool rotate (double rads) const NOEXCEPT_MAYBE diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index c613ff58e..fb05b0400 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -2745,10 +2745,11 @@ ncvisualplane_create(struct ncplane* n, const struct ncplane_options* opts, return newn; } -// If a subtitle ought be displayed at this time, return a heap-allocated copy -// of the UTF8 text. -API ALLOC char* ncvisual_subtitle(const struct ncvisual* ncv) - __attribute__ ((nonnull (1))); +// If a subtitle ought be displayed at this time, return a new plane (bound +// to 'parent' containing the subtitle, which might be text or graphics +// (depending on the input format). +API ALLOC struct ncplane* ncvisual_subtitle(struct ncplane* parent, const struct ncvisual* ncv) + __attribute__ ((nonnull (1, 2))); // Get the default *media* (not plot) blitter for this environment when using // the specified scaling method. Currently, this means: diff --git a/src/lib/internal.h b/src/lib/internal.h index 3eb48deb6..7743f0eca 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -1710,7 +1710,7 @@ typedef struct ncvisual_implementation { int (*visual_decode_loop)(struct ncvisual* nc); int (*visual_stream)(notcurses* nc, struct ncvisual* ncv, float timescale, ncstreamcb streamer, const struct ncvisual_options* vopts, void* curry); - char* (*visual_subtitle)(const struct ncvisual* ncv); + struct ncplane* (*visual_subtitle)(struct ncplane* parent, const struct ncvisual* ncv); int rowalign; // rowstride base, can be 0 for no padding // do a persistent resize, changing the ncv itself int (*visual_resize)(struct ncvisual* ncv, int rows, int cols); diff --git a/src/lib/visual.c b/src/lib/visual.c index 10046149c..a9c6453fb 100644 --- a/src/lib/visual.c +++ b/src/lib/visual.c @@ -63,11 +63,11 @@ int ncvisual_stream(notcurses* nc, ncvisual* ncv, float timescale, return visual_implementation.visual_stream(nc, ncv, timescale, streamer, vopts, curry); } -char* ncvisual_subtitle(const ncvisual* ncv){ +ncplane* ncvisual_subtitle(ncplane* parent, const ncvisual* ncv){ if(!visual_implementation.visual_subtitle){ return NULL; } - return visual_implementation.visual_subtitle(ncv); + return visual_implementation.visual_subtitle(parent, ncv); } int ncvisual_blit(ncvisual* ncv, int rows, int cols, ncplane* n, @@ -1084,14 +1084,14 @@ int ncvisual_simple_streamer(ncvisual* ncv, struct ncvisual_options* vopts, } int ret = 0; if(curry){ + // FIXME improve this hrmmmmm ncplane* subncp = curry; - char* subtitle = ncvisual_subtitle(ncv); - if(subtitle){ - if(ncplane_putstr_yx(subncp, 0, 0, subtitle) < 0){ - ret = -1; - } - free(subtitle); + if(subncp->blist){ +fprintf(stderr, "KILLING %p\n", subncp->blist); + ncplane_destroy(subncp->blist); + subncp->blist = NULL; } + struct ncplane* subtitle = ncvisual_subtitle(subncp, ncv); } clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, tspec, NULL); return ret; diff --git a/src/media/ffmpeg.c b/src/media/ffmpeg.c index cceb4b57b..ddc43aea5 100644 --- a/src/media/ffmpeg.c +++ b/src/media/ffmpeg.c @@ -115,15 +115,59 @@ deass(const char* ass){ return dup; } -char* ffmpeg_subtitle(const ncvisual* ncv){ +static struct ncplane* +subtitle_plane_from_text(ncplane* parent, const char* text){ + if(parent == NULL){ +//logerror("need a parent plane\n"); + return NULL; + } + int width = ncstrwidth(text); + if(width <= 0){ +//logwarn("couldn't extract subtitle from %s\n", text); + return NULL; + } + int rows = (width + ncplane_dim_x(parent) - 1) / ncplane_dim_x(parent); + struct ncplane_options nopts = { + .y = ncplane_dim_y(parent) - (rows + 1), + .rows = rows, + .cols = ncplane_dim_x(parent), + }; + struct ncplane* n = ncplane_create(parent, &nopts); + if(n == NULL){ +//logerror("error creating subtitle plane\n"); + return NULL; + } + uint64_t channels = 0; + ncchannels_set_fg_alpha(&channels, NCALPHA_TRANSPARENT); + ncchannels_set_bg_alpha(&channels, NCALPHA_TRANSPARENT); + ncplane_set_base(n, "", 0, channels); + ncplane_puttext(n, 0, NCALIGN_LEFT, text, NULL); + return n; +} + +struct ncplane* ffmpeg_subtitle(ncplane* parent, const ncvisual* ncv){ for(unsigned i = 0 ; i < ncv->details->subtitle.num_rects ; ++i){ + // it is possible that there are more than one subtitle rects present, + // but we only bother dealing with the first one we find FIXME? const AVSubtitleRect* rect = ncv->details->subtitle.rects[i]; if(rect->type == SUBTITLE_ASS){ - return deass(rect->ass); + char* ass = deass(rect->ass); + struct ncplane* n = NULL; + if(ass){ + n = subtitle_plane_from_text(parent, ass); + } + free(ass); + return n; }else if(rect->type == SUBTITLE_TEXT){; - return strdup(rect->text); + return subtitle_plane_from_text(parent, rect->text); }else if(rect->type == SUBTITLE_BITMAP){ - // FIXME + // there are technically up to AV_NUM_DATA_POINTERS planes, but we + // only try to work with the first FIXME? + if(rect->linesize[0] != rect->w){ +//logwarn("bitmap subtitle size %d != width %d\n", rect->linesize[0], rect->w); + return NULL; + } + // FIXME interpret the bytes of each line } } return NULL; diff --git a/src/media/oiio-indep.c b/src/media/oiio-indep.c index bce0cb5ed..6d7613c4a 100644 --- a/src/media/oiio-indep.c +++ b/src/media/oiio-indep.c @@ -64,11 +64,6 @@ int oiio_stream(struct notcurses* nc, ncvisual* ncv, float timescale, return -1; } -char* oiio_subtitle(const ncvisual* ncv) { // no support in OIIO - (void)ncv; - return NULL; -} - int oiio_init(int logl __attribute__ ((unused))) { // FIXME set OIIO global attribute "debug" based on loglevel // FIXME check OIIO_VERSION_STRING components against linked openimageio_version() @@ -85,7 +80,6 @@ const ncvisual_implementation local_visual_implementation = { .visual_decode = oiio_decode, .visual_decode_loop = oiio_decode_loop, .visual_stream = oiio_stream, - .visual_subtitle = oiio_subtitle, .visual_resize = oiio_resize, .visual_destroy = oiio_destroy, .canopen_images = true, diff --git a/src/player/play.cpp b/src/player/play.cpp index 3812082b3..a12f25ea0 100644 --- a/src/player/play.cpp +++ b/src/player/play.cpp @@ -44,7 +44,8 @@ struct marshal { ncblitter_e blitter; // can be changed while streaming, must propagate out }; -auto handle_subtitle(char* subtitle, struct marshal* marsh, +/* +auto handle_subtitle(struct ncplane* subp, struct marshal* marsh, const ncvisual_options* vopts) -> void { if(!marsh->subtitle_plane){ int dimx, dimy; @@ -72,9 +73,8 @@ auto handle_subtitle(char* subtitle, struct marshal* marsh, }else{ ncplane_erase(marsh->subtitle_plane); } - ncplane_printf_yx(marsh->subtitle_plane, 0, 0, "%s", subtitle); - free(subtitle); } +*/ // frame count is in the curry. original time is kept in n's userptr. auto perframe(struct ncvisual* ncv, struct ncvisual_options* vopts, @@ -106,10 +106,10 @@ auto perframe(struct ncvisual* ncv, struct ncvisual_options* vopts, stdn->printf(0, NCAlign::Left, "frame %06d (%s)", marsh->framecount, notcurses_str_blitter(vopts->blitter)); } - char* subtitle = ncvisual_subtitle(ncv); - if(subtitle){ - handle_subtitle(subtitle, marsh, vopts); - } + struct ncplane* subp = ncvisual_subtitle(*stdn, ncv); + //if(subtitle){ + // handle_subtitle(subtitle, marsh, vopts); + //} const int64_t h = ns / (60 * 60 * NANOSECS_IN_SEC); ns -= h * (60 * 60 * NANOSECS_IN_SEC); const int64_t m = ns / (60 * NANOSECS_IN_SEC);