diff --git a/USAGE.md b/USAGE.md index 9932f3150..5519e0fc7 100644 --- a/USAGE.md +++ b/USAGE.md @@ -2594,9 +2594,9 @@ When compiled against a suitable engine (FFmpeg and OpenImageIO are both currently supported), Notcurses can populate a visual with pixels decoded from an image or video using `ncvisual_from_file()`. Once opened, `ncvisual_decode()` should be used to extract each frame (an image will -have only one frame): +have only one frame), until it returns `NCERR_EOF`: -``` +```c // Open a visual at 'file', extracting a codec and parameters. struct ncvisual* ncvisual_from_file(const char* file, nc_err_e* ncerr); diff --git a/doc/man/man3/notcurses_visual.3.md b/doc/man/man3/notcurses_visual.3.md index e585d218f..92865f3e4 100644 --- a/doc/man/man3/notcurses_visual.3.md +++ b/doc/man/man3/notcurses_visual.3.md @@ -82,7 +82,7 @@ If Notcurses was built against a multimedia engine (FFMpeg or OpenImageIO), 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 the actual frames, once +**ncvisual_decode** ought be invoked to recover subsequent frames, once per frame. Once the visual is loaded, it can be transformed using **ncvisual_rotate** diff --git a/src/demo/chunli.c b/src/demo/chunli.c index 145cc513c..8b8f8f344 100644 --- a/src/demo/chunli.c +++ b/src/demo/chunli.c @@ -24,9 +24,6 @@ chunli_draw(struct notcurses* nc, const char* ext, int count, const cell* b){ if(chuns[i].ncv == NULL){ return -1; } - if((err = ncvisual_decode(chuns[i].ncv)) != NCERR_SUCCESS){ - return -1; - } if((chuns[i].n = ncvisual_render(nc, chuns[i].ncv, NULL)) == NULL){ return -1; } @@ -72,9 +69,6 @@ int chunli_demo(struct notcurses* nc){ break; } free(path); - if((err = ncvisual_decode(ncv)) != NCERR_SUCCESS){ - return -1; - } struct ncplane* ncp; if((ncp = ncvisual_render(nc, ncv, NULL)) == NULL){ return -1; diff --git a/src/demo/eagle.c b/src/demo/eagle.c index b77ae5354..ad45bf80b 100644 --- a/src/demo/eagle.c +++ b/src/demo/eagle.c @@ -38,8 +38,7 @@ zoom_map(struct notcurses* nc, const char* map, int* ret){ } int vheight, yscale; int vwidth, xscale; - if((ncerr = ncvisual_decode(ncv)) != NCERR_SUCCESS || - ncvisual_geom(nc, ncv, NCBLIT_DEFAULT, &vheight, &vwidth, &yscale, &xscale)){ + if(ncvisual_geom(nc, ncv, NCBLIT_DEFAULT, &vheight, &vwidth, &yscale, &xscale)){ ncvisual_destroy(ncv); return NULL; } diff --git a/src/demo/fallin.c b/src/demo/fallin.c index b1d679561..ef6e6b447 100644 --- a/src/demo/fallin.c +++ b/src/demo/fallin.c @@ -183,10 +183,6 @@ int fallin_demo(struct notcurses* nc){ if(ncv == NULL){ goto err; } - if((err = ncvisual_decode(ncv)) != NCERR_SUCCESS){ - ncvisual_destroy(ncv); - goto err; - } struct ncvisual_options vopts = { .n = stdn, .scaling = NCSCALE_STRETCH, diff --git a/src/demo/luigi.c b/src/demo/luigi.c index a5f4e3418..a236003bf 100644 --- a/src/demo/luigi.c +++ b/src/demo/luigi.c @@ -154,9 +154,6 @@ int luigi_demo(struct notcurses* nc){ if(nv == NULL){ return -1; } - if((ncerr = ncvisual_decode(nv)) != NCERR_SUCCESS){ - return -1; - } struct ncvisual_options vopts = { .n = notcurses_stddim_yx(nc, &rows, &cols), .scaling = NCSCALE_STRETCH, @@ -195,10 +192,6 @@ int luigi_demo(struct notcurses* nc){ if(wmncv == NULL){ return -1; } - if((ncerr = ncvisual_decode(wmncv)) != NCERR_SUCCESS){ - ncvisual_destroy(wmncv); - return -1; - } uint64_t channels = 0; channels_set_fg_alpha(&channels, CELL_ALPHA_TRANSPARENT); channels_set_bg_alpha(&channels, CELL_ALPHA_TRANSPARENT); diff --git a/src/demo/outro.c b/src/demo/outro.c index 325c88c8b..0bf88717e 100644 --- a/src/demo/outro.c +++ b/src/demo/outro.c @@ -40,10 +40,6 @@ fadethread(void* vnc){ .scaling = NCSCALE_STRETCH, }; int three = 3; - if(NCERR_SUCCESS != ncvisual_decode(ncv)){ - ncvisual_destroy(ncv); - return NULL; - } struct ncplane* globeplane; if((globeplane = ncvisual_render(nc, ncv, &vopts)) == NULL){ return NULL; @@ -151,10 +147,6 @@ int outro(struct notcurses* nc){ if(chncv == NULL){ return -1; } - if((err = ncvisual_decode(chncv)) != NCERR_SUCCESS){ - ncvisual_destroy(chncv); - return -1; - } struct ncvisual_options vopts = { .n = ncp, .scaling = NCSCALE_STRETCH, diff --git a/src/demo/view.c b/src/demo/view.c index 4503d4be3..af05e4cef 100644 --- a/src/demo/view.c +++ b/src/demo/view.c @@ -76,11 +76,6 @@ view_images(struct notcurses* nc, struct ncplane* nstd, int dimy, int dimx){ return -1; } free(pic); - if((err = ncvisual_decode(ncv2)) != NCERR_SUCCESS){ - ncvisual_destroy(ncv2); - ncplane_destroy(dsplane); - return -1; - } struct ncvisual_options vopts = { .n = dsplane, .scaling = NCSCALE_STRETCH, @@ -107,11 +102,6 @@ view_images(struct notcurses* nc, struct ncplane* nstd, int dimy, int dimx){ return -1; } free(pic); - if((err = ncvisual_decode(ncv)) != NCERR_SUCCESS){ - ncvisual_destroy(ncv); - ncplane_destroy(dsplane); - return -1; - } vopts.n = notcurses_stdplane(nc); if(ncvisual_render(nc, ncv, &vopts) == NULL){ ncvisual_destroy(ncv); diff --git a/src/lib/ffmpeg.cpp b/src/lib/ffmpeg.cpp index 40a4d45d1..b9b418928 100644 --- a/src/lib/ffmpeg.cpp +++ b/src/lib/ffmpeg.cpp @@ -226,6 +226,7 @@ nc_err_e ncvisual_resize(ncvisual* nc, int rows, int cols) { } ncvisual* ncvisual_from_file(const char* filename, nc_err_e* ncerr) { + AVStream* st; *ncerr = NCERR_SUCCESS; ncvisual* ncv = ncvisual_create(); if(ncv == nullptr){ @@ -238,15 +239,13 @@ ncvisual* ncvisual_from_file(const char* filename, nc_err_e* ncerr) { if(averr < 0){ //fprintf(stderr, "Couldn't open %s (%d)\n", filename, averr); *ncerr = averr2ncerr(averr); - ncvisual_destroy(ncv); - return nullptr; + goto err; } averr = avformat_find_stream_info(ncv->details.fmtctx, nullptr); if(averr < 0){ //fprintf(stderr, "Error extracting stream info from %s (%d)\n", filename, averr); *ncerr = averr2ncerr(averr); - ncvisual_destroy(ncv); - return nullptr; + goto err; } //av_dump_format(ncv->details.fmtctx, 0, filename, false); if((averr = av_find_best_stream(ncv->details.fmtctx, AVMEDIA_TYPE_SUBTITLE, -1, -1, &ncv->details.subtcodec, 0)) >= 0){ @@ -254,15 +253,13 @@ ncvisual* ncvisual_from_file(const char* filename, nc_err_e* ncerr) { if((ncv->details.subtcodecctx = avcodec_alloc_context3(ncv->details.subtcodec)) == nullptr){ //fprintf(stderr, "Couldn't allocate decoder for %s\n", filename); *ncerr = NCERR_NOMEM; - ncvisual_destroy(ncv); - return nullptr; + goto err; } // FIXME do we need avcodec_parameters_to_context() here? if((averr = avcodec_open2(ncv->details.subtcodecctx, ncv->details.subtcodec, nullptr)) < 0){ //fprintf(stderr, "Couldn't open codec for %s (%s)\n", filename, av_err2str(*averr)); *ncerr = averr2ncerr(averr); - ncvisual_destroy(ncv); - return nullptr; + goto err; } }else{ ncv->details.sub_stream_index = -1; @@ -271,22 +268,20 @@ ncvisual* ncvisual_from_file(const char* filename, nc_err_e* ncerr) { if((ncv->details.packet = av_packet_alloc()) == nullptr){ // fprintf(stderr, "Couldn't allocate packet for %s\n", filename); *ncerr = NCERR_NOMEM; - ncvisual_destroy(ncv); - return nullptr; + goto err; } if((averr = av_find_best_stream(ncv->details.fmtctx, AVMEDIA_TYPE_VIDEO, -1, -1, &ncv->details.codec, 0)) < 0){ // fprintf(stderr, "Couldn't find visuals in %s (%s)\n", filename, av_err2str(*averr)); *ncerr = averr2ncerr(averr); - ncvisual_destroy(ncv); - return nullptr; + goto err; } ncv->details.stream_index = averr; if(ncv->details.codec == nullptr){ //fprintf(stderr, "Couldn't find decoder for %s\n", filename); - ncvisual_destroy(ncv); - return nullptr; + *ncerr = NCERR_DECODE; + goto err; } - AVStream* st = ncv->details.fmtctx->streams[ncv->details.stream_index]; + st = ncv->details.fmtctx->streams[ncv->details.stream_index]; if((ncv->details.codecctx = avcodec_alloc_context3(ncv->details.codec)) == nullptr){ //fprintf(stderr, "Couldn't allocate decoder for %s\n", filename); *ncerr = NCERR_NOMEM; @@ -313,6 +308,9 @@ ncvisual* ncvisual_from_file(const char* filename, nc_err_e* ncerr) { // frame is set up in prep_details(), so that format can be set there, as // is necessary when it is prepared from inputs other than files. oframe // is set up whenever we convert to RGBA. + if((*ncerr = ncvisual_decode(ncv)) != NCERR_SUCCESS){ + goto err; + } return ncv; err: diff --git a/src/poc/blitters.c b/src/poc/blitters.c index 2a87b0732..b68fa8a78 100644 --- a/src/poc/blitters.c +++ b/src/poc/blitters.c @@ -41,10 +41,6 @@ int main(int argc, char** argv){ goto err; } notcurses_render(nc); - if((err = ncvisual_decode(ncv)) != NCERR_SUCCESS){ - ncvisual_destroy(ncv); - goto err; - } struct ncvisual_options vopts = { .n = std, .scaling = scaling, diff --git a/src/poc/multiselect.c b/src/poc/multiselect.c index 7e4daa9a5..bdfc88163 100644 --- a/src/poc/multiselect.c +++ b/src/poc/multiselect.c @@ -89,9 +89,6 @@ int main(void){ if(!ncv){ goto err; } - if((err = ncvisual_decode(ncv)) != NCERR_SUCCESS){ - goto err; - } struct ncvisual_options vopts = { .scaling = NCSCALE_STRETCH, .n = n, diff --git a/src/poc/resize.cpp b/src/poc/resize.cpp index 14a2e05c2..bcc1d15b7 100644 --- a/src/poc/resize.cpp +++ b/src/poc/resize.cpp @@ -31,9 +31,6 @@ int main(int argc, char** argv){ if(!ncv){ goto err; } - if((ncerr = ncvisual_decode(ncv)) != NCERR_SUCCESS){ - goto err; - } int scaley, scalex; ncvisual_geom(nc, ncv, NCBLIT_DEFAULT, nullptr, nullptr, &scaley, &scalex); //ncvisual_resize(ncv, dimy * scaley, dimx * scalex); @@ -45,7 +42,6 @@ int main(int argc, char** argv){ if(notcurses_render(nc)){ goto err; } - ncvisual_destroy(ncv); return notcurses_stop(nc) || failed ? EXIT_FAILURE : EXIT_SUCCESS; err: diff --git a/src/poc/selector.c b/src/poc/selector.c index 5f513be33..6f58e644b 100644 --- a/src/poc/selector.c +++ b/src/poc/selector.c @@ -90,9 +90,6 @@ int main(void){ if(!ncv){ goto err; } - if((err = ncvisual_decode(ncv)) != NCERR_SUCCESS){ - goto err; - } struct ncvisual_options vopts = { .scaling = NCSCALE_STRETCH, .n = n, diff --git a/src/poc/visual.cpp b/src/poc/visual.cpp index 807a40562..f128b73fe 100644 --- a/src/poc/visual.cpp +++ b/src/poc/visual.cpp @@ -35,9 +35,6 @@ int main(int argc, char** argv){ if(!ncv){ goto err; } - if((ncerr = ncvisual_decode(ncv)) != NCERR_SUCCESS){ - goto err; - } int scaley, scalex; vopts.n = n; if(ncvisual_render(nc, ncv, &vopts) == nullptr){ diff --git a/tests/visual.cpp b/tests/visual.cpp index 79d2437cf..708d3c458 100644 --- a/tests/visual.cpp +++ b/tests/visual.cpp @@ -28,8 +28,6 @@ TEST_CASE("Visual") { auto ncv = ncvisual_from_file(find_data("changes.jpg"), &ncerr); REQUIRE(ncv); REQUIRE(NCERR_SUCCESS == ncerr); - ncerr = ncvisual_decode(ncv); - REQUIRE(NCERR_SUCCESS == ncerr); /*CHECK(dimy * 2 == frame->height); CHECK(dimx == frame->width); FIXME */ struct ncvisual_options opts{}; @@ -49,8 +47,6 @@ TEST_CASE("Visual") { ncplane_dim_yx(ncp_, &dimy, &dimx); auto ncv = ncvisual_from_file(find_data("changes.jpg"), &ncerr); REQUIRE(ncv); - REQUIRE(0 == ncerr); - ncerr = ncvisual_decode(ncv); REQUIRE(NCERR_SUCCESS == ncerr); /*CHECK(dimy * 2 == frame->height); CHECK(dimx == frame->width); FIXME */ @@ -71,8 +67,6 @@ TEST_CASE("Visual") { auto ncv = ncvisual_from_file(find_data("changes.jpg"), &ncerr); REQUIRE(ncv); REQUIRE(NCERR_SUCCESS == ncerr); - ncerr = ncvisual_decode(ncv); - REQUIRE(NCERR_SUCCESS == ncerr); /*CHECK(dimy * 2 == frame->height); CHECK(dimx == frame->width); FIXME */ struct ncvisual_options opts{};