| 193 | } |
| 194 | |
| 195 | bool ReadStream(VideoBackendPlayer& player, VideoPlayerMF& playerMF, DWORD streamIndex, TimeSpan dt) |
| 196 | { |
| 197 | PROFILE_CPU_NAMED("ReadStream"); |
| 198 | ZoneText(player.DebugUrl, player.DebugUrlLen); |
| 199 | const bool isVideo = streamIndex == MF_SOURCE_READER_FIRST_VIDEO_STREAM; |
| 200 | const bool isAudio = streamIndex == MF_SOURCE_READER_FIRST_AUDIO_STREAM; |
| 201 | int32 goodSamples = 1; |
| 202 | TimeSpan validTimeRangeStart(0), validTimeRangeEnd(0); |
| 203 | if (isAudio) |
| 204 | { |
| 205 | constexpr int32 AudioFramesQueue = 10; // How many frames to read into the audio buffers queue in advance (to improve audio playback smoothness) |
| 206 | if (player.AudioBufferDuration.Ticks == 0) |
| 207 | { |
| 208 | // Read more samples for audio to enqueue multiple audio buffers for smoother playback |
| 209 | goodSamples = AudioFramesQueue; |
| 210 | } |
| 211 | else |
| 212 | { |
| 213 | // Skip reading if the last sample was already over this range (we've got enough in a queue) |
| 214 | validTimeRangeStart = player.AudioBufferTime - player.AudioBufferDuration * AudioFramesQueue; |
| 215 | validTimeRangeEnd = validTimeRangeStart + player.AudioBufferDuration; |
| 216 | if (Math::IsInRange(playerMF.Time, validTimeRangeStart, validTimeRangeEnd)) |
| 217 | { |
| 218 | return false; |
| 219 | } |
| 220 | |
| 221 | // Allow to read future samples within queue range |
| 222 | validTimeRangeStart = player.AudioBufferTime - player.AudioBufferDuration; |
| 223 | validTimeRangeEnd = player.AudioBufferTime + player.AudioBufferDuration * AudioFramesQueue; |
| 224 | |
| 225 | // Read more samples to keep queue at capacity |
| 226 | TimeSpan targetQueueEnd = playerMF.Time + player.AudioBufferDuration * AudioFramesQueue; |
| 227 | TimeSpan activeBufferEnd = player.AudioBufferTime + player.AudioBufferDuration; |
| 228 | TimeSpan missingQueueDuration = targetQueueEnd - activeBufferEnd; |
| 229 | goodSamples = (int32)Math::DivideAndRoundUp(missingQueueDuration.Ticks, player.AudioBufferDuration.Ticks); |
| 230 | if (goodSamples < 1) |
| 231 | goodSamples = 1; |
| 232 | } |
| 233 | } |
| 234 | else if (isVideo) |
| 235 | { |
| 236 | // Check if the current frame is valid (eg. when playing 24fps video at 60fps) |
| 237 | if (player.VideoFrameDuration.Ticks > 0 && |
| 238 | Math::IsInRange(playerMF.Time, player.VideoFrameTime, player.VideoFrameTime + player.VideoFrameDuration)) |
| 239 | { |
| 240 | return false; |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | // Read samples until frame is matching the current time |
| 245 | int32 samplesLeft = 500; |
| 246 | int32 goodSamplesLeft = goodSamples; |
| 247 | HRESULT hr; |
| 248 | for (; samplesLeft > 0 && goodSamplesLeft > 0; samplesLeft--) |
| 249 | { |
| 250 | // Read sample |
| 251 | DWORD flags = 0; |
| 252 | LONGLONG samplePos = 0, sampleDuration = 0; |
no test coverage detected