We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 4023

Summary: SDL_LockTexture returns a wrong pitch for format NV21 and streaming textures
Product: SDL Reporter: Michele Caini <michele.caini>
Component: renderAssignee: Sam Lantinga <slouken>
Status: RESOLVED INVALID QA Contact: Sam Lantinga <slouken>
Severity: normal    
Priority: P2    
Version: 2.0.7   
Hardware: x86_64   
OS: Linux   

Description Michele Caini 2018-01-03 18:10:45 UTC
SDL_LockTexture just returns the pitch value of the underlying texture.
As an example - http://hg.libsdl.org/SDL/file/a9a3023d29f9/src/render/opengles2/SDL_render_gles2.c#l888

    *pitch = tdata->pitch;

On the other side, SDL_CreateTexture doesn't set it properly in case of format NV21 and streaming textures.
As an example - http://hg.libsdl.org/SDL/file/a9a3023d29f9/src/render/opengles2/SDL_render_gles2.c#l632

In particulare, see this branch:

   632     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   633         size_t size;
   634         data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
   635         size = texture->h * data->pitch;
   636         if (data->yuv) {
   637             /* Need to add size for the U and V planes */
   638             size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
   639         }
   640         if (data->nv12) {
   641             /* Need to add size for the U/V plane */
   642             size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
   643         }
   644         data->pixel_data = SDL_calloc(1, size);
   645         if (!data->pixel_data) {
   646             SDL_free(data);
   647             return SDL_OutOfMemory();
   648         }
   649     }

The size use to allocate the pixel data is adjusted somehow for yuv images, but the pitch isn't modified.
As an example, for NV21 (for which SDL_BYTESPERPIXEL returns 1), pitch is equale to the width of the texture. It should be 1.5 times the width instead.
Fortunately, enough space is allocated and one can just ignore the pitch value returned by SDL_LockTexture and use its own.
Comment 1 Sam Lantinga 2018-01-03 18:40:24 UTC
The pitch is the amount to offset a pointer to the beginning of a row of pixels to get to the next row of pixels. For NV12 and NV21 you need to go width bytes to get to the next row. The format is special in that there is additional data at the end of the Y plane for chroma, but the meaning of pitch is the same and is correct.
Comment 2 Michele Caini 2018-01-03 18:53:44 UTC
Uhm. It sounds confusing actually.
On Android, the pitch of an NV21 image grabbed from the camera is 1.5 times the width. That's how I spotted the difference in SDL.
That's because it considers 12 bits per pixel as a whole probably and not w*h plus two planes at the end.
That being said, in SDL one cannot use pitch*h to know the size of the storage pointed by the returned void pointer when using an opaque texture with SDL_LockTexture. How should I do to know the actual size of the storage thus?
Comment 3 Sam Lantinga 2018-01-03 21:59:52 UTC
Pitch * h is only valid for single plane formats. For multi-plane formats you'll need to know the format in order to know the size of the storage. Do you have code that needs to know how big the storage is but doesn't know how to interpret the pixel data?
Comment 4 Sam Lantinga 2018-01-03 22:01:13 UTC
Keep in mind that the pitch could actually be different from the width, e.g. for images with row alignment restrictions or odd widths.
Comment 5 Michele Caini 2018-01-03 22:07:03 UTC
I'm grabbing frames from the android camera and rendering some of them on a streaming texture. The idea was to separate the two layers and use opaque textures on which to memcopy pixels with no reasoning at all in the specific system. However, I can push down the size of the image somehow, not a problem actually.
Honestly, I was now curious to understand how things work under the hood.
This "issue" gave me the chance to dig into the code of SDL and it's interesting, but I've not (yet?) the skills to fully understand everything.

Thank you for your help and answers, really appreciated. Keep on working on SDL for it's really an amazing library. Chapeau.
Comment 6 Sam Lantinga 2018-01-03 22:19:16 UTC
You're welcome!

It might help to think about the pitch as the distance in bytes from one row of pixels in an image to the next row of pixels.

SDL started out only supporting single plane images and adding YUV formats was done later. That's why you'll see libraries that specifically deal with YUV formats will often have a pitch for each plane, as they may be different, and it's best not to make assumptions.

Cheers!