diff --git a/include/ncpp/Visual.hh b/include/ncpp/Visual.hh index f34f7818e..d29562621 100644 --- a/include/ncpp/Visual.hh +++ b/include/ncpp/Visual.hh @@ -62,9 +62,9 @@ namespace ncpp return visual; } - AVFrame* decode (nc_err_e* ncerr) const noexcept + nc_err_e decode () const noexcept { - return ncvisual_decode (visual, ncerr); + return ncvisual_decode (visual); } bool render (int begy, int begx, int leny, int lenx) const NOEXCEPT_MAYBE diff --git a/include/notcurses/ncerrs.h b/include/notcurses/ncerrs.h index b78ac079d..937152da0 100644 --- a/include/notcurses/ncerrs.h +++ b/include/notcurses/ncerrs.h @@ -14,6 +14,8 @@ typedef enum { NCERR_SUCCESS = 0, NCERR_NOMEM = ENOMEM, NCERR_EOF = 0x20464f45, // matches AVERROR_EOF + NCERR_DECODE, + NCERR_UNIMPLEMENTED, } nc_err_e; static inline const char* @@ -22,6 +24,8 @@ nc_strerror(nc_err_e ncerr){ case NCERR_SUCCESS: return "success"; case NCERR_NOMEM: return strerror(ENOMEM); case NCERR_EOF: return "end of file"; + case NCERR_DECODE: return "error decoding"; + case NCERR_UNIMPLEMENTED: return "feature not available"; }; return "unknown error"; } diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 4aa7b5686..1d5aba8d0 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -2050,12 +2050,9 @@ API struct ncplane* ncvisual_plane(struct ncvisual* ncv); // can be neither decoded nor rendered any further. API void ncvisual_destroy(struct ncvisual* ncv); -// extract the next frame from an ncvisual. returns NULL on end of file, -// writing NCERR_EOF to 'ncerr'. returns NULL on a decoding or allocation -// error, writing the cause to 'ncerr'. this frame is invalidated by a -// subsequent call to ncvisual_decode(), and should not be freed by the caller. -struct AVFrame; -API struct AVFrame* ncvisual_decode(struct ncvisual* nc, nc_err_e* ncerr); +// extract the next frame from an ncvisual. returns NCERR_EOF on end of file, +// and NCERR_SUCCESS on success, otherwise some other NCERR. +API nc_err_e ncvisual_decode(struct ncvisual* nc); // Render the decoded frame to the associated ncplane. The frame will be scaled // to the size of the ncplane per the ncscale_e style. A subregion of the diff --git a/python/src/notcurses/build_notcurses.py b/python/src/notcurses/build_notcurses.py index f8ce80aa5..af4d105c8 100644 --- a/python/src/notcurses/build_notcurses.py +++ b/python/src/notcurses/build_notcurses.py @@ -267,6 +267,8 @@ typedef enum { NCERR_SUCCESS, NCERR_NOMEM, NCERR_EOF, + NCERR_DECODE, + NCERR_UNIMPLEMENTED, } nc_err_e; struct ncvisual* ncplane_visual_open(struct ncplane* nc, const char* file, nc_err_e* err); typedef enum { @@ -277,7 +279,7 @@ typedef enum { struct ncvisual* ncvisual_open_plane(struct notcurses* nc, const char* file, nc_err_e* err, int y, int x, ncscale_e style); struct ncplane* ncvisual_plane(struct ncvisual* ncv); void ncvisual_destroy(struct ncvisual* ncv); -struct AVFrame* ncvisual_decode(struct ncvisual* nc, nc_err_e* err); +nc_err_e ncvisual_decode(struct ncvisual* nc); int ncvisual_render(const struct ncvisual* ncv, int begy, int begx, int leny, int lenx); char* ncvisual_subtitle(const struct ncvisual* ncv); typedef int (*streamcb)(struct notcurses* nc, struct ncvisual* ncv, void*); diff --git a/src/demo/chunli.c b/src/demo/chunli.c index b37dbdce4..eebdadb4e 100644 --- a/src/demo/chunli.c +++ b/src/demo/chunli.c @@ -24,7 +24,7 @@ chunli_draw(struct notcurses* nc, const char* ext, int count, const cell* b){ if(chuns[i].ncv == NULL){ return -1; } - if(ncvisual_decode(chuns[i].ncv, &err) == NULL){ + if((err = ncvisual_decode(chuns[i].ncv)) != NCERR_SUCCESS){ return -1; } if(ncvisual_render(chuns[i].ncv, 0, 0, -1, -1) <= 0){ @@ -72,7 +72,7 @@ int chunli_demo(struct notcurses* nc){ break; } free(path); - if(ncvisual_decode(ncv, &err) == NULL){ + if((err = ncvisual_decode(ncv)) != NCERR_SUCCESS){ return -1; } struct ncplane* ncp = ncvisual_plane(ncv); diff --git a/src/demo/eagle.c b/src/demo/eagle.c index d9c079400..fdff232a1 100644 --- a/src/demo/eagle.c +++ b/src/demo/eagle.c @@ -31,7 +31,7 @@ outzoomed_map(struct notcurses* nc, const char* map){ if(ncv == NULL){ return -1; } - if(ncvisual_decode(ncv, &ncerr) == NULL){ + if((ncerr = ncvisual_decode(ncv)) != NCERR_SUCCESS){ return -1; } if(ncvisual_render(ncv, 0, 0, -1, -1) <= 0){ @@ -54,8 +54,7 @@ zoom_map(struct notcurses* nc, const char* map){ if(ncv == NULL){ return NULL; } - struct AVFrame* frame; - if((frame = ncvisual_decode(ncv, &ncerr)) == NULL){ + if((ncerr = ncvisual_decode(ncv)) != NCERR_SUCCESS){ ncvisual_destroy(ncv); return NULL; } @@ -92,7 +91,7 @@ zoom_map(struct notcurses* nc, const char* map){ ncplane_destroy(zncp); return NULL; } - if(ncvisual_decode(zncv, &ncerr) == NULL){ + if((ncerr = ncvisual_decode(zncv)) != NCERR_SUCCESS){ ncvisual_destroy(zncv); ncplane_destroy(zncp); return NULL; diff --git a/src/demo/fallin.c b/src/demo/fallin.c index 910ff200e..d135dd716 100644 --- a/src/demo/fallin.c +++ b/src/demo/fallin.c @@ -184,7 +184,7 @@ int fallin_demo(struct notcurses* nc){ if(ncv == NULL){ return -1; } - if(ncvisual_decode(ncv, &err) == NULL){ + if((err = ncvisual_decode(ncv)) == NCERR_SUCCESS){ ncvisual_destroy(ncv); return -1; } @@ -192,8 +192,7 @@ int fallin_demo(struct notcurses* nc){ ncvisual_destroy(ncv); return -1; } - assert(ncvisual_decode(ncv, &err) == NULL); - assert(NCERR_EOF == err); + assert(ncvisual_decode(ncv) == NCERR_EOF); ncvisual_destroy(ncv); #endif #endif diff --git a/src/demo/luigi.c b/src/demo/luigi.c index f632ba4c4..29ec39013 100644 --- a/src/demo/luigi.c +++ b/src/demo/luigi.c @@ -155,16 +155,13 @@ int luigi_demo(struct notcurses* nc){ if(nv == NULL){ return -1; } - if(ncvisual_decode(nv, &ncerr) == NULL){ + if((ncerr = ncvisual_decode(nv)) != NCERR_SUCCESS){ return -1; } if(ncvisual_render(nv, 0, 0, -1, -1) <= 0){ return -1; } - assert(ncvisual_decode(nv, &ncerr) == NULL); -#ifdef USE_FFMPEG - assert(NCERR_EOF == ncerr); -#endif + assert(NCERR_EOF == ncvisual_decode(nv)); // he should be walking on the platform ~4/5 of the way down const int height = 32; int yoff = rows * 4 / 5 - height + 1; // tuned @@ -195,7 +192,7 @@ int luigi_demo(struct notcurses* nc){ if(wmncv == NULL){ return -1; } - if(ncvisual_decode(wmncv, &ncerr) == NULL){ + if((ncerr = ncvisual_decode(wmncv)) != NCERR_SUCCESS){ ncvisual_destroy(wmncv); return -1; } diff --git a/src/demo/outro.c b/src/demo/outro.c index 77914ef2f..ee51cd833 100644 --- a/src/demo/outro.c +++ b/src/demo/outro.c @@ -133,7 +133,7 @@ int outro(struct notcurses* nc){ if(chncv == NULL){ return -1; } - if(ncvisual_decode(chncv, &err) == NULL){ + if((err = ncvisual_decode(chncv)) != NCERR_SUCCESS){ ncvisual_destroy(chncv); return -1; } diff --git a/src/demo/qrcode.c b/src/demo/qrcode.c index 5fc4bb8f3..7812f6cbf 100644 --- a/src/demo/qrcode.c +++ b/src/demo/qrcode.c @@ -32,8 +32,8 @@ int qrcode_demo(struct notcurses* nc){ } DEMO_RENDER(nc); } -#else - DEMO_RENDER(nc); #endif + ncplane_erase(n); + DEMO_RENDER(nc); return 0; } diff --git a/src/demo/view.c b/src/demo/view.c index 9ec9e6a7f..1bd35584f 100644 --- a/src/demo/view.c +++ b/src/demo/view.c @@ -92,13 +92,13 @@ int view_demo(struct notcurses* nc){ return -1; } free(pic); - if(ncvisual_decode(ncv, &err) == NULL){ + if((err = ncvisual_decode(ncv)) != NCERR_SUCCESS){ ncvisual_destroy(ncv); ncvisual_destroy(ncv2); ncplane_destroy(dsplane); return -1; } - if(ncvisual_decode(ncv2, &err) == NULL){ + if((err = ncvisual_decode(ncv2)) != NCERR_SUCCESS){ ncvisual_destroy(ncv); ncvisual_destroy(ncv2); ncplane_destroy(dsplane); diff --git a/src/lib/libav.c b/src/lib/libav.c index 99f17a448..4a94cd9d2 100644 --- a/src/lib/libav.c +++ b/src/lib/libav.c @@ -167,7 +167,7 @@ averr2ncerr(int averr){ return -averr; } -AVFrame* ncvisual_decode(ncvisual* nc, nc_err_e* ncerr){ +nc_err_e ncvisual_decode(ncvisual* nc){ bool have_frame = false; bool unref = false; av_freep(&nc->oframe->data[0]); @@ -184,22 +184,21 @@ AVFrame* ncvisual_decode(ncvisual* nc, nc_err_e* ncerr){ /*if(averr != AVERROR_EOF){ fprintf(stderr, "Error reading frame info (%s)\n", av_err2str(*averr)); }*/ - *ncerr = averr2ncerr(averr); - return NULL; + return averr2ncerr(averr); } unref = true; if(nc->packet->stream_index == nc->sub_stream_index){ int result = 0, ret; ret = avcodec_decode_subtitle2(nc->subtcodecctx, &nc->subtitle, &result, nc->packet); if(ret >= 0 && result){ + // FIXME? } } }while(nc->packet->stream_index != nc->stream_index); ++nc->packet_outstanding; - *ncerr = avcodec_send_packet(nc->codecctx, nc->packet); - if(*ncerr < 0){ + if(avcodec_send_packet(nc->codecctx, nc->packet) < 0){ //fprintf(stderr, "Error processing AVPacket (%s)\n", av_err2str(*ncerr)); - return ncvisual_decode(nc, ncerr); + return ncvisual_decode(nc); } --nc->packet_outstanding; av_packet_unref(nc->packet); @@ -210,7 +209,7 @@ AVFrame* ncvisual_decode(ncvisual* nc, nc_err_e* ncerr){ have_frame = false; }else if(averr < 0){ //fprintf(stderr, "Error decoding AVPacket (%s)\n", av_err2str(averr)); - return NULL; + return averr2ncerr(averr); } }while(!have_frame); //print_frame_summary(nc->codecctx, nc->frame); @@ -223,7 +222,7 @@ AVFrame* ncvisual_decode(ncvisual* nc, nc_err_e* ncerr){ }else{ // FIXME differentiate between scale/stretch notcurses_term_dim_yx(nc->ncobj, &rows, &cols); if(nc->placey >= rows || nc->placex >= cols){ - return NULL; + return NCERR_DECODE; } rows -= nc->placey; cols -= nc->placex; @@ -234,8 +233,7 @@ AVFrame* ncvisual_decode(ncvisual* nc, nc_err_e* ncerr){ nc->placey = 0; nc->placex = 0; if(nc->ncp == NULL){ - *ncerr = NCERR_NOMEM; - return NULL; + return NCERR_NOMEM; } }else{ // check for resize ncplane_dim_yx(nc->ncp, &rows, &cols); @@ -258,7 +256,7 @@ AVFrame* ncvisual_decode(ncvisual* nc, nc_err_e* ncerr){ NULL, NULL, NULL); if(nc->swsctx == NULL){ //fprintf(stderr, "Error retrieving swsctx\n"); - return NULL; + return NCERR_DECODE; } memcpy(nc->oframe, nc->frame, sizeof(*nc->oframe)); nc->oframe->format = targformat; @@ -269,19 +267,19 @@ AVFrame* ncvisual_decode(ncvisual* nc, nc_err_e* ncerr){ nc->oframe->format, IMGALLOCALIGN); if(size < 0){ //fprintf(stderr, "Error allocating visual data (%s)\n", av_err2str(size)); - return NULL; + return NCERR_NOMEM; } int height = sws_scale(nc->swsctx, (const uint8_t* const*)nc->frame->data, nc->frame->linesize, 0, nc->frame->height, nc->oframe->data, nc->oframe->linesize); if(height < 0){ //fprintf(stderr, "Error applying scaling (%s)\n", av_err2str(height)); - return NULL; + return NCERR_NOMEM; } //print_frame_summary(nc->codecctx, nc->oframe); #undef IMGALLOCALIGN av_frame_unref(nc->frame); - return nc->oframe; + return NCERR_SUCCESS; } static ncvisual* @@ -456,7 +454,6 @@ int ncvisual_stream(notcurses* nc, ncvisual* ncv, nc_err_e* ncerr, float timescale, streamcb streamer, void* curry){ int frame = 1; ncv->timescale = timescale; - AVFrame* avf; struct timespec begin; // time we started clock_gettime(CLOCK_MONOTONIC, &begin); uint64_t nsbegin = timespec_to_ns(&begin); @@ -464,11 +461,11 @@ int ncvisual_stream(notcurses* nc, ncvisual* ncv, nc_err_e* ncerr, // each frame has a pkt_duration in milliseconds. keep the aggregate, in case // we don't have PTS available. uint64_t sum_duration = 0; - while( (avf = ncvisual_decode(ncv, ncerr)) ){ + while(ncvisual_decode(ncv) == NCERR_SUCCESS){ // codecctx seems to be off by a factor of 2 regularly. instead, go with // the time_base from the avformatctx. double tbase = av_q2d(ncv->fmtctx->streams[ncv->stream_index]->time_base); - int64_t ts = avf->best_effort_timestamp; + int64_t ts = ncv->oframe->best_effort_timestamp; if(frame == 1 && ts){ usets = true; } @@ -486,7 +483,7 @@ int ncvisual_stream(notcurses* nc, ncvisual* ncv, nc_err_e* ncerr, clock_gettime(CLOCK_MONOTONIC, &now); uint64_t nsnow = timespec_to_ns(&now); struct timespec interval; - uint64_t duration = avf->pkt_duration * tbase * NANOSECS_IN_SEC; + uint64_t duration = ncv->oframe->pkt_duration * tbase * NANOSECS_IN_SEC; //fprintf(stderr, "use: %u dur: %ju ts: %ju cctx: %f fctx: %f\n", usets, duration, ts, av_q2d(ncv->codecctx->time_base), av_q2d(ncv->fmtctx->streams[ncv->stream_index]->time_base)); sum_duration += (duration * ncv->timescale); double schedns = nsbegin; @@ -520,10 +517,9 @@ bool notcurses_canopen(const notcurses* nc __attribute__ ((unused))){ return false; } -struct AVFrame* ncvisual_decode(ncvisual* nc, nc_err_e* ncerr){ +nc_err_e ncvisual_decode(ncvisual* nc){ (void)nc; - (void)ncerr; - return NULL; + return NCERR_UNIMPLEMENTED; } int ncvisual_render(const ncvisual* ncv, int begy, int begx, int leny, int lenx){ diff --git a/src/lib/oiio.cpp b/src/lib/oiio.cpp index a040e9860..5f279b8d1 100644 --- a/src/lib/oiio.cpp +++ b/src/lib/oiio.cpp @@ -75,10 +75,9 @@ ncvisual* ncvisual_open_plane(notcurses* nc, const char* filename, return ncv; } -struct AVFrame* ncvisual_decode(ncvisual* nc, nc_err_e* ncerr){ - (void)nc; - (void)ncerr; - return nullptr; +nc_err_e ncvisual_decode(ncvisual* nc){ + (void)nc; // FIXME + return NCERR_DECODE; } int ncvisual_render(const ncvisual* ncv, int begy, int begx, int leny, int lenx){ diff --git a/src/poc/multiselect.c b/src/poc/multiselect.c index 2d8e97797..4a9548ba8 100644 --- a/src/poc/multiselect.c +++ b/src/poc/multiselect.c @@ -88,7 +88,7 @@ int main(void){ if(!ncv){ goto err; } - if(!ncvisual_decode(ncv, &err)){ + if((err = ncvisual_decode(ncv)) != NCERR_SUCCESS){ goto err; } if(ncvisual_render(ncv, 0, 0, -1, -1) <= 0){ diff --git a/src/poc/selector.c b/src/poc/selector.c index f24498084..84b2325c4 100644 --- a/src/poc/selector.c +++ b/src/poc/selector.c @@ -87,7 +87,7 @@ int main(void){ if(!ncv){ goto err; } - if(!ncvisual_decode(ncv, &err)){ + if((err = ncvisual_decode(ncv)) != NCERR_SUCCESS){ goto err; } if(ncvisual_render(ncv, 0, 0, -1, -1) <= 0){ diff --git a/src/poc/visual.cpp b/src/poc/visual.cpp index 7abf6eb62..ddbd9e02f 100644 --- a/src/poc/visual.cpp +++ b/src/poc/visual.cpp @@ -22,7 +22,7 @@ int main(int argc, char** argv){ if(!ncv){ goto err; } - if(!ncvisual_decode(ncv, &ncerr)){ + if((ncerr = ncvisual_decode(ncv)) != NCERR_SUCCESS){ goto err; } if(ncvisual_render(ncv, 0, 0, -1, -1) <= 0){ diff --git a/src/tetris/background.h b/src/tetris/background.h index b3c109348..56198500c 100644 --- a/src/tetris/background.h +++ b/src/tetris/background.h @@ -6,7 +6,7 @@ void DrawBackground(const std::string& s) { // drawn to the standard plane }catch(std::exception& e){ throw TetrisNotcursesErr("visual(): " + s + ": " + e.what()); } - if(!backg_->decode(&err)){ + if(backg_->decode() != NCERR_SUCCESS){ throw TetrisNotcursesErr("decode(): " + s); } if(backg_->render(0, 0, -1, -1) <= 0){ diff --git a/tests/visual.cpp b/tests/visual.cpp index d79ed9a05..e936a8351 100644 --- a/tests/visual.cpp +++ b/tests/visual.cpp @@ -29,21 +29,19 @@ TEST_CASE("Multimedia") { } SUBCASE("LoadImageCreatePlane") { - nc_err_e ncerr; + nc_err_e ncerr = NCERR_SUCCESS; int dimy, dimx; ncplane_dim_yx(ncp_, &dimy, &dimx); auto ncv = ncvisual_open_plane(nc_, find_data("changes.jpg"), &ncerr, 0, 0, NCSCALE_STRETCH); REQUIRE(ncv); - REQUIRE(0 == ncerr); - auto frame = ncvisual_decode(ncv, &ncerr); - REQUIRE(frame); - REQUIRE(0 == ncerr); - CHECK(dimy * 2 == frame->height); - CHECK(dimx == frame->width); + REQUIRE(NCERR_SUCCESS == ncerr); + ncerr = ncvisual_decode(ncv); + REQUIRE(NCERR_SUCCESS == ncerr); + /*CHECK(dimy * 2 == frame->height); + CHECK(dimx == frame->width); FIXME */ CHECK(0 < ncvisual_render(ncv, 0, 0, -1, -1)); CHECK(0 == notcurses_render(nc_)); - frame = ncvisual_decode(ncv, &ncerr); - REQUIRE_EQ(nullptr, frame); + ncerr = ncvisual_decode(ncv); CHECK(NCERR_EOF == ncerr); ncvisual_destroy(ncv); } @@ -54,16 +52,14 @@ TEST_CASE("Multimedia") { ncplane_dim_yx(ncp_, &dimy, &dimx); auto ncv = ncplane_visual_open(ncp_, find_data("changes.jpg"), &ncerr); REQUIRE(ncv); - REQUIRE(NCERR_SUCCESS == ncerr); - auto frame = ncvisual_decode(ncv, &ncerr); - REQUIRE(frame); REQUIRE(0 == ncerr); - CHECK(dimy * 2 == frame->height); - CHECK(dimx == frame->width); + ncerr = ncvisual_decode(ncv); + REQUIRE(NCERR_SUCCESS == ncerr); + /*CHECK(dimy * 2 == frame->height); + CHECK(dimx == frame->width); FIXME */ CHECK(0 < ncvisual_render(ncv, 0, 0, -1, -1)); CHECK(0 == notcurses_render(nc_)); - frame = ncvisual_decode(ncv, &ncerr); - REQUIRE_EQ(nullptr, frame); + ncerr = ncvisual_decode(ncv); CHECK(NCERR_EOF == ncerr); ncvisual_destroy(ncv); } @@ -75,11 +71,10 @@ TEST_CASE("Multimedia") { auto ncv = ncplane_visual_open(ncp_, find_data("changes.jpg"), &ncerr); REQUIRE(ncv); REQUIRE(NCERR_SUCCESS == ncerr); - auto frame = ncvisual_decode(ncv, &ncerr); - REQUIRE(frame); + ncerr = ncvisual_decode(ncv); REQUIRE(NCERR_SUCCESS == ncerr); - CHECK(dimy * 2 == frame->height); - CHECK(dimx == frame->width); + /*CHECK(dimy * 2 == frame->height); + CHECK(dimx == frame->width); FIXME */ CHECK(0 < ncvisual_render(ncv, 0, 0, -1, -1)); void* needle = malloc(1); REQUIRE(nullptr != needle); @@ -103,14 +98,13 @@ TEST_CASE("Multimedia") { REQUIRE(ncv); CHECK(NCERR_SUCCESS == ncerr); for(;;){ // run at the highest speed we can - auto frame = ncvisual_decode(ncv, &ncerr); - if(!frame){ - CHECK(NCERR_EOF == ncerr); + ncerr = ncvisual_decode(ncv); + if(NCERR_EOF == ncerr){ break; } - CHECK(0 == ncerr); - CHECK(dimy * 2 == frame->height); - CHECK(dimx == frame->width); + CHECK(NCERR_SUCCESS == ncerr); + /*CHECK(dimy * 2 == frame->height); + CHECK(dimx == frame->width); FIXME */ CHECK(0 < ncvisual_render(ncv, 0, 0, -1, -1)); CHECK(0 == notcurses_render(nc_)); } @@ -124,11 +118,10 @@ TEST_CASE("Multimedia") { auto ncv = ncvisual_open_plane(nc_, find_data("notcursesI.avi"), &ncerr, 0, 0, NCSCALE_STRETCH); REQUIRE(ncv); CHECK(NCERR_SUCCESS == ncerr); - auto frame = ncvisual_decode(ncv, &ncerr); - REQUIRE_NE(nullptr, frame); + ncerr = ncvisual_decode(ncv); CHECK(NCERR_SUCCESS == ncerr); - CHECK(dimy * 2 == frame->height); - CHECK(dimx == frame->width); + /*CHECK(dimy * 2 == frame->height); + CHECK(dimx == frame->width); FIXME */ CHECK(0 < ncvisual_render(ncv, 0, 0, -1, -1)); CHECK(0 == notcurses_render(nc_)); ncvisual_destroy(ncv);