diff --git a/src/DSi_Camera.cpp b/src/DSi_Camera.cpp index 192d37ca..b16fbd36 100644 --- a/src/DSi_Camera.cpp +++ b/src/DSi_Camera.cpp @@ -443,10 +443,10 @@ void Camera::Reset() MCURegs[0x2104] = 3; TransferY = 0; - memset(FrameBuffer, 0, 640*480*sizeof(u32)); + memset(FrameBuffer, 0, (640*480/2)*sizeof(u32)); // test pattern - for (int y = 0; y < 480; y++) + /*for (int y = 0; y < 480; y++) { for (int x = 0; x < 640; x++) { @@ -458,7 +458,7 @@ void Camera::Reset() FrameBuffer[y*640 + x] = color; } - } + }*/ } bool Camera::IsActivated() @@ -534,7 +534,7 @@ int Camera::TransferScanline(u32* buffer, int maxlen) int sx; - sx = ((dx*2) * 640) / FrameWidth; + /*sx = ((dx*2) * 640) / FrameWidth; u32 pixel1 = FrameBuffer[sy*640 + sx]; sx = ((dx*2 + 1) * 640) / FrameWidth; @@ -566,7 +566,11 @@ int Camera::TransferScanline(u32* buffer, int maxlen) u1 = (u1 + u2) >> 1; v1 = (v1 + v2) >> 1; - buffer[dx] = y1 | (u1 << 8) | (y2 << 16) | (v1 << 24); + buffer[dx] = y1 | (u1 << 8) | (y2 << 16) | (v1 << 24);*/ + + sx = ((dx) * 640) / FrameWidth; + u32 pixel3 = FrameBuffer[sy*320 + sx]; + buffer[dx] = pixel3; } TransferY++; @@ -752,25 +756,74 @@ void Camera::MCU_Write(u16 addr, u8 val) } -void Camera::InputFrame(u32* data, int width, int height) +void Camera::InputFrame(u32* data, int width, int height, bool rgb) { // TODO: double-buffering? - if (width == 640 && height == 480) + if (width == 640 && height == 480 && !rgb) { - memcpy(FrameBuffer, data, 640*480*sizeof(u32)); + memcpy(FrameBuffer, data, (640*480/2)*sizeof(u32)); return; } - for (int dy = 0; dy < 480; dy++) + if (rgb) { - int sy = (dy * height) / 480; - - for (int dx = 0; dx < 640; dx++) + for (int dy = 0; dy < 480; dy++) { - int sx = (dx * width) / 640; + int sy = (dy * height) / 480; - FrameBuffer[dy*640 + dx] = data[sy*width + sx]; + for (int dx = 0; dx < 640; dx+=2) + { + int sx; + + sx = (dx * width) / 640; + u32 pixel1 = data[sy*width + sx]; + + sx = ((dx+1) * width) / 640; + u32 pixel2 = data[sy*width + sx]; + + int r1 = (pixel1 >> 16) & 0xFF; + int g1 = (pixel1 >> 8) & 0xFF; + int b1 = pixel1 & 0xFF; + + int r2 = (pixel2 >> 16) & 0xFF; + int g2 = (pixel2 >> 8) & 0xFF; + int b2 = pixel2 & 0xFF; + + int y1 = ((r1 * 19595) + (g1 * 38470) + (b1 * 7471)) >> 16; + int u1 = ((b1 - y1) * 32244) >> 16; + int v1 = ((r1 - y1) * 57475) >> 16; + + int y2 = ((r2 * 19595) + (g2 * 38470) + (b2 * 7471)) >> 16; + int u2 = ((b2 - y2) * 32244) >> 16; + int v2 = ((r2 - y2) * 57475) >> 16; + + u1 += 128; v1 += 128; + u2 += 128; v2 += 128; + + y1 = std::clamp(y1, 0, 255); u1 = std::clamp(u1, 0, 255); v1 = std::clamp(v1, 0, 255); + y2 = std::clamp(y2, 0, 255); u2 = std::clamp(u2, 0, 255); v2 = std::clamp(v2, 0, 255); + + // huh + u1 = (u1 + u2) >> 1; + v1 = (v1 + v2) >> 1; + + FrameBuffer[(dy*640 + dx) / 2] = y1 | (u1 << 8) | (y2 << 16) | (v1 << 24); + } + } + } + else + { + for (int dy = 0; dy < 480; dy++) + { + int sy = (dy * height) / 480; + + for (int dx = 0; dx < 640; dx+=2) + { + int sx = (dx * width) / 640; + + FrameBuffer[(dy*640 + dx) / 2] = data[(sy*width + sx) / 2]; + } } } } diff --git a/src/DSi_Camera.h b/src/DSi_Camera.h index 49886f81..12cec38a 100644 --- a/src/DSi_Camera.h +++ b/src/DSi_Camera.h @@ -67,7 +67,7 @@ public: u8 I2C_Read(bool last); void I2C_Write(u8 val, bool last); - void InputFrame(u32* data, int width, int height); + void InputFrame(u32* data, int width, int height, bool rgb); u32 Num; @@ -95,7 +95,7 @@ private: u16 FrameWidth, FrameHeight; u16 FrameReadMode, FrameFormat; int TransferY; - u32 FrameBuffer[640*480]; + u32 FrameBuffer[640*480/2]; // YUYV framebuffer, two pixels per word }; } diff --git a/src/NDS.cpp b/src/NDS.cpp index 9d436cbb..029870a2 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -1261,7 +1261,7 @@ void SetLidClosed(bool closed) } } -void CamInputFrame(int cam, u32* data, int width, int height) +void CamInputFrame(int cam, u32* data, int width, int height, bool rgb) { // TODO: support things like the GBA-slot camera addon // whenever these are emulated @@ -1270,8 +1270,8 @@ void CamInputFrame(int cam, u32* data, int width, int height) { switch (cam) { - case 0: return DSi_CamModule::Camera0->InputFrame(data, width, height); - case 1: return DSi_CamModule::Camera1->InputFrame(data, width, height); + case 0: return DSi_CamModule::Camera0->InputFrame(data, width, height, rgb); + case 1: return DSi_CamModule::Camera1->InputFrame(data, width, height, rgb); } } } diff --git a/src/NDS.h b/src/NDS.h index 5b6e083e..df3c41c8 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -260,7 +260,7 @@ void SetKeyMask(u32 mask); bool IsLidClosed(); void SetLidClosed(bool closed); -void CamInputFrame(int cam, u32* data, int width, int height); +void CamInputFrame(int cam, u32* data, int width, int height, bool rgb); void MicInputFrame(s16* data, int samples); void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 param); diff --git a/src/frontend/qt_sdl/CMakeLists.txt b/src/frontend/qt_sdl/CMakeLists.txt index ec88026f..b155bd79 100644 --- a/src/frontend/qt_sdl/CMakeLists.txt +++ b/src/frontend/qt_sdl/CMakeLists.txt @@ -61,11 +61,12 @@ if (USE_QT6) set(Qt6Gui_DIR ${QT6_STATIC_BASE}Gui) set(Qt6Widgets_DIR ${QT6_STATIC_BASE}Widgets) set(Qt6Network_DIR ${QT6_STATIC_BASE}Network) + set(Qt6Multimedia_DIR ${QT6_STATIC_BASE}Multimedia) set(Qt6OpenGL_DIR ${QT6_STATIC_BASE}OpenGL) set(Qt6OpenGLWidgets_DIR ${QT6_STATIC_BASE}OpenGLWidgets) endif() - find_package(Qt6 COMPONENTS Core Gui Widgets Network OpenGL OpenGLWidgets REQUIRED) - set(QT_LINK_LIBS Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Network Qt6::OpenGL Qt6::OpenGLWidgets) + find_package(Qt6 COMPONENTS Core Gui Widgets Network Multimedia OpenGL OpenGLWidgets REQUIRED) + set(QT_LINK_LIBS Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Network Qt6::Multimedia Qt6::OpenGL Qt6::OpenGLWidgets) else() if (BUILD_STATIC AND QT5_STATIC_DIR) set(QT5_STATIC_BASE ${QT5_STATIC_DIR}/lib/cmake/Qt5) @@ -74,9 +75,10 @@ else() set(Qt5Gui_DIR ${QT5_STATIC_BASE}Gui) set(Qt5Widgets_DIR ${QT5_STATIC_BASE}Widgets) set(Qt5Network_DIR ${QT5_STATIC_BASE}Network) + set(Qt5Multimedia_DIR ${QT5_STATIC_BASE}Multimedia) endif() - find_package(Qt5 COMPONENTS Core Gui Widgets Network REQUIRED) - set(QT_LINK_LIBS Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network) + find_package(Qt5 COMPONENTS Core Gui Widgets Network Multimedia REQUIRED) + set(QT_LINK_LIBS Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network Qt5::Multimedia) endif() set(CMAKE_AUTOMOC ON) diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 91b15008..5f235c9b 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -114,6 +114,7 @@ s16* micWavBuffer; void micCallback(void* data, Uint8* stream, int len); + void audioCallback(void* data, Uint8* stream, int len) { len /= (sizeof(s16) * 2); @@ -314,6 +315,57 @@ void micProcess() } +void camOpen() +{ + // +} + +void camClose() +{ + // +} + +void camProcess() +{ + // +} + +CameraFrameDumper::CameraFrameDumper(QObject* parent) : QAbstractVideoSurface(parent) +{ + printf("BAKA!!\n"); +} + +/*CameraFrameDumper::~CameraFrameDumper() +{ + printf("SAYONARA\n"); +}*/ + +bool CameraFrameDumper::present(const QVideoFrame& _frame) +{ + //printf("FRAMEZORZ!! %d %d %d\n", frame.pixelFormat(), frame.isMapped(), frame.isReadable()); + + QVideoFrame frame(_frame); + if (!frame.map(QAbstractVideoBuffer::ReadOnly)) + return false; +printf("FRAMEZORZ!! %d %d %d\n", frame.pixelFormat(), frame.isMapped(), frame.isReadable()); + NDS::CamInputFrame(0, (u32*)frame.bits(), frame.width(), frame.height(), false); + + frame.unmap(); + + return true; +} + +QList CameraFrameDumper::supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const +{ + QList ret; +printf("PENIS. %d\n", type); + ret.append(QVideoFrame::Format_RGB32); + ret.append(QVideoFrame::Format_YUYV); + + return ret; +} + + EmuThread::EmuThread(QObject* parent) : QThread(parent) { EmuStatus = 0; @@ -374,7 +426,7 @@ void EmuThread::deinitOpenGL() delete oglContext; delete oglSurface; } - +#include void EmuThread::run() { bool hasOGL = mainWindow->hasOGL; @@ -421,8 +473,46 @@ void EmuThread::run() char melontitle[100]; - QImage testimg("test.jpg"); - QImage testimg_conv = testimg.convertToFormat(QImage::Format_RGB32); + //QImage testimg("test.jpg"); + //QImage testimg_conv = testimg.convertToFormat(QImage::Format_RGB32); + + #if 0 + const QList cameras = QCameraInfo::availableCameras(); + for (const QCameraInfo &cameraInfo : cameras) + printf("CAMERAFAZIL: %s\n", cameraInfo.deviceName().toStdString().c_str()); + QCamera* camera = new QCamera(cameras[0]); + CameraFrameDumper* dumper = new CameraFrameDumper(); + //QCameraViewfinder* derp = new QCameraViewfinder(); + printf("PROAON\n"); + //camera->setCaptureMode(QCamera::CaptureVideo); + //camera->setCaptureMode(QCamera::CaptureViewfinder); + printf("PROOT\n"); + //camera->unload(); + camera->setViewfinder(dumper); + //camera->setViewfinder(derp); + //camera->load(); + + // if (status != QCamera::LoadedStatus || m_camera->state() == QCamera::ActiveState) { return + printf("STATUS %d STATE %d\n", camera->status(), camera->state()); + +printf("CHIASSE\n"); + /*QCameraViewfinderSettings settings; + auto zorp = camera->supportedViewfinderResolutions(settings); + for (auto& res : zorp) printf("RESOLUTION: %d x %d\n", res.width(), res.height()); + auto zarp = camera->supportedViewfinderPixelFormats(settings); + for (auto& pf : zarp) printf("PIXEL FORMAT: %d\n", pf); + + settings.setResolution(640, 480); + //settings.setPixelFormat(QVideoFrame::Format_RGB32); + settings.setPixelFormat(QVideoFrame::Format_YUYV); + printf("PRALIPET\n"); + camera->setViewfinderSettings(settings);*/ +printf("PROULON\n"); + //dumper->start(); + //QVideoSurfaceFormat blarf(QSize(640,480), QVideoFrame::Format_RGB32); + //dumper->start(blarf); + camera->start(); + #endif while (EmuRunning != 0) { @@ -505,7 +595,7 @@ void EmuThread::run() } // camera input test - NDS::CamInputFrame(0, (u32*)testimg_conv.bits(), testimg_conv.width(), testimg_conv.height()); + //NDS::CamInputFrame(0, (u32*)testimg_conv.bits(), testimg_conv.width(), testimg_conv.height(), true); // microphone input micProcess(); @@ -665,6 +755,9 @@ void EmuThread::run() } } + //camera->stop(); + //delete camera; + EmuStatus = 0; GPU::DeInitRenderer(); @@ -1718,6 +1811,44 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) actLimitFramerate->setChecked(Config::LimitFPS); actAudioSync->setChecked(Config::AudioSync); + + + + const QList cameras = QCameraInfo::availableCameras(); + for (const QCameraInfo &cameraInfo : cameras) + printf("CAMERAFAZIL: %s\n", cameraInfo.deviceName().toStdString().c_str()); + QCamera* camera = new QCamera(cameras[0]); + CameraFrameDumper* dumper = new CameraFrameDumper(); + //QCameraViewfinder* derp = new QCameraViewfinder(); + printf("PROAON\n"); + //camera->setCaptureMode(QCamera::CaptureVideo); + //camera->setCaptureMode(QCamera::CaptureViewfinder); + printf("PROOT\n"); + //camera->unload(); + camera->setViewfinder(dumper); + //camera->setViewfinder(derp); + //camera->load(); + + // if (status != QCamera::LoadedStatus || m_camera->state() == QCamera::ActiveState) { return + printf("STATUS %d STATE %d\n", camera->status(), camera->state()); + +printf("CHIASSE\n"); + /*QCameraViewfinderSettings settings; + auto zorp = camera->supportedViewfinderResolutions(settings); + for (auto& res : zorp) printf("RESOLUTION: %d x %d\n", res.width(), res.height()); + auto zarp = camera->supportedViewfinderPixelFormats(settings); + for (auto& pf : zarp) printf("PIXEL FORMAT: %d\n", pf); + + settings.setResolution(640, 480); + //settings.setPixelFormat(QVideoFrame::Format_RGB32); + settings.setPixelFormat(QVideoFrame::Format_YUYV); + printf("PRALIPET\n"); + camera->setViewfinderSettings(settings);*/ +printf("PROULON\n"); + //dumper->start(); + //QVideoSurfaceFormat blarf(QSize(640,480), QVideoFrame::Format_RGB32); + //dumper->start(blarf); + camera->start(); } MainWindow::~MainWindow() @@ -1813,7 +1944,7 @@ void MainWindow::keyPressEvent(QKeyEvent* event) if (event->isAutoRepeat()) return; // TODO!! REMOVE ME IN RELEASE BUILDS!! - if (event->key() == Qt::Key_F11) NDS::debug(0); + //if (event->key() == Qt::Key_F11) NDS::debug(0); Input::KeyPress(event); } @@ -2999,7 +3130,7 @@ bool MelonApplication::event(QEvent *event) int main(int argc, char** argv) { - srand(time(NULL)); + srand(time(nullptr)); printf("melonDS " MELONDS_VERSION "\n"); printf(MELONDS_URL "\n"); diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h index 6466e3b9..f4fa8db3 100644 --- a/src/frontend/qt_sdl/main.h +++ b/src/frontend/qt_sdl/main.h @@ -36,8 +36,24 @@ #include #include +#include +#include +#include + #include "FrontendUtil.h" +class CameraFrameDumper : public QAbstractVideoSurface +{ + Q_OBJECT + +public: + CameraFrameDumper(QObject* parent = nullptr); + //~CameraFrameDumper(); + + bool present(const QVideoFrame& frame) override; + QList supportedPixelFormats(QAbstractVideoBuffer::HandleType type = QAbstractVideoBuffer::NoHandle) const override; +}; + class EmuThread : public QThread { Q_OBJECT