github.com/cnotch/ipchub@v1.1.0/service/hls/hls.go (about) 1 // Copyright (c) 2019,CAOHONGJU All rights reserved. 2 // Use of this source code is governed by a MIT-style 3 // license that can be found in the LICENSE file. 4 5 package hls 6 7 import ( 8 "io" 9 "net/http" 10 "strconv" 11 "strings" 12 "time" 13 14 "github.com/cnotch/ipchub/config" 15 "github.com/cnotch/ipchub/media" 16 "github.com/cnotch/xlog" 17 ) 18 19 // GetM3u8 . 20 func GetM3u8(logger *xlog.Logger, path string, token string, addr string, w http.ResponseWriter) { 21 logger = logger.With(xlog.Fields( 22 xlog.F("path", path), xlog.F("ext", "m3u8"), 23 xlog.F("addr", addr))) 24 25 logger.Info("http-hls: access playlist") 26 27 // 需要手动启动,如果需要转换或拉流,很耗时 28 var c media.Hlsable 29 s := media.GetOrCreate(path) 30 if s != nil { 31 c = s.Hlsable() 32 } 33 34 if c == nil { 35 logger.Errorf("http-hls: not found stream '%s'", path) 36 http.Error(w, "404 page not found", http.StatusNotFound) 37 return 38 } 39 40 var err error 41 var cont []byte 42 43 // 最多等待完成 30 秒 44 waitSeconds := int(1.5 * float64(3*config.HlsFragment())) 45 for i := 0; i < waitSeconds; i++ { 46 cont, err = c.M3u8(token) 47 if err == nil { 48 break 49 } 50 51 <-time.After(time.Second) 52 } 53 54 if err != nil { 55 logger.Errorf("http-hls: request playlist error, %v.", err) 56 http.Error(w, err.Error(), http.StatusBadRequest) 57 return 58 } 59 60 w.Header().Set("Access-Control-Allow-Origin", "*") 61 w.Header().Set("Cache-Control", "no-cache") 62 w.Header().Set("Content-Type", "application/x-mpegURL") 63 w.Header().Set("Content-Length", strconv.Itoa(len(cont))) 64 w.Write(cont) 65 66 if logger.LevelEnabled(xlog.DebugLevel) { 67 logger.Debugf("m3u8 ===>>>\r\n%s", string(cont)) 68 } 69 } 70 71 // GetTS . 72 func GetTS(logger *xlog.Logger, path string, addr string, w http.ResponseWriter) { 73 logger = logger.With(xlog.Fields( 74 xlog.F("path", path), xlog.F("ext", "ts"), 75 xlog.F("addr", addr))) 76 77 logger.Info("http-hls: access segment file") 78 79 i := strings.LastIndex(path, "/") 80 if i < 0 { 81 logger.Errorf("http-hls: path illegal `%s`", path) 82 http.Error(w, "Path illegal", http.StatusBadRequest) 83 return 84 } 85 86 streamPath := path[:i] 87 seqStr := path[i+1:] 88 seq, err := strconv.Atoi(seqStr) 89 if err != nil { 90 logger.Errorf("http-hls: path illegal `%s`", path) 91 http.Error(w, "Path illegal", http.StatusBadRequest) 92 return 93 } 94 95 // 查找的消费者但不创建 96 var c media.Hlsable 97 s := media.GetOrCreate(streamPath) 98 if s != nil { 99 c = s.Hlsable() 100 } 101 102 if c == nil { 103 logger.Errorf("http-hls: not found `%s`", path) 104 http.Error(w, "404 page not found", http.StatusNotFound) 105 return 106 } 107 108 reader, size, err := c.Segment(seq) 109 if err != nil { 110 logger.Errorf("http-hls: not found `%s`", path) 111 http.Error(w, "404 page not found", http.StatusNotFound) 112 return 113 } 114 defer func() { 115 if closer, ok := reader.(io.Closer); ok { 116 closer.Close() 117 } 118 }() 119 120 w.Header().Set("Access-Control-Allow-Origin", "*") 121 w.Header().Set("Content-Type", "video/mp2ts") 122 w.Header().Set("Content-Length", strconv.Itoa(size)) 123 io.Copy(w, reader) 124 }