HLS

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 (קהילה) לא
נתוני לקוח מדיה נפוצים (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, צריך להפעיל Cast של האובייקט שהוחזר אל 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 באיכות גבוהה

כדי להפיק את המרב מ-ExpoPlayer, יש מספר הנחיות שניתן כדי לשפר את תוכן ה-HLS. הסבר מלא זמין בפוסט ב-Medium בנושא הפעלת HLS ב-ExoPlayer. הנקודות העיקריות הן:

  • משתמשים במשכי זמן מדויקים של מקטעים.
  • להשתמש בסטרימינג מדיה רציף. להימנע משינויים במבנה המדיה פלחים.
  • משתמשים בתג #EXT-X-INDEPENDENT-SEGMENTS.
  • עדיף להשתמש בשידורים שהופרדו (demuxed) במקום בקבצים שכוללים גם וידאו וגם אודיו.
  • כדאי לכלול את כל המידע האפשרי בפלייליסט עם וריאציות מרובות.

ההנחיות הבאות רלוונטיות במיוחד לשידורים חיים:

  • משתמשים בתג #EXT-X-PROGRAM-DATE-TIME.
  • משתמשים בתג #EXT-X-DISCONTINUITY-SEQUENCE.
  • לספק חלון זמן ארוך לשידור החי. דקה אחת או יותר הן מצוינות.