Search code examples
http-live-streaming

Smooth video playback with HTTP Live Stream


I'm trying to save to a file an HTTP live video stream. I know that for this purpose, I will need to request periodically the M3U8 file, parse it to extract the URL of the media segments, download the segments and reassemble them. The problem I'm having is finding the right strategy to achieve smooth playback. The reassembled video is always choppy, the audio skips etc...only the first few seconds are okay.

My M3U8 file looks something like this:

#EXTM3U
#EXT-X-TARGETDURATION:2
#EXT-X-VERSION:3
#EXT-X-ALLOW-CACHE:NO
#EXT-X-MEDIA-SEQUENCE:1105
#EXTINF:1.00000,
tmp/video1.ts
#EXTINF:1.00000,
tmp/video2.ts
#EXTINF:1.00000,
tmp/video2.ts
#EXTINF:1.00000,
tmp/video3.ts
#EXTINF:1.00000,
tmp/video4.ts
#EXTINF:1.00000,
tmp/video5.ts

After I parse the file, I start downloading all TS files (one at the time) and when I'm about to download the second from the last, I request a new M3U8 file. Is this wrong? maybe the server has not yet updated the segments? Therefore, I'm re-downloading the same ones? I tried to wait for 5 seconds (number_of_videos * duration) before requesting a new playlist but I still experience the playback issues mentioned.

Any idea/strategy on how I can achieve smooth playback?


Solution

  • The basic strategy is more or less as follows.

    You start by processing the manifest file and downloading the first few segments to fill your buffer. You begin playback once you are happy you have enough data in the buffer, while continuing to download additional segments sequentially until the end of the manifest, at which point you request it again. If you find new segments in the refreshed manifest, you add these URLs to your download queue. If you do not, you wait for a predetermined period of time and refresh the manifest again. For example, your client could poll the M3U8 manifest depending on the (total duration of the segments * number of segments / 2).

    I know some commercial players enter a paranoid mode when the playback buffer is getting low and the refreshed manifest does not contain any new segments to download. In this case, they begin requesting for the updated manifest much more frequently.

    You also need to pay attention to caching between your client and the HTTP server with the content. For example, some CDNs will cache the manifest file for a minimum mandatory period of time, so if you try to request it within this period, you may get a stale manifest file served back to you.

    From your example above (and I hope it is just in your hand-crafted example), the duration for each segment appears to be 1 second, which is quite low. If this is really the case, you would want to adjust your initial buffer accordingly.

    And lastly, I presume you've verified the source stream with a stable player, to make sure the problem is not on the other end?

    -- ab1