Skip to content

Commit 017bcfe

Browse files
committed
Add HLS streaming support on Windows via IMFMediaEngine
IMFSourceReader does not support HLS on desktop Win32 apps, so this adds a dual-path architecture: HLS URLs (.m3u8) use IMFMediaEngine which has native HLS support on Windows 10+, while all other media continues to use the existing IMFSourceReader path. Key changes: - New HLSPlayer class wrapping IMFMediaEngine with D3D11 frame extraction - Automatic HLS detection (URL pattern + fallback on source reader error) - Live stream handling (duration 0, seeking disabled, EOF retry) - Adaptive bitrate support (resolution re-queried per frame) - Audio handled internally by the engine (no WASAPI needed for HLS)
1 parent 4743724 commit 017bcfe

6 files changed

Lines changed: 925 additions & 18 deletions

File tree

mediaplayer/src/jvmMain/kotlin/io/github/kdroidfilter/composemediaplayer/windows/WindowsVideoPlayerState.kt

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -564,13 +564,16 @@ class WindowsVideoPlayerState : VideoPlayerState {
564564
}
565565
}
566566

567-
// Get the media duration
567+
// Get the media duration (may be 0 for live HLS streams)
568568
val durArr = LongArray(1)
569569
val hrDuration = player.GetMediaDuration(instance, durArr)
570570
if (hrDuration < 0) {
571-
setError("Failed to retrieve duration (hr=0x${hrDuration.toString(16)})")
572-
player.CloseMedia(instance)
573-
return@withLock
571+
// Only fail for non-network sources; network/HLS may lack duration
572+
if (!uri.startsWith("http", ignoreCase = true)) {
573+
setError("Failed to retrieve duration (hr=0x${hrDuration.toString(16)})")
574+
player.CloseMedia(instance)
575+
return@withLock
576+
}
574577
}
575578
_duration = durArr[0] / 10000000.0
576579

@@ -684,7 +687,12 @@ class WindowsVideoPlayerState : VideoPlayerState {
684687
if (instance == 0L) break
685688

686689
if (player.IsEOF(instance)) {
687-
if (loop) {
690+
if (_duration <= 0.0) {
691+
// Live HLS stream — EOF means the live window ended,
692+
// wait and continue (new segments may become available)
693+
delay(1000)
694+
continue
695+
} else if (loop) {
688696
try {
689697
userPaused = false // Reset userPaused when looping
690698
initialFrameRead.set(false) // Reset initialFrameRead flag
@@ -724,6 +732,16 @@ class WindowsVideoPlayerState : VideoPlayerState {
724732
continue
725733
}
726734

735+
// Re-query video size — HLS adaptive bitrate may change resolution
736+
val sizeArr = IntArray(2)
737+
player.GetVideoSize(instance, sizeArr)
738+
if (sizeArr[0] > 0 && sizeArr[1] > 0 &&
739+
(sizeArr[0] != videoWidth || sizeArr[1] != videoHeight)
740+
) {
741+
videoWidth = sizeArr[0]
742+
videoHeight = sizeArr[1]
743+
}
744+
727745
val width = videoWidth
728746
val height = videoHeight
729747

@@ -856,7 +874,11 @@ class WindowsVideoPlayerState : VideoPlayerState {
856874
}
857875

858876
_currentTime = frameData.timestamp
859-
_progress = (_currentTime / _duration).toFloat().coerceIn(0f, 1f)
877+
_progress = if (_duration > 0.0) {
878+
(_currentTime / _duration).toFloat().coerceIn(0f, 1f)
879+
} else {
880+
0f // Live stream — no meaningful progress
881+
}
860882
isLoading = false
861883

862884
delay(1)
@@ -985,6 +1007,7 @@ class WindowsVideoPlayerState : VideoPlayerState {
9851007

9861008
override fun seekTo(value: Float) {
9871009
if (isDisposing.get()) return
1010+
if (_duration <= 0.0) return // Live stream — seeking not supported
9881011

9891012
executeMediaOperation(
9901013
operation = "seek",
@@ -1023,7 +1046,9 @@ class WindowsVideoPlayerState : VideoPlayerState {
10231046
val posArr2 = LongArray(1)
10241047
if (player.GetMediaPosition(instance, posArr2) >= 0) {
10251048
_currentTime = posArr2[0] / 10000000.0
1026-
_progress = (_currentTime / _duration).toFloat().coerceIn(0f, 1f)
1049+
_progress = if (_duration > 0.0) {
1050+
(_currentTime / _duration).toFloat().coerceIn(0f, 1f)
1051+
} else 0f
10271052
}
10281053

10291054
if (!isDisposing.get()) {

mediaplayer/src/jvmMain/native/windows/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ add_library(NativeVideoPlayer SHARED
3333
MediaFoundationManager.h
3434
AudioManager.cpp
3535
AudioManager.h
36+
HLSPlayer.cpp
37+
HLSPlayer.h
3638
jni_bridge.cpp
3739
)
3840

0 commit comments

Comments
 (0)