MemoryTS 输出的ts 文件 没有音频编码信息
参考 hls 插件实现 ,使用memoryTs 输出的ts 文件没有音频编码信息,大致的代码如下: 直接使用hls 插件,输出的 ts 也无法获取 音视频信息,测试 拉流地址 http://huadonglive.starschinalive.com/stars/cjpd_stars-hd.m3u8?auth_key=1677980353-0-0-76a9f3c2dbaef16cf6b0f9d12b52eb5d
func (hls *HLSWriter) OnEvent(event any) {
switch v := event.(type) {
case *track.Video:
if hls.Audio != nil {
hls.ts.WritePMTPacket(hls.Audio.CodecID, v.CodecID)
} else {
hls.ts.WritePMTPacket(0, v.CodecID)
}
hls.AddTrack(v)
case *track.Audio:
if hls.Video != nil {
hls.ts.WritePMTPacket(v.CodecID, hls.Video.CodecID)
} else {
hls.ts.WritePMTPacket(v.CodecID, 0)
}
hls.AddTrack(v)
case AudioFrame:
pes := &mpegts.MpegtsPESFrame{
Pid: mpegts.PID_AUDIO,
IsKeyFrame: false,
ContinuityCounter: hls.audio_cc,
ProgramClockReferenceBase: uint64(v.DTS),
}
if err := hls.ts.WriteAudioFrame(v, pes); err != nil {
hls.Error("WriteVideoFrame", zap.Error(err))
return
}
hls.audio_cc = pes.ContinuityCounter
case VideoFrame:
if v.IFrame {
// hls.ts.WriteTo(hFile)
hls.frag(hls.Stream.Path, v.AbsTime, v)
}
pes := &mpegts.MpegtsPESFrame{
Pid: mpegts.PID_VIDEO,
IsKeyFrame: v.IFrame,
ContinuityCounter: hls.video_cc,
ProgramClockReferenceBase: uint64(v.DTS),
}
if err := hls.ts.WriteVideoFrame(v, pes); err != nil {
hls.Error("WriteVideoFrame", zap.Error(err))
return
}
hls.video_cc = pes.ContinuityCounter
default:
hls.Subscriber.OnEvent(event)
}
}
ffprobe 信息如下
[mpegts @ 0x11fde40] PES packet size mismatch
Last message repeated 5 times
[mpegts @ 0x11fde40] decoding for stream 0 failed
[mpegts @ 0x11fde40] decoding for stream 1 failed
[mpegts @ 0x11fde40] PES packet size mismatch
Last message repeated 5 times
[mpegts @ 0x11fde40] Could not find codec parameters for stream 1 (Audio: aac ([15][0][0][0] / 0x000F), 0 channels, fltp): unspecified sample rate
Consider increasing the value for the 'analyzeduration' and 'probesize' options
Input #0, mpegts, from 'monibuca/output/hls/gtzy/cctv5P480/s15/cctv5-2303081101-18747-18765.ts':
Duration: 00:00:00.27, start: 18765.786033, bitrate: 589 kb/s
Program 1
Stream #0:0[0x101]: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p(progressive), 640x480 [SAR 4:3 DAR 16:9], 30 fps, 30 tbr, 90k tbn, 60 tbc
Stream #0:1[0x102]: Audio: aac ([15][0][0][0] / 0x000F), 0 channels, fltp
func (ts *MemoryTs) WriteTo(w io.Writer) (int64, error) {
w.Write(mpegts.DefaultPATPacket)
w.Write(ts.PMT)
return ts.BLL.WriteTo(w)
}
注意写入的数据,PAT+PMT+PES
最新版本 hls 插件不做任何改动测试 hls拉流发布,flv 订阅 可以预览播放, hls 订阅 无法播放,没有编码信息 最新版本的engin 好像不稳定, flv 播放大约 2-3 分钟后就无法播放了,订阅收不到内容
我看之前版本的代码,音频在 AudioDeConf AudioPacketToPES 有处理写入编码信息,视频 VideoPacketToPES 也有使用 Track.DecoderConfiguration 处理写入视频编码信息, memoryts 代码好像没有找到写入 音视频编码的信息
hls拉流发布我抽空测一下,估计之前的改动影响到了这个
我提供的测试直播流,有我之前反馈的 ts 包乱序的问题,需要修正
package mpegts
import (
"bytes"
"errors"
"io"
)
type mpegTsStreamStatus struct {
pesPkt *MpegTsPESPacket
frames int
}
func (s *MpegTsStream) Feed(ts io.Reader) (err error) {
var reader bytes.Reader
var lr io.LimitedReader
lr.R = &reader
var tsHeader MpegTsHeader
tsData := make([]byte, TS_PACKET_SIZE)
streamsStatus := make(map[uint16]*mpegTsStreamStatus)
for {
_, err = io.ReadFull(ts, tsData)
if err == io.EOF {
// 文件结尾 把最后面的数据发出去
for _, ss := range streamsStatus {
if ss.pesPkt != nil {
s.PESChan <- ss.pesPkt
ss.pesPkt = nil
}
}
return nil
} else if err != nil {
return
}
reader.Reset(tsData)
lr.N = TS_PACKET_SIZE
if tsHeader, err = ReadTsHeader(&lr); err != nil {
return
}
if tsHeader.SyncByte != 0x47 {
return errors.New("sync byte error")
}
if tsHeader.Pid == PID_PAT {
if s.PAT, err = ReadPAT(&lr); err != nil {
return
}
continue
}
if len(s.PMT.Stream) == 0 {
for _, v := range s.PAT.Program {
if v.ProgramMapPID == tsHeader.Pid {
if s.PMT, err = ReadPMT(&lr); err != nil {
return
}
}
continue
}
}
for _, v := range s.PMT.Stream {
if v.ElementaryPID == tsHeader.Pid {
ss := streamsStatus[v.ElementaryPID]
if ss == nil {
ss = &mpegTsStreamStatus{}
streamsStatus[v.ElementaryPID] = ss
}
if tsHeader.PayloadUnitStartIndicator == 1 {
if ss.pesPkt != nil {
s.PESChan <- ss.pesPkt
}
ss.pesPkt = &MpegTsPESPacket{}
if ss.pesPkt.Header, err = ReadPESHeader(&lr); err != nil {
return
}
}
io.Copy(&ss.pesPkt.Payload, &lr)
}
}
}
}