oiio: image scaling #535, subimages for video #536

pull/555/head
nick black 4 years ago committed by Nick Black
parent f4f58432b8
commit 7d1e3c77c8

@ -43,7 +43,7 @@ pkg_check_modules(AVFORMAT REQUIRED libavformat>=57.0)
pkg_check_modules(AVUTIL REQUIRED libavutil>=56.0) pkg_check_modules(AVUTIL REQUIRED libavutil>=56.0)
pkg_check_modules(SWSCALE REQUIRED libswscale>=5.0) pkg_check_modules(SWSCALE REQUIRED libswscale>=5.0)
elseif(${USE_OIIO}) elseif(${USE_OIIO})
pkg_check_modules(OIIO REQUIRED OpenImageIO>=2.0.7) pkg_check_modules(OIIO REQUIRED OpenImageIO>=2.1)
endif() endif()
find_library(LIBRT rt) find_library(LIBRT rt)
if(${USE_TESTS}) if(${USE_TESTS})

@ -107,7 +107,7 @@ that fine library.
* (build+runtime) From NCURSES: terminfo 6.1+ * (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 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) 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) (testing) [Doctest](https://github.com/onqtam/doctest) 2.3.5+
* (OPTIONAL) (documentation) [pandoc](https://pandoc.org/index.html) 1.19.2+ * (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+ * (OPTIONAL) (python bindings): Python 3.7+, [CFFI](https://pypi.org/project/cffi/) 1.13.2+

Binary file not shown.

@ -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. **-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 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 **-m**, margins can be supplied. Provide a single number to set all four margins

@ -515,6 +515,10 @@ bool notcurses_canopen(const notcurses* nc __attribute__ ((unused))){
return false; return false;
} }
ncplane* ncvisual_plane(ncvisual* ncv){
return ncv->ncp;
}
nc_err_e ncvisual_decode(ncvisual* nc){ nc_err_e ncvisual_decode(ncvisual* nc){
(void)nc; (void)nc;
return NCERR_UNIMPLEMENTED; return NCERR_UNIMPLEMENTED;

@ -19,7 +19,7 @@ const char *ncmetric(uintmax_t val, unsigned decimal, char *buf, int omitdec,
unsigned mult, int uprefix){ unsigned mult, int uprefix){
const char prefixes[] = "KMGTPEZY"; // 10^21-1 encompasses 2^64-1 const char prefixes[] = "KMGTPEZY"; // 10^21-1 encompasses 2^64-1
// FIXME can't use multibyte μ unless we enlarge the target buffer // 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; unsigned consumed = 0;
uintmax_t dv; uintmax_t dv;

@ -1,17 +1,37 @@
#include "version.h" #include "version.h"
#ifdef USE_OIIO #ifdef USE_OIIO
#include <OpenImageIO/filter.h>
#include <OpenImageIO/version.h> #include <OpenImageIO/version.h>
#include <OpenImageIO/imageio.h> #include <OpenImageIO/imageio.h>
#include <OpenImageIO/imagebuf.h> #include <OpenImageIO/imagebuf.h>
#include <OpenImageIO/imagebufalgo.h>
#include "internal.h" #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 { typedef struct ncvisual {
int packet_outstanding; int packet_outstanding;
int dstwidth, dstheight; int dstwidth, dstheight;
float timescale; // scale frame duration by this value float timescale; // scale frame duration by this value
std::unique_ptr<OIIO::ImageInput> image; // must be close()d std::unique_ptr<OIIO::ImageInput> image; // must be close()d
OIIO::ImageBuf raw; std::unique_ptr<OIIO::ImageBuf> raw;
OIIO::ImageBuf scaled; // in use IFF style == NONE(?) char* filename;
bool did_scaling;
uint64_t framenum;
OIIO::ImageBuf scaled; // in use IFF did_scaling;
std::unique_ptr<uint32_t[]> frame; std::unique_ptr<uint32_t[]> frame;
ncplane* ncp; ncplane* ncp;
// if we're creating the plane based off the first frame's dimensions, these // 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 struct notcurses* ncobj; // set iff this ncvisual "owns" its ncplane
} ncvisual; } ncvisual;
extern "C" {
ncplane* ncvisual_plane(ncvisual* ncv){ ncplane* ncvisual_plane(ncvisual* ncv){
return ncv->ncp; return ncv->ncp;
} }
@ -33,13 +51,14 @@ bool notcurses_canopen(const notcurses* nc __attribute__ ((unused))){
} }
static ncvisual* static ncvisual*
ncvisual_create(float timescale){ ncvisual_create(const char* filename, float timescale){
auto ret = new ncvisual; auto ret = new ncvisual;
if(ret == nullptr){ if(ret == nullptr){
return nullptr; return nullptr;
} }
ret->packet_outstanding = 0; ret->packet_outstanding = 0;
ret->dstwidth = ret->dstheight = 0; ret->dstwidth = ret->dstheight = 0;
ret->framenum = 0;
ret->timescale = timescale; ret->timescale = timescale;
ret->image = nullptr; ret->image = nullptr;
ret->ncp = nullptr; ret->ncp = nullptr;
@ -47,12 +66,14 @@ ncvisual_create(float timescale){
ret->style = NCSCALE_NONE; ret->style = NCSCALE_NONE;
ret->ncobj = nullptr; ret->ncobj = nullptr;
ret->frame = nullptr; ret->frame = nullptr;
ret->raw = nullptr;
ret->filename = strdup(filename);
return ret; return ret;
} }
static ncvisual* static ncvisual*
ncvisual_open(const char* filename, nc_err_e* err){ ncvisual_open(const char* filename, nc_err_e* err){
ncvisual* ncv = ncvisual_create(1); ncvisual* ncv = ncvisual_create(filename, 1);
if(ncv == nullptr){ if(ncv == nullptr){
*err = NCERR_NOMEM; *err = NCERR_NOMEM;
return nullptr; return nullptr;
@ -63,7 +84,7 @@ ncvisual_open(const char* filename, nc_err_e* err){
*err = NCERR_DECODE; *err = NCERR_DECODE;
return nullptr; return nullptr;
} }
/*const auto &spec = ncv->image->spec(); /*const auto &spec = ncv->image->spec_dimensions();
std::cout << "Opened " << filename << ": " << spec.height << "x" << std::cout << "Opened " << filename << ": " << spec.height << "x" <<
spec.width << "@" << spec.nchannels << " (" << spec.format << ")" << std::endl;*/ spec.width << "@" << spec.nchannels << " (" << spec.format << ")" << std::endl;*/
return ncv; return ncv;
@ -99,21 +120,29 @@ ncvisual* ncvisual_open_plane(notcurses* nc, const char* filename,
} }
nc_err_e ncvisual_decode(ncvisual* nc){ nc_err_e ncvisual_decode(ncvisual* nc){
const auto &spec = nc->image->spec_dimensions(nc->framenum);
OIIO::ImageSpec newspec;
if(nc->frame){ if(nc->frame){
return NCERR_EOF; // FIXME if(!nc->image->seek_subimage(nc->image->current_subimage() + 1, 0, newspec)){
return NCERR_EOF;
} }
const auto &spec = nc->image->spec(); // FIXME check newspec vis-a-vis image->spec()
}
//fprintf(stderr, "SUBIMAGE: %d\n", nc->image->current_subimage());
nc->did_scaling = false;
auto pixels = spec.width * spec.height;// * spec.nchannels; auto pixels = spec.width * spec.height;// * spec.nchannels;
if(spec.nchannels < 3 || spec.nchannels > 4){ if(spec.nchannels < 3 || spec.nchannels > 4){
return NCERR_DECODE; // FIXME get some to test with return NCERR_DECODE; // FIXME get some to test with
} }
nc->frame = std::make_unique<uint32_t[]>(pixels); nc->frame = std::make_unique<uint32_t[]>(pixels);
if(spec.nchannels == 3){ if(spec.nchannels == 3){ // FIXME replace with channel shuffle
std::fill(nc->frame.get(), nc->frame.get() + pixels, 0xfffffffful); 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; return NCERR_DECODE;
} }
//fprintf(stderr, "READ: %d %ju\n", nc->image->current_subimage(), nc->framenum);
/*for(int i = 0 ; i < pixels ; ++i){ /*for(int i = 0 ; i < pixels ; ++i){
//fprintf(stderr, "%06d %02x %02x %02x %02x\n", i, //fprintf(stderr, "%06d %02x %02x %02x %02x\n", i,
fprintf(stderr, "%06d %d %d %d %d\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; OIIO::ImageSpec rgbaspec = spec;
rgbaspec.nchannels = 4; rgbaspec.nchannels = 4;
nc->raw.reset(rgbaspec, nc->frame.get()); nc->raw = std::make_unique<OIIO::ImageBuf>(rgbaspec, nc->frame.get());
//fprintf(stderr, "SUBS: %d\n", nc->raw->nsubimages());
int rows, cols; int rows, cols;
if(nc->ncp == nullptr){ // create plane if(nc->ncp == nullptr){ // create plane
if(nc->style == NCSCALE_NONE){ if(nc->style == NCSCALE_NONE){
@ -154,6 +184,13 @@ nc_err_e ncvisual_decode(ncvisual* nc){
nc->dstwidth = cols; 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; 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){ if(ncv->frame == nullptr){
return -1; 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); //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){ if(begx >= spec.width || begy >= spec.height){
return -1; 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); //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; const int linesize = spec.width * 4;
int ret = ncblit_rgba(ncv->ncp, ncv->placey, ncv->placex, linesize, 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); //av_frame_unref(ncv->oframe);
return ret; return ret;
} }
@ -268,6 +306,7 @@ void ncvisual_destroy(ncvisual* ncv){
if(ncv->ncobj){ if(ncv->ncobj){
ncplane_destroy(ncv->ncp); ncplane_destroy(ncv->ncp);
} }
free(ncv->filename);
delete ncv; delete ncv;
} }
} }
@ -276,6 +315,4 @@ const char* oiio_version(void){
return OIIO_VERSION_STRING; return OIIO_VERSION_STRING;
} }
} // extern "C"
#endif #endif

Loading…
Cancel
Save