Repository: dankamongmen/notcurses (language: python)

Issue:
function to just check the scrolling without modifying it
It would take a const reference to the ncplane, and just return a bool.

Right now you have to modify it in order to check the previous value.
function to just check the scrolling without modifying it
It would take a const reference to the ncplane, and just return a bool.

Right now you have to modify it in order to check the previous value.
rotate pocpp is failing on exit
The `rotate` PoCPP is aborting on exit with the following trace:

```c
==1242711== Invalid read of size 8
==1242711==    at 0x609AC7A: av_frame_unref (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x609AE49: av_frame_free (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x484A3C6: ffmpeg_details_destroy (ffmpeg.c:610)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:622)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:620)
==1242711==    by 0x10940E: main (rotate.cpp:90)
==1242711==  Address 0xeb83f20 is 10,720 bytes inside an unallocated block of size 37,856 in arena "client"
==1242711== 
==1242711== Invalid read of size 8
==1242711==    at 0x608FED9: av_buffer_unref (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x609AC86: av_frame_unref (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x609AE49: av_frame_free (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x484A3C6: ffmpeg_details_destroy (ffmpeg.c:610)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:622)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:620)
==1242711==    by 0x10940E: main (rotate.cpp:90)
==1242711==  Address 0x20 is not stack'd, malloc'd or (recently) free'd
==1242711== 
==1242711== 
==1242711== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==1242711==    at 0x492CCBF: raise (raise.c:46)
==1242711==    by 0x492CD5F: ??? (in /lib/x86_64-linux-gnu/libc-2.31.so)
==1242711==    by 0x608FED8: av_buffer_unref (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x609AC86: av_frame_unref (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x609AE49: av_frame_free (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x484A3C6: ffmpeg_details_destroy (ffmpeg.c:610)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:622)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:620)
==1242711==    by 0x10940E: main (rotate.cpp:90)
==1242711== 
==1242711== HEAP SUMMARY:
==1242711==     in use at exit: 1,890,121 bytes in 1,384 blocks
==1242711==   total heap usage: 3,069 allocs, 1,685 frees, 36,280,677 bytes allocated
==1242711== 
==1242711== LEAK SUMMARY:
==1242711==    definitely lost: 536 bytes in 1 blocks
==1242711==    indirectly lost: 0 bytes in 0 blocks
==1242711==      possibly lost: 1,607 bytes in 21 blocks
==1242711==    still reachable: 1,887,978 bytes in 1,362 blocks
==1242711==                       of which reachable via heuristic:
==1242711==                         newarray           : 1,536 bytes in 16 blocks
==1242711==         suppressed: 0 bytes in 0 blocks
==1242711== Rerun with --leak-check=full to see details of leaked memory
==1242711== 
==1242711== For lists of detected and suppressed errors, rerun with: -s
==1242711== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
[schwarzgerat](0) $ 
```
rotate pocpp is failing on exit
The `rotate` PoCPP is aborting on exit with the following trace:

```c
==1242711== Invalid read of size 8
==1242711==    at 0x609AC7A: av_frame_unref (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x609AE49: av_frame_free (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x484A3C6: ffmpeg_details_destroy (ffmpeg.c:610)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:622)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:620)
==1242711==    by 0x10940E: main (rotate.cpp:90)
==1242711==  Address 0xeb83f20 is 10,720 bytes inside an unallocated block of size 37,856 in arena "client"
==1242711== 
==1242711== Invalid read of size 8
==1242711==    at 0x608FED9: av_buffer_unref (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x609AC86: av_frame_unref (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x609AE49: av_frame_free (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x484A3C6: ffmpeg_details_destroy (ffmpeg.c:610)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:622)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:620)
==1242711==    by 0x10940E: main (rotate.cpp:90)
==1242711==  Address 0x20 is not stack'd, malloc'd or (recently) free'd
==1242711== 
==1242711== 
==1242711== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==1242711==    at 0x492CCBF: raise (raise.c:46)
==1242711==    by 0x492CD5F: ??? (in /lib/x86_64-linux-gnu/libc-2.31.so)
==1242711==    by 0x608FED8: av_buffer_unref (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x609AC86: av_frame_unref (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x609AE49: av_frame_free (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x484A3C6: ffmpeg_details_destroy (ffmpeg.c:610)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:622)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:620)
==1242711==    by 0x10940E: main (rotate.cpp:90)
==1242711== 
==1242711== HEAP SUMMARY:
==1242711==     in use at exit: 1,890,121 bytes in 1,384 blocks
==1242711==   total heap usage: 3,069 allocs, 1,685 frees, 36,280,677 bytes allocated
==1242711== 
==1242711== LEAK SUMMARY:
==1242711==    definitely lost: 536 bytes in 1 blocks
==1242711==    indirectly lost: 0 bytes in 0 blocks
==1242711==      possibly lost: 1,607 bytes in 21 blocks
==1242711==    still reachable: 1,887,978 bytes in 1,362 blocks
==1242711==                       of which reachable via heuristic:
==1242711==                         newarray           : 1,536 bytes in 16 blocks
==1242711==         suppressed: 0 bytes in 0 blocks
==1242711== Rerun with --leak-check=full to see details of leaked memory
==1242711== 
==1242711== For lists of detected and suppressed errors, rerun with: -s
==1242711== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
[schwarzgerat](0) $ 
```
rotate pocpp is failing on exit
The `rotate` PoCPP is aborting on exit with the following trace:

```c
==1242711== Invalid read of size 8
==1242711==    at 0x609AC7A: av_frame_unref (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x609AE49: av_frame_free (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x484A3C6: ffmpeg_details_destroy (ffmpeg.c:610)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:622)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:620)
==1242711==    by 0x10940E: main (rotate.cpp:90)
==1242711==  Address 0xeb83f20 is 10,720 bytes inside an unallocated block of size 37,856 in arena "client"
==1242711== 
==1242711== Invalid read of size 8
==1242711==    at 0x608FED9: av_buffer_unref (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x609AC86: av_frame_unref (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x609AE49: av_frame_free (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x484A3C6: ffmpeg_details_destroy (ffmpeg.c:610)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:622)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:620)
==1242711==    by 0x10940E: main (rotate.cpp:90)
==1242711==  Address 0x20 is not stack'd, malloc'd or (recently) free'd
==1242711== 
==1242711== 
==1242711== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==1242711==    at 0x492CCBF: raise (raise.c:46)
==1242711==    by 0x492CD5F: ??? (in /lib/x86_64-linux-gnu/libc-2.31.so)
==1242711==    by 0x608FED8: av_buffer_unref (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x609AC86: av_frame_unref (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x609AE49: av_frame_free (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.51.100)
==1242711==    by 0x484A3C6: ffmpeg_details_destroy (ffmpeg.c:610)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:622)
==1242711==    by 0x484A410: ffmpeg_destroy (ffmpeg.c:620)
==1242711==    by 0x10940E: main (rotate.cpp:90)
==1242711== 
==1242711== HEAP SUMMARY:
==1242711==     in use at exit: 1,890,121 bytes in 1,384 blocks
==1242711==   total heap usage: 3,069 allocs, 1,685 frees, 36,280,677 bytes allocated
==1242711== 
==1242711== LEAK SUMMARY:
==1242711==    definitely lost: 536 bytes in 1 blocks
==1242711==    indirectly lost: 0 bytes in 0 blocks
==1242711==      possibly lost: 1,607 bytes in 21 blocks
==1242711==    still reachable: 1,887,978 bytes in 1,362 blocks
==1242711==                       of which reachable via heuristic:
==1242711==                         newarray           : 1,536 bytes in 16 blocks
==1242711==         suppressed: 0 bytes in 0 blocks
==1242711== Rerun with --leak-check=full to see details of leaked memory
==1242711== 
==1242711== For lists of detected and suppressed errors, rerun with: -s
==1242711== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
[schwarzgerat](0) $ 
```


Discussion / hints:


that address is *not* the address of `ncv->data`/`frame->data[0]`, which is 0xeb614f0 in this case. that's something else.
it's the rotate following a resize. rotate by itself seems fine.
ahhh, in `ffmpeg_resize()`, we set `frame` to `sframe`...i think we need a *false* there in `ncvisual_set_data()`.
ok so this scheme is busted. we need to free the old frame in `ncvisual_set_data()`, and we need do it independently of whether we own the underlying data. in fact...we ought be able to get rid of `owned` entirely by just seeing whether there's a frame to free. this of course means we need to move all frame assignment to *follow* `ncvisual_set_data()` calls. duh.
> ok so this scheme is busted. we need to free the old frame in `ncvisual_set_data()`, and we need do it independently of whether we own the underlying data. in fact...we ought be able to get rid of `owned` entirely by just seeing whether there's a frame to free. this of course means we need to move all frame assignment to _follow_ `ncvisual_set_data()` calls. duh.

EXCEPT `ncvisual_set_data()` is common across all backends; it doesn't know about frames. isn't there a deets reference around these calls off which we might hang?
this failure is weird =/
let's get a unit test built around this problem, to start.
alright, reproducing. i had to write two unit tests -- the one loading from memory didn't fault, but the one loading from a file did. so either you have to be some sufficient size, or it involves `force_rgba()` from `ffmpeg.c`.
that address is *not* the address of `ncv->data`/`frame->data[0]`, which is 0xeb614f0 in this case. that's something else.
it's the rotate following a resize. rotate by itself seems fine.
ahhh, in `ffmpeg_resize()`, we set `frame` to `sframe`...i think we need a *false* there in `ncvisual_set_data()`.
ok so this scheme is busted. we need to free the old frame in `ncvisual_set_data()`, and we need do it independently of whether we own the underlying data. in fact...we ought be able to get rid of `owned` entirely by just seeing whether there's a frame to free. this of course means we need to move all frame assignment to *follow* `ncvisual_set_data()` calls. duh.
> ok so this scheme is busted. we need to free the old frame in `ncvisual_set_data()`, and we need do it independently of whether we own the underlying data. in fact...we ought be able to get rid of `owned` entirely by just seeing whether there's a frame to free. this of course means we need to move all frame assignment to _follow_ `ncvisual_set_data()` calls. duh.

EXCEPT `ncvisual_set_data()` is common across all backends; it doesn't know about frames. isn't there a deets reference around these calls off which we might hang?
this failure is weird =/
let's get a unit test built around this problem, to start.
alright, reproducing. i had to write two unit tests -- the one loading from memory didn't fault, but the one loading from a file did. so either you have to be some sufficient size, or it involves `force_rgba()` from `ffmpeg.c`.
that address is *not* the address of `ncv->data`/`frame->data[0]`, which is 0xeb614f0 in this case. that's something else.
it's the rotate following a resize. rotate by itself seems fine.
ahhh, in `ffmpeg_resize()`, we set `frame` to `sframe`...i think we need a *false* there in `ncvisual_set_data()`.
ok so this scheme is busted. we need to free the old frame in `ncvisual_set_data()`, and we need do it independently of whether we own the underlying data. in fact...we ought be able to get rid of `owned` entirely by just seeing whether there's a frame to free. this of course means we need to move all frame assignment to *follow* `ncvisual_set_data()` calls. duh.
> ok so this scheme is busted. we need to free the old frame in `ncvisual_set_data()`, and we need do it independently of whether we own the underlying data. in fact...we ought be able to get rid of `owned` entirely by just seeing whether there's a frame to free. this of course means we need to move all frame assignment to _follow_ `ncvisual_set_data()` calls. duh.

EXCEPT `ncvisual_set_data()` is common across all backends; it doesn't know about frames. isn't there a deets reference around these calls off which we might hang?
this failure is weird =/
let's get a unit test built around this problem, to start.
alright, reproducing. i had to write two unit tests -- the one loading from memory didn't fault, but the one loading from a file did. so either you have to be some sufficient size, or it involves `force_rgba()` from `ffmpeg.c`.

Fix patch:
diff --git a/NEWS.md b/NEWS.md
index 6fc2cc1505..4106a9467d 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -10,6 +10,7 @@ rearrangements of Notcurses.
     plane and inhibition of the alternate screen, this allows rendered mode
     to easily be used for scrolling shell environment programs.
   * `ncls` now defaults to `NCBLIT_PIXEL`.
+  * Added `ncplane_scrolling_p()` to retrieve a plane's scrolling status.
 
 * 2.3.6 (2021-06-23)
   * Fixed (harmless) warning with `-Wformat-security`.
diff --git a/doc/man/man3/notcurses_plane.3.md b/doc/man/man3/notcurses_plane.3.md
index ca5b6f6879..7f6de4bfa1 100644
--- a/doc/man/man3/notcurses_plane.3.md
+++ b/doc/man/man3/notcurses_plane.3.md
@@ -204,6 +204,8 @@ typedef struct ncplane_options {
 
 **bool ncplane_set_scrolling(struct ncplane* ***n***, bool ***scrollp***);**
 
+**bool ncplane_scrolling_p(const struct ncplane* ***n***);**
+
 **int ncplane_rotate_cw(struct ncplane* ***n***);**
 
 **int ncplane_rotate_ccw(struct ncplane* ***n***);**
diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h
index 03e94e3178..033504e229 100644
--- a/include/notcurses/notcurses.h
+++ b/include/notcurses/notcurses.h
@@ -1209,14 +1209,16 @@ API struct ncplane* ncplane_reparent(struct ncplane* n, struct ncplane* newparen
 // The same as ncplane_reparent(), except any planes bound to 'n' come along
 // with it to its new destination. Their z-order is maintained. If 'newparent'
 // is an ancestor of 'n', NULL is returned, and no changes are made.
-API struct ncplane* ncplane_reparent_family(struct ncplane* n, struct ncplane* newparent);
+API struct ncplane* ncplane_reparent_family(struct ncplane* n, struct ncplane* newparent)
+  __attribute__ ((nonnull (1, 2)));
 
 // Duplicate an existing ncplane. The new plane will have the same geometry,
 // will duplicate all content, and will start with the same rendering state.
 // The new plane will be immediately above the old one on the z axis, and will
 // be bound to the same parent. Bound planes are *not* duplicated; the new
 // plane is bound to the parent of 'n', but has no bound planes.
-API ALLOC struct ncplane* ncplane_dup(const struct ncplane* n, void* opaque);
+API ALLOC struct ncplane* ncplane_dup(const struct ncplane* n, void* opaque)
+  __attribute__ ((nonnull (1)));
 
 // provided a coordinate relative to the origin of 'src', map it to the same
 // absolute coordinate relative to the origin of 'dst'. either or both of 'y'
@@ -1228,12 +1230,17 @@ API void ncplane_translate(const struct ncplane* src, const struct ncplane* dst,
 // within the ncplane 'n'. If not, return false. If so, return true. Either
 // way, translate the absolute coordinates relative to 'n'. If the point is not
 // within 'n', these coordinates will not be within the dimensions of the plane.
-API bool ncplane_translate_abs(const struct ncplane* n, int* RESTRICT y, int* RESTRICT x);
+API bool ncplane_translate_abs(const struct ncplane* n, int* RESTRICT y, int* RESTRICT x)
+  __attribute__ ((nonnull (1)));
 
 // All planes are created with scrolling disabled. Scrolling can be dynamically
 // controlled with ncplane_set_scrolling(). Returns true if scrolling was
 // previously enabled, or false if it was disabled.
-API bool ncplane_set_scrolling(struct ncplane* n, bool scrollp);
+API bool ncplane_set_scrolling(struct ncplane* n, bool scrollp)
+  __attribute__ ((nonnull (1)));
+
+API bool ncplane_scrolling_p(const struct ncplane* n)
+  __attribute__ ((nonnull (1)));
 
 // Palette API. Some terminals only support 256 colors, but allow the full
 // palette to be specified with arbitrary RGB colors. In all cases, it's more
diff --git a/src/lib/input.c b/src/lib/input.c
index b045e1d9c2..07a63e28b6 100644
--- a/src/lib/input.c
+++ b/src/lib/input.c
@@ -340,7 +340,7 @@ block_on_input(int fd, const struct timespec* ts, const sigset_t* sigmask){
   if(sigmask){
     memcpy(&scratchmask, sigmask, sizeof(*sigmask));
   }else{
-    pthread_sigmask(0, NULL, &scratchmask);
+    sigfillset(&scratchmask);
   }
   sigdelset(&scratchmask, SIGCONT);
   sigdelset(&scratchmask, SIGWINCH);
diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c
index 024372546e..505a53d1c3 100644
--- a/src/lib/notcurses.c
+++ b/src/lib/notcurses.c
@@ -2573,6 +2573,10 @@ bool ncplane_set_scrolling(ncplane* n, bool scrollp){
   return old;
 }
 
+bool ncplane_scrolling_p(const ncplane* n){
+  return n->scrolling;
+}
+
 // extract an integer, which must be non-negative, and followed by either a
 // comma or a NUL terminator.
 static int
diff --git a/src/lib/termdesc.c b/src/lib/termdesc.c
index c0d3b0dc50..66313eea7d 100644
--- a/src/lib/termdesc.c
+++ b/src/lib/termdesc.c
@@ -299,6 +299,9 @@ add_u7_escape(tinfo* ti, size_t* tablelen, size_t* tableused){
 
 static int
 add_smulx_escapes(tinfo* ti, size_t* tablelen, size_t* tableused){
+  if(get_escape(ti, ESCAPE_SMULX)){
+    return 0;
+  }
   if(grow_esc_table(ti, "\x1b[4:3m", ESCAPE_SMULX, tablelen, tableused) ||
      grow_esc_table(ti, "\x1b[4:0m", ESCAPE_SMULNOX, tablelen, tableused)){
     return -1;
@@ -308,6 +311,9 @@ add_smulx_escapes(tinfo* ti, size_t* tablelen, size_t* tableused){
 
 static int
 add_appsync_escapes(tinfo* ti, size_t* tablelen, size_t* tableused){
+  if(get_escape(ti, ESCAPE_BSU)){
+    return 0;
+  }
   if(grow_esc_table(ti, "\x1bP=1s\x1b\\", ESCAPE_BSU, tablelen, tableused) ||
      grow_esc_table(ti, "\x1bP=2s\x1b\\", ESCAPE_ESU, tablelen, tableused)){
     return -1;
diff --git a/src/lib/visual.c b/src/lib/visual.c
index 3e27e9577c..e21b392b51 100644
--- a/src/lib/visual.c
+++ b/src/lib/visual.c
@@ -507,9 +507,6 @@ rotate_bounding_box(double stheta, double ctheta, int* leny, int* lenx,
 int ncvisual_rotate(ncvisual* ncv, double rads){
   assert(ncv->rowstride / 4 >= ncv->pixx);
   rads = -rads; // we're a left-handed Cartesian
-  if(ncv->data == NULL){
-    return -1;
-  }
   int centy, centx;
   ncvisual_center(ncv, &centy, &centx); // pixel center (center of 'data')
   double stheta, ctheta; // sine, cosine
@@ -523,11 +520,13 @@ int ncvisual_rotate(ncvisual* ncv, double rads){
   int bboffy = 0;
   int bboffx = 0;
   if(ncvisual_bounding_box(ncv, &bby, &bbx, &bboffy, &bboffx) <= 0){
+    logerror("Couldn't find a bounding box\n");
     return -1;
   }
   int bbarea;
   bbarea = rotate_bounding_box(stheta, ctheta, &bby, &bbx, &bboffy, &bboffx);
   if(bbarea <= 0){
+    logerror("Couldn't rotate the visual (%d, %d, %d, %d)\n", bby, bbx, bboffy, bboffx);
     return -1;
   }
   int bbcentx = bbx, bbcenty = bby;
diff --git a/src/media/ffmpeg.c b/src/media/ffmpeg.c
index 3fa088a1ab..c78c388893 100644
--- a/src/media/ffmpeg.c
+++ b/src/media/ffmpeg.c
@@ -494,7 +494,8 @@ ffmpeg_resize_internal(const ncvisual* ncv, int rows, int* stride, int cols,
     return NULL;
   }
 //fprintf(stderr, "INFRAME DAA: %p SDATA: %p FDATA: %p to %d/%d\n", inframe->data[0], sframe->data[0], ncv->details->frame->data[0], sframe->height, sframe->width);
-  int height = sws_scale(ncv->details->swsctx, (const uint8_t* const*)inframe->data,
+  const uint8_t* data[4] = { (uint8_t*)ncv->data, };
+  int height = sws_scale(ncv->details->swsctx, data,
                          inframe->linesize, 0, srcleny, dptrs, dlinesizes);
   if(height < 0){
 //fprintf(stderr, "Error applying scaling (%d X %d)\n", inframe->height, inframe->width);
@@ -517,29 +518,15 @@ int ffmpeg_resize(ncvisual* n, int rows, int cols){
   if(data == NULL){
     return -1;
   }
-  AVFrame* sframe = av_frame_alloc();
-  if(sframe == NULL){
-//fprintf(stderr, "Couldn't allocate output frame for scaled frame\n");
-    return -1;
-  }
-  const AVFrame* inf = n->details->frame;
-//fprintf(stderr, "WHN NCV: %d/%d\n", inf->width, inf->height);
-  memcpy(sframe, inf, sizeof(*inf));
-  sframe->format = AV_PIX_FMT_RGBA;
-  sframe->width = cols;
-  sframe->height = rows;
-  memset(sframe->data, 0, sizeof(sframe->data));
-  sframe->data[0] = data;
-  memset(sframe->linesize, 0, sizeof(sframe->linesize));
-  sframe->linesize[0] = stride;
-  n->rowstride = sframe->linesize[0];
+  AVFrame* inf = n->details->frame;
+//fprintf(stderr, "WHN NCV: %d/%d %p\n", inf->width, inf->height, n->data);
+  inf->width = cols;
+  inf->height = rows;
+  inf->linesize[0] = stride;
+  n->rowstride = stride;
   n->pixy = rows;
   n->pixx = cols;
-  if(n->owndata){
-    av_frame_unref(n->details->frame);
-  }
-  ncvisual_set_data(n, sframe->data[0], true);
-  n->details->frame = sframe;
+  ncvisual_set_data(n, data, true);
 //fprintf(stderr, "SIZE SCALED: %d %d (%u)\n", n->details->frame->height, n->details->frame->width, n->details->frame->linesize[0]);
   return 0;
 }
@@ -566,10 +553,14 @@ int ffmpeg_blit(ncvisual* ncv, int rows, int cols, ncplane* n,
 }
 
 void ffmpeg_details_seed(ncvisual* ncv){
-  ncv->details->frame->data[0] = (uint8_t*)ncv->data;
+  ncv->details->frame->data[0] = NULL;
   ncv->details->frame->data[1] = NULL;
+  ncv->details->frame->data[2] = NULL;
+  ncv->details->frame->data[3] = NULL;
   ncv->details->frame->linesize[0] = ncv->rowstride;
   ncv->details->frame->linesize[1] = 0;
+  ncv->details->frame->linesize[2] = 0;
+  ncv->details->frame->linesize[3] = 0;
   ncv->details->frame->width = ncv->pixx;
   ncv->details->frame->height = ncv->pixy;
   ncv->details->frame->format = AV_PIX_FMT_RGBA;
diff --git a/src/poc/interp.c b/src/poc/interp.c
index c12d54bdec..493458a615 100644
--- a/src/poc/interp.c
+++ b/src/poc/interp.c
@@ -36,12 +36,14 @@ interp(struct notcurses* nc, int cellpixy, int cellpixx){
   if(ncvisual_render(nc, ncv, &vopts) == NULL){
     return -1;
   }
+  ncplane_putstr_yx(stdn, 2, 4, "scale");
   struct ncplane* scalepni = ncplane_create(stdn, &popts);
   vopts.n = scalepni;
   vopts.flags = NCVISUAL_OPTION_NOINTERPOLATE;
   if(ncvisual_render(nc, ncv, &vopts) == NULL){
     return -1;
   }
+  ncplane_putstr_yx(stdn, 2, 15, "scale(no)");
   popts.x += ncplane_dim_x(scalepni) + 1;
   struct ncplane* resizep = ncplane_create(stdn, &popts);
   if(resizep == NULL){
@@ -56,6 +58,7 @@ interp(struct notcurses* nc, int cellpixy, int cellpixx){
   if(ncvisual_render(nc, ncv, &vopts) == NULL){
     return -1;
   }
+  ncplane_putstr_yx(stdn, 2, 30, "resize");
   ncvisual_destroy(ncv);
   ncv = ncvisual_from_rgb_packed(randrgb, cellpixy, cellpixx * 3, cellpixx, 0xff);
   popts.x += ncplane_dim_x(scalepni) + 1;
@@ -70,6 +73,7 @@ interp(struct notcurses* nc, int cellpixy, int cellpixx){
   if(ncvisual_render(nc, ncv, &vopts) == NULL){
     return -1;
   }
+  ncplane_putstr_yx(stdn, 2, 41, "resize(no)");
   notcurses_render(nc);
   ncplane_destroy(ncvp);
   ncplane_destroy(scalep);
diff --git a/src/poc/rotate.c b/src/poc/rotate.c
index 42b1ea596a..4aab300358 100644
--- a/src/poc/rotate.c
+++ b/src/poc/rotate.c
@@ -10,7 +10,7 @@
 int main(int argc, char** argv){
   struct timespec ts = {
     .tv_sec = 0,
-    .tv_nsec = 250000000,
+    .tv_nsec = 100000000,
   };
   const char* file = "../data/changes.jpg";
   setlocale(LC_ALL, "");


Test patch:
diff --git a/src/tests/media.cpp b/src/tests/media.cpp
index 5d4bcff278..d9b7d401be 100644
--- a/src/tests/media.cpp
+++ b/src/tests/media.cpp
@@ -25,8 +25,6 @@ TEST_CASE("Media") {
   SUBCASE("ResizeThenRotateFromFile") {
     auto ncv = ncvisual_from_file(find_data("changes.jpg").get());
     REQUIRE(nullptr != ncv);
-    CHECK(0 == ncvisual_resize(ncv, 20, 20));
-    CHECK(0 == ncvisual_rotate(ncv, M_PI / 2));
     struct ncvisual_options vopts{};
     vopts.x = NCALIGN_CENTER;
     vopts.y = NCALIGN_CENTER;
@@ -34,7 +32,24 @@ TEST_CASE("Media") {
     auto p = ncvisual_render(nc_, ncv, &vopts);
     REQUIRE(nullptr != p);
     CHECK(0 == notcurses_render(nc_));
-    ncplane_destroy(p);
+sleep(1);
+    CHECK(0 == ncplane_destroy(p));
+    CHECK(0 == ncvisual_resize(ncv, 20, 20));
+    p = ncvisual_render(nc_, ncv, &vopts);
+    CHECK(0 == notcurses_render(nc_));
+sleep(1);
+    CHECK(0 == ncplane_destroy(p));
+    p = ncvisual_render(nc_, ncv, &vopts);
+    REQUIRE(nullptr != p);
+    CHECK(0 == notcurses_render(nc_));
+sleep(1);
+    CHECK(0 == ncplane_destroy(p));
+    CHECK(0 == ncvisual_rotate(ncv, M_PI / 2));
+    p = ncvisual_render(nc_, ncv, &vopts);
+    REQUIRE(nullptr != p);
+    CHECK(0 == notcurses_render(nc_));
+sleep(1);
+    CHECK(0 == ncplane_destroy(p));
     ncvisual_destroy(ncv);
   }
 
diff --git a/src/tests/visual.cpp b/src/tests/visual.cpp
index 31ad78eb9b..701617397f 100644
--- a/src/tests/visual.cpp
+++ b/src/tests/visual.cpp
@@ -71,8 +71,6 @@ TEST_CASE("Visual") {
     memset(rgb, 0, sizeof(rgb));
     auto ncv = ncvisual_from_rgb_packed(rgb, 10, 10 * 3, 10, 0xff);
     REQUIRE(nullptr != ncv);
-    CHECK(0 == ncvisual_resize(ncv, 20, 20));
-    CHECK(0 == ncvisual_rotate(ncv, M_PI / 2));
     struct ncvisual_options vopts{};
     vopts.x = NCALIGN_CENTER;
     vopts.y = NCALIGN_CENTER;
@@ -80,7 +78,17 @@ TEST_CASE("Visual") {
     auto p = ncvisual_render(nc_, ncv, &vopts);
     REQUIRE(nullptr != p);
     CHECK(0 == notcurses_render(nc_));
-    ncplane_destroy(p);
+    CHECK(0 == ncplane_destroy(p));
+    CHECK(0 == ncvisual_resize(ncv, 20, 20));
+    p = ncvisual_render(nc_, ncv, &vopts);
+    REQUIRE(nullptr != p);
+    CHECK(0 == notcurses_render(nc_));
+    CHECK(0 == ncplane_destroy(p));
+    CHECK(0 == ncvisual_rotate(ncv, M_PI / 2));
+    p = ncvisual_render(nc_, ncv, &vopts);
+    REQUIRE(nullptr != p);
+    CHECK(0 == notcurses_render(nc_));
+    CHECK(0 == ncplane_destroy(p));
     ncvisual_destroy(ncv);
   }