rpcsx/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp

335 lines
9.5 KiB
C++
Raw Normal View History

#include "stdafx.h"
#include "Emu/Memory/Memory.h"
2015-03-06 23:58:42 +01:00
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/SysCalls/Modules.h"
2015-04-12 22:16:30 +02:00
extern "C"
{
#include "stblib/stb_image.h"
2015-04-12 22:16:30 +02:00
#include "stblib/stb_image.c"
}
2015-03-12 20:02:02 +01:00
#include "Emu/FS/VFS.h"
#include "Emu/FS/vfsFileBase.h"
#include "Emu/SysCalls/lv2/sys_fs.h"
2015-03-12 20:02:02 +01:00
2014-08-23 22:40:04 +02:00
#include "cellGifDec.h"
extern Module cellGifDec;
2015-06-13 20:16:19 +02:00
s32 cellGifDecCreate(
vm::ptr<CellGifDecMainHandle> mainHandle,
vm::cptr<CellGifDecThreadInParam> threadInParam,
2015-06-13 20:16:19 +02:00
vm::ptr<CellGifDecThreadOutParam> threadOutParam)
{
UNIMPLEMENTED_FUNC(cellGifDec);
return CELL_OK;
}
2015-06-13 20:16:19 +02:00
s32 cellGifDecExtCreate(
vm::ptr<CellGifDecMainHandle> mainHandle,
vm::cptr<CellGifDecThreadInParam> threadInParam,
2015-06-13 20:16:19 +02:00
vm::ptr<CellGifDecThreadOutParam> threadOutParam,
vm::cptr<CellGifDecExtThreadInParam> extThreadInParam,
2015-06-13 20:16:19 +02:00
vm::ptr<CellGifDecExtThreadOutParam> extThreadOutParam)
{
UNIMPLEMENTED_FUNC(cellGifDec);
return CELL_OK;
}
2015-06-13 20:16:19 +02:00
s32 cellGifDecOpen(
CellGifDecMainHandle mainHandle,
vm::ptr<CellGifDecSubHandle> subHandle,
vm::cptr<CellGifDecSrc> src,
2015-06-13 20:16:19 +02:00
vm::ptr<CellGifDecOpnInfo> openInfo)
{
2015-04-14 04:00:31 +02:00
cellGifDec.Warning("cellGifDecOpen(mainHandle=0x%x, subHandle=*0x%x, src=*0x%x, openInfo=*0x%x)", mainHandle, subHandle, src, openInfo);
2014-08-06 00:19:33 +02:00
2015-07-01 19:09:26 +02:00
GifStream current_subHandle;
current_subHandle.fd = 0;
current_subHandle.src = *src;
switch (src->srcSelect.value())
{
case CELL_GIFDEC_BUFFER:
2015-07-01 19:09:26 +02:00
current_subHandle.fileSize = src->streamSize;
break;
case CELL_GIFDEC_FILE:
2015-03-12 20:02:02 +01:00
{
// Get file descriptor and size
2015-03-15 01:41:08 +01:00
std::shared_ptr<vfsStream> file_s(Emu.GetVFS().OpenFile(src->fileName.get_ptr(), vfsRead));
if (!file_s) return CELL_GIFDEC_ERROR_OPEN_FILE;
2015-07-01 19:09:26 +02:00
current_subHandle.fd = Emu.GetIdManager().make<lv2_file_t>(file_s, 0, 0);
current_subHandle.fileSize = file_s->GetSize();
break;
}
2015-03-12 20:02:02 +01:00
}
// From now, every u32 subHandle argument is a pointer to a CellGifDecSubHandle struct.
2015-07-01 19:09:26 +02:00
*subHandle = Emu.GetIdManager().make<GifStream>(current_subHandle);
return CELL_OK;
}
2015-06-13 20:16:19 +02:00
s32 cellGifDecReadHeader(
CellGifDecMainHandle mainHandle,
CellGifDecSubHandle subHandle,
vm::ptr<CellGifDecInfo> info)
{
2015-04-14 04:00:31 +02:00
cellGifDec.Warning("cellGifDecReadHeader(mainHandle=0x%x, subHandle=0x%x, info=*0x%x)", mainHandle, subHandle, info);
2014-08-06 00:19:33 +02:00
2015-06-13 20:16:19 +02:00
const auto subHandle_data = Emu.GetIdManager().get<GifStream>(subHandle);
2015-04-14 04:00:31 +02:00
if (!subHandle_data)
{
return CELL_GIFDEC_ERROR_FATAL;
2015-04-14 04:00:31 +02:00
}
const u32& fd = subHandle_data->fd;
const u64& fileSize = subHandle_data->fileSize;
CellGifDecInfo& current_info = subHandle_data->info;
2015-06-26 16:45:13 +02:00
// Write the header to buffer
u8 buffer[13];
switch(subHandle_data->src.srcSelect.value())
{
case CELL_GIFDEC_BUFFER:
2015-06-26 16:45:13 +02:00
std::memcpy(buffer, subHandle_data->src.streamPtr.get_ptr(), sizeof(buffer));
break;
case CELL_GIFDEC_FILE:
2015-03-12 20:02:02 +01:00
{
auto file = Emu.GetIdManager().get<lv2_file_t>(fd);
file->file->Seek(0);
2015-06-26 16:45:13 +02:00
file->file->Read(buffer, sizeof(buffer));
break;
}
2015-03-12 20:02:02 +01:00
}
2015-06-26 16:45:13 +02:00
if (*(be_t<u32>*)buffer != 0x47494638 ||
(*(le_t<u16>*)(buffer + 4) != 0x6139 && *(le_t<u16>*)(buffer + 4) != 0x6137)) // Error: The first 6 bytes are not a valid GIF signature
{
2014-04-04 15:25:38 +02:00
return CELL_GIFDEC_ERROR_STREAM_FORMAT; // Surprisingly there is no error code related with headerss
}
u8 packedField = buffer[10];
2014-04-04 15:25:38 +02:00
current_info.SWidth = buffer[6] + buffer[7] * 0x100;
current_info.SHeight = buffer[8] + buffer[9] * 0x100;
current_info.SGlobalColorTableFlag = packedField >> 7;
current_info.SColorResolution = ((packedField >> 4) & 7)+1;
current_info.SSortFlag = (packedField >> 3) & 1;
current_info.SSizeOfGlobalColorTable = (packedField & 7)+1;
current_info.SBackGroundColor = buffer[11];
current_info.SPixelAspectRatio = buffer[12];
*info = current_info;
return CELL_OK;
}
2015-06-13 20:16:19 +02:00
s32 cellGifDecSetParameter(
CellGifDecMainHandle mainHandle,
CellGifDecSubHandle subHandle,
vm::cptr<CellGifDecInParam> inParam,
2015-06-13 20:16:19 +02:00
vm::ptr<CellGifDecOutParam> outParam)
{
2015-04-14 04:00:31 +02:00
cellGifDec.Warning("cellGifDecSetParameter(mainHandle=0x%x, subHandle=0x%x, inParam=*0x%x, outParam=*0x%x)", mainHandle, subHandle, inParam, outParam);
2014-08-06 00:19:33 +02:00
2015-06-13 20:16:19 +02:00
const auto subHandle_data = Emu.GetIdManager().get<GifStream>(subHandle);
2015-04-14 04:00:31 +02:00
if (!subHandle_data)
{
return CELL_GIFDEC_ERROR_FATAL;
2015-04-14 04:00:31 +02:00
}
CellGifDecInfo& current_info = subHandle_data->info;
CellGifDecOutParam& current_outParam = subHandle_data->outParam;
2014-04-04 15:25:38 +02:00
current_outParam.outputWidthByte = (current_info.SWidth * current_info.SColorResolution * 3)/8;
current_outParam.outputWidth = current_info.SWidth;
current_outParam.outputHeight = current_info.SHeight;
current_outParam.outputColorSpace = inParam->colorSpace;
switch ((u32)current_outParam.outputColorSpace)
{
case CELL_GIFDEC_RGBA:
case CELL_GIFDEC_ARGB: current_outParam.outputComponents = 4; break;
2014-04-04 15:25:38 +02:00
default: return CELL_GIFDEC_ERROR_ARG; // Not supported color space
}
2014-04-04 15:25:38 +02:00
current_outParam.outputBitDepth = 0; // Unimplemented
current_outParam.useMemorySpace = 0; // Unimplemented
*outParam = current_outParam;
return CELL_OK;
}
2015-06-13 20:16:19 +02:00
s32 cellGifDecDecodeData(
CellGifDecMainHandle mainHandle,
CellGifDecSubHandle subHandle,
vm::ptr<u8> data,
vm::cptr<CellGifDecDataCtrlParam> dataCtrlParam,
2015-06-13 20:16:19 +02:00
vm::ptr<CellGifDecDataOutInfo> dataOutInfo)
{
2015-04-14 04:00:31 +02:00
cellGifDec.Warning("cellGifDecDecodeData(mainHandle=0x%x, subHandle=0x%x, data=*0x%x, dataCtrlParam=*0x%x, dataOutInfo=*0x%x)", mainHandle, subHandle, data, dataCtrlParam, dataOutInfo);
2014-08-06 00:19:33 +02:00
dataOutInfo->status = CELL_GIFDEC_DEC_STATUS_STOP;
2015-06-13 20:16:19 +02:00
const auto subHandle_data = Emu.GetIdManager().get<GifStream>(subHandle);
2015-04-14 04:00:31 +02:00
if (!subHandle_data)
{
return CELL_GIFDEC_ERROR_FATAL;
2015-04-14 04:00:31 +02:00
}
const u32& fd = subHandle_data->fd;
const u64& fileSize = subHandle_data->fileSize;
const CellGifDecOutParam& current_outParam = subHandle_data->outParam;
//Copy the GIF file to a buffer
2015-06-26 16:45:13 +02:00
std::unique_ptr<u8[]> gif(new u8[fileSize]);
switch(subHandle_data->src.srcSelect.value())
{
case CELL_GIFDEC_BUFFER:
2015-06-26 16:45:13 +02:00
std::memcpy(gif.get(), subHandle_data->src.streamPtr.get_ptr(), fileSize);
break;
case CELL_GIFDEC_FILE:
2015-03-12 20:02:02 +01:00
{
auto file = Emu.GetIdManager().get<lv2_file_t>(fd);
file->file->Seek(0);
2015-06-26 16:45:13 +02:00
file->file->Read(gif.get(), fileSize);
break;
}
2015-03-12 20:02:02 +01:00
}
//Decode GIF file. (TODO: Is there any faster alternative? Can we do it without external libraries?)
int width, height, actual_components;
auto image = std::unique_ptr<unsigned char,decltype(&::free)>
(
2015-06-26 16:45:13 +02:00
stbi_load_from_memory(gif.get(), (s32)fileSize, &width, &height, &actual_components, 4),
&::free
);
2014-07-10 21:07:46 +02:00
if (!image)
return CELL_GIFDEC_ERROR_STREAM_FORMAT;
2014-08-30 22:41:01 +02:00
const int bytesPerLine = (u32)dataCtrlParam->outputBytesPerLine;
const char nComponents = 4;
uint image_size = width * height * nComponents;
switch((u32)current_outParam.outputColorSpace)
{
case CELL_GIFDEC_RGBA:
{
if (bytesPerLine > width * nComponents) // Check if we need padding
2014-07-11 11:18:23 +02:00
{
const int linesize = std::min(bytesPerLine, width * nComponents);
for (int i = 0; i < height; i++)
{
const int dstOffset = i * bytesPerLine;
const int srcOffset = width * nComponents * i;
2014-09-05 22:26:36 +02:00
memcpy(&data[dstOffset], &image.get()[srcOffset], linesize);
}
}
else
{
2014-09-05 22:26:36 +02:00
memcpy(data.get_ptr(), image.get(), image_size);
2014-07-11 11:18:23 +02:00
}
}
break;
case CELL_GIFDEC_ARGB:
{
if (bytesPerLine > width * nComponents) // Check if we need padding
{
//TODO: find out if we can't do padding without an extra copy
const int linesize = std::min(bytesPerLine, width * nComponents);
char *output = (char *) malloc(linesize);
for (int i = 0; i < height; i++)
{
const int dstOffset = i * bytesPerLine;
const int srcOffset = width * nComponents * i;
for (int j = 0; j < linesize; j += nComponents)
{
output[j + 0] = image.get()[srcOffset + j + 3];
output[j + 1] = image.get()[srcOffset + j + 0];
output[j + 2] = image.get()[srcOffset + j + 1];
output[j + 3] = image.get()[srcOffset + j + 2];
}
2014-09-05 22:26:36 +02:00
memcpy(&data[dstOffset], output, linesize);
}
free(output);
}
else
{
uint* img = (uint*)new char[image_size];
uint* source_current = (uint*)&(image.get()[0]);
uint* dest_current = img;
for (uint i = 0; i < image_size / nComponents; i++)
{
uint val = *source_current;
*dest_current = (val >> 24) | (val << 8); // set alpha (A8) as leftmost byte
source_current++;
dest_current++;
}
memcpy(data.get_ptr(), img, image_size);
delete[] img;
}
}
break;
default:
return CELL_GIFDEC_ERROR_ARG;
}
dataOutInfo->status = CELL_GIFDEC_DEC_STATUS_FINISH;
dataOutInfo->recordType = CELL_GIFDEC_RECORD_TYPE_IMAGE_DESC;
return CELL_OK;
}
2015-06-13 20:16:19 +02:00
s32 cellGifDecClose(CellGifDecMainHandle mainHandle, CellGifDecSubHandle subHandle)
{
2015-04-14 04:00:31 +02:00
cellGifDec.Warning("cellGifDecClose(mainHandle=0x%x, subHandle=0x%x)", mainHandle, subHandle);
2014-08-06 00:19:33 +02:00
2015-06-13 20:16:19 +02:00
const auto subHandle_data = Emu.GetIdManager().get<GifStream>(subHandle);
2015-04-14 04:00:31 +02:00
if (!subHandle_data)
{
return CELL_GIFDEC_ERROR_FATAL;
2015-04-14 04:00:31 +02:00
}
Emu.GetIdManager().remove<lv2_file_t>(subHandle_data->fd);
Emu.GetIdManager().remove<CellGifDecSubHandle>(subHandle);
return CELL_OK;
}
2015-06-13 20:16:19 +02:00
s32 cellGifDecDestroy(CellGifDecMainHandle mainHandle)
{
UNIMPLEMENTED_FUNC(cellGifDec);
return CELL_OK;
}
Module cellGifDec("cellGifDec", []()
{
REG_FUNC(cellGifDec, cellGifDecCreate);
REG_FUNC(cellGifDec, cellGifDecExtCreate);
REG_FUNC(cellGifDec, cellGifDecOpen);
REG_FUNC(cellGifDec, cellGifDecReadHeader);
REG_FUNC(cellGifDec, cellGifDecSetParameter);
REG_FUNC(cellGifDec, cellGifDecDecodeData);
REG_FUNC(cellGifDec, cellGifDecClose);
REG_FUNC(cellGifDec, cellGifDecDestroy);
/*REG_FUNC(cellGifDec, cellGifDecExtOpen);
REG_FUNC(cellGifDec, cellGifDecExtReadHeader);
REG_FUNC(cellGifDec, cellGifDecExtSetParameter);
REG_FUNC(cellGifDec, cellGifDecExtDecodeData);*/
});