github.com/cnotch/ipchub@v1.1.0/media/cache/flvcache.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 cache
     6  
     7  import (
     8  	"sync"
     9  
    10  	"github.com/cnotch/ipchub/av/format/flv"
    11  	"github.com/cnotch/queue"
    12  )
    13  
    14  // FlvCache Flv包缓存.
    15  type FlvCache struct {
    16  	cacheGop bool
    17  	l        sync.RWMutex
    18  	gop      queue.Queue
    19  	// cached meta data
    20  	metaData *flv.Tag
    21  	// cached video sequence header
    22  	videoSequenceHeader *flv.Tag
    23  	// cached aideo sequence header
    24  	audioSequenceHeader *flv.Tag
    25  }
    26  
    27  // NewFlvCache 创建FlvCache实例
    28  func NewFlvCache(cacheGop bool) *FlvCache {
    29  	return &FlvCache{
    30  		cacheGop: cacheGop,
    31  	}
    32  }
    33  
    34  // CachePack 向FlvCache中缓存包
    35  func (cache *FlvCache) CachePack(pack Pack) bool {
    36  	tag := pack.(*flv.Tag)
    37  
    38  	cache.l.Lock()
    39  	defer cache.l.Unlock()
    40  
    41  	if tag.IsMetadata() {
    42  		cache.metaData = tag
    43  		return false
    44  	}
    45  	if tag.IsH2645SequenceHeader() {
    46  		cache.videoSequenceHeader = tag
    47  		return false
    48  	}
    49  	if tag.IsAACSequenceHeader() {
    50  		cache.audioSequenceHeader = tag
    51  		return false
    52  	}
    53  
    54  	keyframe := tag.IsH2645KeyFrame()
    55  	if cache.cacheGop { // 如果启用 FlvCache
    56  		if keyframe { // 关键帧,重置GOP
    57  			cache.gop.Reset()
    58  			cache.gop.Push(pack)
    59  		} else if cache.gop.Len() > 0 { // 必须关键帧作为cache的第一个包
    60  			cache.gop.Push(pack)
    61  		}
    62  	}
    63  	return keyframe
    64  }
    65  
    66  // Reset 重置FlvCache缓存
    67  func (cache *FlvCache) Reset() {
    68  	cache.l.Lock()
    69  	defer cache.l.Unlock()
    70  	cache.gop.Reset()
    71  	cache.metaData = nil
    72  	cache.videoSequenceHeader = nil
    73  	cache.audioSequenceHeader = nil
    74  }
    75  
    76  // PushTo 入列到指定的队列
    77  func (cache *FlvCache) PushTo(q *queue.SyncQueue) int {
    78  	cache.l.RLock()
    79  	defer cache.l.RUnlock()
    80  
    81  	bytes := 0
    82  
    83  	gop := cache.gop.Elems()
    84  	initTimestamp := uint32(0)
    85  	if len(gop) > 0 {
    86  		tag := gop[0].(*flv.Tag)
    87  		initTimestamp = tag.Timestamp
    88  	}
    89  
    90  	//write meta data
    91  	if nil != cache.metaData {
    92  		metaData := *cache.metaData
    93  		metaData.Timestamp = initTimestamp
    94  		q.Queue().Push(&metaData)
    95  		bytes += metaData.Size()
    96  	}
    97  
    98  	//write video data
    99  	if nil != cache.videoSequenceHeader {
   100  		videoSequenceHeader := *cache.videoSequenceHeader
   101  		videoSequenceHeader.Timestamp = initTimestamp
   102  		q.Queue().Push(&videoSequenceHeader)
   103  		bytes += videoSequenceHeader.Size()
   104  	}
   105  
   106  	//write audio data
   107  	if nil != cache.audioSequenceHeader {
   108  		audioSequenceHeader := *cache.audioSequenceHeader
   109  		audioSequenceHeader.Timestamp = initTimestamp
   110  		q.Queue().Push(&audioSequenceHeader)
   111  		bytes += audioSequenceHeader.Size()
   112  	}
   113  
   114  	// write gop
   115  	q.Queue().PushN(gop) // 启动阶段调用,无需加锁
   116  	for _, p := range gop {
   117  		bytes += p.(Pack).Size()
   118  	}
   119  
   120  	return bytes
   121  }