custom YUY2 -> IYUV conversion code
improves from 1+60ms to 3ms
This commit is contained in:
parent
b4373e0d9a
commit
a622b6aa3f
@ -45,6 +45,61 @@ static bool isFormatPlanar(SDL_PixelFormat f) {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SDL_Surface* convertYUY2_IYUV(SDL_Surface* surf) {
|
||||||
|
if (surf->format != SDL_PIXELFORMAT_YUY2) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if ((surf->w % 2) != 0) {
|
||||||
|
// hmmm, we dont handle odd widths
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_LockSurface(surf);
|
||||||
|
|
||||||
|
SDL_Surface* conv_surf = SDL_CreateSurface(surf->w, surf->h, SDL_PIXELFORMAT_IYUV);
|
||||||
|
SDL_LockSurface(conv_surf);
|
||||||
|
|
||||||
|
// YUY2 is 4:2:2 packed
|
||||||
|
// Y is simple, we just copy it over
|
||||||
|
// U V are double the resolution (vertically), so we avg both
|
||||||
|
// Packed mode: Y0+U0+Y1+V0 (1 plane)
|
||||||
|
|
||||||
|
uint8_t* y_plane = static_cast<uint8_t*>(conv_surf->pixels);
|
||||||
|
uint8_t* u_plane = static_cast<uint8_t*>(conv_surf->pixels) + conv_surf->w*conv_surf->h;
|
||||||
|
uint8_t* v_plane = static_cast<uint8_t*>(conv_surf->pixels) + conv_surf->w*conv_surf->h + (conv_surf->w/2)*(conv_surf->h/2);
|
||||||
|
|
||||||
|
const uint8_t* yuy2_data = static_cast<const uint8_t*>(surf->pixels);
|
||||||
|
|
||||||
|
for (int y = 0; y < surf->h; y++) {
|
||||||
|
for (int x = 0; x < surf->w; x += 2) {
|
||||||
|
// every pixel uses 2 bytes
|
||||||
|
const uint8_t* yuy2_curser = yuy2_data + y*surf->w*2 + x*2;
|
||||||
|
uint8_t src_y0 = yuy2_curser[0];
|
||||||
|
uint8_t src_u = yuy2_curser[1];
|
||||||
|
uint8_t src_y1 = yuy2_curser[2];
|
||||||
|
uint8_t src_v = yuy2_curser[3];
|
||||||
|
|
||||||
|
y_plane[y*conv_surf->w + x] = src_y0;
|
||||||
|
y_plane[y*conv_surf->w + x+1] = src_y1;
|
||||||
|
|
||||||
|
size_t uv_index = (y/2) * (conv_surf->w/2) + x/2;
|
||||||
|
if (y % 2 == 0) {
|
||||||
|
// first write
|
||||||
|
u_plane[uv_index] = src_u;
|
||||||
|
v_plane[uv_index] = src_v;
|
||||||
|
} else {
|
||||||
|
// second write, mix with existing value
|
||||||
|
u_plane[uv_index] = (int(u_plane[uv_index]) + int(src_u)) / 2;
|
||||||
|
v_plane[uv_index] = (int(v_plane[uv_index]) + int(src_v)) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_UnlockSurface(conv_surf);
|
||||||
|
SDL_UnlockSurface(surf);
|
||||||
|
return conv_surf;
|
||||||
|
}
|
||||||
|
|
||||||
struct PushConversionQueuedVideoStream : public QueuedFrameStream2<SDLVideoFrame> {
|
struct PushConversionQueuedVideoStream : public QueuedFrameStream2<SDLVideoFrame> {
|
||||||
SDL_PixelFormat _forced_format {SDL_PIXELFORMAT_IYUV};
|
SDL_PixelFormat _forced_format {SDL_PIXELFORMAT_IYUV};
|
||||||
|
|
||||||
@ -55,19 +110,29 @@ struct PushConversionQueuedVideoStream : public QueuedFrameStream2<SDLVideoFrame
|
|||||||
SDL_Surface* converted_surf = value.surface.get();
|
SDL_Surface* converted_surf = value.surface.get();
|
||||||
if (converted_surf->format != SDL_PIXELFORMAT_IYUV) {
|
if (converted_surf->format != SDL_PIXELFORMAT_IYUV) {
|
||||||
//std::cerr << "DTC: need to convert from " << SDL_GetPixelFormatName(converted_surf->format) << " to SDL_PIXELFORMAT_IYUV\n";
|
//std::cerr << "DTC: need to convert from " << SDL_GetPixelFormatName(converted_surf->format) << " to SDL_PIXELFORMAT_IYUV\n";
|
||||||
if (isFormatPlanar(converted_surf->format)) {
|
if (converted_surf->format == SDL_PIXELFORMAT_YUY2) {
|
||||||
|
// optimized custom impl
|
||||||
|
|
||||||
|
//auto start = Message::getTimeMS();
|
||||||
|
converted_surf = convertYUY2_IYUV(converted_surf);
|
||||||
|
//auto end = Message::getTimeMS();
|
||||||
|
// 3ms
|
||||||
|
//std::cerr << "DTC: timing " << SDL_GetPixelFormatName(converted_surf->format) << "->SDL_PIXELFORMAT_IYUV: " << end-start << "ms\n";
|
||||||
|
} else if (isFormatPlanar(converted_surf->format)) {
|
||||||
// meh, need to convert to rgb as a stopgap
|
// meh, need to convert to rgb as a stopgap
|
||||||
|
|
||||||
//auto start = Message::getTimeMS();
|
//auto start = Message::getTimeMS();
|
||||||
//SDL_Surface* tmp_conv_surf = SDL_ConvertSurfaceAndColorspace(converted_surf, SDL_PIXELFORMAT_RGBA32, nullptr, SDL_COLORSPACE_RGB_DEFAULT, 0);
|
//SDL_Surface* tmp_conv_surf = SDL_ConvertSurfaceAndColorspace(converted_surf, SDL_PIXELFORMAT_RGBA32, nullptr, SDL_COLORSPACE_RGB_DEFAULT, 0);
|
||||||
SDL_Surface* tmp_conv_surf = SDL_ConvertSurfaceAndColorspace(converted_surf, SDL_PIXELFORMAT_RGB24, nullptr, SDL_COLORSPACE_RGB_DEFAULT, 0);
|
SDL_Surface* tmp_conv_surf = SDL_ConvertSurfaceAndColorspace(converted_surf, SDL_PIXELFORMAT_RGB24, nullptr, SDL_COLORSPACE_RGB_DEFAULT, 0);
|
||||||
//auto end = Message::getTimeMS();
|
//auto end = Message::getTimeMS();
|
||||||
|
// 1ms
|
||||||
//std::cerr << "DTC: timing " << SDL_GetPixelFormatName(converted_surf->format) << "->SDL_PIXELFORMAT_RGB24: " << end-start << "ms\n";
|
//std::cerr << "DTC: timing " << SDL_GetPixelFormatName(converted_surf->format) << "->SDL_PIXELFORMAT_RGB24: " << end-start << "ms\n";
|
||||||
|
|
||||||
// TODO: fix sdl rgb->yuv conversion resulting in too dark (colorspace) issues
|
// TODO: fix sdl rgb->yuv conversion resulting in too dark (colorspace) issues
|
||||||
//start = Message::getTimeMS();
|
//start = Message::getTimeMS();
|
||||||
converted_surf = SDL_ConvertSurfaceAndColorspace(tmp_conv_surf, SDL_PIXELFORMAT_IYUV, nullptr, SDL_COLORSPACE_YUV_DEFAULT, 0);
|
converted_surf = SDL_ConvertSurfaceAndColorspace(tmp_conv_surf, SDL_PIXELFORMAT_IYUV, nullptr, SDL_COLORSPACE_YUV_DEFAULT, 0);
|
||||||
//end = Message::getTimeMS();
|
//end = Message::getTimeMS();
|
||||||
|
// 60ms
|
||||||
//std::cerr << "DTC: timing SDL_PIXELFORMAT_RGB24->SDL_PIXELFORMAT_IYUV: " << end-start << "ms\n";
|
//std::cerr << "DTC: timing SDL_PIXELFORMAT_RGB24->SDL_PIXELFORMAT_IYUV: " << end-start << "ms\n";
|
||||||
|
|
||||||
SDL_DestroySurface(tmp_conv_surf);
|
SDL_DestroySurface(tmp_conv_surf);
|
||||||
|
Loading…
Reference in New Issue
Block a user