change repo to github.com/nareix/ffmpeg
This commit is contained in:
parent
0971d60a78
commit
7453318fd5
77
README.md
77
README.md
@ -1,77 +0,0 @@
|
||||
|
||||
codec
|
||||
====
|
||||
|
||||
Golang aac/h264 encoder and decoder.
|
||||
|
||||
H264 encoding example:
|
||||
|
||||
```go
|
||||
w := 400
|
||||
h := 400
|
||||
var nal [][]byte
|
||||
|
||||
c, _ := codec.NewH264Encoder(w, h, image.YCbCrSubsampleRatio420)
|
||||
nal = append(nal, c.Header)
|
||||
|
||||
for i := 0; i < 60; i++ {
|
||||
img := image.NewYCbCr(image.Rect(0,0,w,h), image.YCbCrSubsampleRatio420)
|
||||
p, _ := c.Encode(img)
|
||||
if len(p.Data) > 0 {
|
||||
nal = append(nal, p.Data)
|
||||
}
|
||||
}
|
||||
for {
|
||||
// flush encoder
|
||||
p, err := c.Encode(nil)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
nal = append(nal, p.Data)
|
||||
}
|
||||
```
|
||||
|
||||
H264 decoding example:
|
||||
|
||||
```go
|
||||
dec, err := codec.NewH264Decoder(nal[0])
|
||||
for i, n := range nal[1:] {
|
||||
img, err := dec.Decode(n)
|
||||
if err == nil {
|
||||
fp, _ := os.Create(fmt.Sprintf("/tmp/dec-%d.jpg", i))
|
||||
jpeg.Encode(fp, img, nil)
|
||||
fp.Close()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
AAC encoding example:
|
||||
|
||||
```go
|
||||
var pkts [][]byte
|
||||
|
||||
c, _ := codec.NewAACEncoder()
|
||||
pkts = append(pkts, c.Header)
|
||||
|
||||
for i := 0; i < 60; i++ {
|
||||
var sample [8192]byte
|
||||
p, _ := c.Encode(sample)
|
||||
if len(p) > 0 {
|
||||
pkts = append(pkts, p)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
AAC decoding example:
|
||||
|
||||
```go
|
||||
dec, _ := codec.NewAACDecoder(pkts[0])
|
||||
for _, p := range pkts[1:] {
|
||||
sample, err := dec.Decode(p)
|
||||
}
|
||||
```
|
||||
|
||||
License
|
||||
----
|
||||
|
||||
All code is under WTFPL. You can use it for everything as you want :)
|
82
aacdec.go
82
aacdec.go
@ -1,82 +0,0 @@
|
||||
package codec
|
||||
|
||||
import (
|
||||
/*
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/avutil.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct {
|
||||
AVCodec *c;
|
||||
AVCodecContext *ctx;
|
||||
AVFrame *f;
|
||||
int got;
|
||||
} aacdec_t ;
|
||||
|
||||
static int aacdec_new(aacdec_t *m, uint8_t *buf, int len) {
|
||||
m->c = avcodec_find_decoder(CODEC_ID_AAC);
|
||||
m->ctx = avcodec_alloc_context3(m->c);
|
||||
m->f = av_frame_alloc();
|
||||
m->ctx->extradata = buf;
|
||||
m->ctx->extradata_size = len;
|
||||
m->ctx->debug = 0x3;
|
||||
av_log(m->ctx, AV_LOG_DEBUG, "m %p\n", m);
|
||||
return avcodec_open2(m->ctx, m->c, 0);
|
||||
}
|
||||
|
||||
static int aacdec_decode(aacdec_t *m, uint8_t *data, int len) {
|
||||
AVPacket pkt;
|
||||
av_init_packet(&pkt);
|
||||
pkt.data = data;
|
||||
pkt.size = len;
|
||||
av_log(m->ctx, AV_LOG_DEBUG, "decode %p\n", m);
|
||||
return avcodec_decode_audio4(m->ctx, m->f, &m->got, &pkt);
|
||||
}
|
||||
*/
|
||||
"C"
|
||||
"errors"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type AACDecoder struct {
|
||||
m C.aacdec_t
|
||||
}
|
||||
|
||||
func NewAACDecoder(header []byte) (m *AACDecoder, err error) {
|
||||
m = &AACDecoder{}
|
||||
r := C.aacdec_new(&m.m,
|
||||
(*C.uint8_t)(unsafe.Pointer(&header[0])),
|
||||
(C.int)(len(header)),
|
||||
)
|
||||
if int(r) < 0 {
|
||||
err = errors.New("open codec failed")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (m *AACDecoder) Decode(data []byte) (sample []byte, err error) {
|
||||
r := C.aacdec_decode(
|
||||
&m.m,
|
||||
(*C.uint8_t)(unsafe.Pointer(&data[0])),
|
||||
(C.int)(len(data)),
|
||||
)
|
||||
if int(r) < 0 {
|
||||
err = errors.New("decode failed")
|
||||
return
|
||||
}
|
||||
if int(m.m.got) == 0 {
|
||||
err = errors.New("no data")
|
||||
return
|
||||
}
|
||||
size := int(m.m.f.linesize[0]) * 2
|
||||
sample = make([]byte, size*2)
|
||||
for i := 0; i < 2; i++ {
|
||||
C.memcpy(
|
||||
unsafe.Pointer(&sample[i*size]),
|
||||
unsafe.Pointer(m.m.f.data[i]),
|
||||
(C.size_t)(size),
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
93
aacenc.go
93
aacenc.go
@ -1,93 +0,0 @@
|
||||
package codec
|
||||
|
||||
import (
|
||||
/*
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/avutil.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
AVCodec *c;
|
||||
AVCodecContext *ctx;
|
||||
AVFrame *f;
|
||||
int got;
|
||||
uint8_t buf[1024*10]; int size;
|
||||
int samplerate; int bitrate;
|
||||
int channels;
|
||||
} aacenc_t ;
|
||||
|
||||
static int aacenc_new(aacenc_t *m) {
|
||||
m->c = avcodec_find_encoder_by_name("aac");
|
||||
m->ctx = avcodec_alloc_context3(m->c);
|
||||
m->ctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
|
||||
m->ctx->sample_rate = m->samplerate;
|
||||
m->ctx->bit_rate = m->bitrate;
|
||||
m->ctx->channels = m->channels;
|
||||
m->ctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
|
||||
m->f = av_frame_alloc();
|
||||
int r = avcodec_open2(m->ctx, m->c, 0);
|
||||
//av_log(m->ctx, AV_LOG_DEBUG, "extra %d\n", m->ctx->extradata_size);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void aacenc_encode(aacenc_t *m) {
|
||||
AVPacket pkt;
|
||||
av_init_packet(&pkt);
|
||||
pkt.data = m->buf;
|
||||
pkt.size = sizeof(m->buf);
|
||||
m->f->nb_samples = 1024;
|
||||
m->f->extended_data = m->f->data;
|
||||
m->f->linesize[0] = 1024*4;
|
||||
//m->f->linesize[1] = 1024*4;
|
||||
avcodec_encode_audio2(m->ctx, &pkt, m->f, &m->got);
|
||||
av_log(m->ctx, AV_LOG_DEBUG, "got %d size %d\n", m->got, pkt.size);
|
||||
m->size = pkt.size;
|
||||
}
|
||||
*/
|
||||
"C"
|
||||
"errors"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type AACEncoder struct {
|
||||
m C.aacenc_t
|
||||
Header []byte
|
||||
}
|
||||
|
||||
// only supported fltp,stereo,44100HZ. If you need other config, it's easy to modify code
|
||||
func NewAACEncoder() (m *AACEncoder, err error) {
|
||||
m = &AACEncoder{}
|
||||
m.m.samplerate = 44100
|
||||
m.m.bitrate = 50000
|
||||
m.m.channels = 1
|
||||
r := C.aacenc_new(&m.m)
|
||||
if int(r) != 0 {
|
||||
err = errors.New("open codec failed")
|
||||
return
|
||||
}
|
||||
m.Header = make([]byte, (int)(m.m.ctx.extradata_size))
|
||||
C.memcpy(
|
||||
unsafe.Pointer(&m.Header[0]),
|
||||
unsafe.Pointer(m.m.ctx.extradata),
|
||||
(C.size_t)(len(m.Header)),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
func (m *AACEncoder) Encode(sample []byte) (ret []byte, err error) {
|
||||
m.m.f.data[0] = (*C.uint8_t)(unsafe.Pointer(&sample[0]))
|
||||
//m.m.f.data[1] = (*C.uint8_t)(unsafe.Pointer(&sample[1024*4]))
|
||||
C.aacenc_encode(&m.m)
|
||||
if int(m.m.got) == 0 {
|
||||
err = errors.New("no data")
|
||||
return
|
||||
}
|
||||
ret = make([]byte, (int)(m.m.size))
|
||||
C.memcpy(
|
||||
unsafe.Pointer(&ret[0]),
|
||||
unsafe.Pointer(&m.m.buf[0]),
|
||||
(C.size_t)(m.m.size),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
189
audio.go
189
audio.go
@ -1,189 +0,0 @@
|
||||
package codec
|
||||
|
||||
import (
|
||||
/*
|
||||
#include "ffmpeg.h"
|
||||
int wrap_avcodec_decode_audio4(AVCodecContext *ctx, AVFrame *frame, void *data, int size, int *got) {
|
||||
struct AVPacket pkt = {.data = data, .size = size};
|
||||
return avcodec_decode_audio4(ctx, frame, got, &pkt);
|
||||
}
|
||||
void set_sample_fmt(AVCodecContext *ctx, int sample_fmt) {
|
||||
ctx->sample_fmt = sample_fmt;
|
||||
}
|
||||
int wrap_av_get_bytes_per_sample(int sample_fmt) {
|
||||
return av_get_bytes_per_sample(sample_fmt);
|
||||
}
|
||||
*/
|
||||
"C"
|
||||
"unsafe"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type SampleFormat int
|
||||
|
||||
func (self SampleFormat) BytesPerSample() int {
|
||||
return int(C.wrap_av_get_bytes_per_sample(C.int(self)))
|
||||
}
|
||||
|
||||
const (
|
||||
S16 = SampleFormat(C.AV_SAMPLE_FMT_S16)
|
||||
FLTP = SampleFormat(C.AV_SAMPLE_FMT_FLTP)
|
||||
)
|
||||
|
||||
type AudioEncoder struct {
|
||||
ff C.FFCtx
|
||||
SampleRate int
|
||||
BitRate int
|
||||
ChannelCount int
|
||||
SampleFormat SampleFormat
|
||||
FrameSampleCount int
|
||||
}
|
||||
|
||||
func (self *AudioEncoder) Setup() (err error) {
|
||||
ff := &self.ff
|
||||
|
||||
ff.frame = C.av_frame_alloc()
|
||||
if self.BitRate == 0 {
|
||||
self.BitRate = 50000
|
||||
}
|
||||
C.set_sample_fmt(ff.codecCtx, C.int(self.SampleFormat))
|
||||
ff.codecCtx.sample_rate = C.int(self.SampleRate)
|
||||
ff.codecCtx.bit_rate = C.int(self.BitRate)
|
||||
ff.codecCtx.channels = C.int(self.ChannelCount)
|
||||
ff.codecCtx.strict_std_compliance = C.FF_COMPLIANCE_EXPERIMENTAL
|
||||
if C.avcodec_open2(ff.codecCtx, ff.codec, nil) != 0 {
|
||||
err = fmt.Errorf("avcodec_open2 failed")
|
||||
return
|
||||
}
|
||||
self.SampleFormat = SampleFormat(int(ff.codecCtx.sample_fmt))
|
||||
self.ChannelCount = int(ff.codecCtx.channels)
|
||||
self.FrameSampleCount = int(ff.codecCtx.frame_size)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (self *AudioEncoder) Extradata() (data []byte) {
|
||||
data = C.GoBytes(unsafe.Pointer(self.ff.codecCtx.extradata), self.ff.codecCtx.extradata_size)
|
||||
return
|
||||
}
|
||||
|
||||
func (self *AudioEncoder) Encode(sample []byte, flush bool) (gotPkt bool, pkt []byte, err error) {
|
||||
ff := &self.ff
|
||||
nbSamples := self.FrameSampleCount
|
||||
channelCount := int(ff.codecCtx.channels)
|
||||
sampleSize := int(C.av_get_bytes_per_sample(ff.codecCtx.sample_fmt))
|
||||
expectedSize := nbSamples*sampleSize*channelCount
|
||||
|
||||
frame := ff.frame
|
||||
if flush {
|
||||
frame = nil
|
||||
} else {
|
||||
if len(sample) != expectedSize {
|
||||
err = fmt.Errorf("len(sample) should be %d", expectedSize)
|
||||
return
|
||||
}
|
||||
|
||||
frame.nb_samples = C.int(nbSamples)
|
||||
frame.format = C.int(ff.codecCtx.sample_fmt)
|
||||
frame.channel_layout = ff.codecCtx.channel_layout
|
||||
if C.av_sample_fmt_is_planar(ff.codecCtx.sample_fmt) != 0 {
|
||||
for i := 0; i < self.ChannelCount; i++ {
|
||||
frame.data[i] = (*C.uint8_t)(unsafe.Pointer(&sample[i*nbSamples*sampleSize]))
|
||||
frame.linesize[i] = C.int(nbSamples*sampleSize)
|
||||
}
|
||||
} else {
|
||||
frame.data[0] = (*C.uint8_t)(unsafe.Pointer(&sample[0]))
|
||||
frame.linesize[0] = C.int(channelCount*nbSamples*sampleSize)
|
||||
}
|
||||
//frame.extended_data = &frame.data[0]
|
||||
}
|
||||
|
||||
cpkt := C.AVPacket{}
|
||||
cgotpkt := C.int(0)
|
||||
cerr := C.avcodec_encode_audio2(self.ff.codecCtx, &cpkt, frame, &cgotpkt)
|
||||
if cerr < C.int(0) {
|
||||
err = fmt.Errorf("avcodec_encode_audio2 failed: %d", cerr)
|
||||
return
|
||||
}
|
||||
|
||||
if cgotpkt != 0 {
|
||||
gotPkt = true
|
||||
pkt = C.GoBytes(unsafe.Pointer(cpkt.data), cpkt.size)
|
||||
C.av_free_packet(&cpkt)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type AudioDecoder struct {
|
||||
ff C.FFCtx
|
||||
ChannelCount int
|
||||
SampleFormat SampleFormat
|
||||
Extradata []byte
|
||||
}
|
||||
|
||||
func (self *AudioDecoder) Setup() (err error) {
|
||||
ff := &self.ff
|
||||
|
||||
ff.frame = C.av_frame_alloc()
|
||||
|
||||
if len(self.Extradata) > 0 {
|
||||
ff.codecCtx.extradata = (*C.uint8_t)(unsafe.Pointer(&self.Extradata[0]))
|
||||
ff.codecCtx.extradata_size = C.int(len(self.Extradata))
|
||||
}
|
||||
|
||||
ff.codecCtx.channels = C.int(self.ChannelCount)
|
||||
if C.avcodec_open2(ff.codecCtx, ff.codec, nil) != 0 {
|
||||
err = fmt.Errorf("avcodec_open2 failed")
|
||||
return
|
||||
}
|
||||
self.SampleFormat = SampleFormat(int(ff.codecCtx.sample_fmt))
|
||||
self.ChannelCount = int(ff.codecCtx.channels)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (self *AudioDecoder) Decode(frame []byte) (gotPkt bool, pkt []byte, err error) {
|
||||
ff := &self.ff
|
||||
|
||||
cgotpkt := C.int(0)
|
||||
cerr := C.wrap_avcodec_decode_audio4(ff.codecCtx, ff.frame, unsafe.Pointer(&frame[0]), C.int(len(frame)), &cgotpkt)
|
||||
if cerr < C.int(0) {
|
||||
err = fmt.Errorf("avcodec_decode_audio4 failed: %d", cerr)
|
||||
return
|
||||
}
|
||||
|
||||
if cgotpkt != C.int(0) {
|
||||
gotPkt = true
|
||||
//pkt = C.GoBytes(unsafe.Pointer(cpkt.data), cpkt.size)
|
||||
size := C.av_samples_get_buffer_size(nil, ff.codecCtx.channels, ff.frame.nb_samples, ff.codecCtx.sample_fmt, C.int(1))
|
||||
pkt = C.GoBytes(unsafe.Pointer(ff.frame.data[0]), size)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func FindAudioEncoderByName(name string) (enc *AudioEncoder) {
|
||||
ff := C.FFCtx{}
|
||||
ff.codec = C.avcodec_find_encoder_by_name(C.CString(name))
|
||||
if ff.codec != nil {
|
||||
ff.codecCtx = C.avcodec_alloc_context3(ff.codec)
|
||||
if ff.codecCtx != nil {
|
||||
return &AudioEncoder{ff: ff}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func FindAudioDecoderByName(name string) (dec *AudioDecoder) {
|
||||
ff := C.FFCtx{}
|
||||
ff.codec = C.avcodec_find_decoder_by_name(C.CString(name))
|
||||
if ff.codec != nil {
|
||||
ff.codecCtx = C.avcodec_alloc_context3(ff.codec)
|
||||
if ff.codecCtx != nil {
|
||||
return &AudioDecoder{ff: ff}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
11
ffmpeg.h
11
ffmpeg.h
@ -1,11 +0,0 @@
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/avutil.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
AVCodec *codec;
|
||||
AVCodecContext *codecCtx;
|
||||
AVFrame *frame;
|
||||
} FFCtx;
|
||||
|
88
h264dec.go
88
h264dec.go
@ -1,88 +0,0 @@
|
||||
package codec
|
||||
|
||||
import (
|
||||
/*
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/avutil.h>
|
||||
|
||||
typedef struct {
|
||||
AVCodec *c;
|
||||
AVCodecContext *ctx;
|
||||
AVFrame *f;
|
||||
int got;
|
||||
} h264dec_t ;
|
||||
|
||||
static int h264dec_new(h264dec_t *h, uint8_t *data, int len) {
|
||||
h->c = avcodec_find_decoder(CODEC_ID_H264);
|
||||
h->ctx = avcodec_alloc_context3(h->c);
|
||||
h->f = av_frame_alloc();
|
||||
h->ctx->extradata = data;
|
||||
h->ctx->extradata_size = len;
|
||||
h->ctx->debug = 0x3;
|
||||
return avcodec_open2(h->ctx, h->c, 0);
|
||||
}
|
||||
|
||||
static int h264dec_decode(h264dec_t *h, uint8_t *data, int len) {
|
||||
AVPacket pkt;
|
||||
av_init_packet(&pkt);
|
||||
pkt.data = data;
|
||||
pkt.size = len;
|
||||
return avcodec_decode_video2(h->ctx, h->f, &h->got, &pkt);
|
||||
}
|
||||
*/
|
||||
"C"
|
||||
"errors"
|
||||
"image"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type H264Decoder struct {
|
||||
m C.h264dec_t
|
||||
}
|
||||
|
||||
func NewH264Decoder(header []byte) (m *H264Decoder, err error) {
|
||||
m = &H264Decoder{}
|
||||
r := C.h264dec_new(
|
||||
&m.m,
|
||||
(*C.uint8_t)(unsafe.Pointer(&header[0])),
|
||||
(C.int)(len(header)),
|
||||
)
|
||||
if int(r) < 0 {
|
||||
err = errors.New("open codec failed")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (m *H264Decoder) Decode(nal []byte) (f *image.YCbCr, err error) {
|
||||
r := C.h264dec_decode(
|
||||
&m.m,
|
||||
(*C.uint8_t)(unsafe.Pointer(&nal[0])),
|
||||
(C.int)(len(nal)),
|
||||
)
|
||||
if int(r) < 0 {
|
||||
err = errors.New("decode failed")
|
||||
return
|
||||
}
|
||||
if m.m.got == 0 {
|
||||
err = errors.New("no picture")
|
||||
return
|
||||
}
|
||||
|
||||
w := int(m.m.f.width)
|
||||
h := int(m.m.f.height)
|
||||
ys := int(m.m.f.linesize[0])
|
||||
cs := int(m.m.f.linesize[1])
|
||||
|
||||
f = &image.YCbCr{
|
||||
Y: fromCPtr(unsafe.Pointer(m.m.f.data[0]), ys*h),
|
||||
Cb: fromCPtr(unsafe.Pointer(m.m.f.data[1]), cs*h/2),
|
||||
Cr: fromCPtr(unsafe.Pointer(m.m.f.data[2]), cs*h/2),
|
||||
YStride: ys,
|
||||
CStride: cs,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio420,
|
||||
Rect: image.Rect(0, 0, w, h),
|
||||
}
|
||||
|
||||
return
|
||||
}
|
146
h264enc.go
146
h264enc.go
@ -1,146 +0,0 @@
|
||||
package codec
|
||||
|
||||
import (
|
||||
|
||||
/*
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/avutil.h>
|
||||
|
||||
typedef struct {
|
||||
int w, h;
|
||||
int pixfmt;
|
||||
char *preset[2];
|
||||
char *profile;
|
||||
int bitrate;
|
||||
int got;
|
||||
AVCodec *c;
|
||||
AVCodecContext *ctx;
|
||||
AVFrame *f;
|
||||
AVPacket pkt;
|
||||
} h264enc_t;
|
||||
|
||||
static int h264enc_new(h264enc_t *m) {
|
||||
m->c = avcodec_find_encoder(CODEC_ID_H264);
|
||||
m->ctx = avcodec_alloc_context3(m->c);
|
||||
m->ctx->width = m->w;
|
||||
m->ctx->height = m->h;
|
||||
m->ctx->bit_rate = m->bitrate;
|
||||
m->ctx->pix_fmt = m->pixfmt;
|
||||
m->ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||
m->f = av_frame_alloc();
|
||||
return avcodec_open2(m->ctx, m->c, NULL);
|
||||
}
|
||||
|
||||
*/
|
||||
"C"
|
||||
"errors"
|
||||
"image"
|
||||
"strings"
|
||||
"unsafe"
|
||||
//"log"
|
||||
)
|
||||
|
||||
type H264Encoder struct {
|
||||
m C.h264enc_t
|
||||
Header []byte
|
||||
Pixfmt image.YCbCrSubsampleRatio
|
||||
W, H int
|
||||
}
|
||||
|
||||
func NewH264Encoder(
|
||||
w, h int,
|
||||
pixfmt image.YCbCrSubsampleRatio,
|
||||
opts ...string,
|
||||
) (m *H264Encoder, err error) {
|
||||
m = &H264Encoder{}
|
||||
m.m.w = (C.int)(w)
|
||||
m.m.h = (C.int)(h)
|
||||
m.W = w
|
||||
m.H = h
|
||||
m.Pixfmt = pixfmt
|
||||
switch pixfmt {
|
||||
case image.YCbCrSubsampleRatio444:
|
||||
m.m.pixfmt = C.PIX_FMT_YUV444P
|
||||
case image.YCbCrSubsampleRatio422:
|
||||
m.m.pixfmt = C.PIX_FMT_YUV422P
|
||||
case image.YCbCrSubsampleRatio420:
|
||||
m.m.pixfmt = C.PIX_FMT_YUV420P
|
||||
}
|
||||
for _, opt := range opts {
|
||||
a := strings.Split(opt, ",")
|
||||
switch {
|
||||
case a[0] == "preset" && len(a) == 3:
|
||||
m.m.preset[0] = C.CString(a[1])
|
||||
m.m.preset[1] = C.CString(a[2])
|
||||
case a[0] == "profile" && len(a) == 2:
|
||||
m.m.profile = C.CString(a[1])
|
||||
}
|
||||
}
|
||||
r := C.h264enc_new(&m.m)
|
||||
if int(r) < 0 {
|
||||
err = errors.New("open encoder failed")
|
||||
return
|
||||
}
|
||||
m.Header = fromCPtr(unsafe.Pointer(m.m.ctx.extradata), (int)(m.m.ctx.extradata_size))
|
||||
//m.Header = fromCPtr(unsafe.Pointer(m.m.pps), (int)(m.m.ppslen))
|
||||
return
|
||||
}
|
||||
|
||||
type h264Out struct {
|
||||
Data []byte
|
||||
Key bool
|
||||
}
|
||||
|
||||
func (m *H264Encoder) Encode(img *image.YCbCr) (out h264Out, err error) {
|
||||
var f *C.AVFrame
|
||||
if img == nil {
|
||||
f = nil
|
||||
} else {
|
||||
if img.SubsampleRatio != m.Pixfmt {
|
||||
err = errors.New("image pixfmt not match")
|
||||
return
|
||||
}
|
||||
if img.Rect.Dx() != m.W || img.Rect.Dy() != m.H {
|
||||
err = errors.New("image size not match")
|
||||
return
|
||||
}
|
||||
f = m.m.f
|
||||
f.data[0] = (*C.uint8_t)(unsafe.Pointer(&img.Y[0]))
|
||||
f.data[1] = (*C.uint8_t)(unsafe.Pointer(&img.Cb[0]))
|
||||
f.data[2] = (*C.uint8_t)(unsafe.Pointer(&img.Cr[0]))
|
||||
f.linesize[0] = (C.int)(img.YStride)
|
||||
f.linesize[1] = (C.int)(img.CStride)
|
||||
f.linesize[2] = (C.int)(img.CStride)
|
||||
}
|
||||
|
||||
C.av_init_packet(&m.m.pkt)
|
||||
r := C.avcodec_encode_video2(m.m.ctx, &m.m.pkt, f, &m.m.got)
|
||||
defer C.av_free_packet(&m.m.pkt)
|
||||
if int(r) < 0 {
|
||||
err = errors.New("encode failed")
|
||||
return
|
||||
}
|
||||
if m.m.got == 0 {
|
||||
err = errors.New("no picture")
|
||||
return
|
||||
}
|
||||
if m.m.pkt.size == 0 {
|
||||
err = errors.New("packet size == 0")
|
||||
return
|
||||
}
|
||||
|
||||
out.Data = make([]byte, m.m.pkt.size)
|
||||
C.memcpy(
|
||||
unsafe.Pointer(&out.Data[0]),
|
||||
unsafe.Pointer(m.m.pkt.data),
|
||||
(C.size_t)(m.m.pkt.size),
|
||||
)
|
||||
out.Key = (m.m.pkt.flags & C.AV_PKT_FLAG_KEY) != 0
|
||||
|
||||
return
|
||||
}
|
48
util.go
48
util.go
@ -1,48 +0,0 @@
|
||||
/*
|
||||
|
||||
Golang h264,aac decoder/encoder libav wrapper
|
||||
|
||||
d, err = codec.NewAACEncoder()
|
||||
data, err = d.Encode(samples)
|
||||
|
||||
d, err = codec.NewAACDecoder(aaccfg)
|
||||
samples, err = d.Decode(data)
|
||||
|
||||
var img *image.YCbCr
|
||||
d, err = codec.NewH264Encoder(640, 480)
|
||||
img, err = d.Encode(img)
|
||||
|
||||
d, err = codec.NewH264Decoder(pps)
|
||||
img, err = d.Decode(nal)
|
||||
*/
|
||||
package codec
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lavformat -lavutil -lavcodec
|
||||
|
||||
#include <libavutil/avutil.h>
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
static void libav_init() {
|
||||
av_register_all();
|
||||
av_log_set_level(AV_LOG_DEBUG);
|
||||
}
|
||||
*/
|
||||
"C"
|
||||
)
|
||||
|
||||
func init() {
|
||||
C.libav_init()
|
||||
}
|
||||
|
||||
func fromCPtr(buf unsafe.Pointer, size int) (ret []uint8) {
|
||||
hdr := (*reflect.SliceHeader)((unsafe.Pointer(&ret)))
|
||||
hdr.Cap = size
|
||||
hdr.Len = size
|
||||
hdr.Data = uintptr(buf)
|
||||
return
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user