package decoder

/*
#cgo CFLAGS:  -w -I${SRCDIR}/include  -fPIC
#cgo CPPFLAGS: -w -I${SRCDIR}/include -fPIC
#cgo windows LDFLAGS: -L${SRCDIR}/include -L${SRCDIR}/../ -lez_decoder
#cgo linux LDFLAGS: -Wl,-rpath=./ -L${SRCDIR}/include/linux -L${SRCDIR}/include/RTSP/lib -lez_decoder -lavfilter -lavformat -lavcodec -lavdevice -lswscale -lpostproc -lswresample -lavutil -lx264 -lm -ldl -lstdc++ -pthread -lrt -lssl -lcrypto -lz -lbz2
#include "ez_decoder.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void CToBytes(unsigned char *dst, unsigned char *src, int src_len)
{
	//memset(dst, 0, src_len);
	memcpy(dst, src, src_len);
}
*/
import "C"
import (
	"fmt"
	"log/slog"
	"sync"
	"unsafe"
)

type VideoDecoder struct {
	handle C.EZ_DECODER_HANDLE
	sync.RWMutex
	IsStart bool
}

func (v *VideoDecoder) Create() error {
	v.Lock()
	defer v.Unlock()
	if v.IsStart {
		return nil
	}
	ret := int(C.ez_decoder_create(&v.handle))
	v.IsStart = true
	return IsReturnErrorf(ret, "ez_decoder_create")
}

func (v *VideoDecoder) Destroy() error {
	v.Lock()
	defer v.Unlock()
	if !v.IsStart {
		return nil
	}
	v.IsStart = false
	slog.Info("====>>ez_decoder_destroy", "v", v)
	ret := int(C.ez_decoder_destroy(&v.handle))
	return IsReturnErrorf(ret, "ez_decoder_destroy")
}
func (v *VideoDecoder) PushDataEx(buf []byte, codec int) (w, h int, data []byte, err error) {
	v.Lock()
	defer v.Unlock()
	if !v.IsStart {
		return 0, 0, nil, fmt.Errorf("decoder fail")
	}
	cBytes := C.CBytes(buf)
	defer C.free(unsafe.Pointer(cBytes)) // 必须手动释放
	info := &C.EZDecoderInfo{}
	var out_data *C.uchar
	ret := int(C.ez_decoder_push_data(v.handle, (*C.uchar)(cBytes), C.int(len(buf)), C.int(codec), &out_data, info))
	//return 0, 0, nil, fmt.Errorf("test") // 252
	if ret == 0 {
		data_size := int(info.data_size)
		_w := int(info.width)
		_h := int(info.height)
		yuv := C.GoBytes(unsafe.Pointer(out_data), info.data_size)
		_data := make([]byte, data_size)
		copy(_data, yuv)
		return _w, _h, _data, nil

		//_data := make([]byte, data_size)
		//C.CToBytes((*C.uchar)(unsafe.Pointer(&_data[0])), out_data, C.int(data_size))
		//return _w, _h, _data, nil
	}
	return 0, 0, nil, fmt.Errorf("ez_decoder_push_data fail %d", ret)
}

func IsReturnErrorf(ret int, str string) error {
	if int(ret) != 0 {
		return fmt.Errorf("%s error:%d", str, ret)
	}
	return nil
}
