From 70c6f8198b9d38ae9e97af1ebce353e79ddd31e4 Mon Sep 17 00:00:00 2001 From: Isamu Mogi Date: Wed, 27 Jan 2016 16:04:31 +0900 Subject: [PATCH 1/3] Support rules for passing pointers between Go with C for Go 1.6 --- webp/encode.go | 80 ++++++++++++++++++++++++++++++++++++++++------- webp/webp_test.go | 11 +++++++ 2 files changed, 79 insertions(+), 12 deletions(-) diff --git a/webp/encode.go b/webp/encode.go index 4ca42f4..1129b31 100644 --- a/webp/encode.go +++ b/webp/encode.go @@ -8,6 +8,14 @@ package webp int writeWebP(uint8_t*, size_t, struct WebPPicture*); +static WebPPicture *malloc_WebPPicture(void) { + return malloc(sizeof(WebPPicture)); +} + +static void free_WebPPicture(WebPPicture* webpPicture) { + free(webpPicture); +} + */ import "C" import ( @@ -15,6 +23,7 @@ import ( "fmt" "image" "io" + "sync" "unsafe" ) @@ -38,9 +47,39 @@ type destinationManager struct { writer io.Writer } +var destinationManagerMapMutex sync.RWMutex +var destinationManagerMap = make(map[uintptr]*destinationManager) + +// GetDestinationManagerMapLen returns the number of globally working sourceManagers for debug +func GetDestinationManagerMapLen() int { + destinationManagerMapMutex.RLock() + defer destinationManagerMapMutex.RUnlock() + return len(destinationManagerMap) +} + +func makeDestinationManager(w io.Writer, pic *C.WebPPicture) (mgr *destinationManager) { + mgr = &destinationManager{writer: w} + destinationManagerMapMutex.Lock() + defer destinationManagerMapMutex.Unlock() + destinationManagerMap[uintptr(unsafe.Pointer(pic))] = mgr + return +} + +func releaseDestinationManager(pic *C.WebPPicture) { + destinationManagerMapMutex.Lock() + defer destinationManagerMapMutex.Unlock() + delete(destinationManagerMap, uintptr(unsafe.Pointer(pic))) +} + +func getDestinationManager(pic *C.WebPPicture) *destinationManager { + destinationManagerMapMutex.RLock() + defer destinationManagerMapMutex.RUnlock() + return destinationManagerMap[uintptr(unsafe.Pointer(pic))] +} + //export writeWebP func writeWebP(data *C.uint8_t, size C.size_t, pic *C.WebPPicture) C.int { - mgr := (*destinationManager)(unsafe.Pointer(pic.custom_ptr)) + mgr := getDestinationManager(pic) bytes := C.GoBytes(unsafe.Pointer(data), C.int(size)) _, err := mgr.writer.Write(bytes) if err != nil { @@ -57,30 +96,37 @@ func EncodeRGBA(w io.Writer, img image.Image, c Config) (err error) { return } - var pic C.WebPPicture - if C.WebPPictureInit(&pic) == 0 { + pic := C.malloc_WebPPicture() + if pic == nil { + return errors.New("Could not allocate webp picture") + } + defer C.free_WebPPicture(pic) + + makeDestinationManager(w, pic) + defer releaseDestinationManager(pic) + + if C.WebPPictureInit(pic) == 0 { return errors.New("Could not initialize webp picture") } + defer C.WebPPictureFree(pic) + pic.use_argb = 1 pic.width = C.int(img.Bounds().Dx()) pic.height = C.int(img.Bounds().Dy()) pic.writer = C.WebPWriterFunction(C.writeWebP) - pic.custom_ptr = unsafe.Pointer(&destinationManager{writer: w}) switch p := img.(type) { case *image.RGBA: - C.WebPPictureImportRGBA(&pic, (*C.uint8_t)(&p.Pix[0]), C.int(p.Stride)) + C.WebPPictureImportRGBA(pic, (*C.uint8_t)(&p.Pix[0]), C.int(p.Stride)) case *image.NRGBA: - C.WebPPictureImportRGBA(&pic, (*C.uint8_t)(&p.Pix[0]), C.int(p.Stride)) + C.WebPPictureImportRGBA(pic, (*C.uint8_t)(&p.Pix[0]), C.int(p.Stride)) default: return errors.New("unsupported image type") } - defer C.WebPPictureFree(&pic) - - if C.WebPEncode(webpConfig, &pic) == 0 { + if C.WebPEncode(webpConfig, pic) == 0 { return fmt.Errorf("Encoding error: %d", pic.error_code) } @@ -94,10 +140,20 @@ func EncodeYUVA(w io.Writer, img *YUVAImage, c Config) (err error) { return } - var pic C.WebPPicture - if C.WebPPictureInit(&pic) == 0 { + pic := C.malloc_WebPPicture() + if pic == nil { + return errors.New("Could not allocate webp picture") + } + defer C.free_WebPPicture(pic) + + makeDestinationManager(w, pic) + defer releaseDestinationManager(pic) + + if C.WebPPictureInit(pic) == 0 { return errors.New("Could not initialize webp picture") } + defer C.WebPPictureFree(pic) + pic.use_argb = 0 pic.colorspace = C.WebPEncCSP(img.ColorSpace) pic.width = C.int(img.Rect.Dx()) @@ -116,7 +172,7 @@ func EncodeYUVA(w io.Writer, img *YUVAImage, c Config) (err error) { pic.writer = C.WebPWriterFunction(C.writeWebP) pic.custom_ptr = unsafe.Pointer(&destinationManager{writer: w}) - if C.WebPEncode(webpConfig, &pic) == 0 { + if C.WebPEncode(webpConfig, pic) == 0 { return fmt.Errorf("Encoding error: %d", pic.error_code) } diff --git a/webp/webp_test.go b/webp/webp_test.go index c807e7f..60370ae 100644 --- a/webp/webp_test.go +++ b/webp/webp_test.go @@ -2,13 +2,24 @@ package webp_test import ( "bufio" + "fmt" "image" + "os" "testing" "github.com/harukasan/go-libwebp/test/util" "github.com/harukasan/go-libwebp/webp" ) +func TestMain(m *testing.M) { + result := m.Run() + if webp.GetDestinationManagerMapLen() > 0 { + fmt.Println("destinationManager leaked") + result = 2 + } + os.Exit(result) +} + // // Decode // From 078f9301615c305efba41c0316ae9cbadaab7114 Mon Sep 17 00:00:00 2001 From: Isamu Mogi Date: Wed, 8 Jun 2016 20:07:45 +0900 Subject: [PATCH 2/3] Retire Go 1.3 support --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8777fe2..0456875 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: go go: - - 1.3 - 1.4 env: @@ -11,7 +10,7 @@ env: before_install: - sudo apt-get update -qq - sudo apt-get install -qq libjpeg-dev libpng-dev libtiff-dev libgif-dev - - > + - > cd /tmp && wget http://downloads.webmproject.org/releases/webp/libwebp-${LIBWEBP_VERSION}.tar.gz && tar xf libwebp-${LIBWEBP_VERSION}.tar.gz From 8d57ed8489640773bb0c0a59c053ee9be778d5ef Mon Sep 17 00:00:00 2001 From: Isamu Mogi Date: Wed, 8 Jun 2016 20:08:29 +0900 Subject: [PATCH 3/3] Add test for Go 1.5 - tip and libwebp 4.3 - 5.0 --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0456875..463cc14 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,15 @@ language: go go: - 1.4 + - 1.5 + - 1.6 + - tip env: - LIBWEBP_VERSION="0.4.1" - LIBWEBP_VERSION="0.4.2" + - LIBWEBP_VERSION="0.4.3" + - LIBWEBP_VERSION="0.5.0" before_install: - sudo apt-get update -qq