package goconv /* #cgo CFLAGS: -I./ -I./inc -I/usr/local/cuda/include #cgo CXXFLAGS: -I./ -I./inc -I/usr/local/cuda/include -std=c++11 #cgo LDFLAGS: -L/usr/local/cuda/lib64 -lnppi -lcudart -ldl #include #include "conv.h" */ import "C" import ( "unsafe" "basic.com/valib/godraw.git" "basic.com/valib/gogpu.git" "github.com/disintegration/imaging" ) const ( need = 200 reserved = 512 ) func gpuIndex(lastIndex int) int { indices := gogpu.RankGPU() if len(indices) == 0 { return -1 } for _, v := range indices { if v != lastIndex { if gogpu.SatisfyGPU(v, need, need/2) { return v } } } if gogpu.SatisfyGPU(lastIndex, need, reserved) { return lastIndex } return -1 } type convertor struct { width int height int rWidth int rHeight int conv C.convHandle } var convts []*convertor func find(w, h, rw, rh int) *convertor { for _, v := range convts { if v.width == w && v.height == h && v.rWidth == rw && v.rHeight == rh { return v } } gpu := gpuIndex(0) if gpu < 0 { return nil } cw := C.conv_create(C.int(w), C.int(h), C.int(rw), C.int(rh), C.int(gpu)) if cw == nil { return nil } c := &convertor{w, h, rw, rh, cw} convts = append(convts, c) return c } // YUV2BGR yuv->bgr func YUV2BGR(yuv []byte, w, h int) []byte { cw := find(w, h, -1, -1) if cw == nil { return yuv2bgr(yuv, w, h) } var bgr *C.uchar var bgrLen C.int ret := C.yuv2bgr(cw.conv, unsafe.Pointer(&yuv[0]), &bgr, &bgrLen) if ret != 0 { return nil } const maxLen = 0x7fffffff goBGRLen := int(bgrLen) if goBGRLen > 0 { return (*[maxLen]byte)(unsafe.Pointer(bgr))[:goBGRLen:goBGRLen] } return nil } // YUV2ResizedBGR yuv -> resized bgr func YUV2ResizedBGR(yuv []byte, w, h, rw, rh int) []byte { cw := find(w, h, rw, rh) if cw == nil { bgr := yuv2bgr(yuv, w, h) return bgresize(bgr, w, h, rw, rh) } var bgr *C.uchar var bgrLen C.int ret := C.yuv2resizedbgr(cw.conv, unsafe.Pointer(&yuv[0]), &bgr, &bgrLen) if ret != 0 { return nil } const maxLen = 0x7fffffff goBGRLen := int(bgrLen) if goBGRLen > 0 { return (*[maxLen]byte)(unsafe.Pointer(bgr))[:goBGRLen:goBGRLen] } return nil } // ResizeBGR resize func ResizeBGR(bgrO []byte, w, h, rw, rh int) []byte { if (rw < 0 && rh < 0) || (rw > w && rh > h) { return bgrO } cw := find(w, h, rw, rh) if cw == nil { return bgresize(bgrO, w, h, rw, rh) } var bgr *C.uchar var bgrLen C.int ret := C.resizebgr(cw.conv, unsafe.Pointer(&bgrO[0]), &bgr, &bgrLen) if ret != 0 { return nil } const maxLen = 0x7fffffff goBGRLen := int(bgrLen) if goBGRLen > 0 { return (*[maxLen]byte)(unsafe.Pointer(bgr))[:goBGRLen:goBGRLen] } return nil } // ResizeYUV yuv func ResizeYUV(yuv []byte, w, h, rw, rh int) []byte { if (rw < 0 && rh < 0) || (rw > w && rh > h) { return yuv } cw := find(w, h, rw, rh) if cw == nil { return yuv } var resized *C.uchar var resizedLen C.int ret := C.resizeyuv(cw.conv, unsafe.Pointer(&yuv[0]), &resized, &resizedLen) if ret != 0 { return nil } const maxLen = 0x7fffffff goResizedLen := int(resizedLen) if goResizedLen > 0 { return (*[maxLen]byte)(unsafe.Pointer(resized))[:goResizedLen:goResizedLen] } return nil } // YUV2BGRandResize conv and resize func YUV2BGRandResize(yuv []byte, w, h, rw, rh int) ([]byte, []byte) { cw := find(w, h, rw, rh) if cw == nil { origin := yuv2bgr(yuv, w, h) resized := bgresize(origin, w, h, rw, rh) return origin, resized } var bgr *C.uchar var bgrLen C.int var scale *C.uchar var scaleLen C.int ret := C.yuv2bgrandresize(cw.conv, unsafe.Pointer(&yuv[0]), &bgr, &bgrLen, &scale, &scaleLen) if ret != 0 { return nil, nil } var out, resized []byte const maxLen = 0x7fffffff goBGRLen, goScaleLen := int(bgrLen), int(scaleLen) if goBGRLen > 0 { out = (*[maxLen]byte)(unsafe.Pointer(bgr))[:goBGRLen:goBGRLen] } if goScaleLen > 0 { resized = (*[maxLen]byte)(unsafe.Pointer(scale))[:goScaleLen:goScaleLen] } return out, resized } // Free free func Free() { for _, v := range convts { if v.conv != nil { C.conv_destroy(v.conv) } } } func yuv2bgr(yuv []byte, w, h int) []byte { data := make([]byte, 0, w*h*3) start := w * h for i := 0; i < h; i++ { for j := 0; j < w; j++ { index := i/2*w + j - (j & 0x01) y := int32(yuv[j+i*w]) v := int32(yuv[start+index]) u := int32(yuv[start+index+1]) r := y + (140*(v-128))/100 g := y - (34*(u-128)+71*(v-128))/100 b := y + (177*(u-128))/100 if r > 255 { r = 255 } if r < 0 { r = 0 } if g > 255 { g = 255 } if g < 0 { g = 0 } if b > 255 { b = 255 } if b < 0 { b = 0 } data = append(data, byte(r), byte(g), byte(b)) } } return data } func bgresize(bgr []byte, w, h, rw, rh int) []byte { img, err := godraw.ToImage(bgr, w, h) if err != nil { return nil } dstImg := imaging.Resize(img, rw, rh, imaging.NearestNeighbor) return godraw.Image2BGR(dstImg) }