github.com/cnotch/ipchub@v1.1.0/service/flv/httpflv.go (about) 1 // Copyright calabashdad. https://github.com/calabashdad/seal.git 2 // 3 // Copyright (c) 2019,CAOHONGJU All rights reserved. 4 // Use of this source code is governed by a MIT-style 5 // license that can be found in the LICENSE file. 6 7 package flv 8 9 import ( 10 "net/http" 11 "runtime/debug" 12 13 "github.com/cnotch/ipchub/av/format/flv" 14 "github.com/cnotch/ipchub/media" 15 "github.com/cnotch/ipchub/stats" 16 "github.com/cnotch/xlog" 17 ) 18 19 type httpFlvConsumer struct { 20 logger *xlog.Logger 21 addr string 22 w *flv.Writer 23 closeCh chan bool 24 closed bool 25 } 26 27 func (c *httpFlvConsumer) Consume(pack Pack) { 28 if c.closed { 29 return 30 } 31 32 err := c.w.WriteFlvTag(pack.(*flv.Tag)) 33 34 if err != nil { 35 c.logger.Errorf("http-flv: send tag failed; %v", err) 36 c.Close() 37 return 38 } 39 } 40 41 func (c *httpFlvConsumer) Close() (err error) { 42 if c.closed { 43 return 44 } 45 46 c.closed = true 47 close(c.closeCh) 48 return nil 49 } 50 51 // ConsumeByHTTP 处理 http 方式访问流媒体 52 func ConsumeByHTTP(logger *xlog.Logger, path string, addr string, w http.ResponseWriter) { 53 logger = logger.With(xlog.Fields( 54 xlog.F("path", path),xlog.F("ext", "flv"), 55 xlog.F("addr", addr))) 56 57 stream := media.GetOrCreate(path) 58 if stream == nil { 59 http.Error(w, "404 page not found", http.StatusNotFound) 60 logger.Errorf("http-flv: no stream found") 61 return 62 } 63 64 typeFlags := stream.FlvTypeFlags() 65 if typeFlags == 0 { 66 http.Error(w, "404 page not found", http.StatusNotFound) 67 logger.Errorf("http-flv: stream not support flv") 68 return 69 } 70 71 var cid media.CID 72 defer func() { 73 if r := recover(); r != nil { 74 xlog.Errorf("http-flv: panic; %v \n %s", r, debug.Stack()) 75 } 76 stream.StopConsume(cid) 77 stats.FlvConns.Release() 78 logger.Info("http-flv: stop http-flv consume") 79 }() 80 81 logger.Info("http-flv: start http-flv consume") 82 stats.FlvConns.Add() 83 84 w.Header().Set("Access-Control-Allow-Origin", "*") 85 w.Header().Set("Content-Type", "video/x-flv") 86 87 // 启动 pack 消费,必须 StartConsume 前写入 Header 88 flvWriter, err := flv.NewWriter(w, typeFlags) 89 if err != nil { 90 http.Error(w, "send flv header failed", http.StatusInternalServerError) 91 logger.Error("http-flv: send flv header failed.") 92 return 93 } 94 95 c := &httpFlvConsumer{ 96 logger: logger, 97 w: flvWriter, 98 closeCh: make(chan bool), 99 } 100 101 cid = stream.StartConsume(c, media.FLVPacket, "net=http-flv,"+addr) 102 103 // 等待关闭 104 select { 105 case <-c.closeCh: 106 } 107 }