gomedia
mpeg-ts,mpeg-ps,flv muxer/demuxer
-
mpeg-ts muxer
-
mpeg-ts demuxer
-
mpeg-ps muxer
-
mpeg-ps demuxer
-
flv muxer
-
flv demuxer
mpeg-ps will be done in the next two weeks
mpeg-ts,mpeg-ps,flv muxer/demuxer
mpeg-ts muxer
mpeg-ts demuxer
mpeg-ps muxer
mpeg-ps demuxer
flv muxer
flv demuxer
mpeg-ps will be done in the next two weeks
progressive.mp4 is a mp4 file on local disk or nfs mount. hls player try to play this file with hls protocol.
example server will read mp4, generate m3u8 and stream it in mpeg-ts format. reference https://www.jianshu.com/p/5eb817ccdd1f
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)
}
}
好奇怪一个问题, 从外面引入这个包, 包中代码和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
./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)
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
用的你的例程。 ` 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的分享
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
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
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
}
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文件转封装后得到的
Hi,
this is another change I made in my fork.
It autodetects the channel count and sample rate for aac audio tracks when muxing mp4's, similar to how the video resolution is autodetected.
It adds a generic AddTrack
function without any options to the muxer. But I am not that happy with the name, it will likely break in the future if more arguments are needed.
Another option would be to use a function for each codec, something like this:
func (muxer *Movmuxer) AddH264Track() uint32
func (muxer *Movmuxer) AddH265Track() uint32
func (muxer *Movmuxer) AddAACTrack() uint32
// not sure if the G711 codecs could also support no arguments functions with auto detection
func (muxer *Movmuxer) AddG711ATrack(channelcount uint8, sampleBits uint8, sampleRate uint) uint32
func (muxer *Movmuxer) AddG711UTrack(channelcount uint8, sampleBits uint8, sampleRate uint) uint32
and use the more generic names for functions with all track options:
func (muxer *Movmuxer) AddVideoTrack(cid MP4_CODEC_TYPE, width uint32, height uint32) uint32
func (muxer *Movmuxer) AddAudioTrack(cid MP4_CODEC_TYPE, channelcount uint8, sampleBits uint8, sampleRate uint) uint32
Whereby I am not sure whether manually setting the width & height will ever be useful or needed 😄 But it more clearly differentiates the auto config functions from the expert/technical functions. Let me know what you prefer I can change the PR accordingly.
Hi again :D
this PR is similar to #8 but for the ts demuxer.
With this, instead of a byte slice the ts demuxer reads from an io.Reader
. This makes it possible to demux larger .ts files since they do not have to be loaded completely into memory.
It also makes the Flush
function private and automatically calls it at the end of Input
so users do not have to think about it.
Additionally, there was a nil dereference bug in Flush that was triggered when the ts file contained a pes private stream without any packets.
The last commit https://github.com/yapingcat/gomedia/commit/6dbd0a46d3c3c5f3e0477c655f648d4c3040852a tries to fix some decode errors that were silently ignored. For pes_pkg.Decode I had to add a special case in ts-demuxer, because you added an error when the remaining ts packet data is smaller than the expected pes packet data with commit 5fbdc43. For the ts demuxer the short read is the normal behavior, but I did not want to remove the error in case the Decode function is used somewhere else. Maybe the error is needed for the ps demuxer? (I did not test that).
lal是一个开源GoLang直播流媒体网络传输项目,包含三个主要组成部分: lalserver:流媒体转发服务器。类似于nginx-rtmp-module等应用,但支持更多的协议,提供更丰富的功能。lalserver简介 demo:一些小应用,比如推、拉流客户端,压测工具,流分析工具,调度示例程序等
Reisen A simple library to extract video and audio frames from media containers (based on libav, i.e. ffmpeg). Dependencies The library requires libav
lmmp3 lmmp3 is a function that download a video from youtube, and convert it to a mp3 file using ffmpeg You need to have installed ffmpeg in your syst
echedwnmp3 echedwnmp3 is a function that download a video from youtube, and convert it to a mp3 file using ffmpeg example package main import(echedwn
SlideXtract A tool to help extract slides from a video file. Slides are output in the out folder. Features I didn't find any other piece of code that
libgosubs Golang library to read and write subtitles in the following formats Advanced SubStation Alpha v4 SRT TTML v1.0 - This is based on the spec p
M3U8 This is the most complete opensource library for parsing and generating of M3U8 playlists used in HTTP Live Streaming (Apple HLS) for internet vi
RTSP 1.0 client and server library for the Go programming language
go4vl A Go library for working with the Video for Linux user API (V4L2). Gov4l hides all the complexities of working with V4L2 and exposes idiomatic G
go-m3u8 Golang package for m3u8 (ported m3u8 gem https://github.com/sethdeckard/m3u8) go-m3u8 provides easy generation and parsing of m3u8 playlists d
go-playlist ⚠️ WARNING The API is not stable yet and can change. Package playlist implement reading and writing popular playlist formats: PLS, ASX, M3
% FFCOMMANDER(1) ffcommander 2.39 % Mikael Hartzell (C) 2018 % 2021 Name ffcommander - An easy frontend to FFmpeg and Imagemagick to automatically pro
goav Golang binding for FFmpeg A comprehensive binding to the ffmpeg video/audio manipulation library. Usage import "github.com/giorgisio/goav/avforma
中文 Simple and efficient live broadcast server: Very simple to install and use; Pure Golang, high performance, and cross-platform; Supports commonly us
中文 Simple and efficient live broadcast server: Very simple to install and use; Pure Golang, high performance, and cross-platform; Supports commonly us
Requirements Debian-like system (ubuntu, mint, etc...) with apt package manager Golang >1.15 Command tool make (use sudo apt install make -y to instal
go-ffmpeg-core ffmpeg core for golang 基于ffmpeg命令封装简单功能,因此运行环境需事先安装有ffmpeg命令。 ffmpeg官方下载地址: http://ffmpeg.org/download.html 1. 剥离视频文件的音频/视频 package mai
?? MovieGo - Video Editing in Golang MovieGo is a Golang library for video editing. The library is designed for fast processing of routine tasks relat
Go bindings for libVLC 2.X/3.X/4.X and high-level media player interface. The package can be useful for adding multimedia capabilities to applications