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  }