feat(ajm): implement DecodeSingle, GetGaplessDecode and GetCodecInfo
sceAjmBatchJobDecodeSingle runs a single-frame decode job with the stream sideband. sceAjmBatchJobGetGaplessDecode and sceAjmBatchJobGetCodecInfo append run jobs without buffers that return the gapless-decode and codec-info sidebands. A run job without input or output buffers no longer decodes: it reports the instance state with a zero result instead of PARTIAL_INPUT on MP3 and Opus. RUN_GET_CODEC_INFO (bit 11) writes the ATRAC9 codec info after the gapless sideband. Codec info for other codecs, and codec info together with RUN_MULTIPLE_FRAMES, throw. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
07404b67e4
commit
2771eeea77
|
|
@ -33,18 +33,6 @@ int APS5_VABI sceAjmBatchJobControl(AjmBatchInfo* info, uint32_t instance, uint6
|
|||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAjmBatchJobDecodeSingle(AjmBatchInfo* info, uint32_t instance, const void* bitstream_input, size_t bitstream_input_size, void* pcm_output, size_t pcm_output_size, void* result) {
|
||||
(void)info;
|
||||
(void)instance;
|
||||
(void)bitstream_input;
|
||||
(void)bitstream_input_size;
|
||||
(void)pcm_output;
|
||||
(void)pcm_output_size;
|
||||
(void)result;
|
||||
AjmStub(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAjmBatchJobDecodeSplit(AjmBatchInfo* info, uint32_t instance, const AjmBuffer* input_buffers, size_t input_buffers_num, const AjmBuffer* output_buffers, size_t output_buffers_num, void* result) {
|
||||
(void)info;
|
||||
(void)instance;
|
||||
|
|
@ -69,23 +57,6 @@ int APS5_VABI sceAjmBatchJobEncode(AjmBatchInfo* info, uint32_t instance, const
|
|||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAjmBatchJobGetCodecInfo(AjmBatchInfo* info, uint32_t instance, void* result, size_t result_size) {
|
||||
(void)info;
|
||||
(void)instance;
|
||||
(void)result;
|
||||
(void)result_size;
|
||||
AjmStub(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAjmBatchJobGetGaplessDecode(AjmBatchInfo* info, uint32_t instance, void* result) {
|
||||
(void)info;
|
||||
(void)instance;
|
||||
(void)result;
|
||||
AjmStub(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAjmBatchJobGetInfo(AjmBatchInfo* info, uint32_t instance, void* result) {
|
||||
(void)info;
|
||||
(void)instance;
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ bool TraceEnabled() {
|
|||
if (TraceEnabled()) std::fprintf(stderr, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
constexpr std::uint64_t RUN_GET_CODEC_INFO = 1ull << 11;
|
||||
constexpr std::uint64_t RUN_MULTIPLE_FRAMES = 1ull << 12;
|
||||
constexpr std::uint64_t SIDEBAND_GAPLESS_DECODE = 1ull << 45;
|
||||
constexpr std::uint64_t SIDEBAND_FORMAT = 1ull << 46;
|
||||
|
|
@ -87,6 +88,13 @@ struct SidebandMultipleFrames {
|
|||
std::uint32_t reserved;
|
||||
};
|
||||
|
||||
struct SidebandAt9CodecInfo {
|
||||
std::uint32_t superframeSize;
|
||||
std::uint32_t framesInSuperframe;
|
||||
std::uint32_t nextFrameSize;
|
||||
std::uint32_t frameSamples;
|
||||
};
|
||||
|
||||
struct Instance {
|
||||
std::uint32_t codec = 0;
|
||||
std::uint64_t flags = 0;
|
||||
|
|
@ -337,6 +345,20 @@ void EmitFrame(Instance& instance, PcmOutputs& outputs, const std::uint8_t* pcm,
|
|||
instance.totalDecodedSamples += count;
|
||||
}
|
||||
|
||||
SidebandFormat CurrentFormat(const Instance& instance) {
|
||||
switch (instance.codec) {
|
||||
case CODEC_AT9: return {static_cast<std::uint32_t>(instance.info.channels), ChannelMask(static_cast<std::size_t>(instance.info.channels)), static_cast<std::uint32_t>(instance.info.samplingRate), PcmEncoding(instance), 0, 0};
|
||||
case CODEC_MP3: return {instance.mp3Channels, ChannelMask(instance.mp3Channels), instance.mp3SampleRate, PcmEncoding(instance), instance.mp3Bitrate, 0};
|
||||
case CODEC_OPUS: return {instance.opusChannels, ChannelMask(instance.opusChannels), instance.opusSampleRate, PcmEncoding(instance), 0, 0};
|
||||
default: throw std::runtime_error("AJM: the format of codec " + std::to_string(instance.codec) + " is not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
SidebandAt9CodecInfo At9CodecInfo(const Instance& instance) {
|
||||
const auto superframeSize = static_cast<std::uint32_t>(instance.info.superframeSize);
|
||||
return {superframeSize, static_cast<std::uint32_t>(instance.info.framesInSuperframe), instance.superframeRemaining == 0 ? superframeSize : instance.superframeRemaining, static_cast<std::uint32_t>(instance.info.frameSamples)};
|
||||
}
|
||||
|
||||
void WriteRunSideband(const JobHeader& job, const Instance& instance, std::int32_t result, std::size_t consumed, std::size_t produced, std::uint32_t frames, const SidebandFormat& format) {
|
||||
auto* sideband = static_cast<std::uint8_t*>(job.sideband);
|
||||
std::size_t offset = 0;
|
||||
|
|
@ -353,6 +375,10 @@ void WriteRunSideband(const JobHeader& job, const Instance& instance, std::int32
|
|||
}
|
||||
if (job.flags & SIDEBAND_FORMAT) write(&format, sizeof(format));
|
||||
if (job.flags & SIDEBAND_GAPLESS_DECODE) write(&instance.gapless, sizeof(instance.gapless));
|
||||
if (job.flags & RUN_GET_CODEC_INFO) {
|
||||
const SidebandAt9CodecInfo codecInfo = At9CodecInfo(instance);
|
||||
write(&codecInfo, sizeof(codecInfo));
|
||||
}
|
||||
if (job.flags & RUN_MULTIPLE_FRAMES) {
|
||||
const SidebandMultipleFrames multiple{frames, 0};
|
||||
write(&multiple, sizeof(multiple));
|
||||
|
|
@ -431,7 +457,7 @@ void RunAt9(Instance& instance, const JobHeader& job, const AjmBuffer* inputs, c
|
|||
for (std::size_t i = 0; i < input.size() && i < 16; ++i) std::fprintf(stderr, " %02x", input[i]);
|
||||
std::fprintf(stderr, "\n");
|
||||
}
|
||||
WriteRunSideband(job, instance, result, consumed, pcmOutputs.produced, frames, SidebandFormat{static_cast<std::uint32_t>(channels), ChannelMask(channels), static_cast<std::uint32_t>(instance.info.samplingRate), encoding, 0, 0});
|
||||
WriteRunSideband(job, instance, result, consumed, pcmOutputs.produced, frames, CurrentFormat(instance));
|
||||
}
|
||||
|
||||
struct Mp3Frame {
|
||||
|
|
@ -546,7 +572,7 @@ void RunMp3(Instance& instance, const JobHeader& job, const AjmBuffer* inputs, c
|
|||
|
||||
AJM_TRACE("[ajm] instance %u mp3 run flags 0x%llx: %zu input bytes, %zu output bytes -> result 0x%x, %u frames, consumed %zu, produced %zu, %u channels, %u Hz, %u bps, total samples %llu\n", job.instance, static_cast<unsigned long long>(job.flags), input.size(), pcmOutputs.capacity, static_cast<unsigned>(result), frames, consumed, pcmOutputs.produced,
|
||||
instance.mp3Channels, instance.mp3SampleRate, instance.mp3Bitrate, static_cast<unsigned long long>(instance.totalDecodedSamples));
|
||||
WriteRunSideband(job, instance, result, consumed, pcmOutputs.produced, frames, SidebandFormat{instance.mp3Channels, ChannelMask(instance.mp3Channels), instance.mp3SampleRate, encoding, instance.mp3Bitrate, 0});
|
||||
WriteRunSideband(job, instance, result, consumed, pcmOutputs.produced, frames, CurrentFormat(instance));
|
||||
}
|
||||
void OpenOpus(Instance& instance) {
|
||||
static const bool quiet = (av_log_set_level(TraceEnabled() ? AV_LOG_WARNING : AV_LOG_QUIET), true);
|
||||
|
|
@ -682,7 +708,7 @@ void RunOpus(Instance& instance, const JobHeader& job, const AjmBuffer* inputs,
|
|||
if (consumed == input.size() && frames == 0 && pcmOutputs.produced == 0 && result == 0) result |= AJM_RESULT_PARTIAL_INPUT;
|
||||
|
||||
AJM_TRACE("[ajm] instance %u opus run flags 0x%llx: %zu input bytes, %zu output bytes -> result 0x%x, %u frames, consumed %zu, produced %zu, total samples %llu\n", job.instance, static_cast<unsigned long long>(job.flags), input.size(), pcmOutputs.capacity, static_cast<unsigned>(result), frames, consumed, pcmOutputs.produced, static_cast<unsigned long long>(instance.totalDecodedSamples));
|
||||
WriteRunSideband(job, instance, result, consumed, pcmOutputs.produced, frames, SidebandFormat{instance.opusChannels, ChannelMask(instance.opusChannels), instance.opusSampleRate, encoding, 0, 0});
|
||||
WriteRunSideband(job, instance, result, consumed, pcmOutputs.produced, frames, CurrentFormat(instance));
|
||||
}
|
||||
|
||||
void Execute(const JobHeader& job, const AjmBuffer* inputs, const AjmBuffer* outputs) {
|
||||
|
|
@ -729,14 +755,21 @@ void Execute(const JobHeader& job, const AjmBuffer* inputs, const AjmBuffer* out
|
|||
if (!instance->initialized) {
|
||||
AJM_TRACE("[ajm] instance %u run before initialize\n", job.instance);
|
||||
WriteResult(job.sideband, job.sidebandSize, AJM_RESULT_NOT_INITIALIZED);
|
||||
} else if (instance->codec != CODEC_AT9 && instance->codec != CODEC_MP3 && instance->codec != CODEC_OPUS) {
|
||||
throw std::runtime_error("AJM: decoding codec " + std::to_string(instance->codec) + " is not implemented");
|
||||
} else if ((job.flags & RUN_GET_CODEC_INFO) && (job.flags & RUN_MULTIPLE_FRAMES)) {
|
||||
NotImplemented_nid_no_patch("AJM run job with both RUN_GET_CODEC_INFO and RUN_MULTIPLE_FRAMES (sideband order)");
|
||||
} else if ((job.flags & RUN_GET_CODEC_INFO) && instance->codec != CODEC_AT9) {
|
||||
NotImplemented_nid_no_patch("AJM RUN_GET_CODEC_INFO for a codec other than ATRAC9");
|
||||
} else if (job.inputCount == 0 && job.outputCount == 0) {
|
||||
AJM_TRACE("[ajm] instance %u run flags 0x%llx without buffers, sideband %llu bytes\n", job.instance, static_cast<unsigned long long>(job.flags), static_cast<unsigned long long>(job.sidebandSize));
|
||||
WriteRunSideband(job, *instance, 0, 0, 0, 0, CurrentFormat(*instance));
|
||||
} else if (instance->codec == CODEC_AT9) {
|
||||
RunAt9(*instance, job, inputs, outputs);
|
||||
} else if (instance->codec == CODEC_MP3) {
|
||||
RunMp3(*instance, job, inputs, outputs);
|
||||
} else if (instance->codec == CODEC_OPUS) {
|
||||
RunOpus(*instance, job, inputs, outputs);
|
||||
} else {
|
||||
throw std::runtime_error("AJM: decoding codec " + std::to_string(instance->codec) + " is not implemented");
|
||||
RunOpus(*instance, job, inputs, outputs);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
@ -907,6 +940,18 @@ int APS5_VABI sceAjmBatchJobDecode(AjmBatchInfo* info, uint32_t instance, const
|
|||
return sceAjmBatchJobRun(info, instance, SIDEBAND_STREAM, bitstream_input, bitstream_input_size, pcm_output, pcm_output_size, result, sizeof(SidebandResult) + sizeof(SidebandStream));
|
||||
}
|
||||
|
||||
int APS5_VABI sceAjmBatchJobDecodeSingle(AjmBatchInfo* info, uint32_t instance, const void* bitstream_input, size_t bitstream_input_size, void* pcm_output, size_t pcm_output_size, void* result) {
|
||||
return sceAjmBatchJobRun(info, instance, SIDEBAND_STREAM, bitstream_input, bitstream_input_size, pcm_output, pcm_output_size, result, sizeof(SidebandResult) + sizeof(SidebandStream));
|
||||
}
|
||||
|
||||
int APS5_VABI sceAjmBatchJobGetGaplessDecode(AjmBatchInfo* info, uint32_t instance, void* result) {
|
||||
return sceAjmBatchJobRunSplit(info, instance, SIDEBAND_GAPLESS_DECODE, nullptr, 0, nullptr, 0, result, sizeof(SidebandResult) + sizeof(SidebandGaplessDecode));
|
||||
}
|
||||
|
||||
int APS5_VABI sceAjmBatchJobGetCodecInfo(AjmBatchInfo* info, uint32_t instance, void* result, size_t result_size) {
|
||||
return sceAjmBatchJobRunSplit(info, instance, RUN_GET_CODEC_INFO, nullptr, 0, nullptr, 0, result, result_size);
|
||||
}
|
||||
|
||||
int APS5_VABI sceAjmBatchJobGetStatistics(AjmBatchInfo* info, float interval, void* result) {
|
||||
(void)interval;
|
||||
return Append(info, MakeHeader(JobKind::GetStatistics, 0, result, 24), nullptr, nullptr);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
|
|
@ -17,6 +18,11 @@ int APS5_VABI sceAjmInstanceDestroy(std::uint32_t, std::uint32_t);
|
|||
int APS5_VABI sceAjmBatchInitialize(void*, std::size_t, AjmBatchInfo*);
|
||||
int APS5_VABI sceAjmBatchJobInitialize(AjmBatchInfo*, std::uint32_t, const void*, std::size_t, void*);
|
||||
int APS5_VABI sceAjmBatchJobDecode(AjmBatchInfo*, std::uint32_t, const void*, std::size_t, void*, std::size_t, void*);
|
||||
int APS5_VABI sceAjmBatchJobDecodeSingle(AjmBatchInfo*, std::uint32_t, const void*, std::size_t, void*, std::size_t, void*);
|
||||
int APS5_VABI sceAjmBatchJobRun(AjmBatchInfo*, std::uint32_t, std::uint64_t, const void*, std::size_t, void*, std::size_t, void*, std::size_t);
|
||||
int APS5_VABI sceAjmBatchJobSetGaplessDecode(AjmBatchInfo*, std::uint32_t, const void*, int, void*);
|
||||
int APS5_VABI sceAjmBatchJobGetGaplessDecode(AjmBatchInfo*, std::uint32_t, void*);
|
||||
int APS5_VABI sceAjmBatchJobGetCodecInfo(AjmBatchInfo*, std::uint32_t, void*, std::size_t);
|
||||
int APS5_VABI sceAjmBatchStart(std::uint32_t, const AjmBatchInfo*, int, AjmBatchError*, std::uint32_t*);
|
||||
int APS5_VABI sceAjmBatchWait(std::uint32_t, std::uint32_t, std::uint32_t, AjmBatchError*);
|
||||
}
|
||||
|
|
@ -195,6 +201,126 @@ void TestMp3ParseFrame() {
|
|||
Require(sceAjmDecMp3ParseFrame(mpeg25Above64Kbps, 4, 0, &frame) == invalidParameter);
|
||||
}
|
||||
|
||||
struct GaplessDecode {
|
||||
std::uint32_t totalSamples;
|
||||
std::uint16_t skipSamples;
|
||||
std::uint16_t skippedSamples;
|
||||
};
|
||||
|
||||
struct GaplessSideband {
|
||||
std::int32_t result;
|
||||
std::int32_t internalResult;
|
||||
std::uint32_t totalSamples;
|
||||
std::uint16_t skipSamples;
|
||||
std::uint16_t skippedSamples;
|
||||
};
|
||||
|
||||
struct At9CodecInfoSideband {
|
||||
std::int32_t result;
|
||||
std::int32_t internalResult;
|
||||
std::uint32_t superframeSize;
|
||||
std::uint32_t framesInSuperframe;
|
||||
std::uint32_t nextFrameSize;
|
||||
std::uint32_t frameSamples;
|
||||
};
|
||||
|
||||
void Submit(std::uint32_t context, const AjmBatchInfo& info) {
|
||||
std::uint32_t id = 0;
|
||||
AjmBatchError error{};
|
||||
Require(sceAjmBatchStart(context, &info, 0, &error, &id) == 0 && sceAjmBatchWait(context, id, 0, &error) == 0);
|
||||
}
|
||||
|
||||
bool Refused(std::uint32_t context, const AjmBatchInfo& info) {
|
||||
std::uint32_t id = 0;
|
||||
AjmBatchError error{};
|
||||
try {
|
||||
static_cast<void>(sceAjmBatchStart(context, &info, 0, &error, &id));
|
||||
} catch (const std::runtime_error&) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void TestDecodeSingle(std::uint32_t context) {
|
||||
std::uint32_t instance = 0;
|
||||
Require(sceAjmInstanceCreate(context, 0, 0, &instance) == 0);
|
||||
std::vector<std::uint8_t> batch(0x40);
|
||||
std::vector<std::int16_t> pcm(1152 * 6);
|
||||
AjmBatchInfo info{};
|
||||
DecodeSideband sideband{};
|
||||
Require(sceAjmBatchInitialize(batch.data(), batch.size(), &info) == 0);
|
||||
Require(sceAjmBatchJobDecodeSingle(&info, instance, MP3_MONO, sizeof(MP3_MONO), pcm.data(), pcm.size() * sizeof(std::int16_t), &sideband) == 0);
|
||||
Submit(context, info);
|
||||
Require(sideband.result == 0 && sideband.inputConsumed == 96 && sideband.outputWritten == 1152 * 2 && sideband.totalDecodedSamples == 1152);
|
||||
Require(sceAjmInstanceDestroy(context, instance) == 0);
|
||||
}
|
||||
|
||||
void TestGaplessDecode(std::uint32_t context) {
|
||||
std::uint32_t instance = 0;
|
||||
Require(sceAjmInstanceCreate(context, 0, 0, &instance) == 0);
|
||||
std::vector<std::uint8_t> batch(4096);
|
||||
const GaplessDecode gapless{2000, 100, 0};
|
||||
AjmBatchInfo info{};
|
||||
std::int32_t setResult[2] = {-1, -1};
|
||||
GaplessSideband before{-1, -1, 0, 0, 0xffff};
|
||||
Require(sceAjmBatchInitialize(batch.data(), batch.size(), &info) == 0);
|
||||
Require(sceAjmBatchJobSetGaplessDecode(&info, instance, &gapless, 1, setResult) == 0);
|
||||
Require(sceAjmBatchJobGetGaplessDecode(&info, instance, &before) == 0);
|
||||
Submit(context, info);
|
||||
Require(setResult[0] == 0);
|
||||
Require(before.result == 0 && before.internalResult == 0 && before.totalSamples == 2000 && before.skipSamples == 100 && before.skippedSamples == 0);
|
||||
|
||||
std::vector<std::int16_t> pcm(1152);
|
||||
DecodeSideband decoded{};
|
||||
GaplessSideband after{-1, -1, 0, 0, 0};
|
||||
Require(sceAjmBatchInitialize(batch.data(), batch.size(), &info) == 0);
|
||||
Require(sceAjmBatchJobDecodeSingle(&info, instance, MP3_MONO, sizeof(MP3_MONO), pcm.data(), pcm.size() * sizeof(std::int16_t), &decoded) == 0);
|
||||
Require(sceAjmBatchJobGetGaplessDecode(&info, instance, &after) == 0);
|
||||
Submit(context, info);
|
||||
Require(decoded.result == 0 && decoded.inputConsumed == 96 && decoded.outputWritten == (1152 - 100) * 2);
|
||||
Require(after.result == 0 && after.skippedSamples == 100);
|
||||
Require(sceAjmInstanceDestroy(context, instance) == 0);
|
||||
}
|
||||
|
||||
void TestCodecInfo(std::uint32_t context) {
|
||||
std::uint32_t instance = 0;
|
||||
Require(sceAjmInstanceCreate(context, 1, 0, &instance) == 0);
|
||||
std::vector<std::uint8_t> batch(4096);
|
||||
AjmBatchInfo info{};
|
||||
At9CodecInfoSideband early{-1, -1, 0xaaaaaaaau, 0xaaaaaaaau, 0xaaaaaaaau, 0xaaaaaaaau};
|
||||
Require(sceAjmBatchInitialize(batch.data(), batch.size(), &info) == 0);
|
||||
Require(sceAjmBatchJobGetCodecInfo(&info, instance, &early, sizeof(early)) == 0);
|
||||
Submit(context, info);
|
||||
Require(early.result == 1 && early.superframeSize == 0xaaaaaaaau);
|
||||
|
||||
const std::uint8_t config[8] = {0xFE, 0x72, 0x1F, 0xF0};
|
||||
std::int32_t initResult[2] = {-1, -1};
|
||||
At9CodecInfoSideband codec{-1, -1, 0, 0, 0, 0};
|
||||
At9CodecInfoSideband bounded{-1, -1, 0xaaaaaaaau, 0xaaaaaaaau, 0xaaaaaaaau, 0xaaaaaaaau};
|
||||
Require(sceAjmBatchInitialize(batch.data(), batch.size(), &info) == 0);
|
||||
Require(sceAjmBatchJobInitialize(&info, instance, config, sizeof(config), initResult) == 0);
|
||||
Require(sceAjmBatchJobGetCodecInfo(&info, instance, &codec, sizeof(codec)) == 0);
|
||||
Require(sceAjmBatchJobGetCodecInfo(&info, instance, &bounded, 2 * sizeof(std::int32_t)) == 0);
|
||||
Submit(context, info);
|
||||
Require(initResult[0] == 0);
|
||||
Require(codec.result == 0 && codec.internalResult == 0 && codec.superframeSize == 1024 && codec.framesInSuperframe == 4 && codec.nextFrameSize == 1024 && codec.frameSamples == 256);
|
||||
Require(bounded.result == 0 && bounded.superframeSize == 0xaaaaaaaau && bounded.frameSamples == 0xaaaaaaaau);
|
||||
|
||||
constexpr std::uint64_t runGetCodecInfo = 1ull << 11;
|
||||
constexpr std::uint64_t runMultipleFrames = 1ull << 12;
|
||||
std::uint8_t sideband[64] = {};
|
||||
Require(sceAjmBatchInitialize(batch.data(), batch.size(), &info) == 0);
|
||||
Require(sceAjmBatchJobRun(&info, instance, runGetCodecInfo | runMultipleFrames, nullptr, 0, nullptr, 0, sideband, sizeof(sideband)) == 0);
|
||||
Require(Refused(context, info));
|
||||
Require(sceAjmInstanceDestroy(context, instance) == 0);
|
||||
|
||||
Require(sceAjmInstanceCreate(context, 0, 0, &instance) == 0);
|
||||
Require(sceAjmBatchInitialize(batch.data(), batch.size(), &info) == 0);
|
||||
Require(sceAjmBatchJobGetCodecInfo(&info, instance, sideband, sizeof(sideband)) == 0);
|
||||
Require(Refused(context, info));
|
||||
Require(sceAjmInstanceDestroy(context, instance) == 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
|
@ -214,5 +340,8 @@ int main() {
|
|||
TestMp3ParseFrame();
|
||||
TestMp3(context);
|
||||
TestOpus(context);
|
||||
TestDecodeSingle(context);
|
||||
TestGaplessDecode(context);
|
||||
TestCodecInfo(context);
|
||||
Require(sceAjmFinalize(context) == 0);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue