Search code examples
goamazon-s3http-live-streamingm3u8

Streaming HLS Video from S3 with Golang


I want to create video streaming server that serve HLS video (m3u8) that is stored in S3 using Go.

Here is my code:

e.GET("/video", func(c echo.Context) error {
    // download file m3u8
    buf := aws.NewWriteAtBuffer([]byte{})
    _, err := s3downloader.DownloadWithContext(ctx, buf, &s3.GetObjectInput{
        Bucket: aws.String(bucket),
        Key:    aws.String(objectKey), // hls/master.m3u8
    })

    return c.Stream(http.StatusOK, "application/x-mpegURL", bytes.NewReader(buf.Bytes()))
})

When I execute localhost:1234/video from Insomnia/postman, it correctly returns m3u8 file, which is the same as I execute S3 URL directly (https://xxx.s3.ap-southeast-1.amazonaws.com/xxx/hls/master.m3u8)

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-STREAM-INF:BANDWIDTH=800800,RESOLUTION=640x360,CODECS="avc1.4d401e,mp4a.40.2"
360pixel/list.m3u8

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-STREAM-INF:BANDWIDTH=965800,RESOLUTION=854x480,CODECS="avc1.4d401f,mp4a.40.2"
480pixel/list.m3u8

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-STREAM-INF:BANDWIDTH=1267200,RESOLUTION=1280x720,CODECS="avc1.4d401f,mp4a.40.2"
720pixel/list.m3u8

But, when I execute from browser, the video that served by my golang server can't be played as the s3 server does.

How to solve this problem?


Solution

  • the video that served by my golang server can't be played as the s3 server does.

    There could be two issues in your code:

    1. The Access-Control-Allow-Origin header is not set to *.

      e.GET("/video", func(c echo.Context) error {
          // download file m3u8
          buf := aws.NewWriteAtBuffer([]byte{})
          _, err := s3downloader.DownloadWithContext(ctx, buf, &s3.GetObjectInput{
              Bucket: aws.String(bucket),
              Key:    aws.String(objectKey), // hls/master.m3u8
          })
      
          c.Response().Header().Set(echo.HeaderAccessControlAllowOrigin, "*")
          return c.Stream(http.StatusOK, "application/x-mpegURL", bytes.NewReader(buf.Bytes()))
      })
      
    2. The following paths are relative to the original request. If the master m3u8 file is served by your golang server, the request to the embedded m3u8 file goes to your golang server. So you should either change your golang server to serve the embedded m3u8 files or convert them to absolute URLs (that points to the object stored in S3).

      ...
      360pixel/list.m3u8
      ...
      480pixel/list.m3u8
      ...
      720pixel/list.m3u8