ExoPlayer תומך ב-HLS עם כמה פורמטים של קונטיינרים. בנוסף, צריכה להיות תמיכה בפורמטים של קטעי האודיו והווידאו שכלולים במודעה (פרטים מופיעים בקטע פורמטים של קטעי טעימות). אנחנו ממליצים מאוד ליוצרי תוכן ב-HLS ליצור שידורי HLS באיכות גבוהה, כפי שמתואר כאן.
תכונה | נתמך | תגובות |
---|---|---|
קונטיינרים | ||
MPEG-TS | כן | |
FMP4/CMAF | כן | |
ADTS (AAC) | כן | |
MP3 | כן | |
כתוביות | ||
CEA-608 | כן | |
CEA-708 | כן | |
WebVTT | כן | |
מטא-נתונים | ||
ID3 | כן | |
SCTE-35 | לא | |
הגנה על תוכן | ||
AES-128 | כן | |
דוגמה ל-AES-128 | לא | |
Widevine | כן | API מגרסה 19 ואילך (סכימת 'cenc') ומגרסה 25 ואילך (סכימת 'cbcs') |
PlayReady SL2000 | כן | Android TV בלבד |
שליטה בשרת | ||
עדכוני Delta | כן | |
חסימה של טעינת הפלייליסט מחדש | כן | |
חסימה של טעינת רמזים לטעינה מראש | כן | מלבד טווחי בייטים באורך לא מוגדר |
הפעלה בשידור חי | ||
הפעלה רגילה בשידור חי | כן | |
HLS עם זמן אחזור קצר (Apple) | כן | |
HLS בזמן אחזור קצר (קהילתי) | לא | |
Common Media Client Data (CMCD) | כן | מדריך לשילוב |
שימוש ב-MediaItem
כדי להפעיל שידור בפרוטוקול HLS, צריך להסתמך על מודול HLS.
Kotlin
implementation("androidx.media3:media3-exoplayer-hls:1.4.1")
Groovy
implementation "androidx.media3:media3-exoplayer-hls:1.4.1"
לאחר מכן תוכלו ליצור MediaItem
עבור URI של פלייליסט HLS ולהעביר אותו לנגן.
Kotlin
// Create a player instance. val player = ExoPlayer.Builder(context).build() // Set the media item to be played. player.setMediaItem(MediaItem.fromUri(hlsUri)) // Prepare the player. player.prepare()
Java
// Create a player instance. ExoPlayer player = new ExoPlayer.Builder(context).build(); // Set the media item to be played. player.setMediaItem(MediaItem.fromUri(hlsUri)); // Prepare the player. player.prepare();
אם כתובת ה-URI לא מסתיימת ב-.m3u8
, אפשר להעביר את MimeTypes.APPLICATION_M3U8
אל setMimeType
של MediaItem.Builder
כדי לציין במפורש את סוג התוכן.
ה-URI של פריט המדיה עשוי להפנות לפלייליסט מדיה או לפלייליסט עם וריאנטים מרובים. אם ה-URI מפנה לפלייליסט עם כמה וריאנטים שמוצהרים בו כמה תגי #EXT-X-STREAM-INF
, המערכת של ExoPlayer תתאים את עצמה באופן אוטומטי בין הווריאנטים, תוך התחשבות ברוחב הפס הזמין וביכולות המכשיר.
שימוש ב-HlsMediaSource
לאפשרויות התאמה אישית נוספות, אפשר ליצור HlsMediaSource
ולהעביר אותו ישירות לנגן במקום MediaItem
.
Kotlin
// Create a data source factory. val dataSourceFactory: DataSource.Factory = DefaultHttpDataSource.Factory() // Create a HLS media source pointing to a playlist uri. val hlsMediaSource = HlsMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(hlsUri)) // Create a player instance. val player = ExoPlayer.Builder(context).build() // Set the HLS media source as the playlist with a single media item. player.setMediaSource(hlsMediaSource) // Prepare the player. player.prepare()
Java
// Create a data source factory. DataSource.Factory dataSourceFactory = new DefaultHttpDataSource.Factory(); // Create a HLS media source pointing to a playlist uri. HlsMediaSource hlsMediaSource = new HlsMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(hlsUri)); // Create a player instance. ExoPlayer player = new ExoPlayer.Builder(context).build(); // Set the HLS media source as the playlist with a single media item. player.setMediaSource(hlsMediaSource); // Prepare the player. player.prepare();
גישה למניפסט
כדי לאחזר את המניפסט הנוכחי, קוראים לפונקציה Player.getCurrentManifest
.
עבור HLS, צריך להמיר את האובייקט המוחזר ל-HlsManifest
. הקריאה החוזרת onTimelineChanged
של Player.Listener
נקראת גם בכל פעם שהמניפסט נטען. הדבר יקרה פעם אחת לגבי תוכן על פי דרישה, ויכול להיות שהוא יקרה הרבה פעמים לגבי תוכן בשידור חי. קטע הקוד הבא מראה איך אפליקציה יכולה לבצע פעולה כלשהי בכל פעם שהמניפסט נטען.
Kotlin
player.addListener( object : Player.Listener { override fun onTimelineChanged(timeline: Timeline, @TimelineChangeReason reason: Int) { val manifest = player.currentManifest if (manifest is HlsManifest) { // Do something with the manifest. } } } )
Java
player.addListener( new Player.Listener() { @Override public void onTimelineChanged( Timeline timeline, @Player.TimelineChangeReason int reason) { Object manifest = player.getCurrentManifest(); if (manifest != null) { HlsManifest hlsManifest = (HlsManifest) manifest; // Do something with the manifest. } } });
התאמה אישית של ההפעלה
ב-ExoPlayer יש כמה דרכים להתאים אישית את חוויית ההפעלה לצרכים של האפליקציה. דוגמאות מופיעות בדף ההתאמה האישית.
השבתת הכנה ללא קטעים
כברירת מחדל, ExoPlayer ישתמש בהכנה ללא קטעים. המשמעות היא ש-ExoPlayer ישתמש במידע שבפלייליסט עם הווריאציות השונות רק כדי להכין את הסטרימינג. הפעולה הזו תתבצע אם התגים #EXT-X-STREAM-INF
מכילים את המאפיין CODECS
.
יכול להיות שתצטרכו להשבית את התכונה הזו אם קטעי המדיה שלכם מכילים טראקים של כתוביות מעורבבות שלא הוגדרו בפלייליסט עם וריאנטים מרובים באמצעות תג #EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS
. אחרת, הטראקים של הכתוביות לא יזוהו ולא יופעלו. אפשר להשבית את ההכנה ללא קטעים ב-HlsMediaSource.Factory
, כפי שמתואר בקטע הקוד הבא. חשוב לזכור שהפעולה הזו תגדיל את זמן ההפעלה, כי המערכת של ExoPlayer צריכה להוריד קטע מדיה כדי לזהות את הטראקים הנוספים האלה. לכן, מומלץ להצהיר על הטראקים של הכתוביות בפלייליסט עם הווריאנטים השונים במקום זאת.
Kotlin
val hlsMediaSource = HlsMediaSource.Factory(dataSourceFactory) .setAllowChunklessPreparation(false) .createMediaSource(MediaItem.fromUri(hlsUri))
Java
HlsMediaSource hlsMediaSource = new HlsMediaSource.Factory(dataSourceFactory) .setAllowChunklessPreparation(false) .createMediaSource(MediaItem.fromUri(hlsUri));
יצירת תוכן HLS באיכות גבוהה
כדי להפיק את המקסימום מ-ExoPlayer, יש הנחיות מסוימות שאפשר לפעול לפיהן כדי לשפר את התוכן ב-HLS. בפוסט שלנו ב-Medium על הפעלת HLS ב-ExoPlayer מוסבר בהרחבה על הנושא. הנקודות העיקריות הן:
- להשתמש באורך מדויק של פלחים.
- שימוש בזרם מדיה רציף, הימנעות משינויים במבנה המדיה בין קטעים.
- משתמשים בתג
#EXT-X-INDEPENDENT-SEGMENTS
. - עדיף להשתמש בשידורים שהופרדו (demuxed) במקום בקבצים שכוללים גם וידאו וגם אודיו.
- מומלץ לכלול את כל המידע האפשרי בפלייליסט עם וריאציות מרובות.
ההנחיות הבאות רלוונטיות במיוחד לשידורים חיים:
- משתמשים בתג
#EXT-X-PROGRAM-DATE-TIME
. - משתמשים בתג
#EXT-X-DISCONTINUITY-SEQUENCE
. - לספק חלון זמן ארוך לשידור החי. דקה אחת או יותר הן מצוינות.