/* This file is part of jpcsp. Jpcsp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Jpcsp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.HLE.modules; import static jpcsp.HLE.modules.sceJpeg.clamp8bit; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; import javax.imageio.ImageIO; import jpcsp.HLE.HLEFunction; import jpcsp.HLE.HLELogging; import jpcsp.HLE.HLEModule; import jpcsp.HLE.HLEUnimplemented; import jpcsp.HLE.TPointer; import jpcsp.HLE.TPointer32; import org.apache.log4j.Logger; import com.xuggle.mediatool.IMediaReader; import com.xuggle.mediatool.MediaListenerAdapter; import com.xuggle.mediatool.ToolFactory; import com.xuggle.mediatool.event.IVideoPictureEvent; import com.xuggle.xuggler.ICodec; import com.xuggle.xuggler.IContainer; import com.xuggle.xuggler.IContainerFormat; import com.xuggle.xuggler.IPixelFormat.Type; import com.xuggle.xuggler.IStream; import com.xuggle.xuggler.IStreamCoder; import com.xuggle.xuggler.IVideoPicture; import com.xuggle.xuggler.IVideoResampler; import com.xuggle.xuggler.video.ConverterFactory; import com.xuggle.xuggler.video.IConverter; import jpcsp.Emulator; import jpcsp.HLE.Modules; import jpcsp.HLE.kernel.types.SceKernelErrors; import jpcsp.HLE.kernel.types.pspUsbCamSetupMicExParam; import jpcsp.HLE.kernel.types.pspUsbCamSetupMicParam; import jpcsp.HLE.kernel.types.pspUsbCamSetupStillExParam; import jpcsp.HLE.kernel.types.pspUsbCamSetupStillParam; import jpcsp.HLE.kernel.types.pspUsbCamSetupVideoExParam; import jpcsp.HLE.kernel.types.pspUsbCamSetupVideoParam; import jpcsp.memory.IMemoryWriter; import jpcsp.memory.MemoryWriter; public class sceUsbCam extends HLEModule { public static Logger log = Modules.getLogger("sceUsbCam"); private static final boolean dumpJpeg = false; public static final int PSP_USBCAM_PID = 0x282; public static final String PSP_USBCAM_DRIVERNAME = "USBCamDriver"; public static final String PSP_USBCAMMIC_DRIVERNAME = "USBCamMicDriver"; /** Resolutions for sceUsbCamSetupStill & sceUsbCamSetupVideo ** DO NOT use on sceUsbCamSetupStillEx & sceUsbCamSetupVideoEx */ public static final int PSP_USBCAM_RESOLUTION_160_120 = 0; public static final int PSP_USBCAM_RESOLUTION_176_144 = 1; public static final int PSP_USBCAM_RESOLUTION_320_240 = 2; public static final int PSP_USBCAM_RESOLUTION_352_288 = 3; public static final int PSP_USBCAM_RESOLUTION_640_480 = 4; public static final int PSP_USBCAM_RESOLUTION_1024_768 = 5; public static final int PSP_USBCAM_RESOLUTION_1280_960 = 6; public static final int PSP_USBCAM_RESOLUTION_480_272 = 7; public static final int PSP_USBCAM_RESOLUTION_360_272 = 8; protected static final int[] resolutionWidth = new int[] { 160, 176, 320, 352, 640, 1024, 1280, 480, 360 }; protected static final int[] resolutionHeight = new int[] { 120, 144, 240, 288, 480, 768, 960, 272, 272 }; /** Resolutions for sceUsbCamSetupStillEx & sceUsbCamSetupVideoEx ** DO NOT use on sceUsbCamSetupStill & sceUsbCamSetupVideo */ public static final int PSP_USBCAM_RESOLUTION_EX_160_120 = 0; public static final int PSP_USBCAM_RESOLUTION_EX_176_144 = 1; public static final int PSP_USBCAM_RESOLUTION_EX_320_240 = 2; public static final int PSP_USBCAM_RESOLUTION_EX_352_288 = 3; public static final int PSP_USBCAM_RESOLUTION_EX_360_272 = 4; public static final int PSP_USBCAM_RESOLUTION_EX_480_272 = 5; public static final int PSP_USBCAM_RESOLUTION_EX_640_480 = 6; public static final int PSP_USBCAM_RESOLUTION_EX_1024_768 = 7; public static final int PSP_USBCAM_RESOLUTION_EX_1280_960 = 8; /** Flags for reverse effects. */ public static final int PSP_USBCAM_FLIP = 1; public static final int PSP_USBCAM_MIRROR = 0x100; /** Delay to take pictures */ public static final int PSP_USBCAM_NODELAY = 0; public static final int PSP_USBCAM_DELAY_10SEC = 1; public static final int PSP_USBCAM_DELAY_20SEC = 2; public static final int PSP_USBCAM_DELAY_30SEC = 3; /** Usbcam framerates */ public static final int PSP_USBCAM_FRAMERATE_3_75_FPS = 0; /* 3.75 fps */ public static final int PSP_USBCAM_FRAMERATE_5_FPS = 1; public static final int PSP_USBCAM_FRAMERATE_7_5_FPS = 2; /* 7.5 fps */ public static final int PSP_USBCAM_FRAMERATE_10_FPS = 3; public static final int PSP_USBCAM_FRAMERATE_15_FPS = 4; public static final int PSP_USBCAM_FRAMERATE_20_FPS = 5; public static final int PSP_USBCAM_FRAMERATE_30_FPS = 6; public static final int PSP_USBCAM_FRAMERATE_60_FPS = 7; /** White balance values */ public static final int PSP_USBCAM_WB_AUTO = 0; public static final int PSP_USBCAM_WB_DAYLIGHT = 1; public static final int PSP_USBCAM_WB_FLUORESCENT = 2; public static final int PSP_USBCAM_WB_INCADESCENT = 3; /** Effect modes */ public static final int PSP_USBCAM_EFFECTMODE_NORMAL = 0; public static final int PSP_USBCAM_EFFECTMODE_NEGATIVE = 1; public static final int PSP_USBCAM_EFFECTMODE_BLACKWHITE = 2; public static final int PSP_USBCAM_EFFECTMODE_SEPIA = 3; public static final int PSP_USBCAM_EFFECTMODE_BLUE = 4; public static final int PSP_USBCAM_EFFECTMODE_RED = 5; public static final int PSP_USBCAM_EFFECTMODE_GREEN = 6; /** Exposure levels */ public static final int PSP_USBCAM_EVLEVEL_2_0_POSITIVE = 0; // +2.0 public static final int PSP_USBCAM_EVLEVEL_1_7_POSITIVE = 1; // +1.7 public static final int PSP_USBCAM_EVLEVEL_1_5_POSITIVE = 2; // +1.5 public static final int PSP_USBCAM_EVLEVEL_1_3_POSITIVE = 3; // +1.3 public static final int PSP_USBCAM_EVLEVEL_1_0_POSITIVE = 4; // +1.0 public static final int PSP_USBCAM_EVLEVEL_0_7_POSITIVE = 5; // +0.7 public static final int PSP_USBCAM_EVLEVEL_0_5_POSITIVE = 6; // +0.5 public static final int PSP_USBCAM_EVLEVEL_0_3_POSITIVE = 7; // +0.3 public static final int PSP_USBCAM_EVLEVEL_0_0 = 8; // 0.0 public static final int PSP_USBCAM_EVLEVEL_0_3_NEGATIVE = 9; // -0.3 public static final int PSP_USBCAM_EVLEVEL_0_5_NEGATIVE = 10; // -0.5 public static final int PSP_USBCAM_EVLEVEL_0_7_NEGATIVE = 11; // -0.7 public static final int PSP_USBCAM_EVLEVEL_1_0_NEGATIVE = 12; // -1.0 public static final int PSP_USBCAM_EVLEVEL_1_3_NEGATIVE = 13; // -1.3 public static final int PSP_USBCAM_EVLEVEL_1_5_NEGATIVE = 14; // -1.5 public static final int PSP_USBCAM_EVLEVEL_1_7_NEGATIVE = 15; // -1.7 public static final int PSP_USBCAM_EVLEVEL_2_0_NEGATIVE = 16; // -2.0 protected int workArea; protected int workAreaSize; protected TPointer jpegBuffer; protected int jpegBufferSize; protected BufferedImage currentVideoImage; protected byte[] currentVideoImageBytes; protected int currentVideoFrameCount; protected int lastVideoFrameCount; protected VideoListener videoListener; // Camera settings protected int resolution; // One of PSP_USBCAM_RESOLUTION_* (not PSP_USBCAM_RESOLUTION_EX_*) protected int frameRate; protected int whiteBalance; protected int frameSize; protected int saturation; protected int brightness; protected int contrast; protected int sharpness; protected int imageEffectMode; protected int evLevel; protected boolean flip; protected boolean mirror; protected int zoom; protected boolean autoImageReverseSW; protected boolean lensDirectionAtYou; protected int micFrequency; protected int micGain; protected TPointer readMicBuffer; protected int readMicBufferSize; protected class VideoListener extends MediaListenerAdapter { IMediaReader reader; int videoStream; IStreamCoder videoCoder; IConverter videoConverter; IVideoResampler videoResampler; IVideoPicture videoPicture; VideoReaderThread videoReaderThread; public VideoListener(IMediaReader reader, int width, int height) { this.reader = reader; IContainer container = reader.getContainer(); int numStreams = container.getNumStreams(); for (int i = 0; i < numStreams; i++) { IStream stream = container.getStream(i); IStreamCoder coder = stream.getStreamCoder(); if (coder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO) { videoStream = i; videoCoder = coder; } } if (videoCoder != null) { videoConverter = ConverterFactory.createConverter(ConverterFactory.XUGGLER_BGR_24, videoCoder.getPixelType(), videoCoder.getWidth(), videoCoder.getHeight()); videoPicture = IVideoPicture.make(videoCoder.getPixelType(), width, height); videoResampler = IVideoResampler.make(width, height, videoCoder.getPixelType(), videoCoder.getWidth(), videoCoder.getHeight(), videoCoder.getPixelType()); } videoReaderThread = new VideoReaderThread(reader); videoReaderThread.setName("Video Reader Thread"); videoReaderThread.setDaemon(true); videoReaderThread.start(); } public void stop() { videoReaderThread.end(); } @Override public void onVideoPicture(IVideoPictureEvent event) { BufferedImage image = event.getImage(); if (image == null && videoConverter != null) { IVideoPicture eventPicture = event.getPicture(); videoResampler.resample(videoPicture, eventPicture); try { image = videoConverter.toImage(videoPicture); } catch (RuntimeException e) { if (videoPicture.getPixelType() == Type.YUYV422) { image = convertYUYV422toRGB(videoPicture.getWidth(), videoPicture.getHeight(), videoPicture.getByteBuffer()); } else { log.error(String.format("VideoListener.onVideoPicture: %s", videoPicture), e); } } } if (log.isDebugEnabled()) { log.debug(String.format("onVideoPicture event=%s, image=%s", event, image)); } if (image != null) { setCurrentVideoImage(image); } } } protected class VideoReaderThread extends Thread { private IMediaReader reader; private volatile boolean end; public VideoReaderThread(IMediaReader reader) { this.reader = reader; } public void end() { end = true; } @Override public void run() { while (!end) { reader.readPacket(); } reader.close(); } } // Faked video reading protected long lastVideoFrameMillis; protected static final int[] framerateFrameDurationMillis = new int[] { 267, // PSP_USBCAM_FRAMERATE_3_75_FPS 200, // PSP_USBCAM_FRAMERATE_5_FPS 133, // PSP_USBCAM_FRAMERATE_7_5_FPS 100, // PSP_USBCAM_FRAMERATE_10_FPS 67, // PSP_USBCAM_FRAMERATE_15_FPS 50, // PSP_USBCAM_FRAMERATE_20_FPS 33, // PSP_USBCAM_FRAMERATE_30_FPS 17 // PSP_USBCAM_FRAMERATE_60_FPS }; protected static int convertYUVtoRGB(int y, int u, int v) { // based on http://en.wikipedia.org/wiki/Yuv#Y.27UV444_to_RGB888_conversion int c = y - 16; int d = u - 128; int e = v - 128; int r = clamp8bit((298 * c + 409 * e + 128) >> 8); int g = clamp8bit((298 * c - 100 * d - 208 * e + 128) >> 8); int b = clamp8bit((298 * c + 516 * d + 128) >> 8); return (r << 16) | (g << 8) | b; } protected BufferedImage convertYUYV422toRGB(int width, int height, ByteBuffer buffer) { byte[] input = new byte[width * height * 2]; buffer.get(input); int[] output = new int[width * height]; int i = 0; int j = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x += 2) { int y0 = input[i++] & 0xFF; int u = input[i++] & 0xFF; int y1 = input[i++] & 0xFF; int v = input[i++] & 0xFF; output[j++] = convertYUVtoRGB(y0, u, v); output[j++] = convertYUVtoRGB(y1, u, v); } } BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); image.setRGB(0, 0, width, height, output, 0, width); if ((currentVideoFrameCount % 30) == 0) { int imageIndex = currentVideoFrameCount / 30; try { OutputStream os = new FileOutputStream(String.format("tmp/UsbCam-%d.yuyv422", imageIndex)); os.write(input); os.close(); } catch (IOException e) { log.error("dumping yuyv422 image", e); } } return image; } /** * Convert a value PSP_USBCAM_RESOLUTION_EX_* * to the corresponding PSP_USBCAM_RESOLUTION_* * * @param resolutionEx One of PSP_USBCAM_RESOLUTION_EX_* * @return The corresponding value PSP_USBCAM_RESOLUTION_* */ protected int convertResolutionExToResolution(int resolutionEx) { switch(resolutionEx) { case PSP_USBCAM_RESOLUTION_EX_160_120: return PSP_USBCAM_RESOLUTION_160_120; case PSP_USBCAM_RESOLUTION_EX_176_144: return PSP_USBCAM_RESOLUTION_176_144; case PSP_USBCAM_RESOLUTION_EX_320_240: return PSP_USBCAM_RESOLUTION_320_240; case PSP_USBCAM_RESOLUTION_EX_352_288: return PSP_USBCAM_RESOLUTION_352_288; case PSP_USBCAM_RESOLUTION_EX_360_272: return PSP_USBCAM_RESOLUTION_360_272; case PSP_USBCAM_RESOLUTION_EX_480_272: return PSP_USBCAM_RESOLUTION_480_272; case PSP_USBCAM_RESOLUTION_EX_640_480: return PSP_USBCAM_RESOLUTION_640_480; case PSP_USBCAM_RESOLUTION_EX_1024_768: return PSP_USBCAM_RESOLUTION_1024_768; case PSP_USBCAM_RESOLUTION_EX_1280_960: return PSP_USBCAM_RESOLUTION_1280_960; } return resolutionEx; } protected int getFramerateFrameDurationMillis() { if (frameRate < 0 || frameRate > PSP_USBCAM_FRAMERATE_60_FPS) { return framerateFrameDurationMillis[PSP_USBCAM_FRAMERATE_60_FPS]; } return framerateFrameDurationMillis[frameRate]; } private void stopVideo() { if (videoListener != null) { videoListener.stop(); videoListener = null; } } @Override public void stop() { stopVideo(); super.stop(); } protected static int getResolutionWidth(int resolution) { if (resolution < 0 || resolution >= resolutionWidth.length) { return 0; } return resolutionWidth[resolution]; } protected static int getResolutionHeight(int resolution) { if (resolution < 0 || resolution >= resolutionHeight.length) { return 0; } return resolutionHeight[resolution]; } protected boolean setupVideo() { if (videoListener != null) { return true; } IContainer container = IContainer.make(); IContainerFormat format = IContainerFormat.make(); int ret = format.setInputFormat("vfwcap"); if (ret < 0) { container.close(); format.delete(); log.error(String.format("USB Cam: cannot open WebCam ('vfwcap' device)")); return false; } ret = container.open("0", IContainer.Type.READ, format); if (ret < 0) { container.close(); format.delete(); log.error(String.format("USB Cam: cannot open WebCam ('0')")); return false; } IMediaReader reader = ToolFactory.makeReader(container); videoListener = new VideoListener(reader, getResolutionWidth(resolution), getResolutionHeight(resolution)); reader.addListener(videoListener); return true; } protected void setCurrentVideoImage(BufferedImage image) { byte[] newVideoImageBytes = null; if (image != null) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(jpegBufferSize); try { if (ImageIO.write(image, "jpeg", outputStream)) { outputStream.close(); newVideoImageBytes = outputStream.toByteArray(); if (dumpJpeg) { FileOutputStream dumpFile = new FileOutputStream("dumpUsbCam.jpeg"); dumpFile.write(newVideoImageBytes); dumpFile.close(); } } } catch (IOException e) { log.error("setCurrentVideoImage", e); } currentVideoFrameCount++; } currentVideoImage = image; currentVideoImageBytes = newVideoImageBytes; } public BufferedImage getCurrentVideoImage() { return currentVideoImage; } private int getCurrentVideoImageSize() { if (currentVideoImageBytes == null) { return jpegBufferSize; } return currentVideoImageBytes.length; } public int writeCurrentVideoImage(TPointer jpegBuffer, int jpegBufferSize) { lastVideoFrameCount = currentVideoFrameCount; if (currentVideoImageBytes == null) { if (jpegBuffer == null) { return 0; } // Image has to be stored in Jpeg format in buffer jpegBuffer.clear(jpegBufferSize); return jpegBufferSize; } int length = Math.min(currentVideoImageBytes.length, jpegBufferSize); IMemoryWriter memoryWriter = MemoryWriter.getMemoryWriter(jpegBuffer.getAddress(), length, 1); for (int i = 0; i < length; i++) { memoryWriter.writeNext(currentVideoImageBytes[i] & 0xFF); } memoryWriter.flush(); return length; } private void waitForNextVideoFrame() { long now = Emulator.getClock().currentTimeMillis(); int millisSinceLastFrame = (int) (now - lastVideoFrameMillis); int frameDurationMillis = getFramerateFrameDurationMillis(); if (millisSinceLastFrame >= 0 && millisSinceLastFrame < frameDurationMillis) { int delayMillis = frameDurationMillis - millisSinceLastFrame; Modules.ThreadManForUserModule.hleKernelDelayThread(delayMillis * 1000, false); lastVideoFrameMillis = now + delayMillis; } else { lastVideoFrameMillis = now; } } /** * Set ups the parameters for video capture. * * @param param - Pointer to a pspUsbCamSetupVideoParam structure. * @param workarea - Pointer to a buffer used as work area by the driver. * @param wasize - Size of the work area. * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x17F7B2FB, version = 271) public int sceUsbCamSetupVideo(pspUsbCamSetupVideoParam usbCamSetupVideoParam, TPointer workArea, int workAreaSize) { this.workArea = workArea.getAddress(); this.workAreaSize = workAreaSize; resolution = usbCamSetupVideoParam.resolution; frameRate = usbCamSetupVideoParam.framerate; whiteBalance = usbCamSetupVideoParam.wb; saturation = usbCamSetupVideoParam.saturation; brightness = usbCamSetupVideoParam.brightness; contrast = usbCamSetupVideoParam.contrast; sharpness = usbCamSetupVideoParam.sharpness; imageEffectMode = usbCamSetupVideoParam.effectmode; frameSize = usbCamSetupVideoParam.framesize; evLevel = usbCamSetupVideoParam.evlevel; if (!setupVideo()) { log.warn(String.format("Cannot find webcam")); return SceKernelErrors.ERROR_USBCAM_NOT_READY; } return 0; } /** * Sets if the image should be automatically reversed, depending of the position * of the camera. * * @param on - 1 to set the automatical reversal of the image, 0 to set it off * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0xF93C4669, version = 271) public int sceUsbCamAutoImageReverseSW(boolean on) { autoImageReverseSW = on; return 0; } /** * Starts video input from the camera. * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x574A8C3F, version = 271) public int sceUsbCamStartVideo() { if (!setupVideo()) { log.warn(String.format("Cannot find webcam")); } return 0; } /** * Stops video input from the camera. * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x6CF32CB9, version = 271) public int sceUsbCamStopVideo() { // No parameters stopVideo(); return 0; } @HLEFunction(nid = 0x03ED7A82, version = 271) public int sceUsbCamSetupMic(pspUsbCamSetupMicParam camSetupMicParam, TPointer workArea, int workAreaSize) { micFrequency = camSetupMicParam.frequency; micGain = camSetupMicParam.gain; return 0; } @HLELogging(level="info") @HLEFunction(nid = 0x82A64030, version = 271) public int sceUsbCamStartMic() { return 0; } /** * Reads a video frame. The function doesn't return until the frame * has been acquired. * * @param buf - The buffer that receives the frame jpeg data * @param size - The size of the buffer. * * @return size of acquired frame on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x7DAC0C71, version = 271) public int sceUsbCamReadVideoFrameBlocking(TPointer jpegBuffer, int jpegBufferSize) { this.jpegBuffer = jpegBuffer; this.jpegBufferSize = jpegBufferSize; waitForNextVideoFrame(); return writeCurrentVideoImage(jpegBuffer, jpegBufferSize); } /** * Reads a video frame. The function returns immediately, and * the completion has to be handled by calling sceUsbCamWaitReadVideoFrameEnd * or sceUsbCamPollReadVideoFrameEnd. * * @param buf - The buffer that receives the frame jpeg data * @param size - The size of the buffer. * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x99D86281, version = 271) public int sceUsbCamReadVideoFrame(TPointer jpegBuffer, int jpegBufferSize) { this.jpegBuffer = jpegBuffer; this.jpegBufferSize = jpegBufferSize; return writeCurrentVideoImage(jpegBuffer, jpegBufferSize); } /** * Polls the status of video frame read completion. * * @return the size of the acquired frame if it has been read, * 0 if the frame has not yet been read, < 0 on error. */ @HLEUnimplemented @HLEFunction(nid = 0x41E73E95, version = 271) public int sceUsbCamPollReadVideoFrameEnd() { if (jpegBuffer == null || jpegBuffer.isNull()) { return SceKernelErrors.ERROR_USBCAM_NO_READ_ON_VIDEO_FRAME; } if (currentVideoFrameCount <= lastVideoFrameCount) { if (log.isDebugEnabled()) { log.debug(String.format("sceUsbCamPollReadVideoFrameEnd not frame end (%d - %d)", currentVideoFrameCount, lastVideoFrameCount)); } return SceKernelErrors.ERROR_USBCAM_NO_VIDEO_FRAME_AVAILABLE; } return writeCurrentVideoImage(jpegBuffer, jpegBufferSize); } /** * Waits until the current frame has been read. * * @return the size of the acquired frame on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0xF90B2293, version = 271) public int sceUsbCamWaitReadVideoFrameEnd() { waitForNextVideoFrame(); return getCurrentVideoImageSize(); } /** * Gets the direction of the camera lens * * @return 1 if the camera is "looking to you", 0 if the camera * is "looking to the other side". */ @HLEUnimplemented @HLEFunction(nid = 0x4C34F553, version = 271) public boolean sceUsbCamGetLensDirection() { return lensDirectionAtYou; } /** * Setups the parameters to take a still image. * * @param param - pointer to a pspUsbCamSetupStillParam * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x3F0CF289, version = 271) public int sceUsbCamSetupStill(pspUsbCamSetupStillParam usbCamSetupStillParam) { return 0; } /** * Setups the parameters to take a still image (with more options) * * @param param - pointer to a pspUsbCamSetupStillParamEx * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x0A41A298, version = 271) public int sceUsbCamSetupStillEx(pspUsbCamSetupStillExParam usbCamSetupStillExParam) { return 0; } /** * Gets a still image. The function doesn't return until the image * has been acquired. * * @param buf - The buffer that receives the image jpeg data * @param size - The size of the buffer. * * @return size of acquired image on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x61BE5CAC, version = 271) public int sceUsbCamStillInputBlocking(TPointer buffer, int size) { return 0; } /** * Gets a still image. The function returns immediately, and * the completion has to be handled by calling ::sceUsbCamStillWaitInputEnd * or ::sceUsbCamStillPollInputEnd. * * @param buf - The buffer that receives the image jpeg data * @param size - The size of the buffer. * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0xFB0A6C5D, version = 271) public int sceUsbCamStillInput(TPointer buffer, int size) { return 0; } /** * Waits until still input has been finished. * * @return the size of the acquired image on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x7563AFA1, version = 271) public int sceUsbCamStillWaitInputEnd() { return 0; } /** * Polls the status of still input completion. * * @return the size of the acquired image if still input has ended, * 0 if the input has not ended, < 0 on error. */ @HLEUnimplemented @HLEFunction(nid = 0x1A46CFE7, version = 271) public int sceUsbCamStillPollInputEnd() { return 0; } /** * Cancels the still input. * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0xA720937C, version = 271) public int sceUsbCamStillCancelInput() { return 0; } /** * Gets the size of the acquired still image. * * @return the size of the acquired image on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0xE5959C36, version = 271) public int sceUsbCamStillGetInputLength() { return 0; } /** * Set ups the parameters for video capture (with more options) * * @param param - Pointer to a pspUsbCamSetupVideoExParam structure. * @param workarea - Pointer to a buffer used as work area by the driver. * @param wasize - Size of the work area. * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0xCFE9E999, version = 271) public int sceUsbCamSetupVideoEx(pspUsbCamSetupVideoExParam usbCamSetupVideoExParam, TPointer workArea, int workAreaSize) { this.workArea = workArea.getAddress(); this.workAreaSize = workAreaSize; resolution = convertResolutionExToResolution(usbCamSetupVideoExParam.resolution); frameRate = usbCamSetupVideoExParam.framerate; whiteBalance = usbCamSetupVideoExParam.wb; saturation = usbCamSetupVideoExParam.saturation; brightness = usbCamSetupVideoExParam.brightness; contrast = usbCamSetupVideoExParam.contrast; sharpness = usbCamSetupVideoExParam.sharpness; imageEffectMode = usbCamSetupVideoExParam.effectmode; frameSize = usbCamSetupVideoExParam.framesize; evLevel = usbCamSetupVideoExParam.evlevel; if (!setupVideo()) { log.warn(String.format("Cannot find webcam")); return SceKernelErrors.ERROR_USBCAM_NOT_READY; } return 0; } /** * Gets the size of the acquired frame. * * @return the size of the acquired frame on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0xDF9D0C92, version = 271) public int sceUsbCamGetReadVideoFrameSize() { return jpegBufferSize; } /** * Sets the saturation * * @param saturation - The saturation (0-255) * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x6E205974, version = 271) public int sceUsbCamSetSaturation(int saturation) { this.saturation = saturation; return 0; } /** * Sets the brightness * * @param brightness - The brightness (0-255) * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x4F3D84D5, version = 271) public int sceUsbCamSetBrightness(int brightness) { this.brightness = brightness; return 0; } /** * Sets the contrast * * @param contrast - The contrast (0-255) * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x09C26C7E, version = 271) public int sceUsbCamSetContrast(int contrast) { this.contrast = contrast; return 0; } /** * Sets the sharpness * * @param sharpness - The sharpness (0-255) * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x622F83CC, version = 271) public int sceUsbCamSetSharpness(int sharpness) { this.sharpness = sharpness; return 0; } /** * Sets the image effect mode * * @param effectmode - The effect mode, one of ::PspUsbCamEffectMode * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0xD4876173, version = 271) public int sceUsbCamSetImageEffectMode(int imageEffectMode) { this.imageEffectMode = imageEffectMode; return 0; } /** * Sets the exposure level * * @param ev - The exposure level, one of ::PspUsbCamEVLevel * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x1D686870, version = 271) public int sceUsbCamSetEvLevel(int evLevel) { this.evLevel = evLevel; return 0; } /** * Sets the reverse mode * * @param reverseflags - The reverse flags, zero or more of ::PspUsbCamReverseFlags * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x951BEDF5, version = 271) public int sceUsbCamSetReverseMode(int reverseMode) { this.flip = (reverseMode & PSP_USBCAM_FLIP) != 0; this.mirror = (reverseMode & PSP_USBCAM_MIRROR) != 0; return 0; } /** * Sets the zoom. * * @param zoom - The zoom level starting by 10. (10 = 1X, 11 = 1.1X, etc) * * @returns 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0xC484901F, version = 271) public int sceUsbCamSetZoom(int zoom) { this.zoom = zoom; return 0; } /** * Gets the current saturation * * @param saturation - pointer to a variable that receives the current saturation * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x383E9FA8, version = 271) public int sceUsbCamGetSaturation(TPointer32 saturationAddr) { saturationAddr.setValue(saturation); return 0; } /** * Gets the current brightness * * @param brightness - pointer to a variable that receives the current brightness * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x70F522C5, version = 271) public int sceUsbCamGetBrightness(TPointer32 brightnessAddr) { brightnessAddr.setValue(brightness); return 0; } /** * Gets the current contrast * * @param contrast - pointer to a variable that receives the current contrast * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0xA063A957, version = 271) public int sceUsbCamGetContrast(TPointer32 contrastAddr) { contrastAddr.setValue(contrast); return 0; } /** * Gets the current sharpness * * @param brightness - pointer to a variable that receives the current sharpness * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0xFDB68C23, version = 271) public int sceUsbCamGetSharpness(TPointer32 sharpnessAddr) { sharpnessAddr.setValue(sharpness); return 0; } /** * Gets the current image efect mode * * @param effectmode - pointer to a variable that receives the current effect mode * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x994471E0, version = 271) public int sceUsbCamGetImageEffectMode(TPointer32 imageEffectModeAddr) { imageEffectModeAddr.setValue(imageEffectMode); return 0; } /** * Gets the current exposure level. * * @param ev - pointer to a variable that receives the current exposure level * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x2BCD50C0, version = 271) public int sceUsbCamGetEvLevel(TPointer32 evLevelAddr) { evLevelAddr.setValue(evLevel); return 0; } /** * Gets the current reverse mode. * * @param reverseflags - pointer to a variable that receives the current reverse mode flags * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0xD5279339, version = 271) public int sceUsbCamGetReverseMode(TPointer32 reverseModeAddr) { int reverseMode = 0; if (mirror) { reverseMode |= PSP_USBCAM_MIRROR; } if (flip) { reverseMode |= PSP_USBCAM_FLIP; } reverseModeAddr.setValue(reverseMode); return 0; } /** * Gets the current zoom. * * @param zoom - pointer to a variable that receives the current zoom * * @return 0 on success, < 0 on error */ @HLEUnimplemented @HLEFunction(nid = 0x9E8AAF8D, version = 271) public int sceUsbCamGetZoom(TPointer32 zoomAddr) { zoomAddr.setValue(zoom); return 0; } /** * Gets the state of the autoreversal of the image. * * @return 1 if it is set to automatic, 0 otherwise */ @HLEUnimplemented @HLEFunction(nid = 0x11A1F128, version = 271) public boolean sceUsbCamGetAutoImageReverseState() { return autoImageReverseSW; } @HLEUnimplemented @HLEFunction(nid = 0x08AEE98A, version = 271) public int sceUsbCamSetMicGain() { return 0; } @HLEUnimplemented @HLEFunction(nid = 0x2E930264, version = 271) public int sceUsbCamSetupMicEx(pspUsbCamSetupMicExParam camSetupMicExParam, TPointer workArea, int workAreaSize) { micFrequency = camSetupMicExParam.frequency; micGain = camSetupMicExParam.gain; return 0; } @HLEFunction(nid = 0x36636925, version = 271) public int sceUsbCamReadMicBlocking(TPointer buffer, int bufferSize) { return Modules.sceAudioModule.hleAudioInputBlocking(bufferSize >> 1, micFrequency, buffer); } @HLEUnimplemented @HLEFunction(nid = 0x3DC0088E, version = 271) public int sceUsbCamReadMic(TPointer buffer, int bufferSize) { readMicBuffer = buffer; readMicBufferSize = bufferSize; buffer.clear(bufferSize); return 0; } @HLEUnimplemented @HLEFunction(nid = 0x41EE8797, version = 271) public int sceUsbCamUnregisterLensRotationCallback() { return 0; } @HLEFunction(nid = 0x5145868A, version = 271) public int sceUsbCamStopMic() { return 0; } @HLEUnimplemented @HLEFunction(nid = 0x5778B452, version = 271) public int sceUsbCamGetMicDataLength() { return readMicBufferSize; } @HLEUnimplemented @HLEFunction(nid = 0x6784E6A8, version = 271) public int sceUsbCamSetAntiFlicker() { return 0; } @HLEUnimplemented @HLEFunction(nid = 0xAA7D94BA, version = 271) public int sceUsbCamGetAntiFlicker() { return 0; } @HLEUnimplemented @HLEFunction(nid = 0xB048A67D, version = 271) public int sceUsbCamWaitReadMicEnd() { return Modules.sceAudioModule.hleAudioInputBlocking(readMicBufferSize >> 1, micFrequency, readMicBuffer); } @HLEUnimplemented @HLEFunction(nid = 0xD293A100, version = 271) public int sceUsbCamRegisterLensRotationCallback() { return 0; } @HLEUnimplemented @HLEFunction(nid = 0xF8847F60, version = 271) public int sceUsbCamPollReadMicEnd() { return 0; } @HLEUnimplemented @HLEFunction(nid = 0x1E958148, version = 271) public int sceUsbCamIoctl() { return 0; } @HLEUnimplemented @HLEFunction(nid = 0x00631D06, version = 271) public int sceUsbCam_00631D06() { return 0; } }