diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d7239353..4c418ab3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ pkg_check_modules(AVFORMAT REQUIRED libavformat>=57.0) pkg_check_modules(AVUTIL REQUIRED libavutil>=56.0) pkg_check_modules(SWSCALE REQUIRED libswscale>=5.0) elseif(${USE_OIIO}) -pkg_check_modules(OIIO REQUIRED OpenImageIO>=2.0.7) +pkg_check_modules(OIIO REQUIRED OpenImageIO>=2.1) endif() find_library(LIBRT rt) if(${USE_TESTS}) diff --git a/README.md b/README.md index 944ac0c42..b54593f49 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ that fine library. * (build+runtime) From NCURSES: terminfo 6.1+ * (OPTIONAL) (build+runtime) From QR-Code-generator: [libqrcodegen](https://github.com/nayuki/QR-Code-generator) 1.5.0+ * (OPTIONAL) (build+runtime) From [FFMpeg](https://www.ffmpeg.org/): libswscale 5.0+, libavformat 57.0+, libavutil 56.0+ -* (OPTIONAL) (build+runtime) [OpenImageIO](https://github.com/OpenImageIO/oiio) 2.0.7+ +* (OPTIONAL) (build+runtime) [OpenImageIO](https://github.com/OpenImageIO/oiio) 2.1+ * (OPTIONAL) (testing) [Doctest](https://github.com/onqtam/doctest) 2.3.5+ * (OPTIONAL) (documentation) [pandoc](https://pandoc.org/index.html) 1.19.2+ * (OPTIONAL) (python bindings): Python 3.7+, [CFFI](https://pypi.org/project/cffi/) 1.13.2+ diff --git a/data/samoa.avi b/data/samoa.avi index 08bb7386f..cd0c7fdcb 100644 Binary files a/data/samoa.avi and b/data/samoa.avi differ diff --git a/doc/man/man1/notcurses-demo.1.md b/doc/man/man1/notcurses-demo.1.md index 498537c1f..38cf2cf83 100644 --- a/doc/man/man1/notcurses-demo.1.md +++ b/doc/man/man1/notcurses-demo.1.md @@ -68,7 +68,7 @@ At any time, press 'q' to quit. The demo is best run in at least an 80x45 termin **-V**: Print the program name and version, and exit with success. -demospec: Select which demos to run, and what order to run them in. The default is **ixethbcgrwuvlsfjqo**. See above for a list of demos. +demospec: Select which demos to run, and what order to run them in. The default is **ixethnbcgrwuvlsfjqo**. See above for a list of demos. Default margins are all 0, and thus the full screen will be rendered. Using **-m**, margins can be supplied. Provide a single number to set all four margins diff --git a/src/lib/libav.c b/src/lib/libav.c index a4c2c4f59..0718a8cc7 100644 --- a/src/lib/libav.c +++ b/src/lib/libav.c @@ -515,6 +515,10 @@ bool notcurses_canopen(const notcurses* nc __attribute__ ((unused))){ return false; } +ncplane* ncvisual_plane(ncvisual* ncv){ + return ncv->ncp; +} + nc_err_e ncvisual_decode(ncvisual* nc){ (void)nc; return NCERR_UNIMPLEMENTED; diff --git a/src/lib/metric.c b/src/lib/metric.c index 8d771457f..7c33a92d3 100644 --- a/src/lib/metric.c +++ b/src/lib/metric.c @@ -19,7 +19,7 @@ const char *ncmetric(uintmax_t val, unsigned decimal, char *buf, int omitdec, unsigned mult, int uprefix){ const char prefixes[] = "KMGTPEZY"; // 10^21-1 encompasses 2^64-1 // FIXME can't use multibyte μ unless we enlarge the target buffer - const char subprefixes[] = "mµnpfazy"; // 10^24-1 + const char subprefixes[] = "munpfazy"; // 10^24-1 unsigned consumed = 0; uintmax_t dv; diff --git a/src/lib/oiio.cpp b/src/lib/oiio.cpp index 47be16ea4..1683e55f3 100644 --- a/src/lib/oiio.cpp +++ b/src/lib/oiio.cpp @@ -1,17 +1,37 @@ #include "version.h" #ifdef USE_OIIO +#include #include #include #include +#include #include "internal.h" +// this garbage is thanks to https://github.com/dankamongmen/notcurses/issues/541 +// and https://github.com/OpenImageIO/oiio/issues/2566. fml. FIXME kill this. +namespace OpenImageIO_v2_1::ImageBufAlgo { +ImageBuf OIIO_API from_IplImage (const struct IplImage *ipl, + TypeDesc convert){ + ImageBuf dst; + if (!ipl) { + dst.errorf("Passed NULL source IplImage"); + return dst; + } + return dst; + (void)convert; +} +} + typedef struct ncvisual { int packet_outstanding; int dstwidth, dstheight; float timescale; // scale frame duration by this value std::unique_ptr image; // must be close()d - OIIO::ImageBuf raw; - OIIO::ImageBuf scaled; // in use IFF style == NONE(?) + std::unique_ptr raw; + char* filename; + bool did_scaling; + uint64_t framenum; + OIIO::ImageBuf scaled; // in use IFF did_scaling; std::unique_ptr frame; ncplane* ncp; // if we're creating the plane based off the first frame's dimensions, these @@ -22,8 +42,6 @@ typedef struct ncvisual { struct notcurses* ncobj; // set iff this ncvisual "owns" its ncplane } ncvisual; -extern "C" { - ncplane* ncvisual_plane(ncvisual* ncv){ return ncv->ncp; } @@ -33,13 +51,14 @@ bool notcurses_canopen(const notcurses* nc __attribute__ ((unused))){ } static ncvisual* -ncvisual_create(float timescale){ +ncvisual_create(const char* filename, float timescale){ auto ret = new ncvisual; if(ret == nullptr){ return nullptr; } ret->packet_outstanding = 0; ret->dstwidth = ret->dstheight = 0; + ret->framenum = 0; ret->timescale = timescale; ret->image = nullptr; ret->ncp = nullptr; @@ -47,12 +66,14 @@ ncvisual_create(float timescale){ ret->style = NCSCALE_NONE; ret->ncobj = nullptr; ret->frame = nullptr; + ret->raw = nullptr; + ret->filename = strdup(filename); return ret; } static ncvisual* ncvisual_open(const char* filename, nc_err_e* err){ - ncvisual* ncv = ncvisual_create(1); + ncvisual* ncv = ncvisual_create(filename, 1); if(ncv == nullptr){ *err = NCERR_NOMEM; return nullptr; @@ -63,7 +84,7 @@ ncvisual_open(const char* filename, nc_err_e* err){ *err = NCERR_DECODE; return nullptr; } -/*const auto &spec = ncv->image->spec(); +/*const auto &spec = ncv->image->spec_dimensions(); std::cout << "Opened " << filename << ": " << spec.height << "x" << spec.width << "@" << spec.nchannels << " (" << spec.format << ")" << std::endl;*/ return ncv; @@ -99,21 +120,29 @@ ncvisual* ncvisual_open_plane(notcurses* nc, const char* filename, } nc_err_e ncvisual_decode(ncvisual* nc){ + const auto &spec = nc->image->spec_dimensions(nc->framenum); + OIIO::ImageSpec newspec; if(nc->frame){ - return NCERR_EOF; // FIXME + if(!nc->image->seek_subimage(nc->image->current_subimage() + 1, 0, newspec)){ + return NCERR_EOF; + } + // FIXME check newspec vis-a-vis image->spec() } - const auto &spec = nc->image->spec(); +//fprintf(stderr, "SUBIMAGE: %d\n", nc->image->current_subimage()); + nc->did_scaling = false; auto pixels = spec.width * spec.height;// * spec.nchannels; if(spec.nchannels < 3 || spec.nchannels > 4){ return NCERR_DECODE; // FIXME get some to test with } nc->frame = std::make_unique(pixels); - if(spec.nchannels == 3){ + if(spec.nchannels == 3){ // FIXME replace with channel shuffle std::fill(nc->frame.get(), nc->frame.get() + pixels, 0xfffffffful); } - if(!nc->image->read_image(0, 0, 0, spec.nchannels, OIIO::TypeDesc(OIIO::TypeDesc::UINT8, 4), nc->frame.get(), 4)){ +//fprintf(stderr, "READING: %d %ju\n", nc->image->current_subimage(), nc->framenum); + if(!nc->image->read_image(nc->framenum++, 0, 0, spec.nchannels, OIIO::TypeDesc(OIIO::TypeDesc::UINT8, 4), nc->frame.get(), 4)){ return NCERR_DECODE; } +//fprintf(stderr, "READ: %d %ju\n", nc->image->current_subimage(), nc->framenum); /*for(int i = 0 ; i < pixels ; ++i){ //fprintf(stderr, "%06d %02x %02x %02x %02x\n", i, fprintf(stderr, "%06d %d %d %d %d\n", i, @@ -125,7 +154,8 @@ nc_err_e ncvisual_decode(ncvisual* nc){ }*/ OIIO::ImageSpec rgbaspec = spec; rgbaspec.nchannels = 4; - nc->raw.reset(rgbaspec, nc->frame.get()); + nc->raw = std::make_unique(rgbaspec, nc->frame.get()); +//fprintf(stderr, "SUBS: %d\n", nc->raw->nsubimages()); int rows, cols; if(nc->ncp == nullptr){ // create plane if(nc->style == NCSCALE_NONE){ @@ -154,6 +184,13 @@ nc_err_e ncvisual_decode(ncvisual* nc){ nc->dstwidth = cols; } } + if(nc->dstwidth != spec.width || nc->dstheight != spec.height){ // scale it + OIIO::ROI roi(0, nc->dstwidth, 0, nc->dstheight, 0, 1, 0, 4); + if(!OIIO::ImageBufAlgo::resize(nc->scaled, *nc->raw, "", 0, roi)){ + // FIXME + } + nc->did_scaling = true; + } return NCERR_SUCCESS; } @@ -165,7 +202,8 @@ int ncvisual_render(const ncvisual* ncv, int begy, int begx, int leny, int lenx) if(ncv->frame == nullptr){ return -1; } - const auto &spec = ncv->image->spec(); + const auto &spec = ncv->did_scaling ? ncv->scaled.spec() : ncv->raw->spec(); + const void* pixels = ncv->did_scaling ? ncv->scaled.localpixels() : ncv->raw->localpixels(); //fprintf(stderr, "render %d/%d to %dx%d+%dx%d\n", f->height, f->width, begy, begx, leny, lenx); if(begx >= spec.width || begy >= spec.height){ return -1; @@ -191,7 +229,7 @@ int ncvisual_render(const ncvisual* ncv, int begy, int begx, int leny, int lenx) //fprintf(stderr, "render: %dx%d:%d+%d of %d/%d -> %dx%d\n", begy, begx, leny, lenx, f->height, f->width, dimy, dimx); const int linesize = spec.width * 4; int ret = ncblit_rgba(ncv->ncp, ncv->placey, ncv->placex, linesize, - ncv->frame.get(), begy, begx, leny, lenx); + pixels, begy, begx, leny, lenx); //av_frame_unref(ncv->oframe); return ret; } @@ -268,6 +306,7 @@ void ncvisual_destroy(ncvisual* ncv){ if(ncv->ncobj){ ncplane_destroy(ncv->ncp); } + free(ncv->filename); delete ncv; } } @@ -276,6 +315,4 @@ const char* oiio_version(void){ return OIIO_VERSION_STRING; } -} // extern "C" - #endif diff --git a/src/poc/rgbbg.c b/src/poc/rgbbg.cpp similarity index 100% rename from src/poc/rgbbg.c rename to src/poc/rgbbg.cpp