uplink/app/media/demuxer.go

140 lines
2.9 KiB
Go
Raw Normal View History

2018-04-10 11:48:51 +00:00
package media
import (
"io"
"log"
2018-04-10 14:34:30 +00:00
"git.icedream.tech/icedream/uplink/app/pubsub"
2018-04-10 11:48:51 +00:00
"github.com/3d0c/gmf"
)
type Demuxer struct {
2018-04-11 12:33:38 +00:00
streams chan *MediaStream
err chan error
containerInfo *MediaStreamContainerInfo
}
func (demuxer *Demuxer) ContainerInfo() *MediaStreamContainerInfo {
return demuxer.containerInfo
2018-04-10 11:48:51 +00:00
}
func (demuxer *Demuxer) Error() <-chan error {
return demuxer.err
}
2018-04-11 12:33:38 +00:00
func (demuxer *Demuxer) Streams() <-chan *MediaStream {
2018-04-10 11:48:51 +00:00
return demuxer.streams
}
func Demux(r io.ReadCloser) (demuxer *Demuxer) {
buffer := make([]byte, 8*1024)
demuxer = &Demuxer{
err: make(chan error),
2018-04-11 12:33:38 +00:00
streams: make(chan *MediaStream),
2018-04-10 11:48:51 +00:00
}
go func() {
var err error
defer func() {
if err != nil {
select {
case demuxer.err <- err:
default:
}
}
}()
ctx := gmf.NewCtx()
defer ctx.CloseInputAndRelease()
avioCtx, err := gmf.NewAVIOContext(ctx, &gmf.AVIOHandlers{
ReadPacket: func() ([]byte, int) {
n, err := r.Read(buffer)
//log.Println("DemuxStream: AVIOHandlers.ReadPacket:", n, err)
if err != nil {
n = -1
}
return buffer, n
},
})
if err != nil {
return
}
defer avioCtx.Release()
ctx.SetPb(avioCtx)
2018-04-10 14:03:39 +00:00
ctx.SetFlag(0x0080) // AVFMT_FLAG_CUSTOM_IO
2018-04-10 11:48:51 +00:00
ctx.OpenInput("")
// fmt.Println("=== FFMPEG DUMP OF INPUT ===")
// ctx.Dump()
// fmt.Println("============================")
2018-04-11 12:33:38 +00:00
demuxer.containerInfo = &MediaStreamContainerInfo{
GlobalHeader: ctx.IsGlobalHeader(),
StartTime: ctx.StartTime(),
//SDP: ctx.GetSDPString(),
}
2018-04-10 11:48:51 +00:00
// Find out order of streams and store info about them
streams := []*gmf.Stream{}
pubsubs := []*pubsub.PubSubWriter{}
pubsubMap := map[int]io.WriteCloser{}
for i := 0; i < ctx.StreamsCnt(); i++ {
stream, err := ctx.GetStream(i)
if err != nil {
panic(err)
}
streamCodec := stream.CodecCtx()
streams = append(streams, stream)
2018-04-11 12:33:38 +00:00
switch streamCodec.Type() {
case gmf.AVMEDIA_TYPE_AUDIO, gmf.AVMEDIA_TYPE_VIDEO:
2018-04-10 11:48:51 +00:00
ps := pubsub.NewPubSubWriter()
2018-04-11 12:33:38 +00:00
dmxStream := &MediaStream{
MediaStreamInfo: MediaStreamInfo{
CodecInfo: MediaStreamCodecInfo{
CodecName: streamCodec.Codec().Name(),
},
Pts: stream.Pts,
StreamId: i,
2018-04-10 11:48:51 +00:00
},
2018-04-11 15:55:15 +00:00
PubSubWriter: ps,
2018-04-10 11:48:51 +00:00
}
defer ps.Close()
2018-04-11 12:33:38 +00:00
switch streamCodec.Type() {
case gmf.AVMEDIA_TYPE_VIDEO:
2018-04-10 11:48:51 +00:00
dmxStream.CodecInfo.Type = Video
2018-04-11 12:33:38 +00:00
case gmf.AVMEDIA_TYPE_AUDIO:
2018-04-10 11:48:51 +00:00
dmxStream.CodecInfo.Type = Audio
}
pubsubMap[i] = ps
pubsubs = append(pubsubs, ps)
demuxer.streams <- dmxStream
}
}
demuxer.err <- nil
packetsChan := ctx.GetNewPackets()
for packet := range packetsChan {
writer, shouldCapture := pubsubMap[packet.StreamIndex()]
if !shouldCapture {
packet.Release()
continue
}
data := packet.Data()
packet.Release()
if _, err := writer.Write(data); err != nil {
log.Println("demuxer stream-out error:", err)
return
}
}
}()
return
}