mirror of
https://github.com/UrloMythus/UnHided.git
synced 2026-06-10 09:10:23 +00:00
new version
This commit is contained in:
@@ -52,6 +52,7 @@ class DASHPreBuffer(BasePrebuffer):
|
||||
max_memory_percent=settings.dash_prebuffer_max_memory_percent,
|
||||
emergency_threshold=settings.dash_prebuffer_emergency_threshold,
|
||||
segment_ttl=settings.dash_segment_cache_ttl,
|
||||
prebuffer_lock_timeout=settings.dash_prebuffer_lock_timeout,
|
||||
)
|
||||
|
||||
self.inactivity_timeout = settings.dash_prebuffer_inactivity_timeout
|
||||
@@ -100,9 +101,26 @@ class DASHPreBuffer(BasePrebuffer):
|
||||
logger.warning(f"No profiles found in MPD for prebuffering: {mpd_url}")
|
||||
return
|
||||
|
||||
# Now get segments for each profile by parsing with profile_id
|
||||
# Early-out for SegmentBase VOD content.
|
||||
# SegmentBase profiles have initRange set (byte range within a large single file).
|
||||
# Prebuffering them means downloading 100 MB+ per profile — not useful.
|
||||
# If every profile is SegmentBase, skip the expensive per-profile segment
|
||||
# parsing entirely and only prewarm init segments via the direct cache path.
|
||||
all_segment_base = all(p.get("initRange") is not None for p in base_profiles)
|
||||
if all_segment_base and not is_live:
|
||||
logger.info(
|
||||
f"[prebuffer_dash_manifest] Skipping SegmentBase VOD: {mpd_url} "
|
||||
f"({len(base_profiles)} profiles, all SegmentBase)"
|
||||
)
|
||||
return
|
||||
|
||||
# Now get segments for each profile by parsing with profile_id.
|
||||
# Skip SegmentBase profiles — their "segments" are whole-file downloads.
|
||||
profiles_with_segments = []
|
||||
for profile in base_profiles:
|
||||
if profile.get("initRange") is not None:
|
||||
# SegmentBase profile — skip expensive segment parsing
|
||||
continue
|
||||
profile_id = profile.get("id")
|
||||
if profile_id:
|
||||
parsed_with_segments = await get_cached_mpd(
|
||||
@@ -122,8 +140,10 @@ class DASHPreBuffer(BasePrebuffer):
|
||||
"last_access": time.time(),
|
||||
}
|
||||
|
||||
# Prebuffer init segments and media segments
|
||||
await self._prebuffer_profiles(profiles_with_segments, headers, is_live)
|
||||
# For live streams we only prewarm init segments by default; media prefetch
|
||||
# is driven by player/playlist requests to avoid lock contention storms.
|
||||
include_media = not is_live or settings.dash_live_initial_media_prebuffer
|
||||
await self._prebuffer_profiles(profiles_with_segments, headers, is_live, include_media=include_media)
|
||||
|
||||
# Start cleanup task if not running
|
||||
self._ensure_cleanup_task_running()
|
||||
@@ -140,6 +160,7 @@ class DASHPreBuffer(BasePrebuffer):
|
||||
profiles: List[dict],
|
||||
headers: Dict[str, str],
|
||||
is_live: bool = False,
|
||||
include_media: bool = True,
|
||||
) -> None:
|
||||
"""
|
||||
Pre-buffer init segments and media segments for all profiles.
|
||||
@@ -151,6 +172,7 @@ class DASHPreBuffer(BasePrebuffer):
|
||||
profiles: List of parsed profiles with resolved URLs
|
||||
headers: Headers to use for requests
|
||||
is_live: Whether this is a live stream
|
||||
include_media: Whether media segments should be prebuffered (init segments are always prewarmed)
|
||||
"""
|
||||
if self._should_skip_for_memory():
|
||||
logger.warning("Memory usage too high, skipping prebuffer")
|
||||
@@ -161,13 +183,29 @@ class DASHPreBuffer(BasePrebuffer):
|
||||
init_urls = []
|
||||
|
||||
for profile in profiles:
|
||||
# Skip SegmentBase profiles entirely.
|
||||
# SegmentBase "segments" are byte-range slices of a single large file
|
||||
# (e.g. a25.mp4 = 122 MB). Prebuffering them without a Range header
|
||||
# would download the entire file per profile — potentially GB of data
|
||||
# for all audio tracks before a single second of playback is served.
|
||||
# SegmentBase is identified by the profile having initRange (byte range
|
||||
# within the base file) or by segments having mediaRange set.
|
||||
segments = profile.get("segments", [])
|
||||
is_segment_base = profile.get("initRange") is not None or (
|
||||
segments and segments[0].get("mediaRange") is not None
|
||||
)
|
||||
if is_segment_base:
|
||||
logger.debug(f"[_prebuffer_profiles] Skipping SegmentBase profile: {profile.get('id')}")
|
||||
continue
|
||||
|
||||
# Collect init segment URL
|
||||
init_url = profile.get("initUrl")
|
||||
if init_url:
|
||||
init_urls.append(init_url)
|
||||
|
||||
# Get segments to prebuffer
|
||||
segments = profile.get("segments", [])
|
||||
if not include_media:
|
||||
continue
|
||||
|
||||
if not segments:
|
||||
continue
|
||||
|
||||
@@ -283,7 +321,13 @@ class DASHPreBuffer(BasePrebuffer):
|
||||
if segment_urls:
|
||||
logger.debug(f"Prefetching {len(segment_urls)} upcoming segments from index {current_index + 1}")
|
||||
# Run prefetch in background
|
||||
asyncio.create_task(self.prebuffer_segments_batch(segment_urls, headers, max_concurrent=3))
|
||||
asyncio.create_task(
|
||||
self.prebuffer_segments_batch(
|
||||
segment_urls,
|
||||
headers,
|
||||
max_concurrent=max(settings.dash_prefetch_max_concurrent, 1),
|
||||
)
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to prefetch upcoming segments: {e}")
|
||||
@@ -322,7 +366,13 @@ class DASHPreBuffer(BasePrebuffer):
|
||||
|
||||
if segment_urls:
|
||||
logger.debug(f"Live playlist prefetch: {len(segment_urls)} segments")
|
||||
asyncio.create_task(self.prebuffer_segments_batch(segment_urls, headers, max_concurrent=3))
|
||||
asyncio.create_task(
|
||||
self.prebuffer_segments_batch(
|
||||
segment_urls,
|
||||
headers,
|
||||
max_concurrent=max(settings.dash_prefetch_max_concurrent, 1),
|
||||
)
|
||||
)
|
||||
|
||||
def _ensure_cleanup_task_running(self) -> None:
|
||||
"""Ensure the cleanup task is running."""
|
||||
|
||||
Reference in New Issue
Block a user