I want to use "H264 NAL unit data" as Input and obtain "RGB data"

Hello.
I want to input “H264 NAL unit data” and obtain “RGB data”.
Specifically, I would like to pass the NAL unit data of “SPS”, “PPS”, and “I frame” to Gstreamer and obtain the “RGB data” of the decoding result.

The Jetson Multimedia API sample code “00_Video_decode” can convert h264 to nv12 with the following command.
./video_decode H264 --disable-rendering -o test.nv12 …/…/data/Video/sample_outdoor_car_1080p_10fps.h264

Is it possible to convert h264 (NAL unit data) to RGB data (still image data) using video_decode?

thank you.

Hi,
The hardware converter does not support 24-bit RGB. The possible solution will be like:

> decode H264 to YUV420 in NvBufSurface -> convert to RGBA in NvBufSurface through hardware converter -> copy RGB data from NvBufSurface to CPU buffer

You can base on 00_video_decode to implement the solution.

thank you for your reply!

decode H264 to YUV420 in NvBufSurface → convert to RGBA in NvBufSurface through hardware converter → copy RGB data from NvBufSurface to CPU buffer

Parsed video_decode.
dump_dmabuf is executed in dec_capture_loop_fcn.
It seems that YUV420 data is mapped to NvBufSurface in dump_dmabuf.
(NvBufSurfaceMap())
Is “decode H264 to YUV420 in NvBufSurface” this part?

Regarding the next “convert to RGBA in NvBufSurface through hardware converter”.
Do you mean convert the mapped NvBufSurface to RGBA?
Where is it written how to do that?
Is it “07_video_convert”?

thank you.

Hi,
Please allocate dst_dma_fd in NVBUF_COLOR_FORMAT_RGBA. And after NvBufSurf::NvTransform() call, you can get RGBA NvBufSurface. And then can get CPU pointer by calling NvBufSurfaceMap()

Hi.

video_decode does not support “NVBUF_COLOR_FORMAT_RGBA”.
It is described in help.

-f <out_pixfmt> 1 NV12, 2 I420, 3 NV16, 4 NV24 [Default = 1]

So I added “5 RGB, 6 RGBA” to video_decode.
(I want to try RGB too)

How should I modify the following process?
(In other words, if ctx->out_pixfmt is 5 or 6, should I execute “dump_dmabuf(ctx->dst_dma_fd, 2, ctx->out_file)”?)

/* Write raw video frame to file. /
if (!ctx->stats && ctx->out_file)
{
/
Dumping two planes for NV12, NV16, NV24 and three for I420 */
dump_dmabuf(ctx->dst_dma_fd, 0, ctx->out_file);
dump_dmabuf(ctx->dst_dma_fd, 1, ctx->out_file);
if (ctx->out_pixfmt == 2)
{
dump_dmabuf(ctx->dst_dma_fd, 2, ctx->out_file);
}
}

thank you.

Hi,
You would need to customize the sample to add the format. The decoded data is in YUV420 and then convert it to RGBA.

thank you for your reply.

It seems I misunderstood.
There’s no need to add “5 RGB, 6 RGBA” to the -f option.

./video_decode H264 --disable-rendering -o test.i420 -f 2 ../../data/Video/sample_outdoor_car_1080p_10fps.h264

Run the above command to convert from H264 to I420.
At that time, NvTransform is executed.

/* Perform Blocklinear to PitchLinear conversion. */
ret = NvBufSurf::NvTransform(&transform_params, dec_buffer->planes[0].fd, ctx->dst_dma_fd);

Then dump_dmabuf is executed.

/* Write raw video frame to file. */
if (!ctx->stats && ctx->out_file)
{
    /* Dumping two planes for NV12, NV16, NV24 and three for I420 */
    dump_dmabuf(ctx->dst_dma_fd, 0, ctx->out_file);
    dump_dmabuf(ctx->dst_dma_fd, 1, ctx->out_file);
    if (ctx->out_pixfmt == 2)
    {
        dump_dmabuf(ctx->dst_dma_fd, 2, ctx->out_file);
    }
}

Inside dump_dmabuf, NvBufSurfaceMap is executed.

NvBufSurface *nvbuf_surf = 0;
ret = NvBufSurfaceFromFd(dmabuf_fd, (void**)(&nvbuf_surf));
ret = NvBufSurfaceMap(nvbuf_surf, 0, plane, NVBUF_MAP_READ_WRITE);

This process stores I420 data in “NvBufSurface *nvbuf_surf”.
After that, I am writing the I420 data to the stream.

I need to “convert I420 data to RGB or RGBA” between “get I420 data” and “write”.

Is the above understanding correct?
If so, how can I convert I420 data to RGB or RGBA?

In the query_and_set_capture function, there is a process to NvAllocate using NvBufSurfaceTag_VIDEO_CONVERT.
Does this process give you a hint?

thank you.

Hi,
The conversion is done in

/* Perform Blocklinear to PitchLinear conversion. */
ret = NvBufSurf::NvTransform(&transform_params, dec_buffer->planes[0].fd, ctx->dst_dma_fd);

Decoded YUV is in dec_buffer->planes[0].fd and convert to ctx->dst_dma_fd. If you allocate ctx->dst_dma_fd in RGBA, you can get NvBufSurface in RGBA.

RGBA is single plane so please only save plane 0:

dump_dmabuf(ctx->dst_dma_fd, 0, ctx->out_file);

to storage.

Hi.

/* Perform Blocklinear to PitchLinear conversion. */
ret = NvBufSurf::NvTransform(&transform_params, dec_buffer->planes[0].fd, ctx->dst_dma_fd);

The value of “ctx->dst_dma_fd” when executing the above process was 52.
52 is “NVBUF_COLOR_FORMAT_NV24”.

The results of changing the value of the “-f” option are as follows.

 -f 1(NV12) -> ctx->dst_dma_fd = 52
 -f 2(I420) -> ctx->dst_dma_fd = 52
 -f 3(NV16) -> ctx->dst_dma_fd = 52
 -f 4(NV24) -> ctx->dst_dma_fd = 52

In other words, regardless of the value of the -f option, NvTransform will be executed with “dst_dma_fd = 52”.
I found this strange.
Is this expected behavior?

Now, I tried forcibly changing the value of ctx->dst_dma_fd to RGBA when executing NvTransform.

/* Perform Blocklinear to PitchLinear conversion. */
ctx->dst_dma_fd = NVBUF_COLOR_FORMAT_RGBA;   // add
ret = NvBufSurf::NvTransform(&transform_params, dec_buffer->planes[0].fd, ctx->dst_dma_fd);

The following error occurred.

nvbuf_utils: dmabuf_fd 19 mapped entry NOT found

How do I assign RGBA to ctx->dst_dma_fd?
thank you.

Hi,
Please study the code and find where dst_dma_fd is allocated. And change the format to RGBA before NvBufSurf::NvAllocate() is called.

Hi.

Please study the code and find where dst_dma_fd is allocated. And change the format to RGBA before Allocate() is called.

It’s in query_and_set_capture().

    params.memtag = NvBufSurfaceTag_VIDEO_CONVERT;

    ret = NvBufSurf::NvAllocate(&params, 1, &ctx->dst_dma_fd);

When I run NvAllocate, 52 (NVBUF_COLOR_FORMAT_NV24) is allocated to dst_dma_fd.
Looking inside NvAllocate, NvBufSurfaceAllocate is being executed, but I was unable to trace the contents of this function.

dst_dma_fd is determined by NvAllocate, but I think it is determined by “params.colorFromat”.
“params.colorFromat” is determined by “ctx->out_pixfmt” just before this.
“ctx->out_pixfmt” is determined by the value of the “-f” option.

In other words, as I wrote before, I thought that changing the value of the “-f” option would change dst_dma_fd, but that was not the case.

Are there any errors in the above analysis results?

thank you.

Hi,
The buffer is allocated per NvCommonAllocateParams. So please configure

params.colorFormat = NVBUF_COLOR_FORMAT_RGBA;

before allocating ctx->dst_dma_fd.

thank you for your reply.

yes. I tried that too.
The method is to execute “params.colorFromat = NVBUF_COLOR_FORMAT_RGBA;” before NvAllocate.
But as a result of NvAllocate, dst_dma_fd was 52.

Let me sort it out here.
The first piece of advice was:

decode H264 to YUV420 in NvBufSurface → convert to RGBA in NvBufSurface through hardware converter → copy RGB data from NvBufSurface to CPU buffer

(1)decode H264 to YUV420 in NvBufSurface

“./video_decode H264 --disable-rendering -o test.i420 -f 2 …/…/data/Video/sample_outdoor_car_1080p_10fps.h264”
Run the above command.

	/* Perform Blocklinear to PitchLinear conversion. */
	ret = NvBufSurf::NvTransform(&transform_params, dec_buffer->planes[0].fd, ctx->dst_dma_fd);

At the time this process is executed, “dec_buffer->planes[0].fd” contains YUV420 data.
ctx->dst_dma_fd contains “NVBUF_COLOR_FORMAT_NV24”, so if left as is, it will be converted to NV24 instead of RGBA.

(2)convert to RGBA in NvBufSurface through hardware converter

I thought that I should set the value of ctx->dst_dma_fd to “NVBUF_COLOR_FORMAT_RGBA” and then execute NvTransform.
However, as I wrote, it didn’t work.

(3)copy RGB data from NvBufSurface to CPU buffer

If (2) goes well, I don’t think (3) will be difficult.

As mentioned above, the problem is that (2) does not work.
What should I try next?

thank you.

Hi,
This is not correct:


You set

params.colorFormat = NVBUF_COLOR_FORMAT_RGBA;

so the buffer is allocated in RGBA. And then call

NvBufSurf::NvTransform(&transform_params, dec_buffer->planes[0].fd, ctx->dst_dma_fd);

dec_buffer->planes[0].fd(YUV420, blocklinear) is converted to ctx->dst_dma_fd(RGBA pitchlinear)

And you get the data in ctx->dst_dma_fd(RGBA pitchlinear). You can call

dump_dmabuf(ctx->dst_dma_fd, 0, ctx->out_file);

to dump it out and check.

Thank you for your reply!

Modified the “-f” option to decode to RGBA.

    if (ctx->out_pixfmt == 1)
      params.colorFormat = NVBUF_COLOR_FORMAT_NV12;
    else if (ctx->out_pixfmt == 2)
      params.colorFormat = NVBUF_COLOR_FORMAT_YUV420;
    else if (ctx->out_pixfmt == 3)
      params.colorFormat = NVBUF_COLOR_FORMAT_NV16;
    else if (ctx->out_pixfmt == 4)
      params.colorFormat = NVBUF_COLOR_FORMAT_NV24;
    // add
    else if (ctx->out_pixfmt == 5)
      params.colorFormat = NVBUF_COLOR_FORMAT_RGBA;

    params.memtag = NvBufSurfaceTag_VIDEO_CONVERT;

    ret = NvBufSurf::NvAllocate(&params, 1, &ctx->dst_dma_fd);

The part that executes dump_dmabuf has also been changed.

    /* Write raw video frame to file. */
    if (!ctx->stats && ctx->out_file)
    {
        // NV12, YUV420, NV16, NV24
        if (ctx->out_pixfmt <= 4)
        {
            /* Dumping two planes for NV12, NV16, NV24 and three for I420 */
            dump_dmabuf(ctx->dst_dma_fd, 0, ctx->out_file);
            dump_dmabuf(ctx->dst_dma_fd, 1, ctx->out_file);
            if (ctx->out_pixfmt == 2)
            {
                dump_dmabuf(ctx->dst_dma_fd, 2, ctx->out_file);
            }
        }
        // RGBA
        else
        {
            dump_dmabuf(ctx->dst_dma_fd, 0, ctx->out_file);
        }
    }

I tried the below command.

./video_decode H264 --disable-rendering -o test.nv12 -f 1 ../../data/Video/sample_outdoor_car_1080p_10fps.h264
./video_decode H264 --disable-rendering -o test.i420 -f 2 ../../data/Video/sample_outdoor_car_1080p_10fps.h264
./video_decode H264 --disable-rendering -o test.nv16 -f 3 ../../data/Video/sample_outdoor_car_1080p_10fps.h264
./video_decode H264 --disable-rendering -o test.nv24 -f 4 ../../data/Video/sample_outdoor_car_1080p_10fps.h264
./video_decode H264 --disable-rendering -o test.rgba -f 5 ../../data/Video/sample_outdoor_car_1080p_10fps.h264

The five files generated were of different sizes.
I will now check whether it is decoded correctly.

In particular, the contents of “test.rgba” were as follows.

sample_outdoor_car_1080p_10fps.h264 has been replaced with “a short video with a pitch black screen”, so I feel that this binary data is appropriate.
Thank you for making it this far.

By the way, do I understand that “test.rgba” stores several pieces of RGBA data consecutively?
The resolution of h264 is “1280x960”.
RGBA represents 1 pixel with 4 bytes.
Therefore, the data size of one still image is “12809604=4915200”.
The file size of “test.rgba” was 737280000 bytes.

737280000/4915200=150

Therefore, am I correct in my understanding that “test.rgba” stores 150 frames of RGBA data?

thank you.

Hi,
In should dump all frames in default 00_video_decode. You may modify the code to dump only one frame for checking.

Hi.

thank you for your reply.

I want to set the output format to RGB.
RGBA “A: Alpha” is not required.

You said “video_decode does not support RGB”.
How can I modify video_decode to output RGB?

thank you.

Hi,
You would need to implement software flow like:

  1. map RGBA NvBufSurface to CPU
  2. malloc a CPU buffer in (width * height * 3) bytes
  3. copy RGB data from NvBufSurface to the CPU buffer
  4. unmap NvBufSurface

Hi.

Regarding the place to be remodeled.
Specifically, the dump_dmabuf function in NvUtils.cpp?

Hi,
You may customize dump_dmabuf(). Or keep dump_dmabuf() and implement a new function for your use-case. Either one is good since it is open source code.