Set partial pixel to be transparent in video

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

Set partial pixel to be transparent in video

Sean
This post was updated on .
Hi,

I wrote to customized element (myelement) to set partial pixels of one video frame to be transparent. My machine is little endian.


This is myelement implementation, I want to make the upper half of 640x480 (i.e. the upper 640x240 pixels ) invisible by setting the Alpha value to be 0x0

    GstMapInfo info;
    if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {
      return GST_FLOW_ERROR;
    }
    for (int i  = 0; i < 240; i++) {
      for (int j = 0; j < 640; j++)
      info.data[(i*640+j)*4] = 0x0;
    }
    GST_FLOW_OK;


This is my test command:
gst_launch -v videotestsrc ! video/x-raw,format=RGBA,width=640, height=480 ! videoconvert ! myelement ! x264enc ! mpegtsmux ! filesink location=test.ts

 I expect the upper half of the test.ts should be transparent. However, the result is the pixel at (row,col)=(0,4), (0,8) (0,12)...... become a GREEN pixel. Would anyone help to comment which part is wrong?

Thanks a lot.
Reply | Threaded
Open this post in threaded view
|

Re: Set partial pixel to be transparent in video

Peter Maersk-Moller-2
Hi Sean.

GStreamer uses RGBA in byteorder and not in word-order. See https://en.wikipedia.org/wiki/RGBA_color_space for byte-order/word-order.

Your code is clearing the red component for the first half of the entire frame.

BTW you code should be more efficient. Find the beginning of the first pixel address, add 3 for RGBA and BGRA (0 for ARGB/ABGR) and then

Something like below

ifr (format != RGBA && format != BGRA && format != ARGB && format != ABGRA) goto fail;
uint8_t *p = frame_address_start ((start_row*width)+start_col)*4 + (format == RGBA || format == BGRA) ? 3 : 0;
stride = (start_col + width - end_col) << 2;
for (j=start_row; j <= end_row; j++) {
    for (i=start_col; i <= end_col; i++) { *p = 0;  p += 4; }
    p += stride;
}

Only one byte setting and one 32 bit addition per pixel affected plus one 32 bit addition per line affected.

On Mon, Sep 26, 2016 at 7:52 AM, Sean <[hidden email]> wrote:
Hi,

I wrote to customized element (myelement) to set partial pixels of one video
frame to be transparent. My machine is little endian.


This is myelement implementation, I want to make the upper half of 640x480
(i.e. the upper 640x240 pixels ) invisible by setting the Alpha value to be
0x0

    GstMapInfo info;
    if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {
      return GST_FLOW_ERROR;
    }
    for (int i  = 0; i < 240; i++) {
      for (int j = 0; j < 640; j++)
      info.data[(i*640+j)*4] = 0x0;
    }
    GST_FLOW_OK;


This is my test command:
gst_launch -v videotestsrc ! video/x-raw,format=RGBA,width=640, height=480 !
videoconvert ! myelement ! x264enc ! mpegtsmux ! filesink location=test.ts

 I expect the upper half of the test.ts should be transparent. However, the
result is (row,col)=(0,4), (0,8) (0,12)...... become a GREEN pixel. Would
anyone help to comment which part is wrong?

Thanks a lot.



--
View this message in context: http://gstreamer-devel.966125.n4.nabble.com/Set-partial-pixel-to-be-transparent-in-video-tp4679769.html
Sent from the GStreamer-devel mailing list archive at Nabble.com.
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel


_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Set partial pixel to be transparent in video

Peter Maersk-Moller-2
Smaller correction

if (format != RGBA && format != BGRA && format != ARGB && format != ABGRA) goto fail;
uint8_t *p = frame_address_start + ((start_row*width)+start_col)*4 + (format == RGBA || format == BGRA) ? 3 : 0;
stride = (start_col + width - end_col) << 2;
for (j=start_row; j <= end_row; j++) {
    for (i=start_col; i <= end_col; i++) { *p = 0;  p += 4; }
    p += stride;
}

On Mon, Sep 26, 2016 at 11:10 AM, Peter Maersk-Moller <[hidden email]> wrote:
Hi Sean.

GStreamer uses RGBA in byteorder and not in word-order. See https://en.wikipedia.org/wiki/RGBA_color_space for byte-order/word-order.

Your code is clearing the red component for the first half of the entire frame.

BTW you code should be more efficient. Find the beginning of the first pixel address, add 3 for RGBA and BGRA (0 for ARGB/ABGR) and then

Something like below

ifr (format != RGBA && format != BGRA && format != ARGB && format != ABGRA) goto fail;
uint8_t *p = frame_address_start ((start_row*width)+start_col)*4 + (format == RGBA || format == BGRA) ? 3 : 0;
stride = (start_col + width - end_col) << 2;
for (j=start_row; j <= end_row; j++) {
    for (i=start_col; i <= end_col; i++) { *p = 0;  p += 4; }
    p += stride;
}

Only one byte setting and one 32 bit addition per pixel affected plus one 32 bit addition per line affected.


On Mon, Sep 26, 2016 at 7:52 AM, Sean <[hidden email]> wrote:
Hi,

I wrote to customized element (myelement) to set partial pixels of one video
frame to be transparent. My machine is little endian.


This is myelement implementation, I want to make the upper half of 640x480
(i.e. the upper 640x240 pixels ) invisible by setting the Alpha value to be
0x0

    GstMapInfo info;
    if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {
      return GST_FLOW_ERROR;
    }
    for (int i  = 0; i < 240; i++) {
      for (int j = 0; j < 640; j++)
      info.data[(i*640+j)*4] = 0x0;
    }
    GST_FLOW_OK;


This is my test command:
gst_launch -v videotestsrc ! video/x-raw,format=RGBA,width=640, height=480 !
videoconvert ! myelement ! x264enc ! mpegtsmux ! filesink location=test.ts

 I expect the upper half of the test.ts should be transparent. However, the
result is (row,col)=(0,4), (0,8) (0,12)...... become a GREEN pixel. Would
anyone help to comment which part is wrong?

Thanks a lot.



--
View this message in context: http://gstreamer-devel.966125.n4.nabble.com/Set-partial-pixel-to-be-transparent-in-video-tp4679769.html
Sent from the GStreamer-devel mailing list archive at Nabble.com.
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel



_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Set partial pixel to be transparent in video

Nicolas Dufresne-4
Another note, x264enc does not support any format with an alpha channel. If "myelement" is expecting RGBA, then your pipeline should fail with "no-negotiated". You should review your caps negotiation.

Nicolas

Le lundi 26 septembre 2016 à 11:12 +0200, Peter Maersk-Moller a écrit :
Smaller correction

if (format != RGBA && format != BGRA && format != ARGB && format != ABGRA) goto fail;
uint8_t *p = frame_address_start + ((start_row*width)+start_col)*4 + (format == RGBA || format == BGRA) ? 3 : 0;
stride = (start_col + width - end_col) << 2;
for (j=start_row; j <= end_row; j++) {
    for (i=start_col; i <= end_col; i++) { *p = 0;  p += 4; }
    p += stride;
}

On Mon, Sep 26, 2016 at 11:10 AM, Peter Maersk-Moller <[hidden email]> wrote:
Hi Sean.

GStreamer uses RGBA in byteorder and not in word-order. See https://en.wikipedia.org/wiki/RGBA_color_space for byte-order/word-order.

Your code is clearing the red component for the first half of the entire frame.

BTW you code should be more efficient. Find the beginning of the first pixel address, add 3 for RGBA and BGRA (0 for ARGB/ABGR) and then

Something like below

ifr (format != RGBA && format != BGRA && format != ARGB && format != ABGRA) goto fail;
uint8_t *p = frame_address_start ((start_row*width)+start_col)*4 + (format == RGBA || format == BGRA) ? 3 : 0;
stride = (start_col + width - end_col) << 2;
for (j=start_row; j <= end_row; j++) {
    for (i=start_col; i <= end_col; i++) { *p = 0;  p += 4; }
    p += stride;
}

Only one byte setting and one 32 bit addition per pixel affected plus one 32 bit addition per line affected.


On Mon, Sep 26, 2016 at 7:52 AM, Sean <[hidden email]> wrote:
Hi,

I wrote to customized element (myelement) to set partial pixels of one video
frame to be transparent. My machine is little endian.


This is myelement implementation, I want to make the upper half of 640x480
(i.e. the upper 640x240 pixels ) invisible by setting the Alpha value to be
0x0

    GstMapInfo info;
    if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {
      return GST_FLOW_ERROR;
    }
    for (int i  = 0; i < 240; i++) {
      for (int j = 0; j < 640; j++)
      info.data[(i*640+j)*4] = 0x0;
    }
    GST_FLOW_OK;


This is my test command:
gst_launch -v videotestsrc ! video/x-raw,format=RGBA,width=640, height=480 !
videoconvert ! myelement ! x264enc ! mpegtsmux ! filesink location=test.ts

 I expect the upper half of the test.ts should be transparent. However, the
result is (row,col)=(0,4), (0,8) (0,12)...... become a GREEN pixel. Would
anyone help to comment which part is wrong?

Thanks a lot.



--
View this message in context: http://gstreamer-devel.966125.n4.nabble.com/Set-partial-pixel-to-be-transparent-in-video-tp4679769.html
Sent from the GStreamer-devel mailing list archive at Nabble.com.
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel




_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel

_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Set partial pixel to be transparent in video

Sean
In reply to this post by Peter Maersk-Moller-2
Hi, Peter,

Thanks for pointing out the "byte-ordering" of RGBA in Gstreamer. However, if we don't care the performance and only care the correctness. I think the following implement should work in myelement (i. e. writing the 4th byte of each pixel):


    for (int i  = 0; i < 240; i++) {
      for (int j = 0; j < 640; j++)
      info.data[(i*640+j)*4-1] = 0x0;
    }

However, the result is the same (i.e. the pixel at (row,col)=(0,4), (0,8) (0,12)...... become a GREEN pixel). Is it related to the "stride" value? If yes, how would I get stride information? I checked "GstMapInfo" which doesn't have stride information?

Thanks.
Reply | Threaded
Open this post in threaded view
|

Re: Set partial pixel to be transparent in video

Sean
In reply to this post by Nicolas Dufresne-4
Hi, Nicolas,

What Caps should I specify if I want to modify Alpha value in Raw video (AYUV or ARGB or RGBA) before x264enc? Thanks a lot.

Sean
Reply | Threaded
Open this post in threaded view
|

Re: Set partial pixel to be transparent in video

Peter Maersk-Moller-2
In reply to this post by Sean
Hi Sean.

See commets inline.

On Mon, Sep 26, 2016 at 6:50 PM, Sean <[hidden email]> wrote:
Hi, Peter,
Thanks for pointing out the "byte-ordering" of RGBA in Gstreamer. However,
if we don't care the performance and only care the correctness. I think the
following implement should work in myelement (i. e. writing the 4th byte of
each pixel):

    for (int i  = 0; i < 240; i++) {
      for (int j = 0; j < 640; j++)
      info.data[(i*640+j)*4-1] = 0x0;
    }

Not quite. When i and j are 0, you get info.data[-1].
Furthermore I don't know the type of info.data. If it not a byte array, you  will get it terribly wrong. So something like this:

  u_int8_t* p = ((u_int8_t*)&info.data[0])+3;
  for (int i = 0; i < 240 ; i++) {
    for (int j = 0 ; j < 640 ; j++) {
      *p = 0x0;
      p += 4;
    }
  }

  If that doesn't work, then maybe the format in info.data isn't RGBA byte-order. Then you could try add 0, 1 or 2 until it worked. That would tell you here the alpha is placed.
 

However, the result is the same (i.e. the pixel at (row,col)=(0,4), (0,8)
(0,12)...... become a GREEN pixel). Is it related to the "stride" value? If
yes, how would I get stride information? I checked "GstMapInfo" which
doesn't have stride information?

Setting something to 0 should not produce green. However you have not explained how you get to see the pixel is green. So how do you get to see that. Maybe you should show your working pipeline for testing this. Are you determining that you see green after encoding it and then displaying it using a player? So what is your pipeline and how do you see it is green? You can not reliably test a pixel value by sending it through an encoder.

If I slightly modify your pipeline to this moving the videoconvert and specifying I420 for input to x264enc:

  gst_launch -v videotestsrc ! video/x-raw,format=RGBA,width=640, height=480 ! myelement ! videoconvert ! video/x-raw,format=I420 ! x264enc ! mpegtsmux ! filesink location=test.ts

Then what would you expect to see?  What would you expect a RGB pixel with alpha set to zero to be converted and encoded as? Again you can not test a pixel value reliably by sending it through an encoder.

By the way your original example pipeline would convert video from RGBA to YUV 4:4:4 BEFORE entering you element. And YUV 4:4:4 is definitely not RGBA. So your green might very well be a result and indicator of an invalid YUV value. Not all 2^24 possible YUV values are valid.

The stride value is the number of bytes between the first pixel in row 0 and the first pixel in row 1. If the format is RGBA, then the stride value is 4 times the width. If is 24 bit RGB, then it is 3 times the width unless it is RGB in 32 bit.

However the stride I used in my example was the number of bytes between the last pixel in first row you wanted to apply a zero alpha value to and the first pixel in the next row you wanted to apply the zero alpha setting to. If you wanted to apply zero alpha to all pixels in first and second row up to some number, then stride would be zero. I just provided code for the general example and if you for a specific subset set startcol=1 and endcol=640, then it will also work.

Thanks.



--
View this message in context: http://gstreamer-devel.966125.n4.nabble.com/Set-partial-pixel-to-be-transparent-in-video-tp4679769p4679799.html
Sent from the GStreamer-devel mailing list archive at Nabble.com.
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel


_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Set partial pixel to be transparent in video

Sean
Hi, Peter,

Thanks for the detailed comment. I saw the GREEN pixel from from the encoded test.ts file via a player. I also tried 4 possible offset (0, 1, 2, 3) of the Alpha byte-position. The result is the same (GREEN pixel at at (row,col)=(0,4), (0,8)...). It seems that the Alpha information is dropped during x264enc and in your modified pipeline, the input format of x264enc is I420, the Alpha information is lost as well. So, is there any way keep the Alpha information after encoding?

I checked this link (https://fossies.org/linux/gst-plugins-good/tests/check/elements/alpha.c). The RGBA format is the same as you mentioned. But I tried 4 possible Alpha offset, no one works. Thanks a lot.

Reply | Threaded
Open this post in threaded view
|

Re: Set partial pixel to be transparent in video

Peter Maersk-Moller-2
Hi Sean.

See comments inline.

On Tue, Sep 27, 2016 at 6:46 AM, Sean <[hidden email]> wrote:
Hi, Peter,
Thanks for the detailed comment. I saw the GREEN pixel from from the encoded
test.ts file via a player. I also tried 4 possible offset (0, 1, 2, 3) of
the Alpha byte-position. The result is the same (GREEN pixel at at
(row,col)=(0,4), (0,8)...).

Well, if you were using the pipeline you original posted, you are not cahnging the alpha value of pixels but rather creating invalid values of YUV before encoding as H.264 which correctly replaces invalid YUV values with a colour of green.
 
It seems that the Alpha information is dropped
during x264enc
 
Yes all alpha information is dropped before video encoding. That is according to specs. Nearly no video codec support preserving the alpha information.
The ones that do, you quite likely will not want to use. See https://www.digitalrebellion.com/blog/posts/list_of_video_formats_supporting_alpha_channels

and in your modified pipeline, the input format of x264enc is
I420, the Alpha information is lost as well.

As according to specs.
 
So, is there any way keep the
Alpha information after encoding?

No. Plain and simple.
 
I checked this link
(https://fossies.org/linux/gst-plugins-good/tests/check/elements/alpha.c).
The RGBA format is the same as you mentioned. But I tried 4 possible Alpha
offset, no one works. Thanks a lot.

As I said, with your original pipeline you just create invalid YUV values, with my modified pipeline you correctly change the alpha value, however when converted to be encoded, alpha values are thrown away.

You can pseudo stream using png still images preserving alpha information costing bandwidth and CPU.

The questions are
a) What are you trying to do?
b) Why ?
 





--
View this message in context: http://gstreamer-devel.966125.n4.nabble.com/Set-partial-pixel-to-be-transparent-in-video-tp4679769p4679803.html
Sent from the GStreamer-devel mailing list archive at Nabble.com.
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel


_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Set partial pixel to be transparent in video

Sean
This post was updated on .
Hi, Peter,

Thanks for the clarification. And you're right. The problem comes from that x264enc doesn't recognized the Alpha channel (or my pipeline sent an invalid YUV to x264enc). I solved this problem by adding "compositor" into my pipeline such that "compositor" will take ARGB/AYUV as input, do alpha blending and output YUV (with Alpha information included). The, the output YUV will become a valid input to x264enc and the output of x264enc (test.ts) will have partial transparent pixels.

1. I use offset 0 to modify the Alpha value of ARGB in myelement.
2. Here is the pipeline that works:

gst_launch -v compositor name=comp  ! videoconvert ! x264enc ! mpegtsmux ! filesink location=test.ts videotestsrc pattern=red ! video/x-raw,format=AYUV,width=640,height=480 ! myelement ! comp.sink_0