הזרמת וידאו אדפטיבית HLS/DASH באפליקציות מובייל
כאשר אפליקציית מובייל מזרימה וידאו דרך רשת LTE לא יציבה, קבצי MP4 סטנדרטיים גורמים לפיקסולציה ולבאפרינג מתמשך. נתקלנו בזה עשרות פעמים ובנינו ארכיטקטורת נגן חזקה. הפתרון הוא הזרמה אדפטיבית באמצעות HLS (HTTP Live Streaming) או DASH (Dynamic Adaptive Streaming over HTTP). הנגן טוען מניפסט (.m3u8 עבור HLS, .mpd עבור DASH) המתאר מקטעי וידאו בקצבי סיביות שונים. על ידי מעבר דינמי בין איכויות בהתאם לרוחב הפס הזמין, אנו משיגים השמעה חלקה אפילו בחיבורים חלשים.
רקורד שלנו: 5+ שנים של בניית נגני וידאו מותאמים אישית מאפס, עם למעלה מ-20 פרויקטים שהושלמו עבור iOS ו-Android. אנו מבטיחים השמעה יציבה אפילו ברשתות עם רוחב פס נמוך. צרו קשר כדי להעריך את הפרויקט שלכם—נמליץ על הסט הטכנולוגי האופטימלי לדרישות שלכם.
HLS לעומת DASH: באיזה מהם לבחור
| פרמטר | HLS | DASH |
|---|---|---|
| תמיכה מקורית ב-iOS | כן (AVFoundation) | לא (דורש ספריית צד שלישי) |
| תמיכה מקורית ב-Android | לא (דורש ExoPlayer) | לא (דורש ExoPlayer) |
| חביון (סטנדרטי) | 6–30 שניות | 2–10 שניות |
| חביון נמוך | LL-HLS: ~2 שניות | LL-DASH: ~1–3 שניות |
| תמיכה ב-DRM | FairPlay (iOS), Widevine | Widevine, PlayReady |
בפועל: אם הקהל שלכם הוא בעיקר iOS ו-DRM אינו נדרש, HLS אינו דורש ספריית צד שלישי. עבור אפליקציות חוצות פלטפורמות עם חביון מינימלי, DASH דרך ExoPlayer הוא הדרך הנכונה. תיעוד ExoPlayer: https://exoplayer.dev
למה AVPlayer עדיף על נגני צד שלישי ב-iOS
AVPlayer מובנה במערכת—הוא משתמש בפענוח חומרה ומנהל את הבאפרינג אוטומטית. עבור HLS, הוא מציע את הביצועים הטובים ביותר, ומספק זמן התחלה מהיר פי 2–3 בהשוואה לפתרונות מותאמים אישית הבנויים על SDK של צד שלישי. דוגמת אתחול:
let asset = AVURLAsset(url: hlsURL, options: [ "AVURLAssetHTTPHeaderFieldsKey": ["Authorization": "Bearer \(token)"] ])
let item = AVPlayerItem(asset: asset)
player = AVPlayer(playerItem: item)נטר את הבאפרינג באמצעות KVO על let asset = AVURLAsset(url: hlsURL, options: [ "AVURLAssetHTTPHeaderFieldsKey": ["Authorization": "Bearer \(token)"] ]) let item = AVPlayerItem(asset: asset) player = AVPlayer(playerItem: item) ו-item.isPlaybackLikelyToKeepUp. כאשר item.loadedTimeRanges—הצג ספינר; כאשר isPlaybackLikelyToKeepUp == false—הסתר אותו.
טען מראש את הווידאו הבא על ידי יצירת true מראש והוספתו ל-AVPlayerItem; המקטע הראשון של הווידאו הבא מתחיל להוריד ברקע.
חשוב: AVPlayer תומך ב-LL-HLS החל מ-iOS 12. כדי להפעיל חביון נמוך, הגדר AVQueuePlayer. זה מקטין את הבאפר ל-1 שנייה אך מגדיל את הסיכון להפרעות. אנו ממליצים על ערך זה רק עבור רשתות יציבות.
כיצד ExoPlayer מטפל ב-HLS ו-DASH ב-Android
ExoPlayer היא הספרייה המומלצת של Google. היא בוחרת אוטומטית את המקור בהתאם לסיומת ה-URL. דוגמת קוד:
val player = ExoPlayer.Builder(context).build()
// HLS
val hlsItem = MediaItem.Builder()
.setUri("https://example.com/stream.m3u8")
.build()
// DASH
val dashItem = MediaItem.Builder()
.setUri("https://example.com/manifest.mpd")
.build()
player.setMediaItem(hlsItem)
player.prepare()
player.play()עבור כותרות מותאמות אישית:
val dataSourceFactory = DefaultHttpDataSource.Factory()
.setDefaultRequestProperties(mapOf("Authorization" to "Bearer $token"))
val hlsSource = HlsMediaSource.Factory(dataSourceFactory)
.createMediaSource(MediaItem.fromUri(uri)) קצב סיביות אדפטיבי
כברירת מחדל, ExoPlayer משתמש ב-playerItem.preferredForwardBufferDuration = 1.0—הוא מחליף איכות בגבולות המקטעים (בדרך כלל כל 2–10 שניות). כדי להגדיר איכות מינימלית:
val trackSelector = DefaultTrackSelector(context)
trackSelector.parameters = trackSelector.buildUponParameters()
.setMaxVideoSizeSd() // не выше 480p на слабых устройствах
.build()ב-iOS, val player = ExoPlayer.Builder(context).build() // HLS val hlsItem = MediaItem.Builder() .setUri("https://example.com/stream.m3u8") .build() // DASH val dashItem = MediaItem.Builder() .setUri("https://example.com/manifest.mpd") .build() player.setMediaItem(hlsItem) player.prepare() player.play() מגביל את קצב הסיביות העליון; זה יכול לחסוך עד 40% מצריכת הנתונים.
כיצד להגדיר HLS עם חביון נמוך
Low‑Latency HLS (LL‑HLS) מקטין את החביון לכ-2 שניות באמצעות מקטעים חלקיים ודחיפת HTTP/2.
- ב-iOS: הגדר
val dataSourceFactory = DefaultHttpDataSource.Factory() .setDefaultRequestProperties(mapOf("Authorization" to "Bearer $token")) val hlsSource = HlsMediaSource.Factory(dataSourceFactory) .createMediaSource(MediaItem.fromUri(uri))ו-AdaptiveTrackSelection. - ב-Android (ExoPlayer 2.12+): צור
val trackSelector = DefaultTrackSelector(context) trackSelector.parameters = trackSelector.buildUponParameters() .setMaxVideoSizeSd() // не выше 480p на слабых устройствах .build()עםAVPlayerItem.preferredPeakBitRate = 2_000_000והעבר אותו ל-playerItem.preferredForwardBufferDuration = 1.0. - ודא שה-CDN שלך תומך במקטעים חלקיים (לדוגמה, AWS MediaTailor או Akamai LL‑HLS).
- בדוק על מכשירים אמיתיים—ההשמעה אמורה להתחיל תוך כ-2 שניות.
| פרמטר | LL‑HLS | LL‑DASH |
|---|---|---|
| חביון | 2–3 שניות | 1–3 שניות |
| תמיכה ב-iOS | כן (iOS 12+) | לא |
| תמיכה ב-Android | ExoPlayer 2.12+ | ExoPlayer 2.12+ |
| מורכבות היישום | בינונית | גבוהה |
טיפול בשגיאות רשת
הרשת אינה אמינה—מקטע נכשל בטעינה, המניפסט מחזיר 403, ה-CDN מגיב עם 5xx. ExoPlayer מנסה שוב אוטומטית עם השהיה אקספוננציאלית (player.automaticallyPreservesTimeOffsetFromLive = true). מדיניות מותאמת אישית:
class RetryPolicy : DefaultLoadErrorHandlingPolicy() {
override fun getRetryDelayMsFor(loadErrorInfo: LoadErrorInfo) =
if (loadErrorInfo.errorCount < 5) 1000L * loadErrorInfo.errorCount else RETRY_DELAY_UNSET
}ב-iOS: LiveConfiguration → targetOffsetMs = 2000—קרא את MediaItem.Builder().setLiveConfiguration(...), הצג כפתור "נסה שוב". חשוב: לאחר שגיאה, זרוק את DefaultLoadErrorHandlingPolicy הישן וצור חדש; אחרת, ניסיון חוזר עלול לא לעבוד.
מקרה בוחן: אפליקציית הזרמת ספורט חיה
עבור אפליקציית הזרמת ספורט חיה של לקוח, הפחתנו את הבאפרינג הראשוני מ-8 שניות ל-1.2 שניות על ידי יישום LL‑HLS ב-iOS ואופטימיזציה של גודל המקטעים ל-2 שניות. ב-Android, השתמשנו ב-ExoPlayer עם class RetryPolicy : DefaultLoadErrorHandlingPolicy() { override fun getRetryDelayMsFor(loadErrorInfo: LoadErrorInfo) = if (loadErrorInfo.errorCount < 5) 1000L * loadErrorInfo.errorCount else RETRY_DELAY_UNSET } מותאם אישית שהפחית אירועי רבאפרינג ב-60% בזמן תעבורה שיא. זה הביא לעלייה של 30% בשימור משתמשים.
מה כלול בעבודה
- ניתוח דרישות ובחירת פרוטוקול (HLS/DASH)
- פיתוח נגן עם ABR, קאשינג ו-DRM (FairPlay/Widevine)
- שילוב אנליטיקה (אירועי באפרינג, שגיאות)
- תיעוד API ומדריך פריסה
- בדיקות על מכשירים אמיתיים עם מהירויות רשת שונות
- תמיכה לאחר השקה (חודש אחד)
טעויות נפוצות בשילוב DRM
- הגדרה שגויה של
AVPlayerItem.status == .failedעבור FairPlay—חסר אישור SPC. - עבור Widevine ב-Android—אי מסירת הרישיון ב-
player.currentItem?.error. - שכחת לבדוק תמיכת DRM במכשיר: ב-Android—
NSError, ב-iOS—AVPlayerItem.
לוחות זמנים משוערים
נגן HLS בפלטפורמה אחת עם ABR וטיפול בשגיאות—החל מיומיים. חוצה פלטפורמות (iOS + Android) עם DASH, DRM ובחירת איכות ידנית—4 עד 5 ימים. אם נדרש LL‑HLS או שילוב DRM ספציפי, לוח הזמנים עלול לגדול ב-1–2 ימים. קבלו ייעוץ—נחשב את לוח הזמנים המדויק לפרויקט שלכם.
הזמינו פיתוח נגן וידאו מותאם אישית: אנו מבטיחים יציבות וחביון נמוך. נעריך את הפרויקט שלכם.
מפרט HLS Authoring של Apple: https://developer.apple.com/documentation/http_live_streaming







