Giter Site home page Giter Site logo

gomedia's Introduction

gomedia

mpeg-ts,mpeg-ps,flv,mp4,rtmp muxer/demuxer

Installation

go get github.com/yapingcat/gomedia

H264/H265/AAC/VP8/OPUS/MP3

USAGE

  • decode sps/pps/vps/slice header
  • decode HEVCDecoderConfigurationRecord/AVCDecoderConfigurationRecord/AAC-ADTS/AudioSpecificConfiguration
  • encode HEVCDecoderConfigurationRecord/AVCDecoderConfigurationRecord/AAC-ADTS/AudioSpecificConfiguration
  • decode OPUS Extradata(ID Head "OpusHead") /OPUS Packet(TOC...)
  • encode OPUS Extradata
  • decode VP8 Frame Tag/Key Frame Head
  • decode MP3 Frame head

mpeg-ts

  • mux
    • H264
    • H265
    • AAC
    • MP3
  • demux
    • H264
    • H265
    • AAC
    • MP3

mpeg-ps

  • mux
    • H264
    • H265
    • AAC
    • G711A
    • G711U
  • demux
    • H264
    • H265
    • AAC
    • G711A
    • G711U

flv

  • mux
    • H264
    • H265
    • AAC
    • G711A
    • G711U
    • MP3
  • demux
    • H264
    • H265
    • AAC
    • G711A
    • G711U
    • MP3

mp4

  • demux
    • H264
    • H265
    • AAC
    • G711A
    • G711U
    • MP3
  • mux
    • H264
    • H265
    • AAC
    • G711A
    • G711U
    • MP3
    • OPUS

fmp4

  • demux
    • H264
    • H265
    • AAC
    • G711A
    • G711U
  • mux
    • H264
    • H265
    • AAC
    • G711A
    • G711U

ogg

  • demux
    • OPUS
    • VP8

rtmp

USAGE

  • support client/server
  • support play/publish
  • support h264/h265/aac/g711a/g711u/mp3

rtsp

  • support client/server(rfc2326)
  • support basic/digest
  • support rtp(rfc3550)
  • support g711/aac/h264/h265

gomedia's People

Contributors

346 avatar autoexpect avatar gyl30 avatar hsnks100 avatar imro0t avatar offmon avatar orestonce avatar udzura avatar yapingcat avatar ydylla avatar zsc714725 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gomedia's Issues

mp4muxer Writetrailer() error

muxer.Writetrailer() 后包报错, stbl-box.go中copy时未判断切片边界
panic: runtime error: slice bounds out of range [9229:9185]

goroutine 656 [running]:
github.com/yapingcat/gomedia/mp4.makeStblBox(0xc00018d800)
/home/lnct/go/pkg/mod/github.com/yapingcat/gomedia/[email protected]/stbl-box.go:39 +0x4f8
github.com/yapingcat/gomedia/mp4.makeMinfBox(0xc00018d800)
/home/lnct/go/pkg/mod/github.com/yapingcat/gomedia/[email protected]/minf-box.go:20 +0x7e
github.com/yapingcat/gomedia/mp4.makeMdiaBox(0xc00018d800)
/home/lnct/go/pkg/mod/github.com/yapingcat/gomedia/[email protected]/mdia-box.go:6 +0xdc
github.com/yapingcat/gomedia/mp4.makeTrak(0x15e7800000002)
/home/lnct/go/pkg/mod/github.com/yapingcat/gomedia/[email protected]/trak-box.go:7 +0x59
github.com/yapingcat/gomedia/mp4.(*Movmuxer).Writetrailer(0xc000311320)
/home/lnct/go/pkg/mod/github.com/yapingcat/gomedia/[email protected]/mp4muxer.go:337 +0x39f

ps流文件转mp4报错,无法转换

func main() {
tsfile := "1666971231078.ps"
tsFd, err := os.Open(tsfile)
if err != nil {
fmt.Println(err)
return
}
defer tsFd.Close()

hasAudio := false
hasVideo := false
var atid uint32 = 0
var vtid uint32 = 0

mp4filename := "convert_ps.mp4"
mp4file, err := os.OpenFile(mp4filename, os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
	fmt.Println(err)
	return
}
defer mp4file.Close()

muxer, err := mp4.CreateMp4Muxer(mp4file)
if err != nil {
	fmt.Println(err)
	return
}

demuxer := mpeg2.NewPSDemuxer()
//demuxer := mpeg2.NewTSDemuxer()
demuxer.OnFrame = func(frame []byte, cid mpeg2.PS_STREAM_TYPE, pts uint64, dts uint64) {
	if cid == mpeg2.PS_STREAM_H264 {
		if !hasVideo {
			vtid = muxer.AddVideoTrack(mp4.MP4_CODEC_H264)
			hasVideo = true
		}
		err := muxer.Write(vtid, frame, uint64(pts), uint64(dts))
		if err != nil {
			fmt.Println(err)
		}
	} else if cid == mpeg2.PS_STREAM_AAC {
		if !hasAudio {
			atid = muxer.AddAudioTrack(mp4.MP4_CODEC_AAC)
			hasAudio = true
		}
		err := muxer.Write(atid, frame, uint64(pts), uint64(dts))
		if err != nil {
			fmt.Println(err)
		}
	} else if cid == mpeg2.PS_STREAM_G711A {
		if !hasAudio {
			atid = muxer.AddAudioTrack(mp4.MP4_CODEC_G711A)
			hasAudio = true
		}
		err := muxer.Write(atid, frame, uint64(pts), uint64(dts))
		if err != nil {
			fmt.Println(err)
		}
	} else if cid == mpeg2.PS_STREAM_G711U {
		if !hasAudio {
			atid = muxer.AddAudioTrack(mp4.MP4_CODEC_G711U)
			hasAudio = true
		}
		err := muxer.Write(atid, frame, uint64(pts), uint64(dts))
		if err != nil {
			fmt.Println(err)
		}
	}
}
demuxer.OnPacket = func(pkg mpeg2.Display, decodeResult error) {

}
buf, _ := ioutil.ReadAll(tsFd)
fmt.Printf("read %d size\n", len(buf))
fmt.Println(demuxer.Input(buf))
err = muxer.WriteTrailer()
if err != nil {
	fmt.Errorf("err:%v", err)
	return
}

}
执行到muxer.WriteTrailer() 报错 panic: runtime error: index out of range [308] with length 308

resteamer

What should we do to forward the broadcast from the RTMP server to another RTMP server?

ts转mp4发生了panic,数组越界

  • 源代码:
package main

import (
    "fmt"
    "io/ioutil"
    "os"

    "bytes"
    "strconv"

    "github.com/yapingcat/gomedia/codec"
    "github.com/yapingcat/gomedia/mp4"
    "github.com/yapingcat/gomedia/mpeg2"
)

func main() {
    tsfile := `01389.ts`                // input
    mp4filename := "output-gomedia.mp4" // output
    mp4file, err := os.OpenFile(mp4filename, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0666)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer mp4file.Close()

    muxer, err := mp4.CreateMp4Muxer(mp4file)
    if err != nil {
        panic(err)
    }

    vtid := muxer.AddVideoTrack(mp4.MP4_CODEC_H264)
    atid := muxer.AddAudioTrack(mp4.MP4_CODEC_AAC)

    buf, err := ioutil.ReadFile(tsfile)
    if err != nil {
        panic(err)
    }
    var audio_timestamp uint64 = 0
    aac_sampleRate := -1
    demuxer := mpeg2.NewTSDemuxer()
    demuxer.OnFrame = func(cid mpeg2.TS_STREAM_TYPE, frame []byte, pts uint64, dts uint64) {
        if cid == mpeg2.TS_STREAM_AAC {
            codec.SplitAACFrame(frame, func(aac []byte) {
                if aac_sampleRate == -1 {
                    adts := codec.NewAdtsFrameHeader()
                    adts.Decode(aac)
                    aac_sampleRate = codec.AACSampleIdxToSample(int(adts.Fix_Header.Sampling_frequency_index))
                    fmt.Println("Got aac sample rate:", aac_sampleRate)
                }
                err = muxer.Write(atid, aac, audio_timestamp, audio_timestamp)
                audio_timestamp += uint64((1024 * 1000 / aac_sampleRate)) //每帧aac采样固定为1024。aac_sampleRate 为采样率
                if err != nil {
                    panic(err)
                }
            })
        } else if cid == mpeg2.TS_STREAM_H264 {
            err = muxer.Write(vtid, frame, uint64(pts), uint64(dts))
            if err != nil {
                panic(err)
            }
        } else {
            panic("unkwon cid " + strconv.Itoa(int(cid)))
        }
    }
    for idx := 0; idx < 4; idx++ {
        fmt.Println("read file ", idx)
        err = demuxer.Input(bytes.NewReader(buf))
        if err != nil {
            panic(err)
        }
    }
    err = muxer.WriteTrailer()
    if err != nil {
        panic(err)
    }
}
read file  0
Got aac sample rate: 44100
panic: runtime error: index out of range [3] with length 3

goroutine 1 [running]:
github.com/yapingcat/gomedia/codec.H265NaluType(...)
	/root/go/pkg/mod/github.com/yapingcat/[email protected]/codec/util.go:95
github.com/yapingcat/gomedia/mpeg2.(*TSDemuxer).flush.func1({0xc0000c9e17, 0x9dd, 0x0})
	/root/go/pkg/mod/github.com/yapingcat/[email protected]/mpeg2/ts-demuxer.go:158 +0xa9
github.com/yapingcat/gomedia/codec.SplitFrameWithStartCode({0xc0000c9800, 0xc0001ce006, 0xaa}, 0xc000088b30)
	/root/go/pkg/mod/github.com/yapingcat/[email protected]/codec/util.go:66 +0xbc
github.com/yapingcat/gomedia/mpeg2.(*TSDemuxer).flush(0xc000088ea0)
	/root/go/pkg/mod/github.com/yapingcat/[email protected]/mpeg2/ts-demuxer.go:152 +0x173
github.com/yapingcat/gomedia/mpeg2.(*TSDemuxer).Input(0xc000088ea0, {0x4e9fa0, 0xc00008e210})
	/root/go/pkg/mod/github.com/yapingcat/[email protected]/mpeg2/ts-demuxer.go:139 +0x4a5
main.main()
	/root/work/min/main.go:67 +0x44d

PSDemuxer 不支持并发调用

例如 一个 PSDemuxer[] 用chan 发送 data数据 ,循环调用 d.Input(tmpData),发行一个ps对象没问题,如果是多个ps对象,会报错
错误代码如下:
panic: runtime error: slice bounds out of range [41988:21648]

goroutine 528 [running]:
github.com/yapingcat/gomedia/go-codec.FindStartCode({0xc0007d2400, 0x5490, 0x9c00}, 0xa404)
C:/Users/Administrator/go/pkg/mod/github.com/yapingcat/[email protected]/go-codec/util.go:16 +0x225
github.com/yapingcat/gomedia/go-mpeg2.(*PSDemuxer).demuxH26x(0xc0001548c0, 0xc0004b2880, 0xc00047b9e0)
C:/Users/Administrator/go/pkg/mod/github.com/yapingcat/[email protected]/go-mpeg2/ps-demuxer.go:254 +0x2d2
github.com/yapingcat/gomedia/go-mpeg2.(*PSDemuxer).demuxPespacket(0xc0001548c0, 0xc0004b2880, 0xc00047b9e0)
C:/Users/Administrator/go/pkg/mod/github.com/yapingcat/[email protected]/go-mpeg2/ps-demuxer.go:221 +0xa7
github.com/yapingcat/gomedia/go-mpeg2.(*PSDemuxer).Input(0xc0001548c0, {0xc0007a4000, 0x54ac, 0x54ac})
C:/Users/Administrator/go/pkg/mod/github.com/yapingcat/[email protected]/go-mpeg2/ps-demuxer.go:142 +0xbba
com.shuweiapp.sip-utils/web.SendLiveData.func1.2()
C:/Users/Administrator/GolandProjects/sip_utils/web/Device.go:152 +0x245
created by com.shuweiapp.sip-utils/web.SendLiveData.func1
C:/Users/Administrator/GolandProjects/sip_utils/web/Device.go:148 +0x639

功能代码如下

for !channel.stop {
					select {
					case data := <-channel.gb.GetData():
						var wg sync.WaitGroup
						if ds, ok := demuxers[channel.deviceId]; ok {
							for _, d := range ds {
								wg.Add(1)
								go func() {
									tmpData := make([]byte, len(data))
									copy(tmpData, data)
									fmt.Printf("当前通道%s,写入对端:%v\r\n", channel.deviceId)
									fmt.Println(d.Input(tmpData))
									wg.Done()
								}()
							}
						} else {
							fmt.Printf("当前通道%s,无人观看\r\n", channel.deviceId)
						}
						wg.Wait()
						channel.gb.SetReply(true)
					case <-time.After(time.Duration(30) * time.Second):
						fmt.Printf("通道:%s,获取流超时,自动关闭\r\n", channel.deviceId)
						channel.stop = true
					}
				}

起初我以为是我没控制chan消费导致的,后面我控制了chan的发送数据频率,结果还是一样,我在调用input之前已经做了一次数据的深度拷贝

bug: if pps sps is not the first Frame , its pts shows wrong

in https://github.com/yapingcat/gomedia/blob/main/example/example_demux_ts.go#L45
dump pts and dts

if the pps and sps is not the first frame , its pts and dts present the last frame pts

below is the first frame
pts dts size type
2899 2899 17 7 sps
2899 2899 8 8 pps
2899 2899 1274 5 IDR
2899 2899 11899 5
2932 2932 7036 1

below is not the first frame
pts dts size type
22602 22602 24163 1
22635 22635 17621 1
22635 22635 17 7 sps
22635 22635 8 8 pps
62455 62455 1238 5
62455 62455 61365 5
62455 62455 3611 5
62489 62489 61424 1
in this case there is a gap in pts,
the same issue exist when there is no gap

flv转mp4报错?

用的你的例程。
`
package main

import (
"fmt"
"os"

"github.com/yapingcat/gomedia/go-codec"
"github.com/yapingcat/gomedia/go-flv"
"github.com/yapingcat/gomedia/go-mp4"

)

func FlvToMp4(Mp4FilePath, FlvFilePath string) {
mp4file, err := os.OpenFile(Mp4FilePath, os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
fmt.Println(err)
return
}
defer mp4file.Close()

muxer, err := mp4.CreateMp4Muxer(mp4file)
if err != nil {
	fmt.Println(err)
	return
}
vtid := muxer.AddVideoTrack(mp4.MP4_CODEC_H264)
atid := muxer.AddAudioTrack(mp4.MP4_CODEC_AAC)

flvfilereader, _ := os.Open(FlvFilePath)
defer flvfilereader.Close()
fr := flv.CreateFlvReader()

fr.OnFrame = func(cid codec.CodecID, b []byte, pts, dts uint32) {
	if cid == codec.CODECID_AUDIO_AAC {
		err := muxer.Write(atid, b, uint64(pts), uint64(dts))
		if err != nil {
			fmt.Println(err)
		}

	} else if cid == codec.CODECID_VIDEO_H264 {
		err := muxer.Write(vtid, b, uint64(pts), uint64(dts))
		if err != nil {
			fmt.Println(err)
		}
	}
}

cache := make([]byte, 4096)
for {
	n, err := flvfilereader.Read(cache)
	if err != nil {
		fmt.Println(err)
		break
	}
	fr.Input(cache[0:n])
}
err = muxer.WriteTrailer()
if err != nil {
	fmt.Println(err)
}
fmt.Println("flv转mp4完成!")

}

func main() {
FlvToMp4("out.mp4", "out.flv")
}

`

错误:
`
EOF
panic: runtime error: index out of range [0] with length 0

goroutine 1 [running]:
github.com/yapingcat/gomedia/go-mp4.(*mp4track).makeStblTable(0xc00008c8f0)
D:/goproject/pkg/mod/github.com/yapingcat/[email protected]/go-mp4/mp4track.go:226 +0x552
github.com/yapingcat/gomedia/go-mp4.makeTrak(0xc00008c8f0, 0x1c060?)
D:/goproject/pkg/mod/github.com/yapingcat/[email protected]/go-mp4/trak-box.go:9 +0x19a
github.com/yapingcat/gomedia/go-mp4.(*Movmuxer).writeMoov(0xc0000d6000, {0xe87bc8, 0xc0000ce018})
D:/goproject/pkg/mod/github.com/yapingcat/[email protected]/go-mp4/mp4muxer.go:294 +0x1cb
github.com/yapingcat/gomedia/go-mp4.(*Movmuxer).WriteTrailer(0xc0000d6000)
D:/goproject/pkg/mod/github.com/yapingcat/[email protected]/go-mp4/mp4muxer.go:219 +0x17c
main.FlvToMp4({0xe6005d?, 0x0?}, {0xe60056, 0x7})
D:/goproject/src/MoocDownload/test/3.go:64 +0x37a
main.main()
D:/goproject/src/MoocDownload/test/3.go:72 +0x2f
`

搞不懂为什么会出这样的错!
这个是视频链接:
链接:https://pan.baidu.com/s/1K4cl2kI6HSbKoSb_Fy32vg
提取码:lttl
--来自百度网盘超级会员V3的分享

画面与声音不同步

代码:

package main

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"github.com/yapingcat/gomedia/go-codec"
	"github.com/yapingcat/gomedia/go-mp4"
	"github.com/yapingcat/gomedia/go-mpeg2"
	"io/ioutil"
	"os"
	"strconv"
)

func main() {
	var tsList []string
	for idx := 1900; idx <= 1950; idx++ {
		tsList = append(tsList, fmt.Sprintf(`%05d.ts`, idx))
	}
	err := MergeTsFileListToSingleMp4(MergeTsFileListToSingleMp4_Req{
		TsFileList: tsList,
		OutputMp4:  `all.mp4`,
		Ctx:        context.Background(),
	})
	if err != nil {
		panic(err)
	}
}

type MergeTsFileListToSingleMp4_Req struct {
	TsFileList []string
	OutputMp4  string
	Ctx        context.Context
}

func MergeTsFileListToSingleMp4(req MergeTsFileListToSingleMp4_Req) (err error) {
	mp4file, err := os.OpenFile(req.OutputMp4, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0666)
	if err != nil {
		return err
	}
	defer mp4file.Close()

	muxer, err := mp4.CreateMp4Muxer(mp4file)
	if err != nil {
		return err
	}
	vtid := muxer.AddVideoTrack(mp4.MP4_CODEC_H264)
	atid := muxer.AddAudioTrack(mp4.MP4_CODEC_AAC)

	demuxer := mpeg2.NewTSDemuxer()
	var OnFrameErr error
	var audioTimestamp uint64 = 0
	aacSampleRate := -1
	demuxer.OnFrame = func(cid mpeg2.TS_STREAM_TYPE, frame []byte, pts uint64, dts uint64) {
		if OnFrameErr != nil {
			return
		}
		if cid == mpeg2.TS_STREAM_AAC {
			codec.SplitAACFrame(frame, func(aac []byte) {
				if aacSampleRate == -1 {
					adts := codec.NewAdtsFrameHeader()
					adts.Decode(aac)
					aacSampleRate = codec.AACSampleIdxToSample(int(adts.Fix_Header.Sampling_frequency_index))
				}
				err = muxer.Write(atid, aac, audioTimestamp, audioTimestamp)
				audioTimestamp += uint64(1024 * 1000 / aacSampleRate) //每帧aac采样固定为1024。aac_sampleRate 为采样率
				if err != nil {
					OnFrameErr = err
					return
				}
			})
		} else if cid == mpeg2.TS_STREAM_H264 {
			err = muxer.Write(vtid, frame, uint64(pts), uint64(dts))
			if err != nil {
				OnFrameErr = err
				return
			}
		} else {
			OnFrameErr = errors.New("unknown cid " + strconv.Itoa(int(cid)))
			return
		}
	}

	for _, tsFile := range req.TsFileList {
		select {
		case <-req.Ctx.Done():
			return req.Ctx.Err()
		default:
		}
		var buf []byte
		buf, err = ioutil.ReadFile(tsFile)
		if err != nil {
			return err
		}
		err = demuxer.Input(bytes.NewReader(buf))
		if err != nil {
			return err
		}
		if OnFrameErr != nil {
			return OnFrameErr
		}
	}

	err = muxer.WriteTrailer()
	if err != nil {
		return err
	}
	err = mp4file.Sync()
	if err != nil {
		return err
	}
	return nil
}

1.zip
2.zip
未命名

  • 少量几个ts看不出明显差异, 需要多一点ts合并才能看清楚. 合并后的mp4文件的 02:00 最明显, 角色还没动嘴就有声音了. 我用播放器看了这个画面原始的ts 01939.ts, 声音与画面是同步的.

请教使用pion(go实现的webrtc)播放mp4,pts顺序的问题

你好,我使用gomedia的mp4.CreateMp4Demuxer(crs)打开一个本地mp4文件,
通过pkg, err := demuxer.ReadPacket()不停地读取packet,然后将数据喂给pion的TrackLocalStaticSample,发现视频有些帧的播放顺序错了,请问是不是需要将读取到的packet按pts重新排序再喂给pion。因为之前没有接触过多媒体播放,不太清楚这部分应该怎么去处理。另外,请问有交流方式吗,Q群或者其他
以下是我拿取到的pts和dts的数据

track:1,cid:1,pts:83 dts:0
track:1,cid:1,pts:250 dts:41
track:1,cid:1,pts:125 dts:83
track:1,cid:1,pts:166 dts:125
track:1,cid:1,pts:208 dts:166
track:1,cid:1,pts:416 dts:208
track:1,cid:1,pts:291 dts:250
track:1,cid:1,pts:333 dts:291
track:1,cid:1,pts:375 dts:333
track:1,cid:1,pts:583 dts:375
track:1,cid:1,pts:458 dts:416
track:1,cid:1,pts:500 dts:458
track:1,cid:1,pts:541 dts:500
track:1,cid:1,pts:750 dts:541
track:1,cid:1,pts:625 dts:583
track:1,cid:1,pts:666 dts:625
track:1,cid:1,pts:708 dts:666
track:1,cid:1,pts:916 dts:708
track:1,cid:1,pts:791 dts:750
track:1,cid:1,pts:833 dts:791
track:1,cid:1,pts:875 dts:833
track:1,cid:1,pts:1083 dts:875
track:1,cid:1,pts:958 dts:916
track:1,cid:1,pts:1000 dts:958
track:1,cid:1,pts:1041 dts:1000
track:1,cid:1,pts:1250 dts:1041
track:1,cid:1,pts:1125 dts:1083
track:1,cid:1,pts:1166 dts:1125
track:1,cid:1,pts:1208 dts:1166
track:1,cid:1,pts:1416 dts:1208
track:1,cid:1,pts:1291 dts:1250
track:1,cid:1,pts:1333 dts:1291
track:1,cid:1,pts:1375 dts:1333
track:1,cid:1,pts:1583 dts:1375
track:1,cid:1,pts:1458 dts:1416
track:1,cid:1,pts:1500 dts:1458
track:1,cid:1,pts:1541 dts:1500
track:1,cid:1,pts:1750 dts:1541
track:1,cid:1,pts:1625 dts:1583
track:1,cid:1,pts:1666 dts:1625
track:1,cid:1,pts:1708 dts:1666
track:1,cid:1,pts:1916 dts:1708
track:1,cid:1,pts:1791 dts:1750
track:1,cid:1,pts:1833 dts:1791
track:1,cid:1,pts:1875 dts:1833
track:1,cid:1,pts:2083 dts:1875
track:1,cid:1,pts:1958 dts:1916
track:1,cid:1,pts:2000 dts:1958
track:1,cid:1,pts:2041 dts:2000
track:1,cid:1,pts:2250 dts:2041
track:1,cid:1,pts:2125 dts:2083
track:1,cid:1,pts:2166 dts:2125
track:1,cid:1,pts:2208 dts:2166
track:1,cid:1,pts:2416 dts:2208
track:1,cid:1,pts:2291 dts:2250
track:1,cid:1,pts:2333 dts:2291
track:1,cid:1,pts:2375 dts:2333
track:1,cid:1,pts:2583 dts:2375
track:1,cid:1,pts:2458 dts:2416
track:1,cid:1,pts:2500 dts:2458
track:1,cid:1,pts:2541 dts:2500
track:1,cid:1,pts:2750 dts:2541
track:1,cid:1,pts:2625 dts:2583
track:1,cid:1,pts:2666 dts:2625
track:1,cid:1,pts:2708 dts:2666
track:1,cid:1,pts:2916 dts:2708
track:1,cid:1,pts:2791 dts:2750
track:1,cid:1,pts:2833 dts:2791
track:1,cid:1,pts:2875 dts:2833
track:1,cid:1,pts:3041 dts:2875
track:1,cid:1,pts:2958 dts:2916
track:1,cid:1,pts:3000 dts:2958
track:1,cid:1,pts:3125 dts:3000
track:1,cid:1,pts:3083 dts:3041
track:1,cid:1,pts:3166 dts:3083
track:1,cid:1,pts:3208 dts:3125
track:1,cid:1,pts:3250 dts:3166
track:1,cid:1,pts:3291 dts:3208
track:1,cid:1,pts:3333 dts:3250
track:1,cid:1,pts:3375 dts:3291
track:1,cid:1,pts:3416 dts:3333
track:1,cid:1,pts:3458 dts:3375
track:1,cid:1,pts:3500 dts:3416
track:1,cid:1,pts:3541 dts:3458
track:1,cid:1,pts:3583 dts:3500
track:1,cid:1,pts:3625 dts:3541
track:1,cid:1,pts:3666 dts:3583
track:1,cid:1,pts:3708 dts:3625
track:1,cid:1,pts:3750 dts:3666
track:1,cid:1,pts:3791 dts:3708
track:1,cid:1,pts:3833 dts:3750
track:1,cid:1,pts:3875 dts:3791
track:1,cid:1,pts:3916 dts:3833
track:1,cid:1,pts:3958 dts:3875
track:1,cid:1,pts:4000 dts:3916
track:1,cid:1,pts:4041 dts:3958
track:1,cid:1,pts:4083 dts:4000
track:1,cid:1,pts:4125 dts:4041
track:1,cid:1,pts:4166 dts:4083
track:1,cid:1,pts:4208 dts:4125
track:1,cid:1,pts:4250 dts:4166
track:1,cid:1,pts:4291 dts:4208
track:1,cid:1,pts:4333 dts:4250
track:1,cid:1,pts:4375 dts:4291

mov读取支持

mov与mp4的box封装格式几乎相同,但试图使用mp4.CreateMp4Demuxer打开mov文件时会返回mp4 Parser error

mov, _ := os.Open("test.mov")
defer mov.Close()
md := mp4.CreateMp4Demuxer(mov)
if infos, err := md.ReadHead(); err != nil && err != io.EOF {
	panic(err)
}

请问我遗漏了什么内容、或是当前的MovDemuxer暂不支持吗?
mov文件是使用ffmpeg -i test.mp4 -c copy test.mov将任意mp4文件转封装后得到的

panic: runtime error: slice bounds out of range [1:0]

  • 复现方法: go run main.go
    d3.zip
  • 完整堆栈信息:
panic: runtime error: slice bounds out of range [1:0]

goroutine 1 [running]:
github.com/yapingcat/gomedia/codec.GetPPSId({0xc0000aa036, 0xc0000a44e0, 0x0})
	/root/go/pkg/mod/github.com/yapingcat/[email protected]/codec/h264.go:227 +0x93
github.com/yapingcat/gomedia/codec.GetPPSIdWithStartCode({0xc0000aa036, 0xc000196000, 0x3fa})
	/root/go/pkg/mod/github.com/yapingcat/[email protected]/codec/h264.go:223 +0xd0
github.com/yapingcat/gomedia/mp4.(*Movmuxer).writeH264.func1({0xc0000b9c22, 0x600, 0x3de})
	/root/go/pkg/mod/github.com/yapingcat/[email protected]/mp4/mp4muxer.go:436 +0x7ad
github.com/yapingcat/gomedia/codec.SplitFrameWithStartCode({0xc0000b9c22, 0x8, 0x3de}, 0xc0001cf9a8)
	/root/go/pkg/mod/github.com/yapingcat/[email protected]/codec/util.go:58 +0x24f
github.com/yapingcat/gomedia/mp4.(*Movmuxer).writeH264(0x7f87e56d0e00, 0x7f87e56d0d00, {0xc0000b9c22, 0x4148ab, 0x7f87e56d0d00}, 0xc0001cfa40, 0x7f87e58bdfff)
	/root/go/pkg/mod/github.com/yapingcat/[email protected]/mp4/mp4muxer.go:415 +0xa5
github.com/yapingcat/gomedia/mp4.(*Movmuxer).Write(0xc00008e180, 0x0, {0xc0000b9c22, 0x8, 0x3de}, 0x64, 0xc000000340)
	/root/go/pkg/mod/github.com/yapingcat/[email protected]/mp4/mp4muxer.go:306 +0x145
main.main.func1.1({0xc0000b9c22, 0x8, 0x3de})
	/tmp/d3/d3/main.go:50 +0x90
github.com/yapingcat/gomedia/codec.SplitFrameWithStartCode({0xc0000b9c22, 0x8, 0x3de}, 0xc0001cfb38)
	/root/go/pkg/mod/github.com/yapingcat/[email protected]/codec/util.go:58 +0x24f
main.main.func1(0x7f880c1ef5b8, {0xc0000b9c22, 0x56bde0, 0xc00024f6b0}, 0x0, 0x10100c0000a4138)
	/tmp/d3/d3/main.go:45 +0x9b
github.com/yapingcat/gomedia/mpeg2.(*TSDemuxer).splitH26XFrame(0xc0001cfec0, 0xc0000b4000)
	/root/go/pkg/mod/github.com/yapingcat/[email protected]/mpeg2/ts-demuxer.go:209 +0x22f
github.com/yapingcat/gomedia/mpeg2.(*TSDemuxer).doVideoPesPacket(0x4e0f40, 0xc0000b4000, 0x40)
	/root/go/pkg/mod/github.com/yapingcat/[email protected]/mpeg2/ts-demuxer.go:167 +0x1a5
github.com/yapingcat/gomedia/mpeg2.(*TSDemuxer).Input(0xc0001cfec0, {0x4e0f00, 0xc00024f560})
	/root/go/pkg/mod/github.com/yapingcat/[email protected]/mpeg2/ts-demuxer.go:122 +0xa3e
main.main()
	/tmp/d3/d3/main.go:61 +0x376
exit status 2

音频用G711编码,Muxer到FMp4,怎么做

func (m *Muxer) audioMuxer(muxer *mp4.Movmuxer, buf []byte, audioCodec mp4.MP4_CODEC_TYPE, sampleRate int, channelCount int, sampleSize int) {
	atid := muxer.AddAudioTrack(audioCodec, mp4.WithAudioSampleRate(uint32(sampleRate)), mp4.WithAudioChannelCount(uint8(channelCount)))
	aInterval := uint64((sampleSize * 1000 / sampleRate))
	if audioCodec == mp4.MP4_CODEC_AAC {
		codec.SplitAACFrame(buf, func(bytes []byte) {
			m.apts += aInterval
			muxer.Write(atid, bytes, m.apts, m.apts)
		})
	if audioCodec == mp4.MP4_CODEC_G711A {
	}
	if audioCodec == mp4.MP4_CODEC_G711U {
	}
	muxer.WriteTrailer()
}

我看了例子和一些TEST,有针对AAC,没有针对G711的,也没有看到类似SplitAACFrame函数,请问大大,怎么处理

support mp4

  • mp4 (h264/h265/aac/g711x)
  • fmp4 (h264/h265/aac/g711x)

ts转mp4报OUT OF RANGE

该问题从commit:18af6a81eb5b0874aff81fbcd6f01a8b6a47543c开始引入

回退到commit:6a8b0915fd0d0fd1ef8fb7a9b7aab2e83a3b63f7 问题消失

ts转为mp4无法成功, 这段代码有什么问题呢 ?

package main

import (
	"fmt"
	"io/ioutil"
	"os"

	"github.com/yapingcat/gomedia/mpeg2"
	"github.com/yapingcat/gomedia/mp4"
	"strconv"
)

type mymp4writer struct {
	fp *os.File
}

func newmymp4writer(f *os.File) *mymp4writer {
	return &mymp4writer{
		fp: f,
	}
}

func (mp4w *mymp4writer) Write(p []byte) (n int, err error) {
	return mp4w.fp.Write(p)
}
func (mp4w *mymp4writer) Seek(offset int64, whence int) (int64, error) {
	return mp4w.fp.Seek(offset, whence)
}
func (mp4w *mymp4writer) Tell() (offset int64) {
	offset, _ = mp4w.fp.Seek(0, 1)
	return
}

func main() {
	tsfile := `/tmp/d/00002.ts`	// input
	mp4filename := "test3.mp4"	// output
	mp4file, err := os.OpenFile(mp4filename, os.O_CREATE|os.O_RDWR, 0666)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer mp4file.Close()

	muxer := mp4.CreateMp4Muxer(newmymp4writer(mp4file))
	vtid := muxer.AddVideoTrack(mp4.MP4_CODEC_H264)
	atid := muxer.AddAudioTrack(mp4.MP4_CODEC_AAC, 0, 16, 44100)

	buf, err := ioutil.ReadFile(tsfile)
	if err != nil {
		panic(err)
	}
	fmt.Printf("read %d size\n", len(buf))

	demuxer := mpeg2.NewTSDemuxer()
	demuxer.OnFrame = func(cid mpeg2.TS_STREAM_TYPE, frame []byte, pts uint64, dts uint64) {
		if cid == mpeg2.TS_STREAM_AAC {
			err = muxer.Write(atid, frame, uint64(pts), uint64(dts))
			if err != nil {
				panic(err)
			}
		} else if cid == mpeg2.TS_STREAM_H264 {
			err = muxer.Write(vtid, frame, uint64(pts), uint64(dts))
			if err != nil {
				panic(err)
			}
		} else {
			panic("unkwon cid " + strconv.Itoa(int(cid)))
		}
	}
	err = demuxer.Input(buf)
	if err != nil {
		panic(err)
	}
	demuxer.Flush()

	err = muxer.Writetrailer()
	if err != nil {
		panic(err)
	}
}

mp4 demuxer: decodeESDescriptor panics

gomedia/go-mp4/esds-box.go

Lines 111 to 134 in 6d6ac05

func decodeESDescriptor(esd []byte, track *mp4track) (vosData []byte) {
for len(esd) > 0 {
based := BaseDescriptor{}
based.Decode(esd)
switch based.tag {
case 0x03:
esd = esd[8:]
case 0x04:
track.cid = getCodecIdByObjectType(esd[5])
esd = esd[18:]
case 0x05:
vosData = esd[5 : 5+based.sizeOfInstance]
esd = esd[5+based.sizeOfInstance:]
case 0x06:
fallthrough
default:
esd = esd[5+based.sizeOfInstance:]
}
}
if track.cid == MP4_CODEC_AAC && len(vosData) == 0 {
panic("no vosdata")
}
return
}

this code panics with slice out of bound error. attaching demo content.

demo content url https://user-images.githubusercontent.com/25949138/216256532-2f2ab347-9562-474f-8e7e-937b48346983.mp4

package main

import (
	"bytes"
	"github.com/yapingcat/gomedia/go-mp4"
	"io"
	"net/http"
)

func main() {
	demoMp4 := "https://user-images.githubusercontent.com/25949138/216256532-2f2ab347-9562-474f-8e7e-937b48346983.mp4"
	resp, err := http.Get(demoMp4)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	body, _ := io.ReadAll(resp.Body)
	demuxer := mp4.CreateMp4Demuxer(bytes.NewReader(body))
	_, err = demuxer.ReadHead()
	if err != nil {
		panic(err)
	}
}

请求写一个 mux ts 包含audio video 的例子, 并缩小 audio mpeg-ts 的payload

我集合了
example_mux_ts
example_mux_ts_aac
写了一个, 不知道标准不标准

发现一个问题
ffmpeg mux 的时候会多个aac 包打一个时间戳
而gomedia是每个aac 打一个时间戳
ffmpeg 版本会缩小audio 的payload 从而缩小文件大小。
请问如何可以做到 ffmpeg 那样, 请给出一个代码例子

ffmpeg version
image


gomedia version
image

代码质量控制建议

  1. 编写测试代码, 提高逻辑代码的测试覆盖率
  2. 使用github action在每次推代码后,自动验证example里面的例子都能编译通过
  3. 建议尽量支持低版本的golang,提高兼容性。我发现go1.12版本无法编译通过,这个也能使用github action自动检查

Is RtmpServerHandle.OnFrame returns raw h264 frame?

Hello! I want to send frames from rtmp stream to webrtc connection. I get a byte representation of the h264 frame from an rtmp session (Rtmp Server Handle.On Frame) and write them to webrtc.TrackLocalStaticSample.

It works, but the image I get in the browser has 0.5 fps. However, if I open the rtmp stream in vlc, there are no such problems. Could you help me?

May be I must to demultiplexing frames from rtp?

https://github.com/kbats183/webrtc-proxy

ts合并为mp4,画面不动了

d4.zip

  • 我尝试吧两个相等的ts文件合并为一个mp4,合并成功后,在mac下的quicktime player上播放发现前半段可以播放,后半段就画面卡住不动了
  • ffmpeg未出现此问题。

mp4muxer_test的 tid := muxer.AddAudioTrack(MP4_CODEC_AAC, 2, 16, 44100)

mp4muxer_test.go:146:44: cannot use 2 (untyped int constant) as TrackOption value in argument to muxer.AddAudioTrack
mp4muxer_test.go:146:47: cannot use 16 (untyped int constant) as TrackOption value in argument to muxer.AddAudioTrack
mp4muxer_test.go:146:51: cannot use 44100 (untyped int constant) as TrackOption value in argument to muxer.AddAudioTrack
提示这些参数传递有问题,谁能帮忙指点怎么改

打包HLS Fmp4的时候音频没有打入到m4s文件中

image

  • 新建Muxer使用的是:
func append_h265_adts_header(sample_rate int, channels int, data []byte) []byte {
	adts_h := codec.NewAdtsFrameHeader()
	if sample_rate == 8000 {
		adts_h.Fix_Header.Sampling_frequency_index = uint8(codec.AAC_SAMPLE_8000)
	}
	if sample_rate == 16000 {
		adts_h.Fix_Header.Sampling_frequency_index = uint8(codec.AAC_SAMPLE_16000)
	}

	adts_h.Fix_Header.Channel_configuration = uint8(channels)
	adts_h.Fix_Header.Profile = uint8(codec.LC)
	adts_h.Fix_Header.Protection_absent = 1

	adts_h.Variable_Header.Frame_length = uint16(len(data) + 7)
	adts_h.Variable_Header.Number_of_raw_data_blocks_in_frame = 0

	b := append(adts_h.Encode(), data...)
	return b
}

mp4.CreateMp4Muxer(mp4file, mp4.WithMp4Flag(mp4.MP4_FLAG_FRAGMENT), mp4.WithMp4Flag(mp4.MP4_FLAG_FRAGMENT))
aid_mp4 := mp4_muxer.AddAudioTrack(mp4.MP4_CODEC_AAC)

mp4_muxer.Write(aid_mp4, append_h265_adts_header(sample_rate, channels, data), ts, ts)

合并ts为mp4,在播放器上播放,点击快进到某一个时间点,画面会卡住

  • 代码
package main

import (
	"bytes"
	"github.com/orestonce/goffmpeg"
	"github.com/yapingcat/gomedia/mp4"
	"github.com/yapingcat/gomedia/mpeg2"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
)

func main() {
	const dir = `D:\d`
	var nameList []string
	for idx := 0; idx < 20; idx++ {
		nameList = append(nameList, filepath.Join(dir, "output"+strconv.Itoa(idx)+".ts"))
	}
	fPath, err := goffmpeg.SetupFfmpeg()
	if err != nil {
		panic(err)
	}
	err = goffmpeg.MergeMultiToSingleMp4(goffmpeg.MergeMultiToSingleMp4_Req{
		FfmpegExePath: fPath,
		TsFileList:    nameList,
		OutputMp4:     filepath.Join(dir, "merge-ffmpeg.mp4"),
		ProgressCh:    nil,
	})
	if err != nil {
		panic(err)
	}
	err = MergeTsFileListToSingleMp4(MergeTsFileListToSingleMp4_Req{
		TsFileList: nameList,
		OutputMp4:  filepath.Join(dir, "merge-gomedia.mp4"),
	})
	if err != nil {
		panic(err)
	}
}

type mymp4writer struct {
	fp *os.File
}

func newmymp4writer(f *os.File) *mymp4writer {
	return &mymp4writer{
		fp: f,
	}
}

func (mp4w *mymp4writer) Write(p []byte) (n int, err error) {
	return mp4w.fp.Write(p)
}
func (mp4w *mymp4writer) Seek(offset int64, whence int) (int64, error) {
	return mp4w.fp.Seek(offset, whence)
}
func (mp4w *mymp4writer) Tell() (offset int64) {
	offset, _ = mp4w.fp.Seek(0, 1)
	return
}

type MergeTsFileListToSingleMp4_Req struct {
	TsFileList []string
	OutputMp4  string
}

func MergeTsFileListToSingleMp4(req MergeTsFileListToSingleMp4_Req) (err error) {
	mp4file, err := os.OpenFile(req.OutputMp4, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0666)
	if err != nil {
		return err
	}
	defer mp4file.Close()

	muxer := mp4.CreateMp4Muxer(newmymp4writer(mp4file))
	vtid := muxer.AddVideoTrack(mp4.MP4_CODEC_H264)
	atid := muxer.AddAudioTrack(mp4.MP4_CODEC_AAC, 0, 16, 44100)

	demuxer := mpeg2.NewTSDemuxer()
	demuxer.OnFrame = func(cid mpeg2.TS_STREAM_TYPE, frame []byte, pts uint64, dts uint64) {

		if cid == mpeg2.TS_STREAM_AAC {
			err = muxer.Write(atid, frame, uint64(pts), uint64(dts))
			if err != nil {
				panic(err)
			}
		} else if cid == mpeg2.TS_STREAM_H264 {
			err = muxer.Write(vtid, frame, uint64(pts), uint64(dts))
			if err != nil {
				panic(err)
			}
		} else {
			panic("unkwon cid " + strconv.Itoa(int(cid)))
		}
	}

	for _, tsFile := range req.TsFileList {
		var buf []byte
		buf, err = ioutil.ReadFile(tsFile)
		if err != nil {
			return err
		}
		err = demuxer.Input(bytes.NewReader(buf))
		if err != nil {
			return err
		}
	}

	err = muxer.WriteTrailer()
	if err != nil {
		return err
	}
	return err
}

支持rtp转rtmp?

目前采用example的代码,获取到rtph的264码流,然后推送到rtmp server,画面能出现,但是基本像假死了一样,半天画面没反应
推送代码用的是example/example_rtmp_publish_client.go

关于网络流录成flv

我现在rtsp拉出来一路视频,一路音频,如果我想把他们录成flv,这应该怎么操作呢?

从外部引入包, 编译失败

好奇怪一个问题, 从外面引入这个包, 包中代码和git main 分支不一致,导致编译不过
❯ go mod init aabbcc
go: creating new go.mod: module aabbcc
❯ cp -r ~/git/golang/gomedia/example/example_play_mp4_with_hls.go ./
❯ go mod tidy
go: finding module for package github.com/yapingcat/gomedia/mpeg2
go: finding module for package github.com/yapingcat/gomedia/mp4
go: found github.com/yapingcat/gomedia/mp4 in github.com/yapingcat/gomedia/mp4 v0.0.0-20220617074658-94762898dc25
go: found github.com/yapingcat/gomedia/mpeg2 in github.com/yapingcat/gomedia/mpeg2 v0.0.0-20220617074658-94762898dc25
❯ go build

aabbcc

./example_play_mp4_with_hls.go:65:51: undefined: mp4.SyncSample
./example_play_mp4_with_hls.go:121:17: info.EndDts undefined (type mp4.TrackInfo has no field or method EndDts)
./example_play_mp4_with_hls.go:124:24: demuxer.GetSyncTable undefined (type *mp4.MovDemuxer has no field or method GetSyncTable)
./example_play_mp4_with_hls.go:158:10: demuxer.SeekTime undefined (type *mp4.MovDemuxer has no field or method SeekTime)

RTMP chromakey

How can I apply chromakey to data coming from an RTMP packet and add another video to the transparent area?
Can you please help? I can't find any resources

for {
	// Rtmp stream read packet
	pkt, err := c.ReadPacket()
	switch pkt.Type {
		case av.H264:
			naluSize := binary.BigEndian.Uint32(pkt.Data[:4])
			img := pkt.Data[4+naluSize:]
			//????
			newImg := image.NewRGBA(img.Bounds())
			backgroundColor, _ := colorful.Hex("#72971E") // yeşil renk
			usingPix(img, *newImg, backgroundColor)
	}
}

To apply to the frame;

func usingPix(img image.Image, newImg image.RGBA, targetColor colorful.Color) {

	bounds := img.Bounds()
	width, height := bounds.Max.X, bounds.Max.Y

	rgba := image.NewRGBA(bounds)
	draw.Draw(rgba, bounds, img, bounds.Min, draw.Src)
	for y := 0; y < height; y++ {
		for x := 0; x < width; x++ {
			index := (y*width + x) * 4
			pix := rgba.Pix[index : index+4]
			clr := color.RGBA{pix[0], pix[1], pix[2], 255}
			clra,_ := colorful.MakeColor(clr)
			a := targetColor.DistanceCIE94(clra)
			
			if a < 0.11{
				newImg.Set(x, y, color.RGBA{0, 0, 0, 0})
			} else {
				newImg.Set(x, y, clr)
			}
		}
	}

}

hls flv 支持流形式转换?

例如 摄像头的ps流,转换为hls、flv格式的在网页上实时画面,目前发现的是example提供的是都是file的存在,如果是ps流这种是否支持流转换输出

通过websocket一帧一帧的传数据,我该如何封装

情况是这样的,服务端把直播流一帧一帧的推过来,我也需要通过gomedia封装成FMp4,然后封装成wasm,让web页面得到封装好的fmp4数据包,我用了下面两种方法

type WsFrame struct {
	codec     mp4.MP4_CODEC_TYPE
	timestamp uint64
	source    []byte  //加了一个16位的头
	raw       []byte  // 真正的帧数据
}
type Muxer struct {
	cache []byte
}
func (m *Muxer) bothMuxer1(muxer *mp4.Movmuxer, frame *WsFrame) {
	var tid uint32
	if frame.codec < mp4.MP4_CODEC_AAC {
		tid = muxer.AddVideoTrack(frame.codec)
		muxer.Write(tid, frame.raw, frame.timestamp, frame.timestamp)
		muxer.WriteTrailer()
		fmt.Printf("frame.timestamp %v\n", frame.timestamp)
	} else {
		//tid = muxer.AddAudioTrack(frame.codec, mp4.WithAudioSampleRate(frame.sampleRate), mp4.WithAudioChannelCount(frame.channelCount))
	}
}

func (m *Muxer) bothMuxer2(muxer *mp4.Movmuxer, frame *WsFrame) {
	var tid uint32
	if frame.codec < mp4.MP4_CODEC_AAC {
		tid = muxer.AddVideoTrack(frame.codec)
		var isVCLNaluType bool
		if frame.codec == mp4.MP4_CODEC_H264 {
			ntype := codec.H264NaluType(frame.raw)
			isVCLNaluType = codec.IsH264VCLNaluType(ntype)
		} else if frame.codec == mp4.MP4_CODEC_H265 {
			ntype := codec.H265NaluType(frame.raw)
			isVCLNaluType = codec.IsH265VCLNaluType(ntype)
		}
		if !isVCLNaluType {
			m.cache = append(m.cache, frame.raw...)
			return
		}
		if len(m.cache) > 0 {
			m.cache = append(m.cache, frame.raw...)
			muxer.Write(tid, m.cache, frame.timestamp, frame.timestamp)
			m.cache = m.cache[:0]
		} else {
			muxer.Write(tid, frame.raw, frame.timestamp, frame.timestamp)
		}
		muxer.WriteTrailer()
		fmt.Printf("frame.timestamp %v\n", frame.timestamp)
	} else {
		// tid = muxer.AddAudioTrack(frame.codec, mp4.WithAudioSampleRate(frame.sampleRate), mp4.WithAudioChannelCount(frame.channelCount))
		// muxer.Write(tid, frame.raw, frame.timestamp, frame.timestamp)
		// muxer.WriteTrailer()
	}
}

我暂时把bothMuxer1和bothMuxer2 中的音频部分去掉了,但是产生的fmap4数据包,我放到web的video表上播放,会出现解析错误(CHUNK_DEMUXER_ERROR_APPEND_FAILED: RunSegmentParserLoop: stream parsing failed. append_window_start=0 append_window_end=inf),但是之前我用多个帧生成的fmp4数据放在video就是可以正常播放,请问是什么原因,是不是我封装的方式还是有问题?

Support mpga audio codec in mpeg2.TSDemuxer

It would be amazing to have this feature, because vlc could generate http stream with audio not in aac codec.

For example, this sting capture webcamera and microfon on a linux vlc -q v4l2:///dev/video0:chroma=h264:width=1920:height=1080 :input-slave=alsa://hw:1,0 --sout '#transcode{venc=x264{keyint=2},acodec=mpga,vb=0}:standard{access=http,mux=ts,dst=:8080,name=stream,mime=video/ts}' or on windows vlc -q dshow:// :dshow-adev="{you audio device name}" --sout "#transcode{venc=x264{keyint=1},vcodec=h264,acodec=mpga,vb=0}:http{access=http,mux=ts,dst=:8080/,name=stream,mime=video/ts}".

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.