import ctypes
import json
import socket
import struct
import time
from ctypes import *
import sys

import cv2
import numpy as np

MV_MAX_DEVICE_NUM=256
MV_VS_OK=0x00000000
CHUNK_MASK_IMAGE_PORT=60005536
CHUNK_RESULT_PORT=60005537

ImageExLen = 4096

MV_VS_GVSP_PIX_MONO = 0x01000000
MV_VS_GVSP_PIX_COLOR = 0x02000000
MV_VS_GVSP_PIX_CUSTOM = 0x80000000
MV_VS_GVSP_PIX_COLOR_MASK = 0xFF000000

MV_VS_GVSP_PIX_EFFECTIVE_PIXEL_SIZE_MASK = 0x00FF0000
MV_VS_GVSP_PIX_EFFECTIVE_PIXEL_SIZE_SHIFT = 16

MV_VS_GVSP_PIX_ID_MASK = 0x0000FFFF
MV_VS_GVSP_PIX_COUNT = 0x46


# Define the macro
def MV_VS_PIXEL_BIT_COUNT(n):
    return (n) << 16

mv_lib = ctypes.windll.LoadLibrary("src/components/hikrobot_sc/bin/MvVisionSensorControl.dll")

# define structures
from ctypes import *

class MvVSGvspPixelType(ctypes.c_uint32):  # Use c_uint32 for compatibility
    MVVS_PixelType_Undefined = 0xFFFFFFFF
    MVVS_PixelType_Mono1p = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(1) | 0x0037)
    MVVS_PixelType_Mono2p = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(2) | 0x0038)
    MVVS_PixelType_Mono4p = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(4) | 0x0039)
    MVVS_PixelType_Mono8 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(8) | 0x0001)
    MVVS_PixelType_Mono8_Signed = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(8) | 0x0002)
    MVVS_PixelType_Mono10 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(16) | 0x0003)
    MVVS_PixelType_Mono10_Packed = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(12) | 0x0004)
    MVVS_PixelType_Mono12 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(16) | 0x0005)
    MVVS_PixelType_Mono12_Packed = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(12) | 0x0006)
    MVVS_PixelType_Mono14 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(16) | 0x0025)
    MVVS_PixelType_Mono16 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(16) | 0x0007)
    MVVS_PixelType_BayerGR8 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(8) | 0x0008)
    MVVS_PixelType_BayerRG8 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(8) | 0x0009)
    MVVS_PixelType_BayerGB8 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(8) | 0x000A)
    MVVS_PixelType_BayerBG8 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(8) | 0x000B)
    MVVS_PixelType_BayerGR10 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(16) | 0x000C)
    MVVS_PixelType_BayerRG10 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(16) | 0x000D)
    MVVS_PixelType_BayerGB10 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(16) | 0x000E)
    MVVS_PixelType_BayerBG10 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(16) | 0x000F)
    MVVS_PixelType_BayerGR12 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(16) | 0x0010)
    MVVS_PixelType_BayerRG12 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(16) | 0x0011)
    MVVS_PixelType_BayerGB12 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(16) | 0x0012)
    MVVS_PixelType_BayerBG12 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(16) | 0x0013)
    MVVS_PixelType_BayerGR10_Packed = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(12) | 0x0026)
    MVVS_PixelType_BayerRG10_Packed = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(12) | 0x0027)
    MVVS_PixelType_BayerGB10_Packed = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(12) | 0x0028)
    MVVS_PixelType_BayerBG10_Packed = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(12) | 0x0029)
    MVVS_PixelType_BayerGR12_Packed = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(12) | 0x002A)
    MVVS_PixelType_BayerRG12_Packed = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(12) | 0x002B)
    MVVS_PixelType_BayerGB12_Packed = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(12) | 0x002C)
    MVVS_PixelType_BayerBG12_Packed = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(12) | 0x002D)
    MVVS_PixelType_BayerGR16 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(16) | 0x002E)
    MVVS_PixelType_BayerRG16 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(16) | 0x002F)
    MVVS_PixelType_BayerGB16 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(16) | 0x0030)
    MVVS_PixelType_BayerBG16 = (MV_VS_GVSP_PIX_MONO | MV_VS_PIXEL_BIT_COUNT(16) | 0x0031)
    MVVS_PixelType_RGB8_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(24) | 0x0014)
    MVVS_PixelType_BGR8_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(24) | 0x0015)
    MVVS_PixelType_RGBA8_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(32) | 0x0016)
    MVVS_PixelType_BGRA8_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(32) | 0x0017)
    MVVS_PixelType_RGB10_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(48) | 0x0018)
    MVVS_PixelType_BGR10_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(48) | 0x0019)
    MVVS_PixelType_RGB12_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(48) | 0x001A)
    MVVS_PixelType_BGR12_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(48) | 0x001B)
    MVVS_PixelType_RGB16_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(48) | 0x0033)
    MVVS_PixelType_BGR16_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(48) | 0x004B)
    MVVS_PixelType_RGBA16_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(64) | 0x0064)
    MVVS_PixelType_BGRA16_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(64) | 0x0051)
    MVVS_PixelType_RGB10V1_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(32) | 0x001C)
    MVVS_PixelType_RGB10V2_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(32) | 0x001D)
    MVVS_PixelType_RGB12V1_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(36) | 0x0034)
    MVVS_PixelType_RGB565_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(16) | 0x0035)
    MVVS_PixelType_BGR565_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(16) | 0x0036)
    MVVS_PixelType_YUV411_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(12) | 0x001E)
    MVVS_PixelType_YUV422_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(16) | 0x001F)
    MVVS_PixelType_YUV422_YUYV_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(16) | 0x0032)
    MVVS_PixelType_YUV444_Packed = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(24) | 0x0020)
    MVVS_PixelType_YCBCR8_CBYCR = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(24) | 0x003A)
    MVVS_PixelType_YCBCR422_8 = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(16) | 0x003B)
    MVVS_PixelType_YCBCR422_8_CBYCRY = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(16) | 0x0043)
    MVVS_PixelType_YCBCR411_8_CBYYCRYY = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(12) | 0x003C)
    MVVS_PixelType_YCBCR601_8_CBYCR = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(24) | 0x003D)
    MVVS_PixelType_YCBCR601_422_8 = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(16) | 0x003E)
    MVVS_PixelType_YCBCR601_422_8_CBYCRY = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(16) | 0x0044)
    MVVS_PixelType_YCBCR601_411_8_CBYYCRYY = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(12) | 0x003F)
    MVVS_PixelType_YCBCR709_8_CBYCR = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(24) | 0x0040)
    MVVS_PixelType_YCBCR709_422_8 = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(16) | 0x0041)
    MVVS_PixelType_YCBCR709_422_8_CBYCRY = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(16) | 0x0045)
    MVVS_PixelType_YCBCR709_411_8_CBYYCRYY = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(12) | 0x0042)
    MVVS_PixelType_RGB8_Planar = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(24) | 0x0021)
    MVVS_PixelType_RGB10_Planar = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(48) | 0x0022)
    MVVS_PixelType_RGB12_Planar = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(48) | 0x0023)
    MVVS_PixelType_RGB16_Planar = (MV_VS_GVSP_PIX_COLOR | MV_VS_PIXEL_BIT_COUNT(48) | 0x0024)
    MVVS_PixelType_Jpeg = (MV_VS_GVSP_PIX_CUSTOM | MV_VS_PIXEL_BIT_COUNT(24) | 0x0001)

class MV_VS_DATA(Structure):
    _fields_ = [
        ("pImage", POINTER(c_char)),             # Pointer of Image
        ("nImageLen", c_uint),                # The Length of Image
        ("nImageWidth", c_uint),               # Image Width
        ("nImageHeight", c_uint),              # Image Height
        ("nImageNum", c_uint64),               # Image Number
        ("enPixelType", c_int),              # Pixel Type (assuming MvVSGvspPixelType is an enum)

        ("nDevTimeStampHigh", c_uint),         # Timestamp high 32 bits
        ("nDevTimeStampLow", c_uint),          # Timestamp low 32 bits
        ("nReserved0", c_uint),               # Reserved, 8-byte aligned
        ("nHostTimeStamp", c_int64),           # Host-generated timestamp

        ("pChunkData", POINTER(c_char)),         # Chunk data
        ("nChunkDataLen", c_uint),            # Chunk Length

        ("nReserved", c_uint * 64),           # Reserved
    ]

class MV_VS_DEVICE_INFO(ctypes.Structure):
    _fields_ = [
        ("nMajorVer", ctypes.c_ushort),                  # GigE protocol Major Version
        ("nMinorVer", ctypes.c_ushort),                  # GigE protocol Minor Version
        ("nMacAddrHigh", ctypes.c_uint),                 # High MAC Address
        ("nMacAddrLow", ctypes.c_uint),                  # Low MAC Address
        ("nIpCfgOption", ctypes.c_uint),                 # Supported IP Configuration Options
        ("nIpCfgCurrent", ctypes.c_uint),                # IP Configuration
        ("nCurrentIp", ctypes.c_uint),                   # Current IP
        ("nCurrentSubNetMask", ctypes.c_uint),           # Current Subnet Mask
        ("nDefultGateWay", ctypes.c_uint),               # Current Gateway
        ("chManufacturerName", ctypes.c_char * 32),     # Manufacturer Name
        ("chModelName", ctypes.c_char * 32),           # Model Name
        ("chDeviceVersion", ctypes.c_char * 32),         # Device Version
        ("chManufacturerSpecificInfo", ctypes.c_char * 48), # Manufacturer Specific Info
        ("chSerialNumber", ctypes.c_char * 16),         # Serial Number
        ("chUserDefinedName", ctypes.c_char * 16),       # User Defined Name
        ("nNetExport", ctypes.c_uint),                   # IP address of connected network port
        ("nReserved", ctypes.c_uint * 8),                # Reserved
    ]


class MV_VS_DEVICE_INFO_LIST(ctypes.Structure):
    _fields_ = [
        ("nDeviceNum", ctypes.c_uint),                       # Online Device Number
        ("pDeviceInfo", ctypes.POINTER(MV_VS_DEVICE_INFO) * MV_MAX_DEVICE_NUM),  # Device info array
    ]


class PROCESS_MEMORY_COUNTERS(ctypes.Structure):
    _fields_ = [
        ("cb", ctypes.c_ulong),
        ("PageFaultCount", ctypes.c_ulong),
        ("PeakWorkingSetSize", ctypes.c_size_t),
        ("WorkingSetSize", ctypes.c_size_t),
        ("QuotaPeakPagedPoolUsage", ctypes.c_size_t),
        ("QuotaPagedPoolUsage", ctypes.c_size_t),
        ("QuotaPeakNonPagedPoolUsage", ctypes.c_size_t),
        ("QuotaNonPagedPoolUsage", ctypes.c_size_t),
        ("PagefileUsage", ctypes.c_size_t),
        ("PeakPagefileUsage", ctypes.c_size_t),
    ]


class MV_VS_JPG_PARAM(ctypes.Structure):
    _fields_ = [
        ("pBufInput", ctypes.POINTER(ctypes.c_ubyte)),
        ("nBufInputLen", ctypes.c_uint),
        ("nWidth", ctypes.c_uint),
        ("nHeight", ctypes.c_uint),
        ("nJpgQuality", ctypes.c_uint),
        ("pBufOutput", ctypes.POINTER(ctypes.c_ubyte)),
        ("nBufOutputLen", ctypes.c_uint),
    ]


# PPROCESS_MEMORY_COUNTERS is simply a pointer to the struct
PPROCESS_MEMORY_COUNTERS = ctypes.POINTER(PROCESS_MEMORY_COUNTERS)

# Define function signatures

mv_lib.MV_VS_GetResultData.argtypes = [c_void_p, POINTER(MV_VS_DATA), c_int]
mv_lib.MV_VS_GetResultData.restype = c_int

mv_lib.MV_VS_ReleaseResultData.argtypes = [ctypes.c_void_p, ctypes.POINTER(MV_VS_DATA)]
mv_lib.MV_VS_ReleaseResultData.restype = ctypes.c_int

mv_lib.MV_VS_EnumDevices.argtypes = [POINTER(MV_VS_DEVICE_INFO_LIST)]
mv_lib.MV_VS_EnumDevices.restype = c_int

mv_lib.MV_VS_CreateHandle.argtypes = [POINTER(c_void_p), c_void_p]  # Assuming pHandle is a void* and pstDeviceInfo is a struct
mv_lib.MV_VS_CreateHandle.restype = c_int

mv_lib.MV_VS_Login.argtypes = [c_void_p, c_char_p, c_char_p]
mv_lib.MV_VS_Login.restype = c_int

mv_lib.MV_VS_SetBoolValue.argtypes = [c_void_p, c_char_p, c_bool]
mv_lib.MV_VS_SetBoolValue.restype = c_int

mv_lib.MV_VS_SetEnumValue.argtypes = [c_void_p, c_char_p, c_uint]
mv_lib.MV_VS_SetEnumValue.restype = c_int

mv_lib.MV_VS_StartRun.argtypes = [c_void_p]  # handle
mv_lib.MV_VS_StartRun.restype = c_int

mv_lib.MV_VS_SetCommandValue.argtypes = [c_void_p, c_char_p]
mv_lib.MV_VS_SetCommandValue.restype = c_int


def MV_VS_GetFrame(handle, name=""):

    stFrameData = MV_VS_DATA()

    nRet = mv_lib.MV_VS_GetResultData(handle, byref(stFrameData), 500)
    if nRet == MV_VS_OK:
        # Print frame information
        # print(f"Frame Width: [{stFrameData.nImageWidth}], Height: [{stFrameData.nImageHeight}], ImageLen: [{stFrameData.nImageLen}]")

        # Process chunk data
        currentDataTag = 0
        chResultInfo = {}
        while stFrameData.nChunkDataLen > currentDataTag:
            chunkLength = ctypes.c_uint32()
            chunkID = ctypes.c_uint32()

            # Calculate source addresses for chunkLength and chunkID
            source_address_length = ctypes.addressof(
                stFrameData.pChunkData.contents) + stFrameData.nChunkDataLen - 4 - currentDataTag
            source_address_id = ctypes.addressof(
                stFrameData.pChunkData.contents) + stFrameData.nChunkDataLen - 8 - currentDataTag

            # Copy data from source to chunkLength and chunkID
            ctypes.memmove(ctypes.byref(chunkLength), source_address_length, 4)
            ctypes.memmove(ctypes.byref(chunkID), source_address_id, 4)

            # Convert network byte order to host byte order
            chunkLength.value = socket.ntohl(chunkLength.value)
            chunkID.value = socket.ntohl(chunkID.value)

            # Print the values
            #print(f"chunkLength [{chunkLength.value}], chunkID: [{chunkID.value}]")

            if chunkLength.value <= 0 or chunkLength.value > stFrameData.nChunkDataLen - 8 - currentDataTag:
                break

            if chunkID.value == CHUNK_RESULT_PORT:  # Result data in JSON format
                chRawInfo = ctypes.cast(stFrameData.pChunkData, ctypes.POINTER(ctypes.c_char))
                chRawInfo = ctypes.cast(ctypes.addressof(
                    chRawInfo.contents) + stFrameData.nChunkDataLen - 8 - chunkLength.value - currentDataTag,
                                        ctypes.POINTER(ctypes.c_char))

                chResultInfo = ctypes.string_at(chRawInfo, chunkLength.value)
                chResultInfo = json.loads(chResultInfo.decode())

                # if chResultInfo:
                #    print(f"chResultInfo OK")

            elif chunkID.value == CHUNK_MASK_IMAGE_PORT:  # Mask image data
                maskModID = ctypes.c_uint32()
                maskModFormat = ctypes.c_uint32()
                maskModWidth = ctypes.c_uint32()
                maskModHeight = ctypes.c_uint32()

                # Calculate source addresses
                source_address_id = ctypes.addressof(
                    stFrameData.pChunkData.contents) + stFrameData.nChunkDataLen - 8 - chunkLength.value - currentDataTag
                source_address_format = source_address_id + 4
                source_address_width = source_address_id + 8
                source_address_height = source_address_id + 12

                # Copy data from source addresses to corresponding variables
                ctypes.memmove(ctypes.byref(maskModID), source_address_id, 4)
                ctypes.memmove(ctypes.byref(maskModFormat), source_address_format, 4)
                ctypes.memmove(ctypes.byref(maskModWidth), source_address_width, 4)
                ctypes.memmove(ctypes.byref(maskModHeight), source_address_height, 4)

                # print(f"Mask ModID[{maskModID.value}], ModFormat[{maskModFormat.value}], ModWidth[{maskModWidth.value}], ModHeight[{maskModHeight.value}], ")

                try:
                    chMaskModImageData = ctypes.cast(ctypes.create_string_buffer(chunkLength.value - 16 + 1),
                                                     ctypes.POINTER(ctypes.c_char))
                    if chMaskModImageData:
                        ctypes.memset(chMaskModImageData, 0, chunkLength.value - 16 + 1)
                        chImageData = ctypes.cast(ctypes.addressof(
                            stFrameData.pChunkData.contents) + stFrameData.nChunkDataLen - 8 - chunkLength.value - currentDataTag + 16,
                                                  ctypes.POINTER(ctypes.c_char))
                        ctypes.memmove(chMaskModImageData, chImageData, chunkLength.value - 16)
                        # print(f"Mask data length [{chunkLength.value - 16}]")

                except (MemoryError, TypeError) as e:
                    print(f"Error allocating or copying memory: {e}")

            currentDataTag = currentDataTag + 8 + chunkLength.value
        # end process chunk data

        m_stJpgParam = MV_VS_JPG_PARAM()
        m_stJpgParam.pBufInput = ctypes.cast(stFrameData.pImage,ctypes.POINTER(ctypes.c_ubyte))
        m_stJpgParam.nBufInputLen = stFrameData.nImageLen
        jpegContents = ctypes.string_at(m_stJpgParam.pBufInput, m_stJpgParam.nBufInputLen)

        # with open(f"tmp/test_{name}.jpg", "wb") as f:
        #    f.write(jpegContents)
        jpg_as_np = np.frombuffer(jpegContents, dtype=np.uint8)
        # Convert the NumPy array to an OpenCV image.
        img = cv2.imdecode(jpg_as_np, flags=1)
        img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
        # Release frame buffer
        nRet = mv_lib.MV_VS_ReleaseResultData(handle, ctypes.byref(stFrameData))

        if nRet != MV_VS_OK:
            print(f"Release frame buffer fail! nRet [0x{nRet:x}]")
        else:
            # print(f"Release frame buffer OK")
            pass

        return {"frame": img, "res": chResultInfo}
    else:
        print(f"MV_VS_GetResultData fail! nRet [0x{nRet&0xFFFFFFFF:x}]")
        return None

def print_device_info(device_info_list):
    num_devices=device_info_list.nDeviceNum
    for i in range(num_devices):
        device_info = device_info_list.pDeviceInfo[i].contents
        nIp1 = ((device_info.nCurrentIp & 0xff000000) >> 24)
        nIp2 = ((device_info.nCurrentIp & 0x00ff0000) >> 16)
        nIp3 = ((device_info.nCurrentIp & 0x0000ff00) >> 8)
        nIp4 = (device_info.nCurrentIp & 0x000000ff)
        print(f"[{i}]Gige: {device_info.chUserDefinedName.decode()}"
              f"({nIp1}.{nIp2}.{nIp3}.{nIp4})")
