diff --git a/config.go b/config.go index 0d3f77c..46d28f3 100644 --- a/config.go +++ b/config.go @@ -6,6 +6,7 @@ import ( "go.uber.org/zap" ) +// Config imagorvideo config.Option func Config(fs *flag.FlagSet, cb func() (*zap.Logger, bool)) imagor.Option { var ( ffmpegFallbackImage = fs.String("ffmpeg-fallback-image", "", diff --git a/ffmpeg/errors.go b/ffmpeg/errors.go index 42c4685..0ffd823 100644 --- a/ffmpeg/errors.go +++ b/ffmpeg/errors.go @@ -5,6 +5,7 @@ import "C" type avError int +// AV Error enum const ( ErrNoMem = avError(-C.ENOMEM) ErrEOF = avError(C.AVERROR_EOF) @@ -31,6 +32,7 @@ func (e avError) errorString() string { } } +// Error implements error interface func (e avError) Error() string { return "ffmpeg: " + e.errorString() } diff --git a/ffmpeg/ffmpeg.go b/ffmpeg/ffmpeg.go index 09d5fab..2187d89 100644 --- a/ffmpeg/ffmpeg.go +++ b/ffmpeg/ffmpeg.go @@ -20,6 +20,7 @@ const ( hasAudio = 2 ) +// Metadata AV metadata type Metadata struct { Orientation int `json:"orientation"` Duration int `json:"duration,omitempty"` @@ -32,6 +33,7 @@ type Metadata struct { HasAudio bool `json:"has_audio"` } +// AVContext manages lifecycle of AV contexts and reader stream type AVContext struct { opaque unsafe.Pointer reader io.Reader @@ -55,6 +57,7 @@ type AVContext struct { closed bool } +// LoadAVContext load and create AVContext from reader stream func LoadAVContext(reader io.Reader, size int64) (*AVContext, error) { av := &AVContext{ reader: reader, @@ -77,6 +80,8 @@ func LoadAVContext(reader io.Reader, size int64) (*AVContext, error) { return av, createDecoder(av) } +// ProcessFrames triggers frame processing +// limit under max num of frames if maxFrames > 0 func (av *AVContext) ProcessFrames(maxFrames int) (err error) { if av.formatContext == nil || av.codecContext == nil { return ErrDecoderNotFound @@ -87,6 +92,7 @@ func (av *AVContext) ProcessFrames(maxFrames int) (err error) { return } +// SelectFrame triggers frame processing and select specific frame index func (av *AVContext) SelectFrame(n int) (err error) { nn := C.int(n - 1) if av.thumbContext != nil && nn > av.availableIndex { @@ -104,6 +110,8 @@ func (av *AVContext) SelectPosition(f float64) (err error) { return av.SelectDuration(av.positionToDuration(f)) } +// SelectDuration seeks to keyframe before the specified duration +// then process frames to find precise duration func (av *AVContext) SelectDuration(ts time.Duration) (err error) { if ts > 0 { av.selectedDuration = ts @@ -116,14 +124,18 @@ func (av *AVContext) SelectDuration(ts time.Duration) (err error) { } } +// SeekPosition seeks to keyframe before specified position percentage between 0 and 1 +// then process frames to find precise position func (av *AVContext) SeekPosition(f float64) error { return av.SeekDuration(av.positionToDuration(f)) } +// SeekDuration seeks to keyframe before the specified duration func (av *AVContext) SeekDuration(ts time.Duration) error { return seekDuration(av, ts) } +// Export frame to RGB or RGBA buffer func (av *AVContext) Export(bands int) (buf []byte, err error) { if err = av.ProcessFrames(-1); err != nil { return @@ -137,10 +149,12 @@ func (av *AVContext) Export(bands int) (buf []byte, err error) { return exportBuffer(av, bands) } +// Close AVContext objects func (av *AVContext) Close() { closeAVContext(av) } +// Metadata AV metadata func (av *AVContext) Metadata() *Metadata { var fps float64 if av.stream != nil { diff --git a/ffmpeg/logging.go b/ffmpeg/logging.go index c8453cd..2ac0528 100644 --- a/ffmpeg/logging.go +++ b/ffmpeg/logging.go @@ -8,7 +8,7 @@ import "sync" // AVLogLevel defines the ffmpeg threshold for dumping information to stderr. type AVLogLevel int -// Possible values for AVLogLevel. +// AVLogLevel enum const ( AVLogQuiet AVLogLevel = (iota - 1) * 8 AVLogPanic @@ -35,6 +35,7 @@ func SetFFmpegLogLevel(logLevel AVLogLevel) { type LoggingHandlerFunction func(messageLevel AVLogLevel, message string) +// SetLogging set AV logging handler func SetLogging(handler LoggingHandlerFunction) { onceLogging.Do(func() { C.goavLogSetup() diff --git a/option.go b/option.go index 3eee880..50835b2 100644 --- a/option.go +++ b/option.go @@ -2,14 +2,17 @@ package imagorvideo import "go.uber.org/zap" +// Option imagorvideo option type Option func(p *Processor) +// WithDebug with debug option func WithDebug(debug bool) Option { return func(p *Processor) { p.Debug = debug } } +// WithLogger with logger option func WithLogger(logger *zap.Logger) Option { return func(p *Processor) { if logger != nil { @@ -18,6 +21,7 @@ func WithLogger(logger *zap.Logger) Option { } } +// WithFallbackImage with fallback imagor option on error func WithFallbackImage(image string) Option { return func(p *Processor) { p.FallbackImage = image diff --git a/processor.go b/processor.go index 2b9c5e7..4741dbe 100644 --- a/processor.go +++ b/processor.go @@ -13,12 +13,14 @@ import ( "time" ) +// Processor for imagorvideo that implements imagor.Processor interface type Processor struct { Logger *zap.Logger Debug bool FallbackImage string } +// NewProcessor creates Processor func NewProcessor(options ...Option) *Processor { p := &Processor{ Logger: zap.NewNop(), @@ -29,6 +31,7 @@ func NewProcessor(options ...Option) *Processor { return p } +// Startup implements imagor.Processor interface func (p *Processor) Startup(_ context.Context) error { ffmpeg.SetLogging(func(level ffmpeg.AVLogLevel, message string) { message = strings.TrimSuffix(message, "\n") @@ -49,10 +52,12 @@ func (p *Processor) Startup(_ context.Context) error { return nil } +// Shutdown implements imagor.Processor interface func (p *Processor) Shutdown(_ context.Context) error { return nil } +// Process implements imagor.Processor interface func (p *Processor) Process(ctx context.Context, in *imagor.Blob, params imagorpath.Params, load imagor.LoadFunc) (out *imagor.Blob, err error) { defer func() { if err == nil || out != nil { @@ -179,6 +184,7 @@ func (p *Processor) Process(ctx context.Context, in *imagor.Blob, params imagorp return } +// Metadata imagorvideo metadata type Metadata struct { Format string `json:"format"` ContentType string `json:"content_type"`