github.com/0chain/gosdk@v1.17.11/zboxcore/sdk/live_upload_reader.go (about) 1 package sdk 2 3 import ( 4 "errors" 5 "io" 6 "os" 7 "os/exec" 8 "os/signal" 9 "syscall" 10 "time" 11 12 "github.com/0chain/gosdk/core/sys" 13 "github.com/h2non/filetype" 14 ) 15 16 var ( 17 // ErrClispIsNotReady clips file is not ready 18 ErrClispIsNotReady = errors.New("live: clips is not ready") 19 ) 20 21 // LiveUploadReader implements io.Reader and Size for live stream upload 22 type LiveUploadReader interface { 23 io.Reader 24 Size() int64 25 GetClipsFile(clipsIndex int) string 26 GetClipsFileName(cliipsIndex int) string 27 } 28 29 type liveUploadReaderBase struct { 30 builder FileNameBuilder 31 32 // delay segment time of output 33 delay int 34 35 // cmd ffmpeg command 36 cmd *exec.Cmd 37 // err last err 38 err error 39 40 // clipsIndex current clips index 41 clipsIndex int 42 // clipsReader file reader of current clips 43 clipsReader sys.File 44 // clipsOffset how much bytes is read 45 clipsOffset int64 46 } 47 48 func (r *liveUploadReaderBase) wait() { 49 sigs := make(chan os.Signal, 1) 50 signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) 51 52 go func() { 53 <-sigs 54 r.Close() 55 }() 56 57 r.err = r.cmd.Wait() 58 } 59 60 // GetClipsFile get clips file 61 func (r *liveUploadReaderBase) GetClipsFile(clipsIndex int) string { 62 return r.builder.ClipsFile(clipsIndex) 63 } 64 65 // GetClipsFileName get clips file name 66 func (r *liveUploadReaderBase) GetClipsFileName(clipsIndex int) string { 67 return r.builder.ClipsFileName(clipsIndex) 68 } 69 70 // Read implements io.Raader 71 func (r *liveUploadReaderBase) Read(p []byte) (int, error) { 72 73 err := r.initClipsReader() 74 75 if err != nil { 76 return 0, err 77 } 78 79 for { 80 81 if r.err != nil { 82 return 0, r.err 83 } 84 85 fi, _ := r.clipsReader.Stat() 86 87 if fi != nil { 88 89 size := fi.Size() 90 91 wantRead := int64(len(p)) 92 93 if r.clipsOffset+wantRead < size { 94 readLen, err := r.clipsReader.Read(p) 95 96 r.clipsOffset += int64(readLen) 97 98 return readLen, err 99 } 100 101 readLen, err := r.clipsReader.Read(p) 102 103 r.clipsReader.Close() 104 r.clipsReader = nil 105 r.clipsOffset = 0 106 r.clipsIndex++ 107 108 return readLen, err 109 } 110 111 sys.Sleep(1 * time.Second) 112 113 } 114 } 115 116 // Close implements io.Closer 117 func (r *liveUploadReaderBase) Close() (err error) { 118 if r != nil { 119 if r.cmd != nil { 120 err = r.cmd.Process.Kill() 121 if err != nil { 122 return 123 } 124 } 125 126 if r.clipsReader != nil { 127 err = r.clipsReader.Close() 128 if err != nil { 129 return 130 } 131 } 132 } 133 134 return nil 135 } 136 137 // GetFileContentType get MIME type 138 func (r *liveUploadReaderBase) GetFileContentType() (string, error) { 139 for { 140 141 if r.err != nil { 142 return "", r.err 143 } 144 145 currentClips := r.GetClipsFile(r.clipsIndex) 146 reader, err := os.Open(currentClips) 147 148 if err == nil { 149 defer reader.Close() 150 151 for { 152 fi, _ := reader.Stat() 153 154 if fi.Size() > 261 { 155 buffer := make([]byte, 261) 156 _, err := reader.Read(buffer) 157 158 if err != nil { 159 return "", err 160 } 161 162 kind, _ := filetype.Match(buffer) 163 if kind == filetype.Unknown { 164 return "application/octet-stream", nil 165 } 166 167 return kind.MIME.Value, nil 168 } 169 170 sys.Sleep(1 * time.Second) 171 } 172 173 } 174 175 } 176 177 } 178 179 // Size get current clips size 180 func (r *liveUploadReaderBase) Size() int64 { 181 err := r.initClipsReader() 182 183 if err != nil { 184 return 0 185 } 186 187 for { 188 189 fi, _ := r.clipsReader.Stat() 190 191 if fi != nil { 192 return fi.Size() 193 } 194 195 sys.Sleep(1 * time.Second) 196 } 197 198 } 199 200 func (r *liveUploadReaderBase) initClipsReader() error { 201 202 if r.clipsReader == nil { 203 204 nextClips := r.GetClipsFile(r.clipsIndex + 1) 205 206 for { 207 208 if r.err != nil { 209 return r.err 210 } 211 212 // file content is less than bytes want to read, check whether current clips file is ended 213 _, err := sys.Files.Stat(nextClips) 214 215 if err == nil { 216 if r.clipsReader == nil { 217 r.clipsReader, err = sys.Files.Open(r.GetClipsFile(r.clipsIndex)) 218 219 if err != nil { 220 return err 221 } 222 223 return nil 224 } 225 } 226 227 sys.Sleep(1 * time.Second) 228 } 229 } 230 231 return nil 232 }