Transparent overlays

I have an application where I need to add a transparent overlay to a camera feed and view it on the connected display. I need to make use of hardware accelerated NVIDIA gstreamer plugins because the camera feed is 3840x2160 at 30fps.

Ultimately this transparent overlay needs to be a full GUI, but for the sake of simplicity when testing, I’m instead using a static PNG file with transparency information, loaded with multifilesrc. I want this PNG to appear on top of the camera feed, showing only the RGB data, and be able to see the pixel data from the camera feed where there are alpha components in the image.

I have tried nvcompositor, however transparency information is not retained. I can only see the PNG with a black background. I’ve made sure that both inputs to the nvcompositor are in RGBA format.

This post suggests that nvcompositor doesn’t support alpha Nvcompositor plugs alpha is not work and alpha plugs no work - #24 by DaneLLL

I can get this to work by avoiding the use of “memory:NVMM”, however performance is then terrible.
Similarly, the standard compositor plugin works fine, but again with awful performance.

Another approach I have tried is nvoverlaysink, making use of the overlay property. Setting the camera sink to “overlay=1” and the PNG sink to “overlay=2” results in the same behviour as nvcompositor - transparency information is not retained and I can only see the PNG with a black background.

Is there any approach that I can use to overlay the transparent image without resorting to software solutions such as “compositor” which don’t provide good enough performance?

Thanks in advance.

1 Like

Hi,
The nvcompositor plugin is implemented through NvBuffer APIs and it calls NvBufferComposite(). It does not implement applying alpha effect. For this use-case, you can customize nvcompositor to enable alpha effect.

For applying alpha effect in calling NvBufferComposite(), please refer to discussion in the topic:
The alpha setting in NvBufferComposite is not in effect

Thanks for confirming that nvcompositor doesn’t implement alpha.

The linked discussion has a suggestion to “allocate NvBuffer in RGBA and add the flag NVBUFFER_BLEND”.
As far as I can tell, the “do_nvcomposite” function already does both of these suggestions (found in gstnvcompositor.c)

Are you able to be more specific about what needs to change in the nvcompositor source to enable alpha?

Hi,
You mat print out the value and check if it is expected:

nvcomp->comp_params.dst_comp_rect_alpha[i]

And confirm it enters the if condition and set NVBUFFER_BLEND:

  if (!all_yuv && (nvcomp->out_pix_fmt == NvBufferColorFormat_ABGR32)) {
    nvcomp->comp_params.composite_flag |= NVBUFFER_BLEND;
  }

I modified the code as follows:

  if (!all_yuv && (nvcomp->out_pix_fmt == NvBufferColorFormat_ABGR32)) {
    nvcomp->comp_params.composite_flag |= NVBUFFER_BLEND;
    GST_INFO("%d = %f", i, nvcomp->comp_params.dst_comp_rect_alpha[i]);
    GST_INFO("0x%08x", nvcomp->comp_params.composite_flag);
  }

I get this debug when running the pipeline

0:00:00.380176840 11230   0x559ebcade0 INFO            nvcompositor gstnvcompositor.c:1309:do_nvcomposite: 1 = 0.000000
0:00:00.380232934 11230   0x559ebcade0 INFO            nvcompositor gstnvcompositor.c:1310:do_nvcomposite: 0x00000007
0:00:00.431282145 11230   0x559ebcade0 INFO            nvcompositor gstnvcompositor.c:1309:do_nvcomposite: 2 = 0.000000
0:00:00.431332512 11230   0x559ebcade0 INFO            nvcompositor gstnvcompositor.c:1310:do_nvcomposite: 0x00000007

This confirms that NVBUFFER_BLEND is being set. It strikes me as odd that the alpha value is 0 for both inputs, despite me specifying in the pipeline for them both to be 1.0. Manually modifying this alpha value within the source code doesn’t seem to have any effect on the output.

I get the exact same debug for piplelines that use “memory:NVMM” and pipelines that do not use NVMM. However as I mention previously the pipeline without NVMM actually gives the correct result (albeit with poor framerates).

I have attached the two pipelines for reference.

nvcompositor-with-nvmm.sh (703 Bytes)
nvcompositor-without-nvmm.sh.sh (612 Bytes)

Hi,
Please manually set the alpha value and check if it works as expected. If yes, you can implement a property to configure alpha values.

Here’s a patch of adding property for reference:
Gst for merging 4 webcams sometimes works, and sometimes it doesn't - #5 by DaneLLL

Just to note that there is already a property to set alpha values and perform blending. This already works as expected for both NVMM and non NVMM so there is no need for me to implement that. My specific issue is with the scenario where both inputs are set to alpha=1.0.

If I set both inputs to alpha=0.5 in the sourcecode, then I see the camera feed with a png overlay (as expected), however the image is dark. I assume this is because the alpha data in the png is being interpreted as black pixel data and then being blended with the camera image.

What I want to do is set both inputs to alpha=1.0 and directly overlay the png, making use of the alpha data that exists in the png source file. This works for non-NVMM, but when using NVMM memory, I just see the png file with a black background (completely covering the camera feed behind). The transparency information of the source doesn’t seem to be interpreted correctly.

I’ve included examples below. Apologies for the poor quality

[1] Alpha = 0.5, without NVMM (note the dark background) - Expected result

[2] Alpha = 0.5, with NVMM (note the dark background) - Expected result

[3] Alpha = 1.0, without NVMM (note the lighter image) - Expected result

[4] Alpha = 1.0, with NVMM (note camera feed not seen) - Unexpected result

Scenario [4] is the one I am trying to resolve. I would expect the output to match [3] given that all the settings are the same.

Hi,
The use-case is not supported. NvBufferComposite() blends each video plane in a fixed alpha value. It doesn’t handle the case that alpha value varies pixel by pixel. Would suggest use software compositor plugin.

If you would like to display text, another approach is to call NvBufferMemMap() to get CPU pointer to the buffer, and use cairo APIs to put text.

Thanks for clarifying. As mentioned previously, the software compositor plugin is not suitable since my camera source is 3840x2160 30fps which the software compositor cannot keep up with.

I need to display a dynamic Qt Widget based GUI overlay rather than just the text from my example, so cairo API’s aren’t suitable.

It sounds like there is no official way to achieve the per-pixel alpha overlay that I require while making use of the NVIDIA hardware accelerated gstreamer plugins. Is there any plan to add support for this in the future?

Hi,
Please share the PNG file and gst-launch-1.0 command for replicating the issue. To help us reproduce the phenomenon and then check with our teams.

Thank you, PNG file attached

Hi,
Thanks. It would be great if you can share gst-launch-1.0 command for working and non-working cases.

gst-launch-1.0 commands are attached as .sh scripts in a previous response. In case you can’t access those for some reason, I’ll include here as inline code

Working command (without NVMM)

gst-launch-1.0 nvcompositor name=comp  sink_0::xpos=0 sink_0::ypos=0 sink_0::width=3840 sink_0::height=2160 sink_1::xpos=0 sink_1::ypos=0 sink_1::width=3840 sink_1::height=2160 ! nvoverlaysink sync=false nvv4l2camerasrc device=/dev/video0 ! "video/x-raw(memory:NVMM),format=UYVY,width=3840,height=2160,framerate=30/1" ! nvvidconv ! 'video/x-raw,format=RGBA,width=3840,height=2160' ! queue ! comp.sink_0 multifilesrc location="overlay0.png" caps="image/png,framerate=30/1" loop=false ! pngdec ! nvvidconv ! 'video/x-raw,format=RGBA,width=3840,height=2160' ! queue ! comp.sink_1

Non-working command (with NVMM)

gst-launch-1.0 nvcompositor name=comp  sink_0::xpos=0 sink_0::ypos=0 sink_0::width=3840 sink_0::height=2160 sink_0::zorder=1 sink_0::alpha=1 sink_1::xpos=0 sink_1::ypos=0 sink_1::width=3840 sink_1::height=2160 sink_1::zorder=2 sink_1::alpha=1 ! nvoverlaysink sync=false nvv4l2camerasrc device=/dev/video0 ! "video/x-raw(memory:NVMM),format=UYVY,width=3840,height=2160,framerate=30/1" ! nvvidconv ! 'video/x-raw(memory:NVMM),format=RGBA,width=3840,height=2160' ! queue ! comp.sink_0 multifilesrc location="overlay0.png" caps="image/png,framerate=30/1" loop=false ! pngdec ! nvvidconv ! 'video/x-raw(memory:NVMM),format=RGBA,width=3840,height=2160' ! queue ! comp.sink_1

If you don’t have a 3840x2160 30fps camera source available, you will need to replace the nvv4l2camerasrc input (comp.sink_0) with a videotestsrc

Hi,
We have checked this and the issue is because alpha effect is applied in nvvidconv plugin and the frames to nvcompositor do not contain the transparency. Please apply the patch to rebuild nvvidconv plugin and try again:

diff --git a/gst-nvvidconv-1.0/gstnvvconv.c b/gst-nvvidconv-1.0/gstnvvconv.c
index 2019c11..ee23013 100644
--- a/gst-nvvidconv-1.0/gstnvvconv.c
+++ b/gst-nvvidconv-1.0/gstnvvconv.c
@@ -3204,6 +3204,19 @@ gst_nvvconv_transform (GstBaseTransform * btrans, GstBuffer * inbuf,
             space->isurf_flag = FALSE;
           }
 
+          if (space->in_pix_fmt == NvBufferColorFormat_ABGR32 &&
+              space->out_pix_fmt == NvBufferColorFormat_ABGR32 &&
+              space->flip_method == PROP_FLIP_METHOD_DEFAULT &&
+              (!space->do_scaling))
+          {
+            ret = gst_nvvconv_do_raw2nvconv (space, inmap.data, omem->buf->dmabuf_fd);
+            if (ret != TRUE) {
+              g_print ("%s: raw to nvrm conversion failed \n", __func__);
+              flow_ret = GST_FLOW_ERROR;
+            }
+            goto done;
+          }
+
           ret = gst_nvvconv_do_raw2nvconv (space, inmap.data, space->interbuf.idmabuf_fd);
           if (ret != TRUE) {
             g_print ("%s: raw to nvrm conversion failed \n", __func__);

We run the command and can see expected output:

$ gst-launch-1.0 nvcompositor name=comp  sink_0::xpos=0 sink_0::ypos=0 sink_0::width=3840 sink_0::height=2160 sink_1::xpos=0 sink_1::ypos=0 sink_1::width=3840 sink_1::height=2160 ! nvoverlaysink nvarguscamerasrc ! "video/x-raw(memory:NVMM),format=NV12,width=1920,height=1080,framerate=30/1" ! nvvidconv ! 'video/x-raw(memory:NVMM),format=RGBA,width=3840,height=2160' ! queue ! comp.sink_0 multifilesrc location="overlay%03d.png" loop=1 ! pngdec ! videoparse format=11 framerate=30/1 width=3840 height=2160 ! 'video/x-raw,format=RGBA,width=3840,height=2160' ! nvvidconv ! 'video/x-raw(memory:NVMM),format=RGBA,width=3840,height=2160' ! queue ! comp.sink_1

Please try it with your camera source nvv4l2camerasrc. And the png file is named to overlay000.png

Thank you for providing this patch, it resolves the issue I was seeing. Makes sense that the issue was with nvvidconv now that you have pointed out the fix.

I have one remaining issue. This patch works as long as the input and the output are of the same resolution (in my case 3840x2160). However if the input source resolution differs from the output resolution (e.g. 1920x1080 input and 3840x2160 output) then the alpha (transparency) information is lost, and a black background is observed.

You can see in the patch code that the conversion does not run on any input that requires scaling. The “if” statement requires the condition:(!space->do_scaling)

Would it be possible to update the patch to consider sources that require scaling and still need to retain alpha?

If you would like to replicate the issue, I have modified your gstreamer command to scale down the png source to 1920x1080 (using nvvidconv) and then scale back up to 3840x2160 (using nvvidconv). You will see the alpha data is lost and you get a black background. Alternatively you could just use a 1920x1080 png image source.

$ gst-launch-1.0 nvcompositor name=comp  sink_0::xpos=0 sink_0::ypos=0 sink_0::width=3840 sink_0::height=2160 sink_1::xpos=0 sink_1::ypos=0 sink_1::width=3840 sink_1::height=2160 ! nvoverlaysink nvarguscamerasrc ! "video/x-raw(memory:NVMM),format=NV12,width=1920,height=1080,framerate=30/1" ! nvvidconv ! 'video/x-raw(memory:NVMM),format=RGBA,width=3840,height=2160' ! queue ! comp.sink_0 multifilesrc location="overlay%03d.png" loop=1 ! pngdec ! videoparse format=11 framerate=30/1 width=3840 height=2160 ! 'video/x-raw,format=RGBA,width=3840,height=2160' ! nvvidconv ! 'video/x-raw(memory:NVMM),format=RGBA,width=1920,height=1080' ! nvvidconv ! 'video/x-raw(memory:NVMM),format=RGBA,width=3840,height=2160' ! queue ! comp.sink_1

Hi,

This may not be possible since for doing scaling, it would need to call NvBufferTransform(). In this step the alpha is applied. Please scale it through videoscale plugin, or have the overlay in same resolution.

I expected that might be the case. The reality of my situation is that my overlay source is actually a windowed application with a transparent background that I am grabbing using the ximagesrc plugin. Combined with nvcompositor, this allows me to use the application as an OSD style overlay to the camera feed.

When the overlay application is 3840x2160, ximagesrc tends to drop frames since Xorg is single threaded and is maxing out one of the CPU cores. My hope was that I could drop the overlay application to 1920x1080 (this way no frames are dropped) and then scale the resolution up to 3840x2160 as part of the gstreamer pipeline before feeding it into the nvcompositor.

My testing shows that the videoscale plugin causes a drop in framerate because it’s a software based plugin so isn’t suitable.
And as mentioned above, using a source of the same resolution is not feasible either due to Xorg.

I don’t suppose there is an NVIDIA equivalent for videoscale that would offer better performance?

Hi,
Please apply the attachment and check if you can successfully run a command like:

$ gst-launch-1.0 nvcompositor name=comp  sink_0::xpos=0 sink_0::ypos=0 sink_0::width=3840 sink_0::height=2160 sink_1::xpos=0 sink_1::ypos=0 sink_1::width=3840 sink_1::height=2160 ! nvoverlaysink nvarguscamerasrc ! "video/x-raw(memory:NVMM),format=NV12,width=1920,height=1080,framerate=30/1" ! nvvidconv ! 'video/x-raw(memory:NVMM),format=RGBA,width=3840,height=2160' ! queue ! comp.sink_0 multifilesrc location="overlay%03d.png" loop=1 ! pngdec ! videoparse format=11 framerate=30/1 width=1920 height=1080 ! 'video/x-raw,format=RGBA,width=1920,height=1080' ! nvvidconv ! 'video/x-raw(memory:NVMM),format=RGBA,width=3840,height=2160' ! queue ! comp.sink_1

r32_7_TEST_libnvbuf_utils.zip (18.6 KB)

Please backup the original lib before the replacement.

This worked a treat! Thank you for taking the time to provide these patches. For anyone who stumbles across this post in the future and wants to get this working, install the two attached files to the following locations on the Jetson file system

libgstnvvidconv.so (81.9 KB)

/usr/lib/aarch64-linux-gnu/gstreamer-1.0/libgstnvvidconv.so

libnvbuf_utils.so (50.7 KB)

/usr/lib/aarch64-linux-gnu/tegra/libnvbuf_utils.so

3 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.