mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
284e4c043e
commit
8be474b0ac
|
@ -12,7 +12,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
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 License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -26,11 +26,11 @@ else ifeq ($(platform),macosx)
|
|||
ruby += audio.openal
|
||||
ruby += #input.quartz input.carbon
|
||||
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 += input.sdl input.xlib #input.udev
|
||||
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 += input.sdl input.xlib
|
||||
endif
|
||||
|
|
|
@ -15,7 +15,6 @@ unique_pointer<Program> program;
|
|||
|
||||
Program::Program(string_vector args) {
|
||||
program = this;
|
||||
Application::onMain({&Program::main, this});
|
||||
|
||||
Emulator::platform = this;
|
||||
emulators.append(new Famicom::Interface);
|
||||
|
@ -77,6 +76,8 @@ Program::Program(string_vector args) {
|
|||
}
|
||||
}
|
||||
loadMedium();
|
||||
|
||||
Application::onMain({&Program::main, this});
|
||||
}
|
||||
|
||||
auto Program::main() -> void {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#define LIBCO_C
|
||||
#include "libco.h"
|
||||
|
||||
#define _XOPEN_SOURCE 500
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
|
|
|
@ -14,7 +14,7 @@ rubylink += $(if $(findstring video.direct3d,$(ruby)),-ld3d9)
|
|||
rubylink += $(if $(findstring video.directdraw,$(ruby)),-lddraw)
|
||||
rubylink += $(if $(findstring video.glx,$(ruby)),-lGL)
|
||||
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.ao,$(ruby)),-lao)
|
||||
|
|
|
@ -161,9 +161,9 @@ private:
|
|||
const char* list = alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
|
||||
if(!list) return result;
|
||||
|
||||
while(list[0] || list[1]) {
|
||||
while(list && *list) {
|
||||
result.append(list);
|
||||
while(list[0]) list++;
|
||||
list += strlen(list) + 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -37,7 +37,7 @@ struct AudioWASAPI : Audio {
|
|||
auto setDevice(string device) -> bool {
|
||||
if(_device == device) return true;
|
||||
_device = device;
|
||||
return true;
|
||||
return initialize();
|
||||
}
|
||||
|
||||
auto setBlocking(bool blocking) -> bool {
|
||||
|
@ -177,12 +177,12 @@ private:
|
|||
_audioClient->GetCurrentPadding(&padding);
|
||||
available = _bufferSize - padding;
|
||||
}
|
||||
uint32_t length = min(available, _queue.count);
|
||||
|
||||
uint8_t* buffer = nullptr;
|
||||
if(_renderClient->GetBuffer(available, &buffer) == S_OK) {
|
||||
if(_renderClient->GetBuffer(length, &buffer) == S_OK) {
|
||||
uint bufferFlags = 0;
|
||||
for(uint _ : range(available)) {
|
||||
//if more samples are available than we have queued, fill remainder with silence
|
||||
for(uint _ : range(length)) {
|
||||
double samples[8] = {};
|
||||
if(_queue.count) {
|
||||
for(uint n : range(_channels)) {
|
||||
|
@ -210,7 +210,7 @@ private:
|
|||
break;
|
||||
}
|
||||
}
|
||||
_renderClient->ReleaseBuffer(available, bufferFlags);
|
||||
_renderClient->ReleaseBuffer(length, bufferFlags);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,8 +66,8 @@ using namespace ruby;
|
|||
#include <ruby/video/xshm.cpp>
|
||||
#endif
|
||||
|
||||
#if defined(VIDEO_XV)
|
||||
#include <ruby/video/xv.cpp>
|
||||
#if defined(VIDEO_XVIDEO)
|
||||
#include <ruby/video/xvideo.cpp>
|
||||
#endif
|
||||
|
||||
namespace ruby {
|
||||
|
@ -111,8 +111,8 @@ auto Video::create(const string& driver) -> Video* {
|
|||
if(driver == "XShm") return new VideoXShm;
|
||||
#endif
|
||||
|
||||
#if defined(VIDEO_XV)
|
||||
if(driver == "X-Video") return new VideoXv;
|
||||
#if defined(VIDEO_XVIDEO)
|
||||
if(driver == "XVideo") return new VideoXVideo;
|
||||
#endif
|
||||
|
||||
return new Video;
|
||||
|
@ -133,8 +133,8 @@ auto Video::optimalDriver() -> string {
|
|||
return "OpenGL";
|
||||
#elif defined(VIDEO_GLX2)
|
||||
return "OpenGL2";
|
||||
#elif defined(VIDEO_XV)
|
||||
return "X-Video";
|
||||
#elif defined(VIDEO_XVIDEO)
|
||||
return "XVideo";
|
||||
#elif defined(VIDEO_XSHM)
|
||||
return "XShm";
|
||||
#elif defined(VIDEO_SDL)
|
||||
|
@ -159,8 +159,8 @@ auto Video::safestDriver() -> string {
|
|||
return "XShm";
|
||||
#elif defined(VIDEO_SDL)
|
||||
return "SDL";
|
||||
#elif defined(VIDEO_XV)
|
||||
return "X-Video";
|
||||
#elif defined(VIDEO_XVIDEO)
|
||||
return "XVideo";
|
||||
#elif defined(VIDEO_GLX2)
|
||||
return "OpenGL2";
|
||||
#elif defined(VIDEO_GLX)
|
||||
|
@ -201,8 +201,8 @@ auto Video::availableDrivers() -> string_vector {
|
|||
"OpenGL2",
|
||||
#endif
|
||||
|
||||
#if defined(VIDEO_XV)
|
||||
"X-Video",
|
||||
#if defined(VIDEO_XVIDEO)
|
||||
"XVideo",
|
||||
#endif
|
||||
|
||||
#if defined(VIDEO_XSHM)
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
|
||||
extern "C" auto XvShmCreateImage(Display*, XvPortID, int, char*, int, int, XShmSegmentInfo*) -> XvImage*;
|
||||
|
||||
struct VideoXv : Video {
|
||||
VideoXv() { initialize(); }
|
||||
~VideoXv() { terminate(); }
|
||||
struct VideoXVideo : Video {
|
||||
VideoXVideo() { initialize(); }
|
||||
~VideoXVideo() { terminate(); }
|
||||
|
||||
auto ready() -> bool { return _ready; }
|
||||
|
||||
|
@ -44,6 +44,8 @@ struct VideoXv : Video {
|
|||
}
|
||||
|
||||
auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool {
|
||||
if(!_ready) return false;
|
||||
|
||||
if(width != _width || height != _height) {
|
||||
resize(_width = width, _height = height);
|
||||
}
|
||||
|
@ -56,8 +58,7 @@ struct VideoXv : Video {
|
|||
}
|
||||
|
||||
auto output() -> void {
|
||||
uint width = _width;
|
||||
uint height = _height;
|
||||
if(!_ready) return;
|
||||
|
||||
XWindowAttributes target;
|
||||
XGetWindowAttributes(_display, _window, &target);
|
||||
|
@ -76,16 +77,18 @@ struct VideoXv : Video {
|
|||
XGetWindowAttributes(_display, _window, &target);
|
||||
|
||||
switch(_format) {
|
||||
case XvFormatRGB32: renderRGB32(width, height); break;
|
||||
case XvFormatRGB24: renderRGB24(width, height); break;
|
||||
case XvFormatRGB16: renderRGB16(width, height); break;
|
||||
case XvFormatRGB15: renderRGB15(width, height); break;
|
||||
case XvFormatYUY2: renderYUY2 (width, height); break;
|
||||
case XvFormatUYVY: renderUYVY (width, height); break;
|
||||
case XvFormatRGB32: renderRGB32(_width, _height); break;
|
||||
case XvFormatRGB24: renderRGB24(_width, _height); break;
|
||||
case XvFormatRGB16: renderRGB16(_width, _height); break;
|
||||
case XvFormatRGB15: renderRGB15(_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,
|
||||
0, 0, width, height,
|
||||
0, 0, _width, _height,
|
||||
0, 0, target.width, target.height,
|
||||
true);
|
||||
}
|
||||
|
@ -157,9 +160,16 @@ struct VideoXv : Video {
|
|||
|
||||
_gc = XCreateGC(_display, _window, 0, 0);
|
||||
|
||||
//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);
|
||||
int attributeCount = 0;
|
||||
XvAttribute* attributeList = XvQueryPortAttributes(_display, _port, &attributeCount);
|
||||
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
|
||||
_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[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'
|
||||
|
@ -211,11 +233,23 @@ 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'
|
||||
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] == 'V'
|
||||
&& 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;
|
||||
break;
|
||||
}
|
||||
|
@ -228,29 +262,11 @@ struct VideoXv : Video {
|
|||
return false;
|
||||
}
|
||||
|
||||
_bufferWidth = 256;
|
||||
_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;
|
||||
_ready = true;
|
||||
initializeTables();
|
||||
resize(_width = 256, _height = 256);
|
||||
clear();
|
||||
return _ready = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
auto terminate() -> void {
|
||||
|
@ -279,7 +295,7 @@ struct VideoXv : Video {
|
|||
_display = nullptr;
|
||||
}
|
||||
|
||||
delete[] _buffer, _buffer = nullptr;
|
||||
delete[] _buffer, _buffer = nullptr, _bufferWidth = 0, _bufferHeight = 0;
|
||||
delete[] _ytable, _ytable = nullptr;
|
||||
delete[] _utable, _utable = nullptr;
|
||||
delete[] _vtable, _vtable = nullptr;
|
||||
|
@ -290,10 +306,19 @@ struct VideoXv : Video {
|
|||
_bufferWidth = max(width, _bufferWidth);
|
||||
_bufferHeight = max(height, _bufferHeight);
|
||||
|
||||
XShmDetach(_display, &_shmInfo);
|
||||
shmdt(_shmInfo.shmaddr);
|
||||
shmctl(_shmInfo.shmid, IPC_RMID, nullptr);
|
||||
XFree(_image);
|
||||
//must round to be evenly divisible by 4
|
||||
if(uint round = _bufferWidth & 3) _bufferWidth += 4 - round;
|
||||
if(uint round = _bufferHeight & 3) _bufferHeight += 4 - round;
|
||||
|
||||
_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);
|
||||
|
||||
|
@ -324,8 +349,8 @@ struct VideoXv : Video {
|
|||
for(uint y : range(height)) {
|
||||
for(uint x : range(width)) {
|
||||
uint32_t p = *input++;
|
||||
*output++ = p;
|
||||
*output++ = p >> 8;
|
||||
*output++ = p >> 0;
|
||||
*output++ = p >> 8;
|
||||
*output++ = p >> 16;
|
||||
}
|
||||
|
||||
|
@ -340,8 +365,8 @@ struct VideoXv : Video {
|
|||
|
||||
for(uint y : range(height)) {
|
||||
for(uint x : range(width)) {
|
||||
uint32_t p = *input++;
|
||||
*output++ = ((p >> 8) & 0xf800) | ((p >> 5) & 0x07e0) | ((p >> 3) & 0x001f); //RGB32->RGB16
|
||||
uint32_t p = toRGB16(*input++);
|
||||
*output++ = p;
|
||||
}
|
||||
|
||||
input += _bufferWidth - width;
|
||||
|
@ -355,31 +380,8 @@ struct VideoXv : Video {
|
|||
|
||||
for(uint y : range(height)) {
|
||||
for(uint x : range(width)) {
|
||||
uint32_t p = *input++;
|
||||
*output++ = ((p >> 9) & 0x7c00) | ((p >> 6) & 0x03e0) | ((p >> 3) & 0x001f); //RGB32->RGB15
|
||||
}
|
||||
|
||||
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];
|
||||
uint32_t p = toRGB15(*input++);
|
||||
*output++ = p;
|
||||
}
|
||||
|
||||
input += _bufferWidth - width;
|
||||
|
@ -388,21 +390,16 @@ struct VideoXv : Video {
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
p1 = ((p1 >> 8) & 0xf800) + ((p1 >> 5) & 0x07e0) + ((p1 >> 3) & 0x001f);
|
||||
uint32_t p0 = toRGB16(*input++);
|
||||
uint32_t p1 = toRGB16(*input++);
|
||||
|
||||
uint8_t u = (_utable[p0] + _utable[p1]) >> 1;
|
||||
uint8_t v = (_vtable[p0] + _vtable[p1]) >> 1;
|
||||
|
||||
*output++ = (_ytable[p0] << 8) | u;
|
||||
*output++ = (_ytable[p1] << 8) | v;
|
||||
*output++ = _ytable[p0] << 8 | ((_utable[p0] + _utable[p1]) >> 1) << 0;
|
||||
*output++ = _ytable[p1] << 8 | ((_vtable[p0] + _vtable[p1]) >> 1) << 0;
|
||||
}
|
||||
|
||||
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 {
|
||||
_ytable = new uint8_t[65536];
|
||||
_utable = new uint8_t[65536];
|
||||
|
@ -460,8 +533,10 @@ struct VideoXv : Video {
|
|||
XvFormatRGB24,
|
||||
XvFormatRGB16,
|
||||
XvFormatRGB15,
|
||||
XvFormatYUY2,
|
||||
XvFormatUYVY,
|
||||
XvFormatYUY2,
|
||||
XvFormatYV12,
|
||||
XvFormatI420,
|
||||
XvFormatUnknown,
|
||||
};
|
||||
|
Loading…
Reference in New Issue