You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
For certain video dimensions where the video is encoded in YUV format, sws_scale in AVProcessVideoFrame will sometimes skip the rightmost pixels in each row of the output image, causing a portion of the image to be cut off. Other times it'll write extra pixels per row, causing a buffer overflow.
Reproduction
(This may only happen on some hardware. I'm running on an x64-based Windows 11 PC with an AMD Ryzen processor)
#include"raymedia.h"constchar*ExampleTitle="Example 01 - Basics";
constintScreenWidth=1920 / 2;
constintScreenHeight=1080 / 2;
constchar*MovieFile=ASSETS_PATH"examples/broken1.mp4"; // You may need to change this line depending on how you load assetsintmain(intargc, char**argv)
{
InitWindow(ScreenWidth, ScreenHeight, TextFormat("raylib-media | %s", ExampleTitle));
SetWindowState(FLAG_WINDOW_RESIZABLE);
SetTargetFPS(60);
InitAudioDevice();
MediaStreamvideoMedia=LoadMedia(MovieFile);
if (!IsMediaValid(videoMedia))
{
TraceLog(LOG_ERROR, "Failed to load media file: %s", MovieFile);
CloseAudioDevice();
CloseWindow();
return-1;
}
SetMediaLooping(videoMedia, true);
while (!WindowShouldClose())
{
UpdateMedia(&videoMedia);
BeginDrawing();
ClearBackground(DARKPURPLE);
floatscale=1.0f;
intdisplayWidth=videoMedia.videoTexture.width;
intdisplayHeight=videoMedia.videoTexture.height;
if (displayWidth>GetScreenWidth() ||displayHeight>GetScreenHeight()) {
floatscaleX= (float)GetScreenWidth() / displayWidth;
floatscaleY= (float)GetScreenHeight() / displayHeight;
scale= (scaleX<scaleY) ? scaleX : scaleY;
displayWidth= (int)(displayWidth*scale);
displayHeight= (int)(displayHeight*scale);
}
constintvideoPosX= (GetScreenWidth() -displayWidth) / 2;
constintvideoPosY= (GetScreenHeight() -displayHeight) / 2;
RectanglesourceRect= {0, 0, (float)videoMedia.videoTexture.width, (float)videoMedia.videoTexture.height};
RectangledestRect= {(float)videoPosX, (float)videoPosY, (float)displayWidth, (float)displayHeight};
Vector2origin= {0, 0};
DrawTexturePro(videoMedia.videoTexture, sourceRect, destRect, origin, 0, WHITE);
EndDrawing();
}
UnloadMedia(&videoMedia);
CloseAudioDevice();
CloseWindow();
return0;
}
Sample files
The video where rightmost pixels are skipped (1078x2316)
1078.mp4
The video that causes buffer overflow (1068x2316)
broken1.mp4
Example of skipping pixels per row (1078x2316; vertical black bar on the right of the video)
Example of buffer overflow (1068x2316)
overflow_with_broken1.mp4
This seems to happen because sws_scale expects the output buffer's stride/linesize per row of the image to be 16-byte aligned at a minimum (that number may be larger though on different hardware I think. I'm running on an x64-based Windows PC with an AMD Ryzen processor). I don't think FFmpeg clearly documents this anywhere, but it's mentioned here and there online:
With the 4.3 release, swscale now crashes if provided with an output buffer that is not 16 bytes aligned for yuv2rgb conversions. It used to work in previous releases *
The data shows how most files crash when (W * 3) % 48 != 0 (and for the few cases where that's not true, those are the cases where not all pixels are processed, causing the black vertical bar on the right of the video). I believe all of this has something to do with the assembly (at least on x86) writing in 48-byte chunks, and something to do with this code, but I didn't dig much deeper since it didn't feel necessary.
What
For certain video dimensions where the video is encoded in YUV format,
sws_scaleinAVProcessVideoFramewill sometimes skip the rightmost pixels in each row of the output image, causing a portion of the image to be cut off. Other times it'll write extra pixels per row, causing a buffer overflow.Reproduction
(This may only happen on some hardware. I'm running on an x64-based Windows 11 PC with an AMD Ryzen processor)
Sample files
The video where rightmost pixels are skipped (1078x2316)
1078.mp4
The video that causes buffer overflow (1068x2316)
broken1.mp4
Example of skipping pixels per row (1078x2316; vertical black bar on the right of the video)
Example of buffer overflow (1068x2316)
overflow_with_broken1.mp4
This seems to happen because
sws_scaleexpects the output buffer's stride/linesize per row of the image to be 16-byte aligned at a minimum (that number may be larger though on different hardware I think. I'm running on an x64-based Windows PC with an AMD Ryzen processor). I don't think FFmpeg clearly documents this anywhere, but it's mentioned here and there online:I also tested this experimentally: (Google Sheets link):
The data shows how most files crash when
(W * 3) % 48 != 0(and for the few cases where that's not true, those are the cases where not all pixels are processed, causing the black vertical bar on the right of the video). I believe all of this has something to do with the assembly (at least on x86) writing in 48-byte chunks, and something to do with this code, but I didn't dig much deeper since it didn't feel necessary.I opened a PR to fix these issues here: #11