Files
ipchub/av/format/mpegts/muxer.go
2021-01-16 20:41:50 +08:00

125 lines
2.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) 2019,CAOHONGJU All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package mpegts
import (
"fmt"
"runtime/debug"
"github.com/cnotch/ipchub/av/codec"
"github.com/cnotch/queue"
"github.com/cnotch/xlog"
)
// Packetizer 封包器
type Packetizer interface {
Packetize(basePts int64, frame *codec.Frame) error
}
type emptyPacketizer struct{}
func (emptyPacketizer) Packetize(basePts int64, frame *codec.Frame) error { return nil }
// 网络播放时 PTSPresentation Time Stamp的延时
// 影响视频 Tag 的 CTS 和音频的 DTSDecoding Time Stamp
const (
ptsDelay = 1000
)
// Muxer mpegts muxer from av.Frame(H264[+AAC])
type Muxer struct {
recvQueue *queue.SyncQueue
closed bool
logger *xlog.Logger // 日志对象
}
// NewMuxer .
func NewMuxer(videoMeta *codec.VideoMeta, audioMeta *codec.AudioMeta, tsframeWriter FrameWriter, logger *xlog.Logger) (*Muxer, error) {
muxer := &Muxer{
recvQueue: queue.NewSyncQueue(),
closed: false,
logger: logger,
}
var vp Packetizer = emptyPacketizer{}
var ap Packetizer = emptyPacketizer{}
switch videoMeta.Codec {
case "H264":
vp = NewH264Packetizer(videoMeta, tsframeWriter)
default:
return nil, fmt.Errorf("ts muxer unsupport video codec type:%s", videoMeta.Codec)
}
switch audioMeta.Codec {
case "AAC":
ap = NewAacPacketizer(audioMeta, tsframeWriter)
default:
return nil, fmt.Errorf("ts muxer unsupport audio codec type:%s", videoMeta.Codec)
}
go muxer.process(vp, ap)
return muxer, nil
}
// WriteFrame .
func (muxer *Muxer) WriteFrame(frame *codec.Frame) error {
muxer.recvQueue.Push(frame)
return nil
}
// Close .
func (muxer *Muxer) Close() error {
if muxer.closed {
return nil
}
muxer.closed = true
muxer.recvQueue.Signal()
return nil
}
func (muxer *Muxer) process(vp, ap Packetizer) {
defer func() {
defer func() { // 避免 handler 再 panic
recover()
}()
if r := recover(); r != nil {
muxer.logger.Errorf("ts muxer routine panicr = %v \n %s", r, debug.Stack())
}
// 尽早通知GC回收内存
muxer.recvQueue.Reset()
}()
var basePts int64
for !muxer.closed {
f := muxer.recvQueue.Pop()
if f == nil {
if !muxer.closed {
muxer.logger.Warn("tsmuxer: receive nil frame")
}
continue
}
frame := f.(*codec.Frame)
if basePts == 0 {
basePts = frame.AbsTimestamp
}
switch frame.MediaType {
case codec.MediaTypeVideo:
if err := vp.Packetize(basePts, frame); err != nil {
muxer.logger.Errorf("tsmuxer: muxVideoTag error - %s", err.Error())
}
case codec.MediaTypeAudio:
if err := ap.Packetize(basePts, frame); err != nil {
muxer.logger.Errorf("tsmuxer: muxAudioTag error - %s", err.Error())
}
default:
}
}
}