Commit 0623e927 authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Add support for recording h.264 video.

We store h.264 in Matroska, since we already have the library.
We currently store the video width and height as 0.
parent 7d29ef5a
...@@ -13,6 +13,7 @@ import ( ...@@ -13,6 +13,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/at-wat/ebml-go/mkvcore"
"github.com/at-wat/ebml-go/webm" "github.com/at-wat/ebml-go/webm"
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/pion/rtp/codecs" "github.com/pion/rtp/codecs"
...@@ -187,7 +188,7 @@ func (conn *diskConn) warn(message string) { ...@@ -187,7 +188,7 @@ func (conn *diskConn) warn(message string) {
} }
// called locked // called locked
func (conn *diskConn) reopen() error { func (conn *diskConn) reopen(extension string) error {
for _, t := range conn.tracks { for _, t := range conn.tracks {
if t.writer != nil { if t.writer != nil {
t.writeBuffered(true) t.writeBuffered(true)
...@@ -197,7 +198,7 @@ func (conn *diskConn) reopen() error { ...@@ -197,7 +198,7 @@ func (conn *diskConn) reopen() error {
} }
conn.file = nil conn.file = nil
file, err := openDiskFile(conn.directory, conn.username) file, err := openDiskFile(conn.directory, conn.username, extension)
if err != nil { if err != nil {
return err return err
} }
...@@ -227,7 +228,7 @@ func (conn *diskConn) Close() error { ...@@ -227,7 +228,7 @@ func (conn *diskConn) Close() error {
return nil return nil
} }
func openDiskFile(directory, username string) (*os.File, error) { func openDiskFile(directory, username, extension string) (*os.File, error) {
filenameFormat := "2006-01-02T15:04:05.000" filenameFormat := "2006-01-02T15:04:05.000"
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
filenameFormat = "2006-01-02T15-04-05-000" filenameFormat = "2006-01-02T15-04-05-000"
...@@ -240,9 +241,11 @@ func openDiskFile(directory, username string) (*os.File, error) { ...@@ -240,9 +241,11 @@ func openDiskFile(directory, username string) (*os.File, error) {
for counter := 0; counter < 100; counter++ { for counter := 0; counter < 100; counter++ {
var fn string var fn string
if counter == 0 { if counter == 0 {
fn = fmt.Sprintf("%v.webm", filename) fn = fmt.Sprintf("%v.%v", filename, extension)
} else { } else {
fn = fmt.Sprintf("%v-%02d.webm", filename, counter) fn = fmt.Sprintf("%v-%02d.%v",
filename, counter, extension,
)
} }
fn = filepath.Join(directory, fn) fn = filepath.Join(directory, fn)
...@@ -278,7 +281,7 @@ type diskTrack struct { ...@@ -278,7 +281,7 @@ type diskTrack struct {
remote conn.UpTrack remote conn.UpTrack
conn *diskConn conn *diskConn
writer webm.BlockWriteCloser writer mkvcore.BlockWriteCloser
builder *samplebuilder.SampleBuilder builder *samplebuilder.SampleBuilder
lastSeqno maybeUint32 lastSeqno maybeUint32
origin maybeUint32 origin maybeUint32
...@@ -300,7 +303,8 @@ func newDiskConn(client *Client, directory string, up conn.Up, remoteTracks []co ...@@ -300,7 +303,8 @@ func newDiskConn(client *Client, directory string, up conn.Up, remoteTracks []co
client.group.WallOps("Multiple audio tracks, recording just one") client.group.WallOps("Multiple audio tracks, recording just one")
} }
} else if strings.EqualFold(codec, "video/vp8") || } else if strings.EqualFold(codec, "video/vp8") ||
strings.EqualFold(codec, "video/vp9") { strings.EqualFold(codec, "video/vp9") ||
strings.EqualFold(codec, "video/h264") {
if video == nil || video.Label() == "l" { if video == nil || video.Label() == "l" {
video = remote video = remote
} else if remote.Label() != "l" { } else if remote.Label() != "l" {
...@@ -375,6 +379,17 @@ func newDiskConn(client *Client, directory string, up conn.Up, remoteTracks []co ...@@ -375,6 +379,17 @@ func newDiskConn(client *Client, directory string, up conn.Up, remoteTracks []co
), ),
) )
conn.hasVideo = true conn.hasVideo = true
} else if strings.EqualFold(codec.MimeType, "video/h264") {
builder = samplebuilder.New(
128, &codecs.H264Packet{}, codec.ClockRate,
samplebuilder.WithPartitionHeadChecker(
&codecs.H264PartitionHeadChecker{},
),
samplebuilder.WithPartitionTailChecker(
markerPartitionTailChecker,
),
)
conn.hasVideo = true
} else { } else {
// this shouldn't happen // this shouldn't happen
return nil, errors.New( return nil, errors.New(
...@@ -565,7 +580,8 @@ func (conn *diskConn) initWriter(width, height uint32) error { ...@@ -565,7 +580,8 @@ func (conn *diskConn) initWriter(width, height uint32) error {
if conn.file != nil && width == conn.width && height == conn.height { if conn.file != nil && width == conn.width && height == conn.height {
return nil return nil
} }
var entries []webm.TrackEntry isWebm := true
var desc []mkvcore.TrackDescription
for i, t := range conn.tracks { for i, t := range conn.tracks {
var entry webm.TrackEntry var entry webm.TrackEntry
codec := t.remote.Codec() codec := t.remote.Codec()
...@@ -602,25 +618,56 @@ func (conn *diskConn) initWriter(width, height uint32) error { ...@@ -602,25 +618,56 @@ func (conn *diskConn) initWriter(width, height uint32) error {
PixelHeight: uint64(height), PixelHeight: uint64(height),
}, },
} }
} else if strings.EqualFold(codec.MimeType, "video/h264") {
entry = webm.TrackEntry{
Name: "Video",
TrackNumber: uint64(i + 1),
CodecID: "V_MPEG4/ISO/AVC",
TrackType: 1,
Video: &webm.Video{
PixelWidth: uint64(width),
PixelHeight: uint64(height),
},
}
isWebm = false
} else { } else {
return errors.New("unknown track type") return errors.New("unknown track type")
} }
entries = append(entries, entry) desc = append(desc,
mkvcore.TrackDescription{
TrackNumber: uint64(i + 1),
TrackEntry: entry,
},
)
}
extension := "webm"
header := webm.DefaultEBMLHeader
if !isWebm {
extension = "mkv"
h := *header
h.DocType = "matroska"
header = &h
} }
err := conn.reopen() err := conn.reopen(extension)
if err != nil { if err != nil {
return err return err
} }
writers, err := webm.NewSimpleBlockWriter(conn.file, entries) ws, err := mkvcore.NewSimpleBlockWriter(
conn.file, desc,
mkvcore.WithEBMLHeader(header),
mkvcore.WithSegmentInfo(webm.DefaultSegmentInfo),
mkvcore.WithBlockInterceptor(webm.DefaultBlockInterceptor),
)
if err != nil { if err != nil {
conn.file.Close() conn.file.Close()
conn.file = nil conn.file = nil
return err return err
} }
if len(writers) != len(conn.tracks) { if len(ws) != len(conn.tracks) {
conn.file.Close() conn.file.Close()
conn.file = nil conn.file = nil
return errors.New("unexpected number of writers") return errors.New("unexpected number of writers")
...@@ -630,7 +677,7 @@ func (conn *diskConn) initWriter(width, height uint32) error { ...@@ -630,7 +677,7 @@ func (conn *diskConn) initWriter(width, height uint32) error {
conn.height = height conn.height = height
for i, t := range conn.tracks { for i, t := range conn.tracks {
t.writer = writers[i] t.writer = ws[i]
} }
return nil return nil
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment