1 Star 0 Fork 0

general252 / gomedia

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
ps-demuxer.go 9.84 KB
一键复制 编辑 原始数据 按行查看 历史
LIN 提交于 2023-08-24 17:00 . rename
package mpeg2
import (
"gitee.com/general252/gomedia/go-codec"
)
type psstream struct {
sid uint8
cid PS_STREAM_TYPE
pts uint64
dts uint64
streamBuf []byte
}
func newpsstream(sid uint8, cid PS_STREAM_TYPE) *psstream {
return &psstream{
sid: sid,
cid: cid,
streamBuf: make([]byte, 0, 4096),
}
}
type PSDemuxer struct {
streamMap map[uint8]*psstream
pkg *PSPacket
mpeg1 bool
cache []byte
OnFrame func(frame []byte, cid PS_STREAM_TYPE, pts uint64, dts uint64)
//解ps包过程中,解码回调psm,system header,pes包等
//decodeResult 解码ps包时的产生的错误
//这个回调主要用于debug,查看是否ps包存在问题
OnPacket func(pkg Display, decodeResult error)
}
func NewPSDemuxer() *PSDemuxer {
return &PSDemuxer{
streamMap: make(map[uint8]*psstream),
pkg: new(PSPacket),
cache: make([]byte, 0, 256),
OnFrame: nil,
OnPacket: nil,
}
}
func (psdemuxer *PSDemuxer) Input(data []byte) error {
var bs *codec.BitStream
if len(psdemuxer.cache) > 0 {
psdemuxer.cache = append(psdemuxer.cache, data...)
bs = codec.NewBitStream(psdemuxer.cache)
} else {
bs = codec.NewBitStream(data)
}
saveReseved := func() {
tmpcache := make([]byte, bs.RemainBytes())
copy(tmpcache, bs.RemainData())
psdemuxer.cache = tmpcache
}
var ret error = nil
for !bs.EOS() {
if mpegerr, ok := ret.(Error); ok {
if mpegerr.NeedMore() {
saveReseved()
}
break
}
if bs.RemainBits() < 32 {
ret = errNeedMore
saveReseved()
break
}
prefix_code := bs.NextBits(32)
switch prefix_code {
case 0x000001BA: //pack header
if psdemuxer.pkg.Header == nil {
psdemuxer.pkg.Header = new(PSPackHeader)
}
ret = psdemuxer.pkg.Header.Decode(bs)
psdemuxer.mpeg1 = psdemuxer.pkg.Header.IsMpeg1
if psdemuxer.OnPacket != nil {
psdemuxer.OnPacket(psdemuxer.pkg.Header, ret)
}
case 0x000001BB: //system header
if psdemuxer.pkg.Header == nil {
panic("psdemuxer.pkg.Header must not be nil")
}
if psdemuxer.pkg.System == nil {
psdemuxer.pkg.System = new(System_header)
}
ret = psdemuxer.pkg.System.Decode(bs)
if psdemuxer.OnPacket != nil {
psdemuxer.OnPacket(psdemuxer.pkg.System, ret)
}
case 0x000001BC: //program stream map
if psdemuxer.pkg.Psm == nil {
psdemuxer.pkg.Psm = new(Program_stream_map)
}
if ret = psdemuxer.pkg.Psm.Decode(bs); ret == nil {
for _, streaminfo := range psdemuxer.pkg.Psm.Stream_map {
if _, found := psdemuxer.streamMap[streaminfo.Elementary_stream_id]; !found {
stream := newpsstream(streaminfo.Elementary_stream_id, PS_STREAM_TYPE(streaminfo.Stream_type))
psdemuxer.streamMap[stream.sid] = stream
}
}
}
if psdemuxer.OnPacket != nil {
psdemuxer.OnPacket(psdemuxer.pkg.Psm, ret)
}
case 0x000001BD, 0x000001BE, 0x000001BF, 0x000001F0, 0x000001F1,
0x000001F2, 0x000001F3, 0x000001F4, 0x000001F5, 0x000001F6,
0x000001F7, 0x000001F8, 0x000001F9, 0x000001FA, 0x000001FB:
if psdemuxer.pkg.CommPes == nil {
psdemuxer.pkg.CommPes = new(CommonPesPacket)
}
ret = psdemuxer.pkg.CommPes.Decode(bs)
case 0x000001FF: //program stream directory
if psdemuxer.pkg.Psd == nil {
psdemuxer.pkg.Psd = new(Program_stream_directory)
}
ret = psdemuxer.pkg.Psd.Decode(bs)
case 0x000001B9: //MPEG_program_end_code
continue
default:
if prefix_code&0xFFFFFFE0 == 0x000001C0 || prefix_code&0xFFFFFFE0 == 0x000001E0 {
if psdemuxer.pkg.Pes == nil {
psdemuxer.pkg.Pes = NewPesPacket()
}
if psdemuxer.mpeg1 {
ret = psdemuxer.pkg.Pes.DecodeMpeg1(bs)
} else {
ret = psdemuxer.pkg.Pes.Decode(bs)
}
if psdemuxer.OnPacket != nil {
psdemuxer.OnPacket(psdemuxer.pkg.Pes, ret)
}
if ret == nil {
if stream, found := psdemuxer.streamMap[psdemuxer.pkg.Pes.Stream_id]; found {
if psdemuxer.mpeg1 && stream.cid == PS_STREAM_UNKNOW {
psdemuxer.guessCodecid(stream)
}
psdemuxer.demuxPespacket(stream, psdemuxer.pkg.Pes)
} else {
if psdemuxer.mpeg1 {
stream := newpsstream(psdemuxer.pkg.Pes.Stream_id, PS_STREAM_UNKNOW)
psdemuxer.streamMap[stream.sid] = stream
stream.streamBuf = append(stream.streamBuf, psdemuxer.pkg.Pes.Pes_payload...)
stream.pts = psdemuxer.pkg.Pes.Pts
stream.dts = psdemuxer.pkg.Pes.Dts
}
}
}
} else {
bs.SkipBits(8)
}
}
}
if ret == nil && len(psdemuxer.cache) > 0 {
psdemuxer.cache = nil
}
return ret
}
func (psdemuxer *PSDemuxer) Flush() {
for _, stream := range psdemuxer.streamMap {
if len(stream.streamBuf) == 0 {
continue
}
if psdemuxer.OnFrame != nil {
psdemuxer.OnFrame(stream.streamBuf, stream.cid, stream.pts/90, stream.dts/90)
}
}
}
func (psdemuxer *PSDemuxer) guessCodecid(stream *psstream) {
if stream.sid&0xE0 == uint8(PES_STREAM_AUDIO) {
stream.cid = PS_STREAM_AAC
} else if stream.sid&0xE0 == uint8(PES_STREAM_VIDEO) {
h264score := 0
h265score := 0
codec.SplitFrame(stream.streamBuf, func(nalu []byte) bool {
h264nalutype := codec.H264NaluTypeWithoutStartCode(nalu)
h265nalutype := codec.H265NaluTypeWithoutStartCode(nalu)
if h264nalutype == codec.H264_NAL_PPS ||
h264nalutype == codec.H264_NAL_SPS ||
h264nalutype == codec.H264_NAL_I_SLICE {
h264score += 2
} else if h264nalutype < 5 {
h264score += 1
} else if h264nalutype > 20 {
h264score -= 1
}
if h265nalutype == codec.H265_NAL_PPS ||
h265nalutype == codec.H265_NAL_SPS ||
h265nalutype == codec.H265_NAL_VPS ||
(h265nalutype >= codec.H265_NAL_SLICE_BLA_W_LP && h265nalutype <= codec.H265_NAL_SLICE_CRA) {
h265score += 2
} else if h265nalutype >= codec.H265_NAL_Slice_TRAIL_N && h265nalutype <= codec.H265_NAL_SLICE_RASL_R {
h265score += 1
} else if h265nalutype > 40 {
h265score -= 1
}
if h264score > h265score && h264score >= 4 {
stream.cid = PS_STREAM_H264
} else if h264score < h265score && h265score >= 4 {
stream.cid = PS_STREAM_H265
}
return true
})
}
}
func (psdemuxer *PSDemuxer) demuxPespacket(stream *psstream, pes *PesPacket) error {
switch stream.cid {
case PS_STREAM_AAC, PS_STREAM_G711A, PS_STREAM_G711U:
return psdemuxer.demuxAudio(stream, pes)
case PS_STREAM_H264, PS_STREAM_H265:
return psdemuxer.demuxH26x(stream, pes)
case PS_STREAM_UNKNOW:
if stream.pts != pes.Pts {
stream.streamBuf = nil
}
stream.streamBuf = append(stream.streamBuf, pes.Pes_payload...)
stream.pts = pes.Pts
stream.dts = pes.Dts
}
return nil
}
func (psdemuxer *PSDemuxer) demuxAudio(stream *psstream, pes *PesPacket) error {
if stream.pts != pes.Pts && len(stream.streamBuf) > 0 {
if psdemuxer.OnFrame != nil {
psdemuxer.OnFrame(stream.streamBuf, stream.cid, stream.pts/90, stream.dts/90)
}
stream.streamBuf = stream.streamBuf[:0]
}
stream.streamBuf = append(stream.streamBuf, pes.Pes_payload...)
stream.pts = pes.Pts
stream.dts = pes.Dts
return nil
}
func (psdemuxer *PSDemuxer) demuxH26x(stream *psstream, pes *PesPacket) error {
if len(stream.streamBuf) == 0 {
stream.pts = pes.Pts
stream.dts = pes.Dts
}
stream.streamBuf = append(stream.streamBuf, pes.Pes_payload...)
start, sc := codec.FindStartCode(stream.streamBuf, 0)
for start >= 0 {
end, sc2 := codec.FindStartCode(stream.streamBuf, start+int(sc))
if end < 0 {
break
}
if stream.cid == PS_STREAM_H264 {
naluType := codec.H264NaluType(stream.streamBuf[start:])
if naluType != codec.H264_NAL_AUD {
if psdemuxer.OnFrame != nil {
psdemuxer.OnFrame(stream.streamBuf[start:end], stream.cid, stream.pts/90, stream.dts/90)
}
}
} else if stream.cid == PS_STREAM_H265 {
naluType := codec.H265NaluType(stream.streamBuf[start:])
if naluType != codec.H265_NAL_AUD {
if psdemuxer.OnFrame != nil {
psdemuxer.OnFrame(stream.streamBuf[start:end], stream.cid, stream.pts/90, stream.dts/90)
}
}
}
start = end
sc = sc2
}
stream.streamBuf = stream.streamBuf[start:]
stream.pts = pes.Pts
stream.dts = pes.Dts
return nil
}
1
https://gitee.com/general252/gomedia.git
git@gitee.com:general252/gomedia.git
general252
gomedia
gomedia
v0.0.2

搜索帮助