fix(avplayer): make decode-ahead buffers optional
This commit is contained in:
parent
c2fa7fd97f
commit
cf10b5e609
|
|
@ -327,6 +327,7 @@ public:
|
|||
return result;
|
||||
}
|
||||
}
|
||||
addVideoDecodeAheadBuffers();
|
||||
const auto start = startOffset;
|
||||
startOffset = 0;
|
||||
seek(start);
|
||||
|
|
@ -605,7 +606,7 @@ private:
|
|||
pitch = AlignUp(static_cast<std::uint32_t>(decoder.context->width), VideoPitchAlignment);
|
||||
bufferHeight = AlignUp(static_cast<std::uint32_t>(decoder.context->height), VideoHeightAlignment);
|
||||
decoder.bufferSize = pitch * bufferHeight * 3 / 2;
|
||||
count = settings.videoBuffers + VideoDecodeAheadFrames;
|
||||
count = settings.videoBuffers;
|
||||
decoder.retained = settings.videoBuffers > 3 ? settings.videoBuffers - 3 : 0;
|
||||
texture = true;
|
||||
alignment = VideoBufferAlignment;
|
||||
|
|
@ -625,6 +626,27 @@ private:
|
|||
return SCE_OK;
|
||||
}
|
||||
|
||||
void addVideoDecodeAheadBuffers() {
|
||||
if (video.stream < 0) return;
|
||||
|
||||
const auto& memory = settings.memory;
|
||||
std::vector<std::uint8_t*> extra;
|
||||
extra.reserve(VideoDecodeAheadFrames);
|
||||
for (std::uint32_t index = 0; index < VideoDecodeAheadFrames; ++index) {
|
||||
auto* buffer = static_cast<std::uint8_t*>(memory.allocate_texture(
|
||||
memory.object_ptr, VideoBufferAlignment, video.bufferSize));
|
||||
if (!buffer) {
|
||||
for (auto* allocated : extra) memory.deallocate_texture(memory.object_ptr, allocated);
|
||||
return;
|
||||
}
|
||||
extra.push_back(buffer);
|
||||
}
|
||||
for (auto* buffer : extra) {
|
||||
video.allocated.push_back(buffer);
|
||||
video.free.push_back(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void releaseDecoders() {
|
||||
const auto& memory = settings.memory;
|
||||
for (auto* decoder : {&video, &audio}) {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <map>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
|
@ -473,12 +474,17 @@ struct Allocations {
|
|||
std::mutex mutex;
|
||||
std::map<void*, Block> blocks;
|
||||
int textures = 0;
|
||||
std::optional<int> textureLimit;
|
||||
};
|
||||
|
||||
Allocations allocations;
|
||||
|
||||
void* Allocate(std::uint32_t alignment, std::uint32_t size, bool texture) {
|
||||
const auto aligned = static_cast<std::align_val_t>(std::max<std::uint32_t>(alignment, 16));
|
||||
{
|
||||
std::lock_guard lock(allocations.mutex);
|
||||
if (texture && allocations.textureLimit && allocations.textures >= *allocations.textureLimit) return nullptr;
|
||||
}
|
||||
void* memory = ::operator new(size, aligned);
|
||||
std::lock_guard lock(allocations.mutex);
|
||||
allocations.blocks[memory] = {texture, aligned};
|
||||
|
|
@ -494,6 +500,7 @@ void Release(void* memory, bool texture) {
|
|||
if (found == allocations.blocks.end() || found->second.texture != texture) std::abort();
|
||||
aligned = found->second.alignment;
|
||||
allocations.blocks.erase(found);
|
||||
if (texture) --allocations.textures;
|
||||
}
|
||||
::operator delete(memory, aligned);
|
||||
}
|
||||
|
|
@ -509,6 +516,16 @@ bool IsAllocation(const void* memory, bool texture) {
|
|||
return found != allocations.blocks.end() && found->second.texture == texture;
|
||||
}
|
||||
|
||||
void SetTextureLimit(std::optional<int> limit) {
|
||||
std::lock_guard lock(allocations.mutex);
|
||||
allocations.textureLimit = limit;
|
||||
}
|
||||
|
||||
int TextureCount() {
|
||||
std::lock_guard lock(allocations.mutex);
|
||||
return allocations.textures;
|
||||
}
|
||||
|
||||
struct Events {
|
||||
std::mutex mutex;
|
||||
std::vector<std::pair<std::int32_t, std::int32_t>> received;
|
||||
|
|
@ -898,6 +915,28 @@ void TestWithoutAllocators() {
|
|||
Check(sceAvPlayerClose(handle) == 0, "close failed");
|
||||
}
|
||||
|
||||
void TestOptionalVideoBuffersRespectMemoryLimit() {
|
||||
const auto run = [](int textureLimit, int expectedTextures) {
|
||||
SetTextureLimit(textureLimit);
|
||||
AvPlayerInitData init = InitData(nullptr);
|
||||
init.num_output_video_framebuffers = 2;
|
||||
auto* player = sceAvPlayerInit(&init);
|
||||
Check(player != nullptr, "init with limited texture memory failed");
|
||||
Check(sceAvPlayerAddSource(player, "/app0/avplayer.mp4") == 0, "add source with limited texture memory failed");
|
||||
Check(WaitFor([&] { return TextureCount() == expectedTextures && sceAvPlayerIsActive(player); }), "unexpected optional video buffer count");
|
||||
AvPlayerFrameInfoEx frame{};
|
||||
Check(WaitFor([&] { return sceAvPlayerGetVideoDataEx(player, &frame) != 0; }), "no frame with limited texture memory");
|
||||
CheckVideoPicture(frame);
|
||||
Check(sceAvPlayerClose(player) == 0, "close with limited texture memory failed");
|
||||
Check(TextureCount() == 0, "limited texture allocations were not released");
|
||||
};
|
||||
|
||||
run(2, 2);
|
||||
run(4, 2);
|
||||
run(6, 6);
|
||||
SetTextureLimit(std::nullopt);
|
||||
}
|
||||
|
||||
void TestFileReplacementAutoStart() {
|
||||
HostFile file;
|
||||
AvPlayerInitData init = InitData(nullptr);
|
||||
|
|
@ -951,6 +990,7 @@ int main() {
|
|||
TestChangeStream();
|
||||
TestExtendedExports();
|
||||
TestWithoutAllocators();
|
||||
TestOptionalVideoBuffersRespectMemoryLimit();
|
||||
TestFileReplacementAutoStart();
|
||||
TestHandedOutFramesStayIntact();
|
||||
std::puts("AvPlayer tests passed");
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ Throughout the project, every function at every stage either **does exactly what
|
|||
|
||||
### Unknown function info
|
||||
|
||||
- [sceAvPlayerAddSource](../../core/libs/prx/libSceAvPlayer/src/Source.cpp) (libSceAvPlayer) - requests up to 4 additional decode-ahead video framebuffers from the memory replacement beyond `num_output_video_framebuffers` when memory is available; the console's internal buffering behaviour is unknown
|
||||
- [sceVideoOutOpen](../../core/libs/prx/libSceVideoOut/src/Output.cpp) (libSceVideoOut) - the open param's first word is unknown (PPSA21564 passes 16; it is not the byte size, since the affinity mask is at offset 16); only 16 is accepted. Whether the param continues past offset 24 is also unknown
|
||||
- [sceRtcParseDateTime](../../core/libs/prx/libSceRtc/Export.cpp) (libSceRtc) - accepted format assumed to be the ISO 8601 subset `YYYY-MM-DDTHH:MM:SS[.ffffff]` (T/t/space separator, optional fractional seconds) with the sibling RFC 3339 zone suffix (`Z` or `±HH:MM`); a string without a zone is taken as UTC, and anything outside this shape throws instead of returning a parse error, unverified against hardware
|
||||
- [AMPR WaitOnAddress / WaitOnCounter](../../core/libs/prx/libkernel/Apr/src/Apr.cpp) (libSceAmpr) - compare encoding assumed to be the WAIT_REG_MEM one (0 always, 1 <, 2 <=, 3 ==, 4 !=, 5 >=, 6 >)
|
||||
|
|
|
|||
Loading…
Reference in New Issue