github.com/cnotch/ipchub@v1.1.0/av/format/mpegts/muxer.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 mpegts
     6  
     7  import (
     8  	"fmt"
     9  	"runtime/debug"
    10  
    11  	"github.com/cnotch/ipchub/av/codec"
    12  	"github.com/cnotch/queue"
    13  	"github.com/cnotch/xlog"
    14  )
    15  
    16  // Packetizer 封包器
    17  type Packetizer interface {
    18  	Packetize(frame *codec.Frame) error
    19  }
    20  
    21  type emptyPacketizer struct{}
    22  
    23  func (emptyPacketizer) Packetize(frame *codec.Frame) error { return nil }
    24  
    25  // Muxer mpegts muxer from av.Frame(H264[+AAC])
    26  type Muxer struct {
    27  	recvQueue *queue.SyncQueue
    28  	closed    bool
    29  	logger    *xlog.Logger // 日志对象
    30  }
    31  
    32  // NewMuxer .
    33  func NewMuxer(videoMeta *codec.VideoMeta, audioMeta *codec.AudioMeta, tsframeWriter FrameWriter, logger *xlog.Logger) (*Muxer, error) {
    34  	muxer := &Muxer{
    35  		recvQueue: queue.NewSyncQueue(),
    36  		closed:    false,
    37  		logger:    logger,
    38  	}
    39  	var vp Packetizer = emptyPacketizer{}
    40  	var ap Packetizer = emptyPacketizer{}
    41  
    42  	switch videoMeta.Codec {
    43  	case "H264":
    44  		vp = NewH264Packetizer(videoMeta, tsframeWriter)
    45  	default:
    46  		return nil, fmt.Errorf("ts muxer unsupport video codec type:%s", videoMeta.Codec)
    47  	}
    48  
    49  	switch audioMeta.Codec {
    50  	case "AAC":
    51  		ap = NewAacPacketizer(audioMeta, tsframeWriter)
    52  	default:
    53  		return nil, fmt.Errorf("ts muxer unsupport audio codec type:%s", videoMeta.Codec)
    54  	}
    55  
    56  	go muxer.process(vp, ap)
    57  	return muxer, nil
    58  }
    59  
    60  // WriteFrame .
    61  func (muxer *Muxer) WriteFrame(frame *codec.Frame) error {
    62  	muxer.recvQueue.Push(frame)
    63  	return nil
    64  }
    65  
    66  // Close .
    67  func (muxer *Muxer) Close() error {
    68  	if muxer.closed {
    69  		return nil
    70  	}
    71  
    72  	muxer.closed = true
    73  	muxer.recvQueue.Signal()
    74  	return nil
    75  }
    76  
    77  func (muxer *Muxer) process(vp, ap Packetizer) {
    78  	defer func() {
    79  		defer func() { // 避免 handler 再 panic
    80  			recover()
    81  		}()
    82  
    83  		if r := recover(); r != nil {
    84  			muxer.logger.Errorf("ts muxer routine panic;r = %v \n %s", r, debug.Stack())
    85  		}
    86  
    87  		// 尽早通知GC,回收内存
    88  		muxer.recvQueue.Reset()
    89  	}()
    90  
    91  	for !muxer.closed {
    92  		f := muxer.recvQueue.Pop()
    93  		if f == nil {
    94  			if !muxer.closed {
    95  				muxer.logger.Warn("tsmuxer: receive nil frame")
    96  			}
    97  			continue
    98  		}
    99  
   100  		frame := f.(*codec.Frame)
   101  
   102  		switch frame.MediaType {
   103  		case codec.MediaTypeVideo:
   104  			if err := vp.Packetize(frame); err != nil {
   105  				muxer.logger.Errorf("tsmuxer: muxVideoTag error - %s", err.Error())
   106  			}
   107  		case codec.MediaTypeAudio:
   108  			if err := ap.Packetize(frame); err != nil {
   109  				muxer.logger.Errorf("tsmuxer: muxAudioTag error - %s", err.Error())
   110  			}
   111  		default:
   112  		}
   113  	}
   114  }