diff --git a/src/lib/blit.c b/src/lib/blit.c new file mode 100644 index 000000000..6c4ebbd4a --- /dev/null +++ b/src/lib/blit.c @@ -0,0 +1,90 @@ +#include "internal.h" + +// alpha comes to us 0--255, but we have only 3 alpha values to map them to. +// settled on experimentally. +static inline bool +ffmpeg_trans_p(bool bgr, unsigned char alpha){ + if(!bgr && alpha < 192){ + return true; + } + return false; +} + +// RGBA/BGRx blitter. For incoming BGRx (no transparency), bgr == true. +static inline int +tria_blit(ncplane* nc, int placey, int placex, int linesize, const void* data, + int begy, int begx, int leny, int lenx, bool bgr){ + const int bpp = 32; + const int rpos = bgr ? 2 : 0; + const int bpos = bgr ? 0 : 2; + int dimy, dimx, x, y; + int visy = begy; + int total = 0; // number of cells written + ncplane_dim_yx(nc, &dimy, &dimx); + // FIXME not going to necessarily be safe on all architectures hrmmm + const unsigned char* dat = data; + for(y = placey ; visy < (begy + leny) && y < dimy ; ++y, visy += 2){ + if(ncplane_cursor_move_yx(nc, y, placex)){ + return -1; + } + int visx = begx; + for(x = placex ; visx < (begx + lenx) && x < dimx ; ++x, ++visx){ + const unsigned char* rgbbase_up = dat + (linesize * visy) + (visx * bpp / CHAR_BIT); + const unsigned char* rgbbase_down = dat + (linesize * (visy + 1)) + (visx * bpp / CHAR_BIT); +//fprintf(stderr, "[%04d/%04d] bpp: %d lsize: %d %02x %02x %02x %02x\n", y, x, bpp, linesize, rgbbase_up[0], rgbbase_up[1], rgbbase_up[2], rgbbase_up[3]); + cell* c = ncplane_cell_ref_yx(nc, y, x); + // use the default for the background, as that's the only way it's + // effective in that case anyway + c->channels = 0; + c->attrword = 0; + if(ffmpeg_trans_p(bgr, rgbbase_up[3]) || ffmpeg_trans_p(bgr, rgbbase_down[3])){ + cell_set_bg_alpha(c, CELL_ALPHA_TRANSPARENT); + if(ffmpeg_trans_p(bgr, rgbbase_up[3]) && ffmpeg_trans_p(bgr, rgbbase_down[3])){ + cell_set_fg_alpha(c, CELL_ALPHA_TRANSPARENT); + }else if(ffmpeg_trans_p(bgr, rgbbase_up[3])){ // down has the color + if(cell_load(nc, c, "\u2584") <= 0){ // lower half block + return -1; + } + cell_set_fg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]); + }else{ // up has the color + if(cell_load(nc, c, "\u2580") <= 0){ // upper half block + return -1; + } + cell_set_fg_rgb(c, rgbbase_up[rpos], rgbbase_up[1], rgbbase_up[bpos]); + } + }else{ + if(memcmp(rgbbase_up, rgbbase_down, 3) == 0){ + cell_set_fg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]); + cell_set_bg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]); + if(cell_load(nc, c, " ") <= 0){ // only need the background + return -1; + } + }else{ + cell_set_fg_rgb(c, rgbbase_up[rpos], rgbbase_up[1], rgbbase_up[bpos]); + cell_set_bg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]); + if(cell_load(nc, c, "\u2580") <= 0){ // upper half block + return -1; + } + } + } + ++total; + } + } + return total; +} + +// Blit a flat array 'data' of BGRx 32-bit values to the ncplane 'nc', offset +// from the upper left by 'placey' and 'placex'. Each row ought occupy +// 'linesize' bytes (this might be greater than lenx * 4 due to padding). A +// subregion of the input can be specified with 'begy'x'begx' and 'leny'x'lenx'. +int ncblit_bgrx(ncplane* nc, int placey, int placex, int linesize, + const void* data, int begy, int begx, int leny, int lenx){ + return tria_blit(nc, placey, placex, linesize, data, + begy, begx, leny, lenx, true); +} + +int ncblit_rgba(ncplane* nc, int placey, int placex, int linesize, + const void* data, int begy, int begx, int leny, int lenx){ + return tria_blit(nc, placey, placex, linesize, data, + begy, begx, leny, lenx, false); +} diff --git a/src/lib/internal.h b/src/lib/internal.h index 5e9676228..f42c7f019 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -80,34 +80,6 @@ typedef struct ncplane { bool scrolling; // is scrolling enabled? always disabled by default } ncplane; -typedef struct ncvisual { - struct AVFormatContext* fmtctx; - struct AVCodecContext* codecctx; // video codec context - struct AVCodecContext* subtcodecctx; // subtitle codec context - struct AVFrame* frame; - struct AVFrame* oframe; - struct AVCodec* codec; - struct AVCodecParameters* cparams; - struct AVCodec* subtcodec; - struct AVPacket* packet; - struct SwsContext* swsctx; - int packet_outstanding; - int dstwidth, dstheight; - int stream_index; // match against this following av_read_frame() - int sub_stream_index; // subtitle stream index, can be < 0 if no subtitles - float timescale; // scale frame duration by this value - ncplane* ncp; - // if we're creating the plane based off the first frame's dimensions, these - // describe where the plane ought be placed, and how it ought be sized. this - // path sets ncobj. ncvisual_destroy() ought in that case kill the ncplane. - int placex, placey; - ncscale_e style; // none, scale, or stretch - struct notcurses* ncobj; // set iff this ncvisual "owns" its ncplane -#ifdef USE_FFMPEG - AVSubtitle subtitle; -#endif -} ncvisual; - // current presentation state of the terminal. it is carried across render // instances. initialize everything to 0 on a terminal reset / startup. typedef struct renderstate { diff --git a/src/lib/libav.c b/src/lib/libav.c index 2302417ca..058cdb482 100644 --- a/src/lib/libav.c +++ b/src/lib/libav.c @@ -2,99 +2,38 @@ #include "version.h" #include "internal.h" +typedef struct ncvisual { + struct AVFormatContext* fmtctx; + struct AVCodecContext* codecctx; // video codec context + struct AVCodecContext* subtcodecctx; // subtitle codec context + struct AVFrame* frame; + struct AVFrame* oframe; + struct AVCodec* codec; + struct AVCodecParameters* cparams; + struct AVCodec* subtcodec; + struct AVPacket* packet; + struct SwsContext* swsctx; + int packet_outstanding; + int dstwidth, dstheight; + int stream_index; // match against this following av_read_frame() + int sub_stream_index; // subtitle stream index, can be < 0 if no subtitles + float timescale; // scale frame duration by this value + ncplane* ncp; + // if we're creating the plane based off the first frame's dimensions, these + // describe where the plane ought be placed, and how it ought be sized. this + // path sets ncobj. ncvisual_destroy() ought in that case kill the ncplane. + int placex, placey; + ncscale_e style; // none, scale, or stretch + struct notcurses* ncobj; // set iff this ncvisual "owns" its ncplane +#ifdef USE_FFMPEG + AVSubtitle subtitle; +#endif +} ncvisual; + ncplane* ncvisual_plane(ncvisual* ncv){ return ncv->ncp; } -// alpha comes to us 0--255, but we have only 3 alpha values to map them to. -// settled on experimentally. -static inline bool -ffmpeg_trans_p(bool bgr, unsigned char alpha){ - if(!bgr && alpha < 192){ - return true; - } - return false; -} - -// RGBA/BGRx blitter. For incoming BGRx (no transparency), bgr == true. -static inline int -tria_blit(ncplane* nc, int placey, int placex, int linesize, const void* data, - int begy, int begx, int leny, int lenx, bool bgr){ - const int bpp = 32; - const int rpos = bgr ? 2 : 0; - const int bpos = bgr ? 0 : 2; - int dimy, dimx, x, y; - int visy = begy; - int total = 0; // number of cells written - ncplane_dim_yx(nc, &dimy, &dimx); - // FIXME not going to necessarily be safe on all architectures hrmmm - const unsigned char* dat = data; - for(y = placey ; visy < (begy + leny) && y < dimy ; ++y, visy += 2){ - if(ncplane_cursor_move_yx(nc, y, placex)){ - return -1; - } - int visx = begx; - for(x = placex ; visx < (begx + lenx) && x < dimx ; ++x, ++visx){ - const unsigned char* rgbbase_up = dat + (linesize * visy) + (visx * bpp / CHAR_BIT); - const unsigned char* rgbbase_down = dat + (linesize * (visy + 1)) + (visx * bpp / CHAR_BIT); -//fprintf(stderr, "[%04d/%04d] bpp: %d lsize: %d %02x %02x %02x %02x\n", y, x, bpp, linesize, rgbbase_up[0], rgbbase_up[1], rgbbase_up[2], rgbbase_up[3]); - cell* c = ncplane_cell_ref_yx(nc, y, x); - // use the default for the background, as that's the only way it's - // effective in that case anyway - c->channels = 0; - c->attrword = 0; - if(ffmpeg_trans_p(bgr, rgbbase_up[3]) || ffmpeg_trans_p(bgr, rgbbase_down[3])){ - cell_set_bg_alpha(c, CELL_ALPHA_TRANSPARENT); - if(ffmpeg_trans_p(bgr, rgbbase_up[3]) && ffmpeg_trans_p(bgr, rgbbase_down[3])){ - cell_set_fg_alpha(c, CELL_ALPHA_TRANSPARENT); - }else if(ffmpeg_trans_p(bgr, rgbbase_up[3])){ // down has the color - if(cell_load(nc, c, "\u2584") <= 0){ // lower half block - return -1; - } - cell_set_fg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]); - }else{ // up has the color - if(cell_load(nc, c, "\u2580") <= 0){ // upper half block - return -1; - } - cell_set_fg_rgb(c, rgbbase_up[rpos], rgbbase_up[1], rgbbase_up[bpos]); - } - }else{ - if(memcmp(rgbbase_up, rgbbase_down, 3) == 0){ - cell_set_fg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]); - cell_set_bg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]); - if(cell_load(nc, c, " ") <= 0){ // only need the background - return -1; - } - }else{ - cell_set_fg_rgb(c, rgbbase_up[rpos], rgbbase_up[1], rgbbase_up[bpos]); - cell_set_bg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]); - if(cell_load(nc, c, "\u2580") <= 0){ // upper half block - return -1; - } - } - } - ++total; - } - } - return total; -} - -// Blit a flat array 'data' of BGRx 32-bit values to the ncplane 'nc', offset -// from the upper left by 'placey' and 'placex'. Each row ought occupy -// 'linesize' bytes (this might be greater than lenx * 4 due to padding). A -// subregion of the input can be specified with 'begy'x'begx' and 'leny'x'lenx'. -int ncblit_bgrx(ncplane* nc, int placey, int placex, int linesize, - const void* data, int begy, int begx, int leny, int lenx){ - return tria_blit(nc, placey, placex, linesize, data, - begy, begx, leny, lenx, true); -} - -int ncblit_rgba(ncplane* nc, int placey, int placex, int linesize, - const void* data, int begy, int begx, int leny, int lenx){ - return tria_blit(nc, placey, placex, linesize, data, - begy, begx, leny, lenx, false); -} - void ncvisual_destroy(ncvisual* ncv){ if(ncv){ #ifdef USE_FFMPEG diff --git a/src/lib/oiio.cpp b/src/lib/oiio.cpp index 6486d211e..64218a253 100644 --- a/src/lib/oiio.cpp +++ b/src/lib/oiio.cpp @@ -1,8 +1,58 @@ #include "internal.h" #ifdef USE_OIIO +#include +typedef struct ncvisual { + struct AVFormatContext* fmtctx; + struct AVCodecContext* codecctx; // video codec context + struct AVCodecContext* subtcodecctx; // subtitle codec context + struct AVFrame* frame; + struct AVFrame* oframe; + struct AVCodec* codec; + struct AVCodecParameters* cparams; + struct AVCodec* subtcodec; + struct AVPacket* packet; + struct SwsContext* swsctx; + int packet_outstanding; + int dstwidth, dstheight; + int stream_index; // match against this following av_read_frame() + int sub_stream_index; // subtitle stream index, can be < 0 if no subtitles + float timescale; // scale frame duration by this value + ncplane* ncp; + // if we're creating the plane based off the first frame's dimensions, these + // describe where the plane ought be placed, and how it ought be sized. this + // path sets ncobj. ncvisual_destroy() ought in that case kill the ncplane. + int placex, placey; + ncscale_e style; // none, scale, or stretch + struct notcurses* ncobj; // set iff this ncvisual "owns" its ncplane +#ifdef USE_FFMPEG + AVSubtitle subtitle; +#endif +} ncvisual; + bool notcurses_canopen(const notcurses* nc __attribute__ ((unused))){ - return false; + return true; +} + +ncvisual* ncplane_visual_open(ncplane* nc, const char* filename, int* averr){ + auto in = OIIO::ImageInput::open(filename); + if(!in){ + return nullptr; + } + (void)nc; + (void)averr; + return NULL; +} + +ncvisual* ncvisual_open_plane(notcurses* nc, const char* filename, + int* averr, int y, int x, ncscale_e style){ + (void)nc; + (void)filename; + (void)averr; + (void)y; + (void)x; + (void)style; + return NULL; } struct AVFrame* ncvisual_decode(ncvisual* nc, int* averr){ @@ -31,24 +81,6 @@ int ncvisual_stream(struct notcurses* nc, struct ncvisual* ncv, int* averr, return -1; } -ncvisual* ncplane_visual_open(ncplane* nc, const char* filename, int* averr){ - (void)nc; - (void)filename; - (void)averr; - return NULL; -} - -ncvisual* ncvisual_open_plane(notcurses* nc, const char* filename, - int* averr, int y, int x, ncscale_e style){ - (void)nc; - (void)filename; - (void)averr; - (void)y; - (void)x; - (void)style; - return NULL; -} - char* ncvisual_subtitle(const ncvisual* ncv){ (void)ncv; return NULL;