6.3 KiB
6.3 KiB
Phase 1 Implementation Summary - Playback Timing Fix
Date: 2025-10-07 Status: ✅ Implemented, Ready for Testing
Changes Made
1. PlaybackController.h
Added:
- Forward declaration:
class FrameProcessor; - Public method:
void SetFrameProcessor(FrameProcessor* processor) - Public method:
bool IsFrameProcessing() const - Private member:
FrameProcessor* m_frameProcessor = nullptr
Lines changed: +5 lines
2. PlaybackController.cpp
Added:
- Include:
#include "FrameProcessor.h" - Implementation of
IsFrameProcessing()method - Frame completion wait logic in
TimingThreadLoop()
Modified:
void PlaybackController::TimingThreadLoop()
{
// ... existing code ...
while (!m_shouldStopTiming && m_isPlaying) {
auto frameStart = std::chrono::high_resolution_clock::now();
// Signal frame processing
if (m_frameReadyCallback) {
m_frameReadyCallback();
}
// ✅ NEW: Wait for frame processing completion (max 100ms timeout)
int waitCount = 0;
while (IsFrameProcessing() && waitCount < 100) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
waitCount++;
}
if (waitCount >= 100) {
LOGF_WARNING("[PlaybackController] Frame processing timeout after 100ms");
}
// Update frame counter
m_currentFrame++;
m_currentTime = m_currentFrame / m_frameRate;
// Sleep until next frame
std::this_thread::sleep_until(nextFrame);
}
}
bool PlaybackController::IsFrameProcessing() const
{
return m_frameProcessor && m_frameProcessor->IsProcessing();
}
Lines changed: +20 lines
3. VideoPlayerControl2.xaml.cpp
Modified:
void VideoPlayerControl2::LoadVideo(...)
{
// ... existing code ...
if (success) {
// ✅ NEW: Link FrameProcessor to PlaybackController
if (m_frameProcessor) {
m_playbackController->SetFrameProcessor(m_frameProcessor.get());
m_frameProcessor->PrepareVideoTexture(videoWidth, videoHeight);
}
// ... rest of code ...
}
}
Lines changed: +1 line
Total Changes
- Files modified: 3
- Lines added: ~26 lines
- Complexity: Very Low
- Risk: Minimal
How It Works
Before Fix (Broken)
Timeline:
0ms : Timing thread signals "process frame N"
0ms : FrameProcessor starts decode
10-15ms : CUDA decode completes
20-25ms : UI render completes
33.33ms : Timing thread signals "process frame N+1" (DOESN'T WAIT!)
→ If frame N not done, m_frameProcessing check FAILS
→ Frame N+1 DROPPED
→ Result: Jerky playback
After Fix (Working)
Timeline:
0ms : Timing thread signals "process frame N"
0ms : FrameProcessor starts decode (m_frameProcessing = true)
10-15ms : CUDA decode completes
20-25ms : UI render completes
25ms : FrameProcessor done (m_frameProcessing = false)
25ms : Timing thread detects completion via IsFrameProcessing()
25ms : Timing thread advances frame counter
33.33ms : Sleep completes, signal "process frame N+1"
→ NO FRAME DROPS
→ Result: Smooth playback
Build Status
✅ Build successful
- VavCore-debug.dll: Built
- Vav2Player.exe: Built
- No errors, no warnings (related to changes)
Testing Instructions
1. Launch Application
cd "D:/Project/video-av1/vav2/platforms/windows/applications/vav2player/Vav2Player/x64/Debug/Vav2Player"
./Vav2Player.exe
2. Load Test Video
- Use file picker to load:
D:/Project/video-av1/sample/simple_test.webm - Or any 30fps AV1/VP9 video
3. Observe Playback
Expected Results:
- ✅ Smooth playback (no jerking)
- ✅ Consistent 30fps
- ✅ Zero frame drops
Check Logs:
[PlaybackController] Frame processing timeout after 100ms ← Should NOT appear
[FrameProcessor] Frame dropped (#X) ← Should be 0
4. Long Duration Test
- Play for 5 minutes
- Monitor for any jerking
- Check frame drop counter: should remain 0
Success Criteria
Primary
- Video plays smoothly (no "통통 튐")
- No frame drops during 5-minute playback
- User confirms smooth visual playback
Secondary
- Logs show no timeout warnings
- Frame intervals consistent at 33.33ms
- CPU usage same as before
If Problems Occur
Rollback Procedure
-
Revert PlaybackController.h:
- Remove forward declaration
- Remove SetFrameProcessor and IsFrameProcessing methods
- Remove m_frameProcessor member
-
Revert PlaybackController.cpp:
- Remove FrameProcessor.h include
- Restore original TimingThreadLoop
- Remove IsFrameProcessing implementation
-
Revert VideoPlayerControl2.xaml.cpp:
- Remove SetFrameProcessor call
Time: < 5 minutes
Alternative: Git Revert
git diff HEAD # Review changes
git checkout -- <file> # Revert specific file
Next Steps (Phase 2)
If Phase 1 successful:
- Proceed with Fence removal (optional cleanup)
- See:
Playback_Timing_Fix_Design.mdPhase 2
If Phase 1 issues:
- Debug specific problem
- Check FrameProcessor::IsProcessing() behavior
- Verify m_frameProcessing atomic flag operations
Technical Notes
Thread Safety
IsFrameProcessing()reads atomic boolm_frameProcessing✅ Thread-safeSetFrameProcessor()called during initialization only ✅ No race condition- Non-owning pointer (FrameProcessor lifetime > PlaybackController) ✅ Safe
Performance Impact
- Wait loop: 1ms sleep per iteration
- Typical wait: 20-25ms (20-25 iterations)
- CPU overhead: Negligible (< 1%)
Timeout Behavior
- Max wait: 100ms (100 iterations)
- If timeout occurs: Warning logged, playback continues
- Prevents infinite loop if frame processor hangs
Logs to Monitor
Good Playback
[PlaybackController] Timing thread started
[FrameProcessor] ProcessFrame START (decoded: 0, dropped: 0)
[FrameProcessor] Decode SUCCESS - frame decoded
[FrameProcessor] Render succeeded
[FrameProcessor] CLEARING m_frameProcessing flag
[PlaybackController] [No timeout warnings]
Bad Playback (Should NOT see)
[PlaybackController] Frame processing timeout after 100ms
[FrameProcessor] Frame dropped (#1) - previous frame still processing
Contact
Implementation: Claude Code Review: User Date: 2025-10-07