avplayer: report loop boundaries when decoded output is delivered

This commit is contained in:
nmzik 2026-09-13 16:27:57 +04:00
parent f3c82a317a
commit b67cb81359
1 changed files with 23 additions and 3 deletions

View File

@ -552,6 +552,7 @@ private:
struct ReadyFrame {
std::unique_ptr<GuestBuffer> buffer;
AvPlayerFrameInfoEx info {};
uint64_t timestamp_offset = 0;
};
class FileStreamer {
@ -933,6 +934,7 @@ public:
}
current_video = std::move(*frame);
*out = current_video->info;
RecordLoopBoundary(*current_video);
if (deliver_seek_frame) {
seek_video_frame_pending = false;
}
@ -963,11 +965,25 @@ public:
std::memcpy(out->details.audio.language_code,
current_audio->info.details.audio.language_code, 4);
last_audio_ts = out->time_stamp;
RecordLoopBoundary(*current_audio);
return true;
}
std::optional<int32_t> TakeWarning() { return warnings.TryPop(); }
std::optional<int32_t> TakeWarning() {
std::lock_guard lock(mutex);
if (pending_loop_warnings == 0) {
return std::nullopt;
}
--pending_loop_warnings;
return AVPLAYER_WARNING_LOOPING_BACK;
}
private:
void RecordLoopBoundary(const ReadyFrame& frame) {
if (frame.timestamp_offset > last_output_loop_offset) {
last_output_loop_offset = frame.timestamp_offset;
++pending_loop_warnings;
}
}
void Close() {
Stop();
if (fmt != nullptr) {
@ -1014,6 +1030,8 @@ private:
audio_done = true;
seek_video_frame_pending = false;
last_audio_ts = 0;
last_output_loop_offset = 0;
pending_loop_warnings = 0;
current_video = std::move(delivered_video);
current_audio = std::move(delivered_audio);
retired_video = std::move(in_flight_video);
@ -1220,7 +1238,6 @@ private:
if (avformat_seek_file(fmt, stream, INT64_MIN, 0, INT64_MAX, 0) < 0) {
break;
}
warnings.Push(AVPLAYER_WARNING_LOOPING_BACK);
continue;
}
if (result != AVERROR_EOF && !worker_stop) {
@ -1340,6 +1357,7 @@ private:
return false;
}
ready.info.time_stamp += timestamp_offset;
ready.timestamp_offset = timestamp_offset;
frames.Push(std::move(ready));
av_frame_free(&frame);
}
@ -1603,7 +1621,6 @@ private:
std::optional<ReadyFrame> current_video;
std::optional<ReadyFrame> current_audio;
std::deque<std::unique_ptr<GuestBuffer>> retired_video;
WorkQueue<int32_t> warnings;
LibKernel::Pthread demux_thread = nullptr;
LibKernel::Pthread video_thread = nullptr;
LibKernel::Pthread audio_thread = nullptr;
@ -1623,6 +1640,8 @@ private:
uint32_t sync_mode = 0;
uint64_t start_time_ms = 0;
uint64_t last_audio_ts = 0;
uint64_t last_output_loop_offset = 0;
uint32_t pending_loop_warnings = 0;
std::chrono::steady_clock::time_point clock_start {};
std::chrono::steady_clock::time_point pause_time {};
std::chrono::steady_clock::duration paused_extra {};
@ -1951,6 +1970,7 @@ Bool KYTY_SYSV_ABI AvPlayerGetVideoData(AvPlayerInternal* h, AvPlayerFrameInfo*
video_info->details.video.height = ex.details.video.height;
video_info->details.video.aspect_ratio = ex.details.video.aspect_ratio;
std::memcpy(video_info->details.video.language_code, ex.details.video.language_code, 4);
pump_warnings(h);
return 1;
}
Bool KYTY_SYSV_ABI AvPlayerGetVideoDataEx(AvPlayerInternal* h, AvPlayerFrameInfoEx* video_info) {