func AddSegmentToSchedule(s *datastore.Schedule, bs BroadcastSegment) error { playlistBlob := datastore.Blob{s.CacheKey()} if s.MediaPlaylist == nil { // If no playlist exists s.MediaPlaylist, _ = m3u8.NewMediaPlaylist(100, 100) // alloc a new one if plistData, err := playlistBlob.GetBuffer(); err == nil { s.MediaPlaylist.Decode(*plistData, false) } } err := s.MediaPlaylist.Append(bs.MediaURL, bs.TargetDuration, bs.Title) // append the item if err != nil { s.MediaPlaylist.Slide(bs.MediaURL, bs.TargetDuration, bs.Title) // or slide if playlist full } s.MediaPlaylist.SetProgramDateTime(time.Now()) if bs.Discontinuity { // If the video format is different than the last segment if err := s.MediaPlaylist.SetDiscontinuity(); err != nil { // let the player know return err } } if err := playlistBlob.Set(s.PlaylistData()); err != nil { return err } return nil }
func (s *Stream) ResetPlaylist(vodPlaylist bool) { s.Playlist, _ = m3u8.NewMediaPlaylist(10000, 10000) // alloc a new Playlist if vodPlaylist { s.Playlist.MediaType = m3u8.VOD s.Playlist.Closed = true } }
func NewStream(idx string, instruction StreamInstruction) (stream Stream) { stream.Identifier = idx stream.UUID = uuid.NewRandom().String() stream.Instruction = instruction stream.Playlist, _ = m3u8.NewMediaPlaylist(10000, 10000) // alloc a new one return }
func RunPlaylist(in generator.StreamInstruction, out chan generator.BroadcastCommand) error { params := in.Args playlistUrl := params["playlist_url"] startString := params["start_at"] endString := params["end_at"] startAt, _ := strconv.Atoi(startString) // error will default to 0 endAt, conversionErr := strconv.Atoi(endString) if conversionErr != nil { endAt = 200000 } resp, err := http.Get(playlistUrl) if err != nil { return err } defer resp.Body.Close() mp, _ := m3u8.NewMediaPlaylist(100000, 100000) if err := mp.DecodeFrom(resp.Body, false); err != nil { return err } playlistHasMoreItems := func(z int) bool { return (mp.Segments[z] != nil && (z < endAt)) } for i := startAt; playlistHasMoreItems(i); i++ { segmentUrl := "" relativePath := mp.Segments[i].URI if comps := strings.Split(playlistUrl, "/"); len(comps) > 0 { suffix := comps[len(comps)-1] baseUrl := strings.TrimSuffix(playlistUrl, suffix) segmentUrl = baseUrl + relativePath } else { segmentUrl = relativePath } relativeUrls, ok := params["relative_urls"] if ok && relativeUrls == "true" { segmentUrl = strings.TrimPrefix(segmentUrl, "http://www.smick.tv") } bs := generator.BroadcastSegment{ MediaURL: segmentUrl, TargetDuration: mp.Segments[i].Duration, Discontinuity: (i == startAt || mp.Segments[i].Discontinuity), } command := generator.BroadcastCommand{ Type: "broadcast-segment", Segment: bs, } out <- command } return nil }
func Preview(p datastore.Program) (mediaPlaylist *m3u8.MediaPlaylist, err error) { pipeline := RunProgram(p) // Run the program pipeline.Close() // And close it out when we're done segments := make([]BroadcastSegment, 0) for vd := range pipeline.MediaChannel() { segments = append(segments, vd.Segment) } seglen := uint(len(segments)) mediaPlaylist, _ = m3u8.NewMediaPlaylist(seglen, seglen) mediaPlaylist.MediaType = m3u8.VOD mediaPlaylist.Closed = true for _, s := range segments { if err = s.AddTo(mediaPlaylist); err != nil { return } } return }
func trimM3u8(c web.C, w http.ResponseWriter, r *http.Request) { q := r.URL.Query().Get("sec") sec, err := strconv.Atoi(q) if err != nil { sec = 0 } resp, err := http.Get(m3u8URL) if err != nil { w.WriteHeader(500) w.Write([]byte("faild to get m3u8 file")) return } defer resp.Body.Close() p, err := m3u8.NewMediaPlaylist(1024, 1024) if err != nil { w.WriteHeader(500) w.Write([]byte("faild to NewMediaPlaylist")) return } defer p.Close() err = p.DecodeFrom(resp.Body, true) if err != nil { w.WriteHeader(500) w.Write([]byte("faild to decode m3u8 file")) return } if sec != 0 { p.Segments = append(p.Segments[(sec / int(p.TargetDuration)):]) } w.Write(p.Encode().Bytes()) }
func (p *Playlist) PlayDescriptor(vd generator.VideoDescriptor) error { params := vd.Params playlistUrl := params["playlist_url"] startString := params["start_at"] endString, _ := params["end_at"] startAt, _ := strconv.Atoi(startString) endAt, conversionErr := strconv.Atoi(endString) if conversionErr != nil { endAt = 200000 } resp, err := http.Get(playlistUrl) if err != nil { return err } defer resp.Body.Close() mp, _ := m3u8.NewMediaPlaylist(100000, 100000) if err := mp.DecodeFrom(resp.Body, false); err != nil { return err } playlistHasMoreItems := func(z int) bool { return (mp.Segments[z] != nil && (z < endAt)) } for i := startAt; playlistHasMoreItems(i); i++ { select { case <-p.CancelChan: return errors.New("canceled") default: segmentUrl := "" relativePath := mp.Segments[i].URI if comps := strings.Split(playlistUrl, "/"); len(comps) > 0 { suffix := comps[len(comps)-1] baseUrl := strings.TrimSuffix(playlistUrl, suffix) segmentUrl = baseUrl + relativePath } else { segmentUrl = relativePath } relativeUrls, ok := params["relative_urls"] if ok && relativeUrls == "true" { segmentUrl = strings.TrimPrefix(segmentUrl, "http://www.smick.tv") } bs := generator.BroadcastSegment{ MediaURL: segmentUrl, TargetDuration: mp.Segments[i].Duration, Discontinuity: (i == startAt), } vd := generator.VideoDescriptor{ SegmentReady: true, Segment: bs, Params: map[string]string{}, } p.Output <- vd } } return nil }
func (s *Stream) ResizePlaylist(size uint) { s.Playlist, _ = m3u8.NewMediaPlaylist(size, size) // alloc a new Playlist }