-
Notifications
You must be signed in to change notification settings - Fork 539
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
655 additions
and
63 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,4 +9,6 @@ rpc: | |
debug: false | ||
interval: 20 | ||
out_put_path: /srv/bililive | ||
feature: | ||
use_native_flv_parser: false | ||
live_rooms: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package ffmpeg | ||
|
||
import ( | ||
"io" | ||
"net/url" | ||
"os/exec" | ||
) | ||
|
||
const ( | ||
userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" | ||
) | ||
|
||
type Parser struct { | ||
cmd *exec.Cmd | ||
cmdStdIn io.WriteCloser | ||
} | ||
|
||
func New() *Parser { | ||
return new(Parser) | ||
} | ||
|
||
func (p *Parser) ParseLiveStream(url *url.URL, file string) error { | ||
p.cmd = exec.Command( | ||
"ffmpeg", | ||
"-loglevel", "warning", | ||
"-y", "-re", | ||
"-user_agent", userAgent, | ||
"-timeout", "60000000", | ||
"-i", url.String(), | ||
"-c", "copy", | ||
"-bsf:a", "aac_adtstoasc", | ||
"-f", "flv", | ||
file, | ||
) | ||
p.cmdStdIn, _ = p.cmd.StdinPipe() | ||
p.cmd.Start() | ||
return p.cmd.Wait() | ||
} | ||
|
||
func (p *Parser) Stop() error { | ||
_, err := p.cmdStdIn.Write([]byte("q")) | ||
return err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package flv | ||
|
||
import ( | ||
"bytes" | ||
"encoding/binary" | ||
"errors" | ||
"github.com/hr3lxphr6j/bililive-go/src/lib/reader" | ||
"io" | ||
"net/http" | ||
"net/url" | ||
"os" | ||
) | ||
|
||
const ( | ||
audioTag uint8 = 8 | ||
videoTag uint8 = 9 | ||
scriptTag uint8 = 18 | ||
) | ||
|
||
var ( | ||
flvSign = []byte{0x46, 0x4c, 0x56, 0x01} // flv version01 | ||
NotFlvStream = errors.New("not flv stream") | ||
UnknownTag = errors.New("unknown tag") | ||
) | ||
|
||
type Metadata struct { | ||
HasVideo, HasAudio bool | ||
} | ||
|
||
type Parser struct { | ||
Metadata Metadata | ||
|
||
i *reader.BufferedReader | ||
o io.Writer | ||
avcHeaderCount uint8 | ||
tagCount uint32 | ||
|
||
hc *http.Client | ||
stopCh chan struct{} | ||
} | ||
|
||
func NewParser() *Parser { | ||
return &Parser{ | ||
Metadata: Metadata{}, | ||
hc: &http.Client{}, | ||
stopCh: make(chan struct{}), | ||
} | ||
} | ||
|
||
func (p *Parser) ParseLiveStream(url *url.URL, file string) error { | ||
// init input | ||
req, err := http.NewRequest("GET", url.String(), nil) | ||
req.Header.Add("User-Agent", "Chrome/59.0.3071.115") | ||
if err != nil { | ||
return err | ||
} | ||
resp, err := p.hc.Do(req) | ||
if err != nil { | ||
return err | ||
} | ||
defer resp.Body.Close() | ||
p.i = reader.New(resp.Body) | ||
defer p.i.Free() | ||
|
||
// init output | ||
f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE, 0666) | ||
if err != nil { | ||
return err | ||
} | ||
p.o = f | ||
defer f.Close() | ||
|
||
// start parse | ||
return p.doParse() | ||
} | ||
|
||
func (p *Parser) Stop() error { | ||
close(p.stopCh) | ||
return nil | ||
} | ||
|
||
func (p *Parser) doParse() error { | ||
// header of flv | ||
b, err := p.i.ReadN(9) | ||
if err != nil { | ||
return err | ||
} | ||
// signature | ||
if !bytes.Equal(b[:4], flvSign) { | ||
return NotFlvStream | ||
} | ||
// flag | ||
p.Metadata.HasVideo = uint8(b[4])&(1<<2) != 0 | ||
p.Metadata.HasAudio = uint8(b[4])&1 != 0 | ||
|
||
// offset must be 9 | ||
if binary.BigEndian.Uint32(b[5:]) != 9 { | ||
return NotFlvStream | ||
} | ||
|
||
// write flv header | ||
if err := p.doWrite(p.i.AllBytes()); err != nil { | ||
return err | ||
} | ||
p.i.Reset() | ||
|
||
for { | ||
select { | ||
case <-p.stopCh: | ||
return nil | ||
default: | ||
if err := p.parseTag(); err != nil { | ||
return err | ||
} | ||
} | ||
} | ||
} | ||
|
||
func (p *Parser) doCopy(n uint32) error { | ||
if n, err := io.CopyN(p.o, p.i, int64(n)); err != nil || n != int64(n) { | ||
if err == nil { | ||
err = io.EOF | ||
} | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func (p *Parser) doWrite(b []byte) error { | ||
if n, err := p.o.Write(b); err != nil || n != len(b) { | ||
if err == nil { | ||
err = io.EOF | ||
} | ||
return err | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package flv | ||
|
||
func (p *Parser) parseTag() error { | ||
p.tagCount += 1 | ||
|
||
b, err := p.i.ReadN(15) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
tagType := uint8(b[4]) | ||
length := uint32(b[5])<<16 | uint32(b[6])<<8 | uint32(b[7]) | ||
timeStamp := uint32(b[8])<<16 | uint32(b[9])<<8 | uint32(b[10]) | uint32(b[11])<<24 | ||
|
||
switch tagType { | ||
case audioTag: | ||
if _, err := p.parseAudioTag(length, timeStamp); err != nil { | ||
return err | ||
} | ||
case videoTag: | ||
if _, err := p.parseVideoTag(length, timeStamp); err != nil { | ||
return err | ||
} | ||
case scriptTag: | ||
return p.parseScriptTag(length) | ||
default: | ||
return UnknownTag | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package flv | ||
|
||
type SoundFormat uint8 | ||
type SoundRate uint8 | ||
type SoundSize uint8 | ||
type SoundType uint8 | ||
type AACPacketType uint8 | ||
type AudioTagHeader struct { | ||
SoundFormat SoundFormat | ||
SoundRate SoundRate | ||
SoundSize SoundSize | ||
SoundType SoundType | ||
AACPacketType AACPacketType | ||
} | ||
|
||
const ( | ||
// SoundFormat | ||
LPCM_PE SoundFormat = 0 // Linear PCM, platform endian | ||
ADPCM SoundFormat = 1 | ||
MP3 SoundFormat = 2 | ||
LPCM_LE SoundFormat = 3 // Linear PCM, little endian | ||
AAC SoundFormat = 10 | ||
Speex SoundFormat = 11 | ||
MP3_8kHz SoundFormat = 14 // MP3 8 kHz | ||
|
||
// SoundRate | ||
Rate5kHz SoundRate = 0 // 5.5kHz | ||
Rate11kHz SoundRate = 1 // 11 kHz | ||
Rate22kHz SoundRate = 2 // 22 kHz | ||
Rate44kHz SoundRate = 3 // 44 kHz | ||
|
||
// SoundSize | ||
Sample8 uint8 = 0 // 8-bit samples | ||
Sample16 uint8 = 1 // 16-bit samples | ||
|
||
// SoundType | ||
Mono SoundType = 0 // Mono sound | ||
Stereo SoundType = 1 // Stereo sound | ||
|
||
// AACPacketType | ||
AACSeqHeader AACPacketType = 0 | ||
AACRaw AACPacketType = 1 | ||
) | ||
|
||
func (p *Parser) parseAudioTag(length, timestamp uint32) (*AudioTagHeader, error) { | ||
b, err := p.i.ReadByte() | ||
l := length - 1 | ||
if err != nil { | ||
return nil, err | ||
} | ||
tag := new(AudioTagHeader) | ||
|
||
tag.SoundFormat = SoundFormat(b >> 4 & 15) | ||
tag.SoundRate = SoundRate(b >> 2 & 3) | ||
tag.SoundSize = SoundSize(b >> 1 & 1) | ||
tag.SoundType = SoundType(b & 1) | ||
|
||
if tag.SoundFormat == AAC { | ||
b, err := p.i.ReadByte() | ||
l -= 1 | ||
if err != nil { | ||
return nil, err | ||
} | ||
tag.AACPacketType = AACPacketType(b) | ||
} | ||
|
||
// write tag header && audio tag header & AACPacketType | ||
if err := p.doWrite(p.i.AllBytes()); err != nil { | ||
return nil, err | ||
} | ||
p.i.Reset() | ||
// write body | ||
if err := p.doCopy(l); err != nil { | ||
return nil, err | ||
} | ||
|
||
return tag, nil | ||
} |
Oops, something went wrong.