github.com/cnotch/ipchub@v1.1.0/av/format/rtp/demuxer.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 rtp
     6  
     7  import (
     8  	"fmt"
     9  	"runtime/debug"
    10  	"time"
    11  
    12  	"github.com/cnotch/ipchub/av/codec"
    13  	"github.com/cnotch/queue"
    14  	"github.com/cnotch/xlog"
    15  )
    16  
    17  // 网络播放时 PTS(Presentation Time Stamp)的延时
    18  const (
    19  	ptsDelay = int64(time.Second)
    20  )
    21  
    22  // Depacketizer 解包器
    23  type Depacketizer interface {
    24  	Control(basePts *int64, p *Packet) error
    25  	Depacketize(basePts int64, p *Packet) error
    26  }
    27  
    28  type emptyDepacketizer struct{}
    29  
    30  func (emptyDepacketizer) Control(basePts *int64, p *Packet) error    { return nil }
    31  func (emptyDepacketizer) Depacketize(basePts int64, p *Packet) error { return nil }
    32  
    33  // Demuxer 帧转换器
    34  type Demuxer struct {
    35  	closed    bool
    36  	recvQueue *queue.SyncQueue
    37  	vdp       Depacketizer
    38  	adp       Depacketizer
    39  	logger    *xlog.Logger
    40  }
    41  
    42  func emptyDepacketize(*int64, *Packet) error { return nil }
    43  
    44  // NewDemuxer 创建 rtp.Packet 解封装处理器。
    45  func NewDemuxer(video *codec.VideoMeta, audio *codec.AudioMeta, fw codec.FrameWriter, logger *xlog.Logger) (*Demuxer, error) {
    46  	demuxer := &Demuxer{
    47  		recvQueue: queue.NewSyncQueue(),
    48  		closed:    false,
    49  		logger:    logger,
    50  	}
    51  
    52  	switch video.Codec {
    53  	case "H264":
    54  		demuxer.vdp = NewH264Depacketizer(video, fw)
    55  	case "H265":
    56  		demuxer.vdp = NewH265Depacketizer(video, fw)
    57  	default:
    58  		return nil, fmt.Errorf("rtp demuxer unsupport video codec type:%s", video.Codec)
    59  	}
    60  	if audio.Codec == "AAC" {
    61  		demuxer.adp = NewAacDepacketizer(audio, fw)
    62  	} else {
    63  		demuxer.adp = emptyDepacketizer{}
    64  	}
    65  
    66  	go demuxer.process()
    67  	return demuxer, nil
    68  }
    69  
    70  func (demuxer *Demuxer) process() {
    71  	defer func() {
    72  		defer func() { // 避免 handler 再 panic
    73  			recover()
    74  		}()
    75  
    76  		if r := recover(); r != nil {
    77  			demuxer.logger.Errorf("FrameConverter routine panic;r = %v \n %s", r, debug.Stack())
    78  		}
    79  
    80  		// 尽早通知GC,回收内存
    81  		demuxer.recvQueue.Reset()
    82  	}()
    83  
    84  	var basePts int64
    85  	for !demuxer.closed {
    86  		p := demuxer.recvQueue.Pop()
    87  		if p == nil {
    88  			if !demuxer.closed {
    89  				demuxer.logger.Warn("FrameConverter:receive nil packet")
    90  			}
    91  			continue
    92  		}
    93  
    94  		packet := p.(*Packet)
    95  		var err error
    96  		switch packet.Channel {
    97  		case ChannelVideo:
    98  			err = demuxer.vdp.Depacketize(basePts, packet)
    99  		case ChannelVideoControl:
   100  			err = demuxer.vdp.Control(&basePts, packet)
   101  		case ChannelAudio:
   102  			err = demuxer.adp.Depacketize(basePts, packet)
   103  		case ChannelAudioControl:
   104  			err = demuxer.adp.Control(&basePts, packet)
   105  		}
   106  
   107  		if err != nil {
   108  			demuxer.logger.Errorf("rtp demuxer: depackeetize rtp frame error :%s", err.Error())
   109  			// break
   110  		}
   111  	}
   112  }
   113  
   114  // Close .
   115  func (demuxer *Demuxer) Close() error {
   116  	if demuxer.closed {
   117  		return nil
   118  	}
   119  
   120  	demuxer.closed = true
   121  	demuxer.recvQueue.Signal()
   122  	return nil
   123  }
   124  
   125  // WritePacket .
   126  func (demuxer *Demuxer) WriteRtpPacket(packet *Packet) error {
   127  	demuxer.recvQueue.Push(packet)
   128  	return nil
   129  }