347 lines
6.8 KiB
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)
|
|
}
|
|
}
|