github.com/0chain/gosdk@v1.17.11/zboxcore/sdk/m3u8.go (about)

     1  package sdk
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"os"
     7  	"path/filepath"
     8  	"strconv"
     9  	"time"
    10  
    11  	"github.com/0chain/gosdk/core/sys"
    12  )
    13  
    14  // #EXTM3U
    15  // #EXT-X-VERSION:3
    16  // #EXT-X-TARGETDURATION:5
    17  // #EXT-X-MEDIA-SEQUENCE:17
    18  // #EXTINF:5.000000,
    19  // tv17.ts
    20  // #EXTINF:5.000000,
    21  // tv18.ts
    22  // #EXTINF:5.000000,
    23  // tv19.ts
    24  // #EXTINF:5.000000,
    25  // tv20.ts
    26  // #EXTINF:5.000000,
    27  // tv21.ts
    28  
    29  // MediaPlaylist queue-based m3u8 playlist
    30  type MediaPlaylist struct {
    31  	dir   string
    32  	delay int
    33  
    34  	writer M3u8Writer
    35  
    36  	// wait wait to play
    37  	wait []string
    38  
    39  	next chan string
    40  	seq  int
    41  }
    42  
    43  // NewMediaPlaylist create media playlist(.m3u8)
    44  func NewMediaPlaylist(delay int, dir string, writer M3u8Writer) *MediaPlaylist {
    45  	m3u8 := &MediaPlaylist{
    46  		dir:    dir,
    47  		delay:  delay,
    48  		wait:   make([]string, 0, 5),
    49  		next:   make(chan string, 100),
    50  		seq:    0,
    51  		writer: writer,
    52  	}
    53  
    54  	m3u8.writer.Write([]byte("#EXTM3U\n"))                                           //nolint
    55  	m3u8.writer.Write([]byte("#EXT-X-VERSION:3\n"))                                  //nolint
    56  	m3u8.writer.Write([]byte("#EXT-X-TARGETDURATION:" + strconv.Itoa(delay) + "\n")) //nolint
    57  	m3u8.writer.Sync()                                                               //nolint
    58  	go m3u8.Play()
    59  
    60  	return m3u8
    61  }
    62  
    63  // Append append new item into playlist
    64  func (m *MediaPlaylist) Append(item string) {
    65  	m.next <- item
    66  }
    67  
    68  // Play start to play the contents of the playlist with 1 second buffer between each item
    69  func (m *MediaPlaylist) Play() {
    70  
    71  	for {
    72  
    73  		item := <-m.next
    74  
    75  		_, err := sys.Files.Stat(filepath.Join(m.dir, item))
    76  
    77  		if err == nil {
    78  			if len(m.wait) < 5 {
    79  				m.seq = 1
    80  				m.wait = append(m.wait, "."+string(os.PathSeparator)+item)
    81  			} else {
    82  				m.seq++
    83  				m.wait = append(m.wait[1:], "."+string(os.PathSeparator)+item)
    84  			}
    85  
    86  			m.flush()
    87  		}
    88  
    89  		sys.Sleep(1 * time.Second)
    90  
    91  	}
    92  
    93  }
    94  
    95  // flush try flush new ts file into playlist. return true if list is full
    96  func (m *MediaPlaylist) flush() {
    97  
    98  	m.writer.Truncate(0)       //nolint
    99  	m.writer.Seek(0, 0)        //nolint
   100  	m.writer.Write(m.Encode()) //nolint
   101  	m.writer.Sync()            //nolint
   102  
   103  }
   104  
   105  // Encode encode m3u8
   106  func (m *MediaPlaylist) Encode() []byte {
   107  	var buf bytes.Buffer
   108  
   109  	duration := strconv.Itoa(m.delay)
   110  
   111  	buf.WriteString("#EXTM3U\n")
   112  	buf.WriteString("#EXT-X-VERSION:3\n")
   113  	buf.WriteString("#EXT-X-TARGETDURATION:" + duration + "\n")
   114  	buf.WriteString("#EXT-X-MEDIA-SEQUENCE:" + strconv.Itoa(m.seq) + "\n")
   115  
   116  	for _, it := range m.wait {
   117  		buf.WriteString("#EXTINF:" + duration + ",\n")
   118  		buf.WriteString(it + "\n")
   119  	}
   120  
   121  	return buf.Bytes()
   122  }
   123  
   124  // String implement Stringer
   125  func (m *MediaPlaylist) String() string {
   126  	return string(m.Encode())
   127  }
   128  
   129  // M3u8Writer m3u8 writer
   130  type M3u8Writer interface {
   131  	io.WriteSeeker
   132  	Truncate(size int64) error
   133  	Sync() error
   134  }