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

Flv To mp4 #95

Open
hasnhasan opened this issue Aug 30, 2023 · 7 comments
Open

Flv To mp4 #95

hasnhasan opened this issue Aug 30, 2023 · 7 comments

Comments

@hasnhasan
Copy link

Hello,
The example in the file "example_covert_flv_to_mp4.go" creates and saves a new mp4 file.

I want to save it as a continuation of an existing mp4 file. Is this possible?

@yapingcat
Copy link
Owner

you should use fragment mp4.

please refer to this example flv to fmp4

@hasnhasan
Copy link
Author

I tried this way but without success.

I'm just trying to do this. If the test2_fmp4.mp4 file already exists (For example, there is a 1 minute video recording.) it should append to it and continue recording.

import (
	"encoding/binary"
	"fmt"
	"net"
	"os"
	"time"

	"github.com/notedit/rtmp/av"
	"github.com/notedit/rtmp/format/rtmp"
	"github.com/yapingcat/gomedia/go-codec"
	"github.com/yapingcat/gomedia/go-mp4"
)

func startRtmp() {

	lis, err := net.Listen("tcp", ":1935")
	if err != nil {
		panic(err)
	}

	s := rtmp.NewServer()

	s.LogEvent = func(c *rtmp.Conn, nc net.Conn, e int) {
		es := rtmp.EventString[e]
		fmt.Println(nc.LocalAddr(), nc.RemoteAddr(), es)
	}

	s.HandleConn = func(c *rtmp.Conn, nc net.Conn) {

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

			i := 0
			muxer, err := mp4.CreateMp4Muxer(mp4file, mp4.WithMp4Flag(mp4.MP4_FLAG_DASH))
			muxer.OnNewFragment(func(duration uint32, firstPts, firstDts uint64) {
				fmt.Println("on segment", duration)
				if i == 0 {
					initFile, _ := os.OpenFile("init.mp4", os.O_CREATE|os.O_RDWR, 0666)
					muxer.WriteInitSegment(initFile)
					initFile.Close()
				}
				i++
				muxer.ReBindWriter(mp4file)
			})

			if err != nil {
				fmt.Println(err)
				return
			}
			hasVideo := false
			hasAudio := false
			var vtid uint32
			var atid uint32
			defer muxer.WriteTrailer()
			var asc []byte
			for {
				nc.SetReadDeadline(time.Now().Add(time.Second))
				pkt, err := c.ReadPacket()
				if err != nil {
					fmt.Println(err)
					return
				}
				pts := pkt.CTime.Milliseconds() + pkt.Time.Milliseconds()
				dts := pkt.Time.Milliseconds()
				switch pkt.Type {
				case av.H264DecoderConfig:
					if !hasVideo {
						vtid = muxer.AddVideoTrack(mp4.MP4_CODEC_H264)
						hasVideo = true
					}
					tmpspss, tmpppss := codec.CovertExtradata(pkt.Data)
					//fmt.Println(len(tmpspss), len(tmpppss))
					pts := pkt.CTime + pkt.Time
					frame := make([]byte, 0, len(tmpspss[0])+len(tmpppss[0]))
					frame = append(frame, tmpspss[0]...)
					frame = append(frame, tmpppss[0]...)
					//codec.ShowPacketHexdump(tmpspss[0])
					//fmt.Println(codec.GetSPSIdWithStartCode(tmpspss[0]))
					muxer.Write(vtid, frame, uint64(pts), uint64(dts))
				case av.H264:
					for len(pkt.Data) > 0 {
						naluSize := binary.BigEndian.Uint32(pkt.Data[:4])
						//codec.ShowPacketHexdump(pkt.Data[:6])
						codec.CovertAVCCToAnnexB(pkt.Data)
						muxer.Write(vtid, pkt.Data[:4+naluSize], uint64(pts), uint64(dts))
						pkt.Data = pkt.Data[4+naluSize:]
					}
					//fmt.Println("h264 frame pts ", pts, "dts ", dts)
				case av.AACDecoderConfig:
					if !hasAudio {
						atid = muxer.AddAudioTrack(mp4.MP4_CODEC_AAC)
						hasAudio = true
					}

					asc = make([]byte, len(pkt.Data))
					copy(asc, pkt.Data)
				case av.AAC:
					adts, err := codec.ConvertASCToADTS(asc, len(pkt.Data)+7)
					if err != nil {
						return
					}
					//fmt.Println("aac frame pts ", pts, "dts ", dts)
					adts_frame := append(adts.Encode(), pkt.Data...)
					muxer.Write(atid, adts_frame, uint64(pts), uint64(dts))
				}
			}

		}
	}

	for {
		nc, err := lis.Accept()
		if err != nil {
			time.Sleep(time.Second)
			continue
		}
		go s.HandleNetConn(nc)
	}
}

func main() {

	startRtmp()
}

@yapingcat
Copy link
Owner

yapingcat commented Aug 31, 2023

#57 (comment)

please according to this issue.

  1. create fmp4 muxer with memeory io handler,fmp4 binary data will be stored into memory buffer
  2. save data into fmp4 file
  3. reset memeory io handler

@hasnhasan
Copy link
Author

The problem here is that I do not record the incoming broadcast continuously. I record it piece by piece. Sometimes during recording, the broadcast from RTMP is interrupted and comes again. When it comes, I try to make it continue from the file recorded until that section.

@yapingcat
Copy link
Owner

yapingcat commented Sep 1, 2023

The problem here is that I do not record the incoming broadcast continuously. I record it piece by piece. Sometimes during recording, the broadcast from RTMP is interrupted and comes again. When it comes, I try to make it continue from the file recorded until that section.

fmp4 satisfy your Scenario . you can append media data to the end of the fmp4 file,just like flv file

@cedricve
Copy link

cedricve commented Dec 5, 2023

I have the same "request". Currently when making very long recordings, as shown by @hasnhasan above, it will load all bytes into memory and then write at once. This might create OOM for very long recordings. I have seen implementations dumping the content directly in a file, and creating the appropriate headers at start, and trailer at end.

Not sure if fragmented mp4 is a good solution, as these will create an init and individual segment files, where as for some usecases you would like to have one large mp4 containing all data. Not sure if this is possible with the current implementation.

@cedricve
Copy link

cedricve commented Dec 5, 2023

Nevermind I just fixed my "usecase" by passing in a file writer, so nothing in memory is stored, but dumped directly to filesystem. @hasnhasan I believe this would fix your issue as well.

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

3 participants