diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index 743fd2a8f7..a216d984e0 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -395,6 +395,7 @@ set(pcsx2USBSources USB/usb-mic/usb-mic-logitech.cpp USB/usb-mic/usb-headset.cpp USB/usb-eyetoy/jpgd/jpgd.cpp + USB/usb-eyetoy/jpgd/jpge.cpp USB/usb-eyetoy/jo_mpeg.cpp USB/usb-eyetoy/usb-eyetoy-webcam.cpp USB/usb-hid/usb-hid.cpp @@ -449,6 +450,7 @@ set(pcsx2USBHeaders USB/usb-mic/usb-headset.h USB/usb-mic/audiodev-noop.h USB/usb-eyetoy/jpgd/jpgd.h + USB/usb-eyetoy/jpgd/jpge.h USB/usb-eyetoy/jo_mpeg.h USB/usb-eyetoy/videodeviceproxy.h USB/usb-eyetoy/videodev.h diff --git a/pcsx2/USB/usb-eyetoy/cam-linux.cpp b/pcsx2/USB/usb-eyetoy/cam-linux.cpp index 19482e20f4..af41b48210 100644 --- a/pcsx2/USB/usb-eyetoy/cam-linux.cpp +++ b/pcsx2/USB/usb-eyetoy/cam-linux.cpp @@ -16,6 +16,7 @@ #include "cam-linux.h" #include "usb-eyetoy-webcam.h" #include "jpgd/jpgd.h" +#include "jpgd/jpge.h" #include "jo_mpeg.h" #include "USB/gtk.h" #include "Utilities/Console.h" @@ -52,6 +53,9 @@ namespace usb_eyetoy buffer_t mpeg_buffer; std::mutex mpeg_mutex; + int frame_width; + int frame_height; + FrameFormat frame_format; bool mirroring_enabled = true; static int xioctl(int fh, unsigned long int request, void* arg) @@ -64,7 +68,7 @@ namespace usb_eyetoy return r; } - static void store_mpeg_frame(unsigned char* data, unsigned int len) + static void store_mpeg_frame(const unsigned char* data, const unsigned int len) { mpeg_mutex.lock(); memcpy(mpeg_buffer.start, data, len); @@ -72,24 +76,77 @@ namespace usb_eyetoy mpeg_mutex.unlock(); } - static void process_image(const unsigned char* ptr, int size) + static void process_image(const unsigned char* data, int size) { + const int bytesPerPixel = 3; + int comprBufSize = frame_width * frame_height * bytesPerPixel; if (pixelformat == V4L2_PIX_FMT_YUYV) { - unsigned char* mpegData = (unsigned char*)calloc(1, 320 * 240 * 2); - int mpegLen = jo_write_mpeg(mpegData, ptr, 320, 240, JO_YUYV, mirroring_enabled ? JO_FLIP_X : JO_NONE, JO_NONE); - store_mpeg_frame(mpegData, mpegLen); - free(mpegData); + unsigned char* comprBuf = (unsigned char*)calloc(1, comprBufSize); + int comprLen = 0; + if (frame_format == format_mpeg) + { + comprLen = jo_write_mpeg(comprBuf, data, frame_width, frame_height, JO_YUYV, mirroring_enabled ? JO_FLIP_X : JO_NONE, JO_NONE); + } + else if (frame_format == format_jpeg) + { + unsigned char* data2 = (unsigned char*)calloc(1, comprBufSize); + for (int y = 0; y < frame_height; y++) + { + for (int x = 0; x < frame_width; x += 2) + { + const unsigned char* src = data + (y * frame_width + x) * 2; + unsigned char* dst = data2 + (y * frame_width + x) * bytesPerPixel; + + int y1 = (int) src[0] << 8; + int u = (int) src[1] - 128; + int y2 = (int) src[2] << 8; + int v = (int) src[3] - 128; + + int r = (y1 + (259 * v) >> 8); + int g = (y1 - (88 * u) - (183 * v)) >> 8; + int b = (y1 + (454 * u)) >> 8; + dst[0] = (r > 255) ? 255 : ((r < 0) ? 0 : r); + dst[1] = (g > 255) ? 255 : ((g < 0) ? 0 : g); + dst[2] = (b > 255) ? 255 : ((b < 0) ? 0 : b); + + r = (y2 + (259 * v) >> 8); + g = (y2 - (88 * u) - (183 * v)) >> 8; + b = (y2 + (454 * u)) >> 8; + dst[3] = (r > 255) ? 255 : ((r < 0) ? 0 : r); + dst[4] = (g > 255) ? 255 : ((g < 0) ? 0 : g); + dst[5] = (b > 255) ? 255 : ((b < 0) ? 0 : b); + } + } + jpge::params params; + params.m_quality = 80; + params.m_subsampling = jpge::H2V1; + comprLen = comprBufSize; + if (!jpge::compress_image_to_jpeg_file_in_memory(comprBuf, comprLen, frame_width, frame_height, 3, data2, params)) + { + comprLen = 0; + } + free(data2); + } + store_mpeg_frame(comprBuf, comprLen); + free(comprBuf); } else if (pixelformat == V4L2_PIX_FMT_JPEG) { - int width, height, actual_comps; - unsigned char* rgbData = jpgd::decompress_jpeg_image_from_memory(ptr, size, &width, &height, &actual_comps, 3); - unsigned char* mpegData = (unsigned char*)calloc(1, 320 * 240 * 2); - int mpegLen = jo_write_mpeg(mpegData, rgbData, 320, 240, JO_RGB24, mirroring_enabled ? JO_FLIP_X : JO_NONE, JO_NONE); - free(rgbData); - store_mpeg_frame(mpegData, mpegLen); - free(mpegData); + if (frame_format == format_mpeg) + { + int width, height, actual_comps; + unsigned char* rgbData = jpgd::decompress_jpeg_image_from_memory(data, size, &width, &height, &actual_comps, 3); + unsigned char* comprBuf = (unsigned char*)calloc(1, comprBufSize); + int comprLen = jo_write_mpeg(comprBuf, rgbData, frame_width, frame_height, JO_RGB24, mirroring_enabled ? JO_FLIP_X : JO_NONE, JO_NONE); + free(rgbData); + store_mpeg_frame(comprBuf, comprLen); + free(comprBuf); + } + else if (frame_format == format_jpeg) + { + store_mpeg_frame(data, size); + } } else { @@ -272,8 +329,8 @@ namespace usb_eyetoy struct v4l2_format fmt; CLEAR(fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt.fmt.pix.width = 320; - fmt.fmt.pix.height = 240; + fmt.fmt.pix.width = frame_width; + fmt.fmt.pix.height = frame_height; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt)) @@ -438,32 +495,60 @@ namespace usb_eyetoy void create_dummy_frame() { - const int width = 320; - const int height = 240; const int bytesPerPixel = 3; - - unsigned char* rgbData = (unsigned char*)calloc(1, width * height * bytesPerPixel); - for (int y = 0; y < height; y++) + int comprBufSize = frame_width * frame_height * bytesPerPixel; + unsigned char* rgbData = (unsigned char*)calloc(1, comprBufSize); + for (int y = 0; y < frame_height; y++) { - for (int x = 0; x < width; x++) + for (int x = 0; x < frame_width; x++) { - unsigned char* ptr = rgbData + (y * width + x) * bytesPerPixel; - ptr[0] = 255 - y; - ptr[1] = y; - ptr[2] = 255 - y; + unsigned char* ptr = rgbData + (y * frame_width + x) * bytesPerPixel; + ptr[0] = 255 * y / frame_height; + ptr[1] = 255 * x / frame_width; + ptr[2] = 255 * y / frame_height; + } + } + unsigned char* comprBuf = (unsigned char*)calloc(1, comprBufSize); + int comprLen = 0; + if (frame_format == format_mpeg) + { + comprLen = jo_write_mpeg(comprBuf, rgbData, frame_width, frame_height, JO_RGB24, JO_NONE, JO_NONE); + } + else if (frame_format == format_jpeg) + { + jpge::params params; + params.m_quality = 80; + params.m_subsampling = jpge::H2V1; + comprLen = comprBufSize; + if (!jpge::compress_image_to_jpeg_file_in_memory(comprBuf, comprLen, frame_width, frame_height, 3, rgbData, params)) + { + comprLen = 0; } } - unsigned char* mpegData = (unsigned char*)calloc(1, width * height * bytesPerPixel); - int mpegLen = jo_write_mpeg(mpegData, rgbData, width, height, JO_RGB24, JO_NONE, JO_NONE); free(rgbData); - store_mpeg_frame(mpegData, mpegLen); - free(mpegData); + store_mpeg_frame(comprBuf, comprLen); + free(comprBuf); } - int V4L2::Open() + V4L2::V4L2(int port) { - mpeg_buffer.start = calloc(1, 320 * 240 * 2); + mPort = port; + mpeg_buffer.start = calloc(1, 640 * 480 * 2); + } + + V4L2::~V4L2() + { + free(mpeg_buffer.start); + mpeg_buffer.start = nullptr; + } + + int V4L2::Open(int width, int height, FrameFormat format, int mirror) + { + frame_width = width; + frame_height = height; + frame_format = format; + mirroring_enabled = mirror; create_dummy_frame(); if (eyetoy_running) { @@ -493,11 +578,11 @@ namespace usb_eyetoy return 0; }; - int V4L2::GetImage(uint8_t* buf, int len) + int V4L2::GetImage(uint8_t* buf, size_t len) { mpeg_mutex.lock(); int len2 = mpeg_buffer.length; - if (len < (int)mpeg_buffer.length) + if (len < mpeg_buffer.length) len2 = len; memcpy(buf, mpeg_buffer.start, len2); mpeg_buffer.length = 0; diff --git a/pcsx2/USB/usb-eyetoy/cam-linux.h b/pcsx2/USB/usb-eyetoy/cam-linux.h index 945254e195..e44c595d7b 100644 --- a/pcsx2/USB/usb-eyetoy/cam-linux.h +++ b/pcsx2/USB/usb-eyetoy/cam-linux.h @@ -20,7 +20,7 @@ namespace usb_eyetoy namespace linux_api { - typedef struct + typedef struct _buffer_t { void* start; size_t length; @@ -31,12 +31,11 @@ namespace usb_eyetoy class V4L2 : public VideoDevice { public: - V4L2(int port) - : mPort(port){}; - ~V4L2(){}; - int Open(); + V4L2(int port); + ~V4L2(); + int Open(int width, int height, FrameFormat format, int mirror); int Close(); - int GetImage(uint8_t* buf, int len); + int GetImage(uint8_t* buf, size_t len); void SetMirroring(bool state); int Reset() { return 0; }; diff --git a/pcsx2/USB/usb-eyetoy/cam-windows.cpp b/pcsx2/USB/usb-eyetoy/cam-windows.cpp index 1984931619..d2ce241c3e 100644 --- a/pcsx2/USB/usb-eyetoy/cam-windows.cpp +++ b/pcsx2/USB/usb-eyetoy/cam-windows.cpp @@ -18,6 +18,7 @@ #include "cam-windows.h" #include "usb-eyetoy-webcam.h" #include "jo_mpeg.h" +#include "jpgd/jpge.h" #include "USB/Win32/Config_usb.h" #include "USB/Win32/resource_usb.h" @@ -26,6 +27,12 @@ namespace usb_eyetoy { namespace windows_api { + buffer_t mpeg_buffer{}; + std::mutex mpeg_mutex; + int frame_width; + int frame_height; + FrameFormat frame_format; + bool mirroring_enabled = true; HRESULT DirectShow::CallbackHandler::SampleCB(double time, IMediaSample* sample) { @@ -224,8 +231,8 @@ namespace usb_eyetoy { VIDEOINFOHEADER* pVih = (VIDEOINFOHEADER*)pmtConfig->pbFormat; - pVih->bmiHeader.biWidth = 320; - pVih->bmiHeader.biHeight = 240; + pVih->bmiHeader.biWidth = frame_width; + pVih->bmiHeader.biHeight = frame_height; pVih->bmiHeader.biSizeImage = DIBSIZE(pVih->bmiHeader); hr = pSourceConfig->SetFormat(pmtConfig); } @@ -354,11 +361,7 @@ namespace usb_eyetoy throw hr; } - buffer_t mpeg_buffer{}; - std::mutex mpeg_mutex; - bool mirroring_enabled = true; - - void store_mpeg_frame(unsigned char* data, unsigned int len) + void store_mpeg_frame(const unsigned char* data, const unsigned int len) { mpeg_mutex.lock(); memcpy(mpeg_buffer.start, data, len); @@ -370,10 +373,42 @@ namespace usb_eyetoy { if (bitsperpixel == 24) { - unsigned char* mpegData = (unsigned char*)calloc(1, 320 * 240 * 2); - int mpegLen = jo_write_mpeg(mpegData, data, 320, 240, JO_BGR24, mirroring_enabled ? JO_FLIP_X : JO_NONE, JO_FLIP_Y); - store_mpeg_frame(mpegData, mpegLen); - free(mpegData); + const int bytesPerPixel = 3; + int comprBufSize = frame_width * frame_height * bytesPerPixel; + unsigned char* comprBuf = (unsigned char*)calloc(1, comprBufSize); + int comprLen = 0; + if (frame_format == format_mpeg) + { + comprLen = jo_write_mpeg(comprBuf, data, frame_width, frame_height, JO_BGR24, mirroring_enabled ? JO_FLIP_X : JO_NONE, JO_FLIP_Y); + } + else if (frame_format == format_jpeg) + { + // flip Y - always required on windows + unsigned char* data2 = (unsigned char*)calloc(1, comprBufSize); + for (int y = 0; y < frame_height; y++) + { + for (int x = 0; x < frame_width; x++) + { + unsigned char* src = data + (y * frame_width + x) * bytesPerPixel; + unsigned char* dst = data2 + ((frame_height - y - 1) * frame_width + x) * bytesPerPixel; + dst[0] = src[2]; + dst[1] = src[1]; + dst[2] = src[0]; + } + } + + jpge::params params; + params.m_quality = 80; + params.m_subsampling = jpge::H2V1; + comprLen = comprBufSize; + if (!jpge::compress_image_to_jpeg_file_in_memory(comprBuf, comprLen, frame_width, frame_height, 3, data2, params)) + { + comprLen = 0; + } + free(data2); + } + store_mpeg_frame(comprBuf, comprLen); + free(comprBuf); } else { @@ -383,27 +418,40 @@ namespace usb_eyetoy void create_dummy_frame() { - const int width = 320; - const int height = 240; const int bytesPerPixel = 3; - - unsigned char* rgbData = (unsigned char*)calloc(1, width * height * bytesPerPixel); - for (int y = 0; y < height; y++) + int comprBufSize = frame_width * frame_height * bytesPerPixel; + unsigned char* rgbData = (unsigned char*)calloc(1, comprBufSize); + for (int y = 0; y < frame_height; y++) { - for (int x = 0; x < width; x++) + for (int x = 0; x < frame_width; x++) { - unsigned char* ptr = rgbData + (y * width + x) * bytesPerPixel; - ptr[0] = 255 - y; - ptr[1] = y; - ptr[2] = 255 - y; + unsigned char* ptr = rgbData + (y * frame_width + x) * bytesPerPixel; + ptr[0] = 255 * y / frame_height; + ptr[1] = 255 * x / frame_width; + ptr[2] = 255 * y / frame_height; + } + } + unsigned char* comprBuf = (unsigned char*)calloc(1, comprBufSize); + int comprLen = 0; + if (frame_format == format_mpeg) + { + comprLen = jo_write_mpeg(comprBuf, rgbData, frame_width, frame_height, JO_RGB24, JO_NONE, JO_NONE); + } + else if (frame_format == format_jpeg) + { + jpge::params params; + params.m_quality = 80; + params.m_subsampling = jpge::H2V1; + comprLen = comprBufSize; + if (!jpge::compress_image_to_jpeg_file_in_memory(comprBuf, comprLen, frame_width, frame_height, 3, rgbData, params)) + { + comprLen = 0; } } - unsigned char* mpegData = (unsigned char*)calloc(1, width * height * bytesPerPixel); - int mpegLen = jo_write_mpeg(mpegData, rgbData, width, height, JO_RGB24, JO_NONE, JO_NONE); free(rgbData); - store_mpeg_frame(mpegData, mpegLen); - free(mpegData); + store_mpeg_frame(comprBuf, comprLen); + free(comprBuf); } DirectShow::DirectShow(int port) @@ -419,11 +467,21 @@ namespace usb_eyetoy samplegrabber = nullptr; callbackhandler = new CallbackHandler(); CoInitialize(NULL); + mpeg_buffer.start = calloc(1, 640 * 480 * 2); } - int DirectShow::Open() + DirectShow::~DirectShow() { - mpeg_buffer.start = calloc(1, 320 * 240 * 2); + free(mpeg_buffer.start); + mpeg_buffer.start = nullptr; + } + + int DirectShow::Open(int width, int height, FrameFormat format, int mirror) + { + frame_width = width; + frame_height = height; + frame_format = format; + mirroring_enabled = mirror; create_dummy_frame(); std::wstring selectedDevice; @@ -461,13 +519,10 @@ namespace usb_eyetoy safe_release(pGraphBuilder); safe_release(pGraph); safe_release(pControl); - - free(mpeg_buffer.start); - mpeg_buffer.start = nullptr; return 0; }; - int DirectShow::GetImage(uint8_t* buf, int len) + int DirectShow::GetImage(uint8_t* buf, size_t len) { mpeg_mutex.lock(); int len2 = mpeg_buffer.length; diff --git a/pcsx2/USB/usb-eyetoy/cam-windows.h b/pcsx2/USB/usb-eyetoy/cam-windows.h index 77cc5980f0..2c25d959ac 100644 --- a/pcsx2/USB/usb-eyetoy/cam-windows.h +++ b/pcsx2/USB/usb-eyetoy/cam-windows.h @@ -84,10 +84,10 @@ namespace usb_eyetoy { public: DirectShow(int port); - ~DirectShow() {} - int Open(); + ~DirectShow(); + int Open(int width, int height, FrameFormat format, int mirror); int Close(); - int GetImage(uint8_t* buf, int len); + int GetImage(uint8_t* buf, size_t len); void SetMirroring(bool state); int Reset() { return 0; }; diff --git a/pcsx2/USB/usb-eyetoy/jo_mpeg.cpp b/pcsx2/USB/usb-eyetoy/jo_mpeg.cpp index aadfad419e..97d5cb92f8 100644 --- a/pcsx2/USB/usb-eyetoy/jo_mpeg.cpp +++ b/pcsx2/USB/usb-eyetoy/jo_mpeg.cpp @@ -178,11 +178,35 @@ static int jo_processDU(jo_bits_t *bits, float A[64], const unsigned char htdc[9 return Q[0]; } +void write_ipu_header(jo_bits_t* bits, int width, int height) { + jo_writeBits(bits, 0x69, 8); + jo_writeBits(bits, 0x70, 8); + jo_writeBits(bits, 0x75, 8); + jo_writeBits(bits, 0x6D, 8); + + jo_writeBits(bits, 0x00, 8); + jo_writeBits(bits, 0x00, 8); + jo_writeBits(bits, 0x00, 8); + jo_writeBits(bits, 0x00, 8); + + jo_writeBits(bits, width & 0xFF, 8); + jo_writeBits(bits, width >> 8, 8); + jo_writeBits(bits, height & 0xFF, 8); + jo_writeBits(bits, height >> 8, 8); + + jo_writeBits(bits, 0x01, 8); + jo_writeBits(bits, 0x00, 8); + jo_writeBits(bits, 0x00, 8); + jo_writeBits(bits, 0x00, 8); +} + unsigned long jo_write_mpeg(unsigned char *mpeg_buf, const unsigned char *raw, int width, int height, int format, int flipx, int flipy) { int lastDCY = 128, lastDCCR = 128, lastDCCB = 128; unsigned char *head = mpeg_buf; jo_bits_t bits = {mpeg_buf}; + write_ipu_header(&bits, width, height); + jo_writeBits(&bits, 0x00, 8); for (int vblock = 0; vblock < (height+15)/16; vblock++) { for (int hblock = 0; hblock < (width+15)/16; hblock++) { diff --git a/pcsx2/USB/usb-eyetoy/jpgd/jpge.cpp b/pcsx2/USB/usb-eyetoy/jpgd/jpge.cpp index 4bdc34a97c..24a6cf3ebf 100644 --- a/pcsx2/USB/usb-eyetoy/jpgd/jpge.cpp +++ b/pcsx2/USB/usb-eyetoy/jpgd/jpge.cpp @@ -28,6 +28,7 @@ // Code review revealed method load_block_16_8_8() (used for the non-default H2V1 sampling mode to downsample chroma) somehow didn't get the rounding factor fix from v1.02. // v1.05, March 25, 2020: Added Apache 2.0 alternate license +#include "PrecompiledHeader.h" #include "jpge.h" #include diff --git a/pcsx2/USB/usb-eyetoy/ov519.h b/pcsx2/USB/usb-eyetoy/ov519.h index 114fab9e6a..1fc611c624 100644 --- a/pcsx2/USB/usb-eyetoy/ov519.h +++ b/pcsx2/USB/usb-eyetoy/ov519.h @@ -33,6 +33,8 @@ #define OV519_R20_DFR 0x20 #define OV519_R25_FORMAT 0x25 #define OV519_RA0_FORMAT 0xA0 +#define OV519_RA0_FORMAT_MPEG 0x42 +#define OV519_RA0_FORMAT_JPEG 0x33 /* OV519 System Controller register numbers */ #define OV519_R51_RESET1 0x51 @@ -50,6 +52,8 @@ #define OV8610_REG_HUE 0x04 /* 04 reserved */ #define OV7610_REG_CNT 0x05 /* Y contrast */ #define OV7610_REG_BRT 0x06 /* Y brightness */ +#define OV7610_REG_COM_A 0x12 /* misc common regs */ +#define OV7610_REG_COM_A_MASK_MIRROR 0x40 /* mirror image */ #define OV7610_REG_COM_C 0x14 /* misc common regs */ #define OV7610_REG_ID_HIGH 0x1c /* manufacturer ID MSB */ #define OV7610_REG_ID_LOW 0x1d /* manufacturer ID LSB */ diff --git a/pcsx2/USB/usb-eyetoy/usb-eyetoy-webcam.cpp b/pcsx2/USB/usb-eyetoy/usb-eyetoy-webcam.cpp index cdd25f3267..b90c4328ca 100644 --- a/pcsx2/USB/usb-eyetoy/usb-eyetoy-webcam.cpp +++ b/pcsx2/USB/usb-eyetoy/usb-eyetoy-webcam.cpp @@ -33,12 +33,11 @@ namespace usb_eyetoy uint8_t regs[0xFF]; //OV519 uint8_t i2c_regs[0xFF]; //OV764x + int hw_camera_running; int frame_step; unsigned char* mpeg_frame_data; unsigned int mpeg_frame_size; unsigned int mpeg_frame_offset; - uint8_t alts[3]; - uint8_t filter_log; // } f; } EYETOYState; @@ -341,18 +340,31 @@ namespace usb_eyetoy switch (index) { case OV519_RA0_FORMAT: - if (data[0] == 0x42) + if (data[0] == OV519_RA0_FORMAT_MPEG) { Console.WriteLn("EyeToy : configured for MPEG format"); } - else if (data[0] == 0x33) + else if (data[0] == OV519_RA0_FORMAT_JPEG) { - Console.WriteLn("EyeToy : configured for JPEG format; Unimplemented"); + Console.WriteLn("EyeToy : configured for JPEG format"); } else { Console.WriteLn("EyeToy : configured for unknown format"); } + + if (s->hw_camera_running && s->regs[OV519_RA0_FORMAT] != data[0]) + { + Console.WriteLn("EyeToy : reinitialize the camera"); + s->dev.klass.close(dev); + s->dev.klass.open(dev); + } + break; + case OV519_R10_H_SIZE: + Console.WriteLn("EyeToy : Image width : %d", data[0] << 4); + break; + case OV519_R11_V_SIZE: + Console.WriteLn("EyeToy : Image height : %d", data[0] << 3); break; case OV519_GPIO_DATA_OUT0: { @@ -379,9 +391,9 @@ namespace usb_eyetoy { s->i2c_regs[reg] = val; } - if (reg == 0x12) + if (reg == OV7610_REG_COM_A) { - const bool mirroring_enabled = val & 0x40; + const bool mirroring_enabled = val & OV7610_REG_COM_A_MASK_MIRROR; s->videodev->SetMirroring(mirroring_enabled); Console.WriteLn("EyeToy : mirroring %s", mirroring_enabled ? "ON" : "OFF"); } @@ -420,6 +432,13 @@ namespace usb_eyetoy uint8_t data[max_ep_size]; uint8_t devep = p->ep->nr; + if (!s->hw_camera_running) + { + Console.WriteLn("EyeToy : initialization done; start the camera"); + s->hw_camera_running = 1; + s->dev.klass.open(dev); + } + switch (p->pid) { case USB_TOKEN_IN: @@ -429,7 +448,7 @@ namespace usb_eyetoy if (s->frame_step == 0) { - s->mpeg_frame_size = s->videodev->GetImage(s->mpeg_frame_data, 320 * 240 * 2); + s->mpeg_frame_size = s->videodev->GetImage(s->mpeg_frame_data, 640 * 480 * 3); if (s->mpeg_frame_size == 0) { p->status = USB_RET_NAK; @@ -437,8 +456,8 @@ namespace usb_eyetoy } uint8_t header[] = { - 0xFF, 0xFF, 0xFF, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x69, 0x70, 0x75, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0xF0, 0x00, 0x01, 0x00, 0x00, 0x00}; + 0xFF, 0xFF, 0xFF, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; + header[0x0A] = s->regs[OV519_RA0_FORMAT] == OV519_RA0_FORMAT_JPEG ? 0x03 : 0x01; memcpy(data, header, sizeof(header)); int data_pk = max_ep_size - sizeof(header); @@ -459,9 +478,11 @@ namespace usb_eyetoy { uint8_t footer[] = { 0xFF, 0xFF, 0xFF, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; + footer[0x0A] = s->regs[OV519_RA0_FORMAT] == OV519_RA0_FORMAT_JPEG ? 0x03 : 0x01; memcpy(data, footer, sizeof(footer)); s->frame_step = 0; } + usb_packet_copy(p, data, max_ep_size); } else if (devep == 2) @@ -489,14 +510,28 @@ namespace usb_eyetoy int eyetoy_open(USBDevice* dev) { EYETOYState* s = (EYETOYState*)dev; - s->videodev->Open(); + if (s->hw_camera_running) + { + const int width = s->regs[OV519_R10_H_SIZE] << 4; + const int height = s->regs[OV519_R11_V_SIZE] << 3; + const FrameFormat format = s->regs[OV519_RA0_FORMAT] == OV519_RA0_FORMAT_JPEG ? format_jpeg : format_mpeg; + const int mirror = !!(s->i2c_regs[OV7610_REG_COM_A] & OV7610_REG_COM_A_MASK_MIRROR); + Console.Error("EyeToy : eyetoy_open(); hw=%d, w=%d, h=%d, fmt=%d, mirr=%d", s->hw_camera_running, + width, height, format, mirror); + s->videodev->Open(width, height, format, mirror); + } return 1; } void eyetoy_close(USBDevice* dev) { EYETOYState* s = (EYETOYState*)dev; - s->videodev->Close(); + Console.Error("EyeToy : eyetoy_close(); hw=%d", s->hw_camera_running); + if (s->hw_camera_running) + { + s->hw_camera_running = 0; + s->videodev->Close(); + } } USBDevice* EyeToyWebCamDevice::CreateDevice(int port) @@ -552,8 +587,9 @@ namespace usb_eyetoy usb_ep_init(&s->dev); eyetoy_handle_reset((USBDevice*)s); + s->hw_camera_running = 0; s->frame_step = 0; - s->mpeg_frame_data = (unsigned char*)calloc(1, 320 * 240 * 4); // TODO: 640x480 ? + s->mpeg_frame_data = (unsigned char*)calloc(1, 640 * 480 * 3); s->mpeg_frame_offset = 0; static_state = s; diff --git a/pcsx2/USB/usb-eyetoy/videodev.h b/pcsx2/USB/usb-eyetoy/videodev.h index 2db5850a01..4bba48aebd 100644 --- a/pcsx2/USB/usb-eyetoy/videodev.h +++ b/pcsx2/USB/usb-eyetoy/videodev.h @@ -20,14 +20,19 @@ namespace usb_eyetoy { + enum FrameFormat + { + format_mpeg, + format_jpeg + }; class VideoDevice { public: virtual ~VideoDevice() {} - virtual int Open() = 0; + virtual int Open(int width, int height, FrameFormat format, int mirror) = 0; virtual int Close() = 0; - virtual int GetImage(uint8_t* buf, int len) = 0; + virtual int GetImage(uint8_t* buf, size_t len) = 0; virtual void SetMirroring(bool state) = 0; virtual int Reset() = 0; diff --git a/pcsx2/pcsx2.vcxproj b/pcsx2/pcsx2.vcxproj index cf8be94c8f..1ef9ec57d8 100644 --- a/pcsx2/pcsx2.vcxproj +++ b/pcsx2/pcsx2.vcxproj @@ -451,6 +451,7 @@ + @@ -936,6 +937,7 @@ + diff --git a/pcsx2/pcsx2.vcxproj.filters b/pcsx2/pcsx2.vcxproj.filters index 7f4cf7c434..514342c1df 100644 --- a/pcsx2/pcsx2.vcxproj.filters +++ b/pcsx2/pcsx2.vcxproj.filters @@ -1218,6 +1218,9 @@ System\Ps2\USB\usb-eyetoy\jpgd + + System\Ps2\USB\usb-eyetoy\jpgd + System\Ps2\USB\usb-eyetoy @@ -2251,6 +2254,9 @@ System\Ps2\USB\usb-eyetoy\jpgd + + System\Ps2\USB\usb-eyetoy\jpgd + System\Ps2\USB\usb-hid