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  }