third commit

This commit is contained in:
harshabose
2025-02-25 14:49:04 +05:30
parent 0dd14b3702
commit 186d3a1c0a
2 changed files with 247 additions and 57 deletions

View File

@@ -19,7 +19,7 @@ type Encoder struct {
codec *astiav.Codec
encoderContext *astiav.CodecContext
codecFlags *astiav.Dictionary
encoderSettings encoderCodecSetting
encoderSettings codecSettings
bandwidthChan chan int64
sps []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()),
filter: filter,
codecFlags: astiav.NewDictionary(),
encoderSettings: EncoderCodecNoSetting,
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
}
@@ -55,7 +54,7 @@ func CreateEncoder(ctx context.Context, codecID astiav.CodecID, filter *Filter,
return nil, err
}
encoder.findParameterSets(encoder.encoderContext.ExtraData())
//encoder.findParameterSets(encoder.encoderContext.ExtraData())
return encoder, nil
}
@@ -85,7 +84,7 @@ loop1:
select {
case <-encoder.ctx.Done():
return
case bitrate := <-encoder.bandwidthChan:
case bitrate := <-encoder.bandwidthChan: // TODO: MIGHT NEED A MUTEX FOR THIS ONE CASE
encoder.encoderContext.SetBitRate(bitrate)
case frame = <-encoder.filter.WaitForFrame():
if err = encoder.encoderContext.SendFrame(frame); err != nil {
@@ -138,45 +137,45 @@ func (encoder *Encoder) SetBitrateChannel(channel chan int64) {
encoder.bandwidthChan = channel
}
func (encoder *Encoder) findParameterSets(extraData []byte) {
if len(extraData) > 0 {
// Find first start code (0x00000001)
for i := 0; i < len(extraData)-4; i++ {
if extraData[i] == 0 && extraData[i+1] == 0 && extraData[i+2] == 0 && extraData[i+3] == 1 {
// Skip start code to get NAL type
nalType := extraData[i+4] & 0x1F
// Find next start code or end
nextStart := len(extraData)
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 {
nextStart = j
break
}
}
if nalType == 7 { // SPS
encoder.sps = make([]byte, nextStart-i)
copy(encoder.sps, extraData[i:nextStart])
} else if nalType == 8 { // PPS
encoder.pps = make([]byte, len(extraData)-i)
copy(encoder.pps, extraData[i:])
}
i = nextStart - 1
}
}
}
}
func (encoder *Encoder) GetSPS() []byte {
return encoder.sps
}
func (encoder *Encoder) GetPPS() []byte {
return encoder.pps
}
//func (encoder *Encoder) findParameterSets(extraData []byte) {
// if len(extraData) > 0 {
// // Find first start code (0x00000001)
// for i := 0; i < len(extraData)-4; i++ {
// if extraData[i] == 0 && extraData[i+1] == 0 && extraData[i+2] == 0 && extraData[i+3] == 1 {
// // Skip start code to get NAL type
// nalType := extraData[i+4] & 0x1F
//
// // Find next start code or end
// nextStart := len(extraData)
// 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 {
// nextStart = j
// break
// }
// }
//
// if nalType == 7 { // SPS
// encoder.sps = make([]byte, nextStart-i)
// copy(encoder.sps, extraData[i:nextStart])
// } else if nalType == 8 { // PPS
// encoder.pps = make([]byte, len(extraData)-i)
// copy(encoder.pps, extraData[i:])
// }
//
// i = nextStart - 1
// }
// }
// }
//
//}
//
//func (encoder *Encoder) GetSPS() []byte {
// return encoder.sps
//}
//
//func (encoder *Encoder) GetPPS() []byte {
// return encoder.pps
//}
func (encoder *Encoder) close() {
if encoder.encoderContext != nil {

View File

@@ -1,14 +1,205 @@
package transcode
import "reflect"
type (
encoderCodecSetting string
EncoderOption = func(*Encoder) error
)
const (
EncoderCodecNoSetting encoderCodecSetting = "None"
EncoderCodecDefaultSetting encoderCodecSetting = "default"
EncoderCodecHighQualitySetting encoderCodecSetting = "high-quality"
EncoderCodecLowLatencySetting encoderCodecSetting = "low-latency"
EncoderCodecLowBandwidthSetting encoderCodecSetting = "low-bandwidth"
)
type codecSettings interface {
ForEach(func(string, string) error) error
}
type X264Settings struct {
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)
})
}