Compare commits

..

19 Commits

Author SHA1 Message Date
Icedream 3bad711693
Update .gitignore. 2018-07-09 12:37:00 +02:00
Icedream f5a86e9282
Remove debug lines. 2018-07-09 12:36:54 +02:00
Icedream 4dc3a544f7
Use properly joined file paths. 2018-07-09 12:35:18 +02:00
Icedream f9c5b5e0c6
Regenerate gen_formats.go. 2018-07-09 12:23:29 +02:00
Icedream 426c26c613
Update format list generator to support aliases. 2018-07-09 12:23:15 +02:00
Icedream 4187d0dfda
Update tests to tolerate mp3/mp3float. 2018-07-09 12:19:08 +02:00
Icedream a4e70df617
Update gmf submodule. 2018-07-09 12:18:54 +02:00
Icedream 994c0995e0
Move test assets into own subfolder. 2018-07-09 12:05:35 +02:00
Icedream a99fa94072
Reenable Icecast input plugin in main app. 2018-07-09 12:05:35 +02:00
Icedream 331286f9d0
Implement metadata parsing on Icecast input. 2018-07-09 12:05:35 +02:00
Icedream c0774e8ba6
Make the Icecast input plugin link properly again. 2018-07-09 12:05:31 +02:00
Icedream 0d8ecc64ad
Send the last metadata info to new listeners. 2018-07-03 08:18:45 +02:00
Icedream 6481884b73
Add logger and recovery middlewares. 2018-07-03 08:17:58 +02:00
Icedream f8dce5ce9d
Send additional headers to signal Icy meta capability. 2018-07-02 08:30:40 +02:00
Icedream 7f13d014b9
Fix crash after connection closure. 2018-07-02 08:30:11 +02:00
Icedream 78f280e743
Fix short write in metadata injector. 2018-07-02 08:09:47 +02:00
Icedream 69147a81b3
Add API interface code. 2018-04-13 09:48:12 +02:00
Icedream ae6b69d40d
Save descriptor along with plugin instance. 2018-04-13 09:47:40 +02:00
Icedream 50e7125bce
Get rid of extra code. 2018-04-12 08:01:59 +02:00
25 changed files with 2475 additions and 79 deletions

3
.gitignore vendored
View File

@ -22,8 +22,11 @@ _testmain.go
# built binaries
uplink
*.exe
*.dll
*.test
*.orig
###############################################################################
# Windows image file caches

View File

@ -17,6 +17,8 @@ type Channel struct {
OutputStreams map[string]*media.MediaStream
Events *pubsub.PubSub
lastMetadata map[string]string
}
func (channel *Channel) AddInputStream(id string) *media.MediaStream {
@ -50,12 +52,17 @@ func (channel *Channel) AddOutputContainer(id string) *media.MediaStreamContaine
}
func (channel *Channel) SetMetadata(data map[string]string) {
channel.lastMetadata = data
channel.Events.Pub(data, "metadata")
}
func (channel *Channel) Metadata() chan map[string]string {
outC := make(chan map[string]string)
go func() {
defer close(outC)
if channel.lastMetadata != nil {
outC <- channel.lastMetadata
}
c := channel.Events.Sub("metadata")
forloop:
for event := range c {

View File

@ -0,0 +1,6 @@
package genericapi
type DynamicallyConfigurable interface {
MakeConfigurationObject() interface{}
ValidateConfiguration(config interface{}) bool
}

View File

@ -0,0 +1,3 @@
package codecs
//go:generate go run ./internal/generator/main.go

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,83 @@
package main
import (
"bufio"
"bytes"
"fmt"
"go/format"
"log"
"os"
"os/exec"
"strings"
)
func must(err error) {
if err == nil {
return
}
log.Fatal(err)
}
func main() {
cmd := exec.Command("ffmpeg", "-codecs")
outputBytes, err := cmd.Output()
must(err)
code := `package codecs
var (
`
bufreader := bufio.NewScanner(bytes.NewReader(outputBytes))
/*Encoders:
V..... = Video
A..... = Audio
S..... = Subtitle
.F.... = Frame-level multithreading
..S... = Slice-level multithreading
...X.. = Codec is experimental
....B. = Supports draw_horiz_band
.....D = Supports direct rendering method 1
------
V..... a64multi Multicolor charset for Commodore 64 (codec a64_multi)
V..... a64multi5 Multicolor charset for Commodore 64, extended with 5th color (colram) (codec a64_multi5)*/
waitingForList := true
for bufreader.Scan() && waitingForList {
text := bufreader.Text()
if text == " -------" {
waitingForList = false
}
}
for bufreader.Scan() {
text := bufreader.Text()
//isVideo := text[1] == 'V'
//isAudio := text[1] == 'A'
//isSubtitle := text[1] == 'S'
text = text[8:]
cols := strings.Fields(text)
id := cols[0]
name := strings.Join(cols[1:], " ")
code += fmt.Sprintf(`
// %s
Codec_%s = %q
`, name, strings.ToUpper(id), id)
}
code += `
)
`
codeBytes, err := format.Source([]byte(code))
must(err)
f, err := os.Create("gen_codecs.go")
must(err)
defer f.Close()
_, err = f.Write(codeBytes)
must(err)
}

View File

@ -0,0 +1,17 @@
package demux
import (
"io"
"git.icedream.tech/icedream/uplink/app/media"
)
type Demuxer interface {
NewInstance(r io.Reader) <-DemuxerInstance
}
type DemuxerInstance interface {
Error() error
Reader() io.Reader
ContainerInfo() *media.MediaStreamContainerInfo
}

View File

@ -4,6 +4,7 @@ import (
"io"
"io/ioutil"
"os"
"path/filepath"
"sync"
"testing"
@ -13,7 +14,7 @@ import (
func Test_Demux(t *testing.T) {
Convey("Demuxer", t, func() {
Convey("audio-only", func() {
reader, _ := os.Open("mpthreetest.mp3")
reader, _ := os.Open(filepath.Join("testassets", "mpthreetest.mp3"))
defer reader.Close()
demuxer := Demux(reader)
@ -28,7 +29,7 @@ func Test_Demux(t *testing.T) {
So(audioStream, ShouldBeNil)
So(stream.StreamId, ShouldEqual, 0)
So(stream.Pts, ShouldEqual, 0)
So(stream.CodecInfo.CodecName, ShouldEqual, "mp3")
So(stream.CodecInfo.CodecName, ShouldBeIn, []string{"mp3", "mp3float"})
So(stream.CodecInfo.Type, ShouldEqual, Audio)
audioStream = stream
}
@ -43,7 +44,7 @@ func Test_Demux(t *testing.T) {
})
Convey("video and audio", func() {
reader, _ := os.Open("small.ogv")
reader, _ := os.Open(filepath.Join("testassets", "small.ogv"))
defer reader.Close()
demuxer := Demux(reader)

View File

@ -0,0 +1,3 @@
package formats
//go:generate go run ./internal/generator/main.go

View File

@ -0,0 +1,839 @@
package formats
var (
// 3GP (3GPP file format)
Format_3GP = "3gp"
// 3GP (3GPP file format)
Mux_Format_3GP = Format_3GP
// a64 - video for Commodore 64
Format_A64 = "a64"
// a64 - video for Commodore 64
Mux_Format_A64 = Format_A64
// raw AC-3
Format_AC3 = "ac3"
// raw AC-3
Mux_Format_AC3 = Format_AC3
// ADTS AAC (Advanced Audio Coding)
Format_ADTS = "adts"
// ADTS AAC (Advanced Audio Coding)
Mux_Format_ADTS = Format_ADTS
// CRI ADX
Format_ADX = "adx"
// CRI ADX
Mux_Format_ADX = Format_ADX
// Audio IFF
Format_AIFF = "aiff"
// Audio IFF
Mux_Format_AIFF = Format_AIFF
// PCM A-law
Format_ALAW = "alaw"
// PCM A-law
Mux_Format_ALAW = Format_ALAW
// ALSA audio output
Format_ALSA = "alsa"
// ALSA audio output
Mux_Format_ALSA = Format_ALSA
// 3GPP AMR
Format_AMR = "amr"
// 3GPP AMR
Mux_Format_AMR = Format_AMR
// Animated Portable Network Graphics
Format_APNG = "apng"
// Animated Portable Network Graphics
Mux_Format_APNG = Format_APNG
// raw aptX (Audio Processing Technology for Bluetooth)
Format_APTX = "aptx"
// raw aptX (Audio Processing Technology for Bluetooth)
Mux_Format_APTX = Format_APTX
// raw aptX HD (Audio Processing Technology for Bluetooth)
Format_APTX_HD = "aptx_hd"
// raw aptX HD (Audio Processing Technology for Bluetooth)
Mux_Format_APTX_HD = Format_APTX_HD
// ASF (Advanced / Active Streaming Format)
Format_ASF = "asf"
// ASF (Advanced / Active Streaming Format)
Mux_Format_ASF = Format_ASF
// ASF (Advanced / Active Streaming Format)
Format_ASF_STREAM = "asf_stream"
// ASF (Advanced / Active Streaming Format)
Mux_Format_ASF_STREAM = Format_ASF_STREAM
// SSA (SubStation Alpha) subtitle
Format_ASS = "ass"
// SSA (SubStation Alpha) subtitle
Mux_Format_ASS = Format_ASS
// AST (Audio Stream)
Format_AST = "ast"
// AST (Audio Stream)
Mux_Format_AST = Format_AST
// Sun AU
Format_AU = "au"
// Sun AU
Mux_Format_AU = Format_AU
// AVI (Audio Video Interleaved)
Format_AVI = "avi"
// AVI (Audio Video Interleaved)
Mux_Format_AVI = Format_AVI
// SWF (ShockWave Flash) (AVM2)
Format_AVM2 = "avm2"
// SWF (ShockWave Flash) (AVM2)
Mux_Format_AVM2 = Format_AVM2
// G.729 BIT file format
Format_BIT = "bit"
// G.729 BIT file format
Mux_Format_BIT = Format_BIT
// Apple CAF (Core Audio Format)
Format_CAF = "caf"
// Apple CAF (Core Audio Format)
Mux_Format_CAF = Format_CAF
// raw Chinese AVS (Audio Video Standard) video
Format_CAVSVIDEO = "cavsvideo"
// raw Chinese AVS (Audio Video Standard) video
Mux_Format_CAVSVIDEO = Format_CAVSVIDEO
// codec2 .c2 muxer
Format_CODEC2 = "codec2"
// codec2 .c2 muxer
Mux_Format_CODEC2 = Format_CODEC2
// raw codec2 muxer
Format_CODEC2RAW = "codec2raw"
// raw codec2 muxer
Mux_Format_CODEC2RAW = Format_CODEC2RAW
// CRC testing
Format_CRC = "crc"
// CRC testing
Mux_Format_CRC = Format_CRC
// DASH Muxer
Format_DASH = "dash"
// DASH Muxer
Mux_Format_DASH = Format_DASH
// raw data
Format_DATA = "data"
// raw data
Mux_Format_DATA = Format_DATA
// D-Cinema audio
Format_DAUD = "daud"
// D-Cinema audio
Mux_Format_DAUD = Format_DAUD
// raw Dirac
Format_DIRAC = "dirac"
// raw Dirac
Mux_Format_DIRAC = Format_DIRAC
// raw DNxHD (SMPTE VC-3)
Format_DNXHD = "dnxhd"
// raw DNxHD (SMPTE VC-3)
Mux_Format_DNXHD = Format_DNXHD
// raw DTS
Format_DTS = "dts"
// raw DTS
Mux_Format_DTS = Format_DTS
// DV (Digital Video)
Format_DV = "dv"
// DV (Digital Video)
Mux_Format_DV = Format_DV
// MPEG-2 PS (DVD VOB)
Format_DVD = "dvd"
// MPEG-2 PS (DVD VOB)
Mux_Format_DVD = Format_DVD
// raw E-AC-3
Format_EAC3 = "eac3"
// raw E-AC-3
Mux_Format_EAC3 = Format_EAC3
// PCM 32-bit floating-point big-endian
Format_F32BE = "f32be"
// PCM 32-bit floating-point big-endian
Mux_Format_F32BE = Format_F32BE
// PCM 32-bit floating-point little-endian
Format_F32LE = "f32le"
// PCM 32-bit floating-point little-endian
Mux_Format_F32LE = Format_F32LE
// F4V Adobe Flash Video
Format_F4V = "f4v"
// F4V Adobe Flash Video
Mux_Format_F4V = Format_F4V
// PCM 64-bit floating-point big-endian
Format_F64BE = "f64be"
// PCM 64-bit floating-point big-endian
Mux_Format_F64BE = Format_F64BE
// PCM 64-bit floating-point little-endian
Format_F64LE = "f64le"
// PCM 64-bit floating-point little-endian
Mux_Format_F64LE = Format_F64LE
// Linux framebuffer
Format_FBDEV = "fbdev"
// Linux framebuffer
Mux_Format_FBDEV = Format_FBDEV
// FFmpeg metadata in text
Format_FFMETADATA = "ffmetadata"
// FFmpeg metadata in text
Mux_Format_FFMETADATA = Format_FFMETADATA
// FIFO queue pseudo-muxer
Format_FIFO = "fifo"
// FIFO queue pseudo-muxer
Mux_Format_FIFO = Format_FIFO
// Fifo test muxer
Format_FIFO_TEST = "fifo_test"
// Fifo test muxer
Mux_Format_FIFO_TEST = Format_FIFO_TEST
// Sega FILM / CPK
Format_FILM_CPK = "film_cpk"
// Sega FILM / CPK
Mux_Format_FILM_CPK = Format_FILM_CPK
// Adobe Filmstrip
Format_FILMSTRIP = "filmstrip"
// Adobe Filmstrip
Mux_Format_FILMSTRIP = Format_FILMSTRIP
// Flexible Image Transport System
Format_FITS = "fits"
// Flexible Image Transport System
Mux_Format_FITS = Format_FITS
// raw FLAC
Format_FLAC = "flac"
// raw FLAC
Mux_Format_FLAC = Format_FLAC
// FLV (Flash Video)
Format_FLV = "flv"
// FLV (Flash Video)
Mux_Format_FLV = Format_FLV
// framecrc testing
Format_FRAMECRC = "framecrc"
// framecrc testing
Mux_Format_FRAMECRC = Format_FRAMECRC
// Per-frame hash testing
Format_FRAMEHASH = "framehash"
// Per-frame hash testing
Mux_Format_FRAMEHASH = Format_FRAMEHASH
// Per-frame MD5 testing
Format_FRAMEMD5 = "framemd5"
// Per-frame MD5 testing
Mux_Format_FRAMEMD5 = Format_FRAMEMD5
// raw G.722
Format_G722 = "g722"
// raw G.722
Mux_Format_G722 = Format_G722
// raw G.723.1
Format_G723_1 = "g723_1"
// raw G.723.1
Mux_Format_G723_1 = Format_G723_1
// raw big-endian G.726 ("left-justified")
Format_G726 = "g726"
// raw big-endian G.726 ("left-justified")
Mux_Format_G726 = Format_G726
// raw little-endian G.726 ("right-justified")
Format_G726LE = "g726le"
// raw little-endian G.726 ("right-justified")
Mux_Format_G726LE = Format_G726LE
// GIF Animation
Format_GIF = "gif"
// GIF Animation
Mux_Format_GIF = Format_GIF
// raw GSM
Format_GSM = "gsm"
// raw GSM
Mux_Format_GSM = Format_GSM
// GXF (General eXchange Format)
Format_GXF = "gxf"
// GXF (General eXchange Format)
Mux_Format_GXF = Format_GXF
// raw H.261
Format_H261 = "h261"
// raw H.261
Mux_Format_H261 = Format_H261
// raw H.263
Format_H263 = "h263"
// raw H.263
Mux_Format_H263 = Format_H263
// raw H.264 video
Format_H264 = "h264"
// raw H.264 video
Mux_Format_H264 = Format_H264
// Hash testing
Format_HASH = "hash"
// Hash testing
Mux_Format_HASH = Format_HASH
// HDS Muxer
Format_HDS = "hds"
// HDS Muxer
Mux_Format_HDS = Format_HDS
// raw HEVC video
Format_HEVC = "hevc"
// raw HEVC video
Mux_Format_HEVC = Format_HEVC
// Apple HTTP Live Streaming
Format_HLS = "hls"
// Apple HTTP Live Streaming
Mux_Format_HLS = Format_HLS
// Microsoft Windows ICO
Format_ICO = "ico"
// Microsoft Windows ICO
Mux_Format_ICO = Format_ICO
// iLBC storage
Format_ILBC = "ilbc"
// iLBC storage
Mux_Format_ILBC = Format_ILBC
// image2 sequence
Format_IMAGE2 = "image2"
// image2 sequence
Mux_Format_IMAGE2 = Format_IMAGE2
// piped image2 sequence
Format_IMAGE2PIPE = "image2pipe"
// piped image2 sequence
Mux_Format_IMAGE2PIPE = Format_IMAGE2PIPE
// iPod H.264 MP4 (MPEG-4 Part 14)
Format_IPOD = "ipod"
// iPod H.264 MP4 (MPEG-4 Part 14)
Mux_Format_IPOD = Format_IPOD
// Berkeley/IRCAM/CARL Sound Format
Format_IRCAM = "ircam"
// Berkeley/IRCAM/CARL Sound Format
Mux_Format_IRCAM = Format_IRCAM
// ISMV/ISMA (Smooth Streaming)
Format_ISMV = "ismv"
// ISMV/ISMA (Smooth Streaming)
Mux_Format_ISMV = Format_ISMV
// On2 IVF
Format_IVF = "ivf"
// On2 IVF
Mux_Format_IVF = Format_IVF
// JACOsub subtitle format
Format_JACOSUB = "jacosub"
// JACOsub subtitle format
Mux_Format_JACOSUB = Format_JACOSUB
// LOAS/LATM
Format_LATM = "latm"
// LOAS/LATM
Mux_Format_LATM = Format_LATM
// LRC lyrics
Format_LRC = "lrc"
// LRC lyrics
Mux_Format_LRC = Format_LRC
// raw MPEG-4 video
Format_M4V = "m4v"
// raw MPEG-4 video
Mux_Format_M4V = Format_M4V
// Matroska
Format_MATROSKA = "matroska"
// Matroska
Mux_Format_MATROSKA = Format_MATROSKA
// MD5 testing
Format_MD5 = "md5"
// MD5 testing
Mux_Format_MD5 = Format_MD5
// MicroDVD subtitle format
Format_MICRODVD = "microdvd"
// MicroDVD subtitle format
Mux_Format_MICRODVD = Format_MICRODVD
// raw MJPEG video
Format_MJPEG = "mjpeg"
// raw MJPEG video
Mux_Format_MJPEG = Format_MJPEG
// extract pts as timecode v2 format, as defined by mkvtoolnix
Format_MKVTIMESTAMP_V2 = "mkvtimestamp_v2"
// extract pts as timecode v2 format, as defined by mkvtoolnix
Mux_Format_MKVTIMESTAMP_V2 = Format_MKVTIMESTAMP_V2
// raw MLP
Format_MLP = "mlp"
// raw MLP
Mux_Format_MLP = Format_MLP
// Yamaha SMAF
Format_MMF = "mmf"
// Yamaha SMAF
Mux_Format_MMF = Format_MMF
// QuickTime / MOV
Format_MOV = "mov"
// QuickTime / MOV
Mux_Format_MOV = Format_MOV
// MP2 (MPEG audio layer 2)
Format_MP2 = "mp2"
// MP2 (MPEG audio layer 2)
Mux_Format_MP2 = Format_MP2
// MP3 (MPEG audio layer 3)
Format_MP3 = "mp3"
// MP3 (MPEG audio layer 3)
Mux_Format_MP3 = Format_MP3
// MP4 (MPEG-4 Part 14)
Format_MP4 = "mp4"
// MP4 (MPEG-4 Part 14)
Mux_Format_MP4 = Format_MP4
// MPEG-1 Systems / MPEG program stream
Format_MPEG = "mpeg"
// MPEG-1 Systems / MPEG program stream
Mux_Format_MPEG = Format_MPEG
// raw MPEG-1 video
Format_MPEG1VIDEO = "mpeg1video"
// raw MPEG-1 video
Mux_Format_MPEG1VIDEO = Format_MPEG1VIDEO
// raw MPEG-2 video
Format_MPEG2VIDEO = "mpeg2video"
// raw MPEG-2 video
Mux_Format_MPEG2VIDEO = Format_MPEG2VIDEO
// MPEG-TS (MPEG-2 Transport Stream)
Format_MPEGTS = "mpegts"
// MPEG-TS (MPEG-2 Transport Stream)
Mux_Format_MPEGTS = Format_MPEGTS
// MIME multipart JPEG
Format_MPJPEG = "mpjpeg"
// MIME multipart JPEG
Mux_Format_MPJPEG = Format_MPJPEG
// PCM mu-law
Format_MULAW = "mulaw"
// PCM mu-law
Mux_Format_MULAW = Format_MULAW
// MXF (Material eXchange Format)
Format_MXF = "mxf"
// MXF (Material eXchange Format)
Mux_Format_MXF = Format_MXF
// MXF (Material eXchange Format) D-10 Mapping
Format_MXF_D10 = "mxf_d10"
// MXF (Material eXchange Format) D-10 Mapping
Mux_Format_MXF_D10 = Format_MXF_D10
// MXF (Material eXchange Format) Operational Pattern Atom
Format_MXF_OPATOM = "mxf_opatom"
// MXF (Material eXchange Format) Operational Pattern Atom
Mux_Format_MXF_OPATOM = Format_MXF_OPATOM
// raw null video
Format_NULL = "null"
// raw null video
Mux_Format_NULL = Format_NULL
// NUT
Format_NUT = "nut"
// NUT
Mux_Format_NUT = Format_NUT
// Ogg Audio
Format_OGA = "oga"
// Ogg Audio
Mux_Format_OGA = Format_OGA
// Ogg
Format_OGG = "ogg"
// Ogg
Mux_Format_OGG = Format_OGG
// Ogg Video
Format_OGV = "ogv"
// Ogg Video
Mux_Format_OGV = Format_OGV
// Sony OpenMG audio
Format_OMA = "oma"
// Sony OpenMG audio
Mux_Format_OMA = Format_OMA
// Ogg Opus
Format_OPUS = "opus"
// Ogg Opus
Mux_Format_OPUS = Format_OPUS
// OSS (Open Sound System) playback
Format_OSS = "oss"
// OSS (Open Sound System) playback
Mux_Format_OSS = Format_OSS
// PSP MP4 (MPEG-4 Part 14)
Format_PSP = "psp"
// PSP MP4 (MPEG-4 Part 14)
Mux_Format_PSP = Format_PSP
// Pulse audio output
Format_PULSE = "pulse"
// Pulse audio output
Mux_Format_PULSE = Format_PULSE
// raw video
Format_RAWVIDEO = "rawvideo"
// raw video
Mux_Format_RAWVIDEO = Format_RAWVIDEO
// RealMedia
Format_RM = "rm"
// RealMedia
Mux_Format_RM = Format_RM
// raw id RoQ
Format_ROQ = "roq"
// raw id RoQ
Mux_Format_ROQ = Format_ROQ
// Lego Mindstorms RSO
Format_RSO = "rso"
// Lego Mindstorms RSO
Mux_Format_RSO = Format_RSO
// RTP output
Format_RTP = "rtp"
// RTP output
Mux_Format_RTP = Format_RTP
// RTP/mpegts output format
Format_RTP_MPEGTS = "rtp_mpegts"
// RTP/mpegts output format
Mux_Format_RTP_MPEGTS = Format_RTP_MPEGTS
// RTSP output
Format_RTSP = "rtsp"
// RTSP output
Mux_Format_RTSP = Format_RTSP
// PCM signed 16-bit big-endian
Format_S16BE = "s16be"
// PCM signed 16-bit big-endian
Mux_Format_S16BE = Format_S16BE
// PCM signed 16-bit little-endian
Format_S16LE = "s16le"
// PCM signed 16-bit little-endian
Mux_Format_S16LE = Format_S16LE
// PCM signed 24-bit big-endian
Format_S24BE = "s24be"
// PCM signed 24-bit big-endian
Mux_Format_S24BE = Format_S24BE
// PCM signed 24-bit little-endian
Format_S24LE = "s24le"
// PCM signed 24-bit little-endian
Mux_Format_S24LE = Format_S24LE
// PCM signed 32-bit big-endian
Format_S32BE = "s32be"
// PCM signed 32-bit big-endian
Mux_Format_S32BE = Format_S32BE
// PCM signed 32-bit little-endian
Format_S32LE = "s32le"
// PCM signed 32-bit little-endian
Mux_Format_S32LE = Format_S32LE
// PCM signed 8-bit
Format_S8 = "s8"
// PCM signed 8-bit
Mux_Format_S8 = Format_S8
// SAP output
Format_SAP = "sap"
// SAP output
Mux_Format_SAP = Format_SAP
// raw SBC
Format_SBC = "sbc"
// raw SBC
Mux_Format_SBC = Format_SBC
// Scenarist Closed Captions
Format_SCC = "scc"
// Scenarist Closed Captions
Mux_Format_SCC = Format_SCC
// SDL2 output device
Format_SDL = "sdl"
// SDL2 output device
Mux_Format_SDL = Format_SDL
// SDL2 output device
Format_SDL2 = "sdl2"
// SDL2 output device
Mux_Format_SDL2 = Format_SDL2
// segment
Format_SEGMENT = "segment"
// segment
Mux_Format_SEGMENT = Format_SEGMENT
// JPEG single image
Format_SINGLEJPEG = "singlejpeg"
// JPEG single image
Mux_Format_SINGLEJPEG = Format_SINGLEJPEG
// Loki SDL MJPEG
Format_SMJPEG = "smjpeg"
// Loki SDL MJPEG
Mux_Format_SMJPEG = Format_SMJPEG
// Smooth Streaming Muxer
Format_SMOOTHSTREAMING = "smoothstreaming"
// Smooth Streaming Muxer
Mux_Format_SMOOTHSTREAMING = Format_SMOOTHSTREAMING
// SoX native
Format_SOX = "sox"
// SoX native
Mux_Format_SOX = Format_SOX
// IEC 61937 (used on S/PDIF - IEC958)
Format_SPDIF = "spdif"
// IEC 61937 (used on S/PDIF - IEC958)
Mux_Format_SPDIF = Format_SPDIF
// Ogg Speex
Format_SPX = "spx"
// Ogg Speex
Mux_Format_SPX = Format_SPX
// SubRip subtitle
Format_SRT = "srt"
// SubRip subtitle
Mux_Format_SRT = Format_SRT
// streaming segment muxer
Format_STREAM_SEGMENT = "stream_segment"
// streaming segment muxer
Mux_Format_STREAM_SEGMENT = Format_STREAM_SEGMENT
// streaming segment muxer
Format_SSEGMENT = "ssegment"
// streaming segment muxer
Mux_Format_SSEGMENT = Format_SSEGMENT
// raw HDMV Presentation Graphic Stream subtitles
Format_SUP = "sup"
// raw HDMV Presentation Graphic Stream subtitles
Mux_Format_SUP = Format_SUP
// MPEG-2 PS (SVCD)
Format_SVCD = "svcd"
// MPEG-2 PS (SVCD)
Mux_Format_SVCD = Format_SVCD
// SWF (ShockWave Flash)
Format_SWF = "swf"
// SWF (ShockWave Flash)
Mux_Format_SWF = Format_SWF
// Multiple muxer tee
Format_TEE = "tee"
// Multiple muxer tee
Mux_Format_TEE = Format_TEE
// raw TrueHD
Format_TRUEHD = "truehd"
// raw TrueHD
Mux_Format_TRUEHD = Format_TRUEHD
// TTA (True Audio)
Format_TTA = "tta"
// TTA (True Audio)
Mux_Format_TTA = Format_TTA
// PCM unsigned 16-bit big-endian
Format_U16BE = "u16be"
// PCM unsigned 16-bit big-endian
Mux_Format_U16BE = Format_U16BE
// PCM unsigned 16-bit little-endian
Format_U16LE = "u16le"
// PCM unsigned 16-bit little-endian
Mux_Format_U16LE = Format_U16LE
// PCM unsigned 24-bit big-endian
Format_U24BE = "u24be"
// PCM unsigned 24-bit big-endian
Mux_Format_U24BE = Format_U24BE
// PCM unsigned 24-bit little-endian
Format_U24LE = "u24le"
// PCM unsigned 24-bit little-endian
Mux_Format_U24LE = Format_U24LE
// PCM unsigned 32-bit big-endian
Format_U32BE = "u32be"
// PCM unsigned 32-bit big-endian
Mux_Format_U32BE = Format_U32BE
// PCM unsigned 32-bit little-endian
Format_U32LE = "u32le"
// PCM unsigned 32-bit little-endian
Mux_Format_U32LE = Format_U32LE
// PCM unsigned 8-bit
Format_U8 = "u8"
// PCM unsigned 8-bit
Mux_Format_U8 = Format_U8
// uncoded framecrc testing
Format_UNCODEDFRAMECRC = "uncodedframecrc"
// uncoded framecrc testing
Mux_Format_UNCODEDFRAMECRC = Format_UNCODEDFRAMECRC
// Video4Linux2 output device
Format_V4L2 = "v4l2"
// Video4Linux2 output device
Mux_Format_V4L2 = Format_V4L2
// raw VC-1 video
Format_VC1 = "vc1"
// raw VC-1 video
Mux_Format_VC1 = Format_VC1
// VC-1 test bitstream
Format_VC1TEST = "vc1test"
// VC-1 test bitstream
Mux_Format_VC1TEST = Format_VC1TEST
// MPEG-1 Systems / MPEG program stream (VCD)
Format_VCD = "vcd"
// MPEG-1 Systems / MPEG program stream (VCD)
Mux_Format_VCD = Format_VCD
// MPEG-2 PS (VOB)
Format_VOB = "vob"
// MPEG-2 PS (VOB)
Mux_Format_VOB = Format_VOB
// Creative Voice
Format_VOC = "voc"
// Creative Voice
Mux_Format_VOC = Format_VOC
// Sony Wave64
Format_W64 = "w64"
// Sony Wave64
Mux_Format_W64 = Format_W64
// WAV / WAVE (Waveform Audio)
Format_WAV = "wav"
// WAV / WAVE (Waveform Audio)
Mux_Format_WAV = Format_WAV
// WebM
Format_WEBM = "webm"
// WebM
Mux_Format_WEBM = Format_WEBM
// WebM Chunk Muxer
Format_WEBM_CHUNK = "webm_chunk"
// WebM Chunk Muxer
Mux_Format_WEBM_CHUNK = Format_WEBM_CHUNK
// WebM DASH Manifest
Format_WEBM_DASH_MANIFEST = "webm_dash_manifest"
// WebM DASH Manifest
Mux_Format_WEBM_DASH_MANIFEST = Format_WEBM_DASH_MANIFEST
// WebP
Format_WEBP = "webp"
// WebP
Mux_Format_WEBP = Format_WEBP
// WebVTT subtitle
Format_WEBVTT = "webvtt"
// WebVTT subtitle
Mux_Format_WEBVTT = Format_WEBVTT
// Windows Television (WTV)
Format_WTV = "wtv"
// Windows Television (WTV)
Mux_Format_WTV = Format_WTV
// raw WavPack
Format_WV = "wv"
// raw WavPack
Mux_Format_WV = Format_WV
// XV (XVideo) output device
Format_XV = "xv"
// XV (XVideo) output device
Mux_Format_XV = Format_XV
// YUV4MPEG pipe
Format_YUV4MPEGPIPE = "yuv4mpegpipe"
// YUV4MPEG pipe
Mux_Format_YUV4MPEGPIPE = Format_YUV4MPEGPIPE
)

View File

@ -0,0 +1,86 @@
package main
import (
"bufio"
"bytes"
"fmt"
"go/format"
"log"
"os"
"os/exec"
"strings"
)
func must(err error) {
if err == nil {
return
}
log.Fatal(err)
}
func main() {
cmd := exec.Command("ffmpeg", "-muxers")
outputBytes, err := cmd.Output()
must(err)
code := `package formats
var (
`
bufreader := bufio.NewScanner(bytes.NewReader(outputBytes))
/*File formats:
D. = Demuxing supported
.E = Muxing supported
--
E 3g2 3GP2 (3GPP2 file format)
E 3gp 3GP (3GPP file format)*/
waitingForList := true
for bufreader.Scan() && waitingForList {
text := bufreader.Text()
if text == " --" {
waitingForList = false
}
}
for bufreader.Scan() {
text := bufreader.Text()
demuxingSupported := text[1] == 'D'
muxingSupported := text[2] == 'E'
text = text[4:]
cols := strings.Fields(text)
ids := strings.Split(cols[0], ",")
name := strings.Join(cols[1:], " ")
for _, id := range ids {
code += fmt.Sprintf(`
// %s
Format_%s = %q
`, name, strings.ToUpper(id), id)
if demuxingSupported {
code += fmt.Sprintf(` // %s
Demux_Format_%s = Format_%s
`, name, strings.ToUpper(id), strings.ToUpper(id))
}
if muxingSupported {
code += fmt.Sprintf(` // %s
Mux_Format_%s = Format_%s
`, name, strings.ToUpper(id), strings.ToUpper(id))
}
}
}
code += `
)
`
codeBytes, err := format.Source([]byte(code))
must(err)
f, err := os.Create("gen_formats.go")
must(err)
defer f.Close()
_, err = f.Write(codeBytes)
must(err)
}

19
app/media/mux/muxer.go Normal file
View File

@ -0,0 +1,19 @@
package mux
import (
"io"
"git.icedream.tech/icedream/uplink/app/media"
)
type Muxer interface {
AcceptsCodec(info media.MediaStreamCodecInfo) bool
GeneratesFormat(info media.MediaStreamContainerInfo) bool
NewInstance(streams ...*media.MediaStream) <-MuxerInstance
}
type MuxerInstance interface {
Error() error
Container() *media.MediaStreamContainerInfo
}

View File

@ -4,6 +4,7 @@ import (
"io"
"io/ioutil"
"os"
"path/filepath"
"testing"
. "github.com/smartystreets/goconvey/convey"
@ -12,7 +13,7 @@ import (
func Test_Muxer(t *testing.T) {
Convey("Muxer", t, func() {
Convey("audio-only", func() {
reader, _ := os.Open("mpthreetest.mp3")
reader, _ := os.Open(filepath.Join("testassets", "mpthreetest.mp3"))
defer reader.Close()
demuxer := Demux(reader)
@ -27,7 +28,7 @@ func Test_Muxer(t *testing.T) {
So(audioStream, ShouldBeNil)
So(stream.StreamId, ShouldEqual, 0)
So(stream.Pts, ShouldEqual, 0)
So(stream.CodecInfo.CodecName, ShouldEqual, "mp3")
So(stream.CodecInfo.CodecName, ShouldBeIn, []string{"mp3", "mp3float"})
So(stream.CodecInfo.Type, ShouldEqual, Audio)
audioStream = stream
}

View File

@ -0,0 +1,12 @@
package transcode
import "git.icedream.tech/icedream/uplink/app/genericapi"
type Transcoder interface {
genericapi.DynamicallyConfigurable
AcceptedInputCodecs() []string
AcceptedOutputCodecs() []string
NewInstance(config interface{}) <-TranscoderInstance
}

View File

@ -9,12 +9,17 @@ import (
"git.icedream.tech/icedream/uplink/plugins"
)
type registeredPlugin struct {
Instance plugins.PluginInstance
Descriptor plugins.PluginDescriptor
}
type App struct {
Server *httpserver.Server
Authenticator authentication.Authenticator
ChannelManager *channels.ChannelManager
plugins []plugins.PluginInstance
plugins []registeredPlugin
}
func New() *App {
@ -23,7 +28,7 @@ func New() *App {
Authenticator: new(authentication.DummyAuthenticator),
ChannelManager: channels.NewChannelManager(),
plugins: []plugins.PluginInstance{},
plugins: []registeredPlugin{},
}
}
@ -40,14 +45,18 @@ func (app *App) UsePlugin(plugin *plugins.Plugin) {
p.SetAuthenticator(app.Authenticator)
}
log.Println("Plugin initialized:", plugin.Descriptor.Name)
log.Println("Plugin registered:", plugin.Descriptor.Name)
app.plugins = append(app.plugins, pluginInstance)
app.plugins = append(app.plugins, registeredPlugin{
Instance: pluginInstance,
Descriptor: plugin.Descriptor,
})
}
func (app *App) Init() {
for _, plugin := range app.plugins {
plugin.Init()
plugin.Instance.Init()
log.Println("Plugin initialized:", plugin.Descriptor.Name)
}
}

View File

@ -21,6 +21,9 @@ func NewServer() *Server {
Router: gin.New(),
}
server.Router.Use(gin.Logger())
server.Router.Use(gin.Recovery())
server.Http.Handler = server.Router
server.Http.Addr = ":8000"

View File

@ -39,22 +39,23 @@ func (mi *MetadataInjector) writeMetadata() (n int, err error) {
func (mi *MetadataInjector) Write(data []byte) (n int, err error) {
for n < len(data) {
restLen := len(data) - n
toWrite := mi.MetadataInterval - mi.offset
if toWrite > restLen {
toWrite = restLen
}
if toWrite <= 0 {
_, cerr := mi.writeMetadata()
//n += cn
if cerr != nil {
err = cerr
_, err = mi.writeMetadata()
if err != nil {
return
}
mi.offset = 0
// toWrite = mi.MetadataInterval
continue
}
outBytes := make([]byte, toWrite)
copy(outBytes, data[mi.offset:mi.offset+toWrite])
copy(outBytes, data[n:n+toWrite])
cn, cerr := mi.Writer.Write(outBytes)
n += cn
mi.offset += cn

View File

@ -4,6 +4,7 @@ import (
"log"
"git.icedream.tech/icedream/uplink/app"
"git.icedream.tech/icedream/uplink/plugins/icecast/input"
"git.icedream.tech/icedream/uplink/plugins/icecast/output"
"git.icedream.tech/icedream/uplink/plugins/test/sine"
)
@ -16,7 +17,7 @@ func main() {
func run() (err error) {
backend := app.New()
// backend.UsePlugin(icecast_input.Plugin)
backend.UsePlugin(icecast_input.Plugin)
backend.UsePlugin(icecast_output.Plugin)
backend.UsePlugin(sine.Plugin)
backend.Init()

View File

@ -2,13 +2,24 @@ package icecast_input
import (
"io"
"strconv"
"git.icedream.tech/icedream/uplink/app/authentication"
"git.icedream.tech/icedream/uplink/app/channels"
"git.icedream.tech/icedream/uplink/app/servers/http"
"git.icedream.tech/icedream/uplink/app/streams"
"github.com/gin-gonic/gin"
)
var allowedCopyHeaders = []string{
"icy-br",
"icy-name",
"icy-description",
"icy-pub",
"icy-url",
"icy-genre",
}
type pluginInstance struct {
server *httpserver.Server
authenticator authentication.Authenticator
@ -25,7 +36,9 @@ func (instance *pluginInstance) SetChannelManager(channelManager *channels.Chann
func (instance *pluginInstance) SetServer(server *httpserver.Server) {
instance.server = server
}
func (instance *pluginInstance) Init() {
router := instance.server.Router
router.PUT("/:channel", func(ctx *gin.Context) {
@ -43,6 +56,36 @@ func (instance *pluginInstance) SetServer(server *httpserver.Server) {
ctx.Status(401)
return
}
io.Copy(channel.InputStream, ctx.Request.Body)
var sr io.Reader = ctx.Request.Body
defer ctx.Request.Body.Close()
if ctx.GetHeader("icy-metadata") == "1" {
metaInt64, err := strconv.ParseInt(ctx.GetHeader("icy-metaint"), 10, 32)
if err != nil {
ctx.Status(400)
return
}
metaInt := int(metaInt64)
// Client is sending metadata!
mr := streams.NewMetadataExtractor(sr, metaInt)
sr = mr
metadataChan := channel.Metadata()
defer func() { metadataChan <- nil }()
go func() {
for metadata := range metadataChan {
metadataToWrite := streams.Metadata{}
if value, ok := metadata["StreamTitle"]; ok {
metadataToWrite["StreamTitle"] = value
}
channel.SetMetadata(metadataToWrite)
}
}()
}
input := channel.AddInputStream("icecast")
io.Copy(input, sr)
})
}

View File

@ -1,27 +1,21 @@
package icecast_output
import (
"bytes"
"fmt"
"io"
"log"
"runtime"
"git.icedream.tech/icedream/uplink/app/authentication"
"git.icedream.tech/icedream/uplink/app/channels"
"git.icedream.tech/icedream/uplink/app/media"
"git.icedream.tech/icedream/uplink/app/servers/http"
"git.icedream.tech/icedream/uplink/app/streams"
humanize "github.com/dustin/go-humanize"
"github.com/gin-gonic/gin"
"github.com/glycerine/rbuf"
)
type pluginInstance struct {
server *httpserver.Server
authenticator authentication.Authenticator
channelManager *channels.ChannelManager
ringBuffers map[string]map[string]*rbuf.FixedSizeRingBuf
}
func (instance *pluginInstance) SetAuthenticator(authenticator authentication.Authenticator) {
@ -31,33 +25,6 @@ func (instance *pluginInstance) SetAuthenticator(authenticator authentication.Au
func (instance *pluginInstance) SetChannelManager(channelManager *channels.ChannelManager) {
instance.channelManager = channelManager
go func() {
channelC := channelManager.Events().Sub("open")
log.Println("Burst cache: Now watching")
for c := range channelC {
channelId := c.(string)
go func(channel *channels.Channel) {
streamRbufMap := map[string]*rbuf.FixedSizeRingBuf{}
instance.ringBuffers[channelId] = streamRbufMap
outputContainerC := channel.Events.Sub("output_container")
log.Println("Burst cache: Now watching channel", channelId)
for c := range outputContainerC {
containerId := c.(string)
burstCache := rbuf.NewFixedSizeRingBuf(64 * 1024)
streamRbufMap[containerId] = burstCache
go func(container *media.MediaStreamContainer) {
r := container.Sub()
log.Println("Burst cache: Now watching container", containerId, "in channel", channelId)
io.Copy(burstCache, r)
}(channel.OutputContainers[containerId])
runtime.Gosched()
}
}(channelManager.Channel(channelId))
runtime.Gosched()
}
}()
runtime.Gosched()
// TODO - handle channel and container closure
}
@ -66,8 +33,6 @@ func (instance *pluginInstance) SetServer(server *httpserver.Server) {
}
func (instance *pluginInstance) Init() {
instance.ringBuffers = map[string]map[string]*rbuf.FixedSizeRingBuf{}
router := instance.server.Router
router.GET("/:channel/:container", func(ctx *gin.Context) {
@ -95,6 +60,13 @@ func (instance *pluginInstance) Init() {
ctx.Writer.Header().Set("icy-metadata", "1")
ctx.Writer.Header().Set("icy-metaint", fmt.Sprintf("%d", metaInt))
}
ctx.Writer.Header().Set("icy-name", "Channel name") // TODO
ctx.Writer.Header().Set("icy-pub", "0") // TODO
ctx.Writer.Header().Set("Server", "Uplink/0.0.0; Icecast 2.4.0 compatible")
ctx.Writer.Header().Set("Cache-Control", "no-cache, no-store")
ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*")
ctx.Writer.Header().Set("Access-Control-Allow-Headers", "Origin, Accept, X-Requested-With, Content-Type")
ctx.Writer.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS, HEAD")
ctx.Writer.WriteHeader(200)
w := ctx.Writer
@ -103,32 +75,26 @@ func (instance *pluginInstance) Init() {
sr := container.Sub()
defer sr.Close()
log.Println("Someone tuned in to", channelId, channel)
if sendMetadata {
mw = streams.NewMetadataInjector(w, metaInt)
nw = mw
}
if channelRbuf, ok := instance.ringBuffers[channelId]; ok {
if containerRbuf, ok := channelRbuf[containerId]; ok {
burst := containerRbuf.Bytes()
log.Println("Sending", humanize.Bytes(uint64(len(burst))), "burst")
_, err := io.Copy(nw, bytes.NewReader(burst))
if err != nil {
log.Println(err)
return
metadataChan := channel.Metadata()
defer func() { metadataChan <- nil }()
go func() {
for metadata := range metadataChan {
metadataToWrite := streams.Metadata{}
if value, ok := metadata["StreamTitle"]; ok {
metadataToWrite["StreamTitle"] = value
}
mw.SetMetadata(metadataToWrite)
}
} else {
log.Println("No burst cache for", channelId, "/", containerId)
}
} else {
log.Println("No burst cache for", channelId)
}()
}
_, err := io.Copy(nw, sr)
if err != nil {
log.Println(err)
log.Println("copying stream to output failed:", err)
}
})

View File

@ -22,8 +22,6 @@ func (instance *pluginInstance) Init() {
channelManager := instance.channelManager
go func() {
time.Sleep(2 * time.Second) // give burst cache a chance to realize
c, err := channelManager.Open("sine")
if err != nil {
log.Println("ERROR: sine channel could not be opened:", err)

View File

@ -43,16 +43,11 @@ func (stream *SineStream) Read(data []byte) (n int, err error) {
targetTime := stream.Timestamp.
Add(time.Duration(float64(time.Second) * float64(stream.State) / float64(stream.Samplerate)))
delay := targetTime.Sub(time.Now())
/*log.Println("state", stream.State, "value", sampleValue, "time", targetTime, "delay", delay)
time.Sleep(time.Second)*/
if delay > 0 {
<-time.After(delay)
}
/*if stream.State%uint64(stream.Samplerate) == 0 {
log.Println("state", stream.State, "value", sampleValue, "time", targetTime, "delay", delay)
}*/
stream.State++
}

2
vendor/github.com/3d0c/gmf generated vendored

@ -1 +1 @@
Subproject commit f158770a793e28c093dc22c2a9ef0af20bdd804f
Subproject commit d481e19a7c9f8d849bb3f6a69854ec711dc894e8