07dcc0d9c6c7 — Ted Unangst 18 days ago
add lazif code here (for now)
4 files changed, 193 insertions(+), 44 deletions(-)

M avif.go
A => lazif.c
A => lazif.h
M main.go
M avif.go +40 -44
@@ 1,12 1,10 @@ 
-//go:build notyet
 package main
 
-// #cgo pkg-config: libavif
 /*
 #include <stdlib.h>
 #include <string.h>
 
-#include "avif/avif.h"
+#include "lazif.h"
 */
 import "C"
 import (

          
@@ 14,10 12,26 @@ import (
 	"image"
 	"image/jpeg"
 	"runtime"
+	"sync"
 	"unsafe"
 )
 
+var avifOnce sync.Once
+var avifLoaded bool
+
+func avifInit() {
+	rv := C.lazifInit()
+	if rv == 0 {
+		avifLoaded = true
+	}
+}
+
 func avifEncode(data []byte) []byte {
+	avifOnce.Do(avifInit)
+	if !avifLoaded {
+		return nil
+	}
+
 	img, err := jpeg.Decode(bytes.NewReader(data))
 	if err != nil {
 		ilog.Printf("failed to decode")

          
@@ 28,57 42,39 @@ func avifEncode(data []byte) []byte {
 		ilog.Printf("not jpeg")
 		return nil
 	}
-	var fmt C.avifPixelFormat
 	switch jpg.SubsampleRatio {
 	case image.YCbCrSubsampleRatio420:
-		fmt = C.AVIF_PIXEL_FORMAT_YUV420
 	default:
 		ilog.Printf("bad sample ratio: %d", jpg.SubsampleRatio)
 		return nil
 	}
 
-	w := C.uint(jpg.Rect.Max.X)
-	h := C.uint(jpg.Rect.Max.Y)
-	frame := C.avifImageCreate(w, h, 8, fmt)
-	if frame == nil {
-		ilog.Printf("no image")
-		return nil
-	}
-	defer C.avifImageDestroy(frame)
+	var args C.struct_lazifArgs
+
+	args.width = C.uint(jpg.Rect.Max.X)
+	args.height = C.uint(jpg.Rect.Max.Y)
+
+	var pinner runtime.Pinner
+	defer pinner.Unpin()
 
-	frame.yuvPlanes[C.AVIF_CHAN_Y] = (*C.uchar)(&jpg.Y[0])
-	frame.yuvRowBytes[C.AVIF_CHAN_Y] = C.uint(jpg.YStride)
-	frame.yuvPlanes[C.AVIF_CHAN_U] = (*C.uchar)(&jpg.Cb[0])
-	frame.yuvRowBytes[C.AVIF_CHAN_U] = C.uint(jpg.CStride)
-	frame.yuvPlanes[C.AVIF_CHAN_V] = (*C.uchar)(&jpg.Cr[0])
-	frame.yuvRowBytes[C.AVIF_CHAN_V] = C.uint(jpg.CStride)
+	args.planes[0] = (*C.uchar)(&jpg.Y[0])
+	pinner.Pin(args.planes[0])
+	args.strides[0] = C.uint(jpg.YStride)
+	args.planes[1] = (*C.uchar)(&jpg.Cb[0])
+	pinner.Pin(args.planes[1])
+	args.strides[1] = C.uint(jpg.CStride)
+	args.planes[2] = (*C.uchar)(&jpg.Cr[0])
+	pinner.Pin(args.planes[2])
+	args.strides[2] = C.uint(jpg.CStride)
 
-	runtime.KeepAlive(jpg)
-
-	enc := C.avifEncoderCreate()
-	if enc == nil {
-		ilog.Printf("failed to create encoder")
+	rv := C.lazifEncode(&args)
+	if rv != 0 {
+		ilog.Printf("failed to encode")
 		return nil
 	}
-	defer C.avifEncoderDestroy(enc)
-	enc.codecChoice = C.AVIF_CODEC_CHOICE_AOM
-	enc.maxThreads = 2
-	enc.speed = 9
-
-	res := C.avifEncoderAddImage(enc, frame, 1, C.AVIF_ADD_IMAGE_FLAG_SINGLE)
-	if res != 0 {
-		ilog.Printf("failed to add image: %d", res)
-		return nil
-	}
+	res := make([]byte, int(args.outlen))
+	C.memcpy(unsafe.Pointer(&res[0]), unsafe.Pointer(args.out), args.outlen)
+	C.lazifFree(&args)
 
-	var out C.avifRWData
-	res = C.avifEncoderFinish(enc, &out)
-	if res != 0 {
-		ilog.Printf("failed to finish encode: %d", res)
-		return nil
-	}
-
-	rv := make([]byte, int(out.size))
-	C.memcpy(unsafe.Pointer(&rv[0]), unsafe.Pointer(out.data), out.size)
-	return rv
+	return res
 }

          
A => lazif.c +137 -0
@@ 0,0 1,137 @@ 
+#include <stdint.h>
+#include <stdio.h>
+#include <dlfcn.h>
+#include <string.h>
+
+#include "lazif.h"
+
+struct frame {
+    uint32_t width;
+    uint32_t height;
+    uint32_t depth;
+
+    int yuvFormat;
+    int yuvRange;
+    int yuvChromaSamplePosition;
+    uint8_t * yuvPlanes[3];
+    uint32_t yuvRowBytes[3];
+    int imageOwnsYUVPlanes;
+
+    uint8_t * alphaPlane;
+    uint32_t alphaRowBytes;
+    int imageOwnsAlphaPlane;
+    int alphaPremultiplied;
+};
+
+struct encoder {
+    int codecChoice;
+    int maxThreads;
+    int speed;
+    int keyframeInterval;    
+    uint64_t timescale;     
+    int repetitionCount;   
+    uint32_t extraLayerCount; 
+    int quality;
+    int qualityAlpha;
+    int minQuantizer;
+    int maxQuantizer;
+    int minQuantizerAlpha;
+    int maxQuantizerAlpha;
+};
+
+struct rwdata {
+	unsigned char *data;
+	size_t size;
+};
+
+static struct frame *(*imgCreate)(unsigned int, unsigned int, int, int);
+static struct encoder *(*encCreate)(void);
+static int (*encWrite)(struct encoder *, struct frame *, struct rwdata *);
+static void (*encDestroy)(struct encoder *);
+static void (*imgDestroy)(struct frame *);
+static void (*dataFree)(struct rwdata *);
+
+int
+lazifInit(void)
+{
+	void *lib = dlopen("libavif.so", RTLD_LAZY);
+	if (!lib) {
+		printf("no libavif\n");
+		return -1;
+	}
+	if (!(imgCreate = dlsym(lib, "avifImageCreate"))) {
+		printf("no imgCreate\n");
+		return -1;
+	}
+	if (!(encCreate = dlsym(lib, "avifEncoderCreate"))) {
+		printf("no encCreate\n");
+		return -1;
+	}
+	if (!(encWrite = dlsym(lib, "avifEncoderWrite"))) {
+		printf("no encWrite\n");
+		return -1;
+	}
+	if (!(encDestroy = dlsym(lib, "avifEncoderDestroy"))) {
+		printf("no encDestroy\n");
+		return -1;
+	}
+	if (!(imgDestroy = dlsym(lib, "avifImageDestroy"))) {
+		printf("no imgDestroy\n");
+		return -1;
+	}
+	if (!(dataFree = dlsym(lib, "avifRWDataFree"))) {
+		printf("no dataFree\n");
+		return -1;
+	}
+	return 0;
+}
+
+int
+lazifEncode(struct lazifArgs *args)
+{
+	int rv = -1;
+	const int yuv420 = 3;
+	struct frame *frame = imgCreate(args->width, args->height, 8, yuv420);
+	if (!frame)
+		goto out;
+
+	printf("create frame\n");
+	for (int i = 0; i < 3; i++) {
+		frame->yuvPlanes[i] = args->planes[i];
+		frame->yuvRowBytes[i] = args->strides[i];
+	}
+
+	struct encoder *enc = encCreate();
+	// avifEncoder *enc = avifEncoderCreate();
+	if (!enc)
+		goto out;
+	printf("create enc\n");
+	enc->maxThreads = 2;
+	enc->speed = 10;
+
+	printf("writing image\n");
+	struct rwdata out;
+	memset(&out, 0, sizeof(out));
+	int err = encWrite(enc, frame, &out);
+	if (err)
+		goto out;
+	printf("wrote image\n");
+	args->out = out.data;
+	args->outlen = out.size;
+	rv = 0;
+out:
+	if (enc)
+		encDestroy(enc);
+	if (frame)
+		imgDestroy(frame);
+	return rv;
+}
+
+void
+lazifFree(struct lazifArgs *args)
+{
+	struct rwdata out;
+	out.data = args->out;
+	out.size = args->outlen;
+	dataFree(&out);
+}

          
A => lazif.h +13 -0
@@ 0,0 1,13 @@ 
+struct lazifArgs {
+	unsigned int width;
+	unsigned int height;
+	unsigned char *planes[3];
+	unsigned int strides[3];
+	unsigned char *out;
+	size_t outlen;
+};
+
+int lazifInit(void);
+int lazifEncode(struct lazifArgs *args);
+void lazifFree(struct lazifArgs *args);
+

          
M main.go +3 -0
@@ 55,6 55,9 @@ func serverURL(u string, args ...interfa
 }
 
 func ElaborateUnitTests() {
+	data, _ := os.ReadFile("input.jpg")
+	d2 := avifEncode(data)
+	os.WriteFile("output.avif", d2, 0600)
 }
 
 func unplugserver(hostname string) {