#include "core/GVSPParser.h" #include #include #include #include GVSPParser::GVSPParser(QObject *parent) : QObject(parent) , m_lastBlockId(0) , m_imageSequence(0) { m_imageProcessingCount.storeRelaxed(0); } GVSPParser::~GVSPParser() { } void GVSPParser::reset() { m_leftIRState = StreamState(); m_rightIRState = StreamState(); m_rgbState = StreamState(); m_depthState = StreamState(); m_pointCloudState = StreamState(); m_imageSequence = 0; } void GVSPParser::parsePacket(const QByteArray &packet) { static int debugCount = 0; if (packet.size() < sizeof(GVSPPacketHeader)) { return; } const uint8_t *data = reinterpret_cast(packet.constData()); const GVSPPacketHeader *header = reinterpret_cast(data); // GigE Vision 2.1 标准 GVSP 包头解析 uint16_t blockId = ntohs(header->block_id); uint8_t packetType = header->packet_format; uint16_t packetId = ntohs(header->packet_id); // 打印前5个包的详细信息 if (debugCount < 5) { // qDebug() << "[GVSPParser] Packet" << debugCount // << "Type:" << packetType // << "BlockID:" << blockId // << "PacketID:" << packetId // << "Size:" << packet.size(); debugCount++; } switch (packetType) { case GVSP_LEADER_PACKET: handleLeaderPacket(data, packet.size()); break; case GVSP_PAYLOAD_PACKET: handlePayloadPacket(data, packet.size()); break; case GVSP_TRAILER_PACKET: handleTrailerPacket(data, packet.size()); break; default: break; } } void GVSPParser::handleLeaderPacket(const uint8_t *data, size_t size) { // 最小大小检查:至少要有包头 + 2字节reserved + 2字节payload_type if (size < sizeof(GVSPPacketHeader) + 4) { qDebug() << "[GVSPParser] Leader packet too small:" << size << "bytes"; return; } const GVSPPacketHeader *header = reinterpret_cast(data); uint32_t blockId = ntohs(header->block_id); // Check payload type const uint16_t *payload_type_ptr = reinterpret_cast(data + sizeof(GVSPPacketHeader) + 2); uint16_t payload_type = ntohs(*payload_type_ptr); if (payload_type == PAYLOAD_TYPE_IMAGE) { // Image data leader if (size < sizeof(GVSPPacketHeader) + sizeof(GVSPImageDataLeader)) { qDebug() << "[GVSPParser] Image leader too small"; return; } const GVSPImageDataLeader *leader = reinterpret_cast(data + sizeof(GVSPPacketHeader)); uint32_t imageWidth = ntohl(leader->size_x); uint32_t imageHeight = ntohl(leader->size_y); uint32_t pixelFormat = ntohl(leader->pixel_format); // 根据像素格式选择对应的状态 StreamState *state = nullptr; if (pixelFormat == PIXEL_FORMAT_MONO16_LEFT || pixelFormat == PIXEL_FORMAT_MONO8_LEFT) { state = &m_leftIRState; } else if (pixelFormat == PIXEL_FORMAT_MONO16_RIGHT || pixelFormat == PIXEL_FORMAT_MONO8_RIGHT) { state = &m_rightIRState; } else if (pixelFormat == PIXEL_FORMAT_MJPEG) { state = &m_rgbState; } else if (pixelFormat == PIXEL_FORMAT_MONO16 || pixelFormat == PIXEL_FORMAT_12BIT_GRAY) { // Legacy格式:根据序号分配 int imageType = m_imageSequence % 2; state = (imageType == 0) ? &m_leftIRState : &m_rightIRState; } if (state) { state->blockId = blockId; state->imageWidth = imageWidth; state->imageHeight = imageHeight; state->pixelFormat = pixelFormat; // 根据pixel format设置期望大小 if (pixelFormat == PIXEL_FORMAT_MJPEG) { // MJPEG是压缩格式,实际大小未知,设置为0表示动态接收 state->expectedSize = 0; } else if (pixelFormat == PIXEL_FORMAT_MONO8_LEFT || pixelFormat == PIXEL_FORMAT_MONO8_RIGHT) { // 8-bit灰度格式(下采样) state->expectedSize = imageWidth * imageHeight; } else { // 16-bit或12-bit灰度等固定格式 state->expectedSize = imageWidth * imageHeight * 2; } state->dataBuffer.clear(); if (state->expectedSize > 0) { state->dataBuffer.reserve(state->expectedSize); } state->receivedSize = 0; state->isReceiving = true; state->packetCount = 0; } } else if (payload_type == PAYLOAD_TYPE_BINARY) { // Depth data leader const GVSPBinaryDataLeader *leader = reinterpret_cast(data + sizeof(GVSPPacketHeader)); m_depthState.blockId = blockId; m_depthState.expectedSize = ntohl(leader->file_size); m_depthState.dataBuffer.clear(); m_depthState.dataBuffer.reserve(m_depthState.expectedSize); m_depthState.receivedSize = 0; m_depthState.isReceiving = true; m_depthState.packetCount = 0; } else if (payload_type == PAYLOAD_TYPE_POINTCLOUD) { // Point cloud data leader (vendor-specific 0x8000) const GVSPPointCloudDataLeader *leader = reinterpret_cast(data + sizeof(GVSPPacketHeader)); m_pointCloudState.blockId = blockId; m_pointCloudState.expectedSize = ntohl(leader->data_size); m_pointCloudState.dataBuffer.clear(); m_pointCloudState.dataBuffer.reserve(m_pointCloudState.expectedSize); m_pointCloudState.receivedSize = 0; m_pointCloudState.isReceiving = true; m_pointCloudState.packetCount = 0; } } void GVSPParser::handlePayloadPacket(const uint8_t *data, size_t size) { if (size < sizeof(GVSPPacketHeader)) { return; } const GVSPPacketHeader *header = reinterpret_cast(data); uint32_t blockId = ntohs(header->block_id); // 查找匹配的状态 StreamState *state = nullptr; if (m_leftIRState.isReceiving && m_leftIRState.blockId == blockId) { state = &m_leftIRState; } else if (m_rightIRState.isReceiving && m_rightIRState.blockId == blockId) { state = &m_rightIRState; } else if (m_rgbState.isReceiving && m_rgbState.blockId == blockId) { state = &m_rgbState; } else if (m_depthState.isReceiving && m_depthState.blockId == blockId) { state = &m_depthState; } else if (m_pointCloudState.isReceiving && m_pointCloudState.blockId == blockId) { state = &m_pointCloudState; } if (!state) { return; // 没有匹配的接收状态 } if (size <= sizeof(GVSPPacketHeader)) { return; } // Extract payload data (skip header) const uint8_t *payload = data + sizeof(GVSPPacketHeader); size_t payload_size = size - sizeof(GVSPPacketHeader); // Append to buffer state->dataBuffer.append(reinterpret_cast(payload), payload_size); state->receivedSize += payload_size; state->packetCount++; } void GVSPParser::handleTrailerPacket(const uint8_t *data, size_t size) { if (size < sizeof(GVSPPacketHeader)) { return; } const GVSPPacketHeader *header = reinterpret_cast(data); uint32_t blockId = ntohs(header->block_id); // 查找匹配的状态并处理 if (m_leftIRState.isReceiving && m_leftIRState.blockId == blockId) { processImageData(&m_leftIRState); m_leftIRState.isReceiving = false; m_lastBlockId = blockId; } else if (m_rightIRState.isReceiving && m_rightIRState.blockId == blockId) { processImageData(&m_rightIRState); m_rightIRState.isReceiving = false; m_lastBlockId = blockId; } else if (m_rgbState.isReceiving && m_rgbState.blockId == blockId) { processImageData(&m_rgbState); m_rgbState.isReceiving = false; m_lastBlockId = blockId; } else if (m_depthState.isReceiving && m_depthState.blockId == blockId) { processDepthData(&m_depthState); m_depthState.isReceiving = false; m_lastBlockId = blockId; } else if (m_pointCloudState.isReceiving && m_pointCloudState.blockId == blockId) { processPointCloudData(&m_pointCloudState); m_pointCloudState.isReceiving = false; m_lastBlockId = blockId; } } void GVSPParser::processImageData(GVSPParser::StreamState *state) { if (!state) return; // 处理MJPEG格式(RGB相机) if (state->pixelFormat == PIXEL_FORMAT_MJPEG) { // RGB MJPEG emit rgbImageReceived(state->dataBuffer, state->blockId); m_imageSequence++; return; } // 处理Mono16格式(左右红外相机原始16位数据) // 使用像素格式直接区分左右,不依赖接收顺序 if (state->pixelFormat == PIXEL_FORMAT_MONO16_LEFT) { // 检查数据大小 if (state->dataBuffer.size() < state->expectedSize) { return; } // 左红外原始数据 emit leftImageReceived(state->dataBuffer, state->blockId); m_imageSequence++; return; } if (state->pixelFormat == PIXEL_FORMAT_MONO16_RIGHT) { // 检查数据大小 if (state->dataBuffer.size() < state->expectedSize) { return; } // 右红外原始数据 emit rightImageReceived(state->dataBuffer, state->blockId); m_imageSequence++; return; } // 处理Mono8格式(左右红外相机下采样8位数据) if (state->pixelFormat == PIXEL_FORMAT_MONO8_LEFT) { // 检查数据大小 if (state->dataBuffer.size() < state->expectedSize) { return; } // 左红外8位数据 emit leftImageReceived(state->dataBuffer, state->blockId); m_imageSequence++; return; } if (state->pixelFormat == PIXEL_FORMAT_MONO8_RIGHT) { // 检查数据大小 if (state->dataBuffer.size() < state->expectedSize) { return; } // 右红外8位数据 emit rightImageReceived(state->dataBuffer, state->blockId); m_imageSequence++; return; } // 兼容旧版本:使用序号区分(legacy) if (state->pixelFormat == PIXEL_FORMAT_MONO16) { // 检查数据大小 if (state->dataBuffer.size() < state->expectedSize) { return; } // 根据图像序号区分:偶数=左红外,奇数=右红外 int imageType = m_imageSequence % 2; if (imageType == 0) { // 左红外原始数据 emit leftImageReceived(state->dataBuffer, state->blockId); } else { // 右红外原始数据 emit rightImageReceived(state->dataBuffer, state->blockId); } m_imageSequence++; return; } // 处理12-bit灰度格式 - 固定大小,需要检查 if (state->dataBuffer.size() < state->expectedSize) { return; } // 处理12-bit灰度图像(左右红外相机) if (state->pixelFormat != PIXEL_FORMAT_12BIT_GRAY) { return; } // 节流机制:如果已有3个或更多图像在处理中,跳过当前帧 if (m_imageProcessingCount.loadAcquire() >= 3) { m_imageSequence++; return; } // 增加处理计数 m_imageProcessingCount.ref(); // 复制数据到局部变量 QByteArray dataCopy = state->dataBuffer; uint32_t blockId = state->blockId; size_t width = state->imageWidth; size_t height = state->imageHeight; int imageSeq = m_imageSequence; // 使用QtConcurrent在后台线程处理图像数据 QtConcurrent::run([this, dataCopy, blockId, width, height, imageSeq]() { // Convert 16-bit depth data to 8-bit grayscale for display const uint16_t *src = reinterpret_cast(dataCopy.constData()); QImage image(width, height, QImage::Format_Grayscale8); // 优化:使用采样方式快速估算min/max(每隔16个像素采样一次) uint16_t minVal = 65535, maxVal = 0; size_t totalPixels = width * height; const size_t sampleStep = 16; // 采样步长 for (size_t i = 0; i < totalPixels; i += sampleStep) { uint16_t val = src[i]; if (val > 0) { if (val < minVal) minVal = val; if (val > maxVal) maxVal = val; } } // 归一化(不翻转,保持原始方向) uint8_t *dst = image.bits(); float scale = (maxVal > minVal) ? (255.0f / (maxVal - minVal)) : 0.0f; for (size_t row = 0; row < height; row++) { for (size_t col = 0; col < width; col++) { size_t idx = row * width + col; uint16_t val = src[idx]; dst[idx] = (val == 0) ? 0 : static_cast((val - minVal) * scale); } } // 注意:此代码路径已废弃,下位机现在发送JPEG格式 // 仅保留兼容旧代码的信号 emit imageReceived(image, blockId); // 减少处理计数 m_imageProcessingCount.deref(); }); // 增加图像序号 m_imageSequence++; } void GVSPParser::processDepthData(GVSPParser::StreamState *state) { if (!state) return; if (state->dataBuffer.size() < state->expectedSize) { return; } emit depthDataReceived(state->dataBuffer, state->blockId); } void GVSPParser::processPointCloudData(GVSPParser::StreamState *state) { if (!state) return; if (state->dataBuffer.size() < state->expectedSize) { return; } // 点云数据直接发送,格式为 short 数组 (x, y, z, x, y, z, ...) emit pointCloudDataReceived(state->dataBuffer, state->blockId); }