{"id":37586,"date":"2016-07-27T21:39:40","date_gmt":"2016-07-27T16:09:40","guid":{"rendered":"http:\/\/www.tothenew.com\/blog\/?p=37586"},"modified":"2024-01-02T17:46:20","modified_gmt":"2024-01-02T12:16:20","slug":"how-to-play-hls-live-stream-using-exoplayer","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/how-to-play-hls-live-stream-using-exoplayer\/","title":{"rendered":"How to Play HLS Live Stream using ExoPlayer"},"content":{"rendered":"<p>In the previous blog, we have discussed the basics of Android ExoPlayer, advantages &amp; disadvantages. You can find its\u00a0link here <a title=\"Introduction to Android ExoPlayer\" href=\"http:\/\/www.tothenew.com\/blog\/introduction-to-android-exoplayer\/\" target=\"_blank\" rel=\"noopener\">Introduction to Android ExoPlayer<\/a>.<\/p>\n<p>In this blog, we are going to learn how to play live stream using ExoPlayer. We will be using HLS (HTTP Live Streaming) technology as communication protocol to serve the multimedia content. HLS is an adaptive streaming communications protocol. At first lets discuss adaptive streaming since it is used in HLS.<\/p>\n<p><strong>Adaptive Streaming:<br \/>\n<\/strong>Adaptive streaming provides the multiple bit-rate streams to end users. Best stream get played at user\u2019s end, which is decided by client player on the basis of some parameters like client computational capacity (CPU), internet bandwidth and memory utilization. Adaptive streaming provides the best user experience.<\/p>\n<p><img decoding=\"async\" src=\"\/blog\/wp-ttn-blog\/uploads\/2015\/08\/592x441xHLS_streaming.png.pagespeed.ic.2Gz9TzTmDI.png\" alt=\"HLS_streaming\" \/><\/p>\n<p>The Index File .m3u8 contains the index of all different version streams and manages the continuity and consistency of streams during playback. Hence for\u00a0adaptive streaming it choses the files from <strong>low, medium or high resolution w.r.t. internet connection<\/strong> and indexes of those files are provided by <strong>.m3u8 file<\/strong>. This is the brief introduction of HLS, now jump directly to the implementation of ExoPlayer.<\/p>\n<p><strong>Implementation:<br \/>\n<\/strong>ExoPlayer supports HLS adaptive playbacks through use of HlsSampleSource. ThisHlsSampleSource\u00a0loads chunks of media data and from that chunk of data individual samples are extracted.<\/p>\n<p><strong>HlsSampleSource<\/strong> is a SampleSource for HLS streams. This class contains various constructors &amp; methods which are very effective in media playback. Some of them are listed below-<\/p>\n<p align=\"left\"><strong>Methods:<\/strong><br \/>\n<strong><span style=\"color: #4c6b87;\"><span style=\"font-size: small;\"><b>continueBuffering<\/b><\/span><\/span><\/strong><code class=\"western\"><span style=\"color: #353833;\"><span style=\"font-size: small;\">(int\u00a0track, long\u00a0playbackPositionUs)<br \/>\n<\/span><\/span><\/code>Indicates to the source that it should still be buffering data for the specified track.<\/p>\n<p align=\"left\"><strong><span style=\"color: #4c6b87;\"><span style=\"font-size: small;\"><b>disable<\/b><\/span><\/span><\/strong><code class=\"western\"><span style=\"font-size: small;\">(int\u00a0track)<br \/>\n<\/span><\/code>Disable the specified track.<\/p>\n<p align=\"left\"><span style=\"color: #353833;\"><span style=\"font-family: Arial, Helvetica, sans-serif;\"><span style=\"font-size: small;\"><strong><span style=\"color: #4c6b87;\"><span style=\"font-size: small;\"><b>enable<\/b><\/span><\/span><\/strong><code class=\"western\"><span style=\"font-size: small;\">(int\u00a0track, long\u00a0positionUs)<br \/>\n<\/span><\/code><\/span><\/span><\/span>Enable the specified track.<\/p>\n<p align=\"left\"><span style=\"color: #353833;\"><span style=\"font-family: Arial, Helvetica, sans-serif;\"><span style=\"font-size: small;\"><strong><span style=\"color: #4c6b87;\"><span style=\"font-size: small;\"><b>getBufferedPositionUs<\/b><\/span><\/span><\/strong><code class=\"western\"><span style=\"font-size: small;\">()<br \/>\n<\/span><\/code><\/span><\/span><\/span>Returns an estimate of the position up to which data is buffered.<\/p>\n<p align=\"left\"><strong><span style=\"color: #4c6b87;\"><span style=\"font-size: small;\"><b>getFormat<\/b><\/span><\/span><\/strong><code class=\"western\"><span style=\"color: #353833;\"><span style=\"font-size: small;\">(int\u00a0track)<br \/>\n<\/span><\/span><\/code>Returns the format of the specified track.<\/p>\n<p align=\"left\"><strong><span style=\"color: #4c6b87;\"><span style=\"font-size: small;\"><b>getTrackCount<\/b><\/span><\/span><\/strong><code class=\"western\"><span style=\"color: #353833;\"><span style=\"font-size: small;\">()<br \/>\n<\/span><\/span><\/code>Returns the number of tracks exposed by the source.<\/p>\n<p align=\"left\"><span style=\"color: #353833;\"><span style=\"font-family: 'Liberation Serif', serif;\"><span style=\"font-size: medium;\"><strong>Constructors:<\/strong><br \/>\n<\/span><\/span><\/span>HlsSampleSource sampleSource = new HlsSampleSource(chunkSource, loadControl, MAIN_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE);<\/p>\n<p align=\"left\">Hence its clear from the constructor that <strong>HlsSampleSource<\/strong> needs <strong>HlsChunkSource<\/strong> and for <strong>HlsChunkSource<\/strong> we need <strong>DataSource<\/strong>. Refer to below figure:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/google.github.io\/ExoPlayer\/images\/hls-model.png\" alt=\"Object model for HLS playbacks using ExoPlayer\" \/><\/p>\n<p>HlsChunkSource is a temporary test source for HLS chunks. It contains chunks of video and audio before it is passed to HlsSampleSource.<\/p>\n<p>Now we will see the code based implementation-<\/p>\n<ol>\n<li><code class=\"language-java\"><span class=\"n\">LoadControl<\/span> <span class=\"n\">loadControl<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">DefaultLoadControl<\/span><span class=\"o\">(<\/span><span class=\"k\">new<\/span> <span class=\"n\">DefaultAllocator<\/span><span class=\"o\">(<\/span><span class=\"n\">BUFFER_SEGMENT_SIZE<\/span><span class=\"o\">));<\/span> <\/code><\/li>\n<li><code class=\"language-java\"><span class=\"n\">DefaultBandwidthMeter<\/span> <span class=\"n\">bandwidthMeter<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">DefaultBandwidthMeter<\/span><span class=\"o\">();<\/span> <\/code><\/li>\n<li><code class=\"language-java\"><span class=\"n\">PtsTimestampAdjusterProvider<\/span> <span class=\"n\">timestampAdjusterProvider<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">PtsTimestampAdjusterProvider<\/span><span class=\"o\">();<\/span> <\/code><\/li>\n<li><code class=\"language-java\"><span class=\"n\">DataSource<\/span> <span class=\"n\">dataSource<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">DefaultUriDataSource<\/span><span class=\"o\">(<\/span><span class=\"n\">context<\/span><span class=\"o\">,<\/span> <span class=\"n\">bandwidthMeter<\/span><span class=\"o\">,<\/span> <span class=\"n\">userAgent<\/span><span class=\"o\">);<\/span> <\/code><\/li>\n<li><code class=\"language-java\"><span class=\"n\">HlsChunkSource<\/span> <span class=\"n\">chunkSource<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">HlsChunkSource<\/span><span class=\"o\">(<\/span><span class=\"kc\">true<\/span> <span class=\"cm\">\/* isMaster *\/<\/span><span class=\"o\">,<\/span> <span class=\"n\">dataSource<\/span><span class=\"o\">,<\/span> <span class=\"n\">url<\/span><span class=\"o\">,<\/span> <span class=\"n\">manifest<\/span><span class=\"o\">,<\/span> <span class=\"n\">DefaultHlsTrackSelector<\/span><span class=\"o\">.<\/span><span class=\"na\">newDefaultInstance<\/span><span class=\"o\">(<\/span><span class=\"n\">context<\/span><span class=\"o\">),<\/span> <span class=\"n\">bandwidthMeter<\/span><span class=\"o\">,<\/span> <span class=\"n\">timestampAdjusterProvider<\/span><span class=\"o\">,<\/span> <span class=\"n\">HlsChunkSource<\/span><span class=\"o\">.<\/span><span class=\"na\">ADAPTIVE_MODE_SPLICE<\/span><span class=\"o\">);<\/span> <\/code><\/li>\n<li><code class=\"language-java\"><span class=\"n\">HlsSampleSource<\/span> <span class=\"n\">sampleSource<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">HlsSampleSource<\/span><span class=\"o\">(<\/span><span class=\"n\">chunkSource<\/span><span class=\"o\">,<\/span> <span class=\"n\">loadControl<\/span><span class=\"o\">,<\/span> <span class=\"n\">MAIN_BUFFER_SEGMENTS<\/span> <span class=\"o\">*<\/span> <span class=\"n\">BUFFER_SEGMENT_SIZE<\/span><span class=\"o\">);<\/span> <\/code><\/li>\n<li><code class=\"language-java\"><span class=\"n\">MediaCodecVideoTrackRenderer<\/span> <span class=\"n\">videoRenderer<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">MediaCodecVideoTrackRenderer<\/span><span class=\"o\">(<\/span><span class=\"n\">context<\/span><span class=\"o\">,<\/span> <span class=\"n\">sampleSource<\/span><span class=\"o\">,<\/span> <span class=\"n\">MediaCodecSelector<\/span><span class=\"o\">.<\/span><span class=\"na\">DEFAULT<\/span><span class=\"o\">,<\/span> <span class=\"n\">MediaCodec<\/span><span class=\"o\">.<\/span><span class=\"na\">VIDEO_SCALING_MODE_SCALE_TO_FIT<\/span><span class=\"o\">);<\/span> <\/code><\/li>\n<li><code class=\"language-java\"><span class=\"n\">MediaCodecAudioTrackRenderer<\/span> <span class=\"n\">audioRenderer<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">MediaCodecAudioTrackRenderer<\/span><span class=\"o\">(<\/span><span class=\"n\">sampleSource<\/span><span class=\"o\">,<\/span> <span class=\"n\">MediaCodecSelector<\/span><span class=\"o\">.<\/span><span class=\"na\">DEFAULT<\/span><span class=\"o\">);<\/span><\/code><\/li>\n<\/ol>\n<p><strong>Description:<br \/>\n<\/strong>In Line 1, LoadControl object is created and BUFFER_SEGMENT_SIZE is provided in the constructor. By default we keep this value as \u00a064*1024.<\/p>\n<p>In Line 2 &amp; 3,\u00a0DefaultBandwidthMeter &amp;\u00a0PtsTimestampAdjusterProvider objects are created which will be needed in the Renderer implementation.<\/p>\n<p>In Line 4,\u00a0DataSource object is created by passing context, bandwidthMeter object and userAgent. For obtaining userAgent we can use below code-<\/p>\n<pre>String userAgent = Util.getUserAgent(this, \"ExoPlayerDemo\");<\/pre>\n<p>In Line 5,\u00a0HlsChunkSource object is created via DataSource object and in Line 6,\u00a0HlsSampleSource object is created via\u00a0HlsChunkSource object.<\/p>\n<p>Now in Line 7 &amp; 8, we can get the objects of\u00a0MediaCodecVideoTrackRenderer &amp;\u00a0MediaCodecAudioTrackRenderer with the SampleSource object.<\/p>\n<p>For more understanding you can refer to the sample project, which is the modified version of standard google exoplayer project:<\/p>\n<p>https:\/\/github.com\/asifkhan11\/ExoPlayer-Demo<\/p>\n<p>In this sample you just need to enter the url which needs to be played and it starts playing\u00a0seamlessly.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the previous blog, we have discussed the basics of Android ExoPlayer, advantages &amp; disadvantages. You can find its\u00a0link here Introduction to Android ExoPlayer. In this blog, we are going to learn how to play live stream using ExoPlayer. We will be using HLS (HTTP Live Streaming) technology as communication protocol to serve the multimedia [&hellip;]<\/p>\n","protected":false},"author":334,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":22},"categories":[1],"tags":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/37586"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/334"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=37586"}],"version-history":[{"count":1,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/37586\/revisions"}],"predecessor-version":[{"id":59842,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/37586\/revisions\/59842"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=37586"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=37586"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=37586"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}