grafov / m3u8

Parser and generator of M3U8-playlists for Apple HLS. Library for Go language. :cinema:
http://tools.ietf.org/html/draft-pantos-http-live-streaming
BSD 3-Clause "New" or "Revised" License
1.22k stars 312 forks source link

program panic when i get the url of media segments #187

Closed misssonder closed 1 year ago

misssonder commented 2 years ago

retry this


import (
    "bytes"
    "fmt"

    "github.com/grafov/m3u8"
)

func main() {
    body := `#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PROGRAM-DATE-TIME:2022-03-01T20:15:19.786+08:00
#EXT-X-TARGETDURATION:4
#EXTINF:4.000,
test
#EXTINF:4.000,
test
#EXTINF:4.000,
test
#EXTINF:4.000,
test
#EXTINF:4.000,
test
#EXTINF:4.000,
test
#EXT-X-ENDLIST
`
    p, listType, err := m3u8.DecodeFrom(bytes.NewReader([]byte(body)), true)
    if err != nil {
        panic(err)
    }
    switch listType {
    case m3u8.MEDIA:
        mediapl := p.(*m3u8.MediaPlaylist)
        for _, segment := range mediapl.Segments {
            println(segment.URI)
        }
    case m3u8.MASTER:
        masterpl := p.(*m3u8.MasterPlaylist)
        fmt.Printf("%+v\n", masterpl)
    }
}

Expected Behavior

print the url of segments

Actual Behavior

program panic

Solve

https://github.com/grafov/m3u8/pull/186

grafov commented 1 year ago

Confirmed. Thank you! I'll apply your patch to the next release.

grafov commented 1 year ago

We have another problem after the patch: https://github.com/grafov/m3u8/pull/186#issuecomment-1441871073 Need more investigation.

grafov commented 1 year ago

Well, the ring buffer used inside a list of mediasegments. It was design decision made years ago :| If I were writing this today, I wouldn't repeat this decision. Hence by design the range loop over Segments could not possible. Maybe add a new method like GetAllSegments() could be useful for the current implementation.

grafov commented 1 year ago

The method like:

func (p *MediaPlaylist) GetAllSegments() []*MediaSegment {
    if p.count == 0 {
        return nil
    }
    buf := make([]*MediaSegment, 0, p.count)
    if p.head < p.tail {
        for i := p.head; i < p.tail; i++ {
            buf = append(buf, p.Segments[i])
        }
        return buf
    }
    for i := uint(0); i < p.tail; i++ {
        buf = append(buf, p.Segments[i])
    }
    for i := p.head; i < p.capacity; i++ {
        buf = append(buf, p.Segments[i])
    }
    return buf
}

Then it could be possible iterate:

    for _, v := range m.GetAllSegments() {
        print(v.URI)
    }
misssonder commented 1 year ago

The method like:

func (p *MediaPlaylist) GetAllSegments() []*MediaSegment {
  if p.count == 0 {
      return nil
  }
  buf := make([]*MediaSegment, 0, p.count)
  if p.head < p.tail {
      for i := p.head; i < p.tail; i++ {
          buf = append(buf, p.Segments[i])
      }
      return buf
  }
  for i := uint(0); i < p.tail; i++ {
      buf = append(buf, p.Segments[i])
  }
  for i := p.head; i < p.capacity; i++ {
      buf = append(buf, p.Segments[i])
  }
  return buf
}

Then it could be possible iterate:

  for _, v := range m.GetAllSegments() {
      print(v.URI)
  }

OK, it also looks good.

grafov commented 1 year ago

Released in https://github.com/grafov/m3u8/releases/tag/v0.12.0