Support m3u playlists

See original GitHub issue

👋 hi, i have the following .m3u playlist file

#EXTM3U
#EXTINF:-1,livestream1
http://foo.com/live/1.ts

when i try to stream it with the following

Uri uri = Uri.parse("http://foo.com/playlist.m3u");
DefaultHttpDataSourceFactory httpDataSourceFactory = new DefaultHttpDataSourceFactory(Util.getUserAgent(this, "test"));
DefaultHlsDataSourceFactory hlsDataSourceFactory = new DefaultHlsDataSourceFactory(httpDataSourceFactory);
HlsMediaSource hlsMediaSource = new HlsMediaSource.Factory(hlsDataSourceFactory).createMediaSource(uri);
player.prepare(hlsMediaSource);

i get the following error which mean the failing happened on the streams with #EXTINF:-1 (aka. the live stream ones which don’t specify a duration time but -1 instead)

E/ExoPlayerImplInternal: Source error.
com.google.android.exoplayer2.ParserException: Couldn't match #EXTINF:([\d\.]+)\b in #EXTINF:-1,livestream1
    at com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser.parseStringAttr(HlsPlaylistParser.java:538)
    at com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser.parseDoubleAttr(HlsPlaylistParser.java:525)
    at com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser.parseMediaPlaylist(HlsPlaylistParser.java:407)
    at com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser.parse(HlsPlaylistParser.java:167)
    at com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser.parse(HlsPlaylistParser.java:48)
    at com.google.android.exoplayer2.upstream.ParsingLoadable.load(ParsingLoadable.java:130)
    at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:308)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
    at java.lang.Thread.run(Thread.java:818)

how can i support an m3u live streams list if HlsPlaylistParser dont allow -1 as duration then

am using version 2.7.2

PS : i replaced the uri’s in the example above but it’s the same.

thanx in advance ❤

Issue Analytics

  • State:open
  • Created 5 years ago
  • Comments:10 (3 by maintainers)

github_iconTop GitHub Comments

5reactions
ojw28commented, Apr 2, 2018

We do not support m3u playlists (which are not the same as m3u8 HLS playlists). Marking as an enhancement.

1reaction
ChenglongMacommented, Mar 9, 2021

The issue here is that the regex used in HlsPlaylistParser does not support #EXTINF:-1. So I copied the source code of HlsPlaylistParser and changed its regex pattern from :([\d\.]+)\b to :(-?[\d\.]+)\b (simply add -? after :(;

More trivially, my changelog:

Line [166] (may also [168]):

private static final Pattern REGEX_MEDIA_DURATION = Pattern.compile(TAG_MEDIA_DURATION
      + ":(-?[\\d\\.]+)\\b"); // prev version: :([\d\.]+)\b

Line [742]:

segmentDurationUs =
            (long) (parseDoubleAttr(line, REGEX_MEDIA_DURATION) * C.MICROS_PER_SECOND);

add a new line to make sure segmentDurationUs is greater than 0 (IMPORTANT!!):

segmentDurationUs = max(segmentDurationUs, 1)

How to use it:

Suppose your new variation of HlsPlaylistParser is called MyPlaylistParser; Implement a HlsPlaylistParserFactory based on the default class DefaultHlsPlaylistParserFactory, let’s call it MyPlaylistParserFactory;

(Mine is kotlin version):

class MyPlaylistParserFactory : HlsPlaylistParserFactory {
    override fun createPlaylistParser(): ParsingLoadable.Parser<HlsPlaylist> {
        return MyPlaylistParser()
    }

    override fun createPlaylistParser(
        masterPlaylist: HlsMasterPlaylist,
        previousMediaPlaylist: HlsMediaPlaylist?
    ): ParsingLoadable.Parser<HlsPlaylist> {
        return MyPlaylistParser(masterPlaylist, previousMediaPlaylist)
    }
}

Then create a HlsMediaSource like:

val item = MediaItem.Builder()
            .setMimeType(MimeTypes.APPLICATION_M3U8) // optional
            .setUri(uri)

val hlsMediaSource = HlsMediaSource.Factory(DefaultHttpDataSource.Factory())
            .setPlaylistParserFactory(MyPlaylistParserFactory()) // This is your implementation
            .createMediaSource(item.build())

exoPlayer.setMediaSource(hlsMediaSource)
exoPlayer.prepare()
exoPlayer.playWhenReady = true

Done. Hope this helps 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

Top 4 M3U Player to Play M3U Files for Free
MediaPlayerLite is the best free M3U player for Windows. Also, you are able to create MPL and M3U music playlists. It comes in...
Read more >
20 Best IPTV M3U Players to Stream IPTV contents
K-Multimedia player is an excellent media player that supports M3U and M3U8 playlists. Hence it takes up a place under the best IPTV...
Read more >
25 Best Free M3U Player Software For Windows
iTunes GOM Audio AIMP Audacious Windows Media Player ALSong jetAudio Winamp GreenForce-Player Clementine PotPlayer Jsound
Read more >
M3U File Extension - What is an .m3u file and how do I open it?
An M3U file is a media playlist that can be opened in various media players, including VideoLAN VLC media player, Nullsoft Winamp, ...
Read more >
Free M3U Playlists for Watching Live TV on Any Device (Dec ...
Using a free M3U playlist is a fabulous way to stream thousands of live channels from anywhere in the world. These work similar...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found