This commit is contained in:
cfanfrank 2013-03-11 11:00:20 +08:00
parent 3e9082fa1b
commit a9f31fa051
7 changed files with 19 additions and 429 deletions

View File

@ -1,22 +1,8 @@
go-av go-av
== ==
Golang audio and video manipulation library. including mp4, rtmp, yuv/rgb image converter Golang audio and video manipulation library
H264,AAC Codec * h264/aac encoder and decoder (using libav) ([HERE](http://github.com/go-av/codec))
==== * mp4 reader and writer ([HERE](http://github.com/go-av/mp4))
Requires `libav` installed.
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)

View File

@ -1,81 +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 = avcodec_alloc_frame();
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 void 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);
avcodec_decode_audio4(m->ctx, m->f, &m->got, &pkt);
av_log(m->ctx, AV_LOG_DEBUG, "got %d\n", m->got);
}
*/
"C"
"unsafe"
"errors"
)
type AACDecoder struct {
m C.aacdec_t
}
func NewAACDecoder(cfg []byte) (m *AACDecoder, err error) {
m = &AACDecoder{}
r := C.aacdec_new(
&m.m,
(*C.uint8_t)(unsafe.Pointer(&cfg[0])),
(C.int)(len(cfg)),
)
if int(r) != 0 {
err = errors.New("avcodec open failed")
}
return
}
func (m *AACDecoder) Decode(data []byte) (sample []byte, err error) {
C.aacdec_decode(
&m.m,
(*C.uint8_t)(unsafe.Pointer(&data[0])),
(C.int)(len(data)),
)
if int(m.m.got) == 0 {
err = errors.New("no data")
return
}
sample = make([]byte, 8192)
for i := 0; i < 2; i++ {
C.memcpy(
unsafe.Pointer(&sample[i*4096]),
unsafe.Pointer(m.m.f.data[i]),
(C.size_t)(4096),
)
}
return
}

View File

@ -1,83 +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;
} aacenc_t ;
static void aacenc_new(aacenc_t *m) {
m->c = avcodec_find_encoder(CODEC_ID_AAC);
m->ctx = avcodec_alloc_context3(m->c);
m->ctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
m->ctx->sample_rate = 44100;
m->ctx->bit_rate = 100000;
m->ctx->channels = 2;
m->ctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
m->f = avcodec_alloc_frame();
avcodec_open2(m->ctx, m->c, 0);
av_log(m->ctx, AV_LOG_DEBUG, "extra %d\n", m->ctx->extradata_size);
}
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] = 4096;
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"
"unsafe"
"errors"
)
type AACEncoder struct {
m C.aacenc_t
Cfg []byte // AAC Audio config
}
// only supported fltp,stereo,44100khz. If you need other config, it's easy to modify code
func NewAACEncoder() (m *AACEncoder) {
m = &AACEncoder{}
C.aacenc_new(&m.m)
m.Cfg = make([]byte, (int)(m.m.ctx.extradata_size))
C.memcpy(
unsafe.Pointer(&m.Cfg[0]),
unsafe.Pointer(&m.m.ctx.extradata),
(C.size_t)(len(m.Cfg)),
)
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[4096]))
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
}

View File

@ -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 = avcodec_alloc_frame();
h->ctx->extradata = data;
h->ctx->extradata_size = len;
h->ctx->debug = 0x3;
return avcodec_open2(h->ctx, h->c, 0);
}
static void h264dec_decode(h264dec_t *h, uint8_t *data, int len) {
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = data;
pkt.size = len;
avcodec_decode_video2(h->ctx, h->f, &h->got, &pkt);
av_log(h->ctx, AV_LOG_DEBUG, "got %d\n", h->got);
}
*/
"C"
"unsafe"
"errors"
"image"
)
type H264Decoder struct {
m C.h264dec_t
}
func NewH264Decoder(pps []byte) (m *H264Decoder, err error) {
m = &H264Decoder{}
r := C.h264dec_new(
&m.m,
(*C.uint8_t)(unsafe.Pointer(&pps[0])),
(C.int)(len(pps)),
)
if int(r) != 0 {
m = nil
err = errors.New("open codec failed")
}
return
}
func (m *H264Decoder) Decode(nal []byte) (f *image.YCbCr, err error) {
C.h264dec_decode(
&m.m,
(*C.uint8_t)(unsafe.Pointer(&nal[0])),
(C.int)(len(nal)),
)
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
}

View File

@ -1,123 +0,0 @@
package codec
import (
/*
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <x264.h>
typedef struct {
x264_t *x;
int w, h;
uint8_t *pps; int ppslen;
uint8_t *sei; int seilen;
x264_picture_t in;
x264_nal_t *nal; int nnal; int nallen;
} h264enc_t;
static void h264enc_new(h264enc_t *m) {
x264_param_t p;
x264_param_default(&p);
x264_param_default_preset(&p, "ultrafast", "zerolatency");
x264_param_apply_profile(&p, "main");
p.rc.i_bitrate = 50;
p.rc.i_rc_method = X264_RC_ABR;
p.i_width = m->w;
p.i_height = m->h;
p.i_csp = X264_CSP_I420;
m->x = x264_encoder_open(&p);
if (!m->x) {
return ;
}
x264_nal_t *nal;
int nnal, i;
uint8_t *pps;
m->ppslen = x264_encoder_headers(m->x, &nal, &nnal);
m->pps = pps = malloc(m->ppslen);
for (i = 0; i < nnal; i++) {
//printf("nal#%d %d\n", i, nal[i].i_type);
if (nal[i].i_type != NAL_SEI) {
memcpy(pps, nal[i].p_payload, nal[i].i_payload);
pps += nal[i].i_payload;
} else {
m->seilen = nal[i].i_payload;
m->sei = malloc(m->seilen);
memcpy(m->sei, nal[i].p_payload, m->seilen);
}
}
m->ppslen = pps - m->pps;
}
static void h264enc_encode(h264enc_t *m) {
x264_picture_t out;
m->in.img.i_csp = X264_CSP_I420;
m->in.i_type = X264_TYPE_AUTO;
x264_encoder_encode(m->x, &m->nal, &m->nnal, &m->in, &out);
m->nallen = 0;
int i;
if (m->seilen)
m->nallen += m->seilen;
for (i = 0; i < m->nnal; i++) {
m->nallen += m->nal[i].i_payload;
}
}
static void h264enc_copy(h264enc_t *m, uint8_t *p) {
int i;
if (m->seilen) {
memcpy(p, m->sei, m->seilen);
p += m->seilen;
m->seilen = 0;
}
for (i = 0; i < m->nnal; i++) {
memcpy(p, m->nal[i].p_payload, m->nal[i].i_payload);
p += m->nal[i].i_payload;
}
}
*/
"C"
"unsafe"
"image"
)
type H264Encoder struct {
m C.h264enc_t
PPS []byte
}
func NewH264Encoder(w, h int) (m *H264Encoder) {
m = &H264Encoder{}
m.m.w = (C.int)(w)
m.m.h = (C.int)(h)
C.h264enc_new(&m.m)
m.PPS = fromCPtr(unsafe.Pointer(m.m.pps), (int)(m.m.ppslen))
return
}
func (m *H264Encoder) Encode(f *image.YCbCr) (nal []byte) {
C.x264_picture_init(&m.m.in);
m.m.in.img.plane[0] = (*C.uint8_t)(unsafe.Pointer(&f.Y[0]));
m.m.in.img.plane[1] = (*C.uint8_t)(unsafe.Pointer(&f.Cb[0]));
m.m.in.img.plane[2] = (*C.uint8_t)(unsafe.Pointer(&f.Cr[0]));
m.m.in.img.i_stride[0] = (C.int)(f.YStride);
m.m.in.img.i_stride[1] = (C.int)(f.CStride);
m.m.in.img.i_stride[2] = (C.int)(f.CStride);
C.h264enc_encode(&m.m)
nal = make([]byte, m.m.nallen)
C.h264enc_copy(&m.m, (*C.uint8_t)(unsafe.Pointer(&nal[0])))
return
}

View File

@ -1,37 +0,0 @@
/*
Golang h264,aac decoder/encoder libav wrapper
*/
package codec
import (
"unsafe"
"reflect"
/*
#cgo darwin LDFLAGS: -lavformat -lavutil -lavcodec -lx264
#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
}

16
util.go Normal file
View File

@ -0,0 +1,16 @@
package av
const (
H264 = 1
AAC = 2
)
type Packet struct {
Codec int
Key bool
Pos float32
Data []byte
Idx int
}