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 }