mirror of
https://github.com/Vita3K/Vita3K-Android.git
synced 2024-12-14 00:38:36 +00:00
modules/sceJpegEncUser, codec: Implement stubbed functions (#2608)
- MJpeg and sceJpegEncoderSetValidRegion functions are not yet supported. - Ignores the CompressionRatio parameter.
This commit is contained in:
parent
a197d981e0
commit
d16f87c337
2
external/ffmpeg
vendored
2
external/ffmpeg
vendored
@ -1 +1 @@
|
||||
Subproject commit 44845469c918c07d8470df2330711ed28174c468
|
||||
Subproject commit f643d93999c4e69bef287a7af6b6656ce8f8a257
|
@ -2,6 +2,7 @@ add_library(
|
||||
codec
|
||||
STATIC
|
||||
include/codec/state.h
|
||||
include/codec/types.h
|
||||
src/atrac9.cpp
|
||||
src/decoder.cpp
|
||||
src/aac.cpp
|
||||
|
@ -236,6 +236,8 @@ struct PlayerState {
|
||||
~PlayerState();
|
||||
};
|
||||
|
||||
void convert_rgb_to_yuv(const uint8_t *rgba, uint8_t *yuv, uint32_t width, uint32_t height, const bool is_yuv420);
|
||||
void convert_yuv_to_rgb(const uint8_t *yuv, uint8_t *rgba, uint32_t width, uint32_t height, const bool is_yuv420);
|
||||
int convert_yuv_to_jpeg(const uint8_t *yuv, uint8_t *jpeg, uint32_t width, uint32_t height, uint32_t max_size, bool is_yuv420);
|
||||
void copy_yuv_data_from_frame(AVFrame *frame, uint8_t *dest);
|
||||
std::string codec_error_name(int error);
|
||||
|
60
vita3k/codec/include/codec/types.h
Normal file
60
vita3k/codec/include/codec/types.h
Normal file
@ -0,0 +1,60 @@
|
||||
// Vita3K emulator project
|
||||
// Copyright (C) 2023 Vita3K team
|
||||
//
|
||||
// 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; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// 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 for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mem/ptr.h>
|
||||
|
||||
#include <util/types.h>
|
||||
|
||||
enum SceJpegEncErrorCode {
|
||||
SCE_JPEGENC_ERROR_IMAGE_SIZE = 0x80650200,
|
||||
SCE_JPEGENC_ERROR_INSUFFICIENT_BUFFER = 0x80650201,
|
||||
SCE_JPEGENC_ERROR_INVALID_COMPRATIO = 0x80650202,
|
||||
SCE_JPEGENC_ERROR_INVALID_PIXELFORMAT = 0x80650203,
|
||||
SCE_JPEGENC_ERROR_INVALID_HEADER_MODE = 0x80650204,
|
||||
SCE_JPEGENC_ERROR_INVALID_POINTER = 0x80650205,
|
||||
SCE_JPEGENC_ERROR_NOT_PHY_CONTINUOUS_MEMORY = 0x80650206
|
||||
};
|
||||
|
||||
enum SceJpegEncoderPixelFormat : int32_t {
|
||||
SCE_JPEGENC_PIXEL_RGBA8888 = 0,
|
||||
SCE_JPEGENC_PIXEL_BGRA8888 = 4,
|
||||
SCE_JPEGENC_PIXEL_YCBCR420 = 8,
|
||||
SCE_JPEGENC_PIXEL_YCBCR422 = 9,
|
||||
SCE_JPEGENC_PITCH_HW_CSC = 16,
|
||||
};
|
||||
|
||||
enum SceJpegEncoderHeaderMode : int32_t {
|
||||
SCE_JPEGENC_HEADER_MODE_JPEG = 0,
|
||||
SCE_JPEGENC_HEADER_MODE_MJPEG = 1
|
||||
};
|
||||
|
||||
enum SceJpegEncoderInitParamOption : int32_t {
|
||||
SCE_JPEGENC_INIT_PARAM_OPTION_NONE = 0,
|
||||
SCE_JPEGENC_INIT_PARAM_OPTION_LPDDR2_MEMORY = 1
|
||||
};
|
||||
|
||||
struct SceJpegEncoderInitParam {
|
||||
uint32_t size;
|
||||
int32_t inWidth;
|
||||
int32_t inHeight;
|
||||
int32_t pixelFormat;
|
||||
Ptr<uint8_t> outBuffer;
|
||||
uint32_t outSize;
|
||||
SceJpegEncoderInitParamOption option;
|
||||
};
|
@ -19,6 +19,7 @@
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libswscale/swscale.h>
|
||||
}
|
||||
|
||||
@ -56,6 +57,116 @@ void convert_yuv_to_rgb(const uint8_t *yuv, uint8_t *rgba, uint32_t width, uint3
|
||||
sws_freeContext(context);
|
||||
}
|
||||
|
||||
void convert_rgb_to_yuv(const uint8_t *rgba, uint8_t *yuv, uint32_t width, uint32_t height, const bool is_yuv420) {
|
||||
SwsContext *context = sws_getContext(width, height, AV_PIX_FMT_RGBA, width, height, is_yuv420 ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_YUV422P,
|
||||
0, nullptr, nullptr, nullptr);
|
||||
assert(context);
|
||||
|
||||
const uint8_t *slices[] = {
|
||||
rgba,
|
||||
};
|
||||
|
||||
int strides[] = {
|
||||
static_cast<int>(width * 4),
|
||||
};
|
||||
|
||||
uint8_t *dst_slices[] = {
|
||||
&yuv[0], // Y Slice
|
||||
&yuv[width * height], // U Slice
|
||||
&yuv[static_cast<uint32_t>(width * height * (is_yuv420 ? 1.25 : 1.5))], // V Slice
|
||||
};
|
||||
|
||||
const int dst_strides[] = {
|
||||
static_cast<int>(width),
|
||||
static_cast<int>(width) / (is_yuv420 ? 2 : 1),
|
||||
static_cast<int>(width) / (is_yuv420 ? 2 : 1),
|
||||
};
|
||||
|
||||
int error = sws_scale(context, slices, strides, 0, height, dst_slices, dst_strides);
|
||||
sws_freeContext(context);
|
||||
assert(error == height);
|
||||
}
|
||||
|
||||
void convert_yuv420_to_yuv444(const uint8_t *yuv420, uint8_t *yuv444, uint32_t width, uint32_t height) {
|
||||
SwsContext *context = sws_getContext(width, height, AV_PIX_FMT_YUV420P, width, height, AV_PIX_FMT_YUV444P,
|
||||
0, nullptr, nullptr, nullptr);
|
||||
assert(context);
|
||||
|
||||
const uint8_t *src_slices[] = {
|
||||
&yuv420[0], // Y Slice
|
||||
&yuv420[width * height], // U Slice
|
||||
&yuv420[static_cast<uint32_t>(width * height * 1.25)], // V Slice
|
||||
};
|
||||
|
||||
int src_strides[] = {
|
||||
static_cast<int>(width),
|
||||
static_cast<int>(width) / 2,
|
||||
static_cast<int>(width) / 2,
|
||||
};
|
||||
|
||||
uint8_t *dst_slices[] = {
|
||||
&yuv444[0], // Y Slice
|
||||
&yuv444[width * height], // U Slice
|
||||
&yuv444[2 * width * height], // V Slice
|
||||
};
|
||||
|
||||
const int dst_strides[] = {
|
||||
static_cast<int>(width),
|
||||
static_cast<int>(width),
|
||||
static_cast<int>(width),
|
||||
};
|
||||
|
||||
int error = sws_scale(context, src_slices, src_strides, 0, height, dst_slices, dst_strides);
|
||||
sws_freeContext(context);
|
||||
assert(error == height);
|
||||
}
|
||||
|
||||
int convert_yuv_to_jpeg(const uint8_t *yuv, uint8_t *jpeg, uint32_t width, uint32_t height, uint32_t max_size, bool is_yuv420) {
|
||||
const AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG);
|
||||
assert(codec);
|
||||
|
||||
AVCodecContext *context = avcodec_alloc_context3(codec);
|
||||
assert(context);
|
||||
|
||||
context->width = width;
|
||||
context->height = height;
|
||||
context->pix_fmt = is_yuv420 ? AV_PIX_FMT_YUVJ420P : AV_PIX_FMT_YUVJ422P;
|
||||
context->time_base.num = 1;
|
||||
context->time_base.den = 25;
|
||||
|
||||
int ret = avcodec_open2(context, codec, NULL);
|
||||
assert(ret >= 0);
|
||||
|
||||
AVFrame *frame = av_frame_alloc();
|
||||
assert(frame);
|
||||
|
||||
frame->format = context->pix_fmt;
|
||||
frame->width = context->width;
|
||||
frame->height = context->height;
|
||||
|
||||
ret = av_image_fill_arrays(frame->data, frame->linesize, yuv, context->pix_fmt, context->width, context->height, 1);
|
||||
assert(ret >= 0);
|
||||
|
||||
AVPacket *pkt = av_packet_alloc();
|
||||
|
||||
ret = avcodec_send_frame(context, frame);
|
||||
assert(ret >= 0);
|
||||
|
||||
ret = avcodec_receive_packet(context, pkt);
|
||||
uint32_t size = pkt->size;
|
||||
if (ret == 0 && size <= max_size) {
|
||||
memcpy(jpeg, pkt->data, pkt->size);
|
||||
}
|
||||
|
||||
av_packet_unref(pkt);
|
||||
av_frame_free(&frame);
|
||||
avcodec_free_context(&context);
|
||||
if (size > max_size) {
|
||||
return -1;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
bool MjpegDecoderState::send(const uint8_t *data, uint32_t size) {
|
||||
std::vector<uint8_t> jpeg_buffer(size + AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
std::memcpy(jpeg_buffer.data(), data, size);
|
||||
|
@ -128,6 +128,7 @@ public:
|
||||
"SceHttp",
|
||||
"SceIme",
|
||||
"SceIofilemgr",
|
||||
"SceJpegEncUser",
|
||||
"SceJpegUser",
|
||||
"SceKernelForMono",
|
||||
"SceKernelForVM",
|
||||
|
@ -17,43 +17,143 @@
|
||||
|
||||
#include "SceJpegEncUser.h"
|
||||
|
||||
EXPORT(int, sceJpegEncoderCsc) {
|
||||
return UNIMPLEMENTED();
|
||||
#include <codec/state.h>
|
||||
#include <codec/types.h>
|
||||
|
||||
#include <util/tracy.h>
|
||||
TRACY_MODULE_NAME(SceJpegEncUser);
|
||||
|
||||
struct SceJpegEncoderContext {
|
||||
int32_t inWidth;
|
||||
int32_t inHeight;
|
||||
int32_t pixelFormat;
|
||||
Ptr<uint8_t> outBuffer;
|
||||
uint32_t outSize;
|
||||
SceJpegEncoderInitParamOption option;
|
||||
|
||||
int32_t compressRatio;
|
||||
int32_t headerMode;
|
||||
};
|
||||
|
||||
int sceJpegEncoderInitImpl(SceJpegEncoderContext *context, int32_t inWidth, int32_t inHeight, int32_t pixelFormat, Ptr<uint8_t> outBuffer, uint32_t outSize, SceJpegEncoderInitParamOption option = SCE_JPEGENC_INIT_PARAM_OPTION_NONE) {
|
||||
context->inWidth = inWidth;
|
||||
context->inHeight = inHeight;
|
||||
context->pixelFormat = pixelFormat;
|
||||
context->outBuffer = outBuffer;
|
||||
context->outSize = outSize;
|
||||
context->option = option;
|
||||
|
||||
context->compressRatio = 255;
|
||||
context->headerMode = SCE_JPEGENC_HEADER_MODE_JPEG;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT(int, sceJpegEncoderEncode) {
|
||||
return UNIMPLEMENTED();
|
||||
EXPORT(int, sceJpegEncoderCsc, SceJpegEncoderContext *context, Ptr<uint8_t> outBuffer, Ptr<uint8_t> inBuffer, int32_t inPitch, int32_t inPixelFormat) {
|
||||
TRACY_FUNC(sceJpegEncoderCsc, context, outBuffer, inBuffer, inPitch, inPixelFormat);
|
||||
auto inBufferData = inBuffer.get(emuenv.mem);
|
||||
auto outBufferData = outBuffer.get(emuenv.mem);
|
||||
|
||||
bool is_yuv420 = false;
|
||||
|
||||
if ((context->pixelFormat & SCE_JPEGENC_PIXEL_YCBCR422) == SCE_JPEGENC_PIXEL_YCBCR422) {
|
||||
is_yuv420 = false;
|
||||
} else if ((context->pixelFormat & SCE_JPEGENC_PIXEL_YCBCR420) == SCE_JPEGENC_PIXEL_YCBCR420) {
|
||||
is_yuv420 = true;
|
||||
} else {
|
||||
return SCE_JPEGENC_ERROR_INVALID_PIXELFORMAT;
|
||||
}
|
||||
|
||||
if (inPixelFormat != SCE_JPEGENC_PIXEL_RGBA8888) {
|
||||
return STUBBED("Only RGBA8888 to YCbCr is implemented.");
|
||||
}
|
||||
|
||||
int32_t width = inPitch;
|
||||
int32_t height = context->inHeight * inPitch / context->inWidth;
|
||||
|
||||
convert_rgb_to_yuv(inBufferData, outBufferData, context->inWidth, context->inHeight, is_yuv420);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT(int, sceJpegEncoderEnd) {
|
||||
return UNIMPLEMENTED();
|
||||
EXPORT(int, sceJpegEncoderEncode, SceJpegEncoderContext *context, Ptr<uint8_t> inBuffer) {
|
||||
TRACY_FUNC(sceJpegEncoderEncode, context, inBuffer);
|
||||
|
||||
auto inBufferData = inBuffer.get(emuenv.mem);
|
||||
auto outBufferData = context->outBuffer.get(emuenv.mem);
|
||||
|
||||
int width = context->inWidth;
|
||||
int height = context->inHeight;
|
||||
|
||||
bool is_yuv420 = false;
|
||||
|
||||
if ((context->pixelFormat & SCE_JPEGENC_PIXEL_YCBCR422) == SCE_JPEGENC_PIXEL_YCBCR422) {
|
||||
is_yuv420 = false;
|
||||
} else if ((context->pixelFormat & SCE_JPEGENC_PIXEL_YCBCR420) == SCE_JPEGENC_PIXEL_YCBCR420) {
|
||||
is_yuv420 = true;
|
||||
} else {
|
||||
return SCE_JPEGENC_ERROR_INVALID_PIXELFORMAT;
|
||||
}
|
||||
|
||||
uint32_t size = convert_yuv_to_jpeg(inBufferData, outBufferData, width, height, context->outSize, is_yuv420);
|
||||
|
||||
if (size == -1) {
|
||||
return SCE_JPEGENC_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
EXPORT(int, sceJpegEncoderEnd, SceJpegEncoderContext *context) {
|
||||
TRACY_FUNC(sceJpegEncoderEnd, context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT(int, sceJpegEncoderGetContextSize) {
|
||||
return UNIMPLEMENTED();
|
||||
TRACY_FUNC(sceJpegEncoderGetContextSize);
|
||||
return sizeof(SceJpegEncoderContext);
|
||||
}
|
||||
|
||||
EXPORT(int, sceJpegEncoderInit) {
|
||||
return UNIMPLEMENTED();
|
||||
EXPORT(int, sceJpegEncoderInit, SceJpegEncoderContext *context, int32_t inWidth, int32_t inHeight, int32_t pixelFormat, Ptr<uint8_t> outBuffer, uint32_t outSize) {
|
||||
TRACY_FUNC(sceJpegEncoderInit, context, inWidth, inHeight, pixelFormat, outBuffer, outSize);
|
||||
return sceJpegEncoderInitImpl(context, inWidth, inHeight, pixelFormat, outBuffer, outSize, SCE_JPEGENC_INIT_PARAM_OPTION_NONE);
|
||||
}
|
||||
|
||||
EXPORT(int, sceJpegEncoderInitWithParam) {
|
||||
return UNIMPLEMENTED();
|
||||
EXPORT(int, sceJpegEncoderInitWithParam, SceJpegEncoderContext *context, SceJpegEncoderInitParam *initParam) {
|
||||
TRACY_FUNC(sceJpegEncoderInitWithParam, context, initParam);
|
||||
return sceJpegEncoderInitImpl(context, initParam->inWidth, initParam->inHeight, initParam->pixelFormat, initParam->outBuffer, initParam->outSize, initParam->option);
|
||||
}
|
||||
|
||||
EXPORT(int, sceJpegEncoderSetCompressionRatio) {
|
||||
return UNIMPLEMENTED();
|
||||
// TODO: CompressionRatio is ignored for the time being.
|
||||
EXPORT(int, sceJpegEncoderSetCompressionRatio, SceJpegEncoderContext *context, int32_t ratio) {
|
||||
TRACY_FUNC(sceJpegEncoderSetCompressionRatio, context, ratio);
|
||||
if (ratio < 0 || ratio > 255) {
|
||||
return SCE_JPEGENC_ERROR_INVALID_COMPRATIO;
|
||||
}
|
||||
context->compressRatio = ratio;
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT(int, sceJpegEncoderSetHeaderMode) {
|
||||
return UNIMPLEMENTED();
|
||||
EXPORT(int, sceJpegEncoderSetHeaderMode, SceJpegEncoderContext *context, int32_t mode) {
|
||||
TRACY_FUNC(sceJpegEncoderSetHeaderMode, context, mode);
|
||||
if (mode != SCE_JPEGENC_HEADER_MODE_JPEG && mode != SCE_JPEGENC_HEADER_MODE_MJPEG) {
|
||||
return SCE_JPEGENC_ERROR_INVALID_HEADER_MODE;
|
||||
} else if (mode == SCE_JPEGENC_HEADER_MODE_MJPEG) {
|
||||
return STUBBED("SCE_JPEGENC_HEADER_MODE_MJPEG is not supported");
|
||||
}
|
||||
context->headerMode = mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT(int, sceJpegEncoderSetOutputAddr) {
|
||||
return UNIMPLEMENTED();
|
||||
EXPORT(int, sceJpegEncoderSetOutputAddr, SceJpegEncoderContext *context, Ptr<uint8_t> outBuffer, uint32_t outSize) {
|
||||
TRACY_FUNC(sceJpegEncoderSetOutputAddr, context, outBuffer, outSize);
|
||||
context->outBuffer = outBuffer;
|
||||
context->outSize = outSize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT(int, sceJpegEncoderSetValidRegion) {
|
||||
EXPORT(int, sceJpegEncoderSetValidRegion, SceJpegEncoderContext *context, int32_t inWidth, int32_t inHeight) {
|
||||
TRACY_FUNC(sceJpegEncoderSetValidRegion, context, inWidth, inHeight);
|
||||
return UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user