mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-18 23:07:07 -05:00
fix(videodec2): answer picture info from the decoder that last wrote the buffer
sceVideodec2GetPictureInfo searched the live decoders in handle order and returned the first one that had ever written the queried frame buffer. When two decoders wrote the same address, the lower handle answered with stale timestamps, a stale AVC decoder answered for an HEVC or VP9 picture, a stale HEVC or VP9 decoder made an AVC query throw, and resetting or deleting the decoder that wrote the buffer last exposed the older decoder's picture again. Record the decoder that last published a picture into each frame buffer and answer from that decoder only. Reset and Delete drop only the decoder's own records, so another decoder's picture is never removed or brought back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9aa5fd2900
commit
48919d01e4
2 files changed
+189
-9
No files matched your search
@@ -147,6 +147,7 @@ struct Decoder {
|
||||
|
||||
std::mutex lock;
|
||||
std::map<std::uint64_t, std::shared_ptr<Decoder>> decoders;
|
||||
std::map<const void*, std::uint64_t> pictureOwners;
|
||||
std::uint64_t nextDecoder = 1;
|
||||
std::uint64_t nextQueue = 1;
|
||||
|
||||
@@ -266,7 +267,7 @@ bool WriteNv12(Decoder& decoder, const AVFrame& frame, std::uint8_t* target, std
|
||||
return sws_scale(decoder.scaler, frame.data, frame.linesize, 0, frame.height, planes, strides) == frame.height;
|
||||
}
|
||||
|
||||
void EmitDecoded(Decoder& decoder, FrameBuffer* frame, OutputInfo* output) {
|
||||
void EmitDecoded(std::uint64_t handle, Decoder& decoder, FrameBuffer* frame, OutputInfo* output) {
|
||||
output->isValid = false;
|
||||
output->isErrorFrame = false;
|
||||
output->pictureCount = 0;
|
||||
@@ -302,6 +303,8 @@ void EmitDecoded(Decoder& decoder, FrameBuffer* frame, OutputInfo* output) {
|
||||
output->framePitchInBytes = pitch;
|
||||
}
|
||||
decoder.pictures[frame->frameBuffer] = timestamps;
|
||||
std::lock_guard guard(lock);
|
||||
if (decoders.contains(handle)) pictureOwners[frame->frameBuffer] = handle;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -358,6 +361,7 @@ int APS5_VABI sceVideodec2CreateDecoder_nid_postfix(const DecoderConfigInfo* con
|
||||
int APS5_VABI sceVideodec2DeleteDecoder_nid_postfix(std::uint64_t handle) {
|
||||
std::lock_guard guard(lock);
|
||||
if (decoders.erase(handle) == 0) throw std::runtime_error("Videodec2: invalid decoder handle");
|
||||
std::erase_if(pictureOwners, [handle](const auto& owner) { return owner.second == handle; });
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -383,7 +387,7 @@ int APS5_VABI sceVideodec2Decode_nid_postfix(std::uint64_t handle, const InputDa
|
||||
packet->pts = decoder.nextKey;
|
||||
decoder.inputs.emplace(decoder.nextKey++, picture);
|
||||
Send(decoder, packet);
|
||||
EmitDecoded(decoder, frame, output);
|
||||
EmitDecoded(handle, decoder, frame, output);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -397,7 +401,7 @@ int APS5_VABI sceVideodec2Flush_nid_postfix(std::uint64_t handle, FrameBuffer* f
|
||||
Send(decoder, nullptr);
|
||||
decoder.flushing = true;
|
||||
}
|
||||
EmitDecoded(decoder, frame, output);
|
||||
EmitDecoded(handle, decoder, frame, output);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -407,6 +411,10 @@ int APS5_VABI sceVideodec2Reset_nid_postfix(std::uint64_t handle) {
|
||||
auto& decoder = *found;
|
||||
std::lock_guard guard(decoder.mutex);
|
||||
decoder.pictures.clear();
|
||||
{
|
||||
std::lock_guard ownersGuard(lock);
|
||||
std::erase_if(pictureOwners, [handle](const auto& owner) { return owner.second == handle; });
|
||||
}
|
||||
avcodec_flush_buffers(decoder.context);
|
||||
decoder.ready.clear();
|
||||
decoder.inputs.clear();
|
||||
@@ -417,15 +425,18 @@ int APS5_VABI sceVideodec2Reset_nid_postfix(std::uint64_t handle) {
|
||||
int APS5_VABI sceVideodec2GetPictureInfo_nid_postfix(const OutputInfo* output, AvcPictureInfo* first, void* second) {
|
||||
(void)second;
|
||||
if (!output || !first) throw std::runtime_error("Videodec2: invalid argument pointer");
|
||||
std::vector<std::shared_ptr<Decoder>> all;
|
||||
{
|
||||
const auto owner = [output]() -> std::uint64_t {
|
||||
std::lock_guard guard(lock);
|
||||
for (const auto& [handle, decoder] : decoders) all.push_back(decoder);
|
||||
}
|
||||
for (const auto& decoder : all) {
|
||||
const auto found = pictureOwners.find(output->frameBuffer);
|
||||
return found != pictureOwners.end() ? found->second : 0;
|
||||
};
|
||||
for (auto handle = owner(); handle != 0; handle = owner()) {
|
||||
const auto decoder = FindDecoder(handle);
|
||||
if (!decoder) continue;
|
||||
std::lock_guard guard(decoder->mutex);
|
||||
if (owner() != handle) continue;
|
||||
const auto found = decoder->pictures.find(output->frameBuffer);
|
||||
if (found == decoder->pictures.end()) continue;
|
||||
if (found == decoder->pictures.end()) throw std::runtime_error("Videodec2: owned picture is missing");
|
||||
if (decoder->codec != CodecAvc) throw std::runtime_error("Videodec2: picture info is only implemented for H.264");
|
||||
const auto& picture = found->second;
|
||||
first->isValid = true;
|
||||
|
||||
Reference in new issue
Block a user