mirror of
https://github.com/harshabose/transcode.git
synced 2025-10-09 11:30:03 +08:00
third commit
This commit is contained in:
@@ -19,7 +19,7 @@ type Encoder struct {
|
|||||||
codec *astiav.Codec
|
codec *astiav.Codec
|
||||||
encoderContext *astiav.CodecContext
|
encoderContext *astiav.CodecContext
|
||||||
codecFlags *astiav.Dictionary
|
codecFlags *astiav.Dictionary
|
||||||
encoderSettings encoderCodecSetting
|
encoderSettings codecSettings
|
||||||
bandwidthChan chan int64
|
bandwidthChan chan int64
|
||||||
sps []byte
|
sps []byte
|
||||||
pps []byte
|
pps []byte
|
||||||
@@ -30,7 +30,6 @@ func CreateEncoder(ctx context.Context, codecID astiav.CodecID, filter *Filter,
|
|||||||
buffer: buffer.CreateChannelBuffer(ctx, DefaultVideoFPS*3, internal.CreatePacketPool()),
|
buffer: buffer.CreateChannelBuffer(ctx, DefaultVideoFPS*3, internal.CreatePacketPool()),
|
||||||
filter: filter,
|
filter: filter,
|
||||||
codecFlags: astiav.NewDictionary(),
|
codecFlags: astiav.NewDictionary(),
|
||||||
encoderSettings: EncoderCodecNoSetting,
|
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +44,7 @@ func CreateEncoder(ctx context.Context, codecID astiav.CodecID, filter *Filter,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if encoder.encoderSettings == EncoderCodecNoSetting {
|
if encoder.encoderSettings == nil {
|
||||||
return nil, ErrorCodecNoSetting
|
return nil, ErrorCodecNoSetting
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +54,7 @@ func CreateEncoder(ctx context.Context, codecID astiav.CodecID, filter *Filter,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder.findParameterSets(encoder.encoderContext.ExtraData())
|
//encoder.findParameterSets(encoder.encoderContext.ExtraData())
|
||||||
|
|
||||||
return encoder, nil
|
return encoder, nil
|
||||||
}
|
}
|
||||||
@@ -85,7 +84,7 @@ loop1:
|
|||||||
select {
|
select {
|
||||||
case <-encoder.ctx.Done():
|
case <-encoder.ctx.Done():
|
||||||
return
|
return
|
||||||
case bitrate := <-encoder.bandwidthChan:
|
case bitrate := <-encoder.bandwidthChan: // TODO: MIGHT NEED A MUTEX FOR THIS ONE CASE
|
||||||
encoder.encoderContext.SetBitRate(bitrate)
|
encoder.encoderContext.SetBitRate(bitrate)
|
||||||
case frame = <-encoder.filter.WaitForFrame():
|
case frame = <-encoder.filter.WaitForFrame():
|
||||||
if err = encoder.encoderContext.SendFrame(frame); err != nil {
|
if err = encoder.encoderContext.SendFrame(frame); err != nil {
|
||||||
@@ -138,45 +137,45 @@ func (encoder *Encoder) SetBitrateChannel(channel chan int64) {
|
|||||||
encoder.bandwidthChan = channel
|
encoder.bandwidthChan = channel
|
||||||
}
|
}
|
||||||
|
|
||||||
func (encoder *Encoder) findParameterSets(extraData []byte) {
|
//func (encoder *Encoder) findParameterSets(extraData []byte) {
|
||||||
if len(extraData) > 0 {
|
// if len(extraData) > 0 {
|
||||||
// Find first start code (0x00000001)
|
// // Find first start code (0x00000001)
|
||||||
for i := 0; i < len(extraData)-4; i++ {
|
// for i := 0; i < len(extraData)-4; i++ {
|
||||||
if extraData[i] == 0 && extraData[i+1] == 0 && extraData[i+2] == 0 && extraData[i+3] == 1 {
|
// if extraData[i] == 0 && extraData[i+1] == 0 && extraData[i+2] == 0 && extraData[i+3] == 1 {
|
||||||
// Skip start code to get NAL type
|
// // Skip start code to get NAL type
|
||||||
nalType := extraData[i+4] & 0x1F
|
// nalType := extraData[i+4] & 0x1F
|
||||||
|
//
|
||||||
// Find next start code or end
|
// // Find next start code or end
|
||||||
nextStart := len(extraData)
|
// nextStart := len(extraData)
|
||||||
for j := i + 4; j < len(extraData)-4; j++ {
|
// for j := i + 4; j < len(extraData)-4; j++ {
|
||||||
if extraData[j] == 0 && extraData[j+1] == 0 && extraData[j+2] == 0 && extraData[j+3] == 1 {
|
// if extraData[j] == 0 && extraData[j+1] == 0 && extraData[j+2] == 0 && extraData[j+3] == 1 {
|
||||||
nextStart = j
|
// nextStart = j
|
||||||
break
|
// break
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if nalType == 7 { // SPS
|
// if nalType == 7 { // SPS
|
||||||
encoder.sps = make([]byte, nextStart-i)
|
// encoder.sps = make([]byte, nextStart-i)
|
||||||
copy(encoder.sps, extraData[i:nextStart])
|
// copy(encoder.sps, extraData[i:nextStart])
|
||||||
} else if nalType == 8 { // PPS
|
// } else if nalType == 8 { // PPS
|
||||||
encoder.pps = make([]byte, len(extraData)-i)
|
// encoder.pps = make([]byte, len(extraData)-i)
|
||||||
copy(encoder.pps, extraData[i:])
|
// copy(encoder.pps, extraData[i:])
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
i = nextStart - 1
|
// i = nextStart - 1
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
func (encoder *Encoder) GetSPS() []byte {
|
//func (encoder *Encoder) GetSPS() []byte {
|
||||||
return encoder.sps
|
// return encoder.sps
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
func (encoder *Encoder) GetPPS() []byte {
|
//func (encoder *Encoder) GetPPS() []byte {
|
||||||
return encoder.pps
|
// return encoder.pps
|
||||||
}
|
//}
|
||||||
|
|
||||||
func (encoder *Encoder) close() {
|
func (encoder *Encoder) close() {
|
||||||
if encoder.encoderContext != nil {
|
if encoder.encoderContext != nil {
|
||||||
|
@@ -1,14 +1,205 @@
|
|||||||
package transcode
|
package transcode
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
type (
|
type (
|
||||||
encoderCodecSetting string
|
|
||||||
EncoderOption = func(*Encoder) error
|
EncoderOption = func(*Encoder) error
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
type codecSettings interface {
|
||||||
EncoderCodecNoSetting encoderCodecSetting = "None"
|
ForEach(func(string, string) error) error
|
||||||
EncoderCodecDefaultSetting encoderCodecSetting = "default"
|
}
|
||||||
EncoderCodecHighQualitySetting encoderCodecSetting = "high-quality"
|
|
||||||
EncoderCodecLowLatencySetting encoderCodecSetting = "low-latency"
|
type X264Settings struct {
|
||||||
EncoderCodecLowBandwidthSetting encoderCodecSetting = "low-bandwidth"
|
Preset string `x264:"preset"`
|
||||||
)
|
Tune string `x264:"tune"`
|
||||||
|
Refs string `x264:"refs"`
|
||||||
|
Profile string `x264:"profile"`
|
||||||
|
Level string `x264:"level"`
|
||||||
|
Qmin string `x264:"qmin"`
|
||||||
|
Qmax string `x264:"qmax"`
|
||||||
|
BFrames string `x264:"bframes"`
|
||||||
|
BAdapt string `x264:"b-adapt"`
|
||||||
|
NGOP string `x264:"keyint"`
|
||||||
|
NGOPMin string `x264:"min-keyint"`
|
||||||
|
Scenecut string `x264:"scenecut"`
|
||||||
|
InfraRefresh string `x264:"intra-refresh"`
|
||||||
|
LookAhead string `x264:"rc-lookahead"`
|
||||||
|
SlicedThreads string `x264:"sliced-threads"`
|
||||||
|
SyncLookAhead string `x264:"sync-lookahead"`
|
||||||
|
ForceIDR string `x264:"force-idr"`
|
||||||
|
AQMode string `x264:"aq-mode"`
|
||||||
|
AQStrength string `x264:"aq-strength"`
|
||||||
|
MBTree string `x264:"mbtree"`
|
||||||
|
Bitrate string `x264:"bitrate"`
|
||||||
|
VBVMaxBitrate string `x264:"vbv-maxrate"`
|
||||||
|
VBVBuffer string `x264:"vbv-bufsize"`
|
||||||
|
RateTol string `x264:"ratetol"`
|
||||||
|
Threads string `x264:"threads"`
|
||||||
|
AnnexB string `x264:"annexb"`
|
||||||
|
Aud string `x264:"aud"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s X264Settings) ForEach(fn func(key, value string) error) error {
|
||||||
|
t := reflect.TypeOf(s)
|
||||||
|
v := reflect.ValueOf(s)
|
||||||
|
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
field := t.Field(i)
|
||||||
|
tag := field.Tag.Get("x264")
|
||||||
|
if tag != "" {
|
||||||
|
if err := fn(tag, v.Field(i).String()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var DefaultX264Settings = X264Settings{
|
||||||
|
Preset: "medium",
|
||||||
|
Tune: "film",
|
||||||
|
Refs: "6",
|
||||||
|
Profile: "high",
|
||||||
|
Level: "auto",
|
||||||
|
Qmin: "18",
|
||||||
|
Qmax: "28",
|
||||||
|
BFrames: "3",
|
||||||
|
BAdapt: "1",
|
||||||
|
NGOP: "250",
|
||||||
|
NGOPMin: "25",
|
||||||
|
Scenecut: "40",
|
||||||
|
InfraRefresh: "0",
|
||||||
|
LookAhead: "40",
|
||||||
|
SlicedThreads: "0",
|
||||||
|
SyncLookAhead: "1",
|
||||||
|
ForceIDR: "0",
|
||||||
|
AQMode: "1",
|
||||||
|
AQStrength: "1.0",
|
||||||
|
MBTree: "1",
|
||||||
|
Bitrate: "4000",
|
||||||
|
VBVMaxBitrate: "5000",
|
||||||
|
VBVBuffer: "8000",
|
||||||
|
RateTol: "1",
|
||||||
|
Threads: "0",
|
||||||
|
AnnexB: "1",
|
||||||
|
Aud: "0",
|
||||||
|
}
|
||||||
|
|
||||||
|
var LowBandwidthX264Settings = X264Settings{
|
||||||
|
Preset: "veryfast",
|
||||||
|
Tune: "fastdecode",
|
||||||
|
Refs: "2",
|
||||||
|
Profile: "baseline",
|
||||||
|
Level: "4.1",
|
||||||
|
Qmin: "23",
|
||||||
|
Qmax: "35",
|
||||||
|
BFrames: "0",
|
||||||
|
BAdapt: "0",
|
||||||
|
NGOP: "60",
|
||||||
|
NGOPMin: "30",
|
||||||
|
Scenecut: "30",
|
||||||
|
InfraRefresh: "0",
|
||||||
|
LookAhead: "20",
|
||||||
|
SlicedThreads: "1",
|
||||||
|
SyncLookAhead: "0",
|
||||||
|
ForceIDR: "0",
|
||||||
|
AQMode: "0",
|
||||||
|
AQStrength: "1.2",
|
||||||
|
MBTree: "0",
|
||||||
|
Bitrate: "1500",
|
||||||
|
VBVMaxBitrate: "1800",
|
||||||
|
VBVBuffer: "3000",
|
||||||
|
RateTol: "0.25",
|
||||||
|
Threads: "0",
|
||||||
|
AnnexB: "1",
|
||||||
|
Aud: "0",
|
||||||
|
}
|
||||||
|
|
||||||
|
var LowLatencyX264Settings = X264Settings{
|
||||||
|
Preset: "ultrafast",
|
||||||
|
Tune: "zerolatency",
|
||||||
|
Refs: "1",
|
||||||
|
Profile: "baseline",
|
||||||
|
Level: "4.1",
|
||||||
|
Qmin: "20",
|
||||||
|
Qmax: "32",
|
||||||
|
BFrames: "0",
|
||||||
|
BAdapt: "0",
|
||||||
|
NGOP: "30",
|
||||||
|
NGOPMin: "15",
|
||||||
|
Scenecut: "0",
|
||||||
|
InfraRefresh: "1",
|
||||||
|
LookAhead: "10",
|
||||||
|
SlicedThreads: "1",
|
||||||
|
SyncLookAhead: "0",
|
||||||
|
ForceIDR: "1",
|
||||||
|
AQMode: "0",
|
||||||
|
AQStrength: "0",
|
||||||
|
MBTree: "0",
|
||||||
|
Bitrate: "2500",
|
||||||
|
VBVMaxBitrate: "3000",
|
||||||
|
VBVBuffer: "5000",
|
||||||
|
RateTol: "0.5",
|
||||||
|
Threads: "0",
|
||||||
|
AnnexB: "1",
|
||||||
|
Aud: "1",
|
||||||
|
}
|
||||||
|
|
||||||
|
var HighQualityX264Settings = X264Settings{
|
||||||
|
Preset: "slow",
|
||||||
|
Tune: "film",
|
||||||
|
Refs: "8",
|
||||||
|
Profile: "high",
|
||||||
|
Level: "5.1",
|
||||||
|
Qmin: "15",
|
||||||
|
Qmax: "24",
|
||||||
|
BFrames: "5",
|
||||||
|
BAdapt: "2",
|
||||||
|
NGOP: "250",
|
||||||
|
NGOPMin: "30",
|
||||||
|
Scenecut: "80",
|
||||||
|
InfraRefresh: "0",
|
||||||
|
LookAhead: "60",
|
||||||
|
SlicedThreads: "0",
|
||||||
|
SyncLookAhead: "1",
|
||||||
|
ForceIDR: "0",
|
||||||
|
AQMode: "0",
|
||||||
|
AQStrength: "1.3",
|
||||||
|
MBTree: "1",
|
||||||
|
Bitrate: "15000",
|
||||||
|
VBVMaxBitrate: "20000",
|
||||||
|
VBVBuffer: "30000",
|
||||||
|
RateTol: "2.0",
|
||||||
|
Threads: "0",
|
||||||
|
AnnexB: "1",
|
||||||
|
Aud: "0",
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithX264DefaultOptions(encoder *Encoder) error {
|
||||||
|
encoder.encoderSettings = DefaultX264Settings
|
||||||
|
return encoder.encoderSettings.ForEach(func(key, value string) error {
|
||||||
|
return encoder.codecFlags.Set(key, value, 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithX264HighQualityOptions(encoder *Encoder) error {
|
||||||
|
encoder.encoderSettings = HighQualityX264Settings
|
||||||
|
return encoder.encoderSettings.ForEach(func(key, value string) error {
|
||||||
|
return encoder.codecFlags.Set(key, value, 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithX264LowLatencyOptions(encoder *Encoder) error {
|
||||||
|
encoder.encoderSettings = LowLatencyX264Settings
|
||||||
|
return encoder.encoderSettings.ForEach(func(key, value string) error {
|
||||||
|
return encoder.codecFlags.Set(key, value, 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithX264LowBandwidthOptions(encoder *Encoder) error {
|
||||||
|
encoder.encoderSettings = LowBandwidthX264Settings
|
||||||
|
return encoder.encoderSettings.ForEach(func(key, value string) error {
|
||||||
|
return encoder.codecFlags.Set(key, value, 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user