diff --git a/src/lib/internal.h b/src/lib/internal.h index 5de0536b0..31459bb6d 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -1074,7 +1074,11 @@ typedef struct ncvisual_implementation { void (*visual_details_seed)(struct ncvisual* ncv); void (*visual_details_destroy)(struct ncvisual_details* deets); int (*visual_decode)(struct ncvisual* nc); + int (*visual_decode_loop)(struct ncvisual* nc); + int (*visual_stream)(notcurses* nc, struct ncvisual* ncv, float timescale, + streamcb streamer, const struct ncvisual_options* vopts, void* curry); char* (*visual_subtitle)(const struct ncvisual* ncv); + int (*visual_resize)(struct ncvisual* ncv, int rows, int cols); bool canopen_images; bool canopen_videos; } ncvisual_implementation; diff --git a/src/lib/visual.cpp b/src/lib/visual.cpp index ed78888c8..349e85a05 100644 --- a/src/lib/visual.cpp +++ b/src/lib/visual.cpp @@ -647,20 +647,19 @@ auto notcurses_canopen_videos(const notcurses* nc __attribute__ ((unused))) -> b } auto ncvisual_decode_loop(ncvisual* nc) -> int { - (void)nc; - return -1; + if(!visual_implementation){ + return -1; + } + return visual_implementation->visual_decode_loop(nc); } auto ncvisual_stream(notcurses* nc, ncvisual* ncv, float timescale, streamcb streamer, const ncvisual_options* vopts, void* curry) -> int { - (void)nc; - (void)ncv; - (void)timescale; - (void)streamer; - (void)vopts; - (void)curry; - return -1; + if(!visual_implementation){ + return -1; + } + return ncvisual_stream(nc, ncv, timescale, streamer, vopts, curry); } auto ncvisual_subtitle(const ncvisual* ncv) -> char* { @@ -671,11 +670,8 @@ auto ncvisual_subtitle(const ncvisual* ncv) -> char* { } auto ncvisual_resize(ncvisual* nc, int rows, int cols) -> int { - // we'd need to verify that it's RGBA as well, except that if we've got no - // multimedia engine, we've only got memory-assembled ncvisuals, which are - // RGBA-native. so we ought be good, but this is undeniably sloppy... - if(nc->rows == rows && nc->cols == cols){ - return 0; + if(!visual_implementation){ + return -1; } - return -1; + return visual_implementation->visual_resize(nc, rows, cols); } diff --git a/src/media/ffmpeg.cpp b/src/media/ffmpeg.cpp index 8f3822056..da792e29f 100644 --- a/src/media/ffmpeg.cpp +++ b/src/media/ffmpeg.cpp @@ -197,7 +197,7 @@ int ffmpeg_decode(ncvisual* nc){ } // resize frame to oframe, converting to RGBA (if necessary) along the way -int ncvisual_resize(ncvisual* nc, int rows, int cols) { +int ffmpeg_resize(ncvisual* nc, int rows, int cols) { const int targformat = AV_PIX_FMT_RGBA; AVFrame* inf = nc->details->oframe ? nc->details->oframe : nc->details->frame; //fprintf(stderr, "got format: %d (%d/%d) want format: %d (%d/%d)\n", inf->format, nc->rows, nc->cols, targformat, rows, cols); @@ -373,9 +373,9 @@ err: // frames carry a presentation time relative to the beginning, so we get an // initial timestamp, and check each frame against the elapsed time to sync // up playback. -int ncvisual_stream(notcurses* nc, ncvisual* ncv, float timescale, - streamcb streamer, const struct ncvisual_options* vopts, - void* curry) { +int ffmpeg_stream(notcurses* nc, ncvisual* ncv, float timescale, + streamcb streamer, const struct ncvisual_options* vopts, + void* curry) { int frame = 1; struct timespec begin; // time we started clock_gettime(CLOCK_MONOTONIC, &begin); @@ -445,7 +445,7 @@ int ncvisual_stream(notcurses* nc, ncvisual* ncv, float timescale, return ncerr; } -int ncvisual_decode_loop(ncvisual* ncv){ +int ffmpeg_decode_loop(ncvisual* ncv){ int r = ffmpeg_decode(ncv); if(r == 1){ if(av_seek_frame(ncv->details->fmtctx, ncv->details->stream_index, 0, AVSEEK_FLAG_FRAME) < 0){ @@ -564,7 +564,7 @@ auto ffmpeg_init(int loglevel) -> int { return 0; } -void ncvisual_printbanner(const notcurses* nc __attribute__ ((unused))){ +void ffmpeg_printbanner(const notcurses* nc __attribute__ ((unused))){ printf(" avformat %u.%u.%u avutil %u.%u.%u swscale %u.%u.%u\n", LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO, LIBAVUTIL_VERSION_MAJOR, LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO, @@ -587,14 +587,17 @@ auto ffmpeg_details_destroy(ncvisual_details* deets) -> void { static const ncvisual_implementation ffmpeg_impl = { .visual_init = ffmpeg_init, - .visual_printbanner = ncvisual_printbanner, + .visual_printbanner = ffmpeg_printbanner, .visual_blit = ffmpeg_blit, .visual_create = ffmpeg_create, .visual_from_file = ffmpeg_from_file, .visual_details_seed = ffmpeg_details_seed, .visual_details_destroy = ffmpeg_details_destroy, .visual_decode = ffmpeg_decode, + .visual_decode_loop = ffmpeg_decode_loop, + .visual_stream = ffmpeg_stream, .visual_subtitle = ffmpeg_subtitle, + .visual_resize = ffmpeg_resize, .canopen_images = true, .canopen_videos = true, }; diff --git a/src/media/none.cpp b/src/media/none.cpp index e953b08f4..c583ad107 100644 --- a/src/media/none.cpp +++ b/src/media/none.cpp @@ -18,16 +18,19 @@ ncvisual* none_from_file(const char* filename) { return nullptr; } -int ncvisual_decode_loop(ncvisual* ncv){ +int none_decode_loop(ncvisual* ncv){ (void)ncv; return -1; } // resize, converting to RGBA (if necessary) along the way -int ncvisual_resize(ncvisual* nc, int rows, int cols) { - (void)nc; - (void)rows; - (void)cols; +int none_resize(ncvisual* nc, int rows, int cols) { + // we'd need to verify that it's RGBA as well, except that if we've got no + // multimedia engine, we've only got memory-assembled ncvisuals, which are + // RGBA-native. so we ought be good, but this is undeniably sloppy... + if(nc->rows == rows && nc->cols == cols){ + return 0; + } return -1; } @@ -44,8 +47,8 @@ int none_blit(struct ncvisual* ncv, int rows, int cols, return -1; } -auto ncvisual_stream(notcurses* nc, ncvisual* ncv, float timescale, - streamcb streamer, const struct ncvisual_options* vopts, void* curry) -> int { +auto none_stream(notcurses* nc, ncvisual* ncv, float timescale, + streamcb streamer, const struct ncvisual_options* vopts, void* curry) -> int { (void)nc; (void)ncv; (void)timescale; @@ -106,7 +109,10 @@ const static ncvisual_implementation none_impl = { .visual_details_seed = none_details_seed, .visual_details_destroy = none_details_destroy, .visual_decode = none_decode, + .visual_decode_loop = none_decode_loop, + .visual_stream = none_stream, .visual_subtitle = none_subtitle, + .visual_resize = none_resize, .canopen_images = false, .canopen_videos = false, }; diff --git a/src/media/oiio.cpp b/src/media/oiio.cpp index 7ac0c12a2..c0d222dda 100644 --- a/src/media/oiio.cpp +++ b/src/media/oiio.cpp @@ -111,7 +111,7 @@ spec.width << "@" << spec.nchannels << " (" << spec.format << ")" << std::endl;* return ncv; } -int ncvisual_decode_loop(ncvisual* ncv){ +int oiio_decode_loop(ncvisual* ncv){ int r = oiio_decode(ncv); if(r == 1){ OIIO::ImageSpec newspec; @@ -127,7 +127,7 @@ int ncvisual_decode_loop(ncvisual* ncv){ } // resize, converting to RGBA (if necessary) along the way -int ncvisual_resize(ncvisual* nc, int rows, int cols) { +int oiio_resize(ncvisual* nc, int rows, int cols) { //fprintf(stderr, "%d/%d -> %d/%d on the resize\n", ncv->rows, ncv->cols, rows, cols); auto ibuf = std::make_unique(); if(nc->details->ibuf && (nc->cols != cols || nc->rows != rows)){ // scale it @@ -180,8 +180,8 @@ int oiio_blit(struct ncvisual* ncv, int rows, int cols, return 0; } -auto ncvisual_stream(notcurses* nc, ncvisual* ncv, float timescale, - streamcb streamer, const struct ncvisual_options* vopts, void* curry) -> int { +auto oiio_stream(notcurses* nc, ncvisual* ncv, float timescale, + streamcb streamer, const struct ncvisual_options* vopts, void* curry) -> int { (void)timescale; // FIXME int frame = 1; struct timespec begin; // time we started @@ -277,7 +277,10 @@ const static ncvisual_implementation oiio_impl = { .visual_details_seed = oiio_details_seed, .visual_details_destroy = oiio_details_destroy, .visual_decode = oiio_decode, + .visual_decode_loop = oiio_decode_loop, + .visual_stream = oiio_stream, .visual_subtitle = oiio_subtitle, + .visual_resize = oiio_resize, .canopen_images = true, .canopen_videos = false, }; diff --git a/tests/rotate.cpp b/tests/rotate.cpp index c36101193..d2060e268 100644 --- a/tests/rotate.cpp +++ b/tests/rotate.cpp @@ -191,20 +191,22 @@ TEST_CASE("Rotate") { } free(c); } - opts.n = rendered; - // FIXME check pixels after all rotations - CHECK(0 == ncvisual_rotate(ncv, M_PI / 2)); - CHECK(ncvisual_render(nc_, ncv, &opts)); - CHECK(0 == notcurses_render(nc_)); - CHECK(0 == ncvisual_rotate(ncv, M_PI / 2)); - CHECK(ncvisual_render(nc_, ncv, &opts)); - CHECK(0 == notcurses_render(nc_)); - CHECK(0 == ncvisual_rotate(ncv, M_PI / 2)); - CHECK(ncvisual_render(nc_, ncv, &opts)); - CHECK(0 == notcurses_render(nc_)); - CHECK(0 == ncvisual_rotate(ncv, M_PI / 2)); - CHECK(ncvisual_render(nc_, ncv, &opts)); - CHECK(0 == notcurses_render(nc_)); + if(notcurses_canopen_images(nc_)){ + opts.n = rendered; + // FIXME check pixels after all rotations + CHECK(0 == ncvisual_rotate(ncv, M_PI / 2)); + CHECK(ncvisual_render(nc_, ncv, &opts)); + CHECK(0 == notcurses_render(nc_)); + CHECK(0 == ncvisual_rotate(ncv, M_PI / 2)); + CHECK(ncvisual_render(nc_, ncv, &opts)); + CHECK(0 == notcurses_render(nc_)); + CHECK(0 == ncvisual_rotate(ncv, M_PI / 2)); + CHECK(ncvisual_render(nc_, ncv, &opts)); + CHECK(0 == notcurses_render(nc_)); + CHECK(0 == ncvisual_rotate(ncv, M_PI / 2)); + CHECK(ncvisual_render(nc_, ncv, &opts)); + CHECK(0 == notcurses_render(nc_)); + } ncvisual_destroy(ncv); ncplane_destroy(rendered); CHECK(0 == notcurses_render(nc_)); @@ -242,20 +244,22 @@ TEST_CASE("Rotate") { } free(c); } - // FIXME check pixels after all rotations - opts.n = rendered; - CHECK(0 == ncvisual_rotate(ncv, -M_PI / 2)); - CHECK(ncvisual_render(nc_, ncv, &opts)); - CHECK(0 == notcurses_render(nc_)); - CHECK(0 == ncvisual_rotate(ncv, -M_PI / 2)); - CHECK(ncvisual_render(nc_, ncv, &opts)); - CHECK(0 == notcurses_render(nc_)); - CHECK(0 == ncvisual_rotate(ncv, -M_PI / 2)); - CHECK(ncvisual_render(nc_, ncv, &opts)); - CHECK(0 == notcurses_render(nc_)); - CHECK(0 == ncvisual_rotate(ncv, -M_PI / 2)); - CHECK(ncvisual_render(nc_, ncv, &opts)); - CHECK(0 == notcurses_render(nc_)); + if(notcurses_canopen_images(nc_)){ + // FIXME check pixels after all rotations + opts.n = rendered; + CHECK(0 == ncvisual_rotate(ncv, -M_PI / 2)); + CHECK(ncvisual_render(nc_, ncv, &opts)); + CHECK(0 == notcurses_render(nc_)); + CHECK(0 == ncvisual_rotate(ncv, -M_PI / 2)); + CHECK(ncvisual_render(nc_, ncv, &opts)); + CHECK(0 == notcurses_render(nc_)); + CHECK(0 == ncvisual_rotate(ncv, -M_PI / 2)); + CHECK(ncvisual_render(nc_, ncv, &opts)); + CHECK(0 == notcurses_render(nc_)); + CHECK(0 == ncvisual_rotate(ncv, -M_PI / 2)); + CHECK(ncvisual_render(nc_, ncv, &opts)); + CHECK(0 == notcurses_render(nc_)); + } ncvisual_destroy(ncv); ncplane_destroy(rendered); CHECK(0 == notcurses_render(nc_));