From b35c680f48994f6842ac70c844348b6698dc4f85 Mon Sep 17 00:00:00 2001 From: nick black Date: Tue, 20 Oct 2020 19:35:16 -0400 Subject: [PATCH] add LoopVideo unit test #1066 --- NEWS.md | 3 ++- USAGE.md | 4 +++- doc/man/man3/notcurses_visual.3.md | 10 ++++++---- include/notcurses/notcurses.h | 4 +++- python/src/notcurses/build_notcurses.py | 1 + tests/visual.cpp | 22 ++++++++++++++++++++++ 6 files changed, 37 insertions(+), 7 deletions(-) diff --git a/NEWS.md b/NEWS.md index c296008aa..3f52b1767 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,7 +2,8 @@ This document attempts to list user-visible changes and any major internal rearrangements of Notcurses. * 2.0.2 (not yet released) - * Add `ncvisual_rewind()`. + * Add `ncvisual_decode_loop()`, which returns to the first frame upon + reaching the end of a file. * 2.0.1 (2020-10-19) * Add `ncmenu_item_set_status()` for disabling or enabling menu items. diff --git a/USAGE.md b/USAGE.md index 1223af098..d4dbafdbf 100644 --- a/USAGE.md +++ b/USAGE.md @@ -2662,9 +2662,11 @@ And finally, the `ncvisual` can be blitted to one or more `ncplane`s: struct ncplane* ncvisual_render(struct notcurses* nc, struct ncvisual* ncv, const struct ncvisual_options* vopts); +// decode the next frame ala ncvisual_decode(), but if we have reached the end, // rewind to the first frame of the ncvisual. a subsequent `ncvisual_render()` // will render the first frame, as if the ncvisual had been closed and reopened. -int ncvisual_rewind(struct ncvisual* nc); +// the return values remain the same as those of ncvisual_decode(). +int ncvisual_decode_loop(struct ncvisual* nc); // each has the empty cell in addition to the product of its dimensions. i.e. // NCBLIT_1x1 has two states: empty and full block. NCBLIT_1x1x4 has five diff --git a/doc/man/man3/notcurses_visual.3.md b/doc/man/man3/notcurses_visual.3.md index ea7bb1a3a..4dbc0a4f8 100644 --- a/doc/man/man3/notcurses_visual.3.md +++ b/doc/man/man3/notcurses_visual.3.md @@ -64,7 +64,7 @@ typedef int (*streamcb)(struct notcurses*, struct ncvisual*, void*); **int ncvisual_decode(struct ncvisual* nc);** -**int ncvisual_rewind(struct ncvisual* nc);** +**int ncvisual_decode_loop(struct ncvisual* nc);** **struct ncplane* ncvisual_render(struct notcurses* nc, struct ncvisual* ncv, const struct ncvisual_options* vopts);** @@ -104,8 +104,8 @@ image and video files can be loaded into visuals using **ncvisual_from_file**. **ncvisual_from_file** discovers the container and codecs, but does not verify that the entire file is well-formed. **ncvisual_decode** ought be invoked to recover subsequent frames, once -per frame. **ncvisual_rewind** will return to the beginning of a multiframe -visual, as if **ncvisual_decode** had never been called on it. +per frame. **ncvisual_decode_loop** will return to the first frame, +as if **ncvisual_decode** had never been called. Once the visual is loaded, it can be transformed using **ncvisual_rotate** and **ncvisual_resize**. These are persistent operations, unlike any scaling @@ -172,7 +172,9 @@ that the entire file is properly-formed. **ncvisual_decode** returns 0 on success, or 1 on end of file, or -1 on failure. It is only necessary for multimedia-based visuals. It advances one -frame for each call. +frame for each call. **ncvisual_decode_loop** has the same return values: when +called following decoding of the last frame, it will return 1, but a subsequent +**ncvisual_render** will return the first frame. **ncvisual_from_plane** returns **NULL** if the **ncvisual** cannot be created and bound. This is usually due to illegal content in the source **ncplane**. diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 30f1a58e1..e69ea69d3 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -2316,9 +2316,11 @@ API void ncvisual_destroy(struct ncvisual* ncv); // success, and -1 on failure. API int ncvisual_decode(struct ncvisual* nc); +// decode the next frame ala ncvisual_decode(), but if we have reached the end, // rewind to the first frame of the ncvisual. a subsequent `ncvisual_render()` // will render the first frame, as if the ncvisual had been closed and reopened. -API int ncvisual_rewind(struct ncvisual* nc); +// the return values remain the same as those of ncvisual_decode(). +API int ncvisual_decode_loop(struct ncvisual* nc); // Rotate the visual 'rads' radians. Only M_PI/2 and -M_PI/2 are // supported at the moment, but this will change FIXME. diff --git a/python/src/notcurses/build_notcurses.py b/python/src/notcurses/build_notcurses.py index a1d881cf9..e4005556c 100644 --- a/python/src/notcurses/build_notcurses.py +++ b/python/src/notcurses/build_notcurses.py @@ -213,6 +213,7 @@ struct ncvisual* ncvisual_from_plane(const struct ncplane* n, ncblitter_e blit, int ncvisual_geom(const struct notcurses* nc, const struct ncvisual* n, const struct ncvisual_options* vopts, int* y, int* x, int* toy, int* tox); void ncvisual_destroy(struct ncvisual* ncv); int ncvisual_decode(struct ncvisual* nc); +int ncvisual_decode_loop(struct ncvisual* nc); int ncvisual_rotate(struct ncvisual* n, double rads); int ncvisual_resize(struct ncvisual* n, int rows, int cols); int ncvisual_polyfill_yx(struct ncvisual* n, int y, int x, uint32_t rgba); diff --git a/tests/visual.cpp b/tests/visual.cpp index b8d152360..463575f15 100644 --- a/tests/visual.cpp +++ b/tests/visual.cpp @@ -101,6 +101,28 @@ TEST_CASE("Visual") { } } + SUBCASE("LoopVideo") { + if(notcurses_canopen_videos(nc_)){ + int dimy, dimx; + ncplane_dim_yx(ncp_, &dimy, &dimx); + auto ncv = ncvisual_from_file(find_data("notcursesII.mkv")); + REQUIRE(ncv); + int ret; + while((ret = ncvisual_decode(ncv)) == 0){ + ; + } + // FIXME verify that it is last frame? + CHECK(1 == ret); + ret = ncvisual_decode_loop(ncv); + CHECK(1 == ret); + struct ncplane* ncp = ncvisual_render(nc_, ncv, nullptr); + CHECK(nullptr != ncp); + // FIXME verify that it is first frame, not last? + ncplane_destroy(ncp); + ncvisual_destroy(ncv); + } + } + SUBCASE("LoadVideoCreatePlane") { if(notcurses_canopen_videos(nc_)){ int dimy, dimx;