Update to v103r19 release.

byuu says:

Changelog:

  - tomoko: Application::onMain assigned at end of Program::Program()
    [Screwtape]¹
  - libco: add `#define _XOPEN_SOURCE 500` to fix compilation of sjlj.c
    [Screwtape]
  - ruby/audio/openal: fixed device driver string list enumeration
  - ruby/audio/wasapi: changing device re-initializes the driver now
  - ruby/audio/wasapi: probably a pointless change, but don't fill the
    buffer beyond the queue size with silence
  - ruby/video/xvideo: renamed from ruby/video/xv
  - ruby/video/xvideo: check to see if `XV_AUTOPAINT_COLORKEY` exists
    before setting it [SuperMikeMan]
  - ruby/video/xvideo: align buffer sizes to be evenly divisible by four
    [SuperMikeMan]
  - ruby/video/xvideo: fail nicely without crashing (hopefully)
  - ruby/video/xvideo: add support for YV12 and I420 12-bit planar YUV
    formats²

¹: prevents crashes when drivers fail to initialize from running the
main loop that polls input drivers before the input driver is
initialized (or fails to initialize itself.) Some drivers still don't
block their main functions when initialization fails, so they will still
crash, but I'll work to fix them.

²: this was a **major** pain in the ass, heh. You only get one chroma
sample for every four luma samples, so the color reproduction is even
worse than UYVY and YUYV (which is two to four chroma to luma.) Further,
the planar format took forever to figure out. Apparently it doesn't care
what portion of the image you specify in XvShmPutImage, it expects you
to use the buffer dimensions to locate the U and V portions of the data.

This is probably the most thorough X-Video driver in existence now.

Notes:

  - forgot to rename the configuration settings dialog window title to
    just "Settings"
This commit is contained in:
Tim Allen 2017-07-23 19:18:16 +10:00
parent 284e4c043e
commit 8be474b0ac
9 changed files with 184 additions and 107 deletions

View File

@ -12,7 +12,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; static const string Name = "higan";
static const string Version = "103.18"; static const string Version = "103.19";
static const string Author = "byuu"; static const string Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "http://byuu.org/"; static const string Website = "http://byuu.org/";

View File

@ -26,11 +26,11 @@ else ifeq ($(platform),macosx)
ruby += audio.openal ruby += audio.openal
ruby += #input.quartz input.carbon ruby += #input.quartz input.carbon
else ifeq ($(platform),linux) else ifeq ($(platform),linux)
ruby += video.glx2 video.xv video.xshm video.sdl #video.glx ruby += video.glx2 video.xvideo video.xshm video.sdl #video.glx
ruby += audio.oss audio.openal #audio.alsa audio.pulseaudio audio.pulseaudiosimple audio.ao ruby += audio.oss audio.openal #audio.alsa audio.pulseaudio audio.pulseaudiosimple audio.ao
ruby += input.sdl input.xlib #input.udev ruby += input.sdl input.xlib #input.udev
else ifeq ($(platform),bsd) else ifeq ($(platform),bsd)
ruby += video.glx2 video.xv video.xshm video.sdl #video.glx ruby += video.glx2 video.xvideo video.xshm video.sdl #video.glx
ruby += audio.oss audio.openal ruby += audio.oss audio.openal
ruby += input.sdl input.xlib ruby += input.sdl input.xlib
endif endif

View File

@ -15,7 +15,6 @@ unique_pointer<Program> program;
Program::Program(string_vector args) { Program::Program(string_vector args) {
program = this; program = this;
Application::onMain({&Program::main, this});
Emulator::platform = this; Emulator::platform = this;
emulators.append(new Famicom::Interface); emulators.append(new Famicom::Interface);
@ -77,6 +76,8 @@ Program::Program(string_vector args) {
} }
} }
loadMedium(); loadMedium();
Application::onMain({&Program::main, this});
} }
auto Program::main() -> void { auto Program::main() -> void {

View File

@ -12,6 +12,7 @@
#define LIBCO_C #define LIBCO_C
#include "libco.h" #include "libco.h"
#define _XOPEN_SOURCE 500
#include <stdlib.h> #include <stdlib.h>
#include <signal.h> #include <signal.h>
#include <setjmp.h> #include <setjmp.h>

View File

@ -14,7 +14,7 @@ rubylink += $(if $(findstring video.direct3d,$(ruby)),-ld3d9)
rubylink += $(if $(findstring video.directdraw,$(ruby)),-lddraw) rubylink += $(if $(findstring video.directdraw,$(ruby)),-lddraw)
rubylink += $(if $(findstring video.glx,$(ruby)),-lGL) rubylink += $(if $(findstring video.glx,$(ruby)),-lGL)
rubylink += $(if $(findstring video.wgl,$(ruby)),-lopengl32) rubylink += $(if $(findstring video.wgl,$(ruby)),-lopengl32)
rubylink += $(if $(findstring video.xv,$(ruby)),-lXv) rubylink += $(if $(findstring video.xvideo,$(ruby)),-lXv)
rubylink += $(if $(findstring audio.alsa,$(ruby)),-lasound) rubylink += $(if $(findstring audio.alsa,$(ruby)),-lasound)
rubylink += $(if $(findstring audio.ao,$(ruby)),-lao) rubylink += $(if $(findstring audio.ao,$(ruby)),-lao)

View File

@ -161,9 +161,9 @@ private:
const char* list = alcGetString(nullptr, ALC_DEVICE_SPECIFIER); const char* list = alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
if(!list) return result; if(!list) return result;
while(list[0] || list[1]) { while(list && *list) {
result.append(list); result.append(list);
while(list[0]) list++; list += strlen(list) + 1;
} }
return result; return result;

View File

@ -37,7 +37,7 @@ struct AudioWASAPI : Audio {
auto setDevice(string device) -> bool { auto setDevice(string device) -> bool {
if(_device == device) return true; if(_device == device) return true;
_device = device; _device = device;
return true; return initialize();
} }
auto setBlocking(bool blocking) -> bool { auto setBlocking(bool blocking) -> bool {
@ -177,12 +177,12 @@ private:
_audioClient->GetCurrentPadding(&padding); _audioClient->GetCurrentPadding(&padding);
available = _bufferSize - padding; available = _bufferSize - padding;
} }
uint32_t length = min(available, _queue.count);
uint8_t* buffer = nullptr; uint8_t* buffer = nullptr;
if(_renderClient->GetBuffer(available, &buffer) == S_OK) { if(_renderClient->GetBuffer(length, &buffer) == S_OK) {
uint bufferFlags = 0; uint bufferFlags = 0;
for(uint _ : range(available)) { for(uint _ : range(length)) {
//if more samples are available than we have queued, fill remainder with silence
double samples[8] = {}; double samples[8] = {};
if(_queue.count) { if(_queue.count) {
for(uint n : range(_channels)) { for(uint n : range(_channels)) {
@ -210,7 +210,7 @@ private:
break; break;
} }
} }
_renderClient->ReleaseBuffer(available, bufferFlags); _renderClient->ReleaseBuffer(length, bufferFlags);
} }
} }

View File

@ -66,8 +66,8 @@ using namespace ruby;
#include <ruby/video/xshm.cpp> #include <ruby/video/xshm.cpp>
#endif #endif
#if defined(VIDEO_XV) #if defined(VIDEO_XVIDEO)
#include <ruby/video/xv.cpp> #include <ruby/video/xvideo.cpp>
#endif #endif
namespace ruby { namespace ruby {
@ -111,8 +111,8 @@ auto Video::create(const string& driver) -> Video* {
if(driver == "XShm") return new VideoXShm; if(driver == "XShm") return new VideoXShm;
#endif #endif
#if defined(VIDEO_XV) #if defined(VIDEO_XVIDEO)
if(driver == "X-Video") return new VideoXv; if(driver == "XVideo") return new VideoXVideo;
#endif #endif
return new Video; return new Video;
@ -133,8 +133,8 @@ auto Video::optimalDriver() -> string {
return "OpenGL"; return "OpenGL";
#elif defined(VIDEO_GLX2) #elif defined(VIDEO_GLX2)
return "OpenGL2"; return "OpenGL2";
#elif defined(VIDEO_XV) #elif defined(VIDEO_XVIDEO)
return "X-Video"; return "XVideo";
#elif defined(VIDEO_XSHM) #elif defined(VIDEO_XSHM)
return "XShm"; return "XShm";
#elif defined(VIDEO_SDL) #elif defined(VIDEO_SDL)
@ -159,8 +159,8 @@ auto Video::safestDriver() -> string {
return "XShm"; return "XShm";
#elif defined(VIDEO_SDL) #elif defined(VIDEO_SDL)
return "SDL"; return "SDL";
#elif defined(VIDEO_XV) #elif defined(VIDEO_XVIDEO)
return "X-Video"; return "XVideo";
#elif defined(VIDEO_GLX2) #elif defined(VIDEO_GLX2)
return "OpenGL2"; return "OpenGL2";
#elif defined(VIDEO_GLX) #elif defined(VIDEO_GLX)
@ -201,8 +201,8 @@ auto Video::availableDrivers() -> string_vector {
"OpenGL2", "OpenGL2",
#endif #endif
#if defined(VIDEO_XV) #if defined(VIDEO_XVIDEO)
"X-Video", "XVideo",
#endif #endif
#if defined(VIDEO_XSHM) #if defined(VIDEO_XSHM)

View File

@ -6,9 +6,9 @@
extern "C" auto XvShmCreateImage(Display*, XvPortID, int, char*, int, int, XShmSegmentInfo*) -> XvImage*; extern "C" auto XvShmCreateImage(Display*, XvPortID, int, char*, int, int, XShmSegmentInfo*) -> XvImage*;
struct VideoXv : Video { struct VideoXVideo : Video {
VideoXv() { initialize(); } VideoXVideo() { initialize(); }
~VideoXv() { terminate(); } ~VideoXVideo() { terminate(); }
auto ready() -> bool { return _ready; } auto ready() -> bool { return _ready; }
@ -44,6 +44,8 @@ struct VideoXv : Video {
} }
auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool { auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool {
if(!_ready) return false;
if(width != _width || height != _height) { if(width != _width || height != _height) {
resize(_width = width, _height = height); resize(_width = width, _height = height);
} }
@ -56,8 +58,7 @@ struct VideoXv : Video {
} }
auto output() -> void { auto output() -> void {
uint width = _width; if(!_ready) return;
uint height = _height;
XWindowAttributes target; XWindowAttributes target;
XGetWindowAttributes(_display, _window, &target); XGetWindowAttributes(_display, _window, &target);
@ -76,16 +77,18 @@ struct VideoXv : Video {
XGetWindowAttributes(_display, _window, &target); XGetWindowAttributes(_display, _window, &target);
switch(_format) { switch(_format) {
case XvFormatRGB32: renderRGB32(width, height); break; case XvFormatRGB32: renderRGB32(_width, _height); break;
case XvFormatRGB24: renderRGB24(width, height); break; case XvFormatRGB24: renderRGB24(_width, _height); break;
case XvFormatRGB16: renderRGB16(width, height); break; case XvFormatRGB16: renderRGB16(_width, _height); break;
case XvFormatRGB15: renderRGB15(width, height); break; case XvFormatRGB15: renderRGB15(_width, _height); break;
case XvFormatYUY2: renderYUY2 (width, height); break; case XvFormatUYVY: renderUYVY (_width, _height); break;
case XvFormatUYVY: renderUYVY (width, height); break; case XvFormatYUY2: renderYUY2 (_width, _height); break;
case XvFormatYV12: renderYV12 (_width, _height); break;
case XvFormatI420: renderI420 (_width, _height); break;
} }
XvShmPutImage(_display, _port, _window, _gc, _image, XvShmPutImage(_display, _port, _window, _gc, _image,
0, 0, width, height, 0, 0, _width, _height,
0, 0, target.width, target.height, 0, 0, target.width, target.height,
true); true);
} }
@ -157,9 +160,16 @@ struct VideoXv : Video {
_gc = XCreateGC(_display, _window, 0, 0); _gc = XCreateGC(_display, _window, 0, 0);
//set colorkey to auto paint, so that Xv video output is always visible int attributeCount = 0;
Atom atom = XInternAtom(_display, "XV_AUTOPAINT_COLORKEY", true); XvAttribute* attributeList = XvQueryPortAttributes(_display, _port, &attributeCount);
if(atom != None) XvSetPortAttribute(_display, _port, atom, 1); for(auto n : range(attributeCount)) {
if(string{attributeList[n].name} == "XV_AUTOPAINT_COLORKEY") {
//set colorkey to auto paint, so that Xv video output is always visible
Atom atom = XInternAtom(_display, "XV_AUTOPAINT_COLORKEY", true);
if(atom != None) XvSetPortAttribute(_display, _port, atom, 1);
}
}
XFree(attributeList);
//find optimal rendering format //find optimal rendering format
_format = XvFormatUnknown; _format = XvFormatUnknown;
@ -198,6 +208,18 @@ struct VideoXv : Video {
} }
} }
if(_format == XvFormatUnknown) for(auto n : range(formatCount)) {
if(format[n].type == XvYUV && format[n].bits_per_pixel == 16 && format[n].format == XvPacked) {
if(format[n].component_order[0] == 'U' && format[n].component_order[1] == 'Y'
&& format[n].component_order[2] == 'V' && format[n].component_order[3] == 'Y'
) {
_format = XvFormatUYVY;
_fourCC = format[n].id;
break;
}
}
}
if(_format == XvFormatUnknown) for(auto n : range(formatCount)) { if(_format == XvFormatUnknown) for(auto n : range(formatCount)) {
if(format[n].type == XvYUV && format[n].bits_per_pixel == 16 && format[n].format == XvPacked) { if(format[n].type == XvYUV && format[n].bits_per_pixel == 16 && format[n].format == XvPacked) {
if(format[n].component_order[0] == 'Y' && format[n].component_order[1] == 'U' if(format[n].component_order[0] == 'Y' && format[n].component_order[1] == 'U'
@ -211,11 +233,23 @@ struct VideoXv : Video {
} }
if(_format == XvFormatUnknown) for(auto n : range(formatCount)) { if(_format == XvFormatUnknown) for(auto n : range(formatCount)) {
if(format[n].type == XvYUV && format[n].bits_per_pixel == 16 && format[n].format == XvPacked) { if(format[n].type == XvYUV && format[n].bits_per_pixel == 12 && format[n].format == XvPlanar) {
if(format[n].component_order[0] == 'U' && format[n].component_order[1] == 'Y' if(format[n].component_order[0] == 'Y' && format[n].component_order[1] == 'V'
&& format[n].component_order[2] == 'V' && format[n].component_order[3] == 'Y' && format[n].component_order[2] == 'U' && format[n].component_order[3] == '\x00'
) { ) {
_format = XvFormatUYVY; _format = XvFormatYV12;
_fourCC = format[n].id;
break;
}
}
}
if(_format == XvFormatUnknown) for(auto n : range(formatCount)) {
if(format[n].type == XvYUV && format[n].bits_per_pixel == 12 && format[n].format == XvPlanar) {
if(format[n].component_order[0] == 'Y' && format[n].component_order[1] == 'U'
&& format[n].component_order[2] == 'V' && format[n].component_order[3] == '\x00'
) {
_format = XvFormatI420;
_fourCC = format[n].id; _fourCC = format[n].id;
break; break;
} }
@ -228,29 +262,11 @@ struct VideoXv : Video {
return false; return false;
} }
_bufferWidth = 256; _ready = true;
_bufferHeight = 256;
_image = XvShmCreateImage(_display, _port, _fourCC, 0, _bufferWidth, _bufferHeight, &_shmInfo);
if(!_image) {
print("VideoXv: XShmCreateImage failed.\n");
return false;
}
_shmInfo.shmid = shmget(IPC_PRIVATE, _image->data_size, IPC_CREAT | 0777);
_shmInfo.shmaddr = _image->data = (char*)shmat(_shmInfo.shmid, 0, 0);
_shmInfo.readOnly = false;
if(!XShmAttach(_display, &_shmInfo)) {
print("VideoXv: XShmAttach failed.\n");
return false;
}
_buffer = new uint32_t[_bufferWidth * _bufferHeight];
_width = 256;
_height = 256;
initializeTables(); initializeTables();
resize(_width = 256, _height = 256);
clear(); clear();
return _ready = true; return true;
} }
auto terminate() -> void { auto terminate() -> void {
@ -279,7 +295,7 @@ struct VideoXv : Video {
_display = nullptr; _display = nullptr;
} }
delete[] _buffer, _buffer = nullptr; delete[] _buffer, _buffer = nullptr, _bufferWidth = 0, _bufferHeight = 0;
delete[] _ytable, _ytable = nullptr; delete[] _ytable, _ytable = nullptr;
delete[] _utable, _utable = nullptr; delete[] _utable, _utable = nullptr;
delete[] _vtable, _vtable = nullptr; delete[] _vtable, _vtable = nullptr;
@ -290,10 +306,19 @@ struct VideoXv : Video {
_bufferWidth = max(width, _bufferWidth); _bufferWidth = max(width, _bufferWidth);
_bufferHeight = max(height, _bufferHeight); _bufferHeight = max(height, _bufferHeight);
XShmDetach(_display, &_shmInfo); //must round to be evenly divisible by 4
shmdt(_shmInfo.shmaddr); if(uint round = _bufferWidth & 3) _bufferWidth += 4 - round;
shmctl(_shmInfo.shmid, IPC_RMID, nullptr); if(uint round = _bufferHeight & 3) _bufferHeight += 4 - round;
XFree(_image);
_bufferWidth = bit::round(_bufferWidth);
_bufferHeight = bit::round(_bufferHeight);
if(_image) {
XShmDetach(_display, &_shmInfo);
shmdt(_shmInfo.shmaddr);
shmctl(_shmInfo.shmid, IPC_RMID, nullptr);
XFree(_image);
}
_image = XvShmCreateImage(_display, _port, _fourCC, 0, _bufferWidth, _bufferHeight, &_shmInfo); _image = XvShmCreateImage(_display, _port, _fourCC, 0, _bufferWidth, _bufferHeight, &_shmInfo);
@ -324,8 +349,8 @@ struct VideoXv : Video {
for(uint y : range(height)) { for(uint y : range(height)) {
for(uint x : range(width)) { for(uint x : range(width)) {
uint32_t p = *input++; uint32_t p = *input++;
*output++ = p; *output++ = p >> 0;
*output++ = p >> 8; *output++ = p >> 8;
*output++ = p >> 16; *output++ = p >> 16;
} }
@ -340,8 +365,8 @@ struct VideoXv : Video {
for(uint y : range(height)) { for(uint y : range(height)) {
for(uint x : range(width)) { for(uint x : range(width)) {
uint32_t p = *input++; uint32_t p = toRGB16(*input++);
*output++ = ((p >> 8) & 0xf800) | ((p >> 5) & 0x07e0) | ((p >> 3) & 0x001f); //RGB32->RGB16 *output++ = p;
} }
input += _bufferWidth - width; input += _bufferWidth - width;
@ -355,31 +380,8 @@ struct VideoXv : Video {
for(uint y : range(height)) { for(uint y : range(height)) {
for(uint x : range(width)) { for(uint x : range(width)) {
uint32_t p = *input++; uint32_t p = toRGB15(*input++);
*output++ = ((p >> 9) & 0x7c00) | ((p >> 6) & 0x03e0) | ((p >> 3) & 0x001f); //RGB32->RGB15 *output++ = p;
}
input += _bufferWidth - width;
output += _bufferWidth - width;
}
}
auto renderYUY2(uint width, uint height) -> void {
uint32_t* input = (uint32_t*)_buffer;
uint16_t* output = (uint16_t*)_image->data;
for(uint y : range(height)) {
for(uint x : range(width >> 1)) {
uint32_t p0 = *input++;
uint32_t p1 = *input++;
p0 = ((p0 >> 8) & 0xf800) + ((p0 >> 5) & 0x07e0) + ((p0 >> 3) & 0x001f); //RGB32->RGB16
p1 = ((p1 >> 8) & 0xf800) + ((p1 >> 5) & 0x07e0) + ((p1 >> 3) & 0x001f); //RGB32->RGB16
uint8_t u = (_utable[p0] + _utable[p1]) >> 1;
uint8_t v = (_vtable[p0] + _vtable[p1]) >> 1;
*output++ = (u << 8) | _ytable[p0];
*output++ = (v << 8) | _ytable[p1];
} }
input += _bufferWidth - width; input += _bufferWidth - width;
@ -388,21 +390,16 @@ struct VideoXv : Video {
} }
auto renderUYVY(uint width, uint height) -> void { auto renderUYVY(uint width, uint height) -> void {
uint32_t* input = (uint32_t*)_buffer; const uint32_t* input = (const uint32_t*)_buffer;
uint16_t* output = (uint16_t*)_image->data; uint16_t* output = (uint16_t*)_image->data;
for(uint y : range(height)) { for(uint y : range(height)) {
for(uint x : range(width >> 1)) { for(uint x : range(width >> 1)) {
uint32_t p0 = *input++; uint32_t p0 = toRGB16(*input++);
uint32_t p1 = *input++; uint32_t p1 = toRGB16(*input++);
p0 = ((p0 >> 8) & 0xf800) + ((p0 >> 5) & 0x07e0) + ((p0 >> 3) & 0x001f);
p1 = ((p1 >> 8) & 0xf800) + ((p1 >> 5) & 0x07e0) + ((p1 >> 3) & 0x001f);
uint8_t u = (_utable[p0] + _utable[p1]) >> 1; *output++ = _ytable[p0] << 8 | ((_utable[p0] + _utable[p1]) >> 1) << 0;
uint8_t v = (_vtable[p0] + _vtable[p1]) >> 1; *output++ = _ytable[p1] << 8 | ((_vtable[p0] + _vtable[p1]) >> 1) << 0;
*output++ = (_ytable[p0] << 8) | u;
*output++ = (_ytable[p1] << 8) | v;
} }
input += _bufferWidth - width; input += _bufferWidth - width;
@ -410,6 +407,82 @@ struct VideoXv : Video {
} }
} }
auto renderYUY2(uint width, uint height) -> void {
const uint32_t* input = (const uint32_t*)_buffer;
uint16_t* output = (uint16_t*)_image->data;
for(uint y : range(height)) {
for(uint x : range(width >> 1)) {
uint32_t p0 = toRGB16(*input++);
uint32_t p1 = toRGB16(*input++);
*output++ = ((_utable[p0] + _utable[p1]) >> 1) << 8 | _ytable[p0] << 0;
*output++ = ((_vtable[p0] + _vtable[p1]) >> 1) << 8 | _ytable[p1] << 0;
}
input += _bufferWidth - width;
output += _bufferWidth - width;
}
}
auto renderYV12(uint width, uint height) -> void {
const uint w = _bufferWidth, h = _bufferHeight;
for(uint y : range(height >> 1)) {
const uint32_t* input0 = (const uint32_t*)_buffer + (2 * y * w);
const uint32_t* input1 = input0 + w;
uint16_t* youtput0 = (uint16_t*)_image->data + ((2 * y * w) >> 1);
uint16_t* youtput1 = youtput0 + (w >> 1);
uint8_t* voutput = (uint8_t*)_image->data + (w * h) + ((2 * y * w) >> 2);
uint8_t* uoutput = (uint8_t*)_image->data + (w * h) + ((w * h) >> 2) + ((2 * y * w) >> 2);
for(uint x : range(width >> 1)) {
uint16_t p0 = toRGB16(*input0++);
uint16_t p1 = toRGB16(*input0++);
uint16_t p2 = toRGB16(*input1++);
uint16_t p3 = toRGB16(*input1++);
*youtput0++ = _ytable[p0] << 0 | _ytable[p1] << 8;
*youtput1++ = _ytable[p2] << 0 | _ytable[p3] << 8;
*voutput++ = (_vtable[p0] + _vtable[p1] + _vtable[p2] + _vtable[p3]) >> 2;
*uoutput++ = (_utable[p0] + _utable[p1] + _utable[p2] + _utable[p3]) >> 2;
}
}
}
auto renderI420(uint width, uint height) -> void {
const uint w = _bufferWidth, h = _bufferHeight;
for(uint y : range(height >> 1)) {
const uint32_t* input0 = (const uint32_t*)_buffer + (2 * y * w);
const uint32_t* input1 = input0 + w;
uint16_t* youtput0 = (uint16_t*)_image->data + ((2 * y * w) >> 1);
uint16_t* youtput1 = youtput0 + (w >> 1);
uint8_t* uoutput = (uint8_t*)_image->data + (w * h) + ((2 * y * w) >> 2);
uint8_t* voutput = (uint8_t*)_image->data + (w * h) + ((w * h) >> 2) + ((2 * y * w) >> 2);
for(uint x : range(width >> 1)) {
uint16_t p0 = toRGB16(*input0++);
uint16_t p1 = toRGB16(*input0++);
uint16_t p2 = toRGB16(*input1++);
uint16_t p3 = toRGB16(*input1++);
*youtput0++ = _ytable[p0] << 0 | _ytable[p1] << 8;
*youtput1++ = _ytable[p2] << 0 | _ytable[p3] << 8;
*uoutput++ = (_utable[p0] + _utable[p1] + _utable[p2] + _utable[p3]) >> 2;
*voutput++ = (_vtable[p0] + _vtable[p1] + _vtable[p2] + _vtable[p3]) >> 2;
}
}
}
inline auto toRGB15(uint32_t rgb32) const -> uint16_t {
return ((rgb32 >> 9) & 0x7c00) + ((rgb32 >> 6) & 0x03e0) + ((rgb32 >> 3) & 0x001f);
}
inline auto toRGB16(uint32_t rgb32) const -> uint16_t {
return ((rgb32 >> 8) & 0xf800) + ((rgb32 >> 5) & 0x07e0) + ((rgb32 >> 3) & 0x001f);
}
auto initializeTables() -> void { auto initializeTables() -> void {
_ytable = new uint8_t[65536]; _ytable = new uint8_t[65536];
_utable = new uint8_t[65536]; _utable = new uint8_t[65536];
@ -460,8 +533,10 @@ struct VideoXv : Video {
XvFormatRGB24, XvFormatRGB24,
XvFormatRGB16, XvFormatRGB16,
XvFormatRGB15, XvFormatRGB15,
XvFormatYUY2,
XvFormatUYVY, XvFormatUYVY,
XvFormatYUY2,
XvFormatYV12,
XvFormatI420,
XvFormatUnknown, XvFormatUnknown,
}; };