Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Looking for example of how to use QVideoFrame with multiple plane pixel format (specifically P016 or P216 or NV16)

Looking for example of how to use QVideoFrame with multiple plane pixel format (specifically P016 or P216 or NV16)

Scheduled Pinned Locked Moved Solved General and Desktop
8 Posts 2 Posters 1.7k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P Offline
    P Offline
    paulpv
    wrote on last edited by paulpv
    #1

    I am writing an app that receives NDI video frames from the network, writes them to a QVideoFrame, and then QVideoSinks them to a QVideoWidget.

    https://github.com/NightVsKnight/NDI-Monitor/blob/main/ndi-monitor-qt6/

    Things work fine if I tell NDI to send me NDIlib_recv_color_format_UYVY_BGRA, which I process as QVideoFrameFormat::PixelFormat::Format_UYVY and it renders correctly on the screen with an expected small loss of quality.

    When I tell NDI to send me NDIlib_recv_color_format_best, they send me NDIlib_FourCC_video_type_P216 which I process as QVideoFrameFormat::PixelFormat::Format_P016.
    P216 is a semi-planar format with 2 planes.
    It is described as:

    	// YCbCr color space using 4:2:2 in 16bpp.
    	// In memory this is a semi-planar format. This is identical to a 16bpp version of the NV16 format.
    	// The first buffer is a 16bpp luminance buffer.
    	// Immediately after this is an interleaved buffer of 16bpp Cb, Cr pairs.
    

    See also:

    • https://wiki.videolan.org/YUV#Other_NV_formats
    • https://chromium.googlesource.com/libyuv/libyuv/+/HEAD/docs/formats.md#nv12-and-nv21
    • https://doc.qt.io/qt-6/qvideoframeformat.html#PixelFormat-enum
    • https://en.wikipedia.org/wiki/FFmpeg#Pixel_formats
    • https://docs.microsoft.com/en-us/windows/win32/medfound/10-bit-and-16-bit-yuv-video-formats#422-formats

    I have found zero Qt examples or Qt open source projects showing how to use QVideoFrame with multiple planes.

    I wrote it how I think I understand it should go at:

    https://github.com/NightVsKnight/NDI-Monitor/blob/main/ndi-monitor-qt6/ndireceiverworker.cpp#L291

    Problem with my code is that it crashes with either heap corruption or write access violation just shortly after halfway through memcpying the 2nd plane:

    https://github.com/NightVsKnight/NDI-Monitor/blob/main/ndi-monitor-qt6/ndireceiverworker.cpp#L353

    image

    Before someone responds "You are obviously corrupting your heap or memory", the 2nd plane should be a contiguous 5,529,600 bytes, but I am crashing after writing only 2,858,994 bytes to it.

    I think my problem has something to do with the QVideoFrame::bits(int plane) mapped buffers that I must be using wrong, but I am doing the best I know how considering I have been unable find any examples of how to use multiple planes.

    Or maybe I am incorrectly using P016 for a P216 pixel format?

    If I write less than 2,858,995 bytes of the 2nd plane's 5,529,600 bytes the code no longer crashes and proves that it is mostly working, but it is clearly an incomplete raster:

    image

    Notice how the 2nd plane's U and V [color] components stretch down the screen because the write was incomplete.
    If I write less bytes (ex: less than bytesInPlane / 2), it gets droopier.
    It should look like this:

    image

    So, how does one correctly write to multi-planar or semi-planar video frames and prevent it from corrupting the heap/memory?

    Thanks!

    1 Reply Last reply
    0
    • P Offline
      P Offline
      paulpv
      wrote on last edited by paulpv
      #2

      I have learned two things:

      1. The crash is solved by changing:
      memcpy(videoFrame.bits(plane), pNdiVideoFrame->p_data, bytesInPlane);
      

      to

      memcpy(videoFrame.bits(plane), pNdiVideoFrame->p_data, videoFrame.mappedBytes(planeNum));
      
      1. Format P016's layout is https://docs.microsoft.com/en-us/windows/win32/medfound/10-bit-and-16-bit-yuv-video-formats#p016-and-p010:
        8c0d91c4-9e4a-45cd-af7b-02d1439cd356-image.png
        Format P216's layout is https://docs.microsoft.com/en-us/windows/win32/medfound/10-bit-and-16-bit-yuv-video-formats#p216-and-p210:
        77d009f2-143e-4717-8711-abf3835f2e13-image.png
        That H/2 explains the phenomenon that I am experiencing.

      I need to either:

      1. trick the existing QVideoFrame code in to using P216
        -or-
      2. convert P216 (4:2:2) to P016 (4:2:0)...which I would prefer to not have to do.
        -or-
      3. implement my own P216 processing.
      1 Reply Last reply
      0
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by SGaist
        #3

        Hi,

        I would add solution number 4: add support for P216 to QVideoFrame.

        It would be a nice longterm option.

        As for your current issue, you would indeed need to reprocess the YV part to fit P016.

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        P 1 Reply Last reply
        1
        • SGaistS SGaist

          Hi,

          I would add solution number 4: add support for P216 to QVideoFrame.

          It would be a nice longterm option.

          As for your current issue, you would indeed need to reprocess the YV part to fit P016.

          P Offline
          P Offline
          paulpv
          wrote on last edited by
          #4

          @SGaist said in Looking for example of how to use QVideoFrame wiith multiple plane pixel format (specifically P016 or P216 or NV16):

          Hi,
          I would add solution number 3: add support for P216 to QVideoFrame.
          It would be a nice longterm option.

          I already added to my followup and was about to post a new question specific to P216.
          My OP was on the correct/recommended way to process multi/semi-planar pixel formats.
          Think my solution is close?

          1 Reply Last reply
          0
          • SGaistS Offline
            SGaistS Offline
            SGaist
            Lifetime Qt Champion
            wrote on last edited by
            #5

            My number was wrong !

            Number three might be the quickest to implement but likely not the most efficient.

            Hence my number 4 suggestion.

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            P 1 Reply Last reply
            0
            • SGaistS SGaist

              My number was wrong !

              Number three might be the quickest to implement but likely not the most efficient.

              Hence my number 4 suggestion.

              P Offline
              P Offline
              paulpv
              wrote on last edited by
              #6

              @SGaist Thanks.
              Know much about efficiently converting 4:2:2 (what the unsupported P216 is) to 4:2:0 (what the supported P016 is)?
              Seems like that should be pretty straight forward.

              1 Reply Last reply
              0
              • SGaistS Offline
                SGaistS Offline
                SGaist
                Lifetime Qt Champion
                wrote on last edited by
                #7

                I don't have it at hand but looking for color space conversion should give you some good results.

                Interested in AI ? www.idiap.ch
                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                1 Reply Last reply
                0
                • P Offline
                  P Offline
                  paulpv
                  wrote on last edited by paulpv
                  #8

                  To follow up, I have temporarily mitigated the P216 -> P016 issue by using this code to scan every other UV line:
                  1e87949e-9cab-4e88-90b0-c6efb704556a-image.png

                  It still leaves a few small artifacts laying around, but it is passable while I start the conversation of getting P216 added to Qt.

                  Thanks!

                  Pv

                  1 Reply Last reply
                  1

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved