goffmpeg/pkg/ffmpeg/codec.go

347 lines
6.8 KiB
Go

package ffmpeg
/*
#include <libavcodec/avcodec.h>
static enum AVMediaType codec_get_type(const AVCodec *c) {
return c->type;
}
*/
import "C"
import "unsafe"
// CodecType represents the type of codec
type CodecType int
const (
CodecTypeVideo CodecType = CodecType(C.AVMEDIA_TYPE_VIDEO)
CodecTypeAudio CodecType = CodecType(C.AVMEDIA_TYPE_AUDIO)
CodecTypeSubtitle CodecType = CodecType(C.AVMEDIA_TYPE_SUBTITLE)
)
// Codec represents an FFmpeg codec
type Codec struct {
ptr *C.AVCodec
}
// FindDecoder finds a decoder by name
func FindDecoder(name string) (*Codec, error) {
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
ptr := C.avcodec_find_decoder_by_name(cName)
if ptr == nil {
return nil, ErrCodecNotFound
}
return &Codec{ptr: ptr}, nil
}
// FindEncoder finds an encoder by name
func FindEncoder(name string) (*Codec, error) {
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
ptr := C.avcodec_find_encoder_by_name(cName)
if ptr == nil {
return nil, ErrCodecNotFound
}
return &Codec{ptr: ptr}, nil
}
// CodecFromC converts a C pointer to Codec
func CodecFromC(ptr *C.AVCodec) *Codec {
return &Codec{ptr: ptr}
}
// CPtr returns the underlying C pointer
func (c *Codec) CPtr() *C.AVCodec {
return c.ptr
}
// Name returns the codec name
func (c *Codec) Name() string {
if c.ptr == nil {
return ""
}
return C.GoString(c.ptr.name)
}
// LongName returns the codec long name
func (c *Codec) LongName() string {
if c.ptr == nil {
return ""
}
return C.GoString(c.ptr.long_name)
}
// Type returns the codec type
func (c *Codec) Type() CodecType {
if c.ptr == nil {
return CodecType(0)
}
t := C.codec_get_type(c.ptr)
return CodecType(t)
}
// ID returns the codec ID
func (c *Codec) ID() int {
if c.ptr == nil {
return 0
}
return int(c.ptr.id)
}
// Context represents a codec context
type Context struct {
ptr *C.AVCodecContext
}
// AllocContext allocates a codec context
func AllocContext() *Context {
return &Context{
ptr: C.avcodec_alloc_context3(nil),
}
}
// Free frees the codec context
func (c *Context) Free() {
if c.ptr != nil {
C.avcodec_free_context(&c.ptr)
c.ptr = nil
}
}
// ContextFromC converts a C pointer to Context
func ContextFromC(ptr *C.AVCodecContext) *Context {
return &Context{ptr: ptr}
}
// CPtr returns the underlying C pointer
func (c *Context) CPtr() *C.AVCodecContext {
return c.ptr
}
// SetCodec sets the codec for this context
func (c *Context) SetCodec(codec *Codec) error {
if c.ptr == nil || codec == nil || codec.ptr == nil {
return ErrInvalidCodec
}
C.avcodec_free_context(&c.ptr)
c.ptr = C.avcodec_alloc_context3(codec.ptr)
if c.ptr == nil {
return ErrInvalidCodec
}
return nil
}
// Width returns the width
func (c *Context) Width() int {
if c.ptr == nil {
return 0
}
return int(c.ptr.width)
}
// SetWidth sets the width
func (c *Context) SetWidth(width int) {
if c.ptr != nil {
c.ptr.width = C.int(width)
}
}
// Height returns the height
func (c *Context) Height() int {
if c.ptr == nil {
return 0
}
return int(c.ptr.height)
}
// SetHeight sets the height
func (c *Context) SetHeight(height int) {
if c.ptr != nil {
c.ptr.height = C.int(height)
}
}
// Format returns the pixel/sample format
func (c *Context) Format() int {
if c.ptr == nil {
return -1
}
return int(c.ptr.sample_fmt)
}
// SetFormat sets the pixel/sample format
func (c *Context) SetFormat(format int) {
if c.ptr != nil {
// Use unsafe.Pointer to assign to the enum field
*(*C.int)(unsafe.Pointer(&c.ptr.sample_fmt)) = C.int(format)
}
}
// BitRate returns the bit rate
func (c *Context) BitRate() int64 {
if c.ptr == nil {
return 0
}
return int64(c.ptr.bit_rate)
}
// SetBitRate sets the bit rate
func (c *Context) SetBitRate(br int64) {
if c.ptr != nil {
c.ptr.bit_rate = C.int64_t(br)
}
}
// TimeBase returns the time base
func (c *Context) TimeBase() Rational {
if c.ptr == nil {
return Rational{}
}
return Rational{
num: int(c.ptr.time_base.num),
den: int(c.ptr.time_base.den),
}
}
// SetTimeBase sets the time base
func (c *Context) SetTimeBase(r Rational) {
if c.ptr != nil {
c.ptr.time_base.num = C.int(r.num)
c.ptr.time_base.den = C.int(r.den)
}
}
// SetChannelLayout sets the channel layout
func (c *Context) SetChannelLayout(layout uint64) {
if c.ptr != nil {
c.ptr.channel_layout = C.uint64_t(layout)
}
}
// SetSampleRate sets the sample rate
func (c *Context) SetSampleRate(rate int) {
if c.ptr != nil {
c.ptr.sample_rate = C.int(rate)
}
}
// Channels returns the number of channels
func (c *Context) Channels() int {
if c.ptr == nil {
return 0
}
return int(c.ptr.channels)
}
// Open opens the codec
func (c *Context) Open(codec *Codec) error {
if c.ptr == nil || codec == nil || codec.ptr == nil {
return ErrInvalidCodec
}
ret := C.avcodec_open2(c.ptr, codec.ptr, nil)
if ret < 0 {
return &FFmpegError{
Code: int(ret),
Message: "failed to open codec",
Op: "Open",
}
}
return nil
}
// CopyParameters copies parameters from CodecParameters to this context
func (c *Context) CopyParameters(cp *CodecParameters) error {
if c.ptr == nil || cp == nil || cp.ptr == nil {
return ErrInvalidCodec
}
ret := C.avcodec_parameters_to_context(c.ptr, cp.ptr)
if ret < 0 {
return &FFmpegError{
Code: int(ret),
Message: "failed to copy parameters",
Op: "CopyParameters",
}
}
return nil
}
// SendPacket sends a packet to the decoder
func (c *Context) SendPacket(pkt *Packet) error {
if c.ptr == nil {
return ErrInvalidCodec
}
ret := C.avcodec_send_packet(c.ptr, pkt.CPtr())
if ret < 0 {
return &FFmpegError{
Code: int(ret),
Message: "failed to send packet",
Op: "SendPacket",
}
}
return nil
}
// ReceiveFrame receives a frame from the decoder
func (c *Context) ReceiveFrame(frame *Frame) error {
if c.ptr == nil {
return ErrInvalidCodec
}
ret := C.avcodec_receive_frame(c.ptr, frame.CPtr())
if ret < 0 {
return &FFmpegError{
Code: int(ret),
Message: "failed to receive frame",
Op: "ReceiveFrame",
}
}
return nil
}
// SendFrame sends a frame to the encoder
func (c *Context) SendFrame(frame *Frame) error {
if c.ptr == nil {
return ErrInvalidCodec
}
ret := C.avcodec_send_frame(c.ptr, frame.CPtr())
if ret < 0 {
return &FFmpegError{
Code: int(ret),
Message: "failed to send frame",
Op: "SendFrame",
}
}
return nil
}
// ReceivePacket receives a packet from the encoder
func (c *Context) ReceivePacket(pkt *Packet) error {
if c.ptr == nil {
return ErrInvalidCodec
}
ret := C.avcodec_receive_packet(c.ptr, pkt.CPtr())
if ret < 0 {
return &FFmpegError{
Code: int(ret),
Message: "failed to receive packet",
Op: "ReceivePacket",
}
}
return nil
}
// Close closes the codec
func (c *Context) Close() {
if c.ptr != nil {
C.avcodec_close(c.ptr)
}
}