2013-05-15 11:49:34 +00:00
|
|
|
// Copyright (c) 2012- PPSSPP Project.
|
|
|
|
|
|
|
|
// This program 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, version 2.0 or later versions.
|
|
|
|
|
|
|
|
// This program 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 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// Official git repository and contact information can be found at
|
|
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
|
2013-05-20 00:54:14 +00:00
|
|
|
#include "Core/HLE/HLE.h"
|
|
|
|
#include "Core/Reporting.h"
|
2013-07-04 09:55:06 +00:00
|
|
|
#include "Common.h"
|
2013-07-04 19:56:20 +00:00
|
|
|
#include "native/ext/cityhash/city.h"
|
2013-07-04 22:08:21 +00:00
|
|
|
#include "native/ext/jpge/jpgd.h"
|
2013-05-15 11:49:34 +00:00
|
|
|
|
2013-07-05 08:55:57 +00:00
|
|
|
static int mjpegWidth, mjpegHeight;
|
|
|
|
|
|
|
|
void __JpegInit() {
|
|
|
|
mjpegWidth = 0;
|
|
|
|
mjpegHeight = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void __JpegDoState(PointerWrap &p) {
|
|
|
|
p.Do(mjpegWidth);
|
|
|
|
p.Do(mjpegHeight);
|
|
|
|
p.DoMarker("sceJpeg");
|
|
|
|
}
|
2013-07-04 09:55:06 +00:00
|
|
|
|
|
|
|
//Uncomment if you want to dump JPEGs loaded through sceJpeg to a file
|
|
|
|
//#define JPEG_DEBUG
|
2013-05-15 11:49:34 +00:00
|
|
|
|
|
|
|
int sceJpegDecompressAllImage()
|
|
|
|
{
|
2013-07-04 21:51:32 +00:00
|
|
|
ERROR_LOG_REPORT(HLE, "UNIMPL sceJpegDecompressAllImage()");
|
2013-05-15 11:49:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-04 21:51:32 +00:00
|
|
|
int sceJpegMJpegCsc(u32 imageAddr, u32 yCbCrAddr, int widthHeight, int bufferWidth)
|
2013-05-15 11:49:34 +00:00
|
|
|
{
|
2013-07-04 21:51:32 +00:00
|
|
|
ERROR_LOG_REPORT(HLE, "UNIMPL sceJpegMJpegCsc(%i, %i, %i, %i)", imageAddr, yCbCrAddr, widthHeight, bufferWidth);
|
2013-05-15 11:49:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-04 21:51:32 +00:00
|
|
|
int sceJpegDecodeMJpeg(u32 jpegAddr, int jpegSize, u32 imageAddr, int dhtMode)
|
2013-05-15 11:49:34 +00:00
|
|
|
{
|
2013-07-04 21:51:32 +00:00
|
|
|
ERROR_LOG_REPORT(HLE, "UNIMPL sceJpegDecodeMJpeg(%i, %i, %i, %i)", jpegAddr, jpegSize, imageAddr, dhtMode);
|
2013-05-15 11:49:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-04 21:51:32 +00:00
|
|
|
int sceJpegDecodeMJpegYCbCrSuccessively(u32 jpegAddr, int jpegSize, u32 yCbCrAddr, int yCbCrSize, int dhtMode)
|
2013-05-15 11:49:34 +00:00
|
|
|
{
|
2013-07-04 21:51:32 +00:00
|
|
|
ERROR_LOG_REPORT(HLE, "UNIMPL sceJpegDecodeMJpegYCbCrSuccessively(%i, %i, %i, %i, %i)", jpegAddr, jpegSize, yCbCrAddr, yCbCrSize, dhtMode);
|
2013-05-15 11:49:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sceJpegDeleteMJpeg()
|
|
|
|
{
|
2013-07-04 21:51:32 +00:00
|
|
|
ERROR_LOG_REPORT(HLE, "UNIMPL sceJpegDeleteMJpeg()");
|
2013-05-15 11:49:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-04 21:51:32 +00:00
|
|
|
int sceJpegDecodeMJpegSuccessively(u32 jpegAddr, int jpegSize, u32 imageAddr, int dhtMode)
|
2013-05-15 11:49:34 +00:00
|
|
|
{
|
2013-07-04 21:51:32 +00:00
|
|
|
ERROR_LOG_REPORT(HLE, "UNIMPL sceJpegDecodeMJpegSuccessively(%i, %i, %i, %i)", jpegAddr, jpegSize, imageAddr, dhtMode);
|
2013-05-15 11:49:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-04 21:51:32 +00:00
|
|
|
int sceJpegCsc(u32 imageAddr, u32 yCbCrAddr, int widthHeight, int bufferWidth, int colourInfo)
|
2013-05-15 11:49:34 +00:00
|
|
|
{
|
2013-07-04 21:51:32 +00:00
|
|
|
ERROR_LOG_REPORT(HLE, "UNIMPL sceJpegCsc(%i, %i, %i, %i, %i)", imageAddr, yCbCrAddr, widthHeight, bufferWidth, colourInfo);
|
2013-05-15 11:49:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sceJpegFinishMJpeg()
|
|
|
|
{
|
2013-07-04 21:51:32 +00:00
|
|
|
ERROR_LOG_REPORT(HLE, "UNIMPL sceJpegFinishMJpeg()");
|
2013-05-15 11:49:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-04 21:51:32 +00:00
|
|
|
int getYCbCrBufferSize(int w, int h)
|
2013-05-15 11:49:34 +00:00
|
|
|
{
|
2013-07-04 09:55:06 +00:00
|
|
|
// Return necessary buffer size for conversion: 12 bits per pixel
|
|
|
|
return ((w * h) >> 1) * 3;
|
2013-05-15 11:49:34 +00:00
|
|
|
}
|
|
|
|
|
2013-07-04 09:55:06 +00:00
|
|
|
int sceJpegGetOutputInfo(u32 jpegAddr, int jpegSize, u32 colourInfoAddr, int dhtMode)
|
2013-05-15 11:49:34 +00:00
|
|
|
{
|
2013-07-04 09:55:06 +00:00
|
|
|
ERROR_LOG_REPORT(HLE, "sceJpegGetOutputInfo(%i, %i, %i, %i)", jpegAddr, jpegSize, colourInfoAddr, dhtMode);
|
|
|
|
|
|
|
|
// Buffer to store info about the color space in use.
|
|
|
|
// - Bits 24 to 32 (Always empty): 0x00
|
|
|
|
// - Bits 16 to 24 (Color mode): 0x00 (Unknown), 0x01 (Greyscale) or 0x02 (YCbCr)
|
|
|
|
// - Bits 8 to 16 (Vertical chroma subsampling value): 0x00, 0x01 or 0x02
|
|
|
|
// - Bits 0 to 8 (Horizontal chroma subsampling value): 0x00, 0x01 or 0x02
|
|
|
|
if (Memory::IsValidAddress(colourInfoAddr))
|
|
|
|
Memory::Write_U32(0x00020202, colourInfoAddr);
|
|
|
|
|
2013-07-04 21:51:32 +00:00
|
|
|
int w = 0, h = 0, actual_components = 0;
|
|
|
|
|
2013-07-04 09:55:06 +00:00
|
|
|
if (!Memory::IsValidAddress(jpegAddr))
|
|
|
|
{
|
|
|
|
ERROR_LOG(HLE, "sceJpegGetOutputInfo: Bad JPEG address 0x%08x", jpegAddr);
|
|
|
|
return 0xC000;
|
|
|
|
}
|
|
|
|
else // Memory address is good
|
|
|
|
{
|
|
|
|
// But data may not be...so check it
|
|
|
|
u8 *buf = Memory::GetPointer(jpegAddr);
|
2013-07-04 21:51:32 +00:00
|
|
|
unsigned char *jpegBuf = jpgd::decompress_jpeg_image_from_memory(buf, jpegSize, &w, &h, &actual_components, 3);
|
|
|
|
if (actual_components != 3)
|
|
|
|
{
|
2013-07-04 21:58:19 +00:00
|
|
|
// The assumption that the image was RGB was wrong...
|
|
|
|
// Try again.
|
2013-07-04 21:51:32 +00:00
|
|
|
int components = actual_components;
|
|
|
|
jpegBuf = jpgd::decompress_jpeg_image_from_memory(buf, jpegSize, &w, &h, &actual_components, components);
|
|
|
|
}
|
|
|
|
if (jpegBuf == NULL)
|
2013-07-04 09:55:06 +00:00
|
|
|
{
|
|
|
|
ERROR_LOG(HLE, "sceJpegGetOutputInfo: Bad JPEG data");
|
|
|
|
return 0xC000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef JPEG_DEBUG
|
|
|
|
char jpeg_fname[256];
|
|
|
|
u8 *jpegBuf = Memory::GetPointer(jpegAddr);
|
|
|
|
uint32 jpeg_cityhash = CityHash32((const char *)jpegBuf, jpegSize);
|
|
|
|
sprintf(jpeg_fname, "Jpeg\\%X.jpg", jpeg_cityhash);
|
|
|
|
FILE *wfp = fopen(jpeg_fname, "wb");
|
|
|
|
fwrite(jpegBuf, 1, jpegSize, wfp);
|
|
|
|
fclose(wfp);
|
|
|
|
#endif //JPEG_DEBUG
|
|
|
|
|
2013-07-04 21:51:32 +00:00
|
|
|
return getYCbCrBufferSize(w, h);
|
2013-07-04 09:55:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int getWidthHeight(int width, int height)
|
|
|
|
{
|
|
|
|
return (width << 16) | height;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sceJpegDecodeMJpegYCbCr(u32 jpegAddr, int jpegSize, u32 yCbCrAddr, int yCbCrSize, int dhtMode)
|
|
|
|
{
|
|
|
|
ERROR_LOG_REPORT(HLE, "sceJpegDecodeMJpegYCbCr(%i, %i, %i, %i, %i)", jpegAddr, jpegSize, yCbCrAddr, yCbCrSize, dhtMode);
|
|
|
|
|
|
|
|
if (!Memory::IsValidAddress(jpegAddr))
|
|
|
|
{
|
|
|
|
return getWidthHeight(0, 0);
|
|
|
|
}
|
|
|
|
|
2013-07-04 21:51:32 +00:00
|
|
|
u8 *buf = Memory::GetPointer(jpegAddr);
|
|
|
|
int width, height, actual_components;
|
|
|
|
unsigned char *jpegBuf = jpgd::decompress_jpeg_image_from_memory(buf, jpegSize, &width, &height, &actual_components, 3);
|
|
|
|
if (actual_components != 3)
|
2013-07-04 09:55:06 +00:00
|
|
|
{
|
2013-07-04 21:58:19 +00:00
|
|
|
// The assumption that the image was RGB was wrong...
|
|
|
|
// Try again.
|
2013-07-04 21:51:32 +00:00
|
|
|
int components = actual_components;
|
|
|
|
jpegBuf = jpgd::decompress_jpeg_image_from_memory(buf, jpegSize, &width, &height, &actual_components, components);
|
2013-07-04 09:55:06 +00:00
|
|
|
}
|
2013-07-04 21:51:32 +00:00
|
|
|
if (jpegBuf == NULL)
|
|
|
|
return getWidthHeight(0, 0);
|
2013-07-04 09:55:06 +00:00
|
|
|
|
|
|
|
// TODO: There's more...
|
|
|
|
|
|
|
|
return getWidthHeight(width, height);
|
2013-05-15 11:49:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int sceJpeg_9B36444C()
|
|
|
|
{
|
2013-07-04 21:51:32 +00:00
|
|
|
ERROR_LOG_REPORT(HLE, "UNIMPL sceJpeg_9B36444C()");
|
2013-05-15 11:49:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-04 09:55:06 +00:00
|
|
|
int sceJpegCreateMJpeg(int width, int height)
|
2013-05-15 11:49:34 +00:00
|
|
|
{
|
2013-07-04 09:55:06 +00:00
|
|
|
ERROR_LOG_REPORT(HLE, "sceJpegCreateMJpeg(%i, %i)", width, height);
|
|
|
|
|
2013-07-05 08:55:57 +00:00
|
|
|
mjpegWidth = width;
|
|
|
|
mjpegHeight = height;
|
2013-07-04 09:55:06 +00:00
|
|
|
|
2013-05-15 11:49:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sceJpegInitMJpeg()
|
|
|
|
{
|
2013-07-04 21:51:32 +00:00
|
|
|
ERROR_LOG_REPORT(HLE, "UNIMPL sceJpegInitMJpeg()");
|
2013-07-04 09:55:06 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sceJpeg_A06A75C4()
|
|
|
|
{
|
2013-07-04 21:51:32 +00:00
|
|
|
ERROR_LOG_REPORT(HLE, "UNIMPL sceJpeg_A06A75C4()");
|
2013-05-15 11:49:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const HLEFunction sceJpeg[] =
|
|
|
|
{
|
|
|
|
{0x0425B986, WrapI_V<sceJpegDecompressAllImage>, "sceJpegDecompressAllImage"},
|
2013-07-04 21:51:32 +00:00
|
|
|
{0x04B5AE02, WrapI_UUII<sceJpegMJpegCsc>, "sceJpegMJpegCsc"},
|
|
|
|
{0x04B93CEF, WrapI_UIUI<sceJpegDecodeMJpeg>, "sceJpegDecodeMJpeg"},
|
|
|
|
{0x227662D7, WrapI_UIUII<sceJpegDecodeMJpegYCbCrSuccessively>, "sceJpegDecodeMJpegYCbCrSuccessively"},
|
2013-05-15 11:49:34 +00:00
|
|
|
{0x48B602B7, WrapI_V<sceJpegDeleteMJpeg>, "sceJpegDeleteMJpeg"},
|
2013-07-04 21:51:32 +00:00
|
|
|
{0x64B6F978, WrapI_UIUI<sceJpegDecodeMJpegSuccessively>, "sceJpegDecodeMJpegSuccessively"},
|
|
|
|
{0x67F0ED84, WrapI_UUIII<sceJpegCsc>, "sceJpegCsc"},
|
2013-05-15 11:49:34 +00:00
|
|
|
{0x7D2F3D7F, WrapI_V<sceJpegFinishMJpeg>, "sceJpegFinishMJpeg"},
|
2013-07-04 09:55:06 +00:00
|
|
|
{0x8F2BB012, WrapI_UIUI<sceJpegGetOutputInfo>, "sceJpegGetOutputInfo"},
|
|
|
|
{0x91EED83C, WrapI_UIUII<sceJpegDecodeMJpegYCbCr>, "sceJpegDecodeMJpegYCbCr"},
|
2013-05-15 11:49:34 +00:00
|
|
|
{0x9B36444C, WrapI_V<sceJpeg_9B36444C>, "sceJpeg_9B36444C"},
|
2013-07-04 09:55:06 +00:00
|
|
|
{0x9D47469C, WrapI_II<sceJpegCreateMJpeg>, "sceJpegCreateMJpeg"},
|
2013-05-15 11:49:34 +00:00
|
|
|
{0xAC9E70E6, WrapI_V<sceJpegInitMJpeg>, "sceJpegInitMJpeg"},
|
2013-07-04 09:55:06 +00:00
|
|
|
{0xa06a75c4, WrapI_V<sceJpeg_A06A75C4>, "sceJpeg_A06A75C4"},
|
2013-05-15 11:49:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
void Register_sceJpeg()
|
|
|
|
{
|
|
|
|
RegisterModule("sceJpeg", ARRAY_SIZE(sceJpeg), sceJpeg);
|
|
|
|
}
|