Skip to content

Commit

Permalink
Don't copy YUV planes in x264
Browse files Browse the repository at this point in the history
  • Loading branch information
sergystepanov committed Oct 19, 2023
1 parent fb5d8c2 commit e4aab10
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 45 deletions.
2 changes: 1 addition & 1 deletion pkg/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ encoder:
# see: https://trac.ffmpeg.org/wiki/Encode/H.264
h264:
# Constant Rate Factor (CRF) 0-51 (default: 23)
crf: 23
crf: 26
# ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow, placebo
preset: superfast
# baseline, main, high, high10, high422, high444
Expand Down
14 changes: 4 additions & 10 deletions pkg/encoder/h264/libx264.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,10 +362,10 @@ type Sei struct {
}

type Image struct {
ICsp int32 /* Colorspace */
IPlane int32 /* Number of image planes */
IStride [4]int32 /* Strides for each plane */
Plane [4]unsafe.Pointer /* Pointers to each plane */
ICsp int32 /* Colorspace */
IPlane int32 /* Number of image planes */
IStride [4]int32 /* Strides for each plane */
Plane [4]uintptr /* Pointers to each plane */
}

type ImageProperties struct {
Expand Down Expand Up @@ -455,12 +455,6 @@ type Picture struct {
Opaque unsafe.Pointer
}

func (p *Picture) freePlanes() {
for _, ptr := range p.Img.Plane {
C.free(ptr)
}
}

func (t *T) cptr() *C.x264_t { return (*C.x264_t)(unsafe.Pointer(t)) }

func (n *Nal) cptr() *C.x264_nal_t { return (*C.x264_nal_t)(unsafe.Pointer(n)) }
Expand Down
53 changes: 19 additions & 34 deletions pkg/encoder/h264/x264.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package h264

// #include <stdint.h>
import "C"
import (
"fmt"
"unsafe"
Expand All @@ -18,7 +16,6 @@ type H264 struct {
nals []*Nal

in, out *Picture
y, u, v []byte
}

type Options struct {
Expand Down Expand Up @@ -86,51 +83,43 @@ func NewEncoder(w, h int, opts *Options) (encoder *H264, err error) {

encoder = &H264{
csp: param.ICsp,
lumaSize: int32(w * h),
chromaSize: int32(w*h) / 4,
lumaSize: param.IWidth * param.IHeight,
chromaSize: param.IWidth * param.IHeight / 4,
nals: make([]*Nal, 1),
width: int32(w),
width: param.IWidth,
out: new(Picture),
in: &Picture{
Img: Image{
ICsp: param.ICsp,
IPlane: 3,
IStride: [4]int32{
0: param.IWidth,
1: param.IWidth >> 1,
2: param.IWidth >> 1,
},
},
},
}

// pool
var picIn Picture

picIn.Img.ICsp = encoder.csp
picIn.Img.IPlane = 3
picIn.Img.IStride[0] = encoder.width
picIn.Img.IStride[1] = encoder.width >> 1
picIn.Img.IStride[2] = encoder.width >> 1

picIn.Img.Plane[0] = C.malloc(C.size_t(encoder.lumaSize))
picIn.Img.Plane[1] = C.malloc(C.size_t(encoder.chromaSize))
picIn.Img.Plane[2] = C.malloc(C.size_t(encoder.chromaSize))

encoder.y = unsafe.Slice((*byte)(picIn.Img.Plane[0]), encoder.lumaSize)
encoder.u = unsafe.Slice((*byte)(picIn.Img.Plane[1]), encoder.chromaSize)
encoder.v = unsafe.Slice((*byte)(picIn.Img.Plane[2]), encoder.chromaSize)

encoder.in = &picIn

if encoder.ref = EncoderOpen(&param); encoder.ref == nil {
err = fmt.Errorf("x264: cannot open the encoder")
return
}
return
}

func LibVersion() int { return int(Build) }

func (e *H264) LoadBuf(yuv []byte) {
copy(e.y, yuv[:e.lumaSize])
copy(e.u, yuv[e.lumaSize:e.lumaSize+e.chromaSize])
copy(e.v, yuv[e.lumaSize+e.chromaSize:])
e.in.Img.Plane[0] = uintptr(unsafe.Pointer(&yuv[0]))
e.in.Img.Plane[1] = uintptr(unsafe.Pointer(&yuv[e.lumaSize]))
e.in.Img.Plane[2] = uintptr(unsafe.Pointer(&yuv[e.lumaSize+e.chromaSize]))
}

func (e *H264) Encode() []byte {
e.in.IPts += 1
if ret := EncoderEncode(e.ref, e.nals, &e.nnals, e.in, e.out); ret > 0 {
return C.GoBytes(e.nals[0].PPayload, C.int(ret))
return unsafe.Slice((*byte)(e.nals[0].PPayload), ret)
//return C.GoBytes(e.nals[0].PPayload, C.int(ret))
}
return []byte{}
}
Expand All @@ -148,10 +137,6 @@ func (e *H264) SetFlip(b bool) {
}

func (e *H264) Shutdown() error {
e.y = nil
e.u = nil
e.v = nil
e.in.freePlanes()
EncoderClose(e.ref)
return nil
}
29 changes: 29 additions & 0 deletions pkg/encoder/h264/x264_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package h264

import "testing"

func TestH264Encode(t *testing.T) {
h264, err := NewEncoder(120, 120, nil)
if err != nil {
t.Error(err)
}
data := make([]byte, 120*120*1.5)
h264.LoadBuf(data)
h264.Encode()
if err := h264.Shutdown(); err != nil {
t.Error(err)
}
}

func Benchmark(b *testing.B) {
w, h := 1920, 1080
h264, err := NewEncoder(w, h, nil)
if err != nil {
b.Error(err)
}
data := make([]byte, int(float64(w)*float64(h)*1.5))
for i := 0; i < b.N; i++ {
h264.LoadBuf(data)
h264.Encode()
}
}

0 comments on commit e4aab10

Please sign in to comment.