Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MemoryTS 输出的ts 文件 没有音频编码信息 #78

Open
mars79668 opened this issue Mar 8, 2023 · 4 comments
Open

MemoryTS 输出的ts 文件 没有音频编码信息 #78

mars79668 opened this issue Mar 8, 2023 · 4 comments

Comments

@mars79668
Copy link

mars79668 commented Mar 8, 2023

参考 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
@langhuihui
Copy link
Member

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

@mars79668
Copy link
Author

mars79668 commented Mar 8, 2023

最新版本 hls 插件不做任何改动测试 hls拉流发布,flv 订阅 可以预览播放, hls 订阅 无法播放,没有编码信息
最新版本的engin 好像不稳定, flv 播放大约 2-3 分钟后就无法播放了,订阅收不到内容

我看之前版本的代码,音频在 AudioDeConf AudioPacketToPES 有处理写入编码信息,视频 VideoPacketToPES 也有使用 Track.DecoderConfiguration 处理写入视频编码信息, memoryts 代码好像没有找到写入 音视频编码的信息

@langhuihui
Copy link
Member

hls拉流发布我抽空测一下,估计之前的改动影响到了这个

@mars79668
Copy link
Author

我提供的测试直播流,有我之前反馈的 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)
			}
		}
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants